By Sport Hub
U

Documentação do Sistema

By Sport Hub · Manual técnico completo · Auditoria: 14/05/2026 · Atualizado: 07/09/2026

Dados ao Vivo

Atualizado: 11:39:38

Alunos Total

0

0 ativos · 0 inadimplentes

Cobranças (Cora)

0

0 abertas · 0 pagas · 0 canceladas

Responsáveis

0

Registros na entidade Guardian

Turmas / Colaboradores

19 / 0

Turmas ativas e colaboradores

Nenhum evento crítico recente nos logs de auditoria.

Padrão Oficial do Sistema Financeiro

📄 Charge — Mensalidades (Cora)

  • Toda mensalidade emitida como boleto/PIX
  • Integrado à API Cora via PHP proxy mTLS
  • Contém boleto_url, pix_emv, linha_digitavel
  • Status: OPEN → PAID via webhook Cora (coraWebhook — implementado e ativo)
  • Fonte de verdade para receita de mensalidade

💳 Payment — Controle Interno

  • Receitas manuais (avulso, evento, produto)
  • Despesas fixas e variáveis
  • Folha de pagamento de colaboradores
  • Confirmações manuais de recebimento
  • ⛔ NÃO usar para mensalidades Cora

⚠️ Payment para mensalidades será descontinuado.

Regra Crítica — Não Violar

Não criar registros de Payment para mensalidades integradas à Cora. Mensalidades com boleto ou PIX bancário devem usar exclusivamente a entidade Charge. A duplicidade entre Payment e Charge é o principal problema arquitetural do sistema hoje.

Fluxo Oficial de Cobrança Mensal

Cobrança Bancária (Boleto/PIX via Cora)

👤 Aluno AtivogerarCobrancasMensais()criarBoletoCora()PHP Proxy mTLS🏦 API CoraCharge OPEN✅ Webhook → PAID

Webhook Cora implementado e ativo (coraWebhook). Ao receber evento PAID, Charge é atualizada automaticamente e e-mail de confirmação é enviado ao responsável.

Controle de Inadimplência (via Payment — provisório)

Cron Diário 09hupdateStudentDelinquency()Payment vencido >30d?Student → Inadimplente

⚠️ Lê apenas Payment, ignora Charge. Deve ser adaptado após implementação do webhook Cora.

Status do Sistema — Auditoria de Código: 14/05/2026

Funcionando

  • ✓Cadastro de alunos (5 etapas)
  • ✓Matrículas online (/matricula)
  • ✓Gestão de turmas/unidades
  • ✓Emissão boleto/PIX via API Cora
  • ✓Webhook Cora → Charge PAID + e-mail
  • ✓Controle financeiro (DRE, Dashboard, LivroCaixa)
  • ✓Folha de pagamento colaboradores
  • ✓Portal do aluno/responsável com sliding session
  • ✓Controle de acesso RBAC (9 perfis)
  • ✓Onboarding por e-mail (emails 2 e 3 agendados)
  • ✓Auditoria imutável do sistema
  • ✓Módulo Responsáveis com impersonação admin
  • ✓sendSystemEmail via Resend + EmailTemplate
  • ✓Renovação automática de sessão (renewPortalSession)

Com Problemas / Atenção

  • manageCollaboratorAccess

    Automação entity (Collaborator create) falha — sem token de usuário retorna 401. Workaround: inviteAllCollaborators manual.

  • CoraIntegration.jsx

    UI usa dados mockados (setTimeout/simulação) — não reflete produção

  • updateStudentDelinquency

    Lê APENAS Payment — ignora Charge.status=PAID. Alunos que pagam via Cora ficam Inadimplentes.

  • coraWebhook sem assinatura

    Nenhuma verificação HMAC ou segredo — qualquer POST pode marcar Charge como PAID

  • onStudentSave em modo de teste

    Validações de campos obrigatórios DESATIVADAS via comentário explícito no código. Apenas chama generateStudentCharge.

  • Student restauração pós-webhook

    coraWebhook não chama Student.update após Charge=PAID. Restauração Inadimplente→Ativo ausente.

  • calculatePayroll incompleto

    Função retorna apenas dados do Collaborator — cálculo real está em calculateCollaboratorPayroll.

Não Implementado

  • ✗Reconciliação automática de Charges via callCora
  • ✗Cancelamento automático de Charges vencidas
  • ✗Emissão automática de NF-e
  • ✗Notificações WhatsApp/SMS
  • ✗Portal responsável financeiro separado
  • ✗Vínculo charge_id em Payment
  • ✗Validação de assinatura no webhook Cora
  • ✗Restauração automática Student→Ativo pós-webhook
  • ✗AuditLog de eventos do webhook
  • ✗Expiração configurável de token JWT

Guia Rápido de Uso

Como cadastrar um aluno

  1. 1Acesse /alunos → clique em "Novo Aluno"
  2. 2Preencha as 5 etapas: Dados → Endereço → Responsável → Autorizações → Operacional
  3. 3Na etapa Operacional: defina Unidade, Turma, Mensalidade e Dia de Vencimento
  4. 4Salvar → aluno convidado por e-mail automaticamente (role='user')
  5. 5Sistema valida campos obrigatórios (onStudentSave) — se incompleto, status muda para Inativo
  6. 6Payment de mensalidade criado automaticamente (generateStudentCharge) — em processo de descontinuação para mensalidades Cora

Mensalidades devem ser geradas exclusivamente via Charge (Cora). O fluxo via Payment está sendo descontinuado para mensalidades e não deve ser utilizado para novos lançamentos integrados.

Como gerar cobranças (Boleto/PIX via Cora)

  1. 1Acesse /financeiro → clique em "Gerar Cobranças Mensais"
  2. 2Sistema executa gerarCobrancasMensais() para todos os alunos Ativos sem Charge no mês
  3. 3Para cada aluno: criarBoletoCora() → PHP proxy → API Cora
  4. 4Charge salvo com boleto_url, pix_emv e linha_digitavel
  5. 5⚠️ Corrigir bug de duplicidade antes de usar em produção em larga escala

Como acompanhar pagamentos

  • /financeiro → aba Receitas: lista Payments com status Pendente/Pago/Atrasado
  • Confirmar recebimento: clicar no registro → marcar como Pago
  • Charges (Cora): status atualizado automaticamente via webhook da Cora (coraWebhook) quando o pagamento é confirmado pelo banco
  • /financeiro-dashboard → análise por unidade/turma/período
  • /dre → demonstrativo de resultado | /livro-caixa → extrato cronológico

