โ—† Case study ยท Product design & build ยท 2026

THE POOL

A World Cup fantasy pool for 27 friends and family: everyone drafts twelve national teams, real match results score the points, and the highest total takes the pot. I built it to replace the spreadsheet we used in 2022, then ran it for the full tournament: 104 matches scored automatically, a daily digest email, and a 148 to 148 finish settled by a tiebreaker.

27 entrants $2,700 pot 11 days from idea to launch
The Pool home screen: final leaderboard of 27 entrants under the archived banner
27
Entrants
104
Matches scored
1,679
Points itemized
34
Morning digests
169
Commits
199
Tests

โ—† The game

Draft twelve teams, one from every tier.

  • 01

    Draft

    All 48 World Cup teams are ranked into 12 tiers of four by their betting odds. Each entrant picks one team from every tier: a roster of twelve, from a favorite like Spain down to a lottery ticket like Iraq.

  • 02

    Score

    Your teams earn points from real results: wins and draws in the group stage, more for advancing, the most for wins deep in the knockout bracket.

  • 03

    Root for the underdogs

    Teams in tiers 7โ€“12 also score a point per goal, and any win over a higher-tier team pays an upset bonus. Even a doomed pick can earn its keep.

  • 04

    Win the pot

    Picks locked at kickoff and went public. $100 a head, with the pot split between the top two overall and the two group-stage leaders.

T1The elite๐Ÿ‡ช๐Ÿ‡ธ๐Ÿ‡ซ๐Ÿ‡ท๐Ÿด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ๐Ÿ‡ง๐Ÿ‡ท
T2Contenders๐Ÿ‡ฆ๐Ÿ‡ท๐Ÿ‡ต๐Ÿ‡น๐Ÿ‡ฉ๐Ÿ‡ช๐Ÿ‡ณ๐Ÿ‡ฑ
T3Dark horses๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ณ๐Ÿ‡ด๐Ÿ‡จ๐Ÿ‡ด๐Ÿ‡บ๐Ÿ‡พ
T4Solid๐Ÿ‡ฒ๐Ÿ‡ฆ๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ‡จ๐Ÿ‡ญ๐Ÿ‡ฏ๐Ÿ‡ต
T5Outsiders๐Ÿ‡ฒ๐Ÿ‡ฝ๐Ÿ‡ญ๐Ÿ‡ท๐Ÿ‡ช๐Ÿ‡จ๐Ÿ‡ธ๐Ÿ‡ณ
T6Longshots๐Ÿ‡น๐Ÿ‡ท๐Ÿ‡ธ๐Ÿ‡ช๐Ÿ‡ฆ๐Ÿ‡น๐Ÿ‡จ๐Ÿ‡ฆ
T7Deep longshots๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ๐Ÿ‡จ๐Ÿ‡ฎ๐Ÿ‡จ๐Ÿ‡ฟ๐Ÿ‡ต๐Ÿ‡พ
T8Faint hope๐Ÿ‡ช๐Ÿ‡ฌ๐Ÿ‡ฌ๐Ÿ‡ญ๐Ÿ‡ฉ๐Ÿ‡ฟ๐Ÿ‡ฐ๐Ÿ‡ท
T9Minnows๐Ÿ‡ง๐Ÿ‡ฆ๐Ÿ‡น๐Ÿ‡ณ๐Ÿ‡ฆ๐Ÿ‡บ๐Ÿ‡ฎ๐Ÿ‡ท
T10Lottery๐Ÿ‡จ๐Ÿ‡ฉ๐Ÿ‡ธ๐Ÿ‡ฆ๐Ÿ‡ฟ๐Ÿ‡ฆ๐Ÿ‡ต๐Ÿ‡ฆ
T11Lottery๐Ÿ‡จ๐Ÿ‡ป๐Ÿ‡ถ๐Ÿ‡ฆ๐Ÿ‡บ๐Ÿ‡ฟ๐Ÿ‡ณ๐Ÿ‡ฟ
T12Pure lottery๐Ÿ‡ฎ๐Ÿ‡ถ๐Ÿ‡ฏ๐Ÿ‡ด๐Ÿ‡จ๐Ÿ‡ผ๐Ÿ‡ญ๐Ÿ‡น

