Gestão
Painel administrativo (Next.js + Tailwind) usado por gestores municipais e operadores de frota das prefeituras. Voltagem institucional da IDV Unipass: cor de marca só em ação/navegação, superfícies neutras, sem mosaico cheio nem fonte rounded — ver arquitetura do ecossistema.
1. Visão geral
O Gestão é a superfície onde gestores municipais e operadores de frota administram todo o ciclo operacional do transporte universitário: cadastros base (estudantes, motoristas, veículos, rotas), planejamento e publicação da operação diária, disciplina, comunicação, relatórios e governança (auditoria, backup). Estudantes e motoristas não acessam o Gestão — usam os apps mobile dedicados; se um usuário com esses papéis tentar entrar, é redirecionado automaticamente para o app correspondente.
Papéis que usam o Gestão
Admin Gestor Operador
Papéis que NÃO usam o Gestão
Motorista Estudante — redirecionados ao app mobile
2. Controle de acesso (RBAC)
Documentação institucional (regra global de segurança do harness, o CLAUDE.md e a apresentação
institucional) descreve um modelo "3-gate RBAC" (status + role + isolamento de tenant). O
código-fonte real (sgtu-gestao/src/lib/rbac.ts) documenta explicitamente que hoje é
2-gate: o terceiro gate (isolamento por tenant/prefeitura) foi removido quando o sistema
virou single-tenant por instância/VPS (commit 9444858) e o contexto de tenant nunca chegou a
ser populado. Esta wiki descreve o comportamento real — use "2-gate" na documentação
voltada ao usuário final, não "3-gate".
2.1 Gate 1 — Estado da entidade
Cada tipo de entidade de negócio (viagem, veículo, rota, estudante, motorista, manutenção, dia de operação,
confirmação, calendário) tem sua própria tabela de "estado atual → ações permitidas". Exemplo: uma viagem
concluída só permite visualizar; uma viagem rascunho permite ver, editar, excluir,
cancelar e atribuir motorista/veículo.
2.2 Gate 2 — Papel do usuário
| Papel | Ações permitidas (regra geral do painel) |
|---|---|
| Admin | Todas: ver, criar, editar, excluir, aprovar, cancelar, iniciar, concluir, atribuir |
| Operador | Ver, criar, editar, excluir, cancelar, iniciar, concluir, atribuir — sem aprovar |
| Gestor | Ver, criar, editar, aprovar, cancelar — sem excluir, iniciar, concluir ou atribuir |
A ação final permitida é a interseção dos dois gates — precisa passar pelo estado da entidade E pelo papel do usuário.
2.3 Bloqueio de rota inteira (nível de página)
| Grupo de rotas | Quem acessa | Rotas |
|---|---|---|
| Admin-only | Admin | /auditoria, /backup |
| Admin + Gestor | Admin Gestor | /usuarios, /configuracoes, /operacao-dia |
| Qualquer staff | Admin Gestor Operador | Estudantes, Motoristas, Veículos, Rotas, Pontos, Instituições, Calendários, Comunicação, Centro Operacional, Agenda, Relatórios, Dashboard, Notificações |
Em /usuarios e /configuracoes, o gestor tem permissão de acessar por URL direta
(o proxy libera), mas o link não aparece no menu lateral para esse papel (o item de navegação
é restrito a admin). Em /configuracoes especificamente, o gestor até chega na tela, mas quase
todo campo aparece travado (disabled) com aviso "Apenas administradores podem editar...". Trate
isso como comportamento real do sistema ao escrever o tutorial — não como bug a ignorar.
2.4 Autenticação e sessão
Token JWT carrega apenas user_id e role — sem tenant_id (confirma o 2-gate). Quatro cookies:
| Cookie | HttpOnly | Propósito |
|---|---|---|
sgtu-access-token | Sim | JWT de acesso (15 min) |
sgtu-refresh-token | Sim, path restrito a /api/auth/refresh | JWT de renovação (7 dias) |
sgtu-user-info | Não (assinado) | E-mail/papel para trilha de auditoria — lido sem decodificar o JWT |
sgtu-auth-token | — | Apenas em modo mock de desenvolvimento |
Fail-closed deliberado: se o cookie de papel estiver ausente ou corrompido, o sistema não assume "quase autenticado" — limpa a sessão inteira e força novo login. Login aceita e-mail ou CPF (para estudantes/motoristas, que fazem login por CPF quando acessam via web em contexto de suporte).
3. Mapa de módulos
Cada tela do painel mapeia a um bounded context do backend. Referência para localizar regra de negócio ↔ tela.
| Bounded context (backend) | Telas do Gestão |
|---|---|
| Frota | Veículos, Motoristas |
| Rede de Rotas | Rotas, Pontos de Embarque, Instituições, Calendários |
| Estudantes | Estudantes |
| Operação Diária | Agenda, Operação do Dia, Centro Operacional |
| Disciplina | Aba Disciplina do Dashboard + Ocorrências/Penalidades (via perfil do estudante) |
| Comunicação | Comunicação, Notificações |
| Tenant/Auth | Usuários, Perfil |
| Backup | Backup |
| Analytics | Dashboard, Relatórios, Auditoria (trilha própria via django-auditlog) |
4. Cadastros base
4.1 Estudantes
Propósito: cadastro do beneficiário do transporte — dados pessoais, vínculo acadêmico (IES/curso/turno) e vínculo de transporte (rota/ponto). Todo estudante é obrigatoriamente também uma conta de usuário; o backend cria a conta automaticamente.
Ações
Listar (KPI cards clicáveis como filtro), criar, editar, desativar (soft delete), importar CSV (wizard de 4 passos), exportar CSV, reset de senha, gerenciar vínculo de rota, aprovar documentos
Identificador único
card_token gerado automaticamente (SGTU-{16 hex}) — é a base da carteirinha digital
Um estudante pode ter vínculo ativo em mais de uma rota (ex.: manhã + tarde), mas nunca dois vínculos ativos no mesmo turno — constraint de unicidade condicional garante isso desde 2026-07-04. Antes disso era possível cadastrar 2 rotas no mesmo turno silenciosamente, corrompendo contagem de vagas e manifesto — já corrigido, mas cite como exemplo de por que essa regra existe.
Validações-chave: CPF com dígito verificador real (não só formato); idade entre 14–80 anos quando data de nascimento informada; telefone 10/11 dígitos; CEP 8 dígitos; ao confirmar presença "fora do manifesto", justificativa do operador com no mínimo 10 caracteres.
O botão de submit no cadastro diz "Cadastrar e Completar Perfil" — é esperado que o gestor crie um registro enxuto primeiro (nome, CPF, IES) e complete endereço/vínculo depois. Ações em massa (ativar/inativar/exportar seleção) não estão implementadas no backend — o sistema avisa honestamente "estará disponível em breve" em vez de simular sucesso.
4.2 Motoristas
Propósito: cadastro de motoristas e monitores — CNH, disponibilidade semanal por turno, indisponibilidades pontuais. Monitor é um Motorista com tipo="monitor", não uma entidade separada.
Ações
Listar, criar, editar, excluir, reset de senha, exportar CSV, CRUD de indisponibilidades embutido
Validação de CNH
11 dígitos + categoria compatível com o tipo de veículo (ônibus exige D/E/AD/AE)
Motorista recebe acesso ao app usando o CPF como senha no primeiro login, com troca obrigatória. CNH já vencida não pode ser cadastrada na criação (o seletor de data trava o mínimo em hoje). Badge de expiração (vencida / vence em ≤30 dias / válida) é calculado no cliente a partir da data de validade.
Um motorista pode ser substituído numa viagem já publicada sem precisar republicar o dia inteiro. O sistema exige um motivo (doença, falta, CNH vencida, férias, licença, outro), registra quem aprovou e notifica o motorista assíncronamente. O ranking de "reservas disponíveis" pondera compatibilidade de CNH, disponibilidade no turno e ausência de conflito de escala.
4.3 Veículos
Propósito: cadastro da frota — identificação, especificações, status, motorista padrão por turno, documentos de conformidade e manutenção.
Placa
Aceita formato antigo (ABC1234) e Mercosul (ABC1D23)
Capacidade
1 a 60 lugares · Ano de fabricação: 1990 até ano atual + 1
As abas de Manutenção e Abastecimento existem no backend (com regras completas), mas o frontend atual não tem formulário de criação conectado para essas duas telas — o gestor consegue ver, mas ainda não cadastrar diretamente pelo painel. Documentos de conformidade (CRLV, seguro, vistoria) não fazem parte do formulário principal — precisam salvar o veículo primeiro e depois anexar via a aba Conformidade.
Um motorista só pode ser "padrão" de um veículo por turno, e um veículo só tem um motorista padrão por turno (constraint de unicidade condicional).
4.4 Rotas
Propósito: o módulo de cadastro com a lógica mais densa — trajetos conectando pontos de embarque a instituições, com sequência ordenada de paradas, turno, motorista padrão, dias de funcionamento e cutoff de confirmação.
Prazo máximo para o estudante confirmar presença no dia seguinte. Pode ser um horário explícito (ex.:
14h, 1 dia antes) ou derivado automaticamente de "3h antes do primeiro ponto da rota" quando não configurado.
cutoff_desabilitado=true (modo piloto) aceita confirmações a qualquer momento, sem prazo.
Toda rota precisa ter no mínimo 2 pontos, com exatamente 1 origem e 1 destino marcados — o restante são pontos intermediários (cada um precisa ter embarque OU desembarque marcado, ao menos um). A primeira parada (ordem 1) é travada automaticamente como origem; o destino é um toggle exclusivo (marcar um desmarca o anterior). O editor de paradas usa drag-and-drop com suporte a teclado, e o botão de submit fica travado até a contagem "Origem 1/1, Destino 1/1" estar correta — esta validação é espelhada no backend (o cliente falha rápido, mas o servidor revalida do zero).
O texto de ajuda "horários devem ser sequenciais" é apenas informativo — não é validado
nem no cliente nem no servidor; é possível salvar uma rota com horários fora de ordem. Um campo legado
(tipo de parada) ainda é mantido para compatibilidade com consumidores antigos (app mobile
anterior à unificação, analytics) durante a janela de transição.
4.5 Pontos de Embarque
Propósito: locais físicos georreferenciados usados como blocos de construção das rotas.
Formulário combina busca de endereço (Google Places) com mapa interativo (marcador arrastável com geocodificação reversa) — os dois lados ficam sincronizados. Coordenadas manuais existem como campo recolhido (escape hatch), fluxo primário é visual. Ao mover/digitar um ponto, o sistema varre todos os pontos cadastrados e avisa (sem bloquear) se houver outro ponto a 100 metros ou menos — proteção contra duplicidade geográfica.
Excluir um ponto vinculado a rotas é bloqueado (o sistema lista até 5 rotas que o usam — é preciso desvincular antes). Desativar um ponto (em vez de excluir) faz ele parar de aparecer nas rotas — efeito colateral não-óbvio que precisa estar no tutorial.
4.6 Instituições (IES)
Propósito: universidades/campi atendidos — endereço, janelas de operação (horários de entrada/saída por turno) e regras/restrições locais.
Janela de operação: início e fim no formato HH:MM, fim sempre depois do início, tolerância de 0 a 60 minutos. Regras de instituição só podem ser criadas ou apagadas — nunca editadas (força recriar em vez de alterar histórico).
4.7 Calendários
Propósito: calendário acadêmico por instituição — datas de semestre e períodos internos (aulas, provas, recesso, férias, feriado, evento) que determinam quando o transporte opera.
Cada período tem datas de início/fim validadas contra o calendário-pai e contra si mesmo (3 níveis de checagem), mas não existe validação de sobreposição entre períodos irmãos — é possível cadastrar "aulas" e "recesso" cobrindo a mesma data sem erro.
4.8 Usuários (staff)
Propósito: contas de staff do painel (admin/gestor/operador) — não gerencia motorista/estudante, que são criados pelos próprios formulários de cadastro (auto-provisionamento de conta).
Restrito a Admin + Gestor (gestor acessa por URL mas não vê o item no menu — ver §2.3).
5. Operação diária
Núcleo operacional do sistema — três telas com papéis distintos e complementares no mesmo ciclo de vida do Dia de Operação (rascunho → publicado → em andamento → concluído).
5.1 Agenda
Visão semanal (grade ou lista) de viagens programadas e disponibilidade de motoristas — somente leitura e navegação, sem CRUD. Clicar numa viagem leva para Operação do Dia na data correspondente. Acessível a todos os papéis staff (diferente de Operação do Dia).
5.2 Operação do Dia
Propósito: onde o Dia de Operação é efetivamente produzido — planejamento e publicação das viagens. Restrito a Admin + Gestor (operador não acessa nem por URL direta).
Nota de RBAC relevante a este módulo: a ação aprovar é o que distingue os dois papéis com acesso — o gestor a possui, o operador não (ver §2.2). Ao escrever o tutorial, confirmar com o time o que exatamente o gestor aprova no ciclo do Dia de Operação, pois o gate existe na matriz de permissão mas o passo de aprovação não está exposto de forma explícita na narrativa da tela.
Publicar
Individual ou em lote — o botão "Publicar todas" só habilita quando há rotas elegíveis (ainda não publicadas)
Override de motorista
Pontual (só hoje) ou permanente (vira o padrão da rota)
Confirmações
Drawer por rota para confirmar/cancelar presença de estudantes individualmente
Cutoff
Countdown ao vivo, com opção de estender em 1h ou desabilitar (ambas via confirmação explícita)
Um gestor abre Operação do Dia pela manhã, revisa alertas (rotas sem motorista, cutoffs vencendo), publica em lote as rotas prontas, e usa o override de motorista pontual para uma rota cujo motorista titular avisou atraso. Estudantes confirmados aparecem no drawer de confirmações; o gestor pode adicionar um estudante "fora do manifesto" mediante justificativa.
5.3 Centro Operacional
Propósito: painel de monitoramento ao vivo do dia — visão consolidada com KPIs, alertas e acesso rápido ao embarque de cada rota. É o "cockpit" durante a operação: consome o resultado da publicação, não produz. Acessível a todos os papéis staff.
Alterna entre visão Lista e Mapa; abrir o drawer de embarque de uma rota reaproveita os mesmos schemas de validação do módulo de embarque do app motorista.
6. Disciplina
Propósito: ocorrências disciplinares do estudante (comportamental, vandalismo, no-show recorrente, fraude) e penalidades formais decorrentes (advertência, suspensão temporária, suspensão definitiva). Gerido a partir do perfil do estudante e da aba Disciplina do Dashboard (rankings Top 10 de no-show/walk-in).
Penalidade: ativa → cumprida | revogada. Só pode transicionar a partir de "ativa" — uma
penalidade já finalizada não pode ser retransicionada (o Dia de Operação e a Viagem também têm ciclos de
estado, mas é a penalidade que tem a guarda explícita contra reversão de estado terminal). Uma penalidade pode agregar várias ocorrências
(M2M). O estudante pode "reconhecer" a própria penalidade (confirmar ciência) — única ação de escrita que um
estudante executa sobre si mesmo neste domínio; a flag de reconhecimento é idempotente (chamar de novo não
tem efeito colateral).
Conceito importante: "Ocorrência" tem dois significados no sistema — OcorrenciaTempoReal (incidente operacional durante a viagem: mecânico, acidente, atraso) é uma entidade separada de Ocorrencia (disciplinar, sobre conduta do estudante). O tutorial de usuário final deve sempre qualificar qual é qual.
7. Comunicação & notificações
7.1 Comunicação
Propósito: envio de avisos às famílias/estudantes (atraso, troca de veículo, cancelamento, mudança de ponto, cutoff, penalidade, informativo) via WhatsApp, push, SMS ou e-mail, com templates reutilizáveis e histórico com taxa de entrega.
Operador seleciona audiência em cascata (Instituição → Rota → Turno, com contagem de destinatários recalculada a cada filtro), escolhe canal, seleciona um template já filtrado por esse canal (trocar de canal invalida templates de outro canal, mas preserva o texto digitado), confere no preview em formato de mensagem de app, e envia.
A entrega real (integração com push/SMS/e-mail/WhatsApp) ainda não está implementada no backend — o modelo de dados existe, mas o envio efetivo é uma fase futura. Documentar como "em desenvolvimento", não como funcionalidade completa.
7.2 Notificações
Propósito: diferente de Comunicação — são alertas gerados automaticamente pelo sistema (documento vencendo/vencido, manutenção pendente, CNH vencendo, capacidade excedida, no-show recorrente, sistema/operação/rota/comunicação), não mensagens enviadas manualmente. Visível a todos os papéis staff.
Cada alerta tem estado de leitura por usuário — um mesmo alerta pode estar lido para um gestor e não-lido para outro. Descarte é definitivo. Abrir/ler um alerta o marca como lido para aquele usuário.
8. Relatórios & dashboard
8.1 Dashboard
Painel inicial pós-login com 4 abas: Hoje (operacional do dia), Operação (histórico de execução/pontualidade), Disciplina (no-show/walk-in/penalidades, rankings), Conformidade (frota/CNH/manutenção).
8.2 Relatórios
Seis relatórios operacionais e de prestação de contas: Consolidado Mensal, Plano vs. Execução, Frequência e no-show, Infrações e ocorrências, Manutenção de frota, Conformidade da frota. Exportação em CSV e impressão/PDF (sem XLSX). Filtros persistidos na URL.
Exportações de relatórios não mascaram CPF/telefone/e-mail (política de zero-masking se estende às exportações, não só à tela) — consistente com a postura LGPD do produto (ver §9.2).
9. Governança
9.1 Auditoria
Propósito: trilha somente-leitura de quem fez o quê (acessou, alterou, excluiu) em cada cadastro. Restrito a Admin.
Exportação CSV busca o dataset completo (até 10 mil linhas) independente da paginação da tela — "exportar" nunca reflete só a página visível, sempre o filtro completo.
9.2 Backup e restauração
Restaurado é Admin-only. Fluxo de 2 passos obrigatórios: confirmar (gera token de uso único, TTL de 5 min) → executar (token consumido, lock de concorrência — só 1 restore por vez no sistema inteiro). Antes de qualquer restauração, um backup de segurança automático é gerado, permitindo reverter uma restauração já aplicada mas indesejada para o estado anterior (o botão "Reverter" fica disponível para restaurações concluídas com sucesso). Download local de backup não persiste no servidor — não pode ser rebaixado depois do fechamento do navegador.
9.3 Configurações e Perfil
Organização (razão social/CNPJ/contato), tema visual com preview ao vivo, configurações operacionais chave-valor (cutoff padrão, vagas padrão, dias de antecedência), preferências de alertas automáticos. Restrito a Admin/Gestor no acesso, mas a maioria dos campos fica travada (read-only) para o gestor — ver §2.3.
10. Requisitos não-funcionais
10.1 Segurança
CSP, HSTS (fora de localhost), X-Content-Type-Options, X-Frame-Options (DENY), Referrer-Policy,
Permissions-Policy em toda resposta não-estática. CSP usa unsafe-inline sem nonce — lacuna de
hardening aceita conscientemente (instrumentar nonce exigiria mudar todo Script inline do
Next.js); mitigação no backlog. CSRF valida Origin (com fallback Referer) em todo POST/PUT/PATCH/DELETE,
fail-closed em produção.
Tiers por escopo: login não-autenticado 10/min, ações pesadas (analytics/embarque/planejamento) 20/min, limite global 60/min, restauração de backup 2/hora. Login por CPF (estudante/motorista) tem throttle adicional de 5 tentativas/15min tanto por IP quanto por CPF (hash, não CPF em claro) — mitigação anti-enumeração.
10.2 LGPD — zero-masking
CPF, telefone, e-mail e nome são exibidos completos em toda a UI, logs e exportações — decisão de produto para rastreabilidade e auditoria, com conformidade via consentimento + registro de operações, não via mascaramento. Apenas credenciais (senha, token, secret) são redigidas em log. Única exceção pontual: a chave de cache de rate-limit por CPF usa hash, porque chaves de cache Redis são visíveis a ferramentas de infraestrutura fora do pipeline de log da aplicação — não é uma mudança de política, é escopo técnico específico.
10.3 Acessibilidade
WCAG 2.2 AA como gate interno do projeto (contraste 4.5:1, badges com ícone+texto nunca só cor, navegação por teclado). A página pública de Acessibilidade declara conformidade AAA (contraste 7:1) — acima do que o gate interno garante; sinalizar essa distância ao escrever conteúdo institucional público.
11. Limitações e exceções conhecidas (transversais)
O sistema já foi multi-tenant; hoje cada VPS/banco serve uma prefeitura. Não existe isolamento de município na mesma instância. Qualquer menção a "tenant" em documentação antiga é resíduo.
Apesar do PostGIS estar na stack, Ponto de Embarque e Instituição ainda usam campos numéricos simples, não o tipo geoespacial nativo — migração pendente, não afeta a UI hoje mas limita queries espaciais avançadas.
A mensagem de erro de login não distingue "senha errada" de "conta não provisionada" — proteção contra enumeração de CPFs válidos. É comportamento esperado, não um bug de UX a "corrigir" no tutorial.
12. Casos de uso adicionais
Gestor cria a instituição de destino (se ainda não existir) → cadastra os pontos de embarque no mapa → cria a rota, define turno e adiciona os pontos ao editor via arrastar-e-soltar, marcando origem/destino → define motorista padrão, dias de funcionamento e horário de cutoff → salva; a validação trava o botão até existir exatamente 1 origem e 1 destino.
Admin acessa Backup, seleciona um backup enviado ao Drive com status "sucesso", confirma a intenção (gera token de 5 min) e executa a restauração — o sistema gera automaticamente um backup de segurança do estado atual antes de aplicar, permitindo reverter para o estado anterior caso a restauração, embora concluída, traga dados indesejados.
Gestor abre o wizard de importação em Estudantes → sobe um CSV (até 2.000 linhas) → sistema mapeia colunas automaticamente por nome → gestor revisa o preview e corrige mapeamentos → sistema valida (CPF duplicado no banco ou dentro do próprio arquivo, e-mail vazio) → confirma → acompanha o progresso via polling da tarefa assíncrona → recebe o resultado final com linhas aceitas/rejeitadas.
13. Fora de escopo / gaps de implementação conhecidos
- Ações em massa sobre estudantes (ativar/inativar/exportar seleção) — modelado na UI, não conectado ao backend
- Cadastro de manutenção e abastecimento de veículo — regras completas no backend, sem formulário de criação no painel
- Entrega real de comunicação (push/SMS/e-mail/WhatsApp) — modelo de dados existe, envio efetivo é fase futura
- Biometria facial, roteirização automática, módulo financeiro completo, integração nativa com WhatsApp/SMS, multi-tenant SaaS
src/components/features/student/— componentes de carteirinha/QR/confirmação já construídos no frontend mas não referenciados por nenhuma página (provável portal do aluno futuro)