Overview
PitchIQ is a Premier League dashboard: the live table, recent results, upcoming fixtures, and a page for every match. Each upcoming fixture gets a home, draw, and away forecast computed in Python, and every forecast states the reasoning behind it and where it stops being reliable. There is no sign-in and no mock data; every figure on screen was fetched, validated, and stored, and says when.
The hard part
Forecasting football honestly. A plain Poisson goals model gets low scores wrong, so the predictor implements Dixon-Coles: a correction for results like 0-0 and 1-1, ratings shrunk toward the league average until a team has enough matches, separate home and away strengths only where the data supports them, and more weight on recent results. It is written as pure functions with no I/O, with 31 tests on the model alone.
The maths is fast enough to run on every read. Scoreline probabilities are built recursively instead of from factorials, so a full 11×11 grid costs a few microseconds, and forecasts never need to be stored.
Highlights
- A page view never reaches the API. Public endpoints only read the database. A daily sync is gated by freshness, a database lock, and a per-run request cap, retries only what is worth retrying, and rolls back to the last good data on failure.
- Validated at every boundary. The Python service maps provider responses into its own types, and the frontend checks every API response with Zod before it renders.
- Committed snapshot, automatic redeploys. The daily job commits the SQLite file only when it changed, which redeploys both the app and the API. The build fails on purpose rather than ship empty pages.
- Two deploys from one repo. Next.js and a FastAPI service on Vercel's Python runtime.
- 212 tests, 141 of them on the Python service.