Como identificar inadimplência

  • Automático: updateStudentDelinquency roda diariamente às 09h
  • Critério: Payment de Mensalidade vencido há mais de 30 dias
  • Resultado: Student.status → Inadimplente (registrado em FinancialLog)
  • Reverter: confirmar Payment como Pago → na próxima execução aluno volta para Ativo
  • /alunos → filtro por status 'Inadimplente' para listar casos

Auditoria de Bugs — Leitura Direta do Código (14/05/2026)

Cada item abaixo foi verificado lendo o código-fonte real das funções listadas. Status: ✅ CORRIGIDO ⚠️ AINDA ABERTO 🔵 EM PROGRESSO

manageCollaboratorAccess — 15 erros consecutivos

✅ CORRIGIDO em 14/05/2026

Função aceita chamada via frontend E trigger sem auth. invite_pending=true como fallback quando trigger não tem contexto de auth. Permissões granulares implementadas.

coraWebhook — validação de assinatura HMAC-SHA256

✅ CORRIGIDO em 14/05/2026

Validação HMAC-SHA256 implementada com graceful degrade. Sem CORA_WEBHOOK_SECRET: processa com warning. Com secret: valida e rejeita POST inválidos. PENDENTE: configurar CORA_WEBHOOK_SECRET no painel da Cora.

onStudentSave — modo teste / validações reativadas

✅ CORRIGIDO em 14/05/2026

Modo teste removido. Validações de campos obrigatórios reativadas. Cadastro incompleto → Student Inativo. Logs de debug removidos.

updateStudentDelinquency — leitura de Charge.status=PAID

✅ CORRIGIDO em 14/05/2026

Agora verifica Charge.status=PAID além de Payment. Aluno que paga via boleto Cora é restaurado para Ativo automaticamente. FinancialLog registrado em cada mudança de status.

Restauração automática Student→Ativo após Charge=PAID

⚠️ AINDA ABERTO

Código lido (functions/coraWebhook): após atualizar Charge→PAID, função apenas chama tryClaimAndSendEmail(). Nenhuma chamada a Student.update ou verificação de status do aluno.

Emails onboarding 2 e 3 — migrados para EmailTemplate

⚠️ AINDA ABERTO

Código lido (functions/processOnboardingQueue): usa buildEmailHtml() hardcoded internamente via base44.integrations.Core.SendEmail — NÃO usa sendSystemEmail nem EmailTemplate do banco.

CoraIntegration.jsx — UI usa dados mockados (setTimeout)

⚠️ AINDA ABERTO

Não lido diretamente nesta auditoria, mas confirmado pela documentação anterior. Componente usa simulação e não executa chamadas reais à Cora.

AuditLog de eventos de webhook

⚠️ AINDA ABERTO

Código lido (functions/coraWebhook): nenhuma chamada a AuditLog.create ou FinancialLog.create. Eventos de pagamento via webhook não são rastreados.

generateMonthlyCharges — duplicação com gerarCobrancasMensais

⚠️ AINDA ABERTO

Código lido: generateMonthlyCharges (Scheduled dia 1) cria Payment. gerarCobrancasMensais (manual) cria Charge via criarBoletoCora. Dois sistemas paralelos sem vínculo entre si.

calculatePayroll — calcula folha: jornada + salário + transporte

⚠️ EM PROGRESSO

Código lido (functions/calculatePayroll): função recebe collaborator_id e month, busca o colaborador mas NÃO implementa o cálculo completo — apenas retorna o registro do Collaborator. Lógica real de cálculo está em calculateCollaboratorPayroll.

Integração Cora — Detalhe Técnico Completo

Fluxo Completo de Emissão

Admin /financeirogerarCobrancasMensais()criarBoletoCora(student_id, due_date)POST cora-boleto.php (mTLS)API Cora matlsCharge salvoE-mail ao guardian

Fluxo Completo de Recebimento

Pagamento bancárioAPI Cora dispara POSTcoraWebhook()Charge → PAIDE-mail confirmação

⚠️ Student.status NÃO é restaurado automaticamente após webhook. updateStudentDelinquency continua lendo apenas Payment.

Payload enviado à Cora (criarBoletoCora)

{
  customer: {
    name: guardian.full_name,
    email: guardian.email,
    document: { identity: cpf, type: "CPF" }
  },
  services: [{
    name: "Mensalidade YYYY-MM nome | Ref: 000001",
    amount: <centavos>
  }],
  payment_terms: { due_date: "YYYY-MM-DD" }
}

Payload do Webhook (Cora → coraWebhook)

// Formato aceito:
{ invoice: { id: "..." }, status: "PAID" }
// OU:
{ invoice_id: "...", status: "PAID" }

// Charge atualizada:
{
  status: "PAID",
  paid_at: new Date().toISOString(),
  payment_updated_by: "webhook"
}

Dados salvos na entidade Charge (após emissão)

  • cora_invoice_id: ID da fatura na Cora (chave de lookup no webhook)
  • boleto_url: URL completa do boleto para download
  • linha_digitavel: código para pagamento em banco
  • codigo_barras: código de barras completo
  • pix_emv: string PIX copia-e-cola
  • unique_key: studentId_YYYY-MM (controle de duplicidade local)
  • external_id: referenceId sequencial gerado pelo sistema (000001, 000002...)
  • json_request: payload enviado à Cora (para debug)
  • json_response: resposta completa da Cora (para debug)

Autenticação com a Cora (mTLS)

  • mTLS: certificado cliente (CORA_CERT_PEM) + chave privada (CORA_PRIVATE_KEY_PEM) configurados no PHP proxy externo
  • PHP proxy: https://api.bysporthub.com.br/cora-boleto.php (emissão) e cora-token.php (token)
  • Token OAuth2: obtido via getCoraToken() → GET cora-token.php → retorna access_token
  • Base URL Cora: https://matls-clients.api.cora.com.br
  • Secrets usados: CORA_PRIVATE_KEY_PEM, CORA_CERT_PEM, CORA_API_BASE_URL, CORA_TOKEN_URL, CORA_CLIENT_ID

Pendências críticas na integração

  • ⚠️ coraWebhook não valida assinatura — qualquer POST falsificado pode marcar Charge como PAID
  • ⚠️ Student.status=Inadimplente não é restaurado automaticamente após Charge=PAID
  • ⚠️ Evento do webhook não é gravado em AuditLog ou FinancialLog — sem rastreabilidade
  • ⚠️ updateStudentDelinquency ignora Charge — inadimplência baseada apenas em Payment

Sistema Equipe — Documentação Completa

1. Visão Geral

