Skip to content

Database Schema — Plataforma OLP

Documentação completa do schema PostgreSQL (Supabase). Última atualização: Abr/2026.


Índice

  1. Visão Geral
  2. Categorias de Tabelas
  3. Tabelas — Detalhamento
  4. Enums
  5. Database Functions
  6. Triggers
  7. Storage Buckets

Visão Geral

MétricaValor
Total de Tabelas73
Enums23
Database Functions18
Storage Buckets4

Convenções

  • PK: Todas as tabelas usam id UUID DEFAULT gen_random_uuid() (exceto tabelas de junção com PK composta e portal_alert_cooldown)
  • Timestamps: criado_em e atualizado_em com DEFAULT now()
  • Soft Delete: Usamos campo ativo BOOLEAN DEFAULT true ao invés de exclusão física
  • FK Naming: <tabela>_<coluna>_fkey
  • FK Deletion Rules:
    • CASCADE: Dados operacionais sem valor histórico (alunos, turmas, inscrições ao deletar escola)
    • SET NULL: Referências a usuarios em campos de autoria/responsabilidade (preserva registros históricos ao deletar usuário)
    • NO ACTION / RESTRICT: Bloqueio intencional (raro)
  • Idioma: Nomes de tabelas e colunas em português

Categorias de Tabelas

CategoriaTabelasDescrição
Estrutura2Configuração base do sistema
Escolas5Dados institucionais (inclui anotações)
Usuários6Identidade, permissões, sub-permissões e vínculos
Olimpíadas8Competições e cronogramas
Alunos6Estudantes, responsáveis e solicitações de vínculo
Inscrições e Resultados5Participação, resultados e importação
Comunicação9Mensagens, mural, templates, snapshots, personalizações
Conteúdo8Cursos, vídeos, tutoriais, banners, progresso
Financeiro4Planos, assinaturas, faturas, billing (twilio_billing_log legado)
Sistema18Auth, logs, cache, cron, config, feature flags, canary, segurança, presença
Agenda2Tarefas e eventos da escola

Tabelas — Detalhamento

1. Estrutura

papeis

Catálogo fixo de papéis do sistema.

ColunaTipoDescrição
idUUID (PK)Identificador
nomeTEXTNome do papel (unique)
descricaoTEXTDescrição do papel

Valores inseridos: administrador, especialista, escola, escola_trial, coordenador, coordenador_olimpiadas, coordenador_pedagogico, diretor, pedagogico, professor, marketing, aluno, responsavel

series_escolares

Catálogo fixo de séries/anos escolares.

ColunaTipoDescrição
idUUID (PK)Identificador
labelTEXTEx: "6º EF", "1ª EM"
grupoTEXT"fundamental" ou "medio"
ordemINTPara ordenação

2. Escolas

escolas

Tabela principal de escolas parceiras.

ColunaTipoDescrição
idUUID (PK)Identificador
nomeTEXTNome da escola
cnpjTEXTCNPJ (opcional)
codigo_inepTEXTCódigo INEP (8 dígitos)
tipoENUM tipo_escolapublica, privada, rede, sistema_ensino
statusENUM status_escolaem_analise, ativa, suspensa, encerrada
cidadeTEXTCidade
estadoTEXTUF (2 letras)
email_contatoTEXTEmail institucional
telefone_contatoTEXTTelefone principal
ano_letivo_atualINTAno letivo vigente (default: 2026)
incremento_ano_automaticoBOOLSe true, incrementa em jan
alunos_contratadosINTQtd contratada no plano
limite_alunosINTLimite calculado (com margem 10%)
alunos_idade_olimpicaINTFaixa etária olímpica
gateway_customer_idTEXTID no MercadoPago
rede_ou_mantenedoraTEXTRede ou mantenedora

endereco_escola

Endereço da escola (1:1 com escolas).

ColunaTipoDescrição
escola_idUUID (FK → escolas)UNIQUE
cep, logradouro, numero, complemento, bairro, cidade, estadoTEXTCampos do endereço

escola_mural_config

Configuração do Mural Olímpico aluno/responsável (1:1 com escolas).

ColunaTipoDescrição
escola_idUUID (FK → escolas)UNIQUE
mural_ativoBOOLSe mural está habilitado
mural_slugTEXTURL amigável (ex: "colegio-abc")
metodo_acesso_por_serieJSONBEx: {"6_ef":"A","8_ef":"B"}

escola_anotacoes

Anotações livres da escola (1:1 com escolas). Usada na Agenda do coordenador.

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)UNIQUE
conteudoTEXTConteúdo da anotação (default: '')
atualizado_porUUID (FK → usuarios)Quem editou por último
atualizado_por_nomeTEXTNome (desnormalizado)

3. Usuários

usuarios

Tabela central de usuários do sistema (admin, especialista, escola, coordenador, etc.).

ColunaTipoDescrição
idUUID (PK)Identificador
nome_completoTEXTNome completo
codigoTEXTCPF, CNPJ ou INEP (normalizado, sem máscara)
tipo_codigoTEXT"cpf", "cnpj" ou "inep"
telefoneTEXTTelefone para OTP
emailTEXTEmail (opcional)
escola_idUUID (FK → escolas)Escola vinculada (null para admin/especialista)
ativoBOOLSe usuário está ativo
auth_user_idUUIDID no Supabase Auth (legado, não utilizado ativamente)

usuario_papeis

Tabela de junção N:N entre usuários e papéis. Um usuário pode ter múltiplos papéis.

ColunaTipoDescrição
idUUID (PK)Identificador
usuario_idUUID (FK → usuarios)Usuário
papel_idUUID (FK → papeis)Papel
escola_idUUID (FK → escolas)Escola do contexto do papel
ativoBOOLSe vínculo está ativo

Trigger: fn_validar_escola_usuario_papel — valida consistência escola_id ↔ papel.

usuarios_escola_permissoes

