Business Intelligence
from the ground up.
Client work stays confidential, so we built the evidence instead: invented-but-plausible Australian businesses, modelled from raw data all the way up to the boardroom pack. Every figure traces back to a live model, not a mock-up, and the whole portfolio rebuilds itself, identically, from a single seed.
A professional association runs its membership lifecycle.
~25k members across four tiers, monthly renewals, and a support desk fielding calls, emails and events. The tricky part: members change tier and status over time and the history has to survive (SCD2, for the practitioners), a monthly snapshot sits alongside individual renewal transactions and the two can never disagree, and a lapsed member is never counted twice. Two Power BI reports answer it: a deck that leads with the answers, then a command centre for digging deeper.
Answer deck
Dark · 7 pages · every figure reconciled to the live measureCommand centre
Dark · 6 pages to explore · cohort heatmap · sankey · Azure mapA mid-market services group closes its books.
Three entities and a monthly management pack: actuals against budget against a rolling forecast. The tricky part: a P&L that rolls up through five levels, a mid-2024 restructure that split Operations into Delivery and Support (so the same month tells a different story under current vs as-was reporting, and the model does both), and forecast versions that reconcile without double-counting. Two Power BI reports answer it: a deck that leads with the answers, then a variance workbench for digging deeper.
Answer deck
Light · 7 pages · every headline drawn as the comparison it namesVariance workbench
Light · 3 pages to explore · drillable P&L matrix · waterfall · decomposition treeBusiness intelligence, end to end.
Every page traces back through one pipeline: synthetic data engineered from scratch, modelled with intent, then reported. No black boxes, no sample datasets.
Every layer is code, not clicks: the schema, the SQL views, the semantic model, even the report pages themselves. One command rebuilds the lot from a single seed, and anyone who clones the repo gets the same 10.8 million rows, byte for byte.
Generate
A Python generator invents ~10.8M rows of realistic business history, with the insights planted deliberately so the reports have something to find. One seed, and every run rebuilds the data byte for byte.
> 36 tables · 10,784,652 rows
Load
Everything lands in Postgres on Supabase, one schema per business, with proper keys and indexes. Hand-written SQL views then shape the raw tables into reporting-ready marts.
> 8 schemas · 24 hand-written views
Model
Where the value lives: a semantic model with real measure definitions. SCD2 history, parent-child P&L rollups, snapshot and transactional grain side by side, forecast vintages that behave.
> 55 DAX measures · 3 SCD2 dimensions
Report
Answer decks that state a claim and draw it, and Explorer dashboards for the follow-up questions. Every number on the page comes from the live measure, never a mock-up.
> 4 reports · 23 pages · 2 dashboards
Code, not clicks
The schema, the marts views, the semantic model and the report definitions are all version-controlled text. If it can't be diffed, reviewed and rebuilt, it doesn't ship.
Determinism is the floor
One seed drives every random draw. The test suite generates the data twice and fails if a single byte differs, and CI does the same on every push.
Insights planted on purpose
The data isn't random noise. All 22 findings are engineered in, each with a documented drill path and a test that proves it's really there.
Reconciled before shipped
A page that looks right but shows a wrong figure is worse than no page. Checking every number against the live model caught real defects before launch, including a rate that read 100% on empty data.
Want reporting built to this standard?
The same discipline behind this portfolio, applied to your data. Book 30 minutes with the person who built every page above.