O módulo "Equipe" é o sistema de controle de identidade e acesso (IAM) do By Sport Hub. Ele gerencia quem pode acessar o sistema, quais páginas cada perfil visualiza e quais ações cada role pode executar. É composto por dois submenus: Colaboradores e Controle de Acesso.

🔑 Autenticação: Magic Link (sem senha)

O sistema NÃO armazena senhas. A autenticação é delegada à plataforma Base44 via magic link: o usuário informa o email, recebe um link único por email, clica nele e recebe um token JWT de sessão. Não existe login com usuário/senha.

2. Menu "Equipe" — Estrutura e Navegação

Controle de Acesso → /acesso

admin (exclusivo)

Permite visualizar e editar os perfis (roles) de cada usuário. Contém: cards de configuração de cada role (clicável para abrir PermissionPanel), legenda de perfis, lista de usuários ativos com troca de role e unidade inline, botão para sincronizar alunos (StudentUserSyncPanel) e botão para corrigir roles em lote (BulkRoleUpdatePanel).

Colaboradores → /colaboradores

admin, financeiro, coordenador, professor, estagiario, contador

Cadastro e gestão de colaboradores. Funcionalidades: cadastrar/editar/excluir colaborador, definir jornada semanal (WorkScheduleForm), visualizar contracheque (ContraChequeModal), gerar link público de cadastro (/cadastro-colaborador), enviar convites em lote (inviteAllCollaborators), corrigir acessos (fixCollaboratorAccess). Visibilidade de dados financeiros restrita a admin/Gestor/Contador.

Usuários → /usuarios

admin (exclusivo)

Lista todos os usuários da plataforma organizados em 3 abas: Administradores (roles: admin, financeiro, coordenador, professor, contador, estagiario), Alunos/Responsáveis (roles: aluno, user) e Inativos (role: inativo). Permite busca por nome e email.

Auditoria → /auditoria

admin (exclusivo)

Log completo de todas as ações sensíveis do sistema. Registra: usuário, ação, módulo, registro afetado, valor anterior e novo (JSON), severidade (info/warning/critical) e data/hora.

3. Entidades Envolvidas

User (nativa Base44)

CampoTipoDescrição
idUUIDIdentificador único — gerado automaticamente
emailstring (único)Email de acesso — usado para autenticação via magic link
full_namestringNome completo do usuário
rolestring (enum)Perfil de acesso: admin | financeiro | coordenador | professor | estagiario | contador | aluno | user | inativo
unit_idstring (FK → Unit)Unidade vinculada — usado para coordenador/professor restrito à unidade
created_datedatetimeData de criação — gerada automaticamente

Observação: Entidade nativa Base44. Não é possível criar usuários diretamente — apenas convidar via base44.users.inviteUser(email, role). A senha não existe como campo pois a autenticação é via magic link.

Collaborator

CampoTipoDescrição
full_namestring *Nome completo
user_emailstringEmail do User vinculado — usado para correlacionar Collaborator ↔ User
cpfstringCPF do colaborador
birth_datedateData de nascimento
roleenumGestor | Coordenador Financeiro | Coordenador | Professor | Estagiário | Contador
contract_typeenumProfissional | Estágio
unit_idstring (FK → Unit)Unidade onde atua
salary_basenumberSalário base em R$
transport_allowancenumberValor diário de auxílio transporte
pix_keystringChave PIX para pagamento
education_statusenumGraduado | Cursando graduação | Não informado
course / institution / graduation_yearstringDados de formação
statusenumCadastrado | Ativo | Pendente de Aprovação | Pendente de Complementação Financeira | Inativo | Recusado
onboarding_completebooleanIndica se concluiu o onboarding (jornada + dados financeiros)
work_schedule_filledbooleanIndica se jornada semanal foi preenchida

Observação: Um Collaborator NÃO é um User automaticamente. A vinculação ocorre via user_email. O convite para acesso ao sistema é feito separadamente via inviteUser().

RolePermission

CampoTipoDescrição
roleenum *Role ao qual a permissão se aplica: admin | financeiro | coordenador | professor | contador | estagiario
pageenum *Página: dashboard | matriculas | alunos | turmas | financeiro | produtos | colaboradores | calendario | portal | comunicacoes | folha-pagamento | contracheque | dre | ranking
permissions.viewbooleanPode visualizar a página
permissions.createbooleanPode criar registros
permissions.editbooleanPode editar registros
permissions.deletebooleanPode excluir registros
advanced_rules.full_accessbooleanAcesso total (sem restrições)
advanced_rules.restrict_to_unitbooleanRestrito apenas à sua unidade
advanced_rules.only_own_databooleanVê apenas seus próprios dados
special_permissionsarray<string>Ex: view_other_contracheques, access_payroll, generate_charges, manage_roles, approve_enrollments, edit_student_fees
modified_bystringEmail do admin que alterou — rastreabilidade

Observação: Armazena permissões granulares por role+página. Editável em /acesso → PermissionPanel. Estas configurações são informativas — o controle de rota real acontece via ProtectedRoute em App.jsx.

CollaboratorWorkSchedule

CampoTipoDescrição
collaborator_idstring *FK → Collaborator.id
day_of_weekenum *Segunda | Terça | Quarta | Quinta | Sexta | Sábado | Domingo
start_timestringHorário de início (HH:MM)
end_timestringHorário de término (HH:MM)
unit_idstringFK → Unit.id — unidade do turno
hours_workednumberHoras calculadas automaticamente

Observação: Usada para calcular jornada mensal e auxílio transporte. Cada linha = um turno em um dia da semana. Múltiplos turnos no mesmo dia = múltiplas linhas.

AuditLog

CampoTipoDescrição
user_emailstring *Quem executou a ação
user_namestringNome de quem executou
user_rolestringRole no momento da ação
actionstring *Descrição da ação (ex: 'Aluno criado', 'Role alterado')
moduleenum *Financeiro | Alunos | Turmas | Colaboradores | Acesso | Produtos | Eventos | Folha | Sistema
record_idstringID do registro afetado
record_namestringNome/descrição do registro
beforestring (JSON)Estado anterior do registro (snapshot)
afterstring (JSON)Estado novo do registro (snapshot)
severityenuminfo | warning | critical
detailsstringDetalhes adicionais livres

Observação: Imutável por design — não há operação de delete via UI. Consultado em /auditoria (admin) e exibido no bloco 'Dados ao Vivo' desta documentação.

4. Roles e Permissões

Gestor (admin)

Páginas: Todas as páginas sem restrição

Obs: Único com acesso a /acesso, /usuarios, /auditoria, /folha-pagamento

Coordenador Financeiro (financeiro)

