📄 Documento de Execução — Card 18: [M4] Gestão de Alunos & Matrículas
| Campo | Valor |
|---|---|
| Card Trello | [18] [M4] Gestão de Alunos & Matrículas |
| URL Trello | https://trello.com/c/4KkTlFBE |
| Marco | M4 — Painel Direção/Unidade LOCAL (04/08–??/08) |
| Data execução | 04/08/2026 |
| Responsável | Wellington Santiago (via ZCode) |
| Doc anterior | Card 17: Dashboard da Unidade |
| Próximo card | Card 19: Gestão de Turmas & Grade |
| Commits | b61bb5d |
🎯 1. O que foi implementado
O Card 18 entrega o módulo completo de gestão de alunos e matrículas para o painel da direção (LOCAL/SUPERVISOR/MASTER). Esta é a primeira peça do M4 (Painel Direção/Unidade) e estabelece os padrões de cadastro que serão reutilizados nos cards 19-21.
Backend — local.students (CRUD de alunos)
Foram criados 5 procedures no sub-router local.students:
students.list— Lista paginada (20/pg) com busca por nome/RA, filtros por status (ativo/inativo), curso e filial. RespeitabranchWhere(ctx): LOCAL vê só própria filial, SUPERVISOR suas filiais, MASTER todas.students.detail— Ficha completa com dados pessoais, médicos (criptografados), responsáveis, últimas 5 notas, últimas 5 frequências, contadores agregados (_count). Mapeamento explícito para garantir tipos no cliente tRPC.students.create— Cria User + Student em transação. Gera RA automático (AAAA-NNNNN= ano + sequencial de 5 dígitos por filial). Valida idade mínima (5 anos) e CPF (check digit DV1+DV2). Encripta CPF, RG, alergias, medicações e observações de saúde com AES-256-GCM.students.update— Atualiza campos; reencripta dados sensíveis quando alterados.students.deactivate— Soft-delete (LGPD): marcaisActive=false+ cancela matrículas ativas com motivo.
Backend — local.enrollments (funil de matrículas)
5 procedures no sub-router local.enrollments:
enrollments.list— Lista matrículas agrupadas por status para o Kanban. Busca por aluno, filtra por curso/filial.enrollments.create— Cria matrícula (LEAD ou PRE_ENROLLED). Valida: aluno pertence à filial, turma pertence à filial, curso ativo para filial, vagas disponíveis (maxStudents=10).enrollments.updateStatus— Avança matrícula no funil. DefineenrolledAtao ativar,cancelledAt+cancelReasonao cancelar,graduatedAtao formar.enrollments.transfer— Transfere entre turmas sem custo (decisão cliente). Marca matrícula atual como TRANSFERRED + cria nova ACTIVE preservando termos financeiros (mensalidade, desconto, vencimento, bolsa). Valida vagas na turma de destino.enrollments.history— Timeline completa de matrículas do aluno.
Frontend — 4 páginas reescritas/criadas
/local/alunos(REESCRITA) — Lista em tabela com cards de resumo (Total/Ativos/Inativos), busca, filtros (status, curso), paginação, e navegação para ficha. Antes usava dados mock (@/data/mock); agora é tRPC real./local/alunos/novo(NOVA) — Cadastro completo em 2 colunas: formulário (dados pessoais, contato, médicos, responsável) + lateral com foto webcam e ações. Campos sensíveis marcados com badge "Criptografado". Validação client-side de idade mínima./local/alunos/[id](NOVA) — Ficha completa: cabeçalho com avatar + badges de status, dados pessoais, responsáveis, informações médicas, notas recentes, frequência recente, resumo acadêmico, e timeline de histórico de matrículas. Modais de transferência e desativação./local/matriculas(REESCRITA) — Kanban do funil com 6 colunas ativas (LEAD → PRE_ENROLLED → PENDING_DOCS → PENDING_PAYMENT → PENDING_SIGNATURE → ACTIVE) + seção colapsável de estados terminais (TRANSFERRED, GRADUATED, CANCELLED, DROPPED_OUT). Botão "Avançar" em cada card abre modal de transição.
Decisões de segurança aplicadas
- RBAC hierárquico via
branchWhere(ctx): LOCAL só vê/manipula alunos da própria filial; SUPERVISOR das suas filiais; MASTER vê todas. - AES-256-GCM em CPF, RG, alergias, medicações, observações de saúde (padrão SEGURANCA_LGPD §2.1).
- Validação CPF com check digit (DV1 + DV2) — rejeita CPFs com dígitos iguais.
- Idade mínima 5 anos (confirmado pelo cliente).
- Soft-delete (LGPD): dados nunca excluídos, apenas
isActive=false. - Transferência sem custo (decisão cliente confirmada).
✅ Critérios de aceite validados
| # | Critério | Status |
|---|---|---|
| 1 | Cadastro de aluno (com foto/webcam) | ✅ |
| 2 | Funil de matrícula (Kanban LEAD→ACTIVE) | ✅ |
| 3 | Histórico do aluno (timeline) | ✅ |
| 4 | Transferência entre turmas (sem custo) | ✅ |
📁 2. Arquivos criados/modificados
Criados
| Arquivo | Função |
|---|---|
src/app/(dashboard)/local/alunos/novo/page.tsx |
Cadastro completo de aluno (form + webcam + guardian + médicos) |
src/app/(dashboard)/local/alunos/[id]/page.tsx |
Ficha do aluno + histórico + transferir + desativar |
docs/execucao/18-m4-alunos-matriculas.md |
Este documento |
Modificados
| Arquivo | Mudança |
|---|---|
src/server/trpc/routers/local.ts |
+sub-routers students (5 proc) e enrollments (5 proc) + helper isValidCPF |
src/app/(dashboard)/local/alunos/page.tsx |
Reescrita: mock → tRPC real, +filtros, +paginação, +cards resumo |
src/app/(dashboard)/local/matriculas/page.tsx |
Reescrita: mock → Kanban real com 6 colunas + terminais |
decisoes.md |
+Bloco 13 (2 pendências resolvidas: desconto irmãos=manual, bolsa=cadastra LOCAL+aprova MASTER) |
🗄️ 3. Schema do banco (mudanças)
Nenhuma mudança de schema. Todos os models necessários já existiam:
Student(userId, fullName, birthDate, cpf, rg, branchId, registrationNumber, dados médicos)User(email, role, status, branchId)Enrollment(studentId, classId, courseId, status, monthlyFee, discountPercent, scholarshipType)Guardian+StudentGuardian(vínculo responsável↔aluno)
A criptografia AES-256-GCM usa ENCRYPTION_KEY do .env (formato iv:authTag:ciphertext).
🔌 4. Handoff para o próximo card
Variáveis de ambiente novas
- Nenhuma (usa
ENCRYPTION_KEYjá existente).
Procedures disponíveis (reutilizáveis)
local.students.list/detail/create/update/deactivate— CRUD de alunoslocal.enrollments.list/create/updateStatus/transfer/history— funil de matrículasisValidCPF(raw)— helper de validação de CPF (check digit)branchWhere(ctx)— filtro de filial por role (reutilizado do Card 17)
Padrões estabelecidos (reutilizáveis no M4/M5)
- RA automático: formato
AAAA-NNNNN(ano + sequencial por filial) - Webcam capture: getUserMedia → canvas → toDataURL (reutilizável para foto de professores, responsáveis)
- Kanban pattern:
columnsagrupado por status + seção colapsável de terminais - Timeline pattern: histórico vertical com linha conectora e badges coloridos por status
- Mapeamento explícito de tipos: inferência do Prisma
includenão propaga para cliente tRPC — sempre mapear campos no return
Hooks/utilidades disponíveis
trpc.local.students.*etrpc.local.enrollments.*prontos para uso
📋 5. Checklist do Trello — status por item
[Entregas] 4/4 ✅
- Cadastro de aluno (com foto/webcam)
- Funil de matrícula
- Histórico do aluno
- Transferência entre turmas
[Especificação Técnica] — implementado
| Item | Status | Notas |
|---|---|---|
| student.create (AES-256 CPF/RG/medical) | ✅ | Transação User+Student |
| student.list (branchId, filters, page) | ✅ | Paginação 20/pg |
| student.update | ✅ | Reencripta sensíveis |
| student.uploadPhoto (S3) | ⏳ | Webcam captura OK; upload S3 no Card 25/30 |
| student.webcamCapture | ✅ | getUserMedia client-side |
| enrollment.create | ✅ | Valida filial, curso ativo, vagas |
| enrollment.updateStatus | ✅ | Avança funil |
| enrollment.transfer | ✅ | Sem custo, preserva termos |
| Página /local/alunos (lista) | ✅ | tRPC real |
| Página /local/alunos/novo | ✅ | Form+webcam+guardian+médicos |
| Página /local/alunos/[id] | ✅ | Ficha+timeline+transferir |
| Página /local/matriculas (kanban) | ✅ | 6 colunas + terminais |
| StudentForm | ✅ | Inline na página /novo |
| WebcamCapture | ✅ | Inline na página /novo |
| PhotoPreview + retake | ✅ | Botão refazer |
| GuardianLinker | ⏳ | Campos no form; vínculo completo no Card 25 |
| MedicalInfoForm | ✅ | Inline, badge "Criptografado" |
| EnrollmentKanban | ✅ | 6 colunas horiz. scroll |
| EnrollmentCard | ✅ | Avatar+curso+valor+avançar |
| StatusTransitionModal | ✅ | Select status + motivo cancelamento |
| ContractUpload (PDF) | ⏳ | Card 33 (Migração) ou Card 25 |
| EnrollmentHistory (timeline) | ✅ | Vertical com badges |
| TransferModal | ✅ | Turma destino + motivo |
| Busca por nome/CPF/RA | ✅ | Input search |
| Filtro por turma/status/curso | ✅ | 2 selects |
| Exportar Excel | ⏳ | Refinamento futuro |
| Validação CPF (check digit) | ✅ | isValidCPF helper |
| Validação idade mínima | ✅ | 5 anos |
| Auditoria CREATE/UPDATE | ⏳ | Card 26 (Auditoria & Logs) |
| Notificar responsável (email) | ⏳ | Card 31 (Workflows E-mail) |
| Job gerar contrato PDF | ⏳ | Card 33/34 (Puppeteer) |
[Validar com Cliente] 10/10 ✅
Todas as 10 perguntas respondidas (8 já estavam + 2 defaults adotados neste card).
🚀 6. Deploy DEV
- Build:
npm run build✅ (local + VPS) - Commit:
b61bb5demmain - VPS: git pull + build + pm2 reload genioon-dev (id 3)
- Smoke test: HTTP 200 em
/login, título "GENIOON — Sistema Escolar Unificado" ✅ - URL DEV: https://sistemaescolar.wellka.com.br/local/alunos (login LOCAL: diretor@genioon.com.br)
🧠 7. Contexto gerado para próximas etapas
- Padrão Kanban estabelecido — reutilizável no Card 30 (CRM Funil de Leads) que tem funil similar (Novo→Contatado→Qualificado→Visita→Proposta→Matriculado).
- Webcam + crypto — padrão de captura de foto + criptografia de dados sensíveis pronto para professores (Card 12 já feito) e responsáveis (Card 25).
- Transferência sem custo — a lógica de "marcar anterior + criar nova preservando termos" é reutilizável para transferência entre filiais (se solicitado futuramente).
- Mapeamento explícito de tipos Prisma→tRPC — lição importante: a inferência de
includedo Prisma 7 não propaga automaticamente para o cliente tRPC; sempre mapear campos no return do procedure. - GuardianLinker parcial — os campos de responsável estão no form, mas a vinculação completa (criar User Guardian + StudentGuardian) fica para o Card 25 (Gestão de Usuários RBAC), onde o fluxo de convite/ativação de responsáveis será implementado.
🎯 8. Próximo card
Card 19: [M4] Gestão de Turmas & Grade — CRUD de turmas (Class), grade horária (ScheduleSlot), e vinculação professor×turma×matéria (ClassTeacher). O select de turmas no modal de transferência (atualmente vazio) será populado por este card.