All 48 teams as seeded for 2026, in betting-odds order within each tier. Tiers 7โ€“12 earn the per-goal bonus. Hover a flag for the country.

โ—† The brief

The 2022 pool was a spreadsheet. It had two problems.

The last World Cup, this pool ran on a Google Form and a hand-scored spreadsheet. Everything was manual: picks came in by form, scores were typed in by hand, and standings went out whenever the commissioner got around to it. And because everyone drafted from the same short list of favorites, the scores bunched together. Half the field sat within a few points of each other, and a Tuesday afternoon group match mattered to nobody.

The 2026 version fixed both problems with the rules themselves: the tier draft spreads everyone across all 48 teams, a live data feed does all the scoring, and the underdog bonuses keep even a lost cause worth watching. It had to be ready before kickoff on June 11. Picks went live eleven days after the first commit.

20222026
Picks by Google FormDrafted on the site, tier by tier
Scored by hand in a spreadsheetScored automatically every 3 minutes
Standings emailed around, eventuallyLive leaderboard, plus a 7am digest
Everyone picked the same favoritesAll 48 teams owned by someone
Half the field within a few pointsA 55-point spread, tie only at the top

โ—† The design

Built for three moments, all of them on a phone.

Nobody was going to sit at a computer for this. People check the pool in bed, at work, and in front of the TV, so every screen was designed for a phone and for a specific moment of the day.

Draft night

Pick twelve teams in one sitting without opening a rulebook in another tab. The full tier sheet fits on one screen.

Morning coffee

What happened yesterday, who moved, and what's on today. One email at 7am, no login required.

Match night

Live scores with the stakes attached: whose teams are playing and what each goal is worth on the board.

Tier list screen: 12 odds-based tiers of four teams each
The draft board. All 48 teams by tier, and who picked each one, public once the tournament locked.
Matches screen: full schedule day by day with final scores
The schedule. Every match with kickoff times in your timezone, updating live while games were on.
The champion's entry page: 12 teams with per-game point breakdowns
The scorecard. Picks went public at lock. This is the champion's entry, with each game's points spelled out (gm 7: semifinal win +7).
Check Math screen: every team's full scoring audit
Check Math. Every point for every team, explained in plain English, so anyone could verify their own score.

โ—† The season

Six weeks of standings, one snapshot a night.

The system saved a copy of the standings every morning, 44 snapshots in all. The tiers did what they were designed to do: the lead changed hands among eight different entrants. Miller led for 19 days, longer than anyone. Michael carried the lead into the final with no teams left alive. And Zach, 26th of 27 on June 13, rode Spain back up the board and won the pool on a tiebreaker, 148 to 148.

Zach F. ยท finished 1st ๐Ÿ†Jeff S. ยท finished 2ndMichael C. ยท finished 4thMiller I. ยท finished 8ththe other 23
151015202527Jun 12Jun 19Jun 26Jul 3Jul 10Jul 20knockouts โ†’Zach ยท ๐Ÿ† 1stJeff ยท 2ndMichael ยท 4thMiller ยท 8thZach: 26th, June 13

Every line is a real entrant; hover to explore. Nightly ranks, June 12 to July 20.

Final standings as a table
#EntrantTotalUnderdogUpset
1Zach F. ๐Ÿ†14850.520
2Jeff S. ๐Ÿฅˆ1485017
3Drew K.1434923
4Michael C.1405620
5Dan S.1364317
6Adam H.13162.525
7Arnie S.128.530.514.5
8Miller I.1286023
9David S.12856.519
10Matthew F.127.548.514.5
11Charlie F.12761.517
12Josh B.125.544.518.5
13Evan S.1204719
14Jack K.1204310
15John I.1165720
16Tim H.115.546.518.5
17Mike S.113.550.519.5
18Tom W.113.545.513.5
19Aaron F.112.540.512.5
20Nick F.11247.512
21Travis R.110.556.524.5
22Paul B.108.535.59.5
23Cooper B.100.546.516.5
24Phil P.98.539.510.5
25Pete K.95.539.510.5
26Bradley B.94.536.516.5
27David R.933516

โ—† The machine

Every three minutes, for six weeks.