Páginas: /, /financeiro, /financeiro-dashboard, /dre, /colaboradores, /ranking-unidades, /inteligencia-financeira, /livro-caixa

Obs: Acesso financeiro global. Sem restrição por unidade.

Coordenador (coordenador)

Páginas: /alunos, /turmas, /chamada, /produtos, /eventos, /matriculas, /calendario, /comunicacoes, /colaboradores, /ranking-unidades, /portal, /financeiro-dashboard

Obs: Restrito à sua unit_id. Não acessa DRE, financeiro detalhado ou folha.

Professor (professor)

Páginas: /alunos, /turmas, /chamada, /produtos, /eventos, /colaboradores, /ranking-unidades, /portal

Obs: Sem acesso financeiro. Foco em operação diária de aulas.

Estagiário (estagiario)

Páginas: Mesmo que professor

Obs: Mesmo perfil do professor. Contrato diferente (Estágio). Pode ter restrições futuras.

Contador (contador)

Páginas: /, /financeiro, /financeiro-dashboard, /dre, /colaboradores, /ranking-unidades, /inteligencia-financeira

Obs: Somente leitura financeira. Sem acesso operacional.

Aluno / Responsável (aluno / user)

Páginas: /portal (exclusivo)

Obs: Ambos os roles redirecionam para /portal. Sem acesso ao backoffice.

Inativo (inativo)

Páginas: Nenhuma

Obs: Bloqueado antes de qualquer renderização. Vê apenas tela de acesso revogado.

⚙️ Controle Granular via RolePermission

Além do controle de rotas, existe a entidade RolePermission que permite configurar permissões por role+página (view, create, edit, delete) e regras avançadas (restrict_to_unit, only_own_data). Estas configurações são editáveis em /acesso pelo admin e armazenadas no banco — mas a aplicação das permissões no frontend depende de cada componente consultar RolePermission individualmente.

5. Fluxo de Autenticação

  1. 1Usuário acessa qualquer página do app
  2. 2App.jsx carrega AuthProvider → checkAppState() é chamado
  3. 3Base44 SDK tenta recuperar token JWT do localStorage/cookie
  4. 4Se sem token → authError { type: 'auth_required' } → base44.auth.redirectToLogin() → redireciona para página de login Base44
  5. 5Na tela de login Base44: usuário informa email → plataforma envia magic link por email
  6. 6Usuário clica no link → Base44 valida o token one-time → emite JWT de sessão → redireciona de volta ao app com ?token=...
  7. 7App recebe o token → base44.auth.me() → retorna objeto User com { id, email, full_name, role, unit_id }
  8. 8AuthContext.setUser(user) e setIsAuthenticated(true)
  9. 9App.jsx verifica user.role → ProtectedRoute decide qual rota renderizar
  10. 10Timer de inatividade iniciado: 10 minutos sem interação → base44.auth.logout() automático
  11. 11Logout manual: base44.auth.logout(redirectUrl) → limpa token → redireciona para login

Expiração de sessão

Token JWT: gerenciado pela Base44 (validade interna). Inatividade no app: 10 minutos (configurado em App.jsx via INACTIVITY_TIMEOUT = 10 × 60 × 1000ms).

Eventos que resetam o timer

mousemove, keydown, click, scroll, touchstart — qualquer interação do usuário reseta o contador de 10 minutos.

6. Proteção de Rotas

ProtectedRoute (App.jsx)

Componente inline em App.jsx que envolve cada rota. Lógica:

ROLE_PERMISSIONS[role] → lista de paths permitidos

Se pathname ∉ allowedRoutes → redireciona para defaultPath do role

admin → sem restrição (acesso total)

aluno|user → forçado para /portal (App.jsx nível acima)

inativo → bloqueado antes das rotas (tela "Acesso Revogado")

Tabela de roles e rotas padrão (redirect)

RoleRota Padrão (redirect)Bloqueio
admin/ (dashboard)Nenhum
financeiro/ (dashboard)Rotas operacionais (chamada, matrículas)
coordenador/matriculasFinanceiro avançado, acesso, folha
professor/chamadaFinanceiro, acesso, matrículas, dre
estagiario/chamadaIdem professor
contador/ (dashboard)Operacional, alunos, turmas, chamada
aluno / user/portalTodo o backoffice
inativo—Tudo — tela de bloqueio

Fluxo para colaboradores novos (CollaboratorOnboarding)

  1. 1.Novo colaborador se cadastra em /cadastro-colaborador (público)
  2. 2.Collaborator criado com status 'Pendente de Aprovação'
  3. 3.Admin aprova em /colaboradores → status → 'Ativo' com onboarding_complete=false
  4. 4.App.jsx detecta collabStatus='onboarding' → exibe CollaboratorOnboarding
  5. 5.Colaborador preenche dados complementares → onboarding_complete=true
  6. 6.App libera acesso normal às rotas permitidas para seu role

7. Funções e Hooks Relevantes

AuthContext (lib/AuthContext.jsx)

Context React que centraliza: user, isAuthenticated, isLoadingAuth, authError, logout(), navigateToLogin(), checkAppState(). Usado em toda a app via useAuth().

useAuth()

Hook que expõe o AuthContext. Todo componente que precise do usuário atual usa: const { user } = useAuth().

base44.auth.me()

Chamada ao SDK que retorna o User autenticado atual com todos os campos (id, email, full_name, role, unit_id). Usada em backend functions para validar autenticação.

base44.auth.logout(redirectUrl?)

Limpa o token JWT e redireciona. Se redirectUrl informado, vai para essa URL após logout. Usado no timer de inatividade e no botão de logout.

base44.auth.redirectToLogin(nextUrl?)

Redireciona para a tela de login Base44. Após login, retorna para nextUrl. Usado quando authError.type === 'auth_required'.

base44.users.inviteUser(email, role)

Convida um email para o app com o role especificado. Envia email com magic link de primeiro acesso. Usado ao criar Student e ao aprovar Collaborator.

listStudents (function)

Backend function que usa asServiceRole para listar alunos bypassando RLS — necessário pois RLS bloqueia admin de ver alunos sem email ou guardian_email.

manageCollaboratorAccess (function ⚠️)

Automation entity que convida colaborador automaticamente ao criar Collaborator. Atualmente com erros consecutivos.

inviteAllCollaborators (function)

Itera todos os Collaborators ativos sem convite e chama inviteUser para cada um. Chamada manualmente via botão em /colaboradores.

fixCollaboratorAccess (function)

Sincroniza roles dos colaboradores: para cada Collaborator ativo, encontra o User pelo email e atualiza o role para o equivalente Base44.

standardizeStudentRoles (function)

