The Tourney

Tourney

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 Engineering hub: a real, at-a-glance look at what the whole system is built from. For the player-facing side — how to play, the entry form, accounts — see Player Experience. Everything below links out to a much deeper page on that specific piece.

Start with the story: how this pool went from paper brackets to a real web application →

01What makes this different from a normal bracket pool

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.

02Big picture

The entire application runs on one Amazon Web Services (AWS) server, packaged with Docker (more on that below). That single server hosts the website, the database, and a reverse proxy — a traffic router that receives every incoming visitor and forwards each request to the right place internally, and is also where HTTPS encryption is handled. There is no fleet of servers or managed cloud infrastructure behind this today — it's a deliberately lean, low-cost setup that fits a free pool with a modest number of players. The only other AWS service in use is Amazon SES (Simple Email Service), which sends account emails such as password resets. The two AI calls appear here too, at a glance — the full step-by-step detail, including the production mTLS setup, is on the Big Picture page in Engineering.

Want the full picture of how this was built? AI paths, environments, the deploy pipeline, database rollout, ESPN scoring, the visual bracket report, and every tradeoff behind those decisions — see Big Picture in Engineering.
The whole app on one server: nginx, gunicorn, MySQL and the job queue in Tourney's own box; the Spark's worker and its open-weight model in a separate private box; Claude and the external data services reached directly; an offline analytics warehouse fed from the same MySQL Browser players + admin Claude via the Anthropic API Tourney's own box dev laptop, SIT, or production nginx reverse proxy · :80 / :443 gunicorn running the Flask app — public · admin · scores · history · daily web container · python:3.11-slim calls ESPN, CollegeBasketballData, SES, and Claude directly — see right MySQL 8.0 teams · players · picks entries · scores · settings Job queue (same MySQL) scoring scheduler thread guarded — only 1 runs per host (a lock file, so a second gunicorn worker steps aside) its own always-on loop — not one HTTP request The Spark's own box private hardware The Spark's worker spark_worker.py gpt-oss:20b the open-weight model, via Ollama External data services Amazon SES email, via boto3 CollegeBasketballData.com betting odds & round dates ESPN public APIs site.api.espn.com datawarehouse/etl.py standalone script · not scheduled, not in Docker Analytics warehouse DuckDB scikit-learn dev-side, optional Google Looker Studio admin-triggered odds import direct call the Spark's worker hitting the app's API over mTLS — never the queue directly, detail below manually run, never wired into live scoring offline copy for analysis feature profiles, trained model reporting Security tools used checked on push, or at admin login Tools ruff — lint bandit — SAST pip-audit — dependency CVEs scan_secrets.py — committed secrets Admin TOTP — MFA (pyotp)
This page reflects the system as it is actually built and deployed today, based on a direct review of the source code, configuration, and deployment pipeline.