Visão Geral da Arquitetura
Última atualização: 2026-03-26
Diagrama de Contexto
┌──────────────┐ HTTPS ┌────────────────────┐
│ Browser │◄──────────────►│ Cloudflare Worker │ (gateway.olp.digital)
│ (React SPA) │ │ - Reescrita cookie │
│ │ │ - Geo headers │
└──────┬───────┘ └─────────┬──────────┘
│ │
│ credentials: include │ Proxy transparente
│ ▼
│ ┌────────────────────┐
│ │ Supabase Edge │ 59 functions
│ │ Functions (Deno) │
│ └─────────┬──────────┘
│ │
│ ┌─────────────┼─────────────┐
│ ▼ ▼ ▼
│ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ │ Postgres │ │ Wasender │ │ Storage │
│ │ (RLS) │ │(WhatsApp) │ │ (Buckets)│
│ │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘
│
└──── Supabase Client direto (APENAS dados públicos, storage)Papéis e Grupos
Grupo: Plataforma OLP
| Papel | Descrição | Escopo | Feature Flags |
|---|---|---|---|
administrador | Gerencia escolas, usuários, planos, assinaturas | Global — cross-escola | Bypass de feature flags |
especialista | Cria olimpíadas, fases, calendários, cursos, templates | Global — conteúdo | Sujeito a feature flags |
Grupo: Equipe da Escola
| Papel | Descrição | Escopo |
|---|---|---|
escola (Gestor) | Admin máximo da escola | Tudo da sua escola |
escola_trial | Gestor em período de avaliação | Tudo da sua escola (trial) |
coordenador | Gerencia olimpíadas, alunos, turmas | CRUD na sua escola |
coordenador_olimpiadas | Coordena especificamente olimpíadas | Olimpíadas na sua escola |
coordenador_pedagogico | Coordena acompanhamento pedagógico | Pedagógico na sua escola |
diretor | Visualiza financeiro, relatórios | Leitura na sua escola |
pedagogico | Acompanha resultados pedagógicos | Leitura na sua escola |
professor | Visualiza turmas e alunos | Leitura na sua escola |
marketing | Acessa comunicação e mural | Escopo reduzido |
Grupo: Comunidade (Mural Olímpico)
| Papel | Descrição | Escopo |
|---|---|---|
aluno | Vê cronograma, provas, resultados | Seus próprios dados |
responsavel | Acompanha filhos vinculados | Dados dos filhos |
Hierarquia
administrador > especialista > escola > escola_trial > coordenador >
coordenador_olimpiadas > coordenador_pedagogico > diretor >
pedagogico > professor > marketing > aluno > responsavelRegra fundamental: Login unificado — todos entram pela mesma tela. Se o usuário tem múltiplos perfis (ou o mesmo perfil em escolas diferentes), uma tela de seleção é apresentada. O papel e a escola ativos vêm do JWT.
Multi-Escola
Um mesmo usuário pode ter papéis em múltiplas escolas via usuario_papeis. Exemplo:
usuario_papeis:
usuario_id=ABC, papel=coordenador, escola_id=ESCOLA_A
usuario_id=ABC, papel=coordenador, escola_id=ESCOLA_B
usuario_id=ABC, papel=diretor, escola_id=ESCOLA_BCada combinação papel + escola é um perfil distinto na tela de login e no role-switcher. O JWT escola_id é derivado do perfil selecionado.
Fluxo de Dados Principal
1. Usuário digita código (CPF/INEP/CNPJ)
2. Frontend → Edge Function `send-otp`
3. Backend localiza usuário + telefone
4. Gera OTP (6 dígitos) → hash SHA-256 → salva em `login_otps`
5. Envia OTP via WhatsApp (Wasender)
6. Usuário digita OTP
7. Frontend → Edge Function `verify-otp`
8. Backend valida OTP → lê papéis → gera JWT customizado
9. Retorna cookie HttpOnly `olp_auth` (8h)
10. Requests subsequentes incluem cookie automaticamente
11. Edge Functions extraem token → validam → executam lógicaDois Contextos de JWT
| Contexto | Secret | Cookie | Expiração | Escopo |
|---|---|---|---|---|
| Sistema Admin | OLP_JWT_SECRET | olp_auth | 8h | CRUD completo |
| Mural Olímpico (Aluno/Responsável) | OLP_JWT_SECRET (unificado) | olp_mural | 2h | portal_readonly |
Secret unificado: Sistema e Portal usam
OLP_JWT_SECRET(mesmo valor). Isso é obrigatório porque o PostgREST do Supabase usa um único secret para verificar tokens e aplicar RLS. A diferenciação de acesso é feita via claims no JWT: tokens do sistema contêmprincipal_role, tokens do portal contêmportal_type+escopo: 'portal_readonly'. Cross-access é bloqueado: tokens de portal não possuemprincipal_rolee vice-versa.
Claims do JWT (Sistema Admin)
{
"sub": "uuid-usuario",
"nome_completo": "Nome",
"principal_role": "escola",
"escola_id": "uuid-escola",
"roles": [{ "nome": "escola", "escola_id": "uuid" }],
"role": "authenticated",
"aud": "authenticated"
}Os claims
role: authenticatedeaud: authenticatedsão obrigatórios para que o PostgREST do Supabase reconheça o token e aplique RLS.
Clientes Supabase nas Edge Functions
| Cliente | Função | RLS | Uso |
|---|---|---|---|
createSupabaseClient(req) | ANON_KEY + Bearer token do cookie | ✅ Ativo | Operações autenticadas com escopo de escola |
createSupabasePublic() | ANON_KEY sem auth | ✅ Ativo | Login, lookup público |
createSupabaseSystem() | SERVICE_ROLE_KEY | ❌ Bypass | Storage uploads, logs, admin cross-escola |
Regra: Sempre preferir createSupabaseClient(req) para operações autenticadas. createSupabaseSystem() apenas quando justificado tecnicamente.
Ambientes
| Ambiente | URL | Gateway |
|---|---|---|
| Preview (Lovable) | https://id-preview--b4188062-...lovable.app | Direto para Supabase |
| Produção | https://olp.digital | https://gateway.olp.digital (Cloudflare Worker) |
| Localhost | http://localhost:5173 | Direto para Supabase |
Cloudflare Worker (Produção)
O Worker atua como proxy transparente e adiciona:
- Reescrita de cookies: Adiciona
Domain=.olp.digitalpara funcionar cross-subdomain - Headers de geolocalização:
X-Geo-City,X-Geo-Region,X-Geo-Country,X-Geo-Timezone - Roteamento: Encaminha requests para as Edge Functions do Supabase
Estrutura do Projeto
src/
components/ # Componentes React (por funcionalidade)
agenda/ # Exemplo de Feature Directory Pattern (7 arquivos)
coordenador/ # Features do coordenador (ex: resultados/)
diretor/ # Features do diretor
mural-olimpico/ # Mural Olímpico (15+ arquivos)
importacao-alunos/ # Importação inteligente (7 arquivos)
ui/ # Design system (shadcn — não alterar)
contexts/ # Auth context (sessão via cookie)
hooks/ # Hooks customizados (1 por Edge Function)
lib/ # Helpers (edge-function.ts, auth.ts, masks.ts)
navigation/ # Registry centralizado de seções e permissões
pages/ # Páginas de rota (portal, cadastro)
types/ # Tipos TypeScript
supabase/
functions/ # 59 Edge Functions
_shared/ # Helpers compartilhados (auth, cors, jwt, logging)
migrations/ # Migrações SQL (read-only)
config.toml # Configuração (verify_jwt = false global)
docs/ # Esta documentaçãoRegras de Integração
- Lógica de Supabase/Auth/Wasender → helpers/hooks (
lib/auth,lib/edge-function,_shared/*), nunca em componentes React - Mocks são transitórios — substituir por chamadas reais na mesma entrega
- Áreas sensíveis (não alterar sem instrução):
components/ui/*,App.tsx,main.tsx,*.config.*