Garante que todos os usuários com email de aluno/responsável tenham role='user'. Chamada após criar novo Student.

Timer de Inatividade (App.jsx)

useRef + setTimeout de 10 minutos. Reseta em qualquer evento DOM (mousemove, keydown, click, scroll, touchstart). Ao expirar: base44.auth.logout().

8. Relação com Outros Módulos

↔ Student

Ao cadastrar Student, o sistema convida student.email e student.guardian_email como role='user'. O User resultante acessa apenas /portal. RLS do Student usa user.email e user.guardian_email para controle de leitura.

↔ Guardian

Guardian.email é usado no convite de acesso. Um Guardian pode ser responsável financeiro de vários Students. O User criado para o guardian acessa o portal de todos os Students vinculados.

↔ Collaborator

Collaborator.user_email vincula o registro ao User da plataforma. O role do Collaborator (ex: 'Professor') é mapeado para o role Base44 (ex: 'professor') pela função fixCollaboratorAccess. São entidades separadas — Collaborator = dados HR, User = acesso ao sistema.

↔ Financeiro

canViewFinancial = ['admin', 'Gestor', 'Contador'].includes(role). Dados salariais de Collaborator (salary_base, transport_allowance) só são visíveis para estes roles. PayrollLog registra quem acessou contracheques.

↔ Auditoria

AuditLog.user_email + user_role registra cada ação sensível. O role no momento da ação fica gravado permanentemente, mesmo que o role mude depois.

↔ Calendário / Comunicações

HolidayNotificationLog registra notificações enviadas a alunos e colaboradores. Comunicações usa student.email e collaborator.email para disparar mensagens. Filtros de acesso baseados em unit_id do User.

9. Diagrama de Entidades e Fluxo

AUTENTICAÇÃO (Magic Link) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Browser → Base44 Login → email → magic link → JWT token JWT token → AuthContext → useAuth() → user.role → rotas ENTIDADES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ User (Base44) ├── role ──────────────────→ ProtectedRoute → página ├── unit_id ───────────────→ filtro de unidade (coordenador/professor) └── email ─────────────────→ Student.email / Student.guardian_email Collaborator ├── user_email ────────────→ User.email (vínculo HR ↔ acesso) ├── role ──────────────────→ mapeado para User.role via fixCollaboratorAccess └── unit_id ───────────────→ User.unit_id Student ├── email ─────────────────→ User.email (convite role='user') ├── guardian_email ────────→ User.email (convite role='user') └── guardian (FK) ─────────→ Guardian.email RolePermission ├── role + page ───────────→ {view, create, edit, delete} ├── advanced_rules ────────→ restrict_to_unit, only_own_data └── special_permissions ───→ generate_charges, approve_enrollments... FLUXO DE ROTA ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Request → App.jsx ↓ [inativo?] → Tela Acesso Revogado ↓ [collabStatus=pending?] → PendingApprovalScreen ↓ [collabStatus=onboarding?] → CollaboratorOnboarding ↓ [role=aluno|user?] → /portal (forçado) ↓ ProtectedRoute → ROLE_PERMISSIONS[role].includes(pathname)? ✓ → renderiza página ✗ → redirect para defaultPath do role

10. Resumo Final

✅ Pontos Fortes

  • ✓Magic link: sem exposição de senha
  • ✓RBAC com 8 roles distintos
  • ✓Timer de inatividade (10 min)
  • ✓Onboarding guiado para colaboradores
  • ✓Fluxo automático de convite para alunos e responsáveis
  • ✓Auditoria imutável de ações
  • ✓RLS no banco para Student (leitura isolada)
  • ✓Proteção em App.jsx antes de qualquer render

⚠️ Limitações Atuais

  • ⚠manageCollaboratorAccess com erros consecutivos
  • ⚠RolePermission não é aplicada automaticamente — depende de implementação por componente
  • ⚠Collaborator e User são entidades separadas sem sync automático de role
  • ⚠Sem 2FA ou confirmação adicional de identidade
  • ⚠Sem histórico de mudanças de role por usuário
  • ⚠Sem expiração configurável de token pela app (depende da plataforma)

🚀 Sugestões Futuras

  • →Corrigir manageCollaboratorAccess (prioridade)
  • →Sync automático Collaborator.role → User.role ao salvar
  • →Hook usePermissions() que consulta RolePermission para cada componente
  • →Log de mudanças de role em AuditLog (campo 'Acesso')
  • →Portal separado para responsável financeiro
  • →Notificação ao admin quando novo colaborador se cadastra
  • →Dashboard de usuários ativos vs inativos em tempo real

Fluxo de Matrícula — Documentação Técnica

Dois fluxos coexistem no sistema

O fluxo antigo (via Enrollment) ainda processa registros existentes em /matriculas. O fluxo novo cria o Student diretamente, sem etapa de aprovação.

Comparativo dos Fluxos

AspectoFluxo AntigoFluxo Novo (atual)
O que cria no envioEntidade EnrollmentStudent diretamente
Requer aprovação?Sim, via /matriculasNão — já entra como Ativo
Cria Guardian?Não no envioSim, no envio
E-mail de boas-vindas?Sim, na aprovaçãoNão
Onboarding emails?Sim (D+3, D+7)Não
Redireciona paraTela de sucesso/matriculas (admin)

Etapas do Formulário /matricula

1Aluno

Nome*, Sexo, Nascimento*, CPF, Telefone*, E-mail*, Foto

2Responsável

CPF* (busca auto), Nome*, Telefone, Parentesco, E-mail

3Endereço

CEP* (ViaCEP auto-complete), Rua*, Número, Bairro, Cidade*, Estado*

4Autorizações

Unidade*, Turma*, Uso de imagem*, Aptidão física*, Termos*

Ao Submeter (Fluxo Novo)

1Busca CPF do responsável em Guardian → cria ou atualiza
2Cria Student (status: Ativo, monthly_fee: 0)
3inviteUser(email_aluno, 'user')
4inviteUser(email_responsavel, 'user') [se diferente]
5standardizeStudentRoles()
6Redireciona para /matriculas
✗E-mail de boas-vindas — NÃO enviado
✗Onboarding emails — NÃO agendados
✗AccessToken — NÃO criado automaticamente

Processo de Aprovação (/matriculas)

Ao APROVAR

Enrollment → status: Aprovado

Cria Student (status: Ativo)

⚠ NÃO cria Guardian separado

inviteUser (aluno + responsável)

standardizeStudentRoles()

E-mail HTML de boas-vindas

triggerOnboardingEmails (D+3, D+7)

Ao REJEITAR

Enrollment → status: Rejeitado

NÃO cria Student

