The project
A long-running free-to-play mobile fighting game had revenue reporting that drifted out of alignment with reality, drawn from several sources that disagreed with each other. The tell was a report showing a single battle pass sold for forty thousand dollars - a product that has never cost anything remotely like that. It was a currency conversion error, and it was not the only one. I reconciled attribution, transaction, user and currency data, then rebuilt the lot as a layered BigQuery architecture: filtered raw events, cleaned and currency-normalised transactions, and trusted reporting views on top.
How it fits together
- Landed GA4 events from Firebase into BigQuery on GCP, then reconciled them against mobile attribution, user and transaction data to find where the numbers diverged.
- Added a daily ingest of currency exchange rates, so every purchase resolves to the dollar amount it was actually worth on the day it happened rather than whatever rate the report ran at.
- Designed a Medallion architecture in BigQuery: bronze for filtered raw events, silver for cleaned and currency-normalised transactions, gold views for trusted reporting, feeding Looker.
- Isolated and corrected incorrect revenue events, then handled late-arriving data so daily figures settled predictably instead of shifting after the fact.
- Instrumented the pipeline with observability at every layer, so the next absurd number is caught on the way through rather than discovered on a dashboard.
- Remediated a 70TB backlog of historical data. Reprocessing that naively is a very expensive query, so the backfill was shaped to keep BigQuery costs low while the history was made accurate.
- Delivered in two weeks, with daily demos to the client as the shape of the data kept changing under us.
The trade-offs that mattered
Layered architecture over a spot fix
A one-off correction would have restored the numbers briefly and broken again. Separating raw, cleaned and reporting layers made the corrections explainable and durable.
Currency normalisation early
Normalising to a single currency in the silver layer removed a whole class of downstream discrepancies and made the reporting views trivial to reason about.
Design for handover from day one
The goal was a capability the client owned, not a dependency on me, so structure and documentation mattered as much as correctness.
What I took from it
Correct numbers were not enough. Confidence had eroded to the point where teams hesitated to act on their own data, and belief does not come back just because the figures happen to be right this week. It comes back when someone can follow the pipeline and see why they are right. I spent about as long making the corrections legible as making them, and that was the right split. It helped that the forty-thousand-dollar battle pass was a story everyone could repeat - a single absurd number did more to explain why the work mattered than any amount of describing the architecture.