michael frith · analytics engineer · glasgow
dbt · BigQuery · GA4 · server-side tracking

Raw events in. Models people trust out.

I'm an analytics engineer who builds the layer between messy source data and confident decisions: layered dbt models, star schemas, semantic layers and tests that make sure revenue means the same thing in every report.

Now
How I build
lineage

A layered DAG, not a pile of queries

Staging views one per source, intermediate models for the awkward aggregations, marts as tables. Everything flows through ref(), so the lineage graph is real documentation: you can see exactly where any number comes from and what breaks if a source changes.

modelling

Star schemas with the grain decided first

Kimball-style facts and dimensions joined on surrogate keys, with relationships tests enforcing referential integrity. The grain of every table is stated before it's built, because most bad numbers are really grain mistakes in disguise.

semantic layer

Metrics defined once, above the marts

Revenue, AOV and repeat rate get one definition in the semantic layer, then every dashboard consumes it. No maths hidden inside report visuals, no three versions of "revenue" arguing in a meeting. I build these as Power BI semantic models over dbt marts.

trust

Tested and reconciled, not assumed

Keys carry unique and not_null, categoricals carry accepted_values, composite grains get their own tests, and singular tests reconcile the warehouse back to the source system. Legitimate mismatches run at warn severity so they're surfaced, not silenced.

Projects

ecommerce-analytics-dbt

analytics engineering

An end-to-end dbt project on the public Olist dataset: 100k real Brazilian ecommerce orders across 9 source tables, modelled into a tested Kimball star schema and used to answer real business questions, each framed as finding, evidence, impact and recommendation.

  • 22 models across staging, intermediate and marts, with 79 passing tests.
  • Surrogate keys with relationships tests enforcing referential integrity across the star schema.
  • A singular test reconciling every order's payment to items plus freight, run at warn severity because the mismatches are real payment mechanics, not bugs.
  • A four-page Power BI dashboard built on the marts, plus documented decisions about what was deliberately not built.
dbt Core · DuckDB · dbt_utils · Power BI · uv
View repo →

online-retail-clv

analytics engineering + ml

Customer lifetime value on 1M+ transactions from a UK retailer, built as a dbt project with the machine learning running inside it as Python models. The core finding: this isn't one customer base, it's two, and a single model gets both wrong.

  • 28% of customers, the wholesale core, drive 82% of revenue and buy completely differently.
  • A pooled CLV model underprices that core by ~10% and overprices one-off buyers by up to 90%.
  • Fitting BG/NBD and Gamma-Gamma per segment cut out-of-sample error on the trade core from 13% to 3.5%.
  • 42 passing tests, out-of-sample validation, and honest limitations stated throughout.
dbt Core · DuckDB · Python models · lifetimes · scikit-learn · Power BI
View repo →