# PROMPT COMPLETO — Portal do Aluno (EduManager Student Portal) > **Copie este prompt inteiro e cole em uma nova conversa para criar o projeto do zero.** --- ## Objetivo Atue como um Desenvolvedor Sênior Full-Stack. Crie um projeto NOVO e SEPARADO chamado **"Portal do Aluno"** — uma aplicação web onde os alunos matriculados no sistema **EduManager** podem fazer login e visualizar seus dados acadêmicos e financeiros. Este portal **NÃO faz parte do código do EduManager**. É um projeto independente que **CONSOME os mesmos dados** do EduManager, lendo diretamente do mesmo banco de dados **Supabase**. --- ## Stack Tecnológica Obrigatória - **Frontend:** React + TypeScript + Vite - **Backend:** Node.js + Express (server.js) - **Banco de Dados:** Supabase (PostgreSQL) — **o mesmo banco do EduManager, apenas leitura** - **Estilização:** TailwindCSS - **Deploy:** Docker (Dockerfile multi-stage) para rodar no **Portainer via Docker Swarm** - **Porta:** 3001 (para não conflitar com o EduManager que roda na 3000) --- ## Arquitetura do Banco de Dados (Supabase — SOMENTE LEITURA) O EduManager armazena TODOS os dados da escola em uma **única tabela** chamada `school_data` com uma **única linha** (id = 1). O campo `data` é um JSON gigante com a seguinte estrutura: ```typescript // Tabela: school_data (id: 1, coluna "data" tipo JSONB) { students: Student[], // Lista de todos os alunos classes: Class[], // Lista de turmas courses: Course[], // Lista de cursos payments: Payment[], // Lista de todos os pagamentos/cobranças contracts: Contract[], // Contratos dos alunos certificates: Certificate[], // Certificados emitidos attendance: Attendance[], // Registros de presença subjects: Subject[], // Disciplinas grades: Grade[], // Notas dos alunos exams: Exam[], // Avaliações (Provas e Atividades) profile: SchoolProfile, // Dados da escola (nome, logo, etc.) logo?: string, // Logo da escola em base64 } ``` ### Interface Student (campos relevantes para login): ```typescript interface Student { id: string; // UUID name: string; // Nome completo email: string; phone: string; birthDate: string; // YYYY-MM-DD cpf: string; // Formato: 000.000.000-00 rg?: string; classId: string; // ID da turma vinculada status: 'active' | 'inactive' | 'cancelled'; registrationDate: string; photo?: string; // Base64 da foto do aluno addressZip?: string; addressStreet?: string; addressNumber?: string; addressNeighborhood?: string; addressCity?: string; addressState?: string; enrollmentNumber?: string; // ← LOGIN (formato: MAT-202600001) portalPassword?: string; // ← SENHA (padrão: 6 primeiros dígitos do CPF) discount?: number; } ``` ### Interface Payment (cobranças do aluno): ```typescript interface Payment { id: string; studentId: string; // Relaciona com Student.id amount: number; discount?: number; dueDate: string; // YYYY-MM-DD status: 'pending' | 'paid' | 'overdue'; paidDate?: string; type: 'monthly' | 'registration' | 'other'; installmentNumber?: number; totalInstallments?: number; description?: string; asaasPaymentId?: string; // ID no Asaas asaasPaymentUrl?: string; // URL do boleto no Asaas } ``` ### Outras Tabelas Auxiliares no Supabase: **Tabela `alunos_cobrancas`** (cobranças sincronizadas com Asaas): ```sql -- Colunas principais: id (uuid), aluno_id (uuid), asaas_customer_id (text), asaas_payment_id (text), asaas_installment_id (text), valor (numeric), vencimento (date), link_boleto (text), link_carne (text), status (text), created_at (timestamptz) ``` ### Interface Grade (notas): ```typescript interface Grade { id: string; studentId: string; subjectId: string; value: number; period: string; // Ex: "1º Bimestre" examId?: string; // ID da avaliação vinculada (se houver) } ``` ### Interface Exam (avaliações): ```typescript interface Exam { id: string; title: string; evaluationType: 'exam' | 'activity'; maxScore: number; subjectId?: string; periodId?: string; } ``` ### Interface Attendance (frequência): ```typescript interface Attendance { id: string; studentId: string; classId: string; date: string; // ISO String verified: boolean; type?: 'presence' | 'absence'; justification?: string; } ``` ### Interface Class e Course: ```typescript interface Class { id: string; name: string; courseId: string; teacher: string; schedule: string; } interface Course { id: string; name: string; duration: string; monthlyFee: number; } ``` ### Interface Contract: ```typescript interface Contract { id: string; studentId: string; title: string; content: string; // HTML do contrato createdAt: string; } ``` ### Interface Certificate: ```typescript interface Certificate { id: string; studentId: string; description?: string; issueDate: string; } ``` ### Interface SchoolProfile: ```typescript interface SchoolProfile { id: string; name: string; address: string; city: string; state: string; cnpj: string; phone: string; email: string; } ``` --- ## Sistema de Autenticação ### Login: - **Usuário:** Campo `enrollmentNumber` do aluno (ex: `MAT-202600001`) - **Senha:** Campo `portalPassword` do aluno (padrão: 6 primeiros dígitos do CPF) ### Fluxo de Login no Backend: 1. Receber `enrollmentNumber` e `password` via POST `/api/portal/login` 2. Consultar a tabela `school_data` (id=1), pegar o JSON `data` 3. Buscar no array `data.students` o aluno cujo `enrollmentNumber` = input do usuário 4. Verificar se `portalPassword` === senha digitada 5. Se válido: gerar um JWT (jsonwebtoken) com `{ studentId, enrollmentNumber, name }` e retornar 6. Se inválido: retornar 401 ### Middleware de Autenticação: - Criar middleware `authMiddleware` que valida o JWT em todas as rotas `/api/portal/*` - O JWT secret deve vir de `process.env.JWT_SECRET` --- ## Funcionalidades do Portal (Páginas) ### 1. Tela de Login - Design moderno, escuro, com gradientes - Logo da escola carregada dinamicamente do Supabase (campo `data.logo`) - Campos: Nº de Matrícula + Senha - Botão "Entrar" - Mensagem de erro amigável se credenciais inválidas ### 2. Dashboard (Página Inicial pós-login) - Saudação: "Olá, {nome do aluno}!" - Foto do aluno (se tiver) - Cards resumo: - **Turma:** nome da turma e curso vinculado - **Financeiro:** total de parcelas pendentes / valor total em aberto - **Frequência:** porcentagem de presença - **Próximo vencimento:** data e valor ### 3. Financeiro (Meus Boletos) - Tabela listando TODOS os pagamentos do aluno (filtrados por `studentId`) - Colunas: Descrição, Vencimento, Valor, Status (badges coloridos), Ação - Botão "Ver Boleto" que abre o link do Asaas (`asaasPaymentUrl` ou buscar da tabela `alunos_cobrancas.link_boleto`) - Filtros: Todos, Pendentes, Pagos, Atrasados - Destaque visual para boletos atrasados (vermelho) ### 4. Notas / Boletim - Buscar no array `data.grades` todas as notas onde `studentId` = aluno logado - Buscar os nomes das disciplinas no array `data.subjects` - Exibir em formato de tabela/boletim organizada por período (1º Bimestre, 2º Bimestre, etc.) - Calcular média automaticamente ### 5. Frequência / Presença - Buscar no array `data.attendance` onde `studentId` = aluno logado - Mostrar calendário ou lista com os dias de presença/falta - Exibir porcentagem total de frequência - Justificativas de falta quando houver ### 6. Contratos - Listar contratos do aluno (array `data.contracts` filtrado por `studentId`) - Botão para visualizar o contrato completo (renderizar HTML) - Botão para download/impressão ### 7. Certificados - Listar certificados emitidos para o aluno - Botão para visualizar/download ### 8. Meus Dados - Exibir dados pessoais do aluno (somente leitura): - Nome, CPF, RG, Data de Nascimento, Telefone, Email - Endereço completo - Dados do responsável (se tiver) - Botão "Alterar Senha" que permite trocar a `portalPassword` - Para salvar a nova senha: fazer PUT no server.js que atualiza o campo `portalPassword` do aluno no JSON `data.students` dentro da `school_data` --- ## Rotas do Backend (server.js) ``` POST /api/portal/login → Autenticação (retorna JWT) GET /api/portal/me → Dados do aluno logado (protegido) GET /api/portal/financeiro → Pagamentos do aluno (protegido) GET /api/portal/notas → Notas/boletim do aluno (protegido) GET /api/portal/frequencia → Registros de presença (protegido) GET /api/portal/contratos → Contratos do aluno (protegido) GET /api/portal/certificados → Certificados do aluno (protegido) GET /api/portal/boletos → Boletos do Asaas (tabela alunos_cobrancas) (protegido) PUT /api/portal/alterar-senha → Alterar senha do portal (protegido) GET /api/portal/escola → Dados da escola + logo (público, para o login) ``` --- ## Variáveis de Ambiente (Portainer) ```env PORT=3001 VITE_SUPABASE_URL=https://xxxx.supabase.co VITE_SUPABASE_KEY=eyJhb... JWT_SECRET=uma-chave-secreta-forte-aqui ``` --- ## Dockerfile (Multi-stage, igual ao EduManager) ```dockerfile # ---- Build Stage ---- FROM node:22-alpine AS builder WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci COPY . . RUN npm run build # ---- Production Stage ---- FROM node:22-alpine AS production WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci --omit=dev COPY server.js ./ COPY --from=builder /app/dist ./dist EXPOSE 3001 CMD ["node", "server.js"] ``` --- ## Regras e Restrições CRÍTICAS 1. **SOMENTE LEITURA** no Supabase — o portal NÃO deve criar, editar ou excluir alunos, pagamentos, notas, etc. A ÚNICA exceção é a rota `PUT /api/portal/alterar-senha` que atualiza o campo `portalPassword` dentro do JSON. 2. **Nunca expor dados de outros alunos** — todas as queries devem filtrar por `studentId` do JWT. 3. **Design Premium** — Use dark mode por padrão, gradientes modernos, animações suaves, tipografia Google Fonts (Inter ou Outfit). O visual deve ser profissional e bonito. 4. **Responsivo** — Deve funcionar perfeitamente em celulares (a maioria dos alunos acessará pelo celular). 5. **O projeto deve ser 100% funcional** — sem mocks, sem placeholder. Lê dados reais do Supabase. 6. **Separação total do EduManager** — Este é um projeto em pasta separada, repositório separado, container Docker separado. Eles compartilham apenas o banco Supabase. --- ## Estrutura de Pastas Esperada ``` portal-aluno/ ├── server.js # Backend Express ├── Dockerfile ├── package.json ├── vite.config.ts ├── tsconfig.json ├── index.html ├── src/ │ ├── main.tsx │ ├── App.tsx │ ├── types.ts # Interfaces compartilhadas │ ├── context/ │ │ └── AuthContext.tsx # Context de autenticação (JWT) │ ├── pages/ │ │ ├── Login.tsx │ │ ├── Dashboard.tsx │ │ ├── Financeiro.tsx │ │ ├── Notas.tsx │ │ ├── Frequencia.tsx │ │ ├── Contratos.tsx │ │ ├── Certificados.tsx │ │ └── MeusDados.tsx │ ├── components/ │ │ ├── Sidebar.tsx │ │ ├── Header.tsx │ │ └── ProtectedRoute.tsx │ └── styles/ │ └── index.css ``` --- **Gere o projeto completo com TODOS os arquivos acima, funcional e pronto para deploy no Docker/Portainer.**