Unified data model
Four sources joined into clean fact and dimension tables — so "revenue" means the same thing in every chart on every page.
A scheduled ETL pipeline that pulls from multiple sources, cleans and normalises the data, and publishes a live dashboard the team checks daily. Manual reporting disappears — and everyone works from the same numbers.
The business ran on a weekly ritual: export from the POS, export from M-Pesa, pull the ops sheet, paste everything into one workbook, and hand-build the same charts again. The numbers were always a week stale — and two people could get two different totals for the same week.
Each stage is independently runnable and observable, so a failure at any point is caught, alerted, and recoverable without re-running the whole chain.
Scheduled jobs fetch from APIs, databases and spreadsheets on an idempotent, date-windowed basis.
Schema, null-rate and range checks run before anything lands. Failures alert instead of silently propagating.
Revenue, orders and returns are computed in a versioned model — so definitions can't drift between reports.
The BI layer reads from the model, so every chart and KPI on the dashboard traces to the same source of truth.
Every load is scored against a set of expectations. When something breaks, the pipeline alerts and halts rather than publishing numbers nobody should trust.
| Check | Table | Expectation | Result | Status |
|---|---|---|---|---|
| Row count anomaly | fct_orders | ±15% vs 7-day avg | +4.2% | Pass |
| Null revenue | fct_orders | 0% | 0.00% | Pass |
| Payment reconciliation | fct_payments | ≥99.5% matched | 99.7% | Pass |
| Freshness | stg_pos_sales | < 24h old | 6h 12m | Pass |
| Duplicate order IDs | stg_orders | 0 | 2 flagged | Review |
Four sources joined into clean fact and dimension tables — so "revenue" means the same thing in every chart on every page.
Revenue, orders, returns and channel performance — refreshed daily, filterable by period, and readable on a phone.
Contract-based checks run on every load. Bad data triggers an alert and blocks the publish — it never reaches a decision-maker.
Task failures, SLA breaches and unexpected drops post to Slack with the failing step and a link to the logs.
Historical windows can be re-run safely thanks to idempotent writes — useful when a source corrects past data.
Transformations live in version control with tests and docs, so the logic behind any number is explainable months later.
“Monday used to be report day. Now the dashboard is just... there, and it's already right.”
— Operations manager, retail deploymentI build pipelines and dashboards that run on their own — with validation strong enough that you can actually trust what you're looking at.