Permissões granulares por usuário × escola × papel. Desde Abr/2026, escopadas por papel_id para isolar permissões de papéis distintos na mesma escola.

ColunaTipoDescrição
idUUID (PK)Identificador
usuario_idUUID (FK → usuarios)Usuário
escola_idUUID (FK → escolas)Escola
papel_idUUID (FK → papeis)Papel do vínculo (adicionado Abr/2026)
permissaoTEXTNome da permissão granular

UNIQUE: (usuario_id, escola_id, papel_id, permissao)

usuarios_escola_sub_permissoes

Sub-permissões granulares (tabs/funcionalidades) por usuário × escola × papel. Controlam visibilidade de sub-features dentro de uma seção (ex: alunos.importacao).

ColunaTipoDescrição
idUUID (PK)Identificador
usuario_idUUID (FK → usuarios)Usuário
escola_idUUID (FK → escolas)Escola
papel_idUUID (FK → papeis)Papel do vínculo
sub_permissaoTEXTChave dot-notation (ex: alunos.lista)

UNIQUE: (usuario_id, escola_id, papel_id, sub_permissao)

solicitacoes_vinculo

Solicitações de vínculo de usuário a escola (convite para novo papel).

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola alvo
solicitante_idUUID (FK → usuarios)Quem solicitou
destinatario_idUUID (FK → usuarios)Usuário alvo
papel_idUUID (FK → papeis)Papel proposto
permissoesTEXT[]Permissões a conceder
statusENUM solicitacao_vinculo_statuspendente, aceita, recusada
respondida_emTIMESTAMPTZQuando respondeu

ADR: Responsáveis × Escolas — Relação Implícita (sem tabela de junção)

Status: Aceita | Data: Mar/2026 | Contexto: Modelagem de dados

Modelo Atual

A relação entre responsaveis e escolas é implícita, derivada pela cadeia:

responsaveis → aluno_responsaveis → alunos.escola_id

Não existe uma tabela responsavel_escolas. A visibilidade de um responsável em uma escola depende inteiramente da existência de pelo menos um aluno ativo vinculado àquela escola.

Campo Legado: responsaveis.escola_id

A coluna responsaveis.escola_id é um campo legado de referência — indica a escola onde o responsável foi cadastrado pela primeira vez. Ela não é usada para controle de acesso nem para determinar visibilidade. A RLS ignora esse campo e usa exclusivamente a cadeia de JOINs.

JOINs Indiretos em Uso

O sistema já realiza esses JOINs em 4 pontos principais:

LocalCadeia de JOINsPropósito
gestao-responsaveis (action list)responsaveis → aluno_responsaveis → alunos → turmas → series_escolares (4 níveis)Listar responsáveis com dados dos filhos
portal-escola (dashboard responsável)aluno_responsaveis → alunos → escolasMontar lista de filhos com nome da escola
RLS responsaveis_escola_selectresponsavel_tem_aluno_na_escola(id)aluno_responsaveis → alunosDeterminar visibilidade por row
RLS aluno_resp_escola_selectaluno_pertence_escola(aluno_id)Validar vínculo aluno ↔ escola

Justificativa

  1. SSOT (Single Source of Truth): A escola de um aluno é definida em alunos.escola_id. Duplicar essa informação em uma tabela responsavel_escolas criaria risco de inconsistência.
  2. Simplicidade: O responsável só tem sentido no contexto dos seus filhos. Se não tem filhos em uma escola, não há razão para ter acesso a ela.
  3. Bloqueio granular: O campo bloqueado_escola em aluno_responsaveis permite bloquear vínculos individualmente, o que é mais preciso que um bloqueio por escola.

Trade-offs Conhecidos

Trade-offImpactoMitigação
Query indiretaPara saber "quais escolas este responsável acessa", é necessário agregar DISTINCT alunos.escola_id via aluno_responsaveisAceitável — essa query é rara e ocorre apenas no portal
Perda silenciosa de visibilidadeSe todos os alunos de uma escola forem desativados (ativo = false), o responsável perde acesso àquela escola sem notificaçãoAceitável no contexto atual — aluno desativado = responsável não precisa mais acessar
Bloqueio por escolaNão há como bloquear um responsável "na escola inteira" sem bloquear cada vínculo aluno_responsaveis individualmenteMitigado pelo fato de que escolas geralmente têm poucos filhos por responsável (1-3)
Performance RLSA função responsavel_tem_aluno_na_escola() executa JOIN em cada row avaliada pela policyAceitável — volume de responsáveis por escola é limitado (centenas, não milhões)

Quando Revisitar

Criar uma tabela explícita responsavel_escolas seria justificado se:

  • Surgir necessidade de metadados no nível escola (ex: data de cadastro na escola, status por escola)
  • O volume de responsáveis crescer a ponto de impactar performance das queries RLS
  • For necessário bloquear responsáveis por escola sem iterar vínculos individuais
  • O responsável precisar ter acesso a uma escola sem filhos ativos (ex: histórico)

4. Olimpíadas

olimpiadas

Tabela principal de olimpíadas/competições científicas.

ColunaTipoDescrição
idUUID (PK)Identificador
siglaTEXTEx: "OBM", "OBF"
nomeTEXTNome completo
area_conhecimentoENUMmatematica, fisica, quimica, etc.
abrangenciaENUMnacional, internacional, regional, estadual
tipo_aplicacaoENUMpresencial, online, hibrido, online_na_escola, por_fase
tipo_inscricaoENUMindividual, por_equipe, por_escola, pelo_professor
custo_inscricaoENUMgratuita, paga
status_inscricaoENUMabertas, encerradas, em_breve, suspensas
edicao_atualINTAno da edição corrente
ativoBOOLSe olimpíada está ativa (soft delete)
criado_porUUIDEspecialista que criou
icone_customizadoTEXTNome do ícone Lucide
config_arquivo_inscricaoJSONBConfiguração do arquivo de inscrição
modo_config_fasesTEXT'uniforme' ou 'por_nivel' — modo de configuração de fases
fases_por_nivelJSONBMapa nível→fases participantes (modo por_nivel)
cronograma_configuradoBOOLFlag de status
links_configuradosBOOLFlag de status

