Welcome
A March Madness pool where you draft individual college basketball players and coaches instead of picking which teams win — so your score depends on how the players you chose actually perform, not just who advances. This page is the front door: what the pool is, and a real, at-a-glance look at what it's built from. Everything below links out to a much deeper page on that specific piece.
A standard bracket pool asks you to predict game winners — get the Final Four right and you win, regardless of how any individual player does. This pool works differently: you draft 22 individual players and coaches across five groups (seeded 1–4, 5–8, 9–12, 13–16, and head coaches), and you earn points based on their actual performance in real games — a player's real scoring stats, a coach's real team wins. That means two people who agree on every single game winner can still land on completely different scores, because they drafted different players from those same teams. It rewards knowing the players, not just the bracket.
This isn't a spreadsheet with a form bolted on. It's a real, live web application: a hosted server, a real database, live data pulled continuously from ESPN, two different AI models generating daily commentary, and a separate analytics pipeline exploring what predicts a good draft pick. The two diagrams below show every real piece — the same names used throughout the rest of this site, not simplified stand-ins. One name worth flagging up front so it doesn't read as a typo: "the Spark" below is real, private hardware — a physical machine on the developer's own network — not the Apache Spark data-processing framework.
flowchart LR
BROWSER["Browser
player or admin"] --> APP
subgraph AWS["AWS EC2 — one server"]
APP["Flask web app
(Tourney)"]
DB[("MySQL database
teams · players · picks
entries · scores · settings")]
APP <--> DB
end
APP -->|"pulls the tournament field,
rosters, and box scores"| ESPN["ESPN public APIs"]
DB -.->|"offline copy for analysis,
never wired into live scoring"| WH[("Analytics warehouse
DuckDB")]
style AWS fill:transparent,stroke:#c65a2e,stroke-width:2px
flowchart LR
APP2["Flask web app
(Tourney)"] -->|"hosted foundation model,
pay per token"| CLAUDE["Claude
via the Anthropic API"]
APP2 -->|"private Tailscale network"| SPARK["The Spark
gpt-oss:20b, served by Ollama"]
APP2 -->|"account emails"| SES["Amazon SES"]
style SPARK fill:transparent,stroke:#c65a2e,stroke-width:2px
Both diagrams show real components with their real names — nothing here is a simplified fiction. The table below is the click-through map: every named piece links to the page that covers it in full engineering depth.
| Component | What it is | Read more |
|---|---|---|
| Flask web app, MySQL, AWS EC2 | The one-server hosting setup: how it's packaged, deployed, and kept running | How It's Built → |
| ESPN public APIs | The real, live source for the tournament field, rosters, and every score | Player Experience → |
| Claude & the Spark | The same daily-commentary task, run through a hosted model and a self-hosted open-weight model, side by side | AI: Foundation vs. Open-Weight → |
| Amazon SES | Sends account emails such as password resets | Player Experience → |
| Analytics warehouse (DuckDB) | A separate, offline copy of the data used to study what predicts a good draft pick — deliberately kept apart from live scoring | Data Warehouse → |
Each entry has 22 picks spread across 5 groups:
| Group | Picks | Scoring |
|---|---|---|
| Seeds 1–4 | 6 | Actual game points |
| Seeds 5–8 | 5 | Actual game points |
| Seeds 9–12 | 4 | Actual game points |
| Seeds 13–16 | 3 | Actual game points |
| Coaches | 4 | 10 pts per team win |
Rounds:
This pool is a real system built end to end — live ESPN data, a working CI/CD pipeline, a self-hosted AI model on a private network, a from-scratch analytics warehouse. Each card below is a 90-second read on one part of it, with the engineering detail underneath for anyone who wants to verify a claim against the code.
Hosting, containers, CI/CD, how ESPN scores become standings, the visual bracket, known tradeoffs.
The smart entry form, live game links, accounts, bracket comparisons, historical simulation, the two APIs, email.
Claude vs. a self-hosted model on a private Tailscale network — the same task, run both ways, compared.
What an admin can actually do — settings, data loading, user management, the daily-update eval.
Every table, what it's for, and how it's kept accurate against the running schema.
A separate DuckDB warehouse for predictive analysis, kept apart from the live database on purpose.
Auth, credential handling, and honestly-tracked gaps.
A tour of every page in the site, public and admin.
The real Architect → Developer → Qcoder → Architect → CI/CD pipeline every change goes through, with a checkable pointer for each stage.