The challenge
A mid-size firm was flying blind on client profitability:
- Xero held invoiced revenue by contact name
- Karbon held logged hours and job costs under different client names
- Budgets lived in a spreadsheet with no reliable link to Karbon work items
- No shared view of effective hourly rate (EHR), utilisation, or budget variance
Month-end meant exporting, VLOOKUP-ing, and hoping the Excel model didn’t break.
What I built
A practice-management analytics dashboard — the same class of tool firms pay SaaS vendors for, tailored to how this firm actually works:
| Module | What it shows |
|---|---|
| Profitability | Revenue vs hours per client, EHR, onshore/offshore split, client-group rollups |
| EHR Rate | Chart + table vs a target rate slider |
| Team Utilisation | Actual hours vs contracted capacity per team member |
| Budget Analysis | Uploaded budget vs Karbon actual cost, grouped by client or job |
| Client Mapping | Xero ↔ Karbon name matching with auto-match and manual override |
| Client drill-down | Invoices, jobs, time entries, and monthly trend per entity |
Architecture
- Production system: Karbon + Xero APIs → PostgreSQL → Express API → React dashboard
- Portfolio demo: Static React app with synthetic JSON fixtures — same UI, no backend, no real client data
The demo uses fictional names (Acme Tax Partners, Harbor Retail, etc.) and a visible Demo data badge.
Try the demo
Use the FY25/26 date preset on the Profitability page to see the full dataset. Switch to Grouped view to see the Summit Family client group rollup.