olimpiada_edicoes

Controla edições anuais de cada olimpíada.

ColunaTipoDescrição
idUUID (PK)Identificador
olimpiada_idUUID (FK → olimpiadas)Olimpíada
ano_edicaoINTAno da edição
statusTEXT"ativa", "encerrada"

fases_olimpiada

Fases dentro de uma edição.

ColunaTipoDescrição
idUUID (PK)Identificador
olimpiada_idUUID (FK → olimpiadas)Olimpíada
nome_faseTEXTEx: "Fase 1", "Semifinal"
ordemINTOrdem sequencial
dataDATEData início
data_fimDATEData fim
ano_edicaoINTFiltro por edição
tempo_maximo_minutosINTTempo máximo global (modo uniforme)
questoes_por_nivelJSONBNº questões por nível: {"Nível 0": 10, ...}
tempo_por_nivelJSONBTempo por nível em minutos: {"Nível 0": 60, ...} (modo por_nivel)
pontuacao_maxima_por_nivelJSONBPontuação máxima por nível
tipo_aplicacaoENUM tipo_aplicacao_olimpiadaTipo de aplicação da fase (nullable — só preenchido quando olimpíada.tipo_aplicacao = 'por_fase')

atividades_cronograma

Eventos e atividades do cronograma de uma edição.

ColunaTipoDescrição
idUUID (PK)Identificador
olimpiada_idUUID (FK)Olimpíada
fase_idUUID (FK → fases_olimpiada)Fase associada (opcional)
tituloTEXTTítulo do evento
descricaoTEXTDescrição
dataDATEData do evento
data_fimDATEData fim (range)
tipo_atividadeENUM tipo_atividade_cronogramainicio_prazo, fim_prazo, atividade, marco, prova, resultado, inscricao, pagamento, documento
ordemINTOrdenação
ano_edicaoINTFiltro por edição

niveis_competicao

Níveis dentro de uma olimpíada (ex: Nível 1, Nível 2).

ColunaTipoDescrição
idUUID (PK)Identificador
olimpiada_idUUID (FK)Olimpíada
tituloTEXTNome do nível
descricaoTEXTDescrição
ordemINTOrdenação

niveis_competicao_series

Junção N:N entre níveis e séries escolares.

ColunaTipoPK
nivel_idUUID (FK → niveis_competicao)Composta
serie_idUUID (FK → series_escolares)Composta

olimpiada_series_participantes

Séries que participam de uma olimpíada.

ColunaTipoPK
olimpiada_idUUID (FK → olimpiadas)Composta
serie_idUUID (FK → series_escolares)Composta

Links externos de uma olimpíada (1:1).

ColunaTipoDescrição
olimpiada_idUUID (FK, PK)UNIQUE
site_oficialTEXTURL do site
link_regulamentoTEXTURL do regulamento
link_provas_anterioresTEXTURL de provas

5. Alunos

alunos

Cadastro de alunos vinculados a escolas.

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
turma_idUUID (FK → turmas)Turma atual
nome_completoTEXTNome
matriculaTEXTMatrícula escolar
data_nascimentoDATEData de nascimento
cpfTEXTCPF (opcional)
sexoTEXTM/F
cor_racaTEXTbranca, preta, parda, etc.
emailTEXTEmail (opcional)
telefoneTEXTTelefone (opcional)
ativoBOOLStatus ativo

turmas

Turmas escolares por ano letivo.

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
serie_idUUID (FK → series_escolares)Série/ano
identificadorTEXTEx: "A", "B", "C"
ano_letivoINTAno letivo
ativoBOOLStatus

UNIQUE: (escola_id, serie_id, identificador, ano_letivo)

aluno_turma_historico

Histórico de turmas de cada aluno (transferências).

ColunaTipoDescrição
idUUID (PK)Identificador
aluno_idUUID (FK → alunos)Aluno
turma_idUUID (FK → turmas)Turma
escola_idUUID (FK → escolas)Escola
ano_letivoINTAno letivo
data_entradaDATEQuando entrou
data_saidaDATEQuando saiu (null = ativo)
statusTEXT"ativo", "transferido"

responsaveis

Responsáveis pelos alunos (pais, tutores).

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola de referência
nome_completoTEXTNome
cpfTEXTCPF (obrigatório, para login mural)
telefoneTEXTTelefone (obrigatório, para OTP)
telefone_secundarioTEXTTelefone alternativo
emailTEXTEmail
ativoBOOLStatus

aluno_responsaveis

Junção N:N entre alunos e responsáveis.

ColunaTipoPK
aluno_idUUID (FK → alunos)Composta
responsavel_idUUID (FK → responsaveis)Composta
parentescoTEXT"responsavel", "pai", "mae", etc.
principalBOOLSe é responsável principal
bloqueado_escolaBOOLSe escola bloqueou o vínculo
bloqueado_porUUIDQuem bloqueou

6. Inscrições e Resultados

escola_olimpiadas

Adesão de uma escola a uma olimpíada (por edição).

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
olimpiada_idUUID (FK → olimpiadas)Olimpíada
ano_edicaoINTEdição
statusTEXT"ativa", "encerrada"
criado_porUUIDCoordenador que aderiu

inscricoes_olimpiada

Inscrição de um aluno em uma olimpíada.

ColunaTipoDescrição
idUUID (PK)Identificador
aluno_idUUID (FK → alunos)Aluno
olimpiada_idUUID (FK → olimpiadas)Olimpíada
escola_idUUID (FK → escolas)Escola
nivel_idUUID (FK → niveis_competicao)Nível
ano_edicaoINTEdição
statusTEXT"pendente", "confirmada", "cancelada"
inscrito_porUUIDQuem inscreveu
autorizado_responsavelBOOLSe responsável autorizou
autorizado_porUUID (FK → responsaveis)Responsável que autorizou
dados_extrasJSONBDados adicionais da inscrição

