Portal público
18 rotas abertas
- /
- /eventos
- /eventos/:slug
- /eventos/:slug/inscrever
- /calendario
- /rankings
- /resultados
- /noticias
- /galeria
- /pilotos
- /pilotos/:id
- /empresa
- /sobre
- /blog
- /parceiros
- /contato
- /termos
- /privacidade
SaaS · Em produção
A plataforma que tirou a gestão de um campeonato de motocross da planilha e do grupo de WhatsApp — inscrição, pagamento, documentação, resultado e ranking no mesmo lugar.
O problema
Organizar uma etapa de motocross envolve muito mais do que largar as motos. Cada piloto precisa se inscrever numa categoria, provar que tem licença e seguro em dia, pagar a taxa, receber um número, correr, e ter o resultado somado à pontuação da temporada. Multiplique isso por dezenas de pilotos, mais de uma dúzia de categorias e várias etapas.
Antes do Portal MX, esse fluxo vivia espalhado entre planilhas, mensagens de WhatsApp e comprovantes soltos. Os pontos de ruptura eram sempre os mesmos:
A solução
O Portal MX é uma aplicação única com duas faces. A pública, onde o piloto se inscreve e o público acompanha o campeonato. E a administrativa, onde a organização conduz a operação da temporada.
18 rotas abertas
14 módulos, acesso por papel
Arquitetura
É uma SPA em React servida como estático, falando direto com o Supabase. Não existe backend próprio no meio do caminho: a autorização mora no banco, em Row Level Security, e o mesmo conjunto de regras vale para qualquer cliente que se conecte.
Decisões
Autorização
Esconder um botão no front-end não é segurança. Como o navegador fala direto com o banco, toda regra de quem-vê-o-quê está escrita em policies de RLS no Postgres — 72 delas. Um piloto lê a própria inscrição porque a policy permite, não porque a tela não mostrou o resto.
Papéis
superadmin, admin, organizer e pilot. O papel vem do perfil do usuário e é lido dentro das policies, então a mesma consulta devolve conjuntos diferentes conforme quem pergunta. As rotas do admin ainda são protegidas no cliente, mas isso é conveniência de navegação — não é a barreira.
Schema
São 22 migrations numeradas, do schema base às permissões e ao fluxo de inscrição. O banco é reconstruível do zero em ordem, e cada mudança tem um arquivo com data e intenção — o que evita o clássico "funciona na minha máquina" quando o schema é editado direto no painel.
Dados no cliente
Quase todo o estado da aplicação é, na verdade, estado do servidor. Delegar cache, revalidação e loading ao React Query eliminou a necessidade de um store global e manteve as telas de listagem consistentes sem sincronização manual.
Formulários
Inscrição de evento tem muitos campos condicionais. Com Zod descrevendo o formato e React Hook Form ligando ao formulário, a regra de validação fica em um lugar só e o erro aparece no campo certo, sem cadeia de ifs espalhada pelo componente.
Números
Números apurados diretamente no código-fonte do projeto. Não incluí métricas de uso (pilotos cadastrados, inscrições processadas) porque essas eu não consigo verificar aqui.
Aprendizados