Modernizing a pricing intelligence SaaS inside a legacy Django product.
Priceindx is a B2B pricing intelligence platform. Retailers use it to watch competitor prices, analyze their catalog, and act on automated price suggestions. From 2022 to 2026 I was its only frontend developer, building a Vue 3 layer inside the existing Django product and most of the screens customers work in.

- Role
- Frontend developer, the only one on the team
- Timeframe
- 2022 - 2026
- Product
- B2B pricing intelligence SaaS
- Core stack
- Vue 3, Vite, Pinia, Quasar, Django
The product started as a server-rendered Django app with paying customers, so a rewrite was never an option. Every new Vue screen had to mount into an existing Django page while the backend and the customers' routines kept running.
I owned that frontend layer for three and a half years: the build setup, shared state, the component library, the main product screens, and the documentation and onboarding around them. Designs arrived as Figma handoffs, and I implemented them as components and screens, working with the backend developers on every API they called.
Vue inside Django
Each product area became its own Vue app. A multi-entry Vite build compiles them into Django's static files, and each one mounts into the server-rendered page it replaces, so there is no separate frontend to deploy. The dashboard moved first and set the patterns the other screens followed for filters, loading states, permissions, and onboarding.
Every app starts from one shared bootstrap that sets up Pinia, Quasar, axios, i18n, and the common directives, so customers moving between old and new screens see one product, in their account's language, rather than a patchwork.
- A shared component library built from the Figma designs, so every new screen started from the same dialogs, filters, date selectors, and chart controls.
- Interface translations in English, French, and German across every screen.
The product table
Pricing teams spend most of their day in the product table. It is a catalog browser, a competitor comparison, an export tool, and the place where price suggestions get applied, with global, table, and quick filters, column preferences, saved views, date controls, and each product's competitor offer history one click away.
One Pinia store owns the filters, competitor columns, offer loading, saved views, and exports, which keeps every control in step with the rows on screen. Exports run in the background with polling and retry, and the table stays usable while they do.

- Saved views that keep filters, sorting, visible columns, and date presets.
- Price suggestions applied from the table, one at a time or in bulk.
Visual Analytics
Visual Analytics lets users build their own charts instead of reading fixed dashboard widgets. A chart combines up to three datasets on independent y-axes, drawn as lines, bars, segmented bars, or boxplots. Each dataset can be aggregated, segmented, and grouped by product, competitor, sales, or Dynamic Pricing dimensions, as a snapshot or over time, with a ratio mode when two datasets are selected.
The chart and the data table under it read the same configuration, so one view serves both exploring and exporting to CSV or an image. The data transformation runs in a web worker to keep the page responsive on large catalogs, and a finished view can be saved privately, shared with the team, or set as the default.

Scheduled reports
For customers who live in spreadsheets and BI tools, scheduled reports deliver the same data on a timetable. I built the report list and a multi-step wizard for report type, columns, schedule and timezone, delivery by email or SFTP, notification addresses, and a final review.

Dynamic Pricing
Dynamic Pricing is a rules engine that suggests price changes. Its UI manages rule group sets and groups, drag-and-drop priority, enabled states, and settings, and shows what the engine did: how many prices it would raise, lower, or keep, and a log of the changes it made.
A few edge settings still lived on old Django pages. The new screens link into those pages instead of rebuilding them, which kept the migration moving.

Help, docs, and tests
A product this dense needs explanation inside it. I wrote the customer documentation as a VitePress site in English, French, and German and tied it into the app: a custom directive turns any element into a help target, new users get guided tours, and short videos sit next to the table workflows that need them.
Vitest and Vue Test Utils cover the main Pinia stores, the table and analytics stores most of all, and the key shared components.
Outcome
By 2026 the Vue layer covered every core customer workflow. There was never a rewrite, a parallel app, or a cutover date; customers kept working in the product while it changed under them.