resultados_aluno

Resultados/notas de alunos em fases de olimpíadas.

ColunaTipoDescrição
idUUID (PK)Identificador
inscricao_idUUID (FK → inscricoes_olimpiada)Inscrição
fase_idUUID (FK → fases_olimpiada)Fase
notaNUMERICNota obtida
classificacaoINTPosição/ranking
premiacaoTEXT"ouro", "prata", "bronze", "mencao_honrosa"
presenteBOOLSe compareceu
escola_idUUID (FK → escolas)Escola

configuracoes_fase_nivel

Faixas de premiação por fase × nível × escola.

ColunaTipoDescrição
idUUID (PK)Identificador
fase_idUUID (FK → fases_olimpiada)Fase
nivel_idUUID (FK → niveis_competicao)Nível
escola_idUUID (FK → escolas)Escola
nota_corteNUMERICNota mínima
faixa_ouro_min/maxNUMERICFaixa para ouro
faixa_prata_min/maxNUMERICFaixa para prata
faixa_bronze_min/maxNUMERICFaixa para bronze
faixa_mencao_min/maxNUMERICFaixa para menção honrosa

7. Comunicação

mural_publicacoes

Publicações no mural da escola (notícias, avisos).

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
olimpiada_idUUID (FK → olimpiadas)Olimpíada (opcional)
tituloTEXTTítulo
conteudoTEXTConteúdo (Markdown)
descricaoTEXTResumo/subtítulo
tipoTEXT"noticia", "aviso", "resultado"
imagem_urlTEXTURL da imagem
video_urlTEXTURL do vídeo
link_externoTEXTLink externo
destaqueBOOLSe está em destaque
ativaBOOLSe está visível
ordemINTOrdenação
criado_porUUID (FK → usuarios)Autor

mural_liberacoes

Controle de liberação de resultados para o Mural Olímpico.

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
escola_olimpiada_idUUID (FK → escola_olimpiadas)Adesão
fase_idUUID (FK)Fase (opcional)
nivel_idUUID (FK)Nível (opcional)
liberar_notasBOOLMostra pontuação
liberar_resultadosBOOLMostra resultados/premiações
config_notasJSONBConfig granular de notas
config_resultadosJSONBConfig granular de resultados

mural_dados_publicados

Snapshots materializados de dados de resultados para o Mural. Evita queries complexas em tempo real no portal público.

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
escola_olimpiada_idUUID (FK → escola_olimpiadas)Adesão
inscricao_idUUID (FK → inscricoes_olimpiada)Inscrição
aluno_idUUID (FK → alunos)Aluno
fase_idUUID (FK → fases_olimpiada)Fase
nivel_idUUID (FK → niveis_competicao)Nível (opcional)
tipoTEXTTipo do snapshot (ex: "resultado")
dadosJSONBDados materializados

mensagens_enviadas

Histórico de mensagens enviadas (WhatsApp/SMS/notificações).

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
enviado_porUUID (FK → usuarios)Remetente
assuntoTEXTAssunto
conteudoTEXTCorpo da mensagem
destinatariosTEXT[]Array de identificadores
template_idUUID (FK → templates_mensagem)Template usado
olimpiada_idUUID (FK)Olimpíada relacionada
statusTEXT"enviada", "erro"

templates_mensagem

Templates de mensagens reutilizáveis.

ColunaTipoDescrição
idUUID (PK)Identificador
hub_idUUID (FK → template_hubs)Hub de templates
tituloTEXTNome do template
conteudoTEXTCorpo com variáveis
tipoTEXT"sms", "notificacao"

template_hubs

Agrupamento de templates por olimpíada.

ColunaTipoDescrição
idUUID (PK)Identificador
tipoENUM template_hub_tipoinstitucional, olimpiada
olimpiada_idUUID (FK → olimpiadas)Olimpíada (opcional)
criado_porUUIDEspecialista
ativoBOOLStatus

template_personalizacoes

Personalizações de templates por escola.

ColunaTipoDescrição
idUUID (PK)Identificador
template_idUUID (FK → templates_mensagem)Template base
escola_idUUID (FK → escolas)Escola
conteudo_personalizadoTEXTVersão customizada

notificacoes

Notificações in-app para usuários.

ColunaTipoDescrição
idUUID (PK)Identificador
usuario_idUUID (FK → usuarios)Destinatário
escola_idUUID (FK → escolas)Escola (opcional)
tituloTEXTTítulo
mensagemTEXTCorpo
tipoENUM notification_typeTipo da notificação
dadosJSONBDados extras
lidaBOOLSe foi lida
lida_emTIMESTAMPTZQuando foi lida
expira_emTIMESTAMPTZExpiração

8. Conteúdo

cursos

Cursos de capacitação.

ColunaTipoDescrição
idUUID (PK)Identificador
tituloTEXTNome do curso
descricaoTEXTDescrição
categoria_visualENUM categoria_visual_cursoazul_claro, verde, vermelho, roxo, amarelo, cinza
tipo_cursoTEXT"curso", "trilha"
ativoBOOLStatus
criado_porUUIDEspecialista

cursos_videos

Vídeos dentro de um curso.

ColunaTipoDescrição
idUUID (PK)Identificador
curso_idUUID (FK → cursos)Curso
tituloTEXTTítulo do vídeo
descricaoTEXTDescrição
detalhesTEXTDetalhes adicionais
url_videoTEXTURL do vídeo
thumbnail_urlTEXTThumbnail
ordemINTOrdenação
statusENUM status_video_cursorascunho, publicado
nivelTEXTiniciante, intermediario, avancado
tagsTEXT[]Tags de categorização
duracao_segundosINTDuração
visualizacoesINTContador
avaliacao_mediaNUMERICMédia de avaliações
total_avaliacoesINTTotal de avaliações
criado_porUUIDAutor

