Back to Work

FPL Assistant (2026): A Fantasy Premier League Decision Engine

A personal Fantasy Premier League analytics platform that turns the game's scattered data into ranked, explained decisions: a transparent projection engine, a multi-week transfer solver, live-matchday bonus and auto-sub computation, and one-click AI briefings grounded in a rules engine plus ingested creator transcripts. Built solo, end to end.

Next.js
React
TypeScript
Drizzle ORM
Neon Postgres
Better Auth
TanStack Query
Gemini
Groq
Recharts

Problem

Fantasy Premier League is a data problem disguised as a game. Expected goals, fixture difficulty, price movements, injuries, ownership, and creator opinions are spread across sources and change every week. Most tools show you raw stats and leave the judgment to you. I wanted a system that does the reasoning: projects points, weighs transfers over a multi-week horizon, and explains why, so my weekly decisions are grounded in a model instead of vibes.

Architecture

A Next.js 16 app (App Router, RSC) over Neon Postgres via Drizzle ORM, built around a pure TypeScript rules engine. A sync layer pulls teams, players, fixtures, and gameweeks from the official FPL API, and source adapters bring in Understat xG, news, and YouTube transcripts from the creators I follow. The engine is deliberately isolated from I/O so every number is deterministic and explainable, and an LLM layer (Gemini with a Groq fallback) turns that structured output into prose. Live-matchday features poll the FPL API only while matches are in play; the rest of the week the pages are static-fast.

Key Design Decisions

  • Built a transparent component projection model instead of a black box: minutes from start probability, attack from shrunk per-90 xG/xA scaled by a Poisson team model for the exact fixture, defense from clean-sheet (Poisson-zero) probability, all blended with an empirical form anchor so one bad input can't produce a silly number. Because every number decomposes into reasons, the AI layer can narrate it honestly.
  • Modeled transfers as a multi-week beam search, not a single-week pick. The solver searches plans across the horizon (roll versus move, one move versus two, take a hit versus wait), time-decays future gameweeks, and prices the option value of a banked free transfer so it only spends when a move clearly beats waiting. FPL rules (budget with individual selling prices, max three per club, squad shape, and the four-point hit) are hard constraints, not suggestions.
  • Kept the LLM grounded rather than creative. A condensed rule set synthesized from the strategy I follow is injected into every prompt, so briefings, player explanations, and draft reviews all reason the same way and stay tied to the engine's numbers and the ingested sources instead of drifting into confident guesses.
  • Isolated the live-matchday logic as pure functions: provisional bonus computed from live BPS using the official tie rules, plus predicted auto-subs and vice-captain activation. The trickiest domain math is deterministic and checkable, and polling only runs during matches so the app stays fast the rest of the week.

Tradeoffs

  • Transparency over raw accuracy. A component model I can explain beats a marginally better one I can't, because the entire point is trusting and narrating the recommendation. I anchor to empirical form to cover the model's blind spots.
  • Private by design. It is a competitive tool, so it is gated rather than public. That costs it a public demo, but sharing it would erode the edge it exists to create. I would only open it up as a paid product.
  • Pragmatic AI stack. Gemini with a Groq fallback rather than a heavier eval and observability layer, with the engine and live logic kept as pure functions so they stay deterministic and can be hardened with tests as the project grows.

Outcome

A complete, production-deployed platform that I use to run my own FPL season: dashboard signals, a player explorer with explained projections, multi-week transfer and captaincy recommendations with reasons, a chip calendar, live-matchday mode, and one-click AI briefings. It replaced a spreadsheet-and-vibes routine with model-grounded decisions, and it is one of the most complete products I have built solo, end to end, in a single focused stretch.

Lessons Learned

  • Explainability is a feature, not a nice-to-have. Designing the model so every number breaks down into reasons is what made the AI layer trustworthy instead of a confident guess.
  • The hard part of an AI product is usually the deterministic core, not the model call. The projection engine and the transfer solver are where the real work and the real edge live; the LLM just narrates them.
  • Real-time correctness is unforgiving. Matching the official live bonus tie rules exactly, and predicting auto-subs, meant treating the domain rules as a spec and isolating them as pure, checkable logic.