01 — Problem
Six Programs, Six Spreadsheets, No Coherent Story
Every workforce education program I managed generated the same data: enrollment counts, completion rates, placement outcomes, revenue collected, expenses incurred. And every program reported this data independently — a separate spreadsheet per program, maintained by a different coordinator, formatted according to whoever built it first. When leadership asked “what’s the ROI of our workforce education portfolio?” the honest answer was: we don’t know, because the data has never been unified enough to compute it. The numbers existed. The arithmetic existed. What didn’t exist was a single surface where someone could ask a comparative question — which programs are profitable, which are subsidized, and where should the next dollar of investment go.
I needed a dashboard that computed financial KPIs from raw program data and let stakeholders filter, compare, and trend across programs and cohorts in real time. Not a static report. A decision instrument.
02 — Architecture
API First, Dashboard Second
The system is a FastAPI application that serves both a REST API (for programmatic access and integration) and a server-rendered HTML dashboard (for stakeholder consumption):
Data Service Layer (Pandas + LRU Cache)
A Pandas-based computation engine calculates 7 KPIs from raw program data: total enrollments, completion count, completion rate, placement count, revenue, total cost, and ROI percentage. All computations are vectorized for performance and cached via LRU with a configurable TTL. The cache invalidates when the underlying data source is updated, not on a fixed timer — stale data is worse than a cache miss.
REST API (FastAPI)
Four endpoints serve the computed KPIs: /summary returns portfolio-level aggregates, /programs returns per-program breakdowns, /cohorts/{program_id} returns cohort-level detail, and /trends returns monthly time-series data. Each endpoint accepts filter parameters for program name, cohort ID, and date range. The API-first design means the same data powers both the HTML dashboard and any future integration — Slack bots, email reports, or executive slide decks.
Dashboard (Server-Rendered HTML + Chart.js)
The stakeholder-facing view renders KPI cards, program comparison tables, and monthly trend charts. Chart.js handles interactive line and bar charts with hover tooltips. The dashboard calls the same API endpoints as any external consumer — dogfooding the API ensures it stays complete and well-documented. Filter controls for program and date range update all visualizations simultaneously.
Test Coverage (pytest + httpx)
Automated tests cover all 4 API endpoints, edge cases (empty datasets, single-program portfolios, zero-revenue programs), and computation accuracy against hand-verified results. Tests run in CI on every commit — catching regressions before they reach the dashboard that stakeholders trust.
Key Design Decisions
Why API-first instead of a standalone dashboard? Dashboards have a single consumer: the person looking at the screen. APIs have unlimited consumers. By building the API first and the dashboard as a consumer of that API, every future reporting need — automated email digests, Slack notifications, board meeting exports — is already served. The dashboard was the first client, not the only one.
Why server-rendered HTML instead of a React SPA? The audience is 5–10 institutional stakeholders who access the dashboard weekly. A React SPA would add build complexity, client-side state management, and a deployment pipeline for a frontend that serves a handful of users on an infrequent cadence. Server-rendered HTML with progressive Chart.js enhancement delivers the same experience with a fraction of the maintenance surface.
03 — Outcomes
Measured Results
Financial KPIs
computed per program, per cohort, and across the portfolio
API Endpoints
serving the dashboard and any future integration consumer
Test Coverage
all endpoints and edge cases validated via pytest + httpx
Dashboard Load Time
with LRU-cached KPI computations and server-rendered HTML
04 — Reflection
The Dashboard Isn’t the Product — the API Is
The dashboard gets the attention. Stakeholders see charts and KPI cards and feel informed. But the API is where the lasting value lives. Six months after launch, when someone asks for a weekly email digest of program performance, the answer is a 30-line script that calls /summary and formats the response — not a new project. When the board requests a quarterly PDF report, the answer is a Jinja2 template consuming /trends data — not a manual export. Every future reporting request becomes a formatting problem rather than a data problem, because the data layer already exists and is already tested.
What I’d change: the data ingestion is currently file-based — someone uploads a CSV to trigger a refresh. Connecting directly to the source systems (LMS database, CRM export API) would eliminate the manual upload step and enable true real-time KPIs rather than refresh-on-upload KPIs. The FastAPI infrastructure can handle this; it’s a matter of writing the connectors.
“A dashboard answers the question someone is asking today. An API answers every question anyone might ask tomorrow. Build the API first, and the dashboard becomes trivial.”
Outcomes
7 financial KPIs per program and cohort; 4 REST endpoints powering dashboard and future integrations; 100% automated test coverage; <200ms dashboard load with LRU caching