usuario_progresso_video

Progresso do usuário em vídeos de cursos.

ColunaTipoDescrição
idUUID (PK)Identificador
usuario_idUUID (FK → usuarios)Usuário
video_idUUID (FK → cursos_videos)Vídeo
concluidoBOOLSe completou (default: false)
concluido_emTIMESTAMPTZQuando concluiu
avaliacaoINTNota dada (1-5)
avaliado_emTIMESTAMPTZQuando avaliou

video_comentarios

Comentários/dúvidas em vídeos de cursos.

ColunaTipoDescrição
idUUID (PK)Identificador
video_idUUID (FK → cursos_videos)Vídeo
usuario_idUUID (FK → usuarios)Quem comentou
tipoTEXT"duvida" (default)
minuto_videoTEXTTimestamp no vídeo
conteudoTEXTTexto do comentário
statusTEXT"pendente" (default)
respondido_porUUID (FK → usuarios)Quem respondeu
respostaTEXTTexto da resposta
respondido_emTIMESTAMPTZQuando respondeu

video_materiais

Materiais complementares de vídeos (PDFs, links).

ColunaTipoDescrição
idUUID (PK)Identificador
video_idUUID (FK → cursos_videos)Vídeo
nomeTEXTNome do material
descricaoTEXTDescrição
arquivo_urlTEXTURL do arquivo
tipo_arquivoTEXTTipo MIME
tamanho_bytesINTTamanho em bytes
criado_porUUID (FK → usuarios)Quem enviou

tutoriais

Tutoriais da plataforma.

ColunaTipoDescrição
idUUID (PK)Identificador
tituloTEXTTítulo
descricaoTEXTDescrição
url_videoTEXTURL do vídeo
thumbnail_urlTEXTThumbnail
categoriaTEXTCategoria
ordemINTOrdenação
ativoBOOLStatus
criado_porUUIDAutor

banners_login

Banners do carrossel na tela de login.

ColunaTipoDescrição
idUUID (PK)Identificador
tituloTEXTTítulo
descricaoTEXTDescrição
imagem_urlTEXTURL da imagem (bucket: banners-login)
linkTEXTLink do banner
horarioTEXTHorário exibido
ativoBOOLSe está ativo
activated_atTIMESTAMPTZQuando foi ativado
ordem_no_carrosselINTPosição
visualizacoesINTContador
cliquesINTContador
criado_porUUIDEspecialista

headers_novidades

Cards de novidades no header do dashboard.

ColunaTipoDescrição
idUUID (PK)Identificador
tituloTEXTTítulo
descricaoTEXTDescrição
cor_fundoTEXTClasse CSS (ex: "bg-[#fd2f55]")
tagTEXTTag de categoria
linkTEXTLink
ativoBOOLSe está ativo
activated_atTIMESTAMPTZQuando ativou
ordem_no_carrosselINTPosição
criado_porUUIDEspecialista

9. Financeiro

planos

Planos de assinatura disponíveis.

ColunaTipoDescrição
idUUID (PK)Identificador
nomeTEXTNome do plano
descricaoTEXTDescrição
preco_mensalNUMERICPreço mensal base
preco_anualNUMERICPreço anual (desconto)
alunos_minimoINTMínimo contratável
alunos_maximoINTMáximo contratável
valor_por_aluno_extraNUMERICValor por aluno excedente
tipo_cobrancaTEXT"mensal", "anual"
trial_diasINTDias de trial
is_trialBOOLSe é plano de trial
featuresJSONBFeatures habilitadas
ativoBOOLStatus

escola_assinaturas

Assinatura ativa de cada escola.

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
plano_idUUID (FK → planos)Plano
status_assinaturaENUM status_assinaturatrial, ativa, suspensa, cancelada
data_inicioDATEInício
data_fimDATEFim (opcional)
trial_ateDATEExpiração do trial
valor_atualNUMERICValor atual mensal
proximo_vencimentoDATEPróxima cobrança
dia_vencimentoINTDia fixo de vencimento
intervalo_cobrancaTEXT"mensal", "anual"
meses_contratadosINTTotal contratado
data_fim_contratoDATEFim do contrato
renovacao_automaticaBOOLSe renova automaticamente
permite_cancelamento_antecipadoBOOLSe permite cancelar
multa_cancelamento_percentualNUMERIC% de multa
gateway_subscription_idTEXTID no gateway
gateway_customer_idTEXTID do cliente no gateway

escola_faturas

Faturas mensais geradas para escolas.

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
plano_idUUID (FK → planos)Plano na geração
numero_faturaTEXTEx: "OLP-2026-0001" (trigger)
referencia_mesDATEMês de referência
valorNUMERICValor da fatura
descontoNUMERICDesconto aplicado
taxasNUMERICTaxas adicionais
status_pagamentoENUM status_pagamentopendente, pago, vencido, cancelado
vencimento_emDATEData de vencimento
pago_emDATEData do pagamento
tipo_faturaTEXT"mensal", "setup"
metodo_pagamentoTEXT"pix", "boleto", "cartao"
link_pagamentoTEXTURL de pagamento
gateway_preference_idTEXTID da preference (MercadoPago)
gateway_payment_idTEXTID do pagamento
pix_qrcodeTEXTQR Code PIX
pix_copia_colaTEXTPIX copia e cola
pix_expiracaoTIMESTAMPTZExpiração do PIX
boleto_pdf_urlTEXTURL do boleto
codigo_barrasTEXTCódigo de barras
sms_enviado_emTIMESTAMPTZQuando lembrete de mensagem enviado
lembrete_d5_enviado_emTIMESTAMPTZLembrete D-5
migradaBOOLSe foi migrada de sistema antigo

