20 KiB
20 KiB
Log da Migração Massiva SQL-First (Sessão Completa)
Visão Geral
Nesta sessão de trabalho, realizamos o "core" da transição do sistema EduManager, saindo do modelo puramente JSON (school_data.json) e consolidando 4 módulos centrais diretamente no Banco de Dados Relacional PostgreSQL.
Módulos Migrados
Fase 4: Gestão de Alunos e Autenticação
- Backend Manager: CRUD no
database.jspara tabelaalunos, com rotas/api/alunose/api/alunos/:id/rematricularnoserver.selfhosted.jsque executam operações no PostgreSQL e realizam sincronização reversa em tempo real no legadoschool_data.jsonpara total compatibilidade legacy. - Frontend Manager (
Students.tsx): Completamente refatorado para ler e gravar diretamente nas rotas relacionais/api/alunos, eliminando 100% das chamadasdbService.saveDatanesta tela, mantendo apenas o estado em memória sincronizado para continuidade UX. - Portal do Aluno: Login (
/api/portal/login) e perfil (/api/portal/me) reescritos para consultar a tabelaalunosno PostgreSQL.
Fase 5: Avaliações e Provas
- Backend e Frontend conectados às tabelas
provasequestoes_provas.
Fase 6: Cronograma e Aulas
- Backend Manager: Queries em lote (
insertAulas,getAulasByTurma,getAllAulas,deleteAulas). - Frontend Manager (
LessonSchedule.tsx): Consomefetch('/api/aulas')em estado próprio (dbLessons). - Frontend Manager (
Classes.tsx): Ao criar/editar turma e gerar cronograma, agora envia aulas viaPOST /api/aulas/lotepara o PostgreSQL. - Portal do Aluno: Rota
/api/portal/aulasfazSELECT FROM aulas WHERE turma_id = ANY(...).
Fase 7: Contratos e Modelos
- Backend Manager: CRUD para
contratosemodelos_contrato. - Frontend Manager (
Contracts.tsx): Consome/api/contratose/api/modelos-contrato. - Portal do Aluno: Rota
/api/portal/contratosfazSELECT FROM contratos WHERE aluno_id = $1.
Bugs Encontrados e Corrigidos
🐛 Bug 1: Tela Branca na Aba Alunos (Students.tsx)
- Causa: Referência circular no
useState—useState<any[]>(dbClasses || [])referenciava a si mesma. - Fix: Alterado para
useState<any[]>(data?.classes || []).
🐛 Bug 2: Dados Não Migrados para PostgreSQL
- Causa: A rotina
syncJsonToRelationalTablessó roda quando o Manager salva o JSON viaPUT /api/school-data. Como a migração era nova, os dados nunca foram sincronizados. - Fix: Criado script
migrate_aulas_contratos.cjsque conecta diretamente ao PostgreSQL de produção e roda os INSERTs. - Resultado: 109 aulas, 9 contratos, 1 modelo e 89 frequências migrados com sucesso.
🐛 Bug 3: Aulas Órfãs (FK Constraint)
- Causa: 57 aulas no JSON pertenciam a uma turma deletada (
d48b268c-...), causando violação de FK. - Fix: O script filtra aulas cujo
classIdnão existe na tabelaturmas.
🐛 Bug 4: Contratos Não Apareciam no Manager
- Causa: A função
getContratos()retornava o campo comodate, mas o frontend (Contracts.tsx) esperavacreatedAt. - Fix: Corrigido o mapeamento em
database.jspara retornarcreatedAt: r.created_at_fmt.
🐛 Bug 5: Classes.tsx Não Salvava Aulas no PostgreSQL
- Causa: Ao criar/editar turma com cronograma, as aulas geradas eram salvas apenas no JSON (
data.lessons), nunca no banco. - Fix: Adicionado
fetch('/api/aulas/lote')noClasses.tsxpara enviar as aulas geradas ao PostgreSQL.
Estado Final do Banco de Dados
| Tabela | Registros |
|---|---|
| alunos | 9 |
| aulas | 109 |
| contratos | 9 |
| frequencias | 89 |
| modelos_contrato | 1 |
| provas | 3 |
| turmas | 3 |
Padrões de Arquitetura
- Reverse Sync (Mão Dupla): Frontend salva no SQL via API e mantém backup no JSON.
- Fallback Gradual: Portal prioriza SQL, invoca JSON apenas se banco retornar vazio.
- Migração de Dados: Executada via script Node.js conectando diretamente ao PostgreSQL de produção (host:
150.230.87.131, user:edumanager).
Fase 8: Consolidação de Frequência, Registro de Matrículas e Contratos Relacionais
- Justificativa Única Rígida (Portal): Implementação de regra de validação rígida impedindo que o aluno envie mais de uma justificativa por aula. O Portal do Aluno agora exibe um aviso dinâmico informando que a aula já possui justificativa e desativa o envio. O backend valida a existência e retorna erro HTTP 400.
- Sincronização Direta de Contratos (Manager): O fluxo de salvamento de matrículas foi aprimorado para disparar uma chamada de
POST /api/contratosem tempo real ao salvar o aluno, escrevendo a emissão do contrato diretamente no PostgreSQL na VPS. - Refinamento do Modal de Alunos (Manager): O checkbox "Gerar Taxa" foi inteiramente removido do modal de matrícula. O checkbox "Gerar Contrato Automático" agora vem selecionado (
true) por padrão em novos cadastros e desmarcado (false) ao editar matrículas para prevenir duplicações acidentais. - Relatório de Frequência Geral em PDF (Manager): Refatoração do exportador de PDF no módulo Registro de Frequência para gerar uma Ficha de Frequência Geral (Roster de todos os alunos ativos da turma, com contagem acumulada de presenças, faltas, justificativas e porcentagem de frequência de cada um) de modo a corresponder perfeitamente ao que o administrador visualiza na modal, eliminando downloads vazios.
Fase 9: Endurecimento da Pré-Matrícula, Upload de Panfleto Promocional e Proteção contra Duplicatas
- Folder Promocional Dinâmico e Reordenável (Banner): Refatorado o folder promocional (flyer) para ser tratado de forma 100% dinâmica como um campo personalizado especial (
tipo: 'banner') dentro do construtor de formulários. O administrador pode fazer o upload da imagem promocional diretamente no construtor (no modal de novo campo ou de edição), excluir e reordenar sua posição de exibição livremente em relação aos outros campos. - Renderização Pública Inline Premium: A página pública de pré-matrícula renderiza a imagem do banner inline de forma premium, responsiva e exatamente na posição sequencial configurada na listagem de campos do banco.
- Prevenção de Duplicatas e Spam: Bloqueio de envios duplicados no backend comparando e-mail e telefone limpos de caracteres não-numéricos (para total equivalência).
- Tratamento de Estado Rascunho (
draft): Se a configuração estiver em rascunho, exibe automaticamente uma página informativa de "Vagas Lotadas - Novas vagas em breve" para proteger a integridade operacional antes do lançamento oficial. - Gestão de Campos Personalizados com Arquivos: Implementação de tipo
filepara campos customizados no formulário do aluno, com upload assíncrono transparente viaFormDatae exibição em formato de hiperlink nos detalhes da inscrição para o administrador. - Preservação de Histórico de Campos Personalizados (Soft Delete): Correção de bug onde a exclusão de um campo (ex: Sexo) fazia com que o rótulo do campo sumisse e exibisse o código UUID bruto na listagem de inscritos e na exportação de CSV. Implementado Soft Delete (
ativo = false) na exclusão e criado um mapeador inteligente com dicionário de fallbacks (getFriendlyLabel) que recupera os rótulos de campos excluídos ou legados em tempo real. - Correção de Máscaras de Entrada (Telefone/CPF/CEP): Correção de bug em teclados móveis (Android Gboard/iOS Safari) onde caracteres digitados desapareciam ou geravam loops repetitivos (ex:
(( () ()- 0-). O problema era causado por double event binding (dois ouvintesinputconcorrentes ativos no mesmo elemento). Centralizada a máscara no ouvinte global de formulário e aprimorada a máscara de telefone para suportar nativamente tanto números fixos (10 dígitos:(XX) XXXX-XXXX) quanto móveis (11 dígitos:(XX) XXXXX-XXXX). - Exclusão Automática Pós-Conversão: Implementada a exclusão automática da inscrição de pré-matrícula quando a mesma é concluída com sucesso e convertida em matrícula ativa de aluno no sistema. Captura o ID da pré-matrícula original de forma resiliente e dispara uma requisição
DELETEcontra/api/prematricula/inscricoes/:id, limpando instantaneamente a lista de pendências da aba de Pré-Matrícula sem requerer intervenção manual. - Favicon Dinâmico e Logos Arredondados: Implementação de crop dinâmico em tempo de execução usando canvas HTML5 para gerar favicons perfeitamente circulares (
rounded-full) a partir do logotipo cadastrado nas configurações da escola. O favicon circular dinâmico é atualizado automaticamente na aba do navegador tanto no painel administrativo do gestor quanto na página pública de pré-matrícula. Adicionalmente, todos os logotipos exibidos no painel do administrador (Sidebar) e na página pública foram estilizados com bordas elegantes, sombras sutis e arredondamento perfeito (rounded-full w-8 h-8 object-cover), elevando o alinhamento visual e a identidade estética premium da plataforma. - Favicon Dinâmico e Suporte PWA no Portal do Aluno: Estendi a geração de favicons perfeitamente circulares (
rounded-full) via canvas HTML5 para o Portal do Aluno, assegurando correspondência e marca unificada em toda a experiência do estudante. O logotipo da escola também foi estilizado como um círculo perfeito (rounded-full object-cover) na barra lateral (Sidebar.tsx) e na tela de Login do Portal (Login.tsx). Além disso, implementei suporte nativo e dinâmico a PWA (Progressive Web App) no Portal do Aluno: a API agora gera dinamicamente o arquivomanifest.jsoncom o nome personalizado e logotipo da escola, registra o Service Worker (sw.js) em segundo plano para atender aos critérios de instalação de navegadores e renderiza um botão premium de glassmorphism verde pulsante e micro-animado ("Instalar App") na Sidebar no momento em que o aplicativo se torna instalável, permitindo aos alunos instalar o EduManager em seus celulares/computadores como um aplicativo nativo. - Correção da Persistência do Valor (Pontuação Máxima) das Avaliações: Corrigido bug crítico no módulo de avaliações (Provas/Atividades) onde alterações na pontuação máxima ("Valor" ou
maxScore) não eram salvas no banco de dados e resetavam de volta para 10.0 ao recarregar a página. A falha ocorria devido à ausência da colunamax_scorenas operações de INSERT e UPDATE da camada de serviço (database.js), bem como a falta de mapeamento do campo no mapeador de retorno (getProvas) e no estado do React (Exams.tsxeReportCard.tsx). Mapeei dinamicamente a propriedademaxScoreem todos os fluxos da aplicação (Manager e Portal do Aluno), encapsulada pela conversão estritaNumber(p.max_score)em conformidade com a Regra 19 de integridade numérica, garantindo que as pontuações e notas correspondentes no Boletim Escolar e Portal do Aluno reflitam precisamente o valor personalizado no banco de dados. - Nova Regra de Cálculo de Notas (Soma Capped 10 & Média por Período): Refatorei por completo a lógica de cálculo de notas do boletim escolar no Manager (
ReportCard.tsx) e no Portal do Aluno (Notas.tsx). Agora, a nota de um aluno em um período para uma determinada disciplina é calculada pela SOMA das notas obtidas em todas as avaliações (provas e atividades) vinculadas àquele período, limitada ao valor máximo de 10.0 (cap a 10). A Média Geral do aluno passou a ser calculada a nível de período: primeiro é calculada a média aritmética de todas as disciplinas daquele período específico e, caso existam múltiplos períodos com notas, a Média Geral do aluno é calculada pela média aritmética dos períodos lançados; caso exista apenas um único período ativo, a média geral é a média aritmética das disciplinas daquele único período.
Fase 10: Limpeza da Arquitetura SQL-First do Portal do Aluno (Completa)
- Depreciação Total do JSON (
school_data) no Portal: Removemos cirurgicamente todas as dependências e fallbacks híbridos que liam ou escreviam no antigo cache JSON da tabelaschool_dataou arquivoschool_data.jsonemportal/server.selfhosted.js. - Autenticação, Configurações e Perfil: Login (
/api/portal/login), busca de dados da escola (/api/portal/escola), carregamento do perfil do aluno (/api/portal/me) e geração dinâmica domanifest.jsondo PWA agora são 100% orientados a tabelas relacionais do PostgreSQL (alunoseconfiguracoes). - Financeiro, Notas e Frequência: As rotas
/api/portal/financeiro(finanças e cobranças),/api/portal/notas(boletim escolar),/api/portal/frequenciae/api/portal/frequencia/justificarforam reescritas para acessar de forma estrita as tabelas SQLalunos_cobrancas,notas_boletim,disciplinas,periodos,provasefrequencias, sem requerer sincronização nem backup JSON. - Contratos, Certificados e Aulas: As rotas de contratos (
/api/portal/contratos), certificados (/api/portal/certificados) e grade de aulas (/api/portal/aulas) agora operam de forma nativa e pura por meio de queries SQL no PostgreSQL. - Remoção de Código Morto: Os métodos auxiliares de compatibilidade híbrida
getSchoolData()esaveSchoolData()foram totalmente eliminados do servidor do portal.
Fase 11: Padronização de Encargos Financeiros e Simulação Asaas
- Regra de Postergação de Fins de Semana: Implementada lógica que detecta se a data de vencimento da parcela recai em um final de semana (sábado ou domingo), estendendo a tolerância para segunda-feira e começando a calcular juros e multa apenas a partir de terça-feira.
- Perda Automática de Desconto: Se a parcela está atrasada (overdue), o desconto é considerado expirado. Os cálculos de multa (lateFee) e juros (interest) incidem sobre o valor bruto original (gross amount), e o desconto deixa de ser exibido/subtraído nas telas de simulação.
- Remoção de Taxas Padrão Ocultas: Caso o curso do aluno não possua as taxas de multa/juros configuradas no banco, o sistema agora assume 0% de encargos (antes assumia fixo 2% de multa e 1% de juros), respeitando estritamente o que foi cadastrado.
- Sincronização de Visões: Aplicado de forma idêntica no painel Manager (tanto na tabela geral quanto no histórico de cobranças por aluno) e no Portal do Aluno para correspondência visual absoluta.
Fase 12: Simulação de Encargos no Dashboard do Portal do Aluno (SQL-First)
- Correção do Dashboard do Portal: Atualizado o painel principal do Portal do Aluno (
portal/src/pages/Dashboard.tsx) para embutir as funções de simulação matemática de juros/multa de atraso e expiração de desconto. O dashboard agora reflete exatamente o mesmo valor com encargos calculado na página Financeiro, unificando os totais pendentes e os valores de parcelas vencidas do card "Próximo Vencimento". - Declaração de Tipos: Atualizada a interface
Paymentemportal/src/types.tspara opcionalmente expor as propriedadeslateFee,interestevalor_pago, garantindo a validação estrita do compilador TypeScript e prevenindo quebras de tela (White Screen).
Fase 13: Consolidação e Resiliência do Módulo de Inteligência Artificial (Julho de 2026)
- Mensagem Amigável de Cota Excedida: Adicionada a função helper
handleAiErroremExams.tsxpara interceptar falhas em todas as chamadas de IA. Erros de limite e cota (HTTP 429) do Gemini, OpenAI, Claude e OpenRouter são formatados em um alerta limpo que explica o erro e fornece a solução correspondente (ex: ativar faturamento ou adicionar saldo). - Remoção de Downgrade do Gemini 2.5 Flash: Corrigido bug crítico na rota
/api/ai/generate-questionsemserver.selfhosted.jsque reescrevia silenciosamente o modelo selecionadogemini-2.5-flashpara o antigogemini-1.5-flash, o que causava erros 404 em contas de API novas onde o 1.5 não está provisionado. - Geração Híbrida de Imagens Gemini/Imagen: Implementação de rotas no backend que suportam a geração nativa de imagens via API do Imagen 3 (
:generateImages) para modelosimagen-, e via multimodalidade (responseModalities) para modelos Gemini. Adicionado fallback em cascata automático entre modelos (imagen-3.0-generate-002,gemini-2.5-flash-image,gemini-3.1-flash-image). - Migração de Chaves de IA para o PostgreSQL: Adicionada rotina de migração transparente que move as credenciais e configurações de IA do antigo cache JSON de configurações para a tabela relacional
configuracoes_ia. - Correção de Autofill no Chrome: Corrigido bug onde o recurso de preenchimento automático do Chrome inseria o usuário 'admin' na barra de busca de provas ao carregar o modal de configuração de IA.
Fase 14: Correção de Precisão Financeira e Fallback do Módulo de IA (Julho de 2026)
- Exibição Estrita de Duas Casas Decimais: Adicionado o parâmetro
maximumFractionDigits: 2em todos os locais onde valores financeiros são formatados no painel Manager (arquivosFinance.tsx,Students.tsxeCourses.tsx). Isso corrige de forma definitiva a exibição de parcelas vencidas com 3 casas decimais (ex: R$ 175,871), aplicando o formato monetário padrão brasileiro de exatamente 2 casas decimais. - Fallback e Filtro de Modelos Gemini Descontinuados: Atualizado o modelo padrão de IA nas camadas de banco (
database.js), backend (server.selfhosted.js) e frontend (Exams.tsx) degemini-1.5-flashparagemini-2.0-flash. Além disso, foi adicionado um filtro que intercepta modelos inexistentes ou inválidos configurados no banco (comogemini-2.5-flash-lite) e faz o redirecionamento automático sob o capô para o modelo estávelgemini-2.0-flash, evitando erros 404.
Fase 15: Disparo de Mensagens em Massa da Pré-Matrícula e Pré-Visualizações Dinâmicas no WhatsApp (Julho de 2026)
- Disparo em Massa na Pré-Matrícula: Criado botão independente de "Disparo em Massa" na aba de Pré-Matrícula do Manager (
PreMatricula.tsx). Ele abre um modal completo idêntico ao painel geral de mensagens (com filtros de destino: todas as inscrições, por turma ou individual; editor de texto; emojis; e envio de anexos via multipart/form-data). Removi as opções duplicadas de pré-matrícula da aba de Mensagens geral (Messages.tsx), que agora é exclusiva para alunos matriculados. - Metadados Open Graph Dinâmicos (OG Tags): O gerador de HTML público do formulário de pré-matrícula no backend (
server.selfhosted.js) foi atualizado para receber metadados dinâmicos da pré-matrícula. Agora, ele busca no PostgreSQL as configurações de título, descrição e imagem de pré-visualização. Ele monta e injeta as tags<meta property="og:*">estaticamente no cabeçalho<head>do HTML final entregue à rede social. - Resolução de URL Absoluta de Mídia: O Express agora detecta o protocolo e host reais das requisições via cabeçalhos proxy (
x-forwarded-proto,x-forwarded-host) no Express e monta uma URL de imagem absoluta para que plataformas como o WhatsApp consigam puxar o preview do link. - Upload de Imagem de Pré-visualização com Progresso e Exclusão: Adicionada opção para upload e exclusão de imagem de visualização personalizada na aba de Configurações da Pré-Matrícula. Ela é integrada com o MinIO local via
/api/prematricula/upload. A interface exibe uma barra de progresso em tempo real usandoXMLHttpRequeste um banner de preview grande e de alta qualidade. - Fallback da Logo Escolar: Se nenhuma imagem de visualização personalizada for carregada nas configurações de pré-matrícula, o sistema exibe e usa automaticamente a logo padrão da escola configurada no perfil global.
- Compactação de Imagens e Conversão de Formato (Sharp): O endpoint
/api/prematricula/uploadagora detecta arquivos de imagem, redimensiona-os proporcionalmente (limite de até 1200x1200px) e converte-os para o formato JPEG progressivo com qualidade 75% usando a bibliotecasharp. Isso impede que o WhatsApp recuse previews de imagens WebP ou imagens muito pesadas (acima de 300KB), enquanto mantém os arquivos de PDF/documentos intactos. - Upload com Progresso nos Folders Promocionais: A mesma barra de progresso animada e upload via
XMLHttpRequestforam integrados nas áreas de upload de folders/banners promocionais (no formulário de novo campo e edição de campo emPreMatricula.tsx).