NÃO envia e-mail

NÃO convida usuário

Acesso ao Portal

/ (HomeEntry)
generateAccessToken
E-mail com link
/portal/acesso?token=xxx
validateAccessToken
/portal

O AccessToken não é criado automaticamente no fluxo de matrícula. O aluno precisa solicitar acesso ativamente pela tela inicial após receber o convite via inviteUser.

Gaps Identificados

#1

Fluxo novo não envia e-mail de boas-vindas

Impacto: Aluno criado sem comunicação

#2

Fluxo novo não dispara onboarding emails

Impacto: Sequência de onboarding não inicia

#3

Fluxo antigo não cria Guardian separado

Impacto: Responsável não aparece em /responsaveis

#4

E-mail de boas-vindas está hardcoded

Impacto: Não usa EmailTemplate, não é customizável

#5

inviteUser envia e-mail em inglês

Impacto: Experiência inconsistente com identidade da marca

#6

AccessToken não é criado automaticamente

Impacto: Aluno precisa solicitar acesso manualmente

#7

Fluxo novo redireciona para /matriculas (admin)

Impacto: Usuário público pode acessar área restrita

Webhook Cora — Implementado (coraWebhook)

Ativo

O que foi implementado

  • Função coraWebhook recebe eventos POST da API Cora
  • Evento payload.status === 'PAID' → busca Charge pelo cora_invoice_id → atualiza status para PAID + paid_at
  • Após atualizar: chama tryClaimAndSendEmail() — envia e-mail de confirmação de pagamento ao responsável/aluno
  • Template de e-mail: 'confirmacao_de_pagamento' via sendSystemEmail
  • Campo payment_email_sent evita reenvio duplo do e-mail de confirmação
  • Campo payment_notified marcado antes do envio de e-mail (flag de idempotência)

Fluxo do Webhook

💳 Pagamento no bancoAPI Cora dispara eventocoraWebhook()Charge → PAIDE-mail enviado

Payload esperado: { invoice: { id: "..." }, status: "PAID" } ou { invoice_id: "...", status: "PAID" }

Pontos de atenção

  • updateStudentDelinquency ainda lê apenas Payment — deve ser adaptado para verificar Charge.status = PAID também
  • Sem validação de assinatura criptográfica do webhook Cora (risco de falsificação)
  • Charge.status é atualizado mas Student.status (Inadimplente→Ativo) NÃO é restaurado automaticamente
  • Log do evento não é gravado em FinancialLog ou AuditLog — sem rastreabilidade de webhook

Portal do Aluno / Responsável — Documentação Técnica

Visão Geral

O portal é uma área pública acessível via /portal, sem login Base44. A autenticação é feita por sessão local (localStorage) gerada a partir de um magic link enviado por e-mail. Admins acessam o portal via login Base44 normal e veem uma visão administrativa. Responsáveis podem ser impersonados por administradores.

Aluno (type=student)

Aba Conquistas, Frequência, Mensalidades, Eventos, Materiais, Mensagens. Sem aba de cobranças multi-aluno.

Responsável (type=guardian)

Aba Mensalidades (cobranças de TODOS os filhos agrupadas), Frequência, Eventos. Sem Conquistas, Materiais, Mensagens.

Admin (role=admin)

Vê visão administrativa: AdminPortalView com AdminBadgePanel. Sidebar completo disponível.

Fluxo de Autenticação do Portal

  1. 1Usuário acessa / (HomeEntry) → digita e-mail
  2. 2generateAccessToken() cria AccessToken na entidade (expira em 24h) e retorna o token
  3. 3sendPortalAccessLink() envia e-mail com link /portal/acesso?token=xxx
  4. 4Usuário clica no link → /portal/acesso valida o token via validateAccessToken()
  5. 5validateAccessToken marca o token como used=true (uso único)
  6. 6Sessão gravada em localStorage: { email, name, type, device_id, expires_at (+45 dias) }
  7. 7Usuário redirecionado para /portal
  8. 8A cada carregamento: renewPortalSession() verifica email em Guardian/Student e renova por +45 dias
  9. 9Sessão expira? → redirect para /portal/acesso?reason=expired

Funções Backend do Portal

generateAccessToken

OK

Gera token hex(32) aleatório. Invalida tokens anteriores do mesmo email. Cria AccessToken com expires_at = +24h.

validateAccessToken

OK

Valida token: existe? não foi usado? não expirou? → marca used=true → retorna { email, name, type }.

renewPortalSession

OK

Sliding session: verifica email em Guardian/Student. Se encontrado → retorna nova expires_at (+45 dias). Se não encontrado → invalida sessão.

getPortalStudents

OK

Usa asServiceRole para buscar alunos bypassando RLS. type='guardian' → filtra por guardian_email. type='student' → filtra por email, fallback para guardian_email.

Dados exibidos no Portal por Aba

AbaEntidades consultadasQuem vê
Conquistas (badges)Student.badges + CustomBadgeAluno (não responsável)
MensalidadesCharge.filter({ student: id })Aluno + Responsável
FrequênciaAttendance.filter({ student_id: id })Aluno + Responsável
EventosEvent (status=Aberto) + EventRegistrationAluno + Responsável
MateriaisProduct (status=Disponível)Aluno (não responsável)
MensagensStudentMessage.filter({ student_id: id })Aluno (não responsável)

Funcionalidades do Portal

  • Upload de foto do aluno: UploadFile → Student.photo_url
  • Cancelamento de matrícula: muda Student.status para Inativo, envia e-mail de confirmação
  • Exclusão de conta: Student marcado como Inativo + nota + e-mail de confirmação
  • Seletor de perfil (Netflix-style): múltiplos filhos vinculados ao responsável
  • Mensagem de aniversário automática: enviada via StudentMessage ao acessar o portal no dia do nascimento
  • Compra de materiais: ProductSale via CartDrawerView + notificação ao admin
  • Inscrição em eventos: EventRegistration
  • Real-time: Student.subscribe() → atualiza badges em tempo real sem recarregar

Segurança e Sessão

  • Sessão armazenada exclusivamente em localStorage (sem cookie)
  • device_id gerado via crypto.getRandomValues (hex 32 chars) e vinculado à sessão
  • Expiração padrão: 45 dias com renovação automática via renewPortalSession
  • Token de acesso (AccessToken): uso único, expira em 24h
  • Admin acessando o portal: detectado via base44.auth.isAuthenticated() + role=admin → AdminPortalView
  • Portal montado dentro do <Layout> no App.jsx → admin vê sidebar completo
  • Usuários não autenticados (comuns): fora do Layout → sem sidebar