twilio_billing_log ⚠️ LEGADO/DESCONTINUADO

Tabela legada do antigo provedor Twilio. Não é mais utilizada ativamente. Mantida apenas por histórico de dados.

ColunaTipoDescrição
idUUID (PK)Identificador
saldoNUMERICSaldo em USD
moedaTEXT"usd" (default)
consultado_porUUID (FK → usuarios)Quem consultou (null = cron)

10. Sistema

login_otps

OTPs para login do sistema admin.

ColunaTipoDescrição
idUUID (PK)Identificador
usuario_idUUID (FK → usuarios)Usuário
codigo_otp_hashTEXTHash SHA-256 do OTP
expira_emTIMESTAMPTZExpiração (5 min)
usado_emTIMESTAMPTZQuando foi usado
tentativas_falhasINTContador (max 3)
ip_origemTEXTIP do solicitante
user_agentTEXTUser agent

portal_otps

OTPs para login do Mural Olímpico (aluno/responsável).

ColunaTipoDescrição
idUUID (PK)Identificador
entidade_idUUIDID do aluno ou responsável
tipo_entidadeTEXT"aluno" ou "responsavel"
escola_idUUID (FK → escolas)Escola
codigo_otp_hashTEXTHash SHA-256
expira_emTIMESTAMPTZExpiração
usado_emTIMESTAMPTZQuando usado
tentativas_falhasINTContador
ip_origemTEXTIP
user_agentTEXTUser agent

portal_login_tentativas

Rate limiting do Mural Olímpico público.

ColunaTipoDescrição
idUUID (PK)Identificador
ipTEXTIP do cliente
tipo_tentativaTEXT"lookup", "login_aluno_a", etc.
identificadorTEXTIdentificador (matrícula, CPF)
escola_idUUID (FK)Escola
sucessoBOOLSe foi sucesso

portal_alert_cooldown

Cooldown de alertas ntfy para evitar spam (sem PK UUID — usa alert_key como PK).

ColunaTipoDescrição
alert_keyTEXT (PK)Chave do alerta
last_sentTIMESTAMPTZÚltima vez enviado

portal_rate_metrics

Métricas agregadas de rate limiting do Mural por janela temporal.

ColunaTipoDescrição
idUUID (PK)Identificador
janela_inicioTIMESTAMPTZInício da janela (por minuto)
tipo_acaoTEXTTipo de ação (lookup, login, otp, etc.)
escola_idUUID (FK → escolas)Escola (nullable — null = global)
contagemINTTotal de requisições na janela
contagem_bloqueadaINTTotal bloqueado na janela

UNIQUE: (janela_inicio, tipo_acao, COALESCE(escola_id, '00000000-...'))

token_blacklist

Tokens JWT invalidados (logout, troca de perfil).

ColunaTipoDescrição
idUUID (PK)Identificador
jtiTEXTJWT ID (claim jti do token)
usuario_idUUID (FK → usuarios)Dono do token
motivoTEXT"logout" (default)
expira_emTIMESTAMPTZExpiração original do token

senha_historico

Histórico de senhas (hashes) para impedir reutilização.

ColunaTipoDescrição
idUUID (PK)Identificador
usuario_idUUID (FK → usuarios)Usuário
senha_hashTEXTHash Argon2 da senha

sms_log

Log unificado de todas as mensagens enviadas (WhatsApp + SMS fallback).

ColunaTipoDescrição
idUUID (PK)Identificador
providerTEXT"wasender" (default). Valor "twilio" é legado.
provider_msg_idTEXTID da mensagem no provider
origemTEXTMódulo que enviou (ex: "otp", "faturamento")
tipoTEXTTipo da mensagem (ex: "otp_login", "lembrete_fatura")
destinatarioTEXTTelefone do destinatário
statusTEXT"sent" (default), "delivered", "failed", etc.
delivery_statusTEXTStatus de entrega (webhook)
delivery_updated_atTIMESTAMPTZÚltima atualização de entrega
erro_codigoTEXTCódigo de erro (se falhou)
erro_mensagemTEXTMensagem de erro
custoNUMERICCusto da mensagem
moedaTEXT"USD" (default)
usuario_idUUID (FK → usuarios)Usuário associado
escola_idUUID (FK → escolas)Escola associada
metadataJSONBDados extras
twilio_sidTEXTSID Twilio (legado — campo mantido por compatibilidade)

logs_transacoes

Log de auditoria para operações de escrita (CREATE, UPDATE, DELETE).

ColunaTipoDescrição
idUUID (PK)Identificador
usuario_idUUID (FK → usuarios)Quem executou
nome_usuarioTEXTNome (desnormalizado)
papel_principalTEXTPapel no momento
acaoTEXTEx: "escola.create", "usuario.update"
detalhesJSONBDiff, resumo, etc.
ipTEXTIP do cliente
cidadeTEXTGeolocalização
estadoTEXTGeolocalização
paisTEXTGeolocalização

incidentes_resolucoes

Resoluções de incidentes vinculadas a logs de transação.

ColunaTipoDescrição
idUUID (PK)Identificador
log_idUUID (FK → logs_transacoes)UNIQUE — Log do incidente
resolvido_porUUID (FK → usuarios)Quem resolveu
resolvido_emTIMESTAMPTZQuando resolveu
notaTEXTNota de resolução

cron_status

Monitoramento de jobs agendados.

ColunaTipoDescrição
idUUID (PK)Identificador
job_nameTEXTNome do job
statusTEXT"operacional", "erro", "critico"
ultima_execucaoTIMESTAMPTZÚltima execução
ultima_execucao_sucessoTIMESTAMPTZÚltima com sucesso
ultimo_erroTEXTMensagem do último erro
ultimo_erro_emTIMESTAMPTZQuando ocorreu
tentativas_consecutivasINTErros consecutivos
proximo_retryTIMESTAMPTZPróximo retry
sms_critico_enviado_emTIMESTAMPTZAlerta enviado

