@audit — Calendário Trial vs Coordenador + Formulários de Cadastro
Data: 2026-03-30
Status: Pendente avaliação — NÃO implementar sem aprovação individual
Nota: Vários itens serão endereçados pela migração Upstash Redis (rate limit, lockout). Avaliar trade-offs antes de agir.
PARTE A — Calendário Trial vs Coordenador
A1. Inconsistências Backend (Edge Functions)
| # | Severidade | Achado | Detalhe |
|---|---|---|---|
| 1 | Atenção | BRT duplicado no Trial, ausente no Coordenador list_mes | Trial calcula hojeBrasil/anoCorrente no escopo global e usa em list_proximos. Coordenador calcula BRT dentro de list_proximos mas NÃO em list_mes. Em list_mes ambos usam new Date(ano, mes, 0) que depende do timezone do runtime Deno (UTC). Resultado: ultimoDiaMes é correto porque é cálculo de calendário puro, mas é inconsistente no padrão. |
| 2 | Atenção | Trial list_proximos não preserva data_fim em fases por nível | Fases por nível em list_proximos geram entradas individuais sem data_fim nos items expandidos, enquanto o coordenador preserva data_fim. O trial perde o range display nas fases por nível da sidebar. |
| 3 | Atenção | Trial busca TODAS olimpíadas ativas; Coordenador filtra por escola_olimpiadas | By-design. Porém, se o Trial criar eventos manuais vinculados a uma olimpíada, e depois migrar para coordenador, os eventos manuais ficam visíveis pois são filtrados por escola_id, não por olimpíada aderida. Não é bug, mas pode confundir. |
| 4 | Atenção | Trial não importa registrarLog | Read-only, não precisa de CUD logs. Porém, get_trial_info poderia ser monitorada. Baixa prioridade. |
| 5 | Recomendação | Duplicação massiva (~300 linhas) entre as duas Edge Functions | Qualquer fix num precisa ser replicado no outro. Risco alto de drift. Candidato a extração para _shared/calendario-helpers.ts. |
A2. Inconsistências Frontend (Hooks + Componentes)
| # | Severidade | Achado | Detalhe |
|---|---|---|---|
| 6 | Atenção | TIPO_MAP divergente | Trial hook não mapeia atividade → evento. Se o backend retornar tipo: 'atividade' (legado), o Trial mostrará tipo raw sem cor/label. Fix: 1 linha. |
| 7 | Atenção | dashboard-trial.tsx é um monolito de 907 linhas | Duplica helpers que já existem em calendario-olimpico/helpers.ts. Correções visuais no calendário do coordenador NÃO se propagam para o Trial. |
| 8 | Recomendação | Trial hook não expõe refetchOnWindowFocus: false explicitamente | Herda do QueryClient global. OK mas implícito. |
| 9 | Critico | Trial getDaysInMonth ignora data_fim | Eventos com range que começam antes do mês não aparecem nos dias intermediários. Relacionado ao item #2 (fases por nível perdem data_fim). |
A3. Tabela de Paridade Funcional
text
Feature | Coordenador | Trial | Status
---------------------------|-------------|----------|--------
list_proximos | ✅ | ✅ | OK
list_mes | ✅ | ✅ | OK
create_manual | ✅ | ❌ | By design
update_manual | ✅ | ❌ | By design
delete_manual | ✅ | ❌ | By design
get_trial_info | ❌ | ✅ | By design
Filtro por olimp. aderidas | ✅ | ❌ (all) | By design
TIPO_MAP 'atividade' | ✅ | ❌ | BUG (#6)
Fases por nível data_fim | ✅ | ⚠️ parcial| BUG (#2)
Logging (registrarLog) | ✅ | ❌ | Gap (#4)
Código compartilhado | helpers.ts | inline | Debt (#7)PARTE B — Formulários de Cadastro e Infra de Tokens
B1. Cadastro Trial (/cadastro/trial)
| # | Severidade | Achado | Detalhe |
|---|---|---|---|
| 10 | Critico | Sem validação algorítmica de CNPJ | Backend apenas verifica length === 14. Aceita 00000000000000. Frontend idem. Já existe isValidCNPJ() em _shared/cnpj-validator.ts — basta importar no backend e replicar no frontend. |
| 11 | Critico | Rollback parcial sem transação | Se a criação do usuário falha, a escola é deletada mas escola_assinaturas pode ficar órfã. Verificar se FK tem ON DELETE CASCADE. |
| 12 | Atenção | Rate limit em memória (Map) | Reseta a cada cold start. Será resolvido pela migração Upstash Redis — NÃO implementar fix paliativo. |
| 13 | Atenção | nome_completo do usuário recebe o nome da escola | Impacta logs, sidebar, display de responsável. Requer campo adicional no formulário. |
| 14 | Recomendação | Frontend não mostra erro se createTrial retorna null mas error já mudou | Frágil mas funciona na prática. |
B2. Cadastro Completo (/cadastro/:token)
| # | Severidade | Achado | Detalhe |
|---|---|---|---|
| 15 | Critico | TOCTOU entre validate_token e complete_signup | Sistema é seguro (segunda verificação protege), mas UX é ruim: usuário preenche formulário inteiro e só descobre token usado ao submeter. |
| 16 | Atenção | complete_signup tipo create não cria assinatura | By-design (admin ativa manualmente), mas sem feedback no frontend. |
| 17 | Atenção | generate_link hardcoda URL de produção | https://olp.digital hardcodado. Usar req.headers.get('origin') ou env var. |
| 18 | Recomendação | Notificação admin com N+1 queries | Loop sequencial de INSERTs. Poderia ser batch. |
B3. Infra de Tokens (cadastro_tokens)
| # | Severidade | Achado | Detalhe |
|---|---|---|---|
| 19 | OK | Cleanup automático funciona | maintenance-cron deleta tokens expirados. ✅ |
| 20 | OK | Token é crypto-random 256 bits | Entropia suficiente. ✅ |
| 21 | Atenção | select("*") retorna token completo ao frontend | Menor superfície = melhor. Usar select explícito. |
PARTE C — Plano de Correção Priorizado
⚠️ Atenção: Avaliar cada item individualmente. Itens marcados com 🔒 dependem da migração Redis.
Prioridade 1 (Critico) — Avaliar para próxima sprint
- CNPJ validation algorítmica — Importar
isValidCNPJ()no backend + replicar no frontend. Baixo risco, alto impacto. - TIPO_MAP sync — 1 linha no hook Trial. Zero risco.
- Fases por nível
data_fim— Preservardata_fimno Triallist_proximos. Baixo risco.
Prioridade 2 (Atenção) — Sprint atual ou próxima
- Rollback completo no
trial_create— Verificar FK CASCADE primeiro. nome_completodo usuário — Adicionar campo "nome do responsável" (4→5 campos).generate_linkURL dinâmica —req.headers.get('origin')ou env var.
Prioridade 3 (Recomendação/Dívida técnica) — Backlog
- Extrair helpers compartilhados entre
dashboard-trial.tsxecalendario-olimpico/helpers.ts. - Extrair lógica compartilhada entre Edge Functions de calendário para
_shared/calendario-helpers.ts. - Notificação admin batch (substituir loop N+1).
select("*")→ select explícito nos queries de token.
🔒 Depende de Upstash Redis (NÃO implementar agora)
- Rate limit persistente (item #12)
- Lockout progressivo atômico
- Token blacklist em Redis
Arquivos impactados (quando aprovado)
supabase/functions/cadastro-escola-publica/index.ts— CNPJ validation, rollback, nome_completo, URLsupabase/functions/eventos-calendario-trial/index.ts— data_fim em fases por nívelsrc/hooks/useEventosCalendarioTrial.ts— TIPO_MAP sync (1 linha)src/pages/cadastro/CadastroTrialPage.tsx— CNPJ validation frontendsrc/pages/cadastro/CadastroFormulario.tsx— CNPJ validation frontendsrc/lib/masks.ts— adicionarisValidCNPJ()frontend