Skip to content

@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)

#SeveridadeAchadoDetalhe
1AtençãoBRT duplicado no Trial, ausente no Coordenador list_mesTrial 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.
2AtençãoTrial list_proximos não preserva data_fim em fases por nívelFases 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.
3AtençãoTrial busca TODAS olimpíadas ativas; Coordenador filtra por escola_olimpiadasBy-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.
4AtençãoTrial não importa registrarLogRead-only, não precisa de CUD logs. Porém, get_trial_info poderia ser monitorada. Baixa prioridade.
5RecomendaçãoDuplicação massiva (~300 linhas) entre as duas Edge FunctionsQualquer 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)

#SeveridadeAchadoDetalhe
6AtençãoTIPO_MAP divergenteTrial hook não mapeia atividade → evento. Se o backend retornar tipo: 'atividade' (legado), o Trial mostrará tipo raw sem cor/label. Fix: 1 linha.
7Atençãodashboard-trial.tsx é um monolito de 907 linhasDuplica helpers que já existem em calendario-olimpico/helpers.ts. Correções visuais no calendário do coordenador NÃO se propagam para o Trial.
8RecomendaçãoTrial hook não expõe refetchOnWindowFocus: false explicitamenteHerda do QueryClient global. OK mas implícito.
9CriticoTrial getDaysInMonth ignora data_fimEventos 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)

#SeveridadeAchadoDetalhe
10CriticoSem validação algorítmica de CNPJBackend apenas verifica length === 14. Aceita 00000000000000. Frontend idem. Já existe isValidCNPJ() em _shared/cnpj-validator.ts — basta importar no backend e replicar no frontend.
11CriticoRollback parcial sem transaçãoSe a criação do usuário falha, a escola é deletada mas escola_assinaturas pode ficar órfã. Verificar se FK tem ON DELETE CASCADE.
12AtençãoRate limit em memória (Map)Reseta a cada cold start. Será resolvido pela migração Upstash Redis — NÃO implementar fix paliativo.
13Atençãonome_completo do usuário recebe o nome da escolaImpacta logs, sidebar, display de responsável. Requer campo adicional no formulário.
14RecomendaçãoFrontend não mostra erro se createTrial retorna null mas error já mudouFrágil mas funciona na prática.

B2. Cadastro Completo (/cadastro/:token)

#SeveridadeAchadoDetalhe
15CriticoTOCTOU entre validate_token e complete_signupSistema é seguro (segunda verificação protege), mas UX é ruim: usuário preenche formulário inteiro e só descobre token usado ao submeter.
16Atençãocomplete_signup tipo create não cria assinaturaBy-design (admin ativa manualmente), mas sem feedback no frontend.
17Atençãogenerate_link hardcoda URL de produçãohttps://olp.digital hardcodado. Usar req.headers.get('origin') ou env var.
18RecomendaçãoNotificação admin com N+1 queriesLoop sequencial de INSERTs. Poderia ser batch.

B3. Infra de Tokens (cadastro_tokens)

#SeveridadeAchadoDetalhe
19OKCleanup automático funcionamaintenance-cron deleta tokens expirados. ✅
20OKToken é crypto-random 256 bitsEntropia suficiente. ✅
21Atençãoselect("*") retorna token completo ao frontendMenor 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

  1. CNPJ validation algorítmica — Importar isValidCNPJ() no backend + replicar no frontend. Baixo risco, alto impacto.
  2. TIPO_MAP sync — 1 linha no hook Trial. Zero risco.
  3. Fases por nível data_fim — Preservar data_fim no Trial list_proximos. Baixo risco.

Prioridade 2 (Atenção) — Sprint atual ou próxima

  1. Rollback completo no trial_create — Verificar FK CASCADE primeiro.
  2. nome_completo do usuário — Adicionar campo "nome do responsável" (4→5 campos).
  3. generate_link URL dinâmicareq.headers.get('origin') ou env var.

Prioridade 3 (Recomendação/Dívida técnica) — Backlog

  1. Extrair helpers compartilhados entre dashboard-trial.tsx e calendario-olimpico/helpers.ts.
  2. Extrair lógica compartilhada entre Edge Functions de calendário para _shared/calendario-helpers.ts.
  3. Notificação admin batch (substituir loop N+1).
  4. 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, URL
  • supabase/functions/eventos-calendario-trial/index.ts — data_fim em fases por nível
  • src/hooks/useEventosCalendarioTrial.ts — TIPO_MAP sync (1 linha)
  • src/pages/cadastro/CadastroTrialPage.tsx — CNPJ validation frontend
  • src/pages/cadastro/CadastroFormulario.tsx — CNPJ validation frontend
  • src/lib/masks.ts — adicionar isValidCNPJ() frontend