Técnica & Operacional · 9 documentos
CAE — Centro de Apoio ao Estudante é um ecossistema digital que centraliza a gestão académica, os serviços ao estudante, as operações escolares e uma rede B2B de refeitórios e fornecedores, numa única plataforma moderna.
Domínio público: https://caeao.com · App publicada em
https://cae-smart-campus.base44.app
| Documento | Conteúdo | | --- | --- | | 01 — Visão Geral e Arquitetura | Missão, stack técnico, portais, papéis e fluxos de alto nível | | 02 — Modelo de Dados | Catálogo de entidades, agrupadas por domínio, com schema e regras RLS | | 03 — Backend | Funções de backend, workflows agendados/acionados e módulos partilhados | | 04 — Frontend | Rotas e páginas, sistema de design (tokens, tipografia, utilitários) | | 05 — Segurança e Fluxos | Autenticação, RLS, fluxo de pagamentos em duas fases, notificações automáticas | | 06 — Manual Operacional | Operações por domínio: onboarding, subscrição/carteira/cartão, académico, feed, salas, eventos, refeitório, fornecedores, marketplace, Twisco, comunicações | | 07 — Regras e Configuração | Constantes de negócio: preços, PTT, CAE Score, categorias, estados, notificações | | 08 — Gestão e Responsabilidades | Matriz RACI, operações automáticas, publicação, erros conhecidos, dívida técnica, manutenção |
@hello-pangea/dnd.@import no src/index.css.base44/functions/<nome>/entry.ts), workflows (base44/workflows/*.jsonc), integrações Core (LLM, e-mail, uploads, voz, vídeo, imagem).@/api/base44Client (cliente Base44 pré-inicializado) — entidades em base44.entities.<Entidade>, integrações em base44.integrations.Core.*, auth em base44.auth.*.Kz e PTT como moedas internas), interface em português de Angola, fuso Africa/Luanda.A plataforma está dividida em portais com separação total de dados e navegação:
| Portal | Rota base | Utilizadores |
| --- | --- | --- |
| Nacional (CAE) | /nacional | Admin e Gestor |
| Escola | /escola | Contas de escola |
| Estudante | /estudante | Estudantes |
| Professor | /professor | Professores |
| Encarregado | /encarregado | Encarregados de educação |
| Refeitório | /refeitorio | Operadores de refeitório |
| Fornecedor | /fornecedor | Fornecedores B2B |
| Parceiro | /parceiro | Parceiros de serviços |
| Financeiro | /financeiro | Contabilidade & Finanças (auth própria) |
admin — gestão total da plataforma (acesso a todos os painéis nacionais).gestor — gestor nacional com secções configuráveis (national_permissions no User); paridade de permissões com o admin nas operações de gestão.user — estudantes, professores, encarregados e contas de entidades (escolas, parceiros, fornecedores, refeitórios). O campo user_type distingue o sub-perfil (escola, parceiro, nacional, etc.) e direciona o login para o portal correto.portal explícito; o sino só mostra o do portal ativo.PTT como carteira interna paralela.O CAE centraliza, para o ecossistema educativo angolano:
┌─────────────────────────────────────────────────────────────┐
│ Frontend (React + Vite) — src/pages, src/components │
│ 9 portais isolados · auth pela plataforma · SDK @/api/base44Client │
└───────────────┬─────────────────────────────────────────────┘
│ base44.entities.* · base44.functions.invoke · base44.integrations.Core.*
┌───────────────▼─────────────────────────────────────────────┐
│ Base44 Backend │
│ ├─ Entidades (JSON Schema + RLS) │
│ ├─ Funções (base44/functions/*/entry.ts) — HTTP handlers │
│ ├─ Workflows (base44/workflows/*.jsonc) — agendados/acionados│
│ ├─ Integrações Core (LLM, SendEmail, Uploads, Voz, Vídeo) │
│ └─ Módulos partilhados (base44/shared/*.ts) │
└─────────────────────────────────────────────────────────────┘
*Dashboard.jsx (layout + sidebar) com páginas-filhas em src/pages/<portal>/. Componentes reutilizáveis em src/components/ e src/components/ui/ (shadcn).rls que regista quem cria/lê/atualiza/elimina.base44/shared/*.ts reutilizam lógica entre funções (pagamentos, notificações, finanças, destinatários de e-mail, auto-notificações).AccountSetupToken (token + código de 6 dígitos, 24h)./primeiro-acesso, insere o código → verifyAccessCode.setupAccountPassword → conta User criada/ativada.completeAccountSetup liga a entidade (por e-mail) ao User e define user_type → resolveLoginIdentifier encaminha ao portal certo.SubscriptionPayment/PTTTopupRequest com status=pendente, finance_status=aguardando.notifyPaymentPending avisa Admin/Gestor (in-app + e-mail).finance_status=aprovado|rejeitado (financeAuth sessão própria).finance_status=aprovado é que Admin/Gestor pode aprovar/rejeitar final (status). Na aprovação: define subscription_start/end, credita PTT (se carregamento) — ver 05 — Segurança e Fluxos.Announcement (scope=nacional, targets=[...]).distributeAnnouncementNotifications → cria Notification por utilizador dos painéis-alvo + envia e-mail (em lotes) aos destinatários autorizados.Notification distribuídas.runAutoNotifications envia as mensagens do horário atual (bom dia 08:00, palavras sábias 12:00, boa noite 20:00) + cleanupAutoNotifications remove as que passaram das 24h. Ver 05.Grade, Attendance, Assignment, PTTTransaction, Announcement (create) e Student (update de card_status) chamam guardianNotify, que cria notificação para os encarregados ligados ao estudante.@/ (nunca caminhos relativos para src/).@/components/ui/.cn vem de @/lib/utils; createPageUrl de @/utils.safelist só para valores em runtime..items das páginas (nunca tratar como array).As entidades são JSON Schemas em base44/entities/<Nome>.jsonc. Todos os registos têm automaticamente id, created_date, updated_date, created_by_id (não se declaram). As regras de acesso (RLS) vivem na chave rls de cada entidade (ver 05 — Segurança).
| Entidade | Descrição |
| --- | --- |
| User (built-in) | Conta de acesso. Campos editáveis: role (admin/gestor/user), user_type (escola/parceiro/nacional…), national_permissions, phone, full_name. Só a plataforma cria utilizadores (convites). |
| FinanceAccount | Acesso ao painel Financeiro por username + senha (sem e-mail). password_hash/password_salt (PBKDF2-SHA256), session_token/session_expires_at. RLS: admin/gestor. |
| AccountSetupToken | Token + código de 6 dígitos para adesão de entidades (24h). RLS: admin. |
| GestorActivity | Registo de auditoria das ações de cada gestor. Leitura: próprio ou admin. |
| Entidade | Descrição |
| --- | --- |
| School | Escola registada; owner_user_id liga à conta de acesso. |
| ClassRoom | Turma de uma escola. |
| Student | Estudante. Campos-chave: student_id_code, card_number, qr_token, card_status, ptt_balance, subscription_status (trial/assinatura), guardian_user_ids[], school_id. |
| Teacher | Professor; created_by_id liga à conta. |
| Grade / StudentScore | Notas e pontuação CAE. |
| Attendance | Registos de presença. |
| Assignment / AssignmentSubmission | Trabalhos e entregas. |
| Occurrence | Ocorrências disciplinares. |
| Complaint | Reclamações. |
| SchoolConfig | Configuração académica por escola (classe, período, ano letivo, disciplina, curso). |
| SchoolEvent / ScheduleItem | Eventos escolares e itens de horário. |
| Entidade | Descrição |
| --- | --- |
| Announcement | Comunicado. scope (escola/nacional), target (escola) e targets[] (nacional: painéis destinatários), type (aviso/comunicado/evento/urgente). RLS: leitura aberta, criação aberta, update/delete só admin/gestor. |
| AnnouncementRead | Marca de leitura (user_id == próprio). |
| Notification | Notificação do sino. user_id, type, portal (escola/refeitorio/fornecedor), source (automatico), auto_category, related_entity_id, expires_at. RLS: próprio ou admin/gestor. |
| Message | Mensagens diretas (sender_id/receiver_id). |
| AcademicPost / AcademicComment / AcademicReaction | Feed académico (resumos, exercícios, etc.) + reações educativas (Excelente, Muito Bom, Inteligente, Muito Útil, Boa Ideia, Criativo, Inspirador). visibility controla audiência (turma/classe/nível/escola). |
| Entidade | Descrição |
| --- | --- |
| AutoNotificationSettings | Registo único (key="default"): timezone, paused, ai_enabled, slots (por categoria: enabled/hour/minute/weekdays/inapp/email/start_date/end_date). RLS: admin/gestor. |
| AutoNotificationMessage | Biblioteca de mensagens aprovadas (category, theme, title, content, author, status, source biblioteca/ia, times_used). RLS: admin/gestor. |
| AutoNotificationPreference | Preferências por utilizador (canais, horários pessoais, período de silêncio). RLS: próprio ou admin/gestor. |
| AutoNotificationLog | Log de cada envio/limpeza (dedupe_key impede duplicações, status entregue/parcial/falhou). RLS: admin/gestor. |
| Entidade | Descrição |
| --- | --- |
| Event | Evento nacional/escolar (data, local, pagamento gratuito/kwanza/ptt/combinado). |
| EventRegistration | Inscrição/bilhete: qr_token, validation_code, ticket_code, payment_type, checked_in. RLS: create admin/gestor (via função registerForEvent), leitura aberta. |
| EventReview | Avaliação de evento. |
| ScanLog | Registo de leituras de QR (cartão/bilhete/pedido). |
| Entidade | Descrição |
| --- | --- |
| Refectory | Refeitório; user_id liga à conta. |
| SchoolRefectoryLink | Ligação escola ↔ refeitório. |
| Meal | Refeição/produto servido. |
| Order | Pedido de refeitório (pago por PTT/Kz). |
| MealReview / RefectoryReview | Avaliações (item_type distingue produto vs refeição). |
| WalletConfig | Configuração da carteira/conversões. |
| Entidade | Descrição |
| --- | --- |
| CafeteriaSupplier | Fornecedor B2B; user_id liga à conta. |
| SupplierProduct / Product | Catálogo de produtos. |
| SupplierOrder / SupplyOrder | Encomendas (refeitório→fornecedor / fornecedor→refeitório). |
| SupplyCampaign | Campanha de abastecimento. |
| StockItem / StockMovement | Stock e movimentos. |
| CafeteriaExpense | Despesas de refeitório. |
| ProductReview | Avaliação de produto. |
| Entidade | Descrição |
| --- | --- |
| Partner | Parceiro de serviços; owner_user_id. |
| Professional | Profissional ligado a um parceiro. |
| Service / Booking | Serviços e reservas. |
| MarketplaceItem / MarketOrder / CartItem / Favorite | Itens de marketplace, encomendas, carrinho, favoritos. |
| MarketplaceReview | Avaliação de marketplace. |
| Entidade | Descrição |
| --- | --- |
| SubscriptionPayment | Pagamento de assinatura/cartão. status (pendente/aprovado/rejeitado) + finance_status (aguardando/aprovado/rejeitado) — duas fases. RLS de update obriga finance_status já decidido para admin/gestor aprovarem. |
| PTTTopupRequest | Carregamento PTT (mesmo padrão de duas fases). credited evita duplo crédito. |
| PTTTransaction | Movimentos da carteira PTT. |
| PaymentConfig | Configuração de pagamentos (IBAN, valores dos planos). |
| CardHistory | Histórico do cartão CAE. |
| Entidade | Descrição | | --- | --- | | StudyRoom | Sala (delegado, disciplina, código de convite, link partilhável). | | StudyRoomMember / StudyRoomMaterial / StudyRoomMessage / StudyRoomTask / StudyRoomEvent | Membros, materiais, mensagens, tarefas, eventos da sala. | | StudyConversation / StudyMessage | Conversas/mensagens de estudo privadas. | | StudySession / StudyTask / StudyEvent / ScheduleItem | Sessões, tarefas e eventos de estudo pessoal. |
| Entidade | Descrição | | --- | --- | | TwiscoConfig / TwiscoCandidate / TwiscoVote | Configuração, candidatos e votos do concurso Twisco. |
As schemas completas das entidades mais centrais estão no repositório em base44/entities/<Nome>.jsonc. Os exemplos abaixo resumem os campos principais.
full_name*, username, date_of_birth, bi_number, phone, phone_country_code, email, photo_url,
school_id, school_name, class_name, grade, shift, academic_year,
guardian_name, guardian_phone, guardian_relation, guardian_user_ids[],
province, municipality,
status (pendente/activo/candidato/suspenso/graduado/desistente),
card_status (pendente/aprovado/impresso/pronto/entregue/reemitido/cancelado),
card_number, student_id_code, qr_token, card_issued_date, last_validated_date,
ptt_balance, enrollment_status,
trial_start, trial_end, trial_12h_notification_sent,
subscription_status (trial_active/trial_expired/payment_pending/payment_rejected/subscription_active/subscription_expired),
selected_plan, subscription_start, subscription_end, physical_card_requested
RLS: delete só admin/gestor (restantes abertos — verificado por checkStudentAccess).
user_id*, type* (enum 16 tipos), title*, message, is_read, link_url,
related_entity_id, portal (escola/refeitorio/fornecedor),
source, auto_category (bom_dia/palavras_sabias/boa_noite), expires_at
RLS: create aberto; read/update/delete — próprio ou admin/gestor.
student_id*, student_name, student_user_id, plan/amount_ptt, amount_kz, total_amount,
comprovativo_url, comprovativo_name,
status* (pendente/aprovado/rejeitado), # decisão final Admin/Gestor
finance_status (aguardando/aprovado/rejeitado), # 1.ª fase — Contabilidade
finance_validated_by_name, finance_validated_at, finance_observation,
validated_by_id, validated_by_name, validated_at, admin_observation, rejection_reason,
subscription_start/end (assinatura), credited (PTT)
RLS de update (admin/gestor): exige finance_status ∈ {aprovado,rejeitado} — garante a ordem das duas fases.
UploadPrivateFile, guarda-se o file_uri.school_id, student_user_id, created_by_id); created_by_id é a âncora fiável de propriedade.phone normalizado em formato xxx xxx xxx; validação de unicidade via checkPhoneExists.Ficheiros em base44/functions/<nome>/entry.ts. Cada um é um handler HTTP export default async (req). Invocam-se pelo SDK (base44.functions.invoke('<nome>', payload)) ou por HTTP em https://cae-smart-campus.base44.app/functions/<nome>. Usam createClientFromRequest(req) para obter o cliente (app user) e base44.asServiceRole para operações privilegiadas que contornam a RLS.
| Função | Auth | Descrição |
| --- | --- | --- |
| checkAdesaoEmail | pública | Verifica se um e-mail já tem conta User ({ exists }). Usado nos formulários de adesão. |
| checkPhoneExists | pública | Verifica unicidade de telemóvel em todas as contas (normaliza dígitos). |
| resolveLoginIdentifier | app user | Resolve username/telemóvel/e-mail → e-mail canónico para login (suporta login por nome de utilizador ou telefone). |
| verifyAccessCode | app user | Valida o código de 6 dígitos de um AccountSetupToken (adesão de entidade). |
| setupAccountPassword | app user | Define a senha da conta a partir do token de adesão. |
| completeAccountSetup | app user | No primeiro login: liga a entidade (School/Refectory/CafeteriaSupplier/Partner) ao User por e-mail e define user_type (escola/parceiro/nacional). Promove gestor se for token de gestor. |
| provisionEntityAccount | admin/gestor | Cria a entidade + gera AccountSetupToken + envia convite por e-mail. |
| deleteLinkedUser | admin/gestor | Revoga a conta User ligada a uma entidade (procura por e-mail se não houver user_id). Usa service role. |
| deleteStudent | admin/gestor | Eliminação em cascata de um estudante: remove Student + todos os registos académicos, financeiros, de cartão, refeitório, sala de estudo, conversas/mensagens, notificações e a conta User (por e-mail). Listas BY_STUDENT e BY_USER mapeiam cada entidade ao campo de ligação. |
| Função | Auth | Descrição |
| --- | --- | --- |
| manageGestores | admin/gestor | CRUD de gestores nacionais: list (gestores + candidatos), promote, demote, setPermissions. Usa service role para ler/atualizar User. |
| manageFinanceAccounts | admin/gestor | CRUD de acessos ao painel Financeiro: list/create/update/remove. Gera hash PBKDF2 via createCredentials; reset de senha limpa a sessão. |
| financeAuth | (pública, login próprio) | Autenticação do painel Financeiro por username+senha: verifica hash, emite session_token com expiração. |
| financeData | sessão finance | Dados de relatórios/validação para o painel Financeiro (comprovativos, entradas, conversões). |
| resetPlatformData | admin | Repõe dados de teste/configuração da plataforma. |
| listGuardians | escola/admin | Lista encarregados ligados aos estudantes de uma escola. |
| Função | Auth | Descrição |
| --- | --- | --- |
| notifyPaymentPending | dono ou admin/gestor | Avisa Admin/Gestor (in-app + e-mail) de um novo SubscriptionPayment (source=assinatura) ou PTTTopupRequest (source=carregamento) aguardando Contabilidade. Usa notifyPaymentSubmitted do paymentFlow.ts. |
| processSubscriptions | agendada | Processa testes gratuitos (expira 24h, notifica 12h antes) e expira assinaturas. PLAN_DURATION = {trimestral:3, semestral:6, anual:12}. |
| Função | Auth | Descrição |
| --- | --- | --- |
| registerForEvent | app user | Inscrição em evento: valida vaga, gere bilhete (qr_token, validation_code, ticket_code); se pago em Kz/PTT valida e debita ptt_balance do estudante; cria EventRegistration. |
| distributeEventNotifications | workflow | Notifica participantes/painéis sobre inscrição, publicação ou cancelamento de evento. |
| Função | Auth | Descrição |
| --- | --- | --- |
| distributeAnnouncementNotifications | workflow | Distribui um Announcement nacional: mapeia targets[] → utilizadores de cada painel (panelUserIds), cria Notification por destinatário (sem duplicar), e envia e-mail em lotes (EMAIL_BATCH=6) aos autorizados (canReceiveCaeEmail). |
| guardianNotify | workflow | Cria notificação para os encarregados (guardian_user_ids) de um estudante sobre nota/presença/trabalho/comunicado/PTT/cartão. |
| runAutoNotifications | agendada | Envia as mensagens automáticas do horário atual (bom dia/palavras sábias/boa noite): lê settings, preferências, escolhe mensagem aprovada da biblioteca, personaliza {{nome}}, entrega in-app + e-mail, regista em AutoNotificationLog com dedupe_key. |
| cleanupAutoNotifications | admin/gestor | Remove as notificações automáticas que passaram das 24h de validade (cleanupExpiredNotifications). |
| manageAutoNotifications | admin/gestor | Ações administrativas: testar envio, executar agora, gerar mensagens com IA (generateMessagesWithAI). |
| Função | Auth | Descrição |
| --- | --- | --- |
| checkStudentAccess | app user | Verifica/actualiza o estado de acesso do estudante (auto-expira teste/assinatura) e devolve hasAccess, datas e plano. |
| schoolAssistant | app user | Assistente de escola (LLM) para apoio a operações escolares. |
Ficheiros em base44/workflows/*.jsonc (CNCF Serverless Workflow DSL). Cada workflow tem trigger (entity/scheduled) + definition.do[] (passos invoke_backend_function).
| Workflow | Acionador | Chama |
| --- | --- | --- |
| Distribute Announcement Notifications | Announcement create | distributeAnnouncementNotifications |
| Notificar Encarregados — Comunicado | Announcement create | guardianNotify |
| Notificar Encarregados — Nova Nota | Grade create | guardianNotify |
| Notificar Encarregados — Presença | Attendance create | guardianNotify |
| Notificar Encarregados — Novo Trabalho | Assignment create | guardianNotify |
| Notificar Encarregados — PTT | PTTTransaction create | guardianNotify |
| Notificar Encarregados — Cartão CAE | Student update (changed_fields inclui card_status) | guardianNotify |
| Notificar Inscrição em Evento | EventRegistration create | distributeEventNotifications |
| Notificar Publicação/Cancelamento de Evento | Event update (changed_fields inclui status) | distributeEventNotifications |
| Workflow | Cadência | Faz |
| --- | --- | --- |
| Notificações Automáticas | cron */5 * * * * (Luanda) | runAutoNotifications → cleanupAutoNotifications |
| Process Student Subscriptions | intervalo 15 min | processSubscriptions (expira testes/assinaturas) |
base44/shared/*.ts)| Módulo | Descrição |
| --- | --- |
| autoNotifications.ts | Núcleo das notificações automáticas: CATEGORIES, DEFAULT_SLOTS (08:00/12:00/20:00), luandaParts, slotDue (janela de 6 min), buildDelivery, pickMessage, loadSettings/loadUsers/loadPreferences, generateMessagesWithAI, cleanupExpiredNotifications. TTL 24h, máx. 3 tentativas, lotes de e-mail de 6. |
| paymentFlow.ts | Estado e etiquetas de pagamento + notifyPaymentSubmitted/notifyFinanceDecision (notifica Admin/Gestor in-app + e-mail respeitando o allowlist). |
| notificationRecipients.ts | CAE_EMAIL_RECIPIENTS (allowlist de e-mails admin/gestor autorizados a receber e-mails CAE) + canReceiveCaeEmail. |
| finance.ts | normalizeUsername, createCredentials (PBKDF2-SHA256), asList — usados pelo auth/CRUD do painel financeiro. |
schoolAssistant, geração de mensagens automáticas (gemini_3_flash quando necessário), assistentes do feed.src/
├─ App.jsx # Router (todas as rotas + auth providers + toasters)
├─ main.jsx # Entry
├─ index.css # Tokens de design + utilitários (gradientes, neon)
├─ api/base44Client.js # SDK Base44 pré-inicializado
├─ lib/ # lógica de apoio (utils, auth, rotas, config)
├─ hooks/ # hooks reutilizáveis (useMySchool, useCurrentStudent, useCart...)
├─ components/
│ ├─ ui/ # shadcn/ui (button, card, dialog, alert-dialog, select...)
│ ├─ shared/ # PortalSidebar, TopBar, NotificationDropdown, ThemeToggle...
│ ├─ landing/ # secções da landing page
│ ├─ announcements/ # feed, badges, diálogo de eliminar comunicado
│ ├─ finance/ # painel financeiro (login, provas, relatórios)
│ ├─ cafeteria/ # refeitório (refeições, stock, scanner QR)
│ ├─ national/ # gestão nacional (formulários de entidades, mapas)
│ ├─ feed/ # feed académico (post, reações, comentários)
│ ├─ studyRoom/ # salas de estudo
│ ├─ marketplace2/ # marketplace de parceiros
│ └─ ... # (profile, guardian, teacher, schedule, twisco, palavrasMinhas, events)
└─ pages/
├─ Landing.jsx /auth/ /school/ /student/ /teacher/ /guardian/
├─ national/ /cafeteria/ /supplier/ /partner/ /marketplace/ /events/
└─ *Dashboard.jsx # layout de cada portal (sidebar + <Outlet/>)
src/App.jsx)Wrapper fixo: AuthProvider → QueryClientProvider → Router → ErrorBoundary → AuthenticatedApp + Toaster + FirstLoginPasswordNotice. Rotas autenticadas aninhadas em <ProtectedRoute>.
/ (Landing) · /relatorio-cae · /login · /forgot-password · /reset-password · /definir-senha · /primeiro-acesso · /auth-redirect · /bem-vindo · /cadastro/estudante · /cadastro/professor · /cadastro/encarregado · /financeiro
/portal (seleção de portal) · /perfil · /validar-cartao/:code · /validar · /scanner · /sala/:token (entrar em sala de estudo por link)
/nacional/*)index (Home) · escolas · refeitorio · estudantes · professores · encarregados · aprovacoes · relatorios · twisco · twisco/perfil · eventos (+criar/editar/estatisticas/detalhe) · fornecedor · parceiros · cartoes · cartoes/:id · carteiras · gestores · assinaturas · pagamentos · contabilidade · comunicados · notificacoes-automaticas
/escola/*)index · estudantes · encarregados · professores · turmas (+:id) · notas · frequencia · desempenho-docente · eventos (+detalhe/meu-calendario) · comunicados · reclamacoes · refeitorios · configuracoes · cartoes
/estudante/*)index (feed académico) · salas (+:id) · palavras-minhas (+:id) · cartao · notas · frequencia · trabalhos · horario · mensagens · marketplace (+servico/:id) · reservas · favoritos · refeitorio (+:id) · carteira · ptt · planos · historico · avaliar-professores · cae-score · eventos (+detalhe/meu-calendario/twisco) · reclamacoes · comunicados
/professor/*)index · gerir-turma · avaliacoes · twisco · eventos · perfil · turmas (+:id) · notas · frequencia · comunicar · historico · marketplace · refeitorio · comunicados
/encarregado/*)index · filhos · educando/:id · notas · frequencia · trabalhos · mensagens · eventos · comunicados · carteira · cartoes
/parceiro/*)index · produtos · refeitorio · servicos · profissionais · reservas · pedidos · avaliacoes · comentarios · relatorios · financeiro · configuracoes · comunicados
/refeitorio/*)index · pedidos · refeicoes · escolas · stock · validar · fornecedor (+:id) · meu-refeitorio · fornecedor-pedidos · relatorios · pagamentos · comunicados
/fornecedor/*)index · refeicoes (+:refeitorioId) · produtos · pedidos · classificacao · perfil · comunicados
* → PageNotFound
*Dashboard.jsx (layout: PortalSidebar + TopBar + <Outlet/>) + páginas-filhas focadas.useQuery/useMutation (TanStack Query); filtros/contagens/agregações no servidor (base44.entities.X.filter/count/aggregate). Páginas leem .items.NotificationDropdown + NotificationsModal filtram por portal ativo e por expires_at (24h).base44.entities.X.subscribe(event => ...) para listas que precisam de atualização ao vivo.AutoNotifications → StatsGrid, ScheduleTab, MessagesTab, HistoryTab).src/index.css)Definidos em :root (claro) e .dark (escuro, tom navy/slate sem neon). Mapeados em tailwind.config.js para classes (bg-primary, text-muted-foreground, font-heading...).
background, foreground, card, popover, primary (lilás 263 70% 58%), secondary (navy), muted, accent (laranja 24 92% 55%), destructive, border, input, ring.energy, lilac, orange, navy, sky, pink, chart-1..5, sidebar.*.--radius: 0.875rem.--font-heading/body/display)..font-landing, que sobrepõe os tokens de fonte localmente) — tom corporativo neutro.@import no topo do index.css (antes de @tailwind base).@layer utilities).bg-grad-primary (lilás→laranja), .bg-grad-cool, .bg-grad-warm, .bg-grad-pink, .bg-grad-blue, .bg-grad-lilac..text-grad-primary (texto com gradiente), .icon-grad-primary..neon-surface, .neon-surface-alt, .neon-glow, .neon-glow-strong, .neon-panel, .neon-panel-soft, .neon-chip, .neon-text, .neon-dot, .neon-hover, .neon-bottom, .neon-line.src/components/ui/)shadcn/ui: button (variantes default/destructive/outline/secondary/ghost/link; default usa .bg-grad-primary), card, dialog, alert-dialog, select, input, textarea, label, badge (variantes incl. lilac/orange/navy/sky), switch, checkbox, tabs, table, dropdown-menu, sheet, tooltip, calendar, scroll-area, etc.
shadow-soft/card/pop).lucide-react (apenas ícones existentes/importados).A plataforma gere a auth (tokens, sessões, OTP, reset, OAuth Google). A app adiciona:
/login): e-mail+senha, OAuth Google, OTP após registo, reset/forgot. Após login, completeAccountSetup liga a entidade e define user_type; resolveLoginIdentifier resolve username/telemóvel/e-mail./primeiro-acesso): código de 6 dígitos (verifyAccessCode) → definir senha (setupAccountPassword)./financeiro): auth própria por username + senha (sem e-mail), validada em financeAuth (hash PBKDF2-SHA256 via createCredentials); emite session_token com session_expires_at. Sessão verificada backend-side em cada chamada.Nota: a verificação de e-mail obrigatória ao nível da plataforma persiste comoKnown issue.
| Papel | Acesso |
| --- | --- |
| admin | Tudo. Vê e gere todos os painéis nacionais, utilizadores e entidades. |
| gestor | Gestor nacional. Secções visíveis definidas por national_permissions (src/lib/nationalPermissions.js); paridade operacional com admin nas ações de gestão (criar/editar/eliminar entidades, aprovar pagamentos, gerir comunicados/auto-notificações). |
| user | Estudantes, professores, encarregados e contas de entidades. user_type direciona ao portal correto. |
As permissões por secção do painel nacional vivem em src/lib/nationalPermissions.js (metadados de secções + filtros por papel).
Regras em base44/entities/<Nome>.jsonc → chave rls (ver guia RLS). Padrões usados no CAE:
created_by_id == user.id ou data.user_id) ou role admin/gestor. Ex.: Notification, AutoNotificationPreference, RefectoryReview.AutoNotificationSettings, AutoNotificationMessage, AutoNotificationLog, FinanceAccount, AccountSetupToken.Announcement (read: {}, create: {}, update/delete: admin|gestor), SchoolConfig.MealReview, RefectoryReview...).SubscriptionPayment e PTTTopupRequest só permitem update por admin/gestor quando finance_status ∈ {aprovado,rejeitado} — garante a ordem das duas fases.Student (leitura/criação/update abertos para fluxos escolares; delete só admin/gestor). ScanLog (create próprio, read aberto, update/delete admin/gestor).null/{} mantêm-se abertas quando o dado é genuinamente partilhado (ex.: leitura de comunicados, catálogo público).Entidades novas devem trazer sempre rls — sem regra, o acesso é aberto a qualquer utilizador autenticado (e, em apps públicas, a anónimos). O dono dos dados define o padrão: dados pessoais → owner-or-admin; submissões de visitantes → create aberto + read próprio/admin; conteúdo publicado → read aberto + escrita admin/gestor.
Garante que Contabilidade/Finanças valida o comprovativo antes de Admin/Gestor aprovar. Lógica partilhada em base44/shared/paymentFlow.ts.
[Estudante/Encarregado submete comprovativo]
│
SubscriptionPayment / PTTTopupRequest criado
status = pendente, finance_status = aguardando
│
notifyPaymentPending ──► Admin/Gestor (in-app + e-mail)
│
┌─────────────────────▼─────────────────────┐
│ Painel Financeiro (financeAuth) │
│ Contabilidade valida o comprovativo: │
│ finance_status = aprovado | rejeitado │
│ (+ finance_observation se rejeitado) │
└─────────────────────┬─────────────────────┘
│ (RLS: update só se finance_status já decidido)
┌─────────────────────▼─────────────────────┐
│ Admin/Gestor (Nacional › Aprovações) │
│ status = aprovado | rejeitado │
│ • aprovado: subscription_start/end │
│ (carregamento: creditar PTT) │
│ • rejeitado: rejection_reason │
└──────────────────────────────────────────┘
CAE_EMAIL_RECIPIENTS (notificationRecipients.ts) — só contas admin/gestor listadas recebem e-mails CAE (as restantes continuam a receber notificações in-app).credited em PTTTopupRequest.GestorActivity regista ações dos gestores; AutoNotificationLog regista envios.Núcleo em base44/shared/autoNotifications.ts. Horários predefinidos: 08:00 / 12:00 / 20:00 (Luanda, janela de 6 min).
runAutoNotifications.AutoNotificationSettings (slots por categoria), AutoNotificationPreference por utilizador, e escolhe uma AutoNotificationMessage aprovada (rotação por last_used_at, evita repetições recentes).{{nome}}/{{name}}, respeita canal (ambos/plataforma/e-mail), período de silêncio e horários pessoais.Notification com source=automatico, auto_category, expires_at = +24h) + e-mail (em lotes de 6) aos autorizados (canReceiveCaeEmail).AutoNotificationLog com dedupe_key (categoria+dia+utilizador) — impede duplicações.cleanupAutoNotifications remove as notificações automáticas que passaram das 24h.Administração no painel Nacional › Notificações Automáticas (AutoNotifications.jsx): stats, agendamento, biblioteca de mensagens, histórico, envio de teste e geração por IA (opcional, ai_enabled).
registerForEvent): valida vagas, gera bilhete com qr_token/validation_code/ticket_code; para eventos pagos em Kz/PTT valida e debita ptt_balance do estudante; check-in via /scanner//validar (regista em ScanLog).pendente → aprovado → impresso → pronto → entregue (ou reemitido/cancelado); mudança de card_status notifica encarregados. Validação por /validar-cartao/:code e leitura QR.AcademicPost com visibility (minha_turma/minha_classe/meu_nivel/minha_escola) + reações educativas + comentários; moderação (status: ativo/denunciado/oculto)./sala/:token).Announcement + remove as Notification distribuídas (AnnouncementDeleteDialog).gestor com admin.full_name de 16 encarregados existentes.UnregisteredSchoolsList nos fluxos do dashboard nacional.Este manual descreve como se opera o CAE dia a dia, por domínio, e quem faz o quê. Para regras/constantes (preços, taxas, níveis, categorias) ver 07 — Regras e Configuração; para papéis e segurança ver 05 — Segurança.
Todas as adesões seguem o padrão convite → código → senha → primeiro login.
| Entidade | Quem convida | Fluxo |
| --- | --- | --- |
| Escola | Admin/Gestor | provisionEntityAccount cria School + AccountSetupToken (código 6 dígitos, 24h) + e-mail. Escola abre /primeiro-acesso, insere o código (verifyAccessCode), define senha (setupAccountPassword). No 1.º login completeAccountSetup liga School.owner_user_id e user_type=escola. |
| Refeitório | Admin/Gestor | Mesmo fluxo; entidade Refectory, user_type=parceiro. |
| Fornecedor B2B | Admin/Gestor | Entidade CafeteriaSupplier, user_type=parceiro. |
| Parceiro de serviços | Admin/Gestor | Entidade Partner, user_type=parceiro. |
| Gestor nacional | Admin | Token entity_type=gestor; no 1.º login é promovido a role=gestor, user_type=nacional. |
| Operador Financeiro | Admin/Gestor | Criado em FinanceAccount (username+senha, sem e-mail) via manageFinanceAccounts. |
Estudantes, professores e encarregados auto-registam-se em /cadastro/... (validação de telemóvel/BI/foto). O encarregado associa-se a estudantes existentes (vincula guardian_user_ids).
trial_start → trial_end = +24h).processSubscriptions, trial_12h_notification_sent).subscription_status = trial_expired e o acesso é bloqueado (checkStudentAccess).| Plano | Preço | Duração | | --- | --- | --- | | Trimestral | 1.300 Kz | 3 meses | | Semestral | 2.500 Kz | 6 meses | | Anual | 3.500 Kz | 12 meses | | Cartão CAE (só cartão) | 3.500 Kz | — |
SubscriptionPayment (status=pendente, finance_status=aguardando).cartao).subscription_start/end são calculados por computeSubscriptionEnd.processSubscriptions expira assinaturas vencidas.WalletConfig.ptt_rate_kz).PTTTopupRequest (comprovativo + duas fases). Aprovado → credited=true e crédito em Student.ptt_balance (registado em PTTTransaction).pendente → aprovado → impresso → pronto → entregue (ou reemitido / cancelado).
card_status notifica automaticamente os encarregados (workflow)./validar-cartao/:code e leitura QR (/scanner, /validar) → ScanLog.CardHistory.ClassRoom): criação/gestão pela escola; detalhe por turma com estudantes e professores.Grade): lançadas pelo professor; notifica encarregados automaticamente.Attendance): registo pelo professor; notifica encarregados; alimenta o CAE Score (Assiduidade).Assignment + AssignmentSubmission): professor cria, estudante entrega, professor avalia; notifica encarregados.Occurrence) e Reclamações (Complaint): registo e seguimento.SchoolConfig): classes, períodos, ano letivo, disciplinas, cursos — definidos pela escola.TeacherReview).AcademicPost (resumo, exercício, vídeo, foto, projeto, experiência, trabalho, PDF, mapa mental, dica, flashcard, notícia).minha_turma / minha_classe / meu_nivel / minha_escola.AcademicComment); moderação (status: ativo/denunciado/oculto); destaque (is_featured).StudyRoom): criadas por um delegado, por disciplina; membros, materiais, mensagens, tarefas, eventos. Entrada por convite ou link partilhável (/sala/:token) com limite e validade opcionais./nacional/eventos/criar) ou escolar, com categorias, organizador (escola/nacional/parceiro), target_roles, local, data, capacidade.gratuito, kwanza, ptt ou combinado. Inscrição via registerForEvent — valida vagas, gera bilhete (qr_token, validation_code 6 dígitos, ticket_code CAE-XXXXXXXX) e, se pago em Kz/PTT, debita ptt_balance./scanner//validar) → EventRegistration.checked_in + ScanLog.distributeEventNotifications).EventReview).Meal) por categoria (pequeno-almoço, almoço, lanche, jantar, aperitivos, bebidas) e produtos (revendidos; avaliação vai ao fornecedor).Order) pagas em PTT, com estados: pendente → confirmado → em preparação → pronto a levantar → levantado (+ cancelado). Cada transição envia notificação ao estudante.StockItem/StockMovement) por categoria; validação de pedidos por QR.MealReview (refeição ou produto) e RefectoryReview.SupplierProduct/Product), encomendas de/para refeitórios (SupplierOrder/SupplyOrder), campanhas de abastecimento (SupplyCampaign), stock e despesas (CafeteriaExpense).ProductReview); perfis e ligações a refeitórios.Service) com variações e profissionais (Professional); reservas (Booking) com calendário.MarketplaceItem), encomendas (MarketOrder), carrinho (CartItem), favoritos (Favorite), avaliações (MarketplaceReview).TwiscoCandidate), votos (TwiscoVote) e configuração (TwiscoConfig) segundo critérios em twiscoCriteria.js. Presente nos portais Estudante, Professor e Nacional./nacional/comunicados): Admin/Gestor escolhe painéis-alvo (targets); distribuição automática in-app + e-mail; eliminação também remove as notificações enviadas./escola/comunicados): escola envia a estudantes/professores/encarregados, opcionalmente por turma.portal field).| Secção | Operação |
| --- | --- |
| Home | Indicadores globais. |
| Escolas / Estudantes / Professores / Encarregados | Registos, detalhe, ações (eliminar estudante em cascata, etc.). |
| Aprovações | Pagamentos (assinatura + carregamento PTT) — decisão final após Contabilidade. |
| Cartões | Estado dos cartões CAE, impressão em lote, detalhe. |
| Carteiras | Saldos PTT, transações. |
| Gestores | Promover/despromover, permissões por secção. |
| Contabilidade | Acessos e operação do painel Financeiro. |
| Pagamentos | PaymentConfig (IBAN, valores). |
| Fornecedor / Parceiros / Refeitório | Gestão de entidades B2B. |
| Eventos | Criação/estatísticas. |
| Comunicados / Notificações Automáticas | Comunicação central. |
| Twisco | Gestão do concurso. |
Constantes e regras de negócio extraídas do código (src/lib/* e src/components/**/*Config.js). Editar nestes ficheiros para ajustar valores.
subscriptionConfig.js)| Chave | Valor |
| --- | --- |
| PLANS.trimestral | 1.300 Kz · 3 meses |
| PLANS.semestral | 2.500 Kz · 6 meses |
| PLANS.anual | 3.500 Kz · 12 meses |
| CARD_PLAN.cartao | 3.500 Kz · só cartão (sem assinatura) |
| PHYSICAL_CARD_PRICE | 3.500 Kz |
| TRIAL_HOURS | 24 h |
| CONTACT_PHONE | +244 923 730 122 |
computeSubscriptionEnd(planId, start) soma os meses; daysRemaining/trialRemainingMs/formatRemaining calculam tempo restante.
walletConversion.js)| Chave | Valor |
| --- | --- |
| DEFAULT_PTT_RATE_KZ | 0,85 (1 Kz = 0,85 PTT) |
| KZ_PRESETS | 1.000 / 2.500 / 5.000 / 10.000 / 20.000 / 50.000 Kz |
| MIN_PTT | 10 PTT |
pttRate(config) usa WalletConfig.ptt_rate_kz se definido pelo admin, senão o padrão CAE. kzToPtt(kz, config) arredonda; minKz(config) é o Kz mínimo para atingir MIN_PTT.
caeScoreConfig.js / caeScoreEngine.js)| Nível | Nome | Pontos | | --- | --- | --- | | 1 | Iniciante | 0–99 | | 2 | Explorador | 100–249 | | 3 | Participante | 250–499 | | 4 | Destaque | 500–999 | | 5 | Mestre CAE | 1.000–1.999 | | 6 | Embaixador CAE | 2.000+ |
100 → 10 PTT · 250 → 25 · 500 → 50 · 1.000 → 100 · 2.000 → 250.
Presença 10 · Bónus de sequência 15 · Trabalho entregue 15 (+5 se pontual) · Presença em evento 20 · Sessão de estudo 10 · Tarefa/desafio 5 · Post 12 (cap 20 posts) · Reação recebida (cap 40) · Comentário dado 3 (cap 40).
Assiduidade 200 · Comportamento 100 · Trabalhos 200 · Participação 200 · Disciplina 100 · Estudo 200 · Comunidade 200 · Eventos 200.
Aluno Exemplar, 30 Dias Sem Faltas, Melhor Média (≥16), Entregas em Dia, Participação Activa, Mestre da Matemática (≥18), Criador de Conteúdo (5+ posts), Ajudante CAE (10+ comentários), Leitor do Mês (20+ sessões), Espírito de Equipa (5+ comentários).
O motor computeCAEScore(raw) apenas computa (não persiste); combina presenças, notas, entregas, sessões, tarefas, posts, eventos e comentários, respeitando tetos e anti-inflação.
eventConfig.jsx)escola, nacional (CAE), parceiro.gratuito / kwanza / ptt / combinado.genTicketCode → CAE-XXXXXXXX; genValidationCode → 6 dígitos; qr_token UUID.target_roles (vazio ou todos = todos); isEventForRole filtra por portal.mealConfig.js)Refeições (6): Pequeno Almoço, Almoço, Lanche, Jantar, Aperitivos, Bebidas. Produtos (8, revenda): Bebidas, Laticínios, Padaria, Snacks, Hortofruto, Conservas, Higiene, Outros.
availability(meal): preparado = stock_available, vendido = stock_consumed, disponível = max(0, preparado−vendido).fmtPtt(n) → N PTT (formato pt-PT).orderConfig.js)Estados e notificação ao estudante em cada transição:
| Estado | Etiqueta | Notificação |
| --- | --- | --- |
| pendente | Pendente | — |
| confirmado | Confirmado | "O teu pedido foi confirmado." |
| em_processamento | Em preparação | "O teu pedido está a ser preparado." |
| pronto_levantamento | Pronto a levantar | "Dirige-te ao refeitório." |
| concluido | Levantado | "Bom apetite!" |
| cancelado | Cancelado | "O teu pedido foi cancelado." |
statusFromOrder normaliza histórico (pedido_realizado→pendente).
stockConfig.js)Categorias: Grãos e Cereais, Leguminosas, Farináceos, (…) — cada uma com ícone/cor. Movimentos registados em StockMovement.
Excelente · Muito Bom · Inteligente · Muito Útil · Boa Ideia · Criativo · Inspirador.
AcademicPost.visibility)minha_turma · minha_classe · meu_nivel · minha_escola.
autoNotifications.ts)Africa/Luanda.dedupe_key = categoria + dia + utilizador (impede duplicações).Student.card_status): pendente · aprovado · impresso · pronto · entregue · reemitido · cancelado.Student.subscription_status): trial_active · trial_expired · payment_pending · payment_rejected · subscription_active · subscription_expired.SubscriptionPayment/PTTTopupRequest): status pendente/aprovado/rejeitado + finance_status aguardando/aprovado/rejeitado.Student.status): pendente · activo · candidato · suspenso · graduado · desistente.Notification.type)comunicado · nota · presenca · evento · marketplace · cartao · ptt · sistema · urgente · sala_estudo · pedido · fornecedor · stock · entrega · refeitorio · pagamento · mensagem.
src/lib/angolaRegions.js.src/lib/countries.js (seletor PhoneCountryPicker).xxx xxx xxx; validação de unicidade por checkPhoneExists.Africa/Luanda (UTC+1, sem horário de verão).Legenda: R responsável de executa · A aprova · C consultado · I informado.
| Atividade | Admin | Gestor | Escola | Financeiro | Estudante/Encarregado | Professor | | --- | --- | --- | --- | --- | --- | --- | | Convidar/promover gestores | A | C | — | — | — | — | | Aprovar acesso de entidades (escolas/refeitórios/fornecedores/parceiros) | A/R | R | I | — | — | — | | Registar/configurar escola | A | R | R | — | — | — | | Criar acessos do painel Financeiro | A | R | — | I | — | — | | Validar comprovativo (1.ª fase) | I | I | — | R | I | — | | Aprovar/rejeitar pagamento (2.ª fase) | A/R | R | — | C | I | — | | Emitir cartão CAE / estados | A | R | C | — | I | — | | Criar comunicado nacional | A/R | R | — | — | I | — | | Criar comunicado escolar | I | I | R | — | I | — | | Configurar notificações automáticas | A | R | — | — | I | — | | Criar evento nacional | A/R | R | C | — | I | C | | Inscrever em evento / pagar | — | — | — | — | R | R | | Lançar notas/presenças/trabalhos | I | I | C | — | I | R | | Gerir refeitório (refeições/stock) | I | I | — | — | — | — | | Gerir fornecedor (produtos/encomendas) | I | I | — | — | — | — | | Publicar no feed / salas de estudo | — | — | — | — | R | R | | Eliminar estudante (cascata) | A/R | R | C | — | — | — | | Eliminar comunicado | A/R | R | — | — | — | — |
Gestor tem paridade operacional com Admin nas ações de gestão; secções visíveis no painel nacional dependem de
national_permissions.
| Cadência/Evento | O que faz |
| --- | --- |
| A cada 5 min | Envia notificações automáticas do horário + remove as expiradas (>24h). |
| A cada 15 min | processSubscriptions: expira testes (24h), notifica 12h antes, expira assinaturas. |
| Announcement create | Distribui comunicado nacional (in-app + e-mail). |
| Announcement create | Notifica encarregados (comunicado escolar). |
| Grade/Attendance/Assignment/PTTTransaction create | Notifica encarregados. |
| Student update (card_status) | Notifica encarregados (estado do cartão). |
| EventRegistration create | Notifica inscrição em evento. |
| Event update (status) | Notifica publicação/cancelamento de evento. |
https://cae-smart-campus.base44.app; domínio próprio caeao.com (estado da verificação a acompanhar no dashboard).npm run build (Vite). Sem segredos no código; segredos em set_secrets (atualmente google_oauth_client_secret)./functions/<nome>; invocadas pelo SDK dentro da app.base44/emails/.| Sintoma | Causa/Ação |
| --- | --- |
| Informação no verso do cartão de identidade truncada | Bug de layout do componente de BI — ajustar dimensões. |
| Domínio caeao.com "pending" | Verificação no dashboard (Domínios) — DNS/CNAME. |
| Pedidos de registo de professor não aparecem no portal da escola | Verificar Teacher.school_id e enrollment_status. |
| Estudantes sem escola/encarregado associado | Corrigir registos; lista de não-registados no dashboard nacional. |
| 16 encarregados com full_name incorreto | Correção manual pendente. |
| E-mails não chegam a admin/gestor | Verificar CAE_EMAIL_RECIPIENTS (allowlist) em notificationRecipients.ts. |
| Notificação duplicada de auto-msg | dedupe_key (categoria+dia+utilizador) deve impedir; verificar AutoNotificationLog. |
| Pagamento não avança | Confirmar finance_status decidido pela Contabilidade antes de o Admin/Gestor aprovar. |
| Verificação de e-mail obrigatória persiste | Restrição da plataforma — Known issue. |
gestor ↔ admin.UnregisteredSchoolsList nos fluxos do dashboard nacional.catch {} silenciosos (8+) que mascaram erros.GestorActivity, relatórios financeiros, estados de cartões.AutoNotificationLog (entregues/parciais/falhou), saldo de créditos de integração, relatórios B2B.SchoolConfig (classes, períodos, ano letivo, disciplinas, cursos).xxx xxx xxx).