BeachTennis Manager
Gestão completa de torneios
Aplicativo PWA para organizar torneios de Beach Tennis do início ao fim. Crie torneios, cadastre jogadores, acompanhe partidas em tempo real e compartilhe resultados via QR Code — tudo do celular, com sync multi-dispositivo no plano PRO.
O problema
Organizar um torneio de Beach Tennis na praia é caótico: anotar resultados em papel, calcular rankings de cabeça, avisar jogadores sobre próximas partidas por WhatsApp em grupo gigante. Ao vento, com sol forte, com os dedos cheios de areia, tentando fazer chave eliminatória num caderno.
Precisávamos de uma ferramenta rápida de usar em pé na quadra, que calculasse rankings automaticamente, que sobrevivesse à oscilação de sinal da praia, e que pudesse compartilhar resultados ao vivo com espectadores sem que eles precisassem instalar nada. O BeachTennis Manager nasceu pra isso.
Funcionalidades
4 formatos de torneio
Rei/Rainha da Praia (Round Robin em 3 fases), Super 8, Chave de Simples (4-64 jogadores) e Chave de Duplas (4-64 duplas). Cada formato com sua lógica de geração de partidas e cálculo de ranking.
Ranking em tempo real
Classificação automática por vitórias, saldo de games e games vencidos. Critério de desempate técnico configurável. Recalcula a cada placar inserido.
Sync multi-dispositivo
No modo PRO, os dados são sincronizados na nuvem via Redis. Organize do celular, acompanhe do tablet — tudo em tempo real, sem precisar recarregar.
Compartilhamento via QR Code
Gere um QR Code único para cada torneio. Jogadores e espectadores acompanham ao vivo pelo celular sem precisar instalar nada nem fazer login.
Dark mode
Tema escuro para usar na quadra sem ofuscar com sol forte. Design mobile-first pensado para uso em pé, com uma mão, com os dedos cheios de areia.
Instale como app
PWA instalável direto no celular, sem precisar de App Store ou Play Store. Acesso rápido pela tela inicial. Funciona offline para visualização.
Decisões técnicas
As escolhas mais consequentes do projeto não foram "qual stack" — foram trade-offs explícitos sobre plataforma, modelagem e como evitar generalização precoce.
Por que PWA em vez de app nativo?
Nenhum requisito do produto exigia API exclusiva de iOS ou Android (Live Activity, Apple Watch, integração com saúde). Em compensação, todos os requisitos exigiam atualização rápida (deploy em minutos), compartilhamento via link (espectadores acompanham sem instalar) e custo zero de operação. PWA cobriu tudo, App Store cobraria 30% e adicionaria fila de revisão.
Por que Redis em vez de Postgres?
O padrão de acesso é orientado a chave. As queries que rodam o tempo todo são "me dá o torneio inteiro X". Não há cross-tenant analytics, não há full-text search, não há agregações complexas. Redis com chaves estruturadas como tournament:{userId}:{tournamentId} resolve isso em microssegundos, sem migration, com backup trivial.
Por que discriminated unions para os formatos?
A primeira tentativa foi uma única classe Tournament com flags por formato. Em duas semanas o arquivo tinha 800 linhas e era impossível de manter. A segunda tentativa, com discriminated unions e arquivos isolados por formato, deixou cada lógica encapsulada e o compilador me força a tratar exaustivamente cada caso.
Por que Server Actions em vez de API REST?
Para 90% dos casos, não precisamos de uma API. Server Actions do Next.js permitem que componentes cliente chamem funções server diretamente, com tipo, sem JSON manual. Menos código, menos bugs, menos mental overhead. As poucas APIs REST que sobraram são para webhooks (Clerk) e endpoints públicos (compartilhamento via QR).
Formatos suportados
Cada formato é modelado como um tipo separado em TypeScript, com lógica isolada em sua própria pasta. Isso permitiu que cada formato evoluísse independentemente sem o risco de uma mudança em um afetar os outros.
Rei/Rainha da Praia
Round Robin em 3 fases progressivas: grupos de 4, semifinais cruzadas (1ºA vs 2ºB) e final em chave eliminatória. Classificação dentro do grupo por vitórias, saldo de games e games vencidos, com desempate por confronto direto. Ideal para eventos sociais com 16-32 jogadores.
Super 8
Round Robin com exatamente 8 jogadores, todos contra todos. Geração via algoritmo do círculo: cada jogador joga 7 partidas. O vencedor é quem somar mais games no acumulado. Máxima competição em mínimo de tempo — geralmente cabe em uma manhã ou tarde.
Chave de Simples
Eliminação direta de 4 a 64 jogadores. Suporte a cabeças-de-chave (seeds) com distribuição padrão (standard seeding) — o 1º cabeça encara o último, o 5º encara o 4º. Garante que os melhores só se encontram nas fases finais. Geração da chave em árvore binária, com avanço automático do vencedor.
Chave de Duplas
Mesma estrutura da Chave de Simples, mas com pares. Cada participante é uma dupla. Suporta cadastro de duplas pré-formadas ou geração de duplas a partir de uma lista de jogadores. Útil para torneios sociais onde quem vai joga em dupla com quem.
Planos
Modelo freemium — começa grátis e evolui conforme a necessidade.
FREE
- 1 torneio
- Todos os formatos
- Ranking automático
- Uso local apenas
PRO
- Torneios ilimitados
- Sync na nuvem
- Backup e restauração
- Exportar participantes
MAX
- Tudo do PRO
- Exportar PDF
- Compartilhar com espectadores
- Inscrições com pagamento
- Lista de presença
- Sorteio de brindes
Stack técnica
Construído com Next.js App Router e TypeScript no frontend, Clerk para autenticação, Redis (Vercel KV) para sincronização na nuvem e Serwist para PWA. Server Components por padrão, Server Actions para mutations, JSON-LD em todas as páginas para SEO. Design responsivo com Tailwind CSS e componentes acessíveis via Radix UI.
O que aprendemos
Server Actions matam REST APIs em projeto pessoal
Para a grande maioria das mutations, não precisamos de uma rota de API. Função server-side direta do componente cliente, com tipo, sem JSON manual. Menos boilerplate, menos bug.
Redis cobre mais do que parece
Para SaaS solo onde o acesso é por chave, Redis é mais barato, mais rápido e mais simples que Postgres. A regra que aplicamos é: Redis quando é por chave, Postgres quando é por relacionamento ou agregação cross-tenant.
PWA não é "app de pobre"
A grande maioria dos usuários do BeachTennis nunca vai abrir uma App Store para baixar um app de torneio. O navegador é o ponto de entrada deles. PWA é o app deles, e o efeito "instalar pela tela de início" funciona bem na prática.
Leia mais sobre o projeto
A stack completa: Next.js, Clerk e Redis
Por que cada peça da stack foi escolhida e como elas se integram.
Modelando 4 formatos de torneio em TypeScript
A história de tentar generalizar e por que voltamos a discriminated unions.
PWA vs app nativo: por que escolhemos PWA
A análise honesta de trade-offs, requisitos cobertos e quando mudaríamos de ideia.