← Blog
Jun 20268 min readnext-jssupabasetypescriptai-developmentside-project

Building Mundial Pool: AI-assisted development for a real-life problem

How I used Claude to build a full-stack World Cup prediction app for my family — custom scoring, private leagues, no ads, and complete control over every rule.

There are prediction apps for the World Cup. Most of them have ads. Some require downloading a full sports platform just to run a pool with six people. The scoring systems are fixed. You cannot change the rules. And the experience is never quite right for the group you are actually playing with.

This World Cup cycle my family wanted to run a pool. I looked at the options, decided none of them were what I wanted, and built one instead. The whole thing took about three weeks of evenings and weekends, using Claude as the primary implementation partner. Here's what that actually looked like.

Mundial Pool landing page — Pronostica el Mundial

The decision to build instead of use

This is a side project about control. Not technical control for its own sake — the specific ability to define exactly how scoring works, who can join, and what the app looks like, without compromising on any of those things.

The scoring question was the clearest case. Most prediction apps score a correct result as +1 and an exact score as +3, or some variant of that. For the knockout stage, things get more complicated: a match can end 0-0 after 90 minutes, go to extra time, and be settled on penalties. Most apps either ignore that complexity or handle it in ways you cannot inspect or adjust. I wanted a specific set of rules:

  • +5 for an exact scoreline at 90 minutes
  • +3 for a correct result at 90 minutes (right winner or draw, wrong score)
  • +3 for an exact scoreline only after extra time
  • +1 for predicting the advancing team when the 90-minute result was wrong and it went to penalties

Those are not arbitrary numbers. They reflect how hard each outcome is to predict. I also wanted the app to ask for a tiebreak pick whenever someone predicted a draw — because in the knockout stage, a draw means someone goes through, and that prediction carries real information.

I could not configure that scoring system in any app I found. So the scoring system became the first reason to build.

How AI changed the scope of what I could attempt

I have built full-stack apps before. The overhead is always the same: auth, database schema, server actions, UI components, deployment config. Not hard, but time-consuming — and time is the thing side projects run out of first.

Using Claude as the implementation partner compressed that overhead significantly. I could describe what I needed at the product level and review what came back, rather than writing every service function from scratch. The pattern I settled into was: design the schema, describe the feature, read the output, verify the correctness, move on.

That changed what I could actually attempt in the time available. Without AI assistance, I would have built a simpler app — maybe just the match prediction form and a basic point total. With it, I built private leagues with invite codes, a leaderboard with MVP-of-the-round tracking, a knockout-stage scoring overlay, and a home page with live stats. All of it working correctly, not just stubbed.

The important qualifier: "working correctly" was my job, not the AI's. When the knockout scoring logic came back, I tested it against edge cases. What happens when a draw goes to extra time and the prediction was wrong? What happens when someone predicted the correct winner but the wrong score? The AI wrote the function. I checked whether it handled each case. That division held consistently throughout the project.

Matches page showing completed games with predictions and points earned

The technical stack

The stack is Next.js 15 App Router with TypeScript, Supabase for the database and auth, and deployed to Vercel. Nothing unusual for this type of project — the choice was about what I already knew well enough to verify generated code quickly.

The one decision worth explaining is the schema for knockout predictions. A knockout match can end in three states: 90-minute result, extra-time result, or penalty shootout. A prediction needs to capture the predicted scoreline plus, optionally, which team the user thinks advances. The predicted_winner column handles the tiebreak: if you predict a draw, you also pick who goes through. If you predict a winner by scoreline, the advancing team is implied.

The scoring function reads both the actual result data (regular time score, extra time score, penalty winner) and the prediction, then applies the rule set in order. It runs server-side and is the same function used everywhere points are calculated, so there is no risk of the leaderboard and the match card disagreeing.

Row-level security in Supabase handles the permission model: you can only read or write your own predictions, and predictions lock the moment a match kicks off. I did not write that policy from scratch — I described what it needed to enforce and reviewed the SQL that came back before applying it. The locking rule is one line, but it is the kind of thing that is easy to get subtly wrong and hard to catch after the tournament starts.

What private leagues actually needed

The original mental model for leagues was simple: share a code, join, see the standings. That worked fine for the first few days. What I had not thought through was what it meant to be the person running the league.

After the pool started, I wanted to see who the MVP was for each round, track each player's precision rate against the league average, and understand the gap between first and second place in points. None of that was in the first version. I added it one thing at a time based on what I actually wanted to look at during the tournament.

The MVP-of-the-round widget — showing who scored the most points in the most recently completed matchday — turned out to be the most talked-about feature. It creates a natural conversation in the group. Someone always wants to know who "won" Thursday's games. That feature emerged from real use, not from upfront planning.

Engendros League leaderboard with podium, MVP of the round, and full standings

The family part

Mundial Pool is running right now with a group that includes family members who have never looked at a line of code. The app needs to work for them, not just for people comfortable with half-finished side projects.

That meant a few things had to be right from the start:

The prediction UI had to be immediate. Tap a number, see the prediction save. No loading states between steps, no confirmation screens.

The scoring feedback had to be readable. After a match finishes, you should know exactly how many points you got and why. A card that says "Tu pronóstico: 2-1 · +3 resultado" is faster to read than a tooltip or a help page.

The standings had to be self-explanatory. Rank, points, exact scores, correct results. No headers that require decoding.

Dark mode had to work. Not as a theme toggle curiosity — as a real mode for people using their phones at night. The whole color system was designed for both modes from the start.

Some of that I got right upfront. A few things I fixed in the first week because I could — the advantage of owning every layer is that the feedback loop between "this is wrong" and "this is fixed" is an afternoon, not a product roadmap.

Home dashboard showing personal stats, next match to predict, and league positions

No ads, no limits

This part sounds obvious but it is worth naming. Every app I evaluated had at least one of: interstitial ads between screens, a premium tier that gated features I wanted, a scoring system I could not change, or a UX that prioritized engagement metrics over actually getting out of the way.

A custom app has none of that because it does not need to monetize anyone. The tradeoff is that I built it instead of just using it. The reason AI made that tradeoff worthwhile is that "building it" no longer meant three months of nights and weekends — it meant three weeks of focused work where I was reviewing and verifying rather than writing everything from scratch.

That is the shift. The real-life problem — run a prediction pool with my family the way I actually want to run it — became achievable in the time available. The app is exactly the thing I wanted. No compromises, no ads, no feature gates. And 144 points on the leaderboard, which I feel fine mentioning.

Why this pattern matters beyond side projects

The argument for AI-assisted development is usually framed around speed. I built this in three weeks instead of three months. That is real, but it understates what actually changed.

The more important shift is which problems become worth solving. A side project that would have been too large to finish before the tournament starts becomes something you can actually complete. The calculus changes: if you have a real problem that a custom tool would solve better than anything available, the threshold for building it drops enough to make it worth trying.

That is what happened with Mundial Pool. The problem was specific, the existing options were inadequate, and the time constraint was real. With AI handling the implementation load, I could stay focused on whether what was being built was actually correct.

The family is currently arguing about the standings. That was the whole point.