One scheduled job ran everything: pull the latest results, rescore the pool, and close each day with a recap. The order was deliberate, with standings saved before new results arrived so "who moved today" had a baseline, and the write-up last, after every number was checked.

Pull the results

Every three minutes, the system asks a live sports-data feed for the latest scores, schedules, and betting odds.

Rescore everything

Every entry is rescored from zero on every pass: 1,679 itemized points, checked by 199 automated tests, so the totals can never quietly drift.

Rate everyone's chances

A simulation plays out the rest of the tournament 10,000 times, using live betting odds, and rates each entry's shot at winning.

Write the recap

When the day's last match ends, the verified stats go to Claude, an AI model that writes the morning recap in a pundit's voice. It phrases the numbers; it can't add any.

Deliver at 7am

The digest emails everyone who opted in: results, movers, upsets, and today's schedule. No login required.

Back itself up

Every night the entire database is compressed and emailed to me. For a pool this size, an inbox is a perfectly good backup.

โ—† The AI

The pundit was a language model on a short leash.

The morning digest was written every night by Claude, under one hard rule: it could only narrate numbers the scoring engine had already verified. Across 34 digests it never misreported a score. Here's how it called the final:

"At the top it could not be tighter. Zach F. leads on 148, dead level with Jeff S. also on 148, with Drew K. right behind at 143. That is a two-man photo finish for the crown. [โ€ฆ] Spain are champions and the group table is basically decided by whoever picked them. That's the tournament, folks."

Morning Digest, day 34, July 19, 2026. Headline: "Zach F. had a day"
  • Verified stats only. The model phrases facts; it never sources them.
  • A narrative failure can't block delivery: if the model errs, the digest ships with just the box score.
Morning Digest screen: day 34 final recap with narrative and box score

โ—† The odds

"What are my chances?", answered honestly.

After every match, a simulation replayed the rest of the tournament 10,000 times and scored all 27 entries in each imaginary run, using the same engine as the real leaderboard. Team strength started from the bookmakers' pre-tournament odds and repriced as results came in, and games about to kick off used the live betting line.

๐Ÿ”ฅ Front-runner ๐Ÿ’ช In the hunt ๐ŸŽฒ Live ๐ŸŒฑ Long shot ๐Ÿ’€ No shot ๐Ÿ”’ Clinched

Every entry wore one of these ratings on the leaderboard. The design rule: the middle four are deliberately coarse, never a fake-precise percentage, and only the two extremes were ever stated as fact. No shot meant mathematically eliminated; Clinched meant first place was locked no matter what.

Going into the final, simulation gave way to arithmetic. With only two outcomes left, the engine played both out exactly: if Spain won, Zach took the pool on a tiebreaker at 148 to 148. If Argentina won, Michael jumped from fourth to champion at 151. Spain won.

โ—† Security & trust

Twenty-seven people's picks, money, and pride. Treated accordingly.

A pool among friends still handles real money and private picks, so it got the same care as a real product.

No passwords, ever

Sign-in is a one-time email link. Nothing to store, nothing to leak, nothing for 27 people to forget.

Privacy lives in the database

Who can see what is enforced by the database itself, not just the interface. Picks stayed hidden until the tournament locked, and outsiders got nothing even if they queried the database directly.

Secrets stay on the server

The browser never held anything sensitive. Admin credentials lived server-side, the scheduled jobs required their own secret, and the developer backdoor didn't exist outside my machine.

It watched itself

A monitor compared every incoming result against the recomputed board and would have emailed me on any mismatch. It stayed quiet all tournament.

It could survive a disaster

The database plan had no built-in backups, so a nightly job emailed me a full copy. The restore plan was an inbox search.

It shut down cleanly

At the end: the schedules removed, a check that no secrets ever entered the public code, names shortened for privacy, and a final audit that outsiders can read nothing personal.

โ—† The finish

148 โ€“ 148.

๐Ÿ† Zach F. Champion on the underdog-points tiebreaker, which was written into the rules on day one and finally needed on day 39. He was in 26th place on June 13.
90100110120130140150148 ยท Zach & Jeff93

Final totals for all 27 entrants: a 55-point spread, settled by a tiebreaker only at the very top. In 2022, half the field finished within a few points of each other. Hover for names.