Voltar ao início
Next.js 15ASP.NET Core 9PostgreSQLEntity Framework CoreTypeScriptTailwind CSSshadcn/uiHerokuVercel

WC26 Pool

Bolão da Copa com dois modos de jogo — palpites por partida e bracket do mata-mata — que substituiu um fluxo manual inteiro no WhatsApp.

WC26 Pool dashboard

Visão Geral

Seis amigos gerenciavam um bolão da Copa no WhatsApp: alguém postava os jogos do dia, cada um respondia com seus palpites e outra pessoa calculava os pontos na mão após cada partida. O WC26 Pool substituiu esse processo inteiro com um app web e dois modos de jogo: palpites de placar por partida com submissão imutável, e um bracket Pick'em onde cada participante escolhe os vencedores de cada fase eliminatória até o campeão — tudo alimentando um ranking unificado.

Funcionalidades

  • Agenda de jogos do dia com placar ao vivo atualizado em tempo real
  • Palpites por partida com submissão imutável — bloqueado após envio
  • Lógica de revelação: palpites ficam ocultos até todos os 6 enviarem ou o jogo começar
  • Pick'em bracket: escolha o vencedor de cada rodada do mata-mata até o campeão antes de um prazo fixo
  • Validação de consistência do bracket: um time só pode avançar se foi escolhido na rodada anterior
  • Pontuação lazy por slot: cada pick é avaliado apenas quando a partida específica daquele time encerra
  • Ranking ao vivo unindo pontos dos dois modos em uma única tabela
  • Calendário dos próximos 7 dias de jogos agrupados por data
  • Suporte a fase eliminatória com palpites de prorrogação e pênaltis
  • Design mobile-first

O Desafio

Os dois maiores desafios foram o gerenciamento de rate limit — seis usuários consultando uma API de futebol gratuita simultaneamente consumiriam a cota em minutos — e adaptar o sistema de pontuação no meio do torneio quando o grupo adicionou regras para a fase eliminatória que exigiam rastrear duração da partida e resultado nos pênaltis separadamente do tempo normal. O bracket Pick'em introduziu uma terceira restrição: pontuar os picks de forma lazy por slot, e não todos de uma vez, para refletir com precisão que o destino de cada time é determinado por uma partida diferente em um momento diferente.

Regras de Pontuação

Fase de Grupos

2 ptsPlacar exato
1 ptResultado correto (vitória / empate / derrota)
0 ptsResultado errado

Fase Eliminatória (Oitavas em diante)

3 ptsPlacar exato (tempo normal + prorrogação) + vencedor nos pênaltis correto
2 ptsPlacar exato (tempo normal + prorrogação)
1 ptTime classificado correto, independente de como
0 ptsTime classificado errado

Apenas o nível mais alto aplicável é concedido por partida — não é cumulativo. Ao palpitar empate na fase eliminatória, selecionar o vencedor nos pênaltis é obrigatório.

Principais Decisões Técnicas

Sem sistema de login

Seis participantes conhecidos tornam a autenticação desnecessária — gerenciar senhas ou fluxos OAuth seria exagero para um grupo fechado. A solução foi seleção de nome na primeira visita, persistida no localStorage com opção de troca. Zero fricção, zero cadastro.

Backend como gateway para dados de futebol

O frontend nunca chama a API de futebol diretamente. Um BackgroundService do ASP.NET Core faz polling da API externa em um intervalo inteligente e armazena tudo no PostgreSQL. Os seis usuários consultam o backend, não a API com rate limit. Os intervalos se adaptam ao contexto: a cada 20 minutos quando não há jogo próximo, a cada 2 minutos quando o kickoff está em menos de 30 minutos, e a cada 1 minuto com jogo em andamento.

Palpites imutáveis

Após enviado, um palpite não pode ser alterado — replicando a dinâmica do WhatsApp. Garantido no banco com uma constraint única em (ParticipantId, MatchId). Submissões duplicadas retornam 409. A interface bloqueia o formulário imediatamente no envio.

Adaptação da fase eliminatória no meio do torneio

As regras de pontuação foram estendidas durante o torneio sem quebrar dados existentes. O sistema foi atualizado para rastrear duração (REGULAR / EXTRA_TIME / PENALTY_SHOOTOUT), regularTimeScore e penaltyScore como campos separados. O serviço de pontuação divide a lógica pelo campo stage da partida, então jogos da fase de grupos e eliminatórios são calculados independentemente.

Pick'em bracket com pontuação lazy por slot

O bracket armazena 7 picks por participante (4 times das quartas, 2 semifinalistas, 1 campeão). Cada pick é avaliado de forma independente quando o time que ele referencia joga — não quando o bracket é fechado. O PickemScoringService é acionado após cada resultado confirmado, verifica quais picks referenciam aquele time e aquela rodada, e propaga apenas o delta para o TotalPoints. Isso evita dupla-contagem entre chamadas sucessivas de scoring e mantém o ranking preciso em qualquer momento do torneio.

Resultados

O app foi usado ativamente por todos os 6 participantes durante toda a Copa do Mundo de 2026. Os palpites por partida rodaram da fase de grupos até a final; o bracket Pick'em foi lançado nas quartas de final com prazo e pontuação progressiva. Os dois modos alimentaram o mesmo ranking sem conflitos.