cadastro_tokens

Tokens para auto-cadastro de escolas trial.

ColunaTipoDescrição
idUUID (PK)Identificador
tokenTEXTToken de cadastro
tipoTEXT"trial"
escola_idUUID (FK → escolas)Escola associada
criado_porUUID (FK → usuarios)Quem gerou
expira_emTIMESTAMPTZExpiração
usadoBOOLSe foi usado
usado_emTIMESTAMPTZQuando foi usado

configuracoes_plataforma

Configurações globais key-value.

ColunaTipoDescrição
chaveTEXT (PK)Chave da configuração
valorJSONBValor
atualizado_porUUID (FK → usuarios)Quem atualizou

coordenador_cores

Cores de identificação de coordenadores na Agenda.

ColunaTipoDescrição
idUUID (PK)Identificador
usuario_idUUID (FK → usuarios)Coordenador
escola_idUUID (FK → escolas)Escola
corVARCHARCor hexadecimal

feature_flags

Feature flags globais para controle de funcionalidades.

ColunaTipoDescrição
idUUID (PK)Identificador
chaveTEXTChave da flag (unique)
nomeTEXTNome legível
descricaoTEXTDescrição
ativa_globalBOOLSe está ativa globalmente (default: true)
parent_chaveTEXTChave da flag pai (para hierarquia)

canary_groups

Grupos canary para rollout gradual de features.

ColunaTipoDescrição
idUUID (PK)Identificador
nomeTEXTNome do grupo
descricaoTEXTDescrição
ativoBOOLSe está ativo (default: true)

canary_group_escolas

Junção N:N entre grupos canary e escolas.

ColunaTipoDescrição
idUUID (PK)Identificador
canary_group_idUUID (FK → canary_groups)Grupo
escola_idUUID (FK → escolas)Escola
adicionada_emTIMESTAMPTZQuando adicionada

canary_group_usuarios

Junção N:N entre grupos canary e usuários.

ColunaTipoDescrição
idUUID (PK)Identificador
canary_group_idUUID (FK → canary_groups)Grupo
usuario_idUUID (FK → usuarios)Usuário
adicionado_emTIMESTAMPTZQuando adicionado

feature_flag_canary

Junção N:N entre feature flags e grupos canary.

ColunaTipoDescrição
idUUID (PK)Identificador
feature_flag_idUUID (FK → feature_flags)Flag
canary_group_idUUID (FK → canary_groups)Grupo canary

11. Agenda

tarefas

Sistema de tarefas internas da escola.

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
tituloTEXTTítulo
descricaoTEXTDescrição
prioridadeTEXT"baixa", "media", "alta", "urgente"
statusTEXT"pendente", "em_andamento", "concluida"
prazoDATEData limite
responsavel_idUUID (FK → usuarios, SET NULL)Responsável (nullable — SET NULL ao deletar usuário)
criado_porUUID (FK → usuarios, SET NULL)Criador (nullable — SET NULL ao deletar usuário)

eventos_manuais_escola

Eventos customizados criados pela escola no calendário.

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
criado_porUUID (FK → usuarios)Criador
tituloTEXTTítulo
descricaoTEXTDescrição
dataDATEData
horaTEXTHorário
localTEXTLocal
tipoTEXT"manual"
olimpiada_idUUID (FK → olimpiadas)Olimpíada (opcional)

12. Importação

importacao_alunos_sessoes

Sessões de importação em lote de alunos (via XLSX).

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
usuario_idUUID (FK → usuarios)Quem importou
statusTEXT"pendente", "processando", "concluida", "erro"
total_alunosINTTotal a processar
alunos_processadosINTProcessados
alunos_sucessoINTCom sucesso
alunos_erroINTCom erro
alunos_ignoradosINTIgnorados
progressoINT% de progresso
dados_importacaoJSONBDados do XLSX
resultadosJSONBResultados detalhados
mensagemTEXTMensagem de status

importacao_resultados_sessoes

Sessões de importação em lote de resultados/notas (via XLSX). Mesmo padrão arquitetural da importacao_alunos_sessoes.

ColunaTipoDescrição
idUUID (PK)Identificador
escola_idUUID (FK → escolas)Escola
usuario_idUUID (FK → usuarios)Quem importou
olimpiada_idUUID (FK → olimpiadas)Olimpíada alvo
fase_idUUID (FK → fases_olimpiada)Fase alvo
nivel_idUUID (FK → niveis_competicao)Nível (opcional)
statusTEXT"pendente", "processando", "concluida", "falha", "cancelada"
total_resultadosINTTotal a processar
resultados_processadosINTProcessados
resultados_sucessoINTCom sucesso
resultados_erroINTCom erro
resultados_atualizadosINTAtualizados (upsert)
inscricoes_auto_criadasINTInscrições criadas automaticamente
matriculas_nao_encontradasTEXT[]Matrículas não localizadas
progressoINT% de progresso
dados_importacaoJSONBDados do XLSX
resultados_detalhesJSONBDetalhes (success, errors, updated)

Enums

