Acquisition KPI Overview
A Streamlit dashboard people relied on, rebuilt as a proper web app. One rule for the rewrite: the numbers were not allowed to move by a single decimal.
- Role
- Migration, backend, frontend
- Context
- RCS MediaGroup
- Period
- 2025 – 2026
- Stack
-
- Python
- FastAPI
- React
- Vite
- Recharts
- BigQuery
- Streamlit views trusted, outgrowing its tooling
- Calculation modules ported unchanged
- View-by-view diff the numbers must not move
- FastAPI + React one combined endpoint
Objective
The acquisition team’s daily dashboard — known versus unknown audience, returning versus new, paywall intercepts, referral ratio, device mix — worked, and was outgrowing its tooling. Every interaction re-ran a script, the layout could not be shaped, and the login story was awkward.
Rewrite it as a real web app. The catch: it was already trusted, so any drift in the numbers would have been a regression, however defensible.
Approach
I treated the data logic as a fixed asset. Each view’s calculation was ported into its own module with the aggregations, overall-filter semantics, conversion-rate formulas and channel remapping unchanged — including the parts I would have written differently. The migration was allowed to change the stack and the presentation. It was not allowed to change a definition.
That constraint is what made the migration verifiable: with logic held constant, the old and new outputs could be diffed view by view, and any difference was a bug rather than a judgement call. The visual layer changed genuinely — one plotting library out, another in, plus a design system in light and dark — but that is the layer where change is safe.
Architecture
Warehouse tables (daily and weekly grain, one pair per view) loaded through a cached loader; calculation modules that are pure transformations; a single combined endpoint that returns everything the page needs in one round trip, plus a filters endpoint. Auth is an opaque in-memory token with credentials mounted from a secret store. No writes at all — the dashboard is strictly read-only, which keeps its threat model small.
What I owned
The port, the API design, the React frontend and the design system implementation, plus the view-by-view reconciliation that proved the numbers had not moved. Deployment was data engineering’s.
Outcome
Same numbers, faster page, shareable with people who never had access to the old tool. The migration pattern — freeze the logic, move the stack, diff the outputs — became the template for the dashboard rewrites that followed.