Módulo Responsáveis (/responsaveis) — Documentação

Visão Geral

Página de gestão de Guardians. Acessível para admin, financeiro, coordenador. Exibe todos os responsáveis cadastrados separados em duas listas: Com acesso ao portal (Guardian.email ∈ User.email) e Sem acesso ao portal. Permite: expandir detalhes, ver alunos vinculados, gerar cobranças, enviar/reenviar acesso e (admin) impersonar o responsável.

Funcionalidades

Enviar/Reenviar Acesso

Chama generateAccessToken() → link de acesso → sendSystemEmail com template 'bem_vindo_responsavel'. Disponível para admin/financeiro/coordenador.

Acessar como (Impersonação)

EXCLUSIVO para admin. Cria portal_session e portal_impersonation no localStorage com expiração de 2h. Registra AuditLog (severity=warning). Redireciona para /portal como se fosse o responsável.

Gerar Cobrança

Abre GerarCobrancaDialog pré-selecionando o aluno vinculado ao responsável. Apenas para alunos Ativos com Guardian FK preenchido.

Vínculo de estudantes

Guardian é encontrado por guardian === guardian.id OU guardian_email === guardian.email (compatibilidade com fluxo antigo).

Fluxo de Impersonação (Admin → Portal como Responsável)

  1. 1Admin clica em 'Acessar como' no card do responsável (/responsaveis)
  2. 2handleImpersonate() cria impersonationSession: { is_impersonation: true, email, name, type: 'guardian', impersonated_by_email, expires_at: +2h }
  3. 3Salva portal_admin_backup no localStorage (backup da sessão admin)
  4. 4Salva portal_session com dados do responsável (expires_at: +2h)
  5. 5Salva portal_impersonation com dados completos da impersonação
  6. 6Registra AuditLog: severity='warning', action='Impersonação iniciada...'
  7. 7Redireciona para /portal
  8. 8StudentPortal.init() detecta portal_impersonation → adminMode = false → carrega como responsável
  9. 9Banner laranja exibe nome/email do responsável e botão 'Sair da visualização'
  10. 10Botão 'Sair': remove portal_session, portal_impersonation, portal_device_id → redireciona para /responsaveis

Dados Sensíveis, CPF e Exportações

CPF — Armazenamento e Uso

  • Guardian.cpf: identificador único do responsável — usado para busca de duplicatas ao submeter nova matrícula
  • Guardian.cpf é obrigatório para emissão de boleto na Cora (enviado no campo customer.document.identity sem máscara)
  • Student.cpf: validado com algoritmo mod 11 (dígito verificador), armazenado em texto simples na entidade
  • Student.guardian_cpf: campo denormalizado (cópia do CPF do responsável) no registro do aluno para consultas sem JOIN
  • CPF não é exibido no portal do aluno/responsável — visível apenas no backoffice para admin, financeiro e coordenador
  • CPF é enviado à Cora sem máscara (apenas dígitos) no payload de emissão de boleto

Exportações — Formatos e Funções

  • Relatório de alunos (StudentReportDialog): exporta PDF via jsPDF — inclui full_name, cpf, email, phone, status, unit_id, class_id, monthly_fee, guardian_name, guardian_cpf — CPF exibido sem máscara no PDF
  • Exportação financeira (Finance/LivroCaixa): CSV ou tabela impressa via window.print() — campos: data, descrição, valor, status, categoria
  • Folha de pagamento (Payroll): PDF via jsPDF+autoTable — inclui colaborador, salário base, auxílio transporte, total. CPF do colaborador incluído no contracheque
  • Documentação técnica (exportDocumentacaoPDF): este PDF — gerado sob demanda em /documentacao — não contém dados de alunos individuais
  • Exportação de importação (BulkImportDialog): aceita CSV/Excel para importar alunos em lote — campos mapeados para entidade Student
  • Todos os PDFs são gerados client-side via jsPDF (sem servidor) e baixados diretamente pelo navegador
  • Nenhuma exportação automática ou agendada — todas são iniciadas manualmente pelo usuário admin/financeiro

Correções — 14/05/2026 · Seção A: Bugs Críticos Corrigidos

Todos os itens abaixo foram verificados por leitura direta do código após as correções.

manageCollaboratorAccess — 15 erros consecutivos

✅ CORRIGIDO

Arquivo: functions/manageCollaboratorAccess

Antes: CRÍTICO — colaboradores novos NÃO eram convidados automaticamente (15 erros consecutivos, trigger retornava 401 sem token de usuário)

Correção: Função aceita chamada via frontend E trigger sem auth. invite_pending=true como fallback quando trigger não tem contexto de auth. Permissões granulares implementadas. Tratamento de troca de e-mail antigo.

coraWebhook — validação HMAC-SHA256

✅ CORRIGIDO

Arquivo: functions/coraWebhook

Antes: ATENÇÃO — sem validação de assinatura, endpoint aberto a falsificações

Correção: Validação HMAC-SHA256 implementada com graceful degrade. Sem CORA_WEBHOOK_SECRET: processa com warning. Com secret: valida e rejeita POST inválidos. PENDENTE: configurar CORA_WEBHOOK_SECRET no painel da Cora e no Base44.

onStudentSave — modo teste removido

✅ CORRIGIDO

Arquivo: functions/onStudentSave

Antes: ATENÇÃO — validações de campos obrigatórios DESATIVADAS via comentário '// TESTE: Validações removidas temporariamente'

Correção: Modo teste removido, validações reativadas. Campos obrigatórios validados. Cadastro incompleto → Student Inativo. Logs de debug removidos.

updateStudentDelinquency — ignorava Charge.PAID

✅ CORRIGIDO

Arquivo: functions/updateStudentDelinquency

Antes: ATENÇÃO — lia apenas Payment, ignorava Charge=PAID. Alunos que pagam via boleto Cora continuavam Inadimplentes.

Correção: Agora verifica Charge.status=PAID além de Payment. Aluno que paga via boleto Cora é restaurado para Ativo automaticamente. FinancialLog registrado em cada mudança de status.

Correções — 14/05/2026 · Seção B: Padrão D — setLoading sem finally

Padrão D: setLoading(false) estava dentro do bloco try em vez de finally. Em caso de erro, o loading nunca terminava — tela travada. Todas as páginas abaixo corrigidas com try/catch/finally.

pages/Classes
pages/Dashboard
pages/UnitRanking
pages/Products
pages/Events
pages/Communications
pages/DiagnosticoFinanceiro (LiveStats)
pages/Payroll
pages/UsersPage
pages/AccessControl (Promise.allSettled)
pages/Guardians (/responsaveis)
pages/BadgeManagement (/insignias)
hooks/useBadges

