I created this project and this post for the **H0: Hack the Zero Stack* hackathon
(Vercel v0 + AWS Databases). #H0Hackathon*
Live demo: https://world-cup-prediction-game-psi.vercel.app
60-second walkthrough: https://youtube.com/shorts/tTPotTmi4fE
A World Cup is one of the few events where you genuinely might get hundreds of millions
of people doing the same thing at the same time. So when I set out to build a prediction
game for it, the question wasn't "can I make a CRUD app" โ it was "would the data layer
survive matchday?" That's exactly the bet H0 asks you to make: prototype on the same
Amazon DynamoDB foundation real products run on, with a v0-scaffolded Next.js
frontend on Vercel.
Here's how it came together โ and the one design decision the whole thing hinges on.
The app
Every match shows a 10,000-run Monte-Carlo forecast (win/draw/loss + a likely
scoreline) next to what the crowd actually picked. You call the result, earn points
(+5 exact score, +3 right outcome), and climb a global leaderboard that settles
against real results pulled from ESPN. No login โ an anonymous cookie makes every visitor
a player instantly.
v0 did the frontend; I owned the data layer
v0 scaffolded a genuinely good Next.js App Router app โ match cards, a pick sheet, three
tabs, SWR data fetching against /api/* โ in minutes. It even left placeholder route
handlers with a literal TODO: "wire to DynamoDB." My job was to make that real without
fighting the contract v0 generated. I dropped in the sim engine + a DynamoDB data layer
and rewrote the four routes to return the exact shapes v0's TypeScript types expected.
The UI never knew the difference โ it just started showing real fixtures.
The decision the whole thing hinges on: the leaderboard
Single-table DynamoDB is the easy part. The trap is the leaderboard. The naive design โ
"put every user in one partition, sort by points" โ is a hot partition waiting to
happen: on matchday every score update hammers one partition key.
So the leaderboard is write-sharded. A user's profile is indexed under
LB#<season>#<hash(uid) % 10> with their (zero-padded) points as the sort key. Writes
spread across 10 partitions; to read the global top-N I scatter-gather โ query the
top-N of each shard in parallel and merge. A user's rank is COUNT(points > mine) summed
across shards. It's the pattern AWS literally recommends, and it means the board scales
horizontally instead of melting.
One GSI does triple duty (all-string keys):
-
LB#<season>#<shard>โ leaderboard -
DATE#<yyyymmdd>โ today's slate -
MPICK#<matchId>โ every pick on a match (so settling fans out cheaply)
Picks bump an atomic counter on the match (that's the "crowd picked" split) inside a
transaction. On-demand capacity means I never pre-provision โ matchday spikes just work.
Shippable, not a demo
The thing that makes me happiest: it's actually deployed and serving real data โ
real 2026 fixtures, real sim odds, a real sharded leaderboard on real AWS โ and it plugs
into a daily-content funnel I already run that sends real fans to it. The whole point of
the "zero stack" is that the weekend prototype is the production foundation. This one is.
Try it: https://world-cup-prediction-game-psi.vercel.app ยท built with v0 + Vercel +
Amazon DynamoDB for #H0Hackathon.