EnumValores
tipo_escolapublica, privada, rede, sistema_ensino
status_escolaem_analise, ativa, suspensa, encerrada
area_conhecimento_olimpiadamatematica, fisica, quimica, biologia, informatica, geografia, historia, portugues, astronomia, robotica, filosofia, multidisciplinar
abrangencia_olimpiadanacional, internacional, regional, estadual
tipo_aplicacao_olimpiadapresencial, online, hibrido, online_na_escola, por_fase
tipo_inscricao_olimpiadaindividual, por_equipe, por_escola, pelo_professor
tipo_custo_inscricaogratuita, paga
status_inscricao_olimpiadaabertas, encerradas, em_breve, suspensas
tipo_atividade_cronogramainicio_prazo, fim_prazo, atividade, marco, prova, resultado, inscricao, pagamento, documento
status_assinaturatrial, ativa, suspensa, cancelada
status_pagamentopendente, pago, vencido, cancelado
status_video_cursorascunho, publicado
categoria_visual_cursoazul_claro, verde, vermelho, roxo, amarelo, cinza
notification_typefatura_proxima, fatura_vencida, pagamento_confirmado, inscricao, resultado, mensagem, sistema, cron_falha, equipe_olp, solicitacao_vinculo
grupo_serie_escolarfundamental_iniciais, fundamental_finais, medio
permissao_areagestao_olimpiadas, resultados, comunicacao, inscricoes, videos, mural, relatorios, painel_controle, calendario, olimpiadas_coord, dashboard_gestor, alunos, usuarios, pagamentos, configuracoes, painel_geral, uso_plataforma, projeto_olimpico, financeiro, agenda, dashboard_escola, formacao
solicitacao_vinculo_statuspendente, aceita, recusada
template_hub_tipoinstitucional, olimpiada
template_mensagem_tipoabertura_turma, lembrete_encontro, anuncio_resultado, sessao_fotos, anuncio_simulado, lembrete_simulado, aplicacao_prova_interna, aplicacao_prova_externa
tipo_codigocpf, cnpj, inep
tipo_planosBásico, Enterprise, Profissional, Essencial
tutorial_secaodashboard, olimpiadas, calendario, resultados, comunicacao, inscricoes, videos, jornal_olimpico, perfil, esp_dashboard, esp_banners, esp_headers, esp_olimpiadas, esp_templates, esp_cursos, esp_cursos_videos, esp_tutoriais, esp_configuracoes, gestor_dashboard, gestor_alunos, gestor_turmas, gestor_usuarios, gestor_responsaveis, gestor_pagamentos, gestor_configuracoes, gestor_portal, coord_painel, coord_calendario, coord_olimpiadas, coord_inscricoes, coord_resultados, coord_comunicacao, coord_videos, coord_videos_player, coord_mural, dir_painel, dir_uso, dir_projeto, dir_financeiro, escola_dashboard, escola_alunos, escola_usuarios, escola_pagamentos, escola_configuracoes, coord_resultados_olimpiada
tutorial_statusativo, inativo

Database Functions

FunçãoTipoDescrição
aluno_pertence_escola(p_aluno_id)SECURITY DEFINERVerifica se aluno pertence à escola do JWT. Evita recursão RLS.
get_alunos_responsavel()SECURITY DEFINERRetorna IDs dos alunos vinculados ao responsável do JWT.
responsavel_vinculado_aluno(p_aluno_id)SECURITY DEFINERVerifica se responsável do JWT está vinculado ao aluno.
responsavel_tem_aluno_na_escola(p_responsavel_id)SECURITY DEFINERVerifica se responsável tem aluno na escola do JWT.
usuario_na_mesma_escola(p_usuario_id, p_escola_id)SECURITY DEFINERVerifica se usuário tem papel ativo na escola. Usada em RLS.
update_updated_at_column()TRIGGERAtualiza atualizado_em = now() antes de UPDATE.
gerar_numero_fatura()TRIGGERGera numero_fatura sequencial (ex: OLP-2026-0001).
calcular_proximo_vencimento()TRIGGERCalcula proximo_vencimento ao criar assinatura.
fn_validar_escola_usuario_papel()TRIGGERValida consistência escola_id ao inserir em usuario_papeis.
limpar_otps_expirados()UtilityRemove OTPs expirados há mais de 24h.
increment_video_view(p_video_id)SECURITY DEFINERIncrementa visualizacoes em cursos_videos.
increment_banner_metric(p_id, p_campo)SECURITY DEFINERIncrementa visualizacoes ou cliques em banners_login.
portal_check_guards(p_escola_id, p_ip, p_identificador, p_tipo, ...)SECURITY DEFINERQuery atômica de rate limit do Mural (count_escola, count_ip, failed_24h). 2 overloads (com e sem p_window_minutes_ip).
portal_increment_metric(p_tipo, p_escola_id, p_blocked)SECURITY DEFINERIncrementa métricas de rate limit em portal_rate_metrics com UPSERT.
portal_check_alert_cooldown(p_key, p_minutes)SECURITY DEFINERVerifica e registra cooldown de alertas ntfy. Retorna TRUE se pode enviar.
admin_list_canary_groups_with_counts()SECURITY DEFINERLista grupos canary com contagem de escolas, usuários e flags.
validar_tarefa_titulo()TRIGGERValida que título da tarefa não excede 120 caracteres.
trigger_set_updated_at_import_resultados()TRIGGERPreserva criado_em original ao atualizar importacao_resultados_sessoes.

Triggers

TriggerTabelaEventoFunção
update_*_updated_atMúltiplas tabelasBEFORE UPDATEupdate_updated_at_column()
trigger_gerar_numero_faturaescola_faturasBEFORE INSERTgerar_numero_fatura()
trigger_calcular_vencimentoescola_assinaturasBEFORE INSERTcalcular_proximo_vencimento()
trigger_validar_escola_papelusuario_papeisBEFORE INSERT/UPDATEfn_validar_escola_usuario_papel()
trigger_validar_tarefa_titulotarefasBEFORE INSERT/UPDATEvalidar_tarefa_titulo()
trigger_set_updated_at_import_resultadosimportacao_resultados_sessoesBEFORE UPDATEtrigger_set_updated_at_import_resultados()

Storage Buckets

BucketPúblicoUso
banners-login✅ SimImagens dos banners na tela de login
curso-thumbnails✅ SimThumbnails de cursos/vídeos
tutoriais-thumbnails✅ SimThumbnails de tutoriais
mural-imagens✅ SimImagens de publicações do mural

Nota: Todos os buckets são públicos para leitura. O upload é controlado via Edge Functions (não há policies de storage client-side).