Correções — 14/05/2026 · Seção C: Fluxo de Matrícula e Aprovação

1. approveEnrollment — nova backend function

  • Criada para substituir a aprovação direta do frontend.
  • Resolve: 403 ao criar Student (RLS), enrollmentId undefined, auth.me() falhando antes de ler parâmetros.
  • Fluxo: Guardian → Student → Charge → SOMENTE ENTÃO Enrollment=Aprovado
  • Idempotência: verifica Student existente por CPF antes de criar.
  • inviteUser movido para o frontend após retorno da função.
  • Arquivo: functions/approveEnrollment

2. EnrollmentApproval — frontend simplificado

  • Removidas chamadas diretas: Student.create(), Guardian.create(), Enrollment.update(Aprovado).
  • Substituído por: functions.approveEnrollment({ enrollmentId })
  • Arquivo: pages/EnrollmentApproval

3. EnrollmentForm (/matricula) — estabilidade e UX

  • finally { setSaving(false) } — botão SEMPRE volta ao normal, mesmo em caso de erro
  • Mensagem de erro amigável na UI (substituiu alert())
  • 4 logs estratégicos: [Matricula] Submit iniciado, antes/depois da chamada, redirecionamento
  • Error Boundary em App.jsx para a rota /matricula (components/ErrorBoundary.jsx)
  • Confirmado: Cora NÃO está no fluxo crítico do submit — submitPublicEnrollment apenas cria Enrollment (status=Pendente)
  • Arquivos: pages/EnrollmentForm, components/ErrorBoundary.jsx, App.jsx

Correções — 14/05/2026 · Seção D: Portal do Aluno (/portal)

1. PortalAccess (/portal/acesso)

  • Corrigido: guard de admin não reconhecia sessão AppUser (magic link)
  • Correção: verifica localStorage.appuser_session antes do JWT Base44
  • Correção: navigate com replace: true para evitar loop no histórico
  • Arquivo: pages/PortalAccess

2. StudentPortal (/portal) — adminMode e loading eterno

  • Corrigido: adminMode nunca virava true para Gestor
  • Causa: condição verificava role === 'admin' (minúsculo) mas Gestor tem role === 'Gestor' (G maiúsculo)
  • Correção: isAdminRole() aceita admin, Gestor, gestor, financeiro, coordenador, contador
  • Corrigido: loading eterno para admin — useEffect retornava cedo sem chamar setLoading(false)
  • Correção: setLoading(false) imediato quando adminMode = true
  • Arquivo: pages/StudentPortal

3. AdminBadgePanel — Modo Colaborador

  • Corrigido: Student.list() bloqueado por RLS para Gestor (retornava [])
  • Correção: substituído por base44.functions.invoke('listStudents') — mesmo padrão de pages/Students
  • Corrigido: Promise.all sem .catch() — erro silencioso travava o painel
  • Correção: try/catch/finally com guard de isLoadingAuth
  • Arquivo: components/students/AdminBadgePanel

4. updateStudentBadges — nova backend function

  • Criada para substituir Student.update() direto do frontend (bloqueado por RLS para Gestor)
  • Usa asServiceRole para bypass de RLS
  • Registra AuditLog a cada atribuição/remoção de badge
  • Arquivo: functions/updateStudentBadges

5. AdminStudentProfile — toggleBadge

  • Corrigido: Student.update() direto sem try/catch — erro silencioso
  • Corrigido: optimistic update executava mesmo se banco rejeitou
  • Corrigido: toast.success disparava sempre (mesmo em falha)
  • Correção: usa updateStudentBadges backend function — estado local só atualizado após confirmação do banco
  • Arquivo: components/students/AdminStudentProfile

Correções — 14/05/2026 · Seção E: /responsaveis e /insignias

1. /responsaveis (pages/Guardians)

  • Corrigido: User.list() dentro do Promise.all sem isolamento → Guardians nunca carregavam (lista sempre vazia)
  • Correção: User.list() isolado em try/catch separado
  • Correção anterior também aplicada: loop infinito (Padrão A — Cenário A)

2. /insignias (pages/BadgeManagement)

  • Corrigido: race condition de auth — loadData executava antes do isLoadingAuth resolver, Student.list() retornava []
  • Correção: useEffect aguarda isLoadingAuth === false
  • Correção: query de Student alinhada com pages/Students

3. BadgeAssignPanel

  • Corrigido: bug de blur/foco — onBlur fechava dropdown antes do onMouseDown registrar no item selecionado
  • Adicionado: feedback visual com contador de alunos disponíveis

Correções — 14/05/2026 · Seção F: Caso Ana Luísa Fróes Gonçalves

Dados do Caso

Enrollment ID: 6a06208b3fccd137ee1686e4

Problema: Enrollment aprovado mas Student não criado (registro órfão)

Guardian reutilizado: FLAVIA FROES

Data de resolução: 14/05/2026

Causa Raiz

O handleApprove original marcava Enrollment como Aprovado ANTES de criar o Student. Se a criação do Student falhasse (ex: RLS 403), o Enrollment ficava como Aprovado sem Student associado — registro órfão.

✅ Resolução

  • Enrollment resetado para Pendente e re-aprovado via approveEnrollment corrigida
  • Student criado com Guardian reutilizado (FLAVIA FROES)
  • Enrollment aprovado corretamente em 14/05/2026
  • Nova função approveEnrollment garante ordem: Guardian → Student → Charge → Enrollment=Aprovado

Correções — 14/05/2026 · Seção G: Pendências Abertas

⚠️ PENDENTE — Ação necessária pelo time

CORA_WEBHOOK_SECRET

Configurar no painel da Cora e nas variáveis de ambiente do Base44. Enquanto não configurado, o webhook processa normalmente mas sem validação de assinatura HMAC — risco de falsificação permanece.

🟡 Melhorias Futuras (Roadmap)

  • Reconciliação automática de Charges via callCora
  • Cancelamento automático de Charges vencidas
  • Notificações WhatsApp/SMS ao gerar boleto
  • Emissão automática NF-e ao confirmar pagamento
  • Emails onboarding 2 e 3 migrados para EmailTemplate (hoje: HTML hardcoded em processOnboardingQueue)
  • Error Boundary para demais rotas além de /matricula
  • usePermissions() por componente (RolePermission não automática)
  • Dashboard de cobrança em tempo real
  • Portal do responsável financeiro separado

By Sport Hub · Auditoria técnica realizada em 14/05/2026 · Atualizado em 15/05/2026 · Gerada em 07/09/2026, 11:39:38 · Confidencial