Skip to content

Documentação do Projeto

Ícaro Caldeira Botelho edited this page Jun 21, 2026 · 5 revisions

Documentação — Valida AI

Documentação técnica completa da arquitetura, fluxos de uso e funcionamento da plataforma Valida AI.


Sumário

  1. Visão Geral
  2. Arquitetura da Aplicação
  3. Stack Tecnológica
  4. Backend — Como Funciona
  5. Frontend — Como Funciona
  6. Banco de Dados
  7. Armazenamento de Arquivos (S3)
  8. Fluxos de Uso
  9. Autenticação e Autorização
  10. Multi-Tenancy
  11. Sistema de Eventos
  12. Geração e Verificação de Certificados
  13. Monitoramento e Observabilidade
  14. Infraestrutura e Deploy
  15. CI/CD

1. Visão Geral

O Valida AI é uma plataforma web para validação de horas complementares acadêmicas. Estudantes submetem comprovantes em PDF, coordenadores de curso avaliam (aprovando, reprovando ou solicitando revisão) e, ao aprovar, o sistema gera automaticamente um certificado em PDF com QR Code, verificável publicamente sem login.

Atores do Sistema

Ator Papel
Estudante Submete documentos comprobatórios, acompanha status e baixa certificados
Coordenador Avalia documentos dos cursos que coordena (aprova, reprova, solicita revisão)
Administrador Gerencia instituições, cursos, usuários e vínculos de coordenadores
Visitante Verifica a autenticidade de certificados pela página pública (sem login)

Diagrama de Contexto

flowchart LR
    Estudante(["Estudante"])
    Coordenador(["Coordenador"])
    Admin(["Administrador"])
    Visitante(["Visitante"])

    ValidaAI["Valida AI\nFrontend + Backend + DB"]
    S3[("MinIO / AWS S3\nArmazenamento de\nPDFs e Certificados")]

    Estudante -- "HTTPS" --> ValidaAI
    Coordenador -- "HTTPS" --> ValidaAI
    Admin -- "HTTPS" --> ValidaAI
    Visitante -- "HTTPS" --> ValidaAI
    ValidaAI -- "S3 API" --> S3
Loading

2. Arquitetura da Aplicação

A aplicação segue uma arquitetura cliente-servidor com separação clara entre frontend (SPA) e backend (API REST), comunicando-se via JSON sobre HTTPS.

Diagrama de Containers

flowchart TB
    subgraph ValidaAI["Valida AI"]
        SPA["Frontend SPA\nReact 19 · Vite · TailwindCSS 4\nReact Router 7"]
        API["API REST\nNode.js · Express 5 · TypeScript\nJWT Auth · Barramento de Eventos"]
        DB[("PostgreSQL 16")]
        S3[("MinIO / AWS S3\nArmazenamento de Objetos")]
        Prometheus["Prometheus"]
        Grafana["Grafana"]
    end

    SPA <-- "JSON / HTTPS" --> API
    API -- "SQL / TCP" --> DB
    API -- "S3 API" --> S3
    Prometheus -. "Scrape /metrics" .-> API
    Grafana -. "Query" .-> Prometheus
Loading

Princípios Arquiteturais

  • Modular por domínio: backend organizado em módulos (auth, usuarios, documentos, validacao, certificados, cursos, instituicoes), cada um com rotas e repositórios próprios.
  • Orientada a eventos: transições de status de documentos disparam eventos processados assincronamente por handlers dedicados.
  • Multi-tenant hierárquico: isolamento por instituição → curso → usuário.
  • Stateless: autenticação via JWT, sem estado de sessão no servidor.
  • SQL direto: queries explícitas via driver pg (sem ORM).

3. Stack Tecnológica

Camada Tecnologias
Linguagem TypeScript (backend e frontend)
Backend Node.js 18+, Express 5, JWT (jsonwebtoken), bcryptjs, zod, helmet, multer, pdfkit, qrcode, winston
Frontend React 19, Vite 8, TailwindCSS 4, React Router 7, React Hook Form, TanStack Query, Axios
Banco de Dados PostgreSQL 16 (driver pg, SQL direto)
Armazenamento MinIO (dev) / AWS S3 (prod) via @aws-sdk/client-s3
Containerização Docker, Docker Compose
Proxy Reverso Nginx (SSL/TLS termination)
SSL/TLS Let's Encrypt via Certbot
CI/CD GitHub Actions
Qualidade ESLint, Prettier, SonarCloud
Testes Jest + Supertest (backend), Vitest + Testing Library (frontend)
Monitoramento Prometheus (métricas), Grafana (dashboards)
Logging Winston (structured logging com rotação de arquivos)
Cache Redis (provisionado para uso futuro)

4. Backend — Como Funciona

Estrutura de Diretórios

backend/src/
├── servidor.ts              # Inicialização do servidor HTTP (porta 3000)
├── aplicativo.ts            # Configuração do Express (middlewares, rotas, error handling)
├── configuracao.ts          # Leitura de variáveis de ambiente
│
├── banco/
│   ├── conexao.ts           # Pool de conexões PostgreSQL
│   └── migrations/          # Scripts de migração SQL incrementais
│
├── middleware/
│   ├── autenticacao.ts      # Verificação do token JWT (Bearer)
│   └── autorizacao.ts       # Controle de acesso por perfil (RBAC)
│
├── modulos/                 # Módulos de domínio
│   ├── auth/
│   │   └── rotas.ts         # POST /api/auth/login, /api/auth/cadastro
│   ├── usuarios/
│   │   ├── rotas.ts         # CRUD de usuários
│   │   └── repositorio.ts   # Queries SQL de usuários
│   ├── documentos/
│   │   ├── rotas.ts         # Submissão, listagem, download de documentos
│   │   └── repositorio.ts   # Queries SQL de documentos
│   ├── validacao/
│   │   ├── rotas.ts         # Aprovar, reprovar, solicitar revisão
│   │   └── repositorio.ts   # Queries SQL de validação
│   ├── certificados/
│   │   ├── rotas.ts         # Listagem e download de certificados
│   │   └── repositorio.ts   # Queries SQL de certificados
│   ├── cursos/
│   │   ├── rotas.ts         # CRUD de cursos
│   │   └── repositorio.ts   # Queries SQL de cursos
│   └── instituicoes/
│       ├── rotas.ts         # CRUD de instituições
│       └── repositorio.ts   # Queries SQL de instituições
│
├── eventos/
│   ├── barramento.ts        # EventEmitter (barramento de eventos)
│   ├── tipos.ts             # Tipos de eventos
│   ├── registrar.ts         # Registro de handlers
│   └── handlers/
│       ├── documento-submetido.ts           # Notifica coordenadores
│       ├── documento-aprovado.ts            # Gera certificado + notifica estudante
│       ├── documento-reprovado.ts           # Notifica estudante
│       └── documento-revisao-solicitada.ts  # Notifica estudante
│
├── servicos/
│   ├── armazenamento.ts     # Upload/download S3 + URLs assinadas
│   ├── gerador-certificado.ts  # Geração de PDF com QR Code
│   └── notificacao.ts       # Serviço de notificações (stub)
│
├── utils/
│   ├── metricas.ts          # Métricas Prometheus
│   ├── registrador.ts       # Winston logger
│   └── erros.ts             # Utilitários de erro
│
└── routes/
    ├── publica.ts           # Verificação pública de certificados
    └── verificacao.ts       # Health check

Pipeline de uma Requisição

Cada requisição HTTP passa pelas seguintes camadas, em ordem:

flowchart TD
    A["Requisição HTTP"] --> B["Helmet\nCabeçalhos de segurança"]
    B --> C["CORS\nValidação de origem"]
    C --> D["express.json()\nParse do body JSON — limite 10 MB"]
    D --> E["Métricas\nRegistra duração e status — Prometheus"]
    E --> F["Logger\nLog da requisição — Winston"]
    F --> G["autenticar()\nVerifica token JWT — rotas protegidas"]
    G --> H["exigirPerfil()\nVerifica papel do usuário — RBAC"]
    H --> I["Rota / Handler\nLógica de negócio do módulo"]
    I --> J["Repositório\nQuery SQL via Pool PostgreSQL"]
    J --> K["Resposta JSON\nRetorno ao cliente"]
Loading

Endpoints da API

Autenticação (públicos)

Método Rota Descrição
POST /api/auth/login Login com e-mail e senha, retorna token JWT
POST /api/auth/cadastro Auto-cadastro de estudante (4 etapas)

Documentos (autenticados)

Método Rota Perfil Descrição
GET /api/documentos Todos Lista documentos (filtrado por perfil)
POST /api/documentos Estudante Submete um documento PDF
GET /api/documentos/:id/download Todos URL assinada para download do PDF original

Validação (autenticados)

Método Rota Perfil Descrição
PATCH /api/documentos/:id/aprovar Coordenador/Admin Aprova o documento, dispara geração de certificado
PATCH /api/documentos/:id/reprovar Coordenador/Admin Reprova com observações obrigatórias
PATCH /api/documentos/:id/solicitar-revisao Coordenador/Admin Solicita revisão com observações

Certificados (autenticados)

Método Rota Perfil Descrição
GET /api/certificados Estudante Lista certificados do estudante
GET /api/certificados/:id/download Todos URL assinada para download do certificado PDF

Cursos

Método Rota Perfil Descrição
GET /api/cursos Público Lista cursos ativos (para cadastro)
GET /api/cursos/admin Admin Lista todos os cursos com contagem de alunos
GET /api/cursos/meus Coordenador Cursos que o coordenador gerencia
POST /api/cursos Admin Cria um novo curso

Instituições

Método Rota Perfil Descrição
GET /api/instituicoes Todos Lista instituições
POST /api/instituicoes Admin Cria uma nova instituição

Usuários

Método Rota Perfil Descrição
GET /api/usuarios Admin Lista todos os usuários
POST /api/usuarios Admin Cria um novo usuário
PATCH /api/usuarios/:id Admin Atualiza dados de um usuário

Rotas Públicas

Método Rota Descrição
GET /api/publica/verificar/:hash Verifica autenticidade de um certificado (sem login)
GET /verificacao Health check
GET /metrics Métricas Prometheus

5. Frontend — Como Funciona

Estrutura de Diretórios

frontend/src/
├── main.tsx                 # Entry point (React DOM + providers)
├── App.tsx                  # Roteamento principal (React Router)
│
├── pages/                   # Páginas da aplicação
│   ├── Apresentacao.tsx     # Landing page pública
│   ├── Login.tsx            # Login em 2 etapas (e-mail → senha)
│   ├── Cadastro.tsx         # Cadastro em 4 etapas
│   ├── Dashboard.tsx        # Painel principal (conteúdo por perfil)
│   ├── Documentos.tsx       # Lista de documentos com filtros
│   ├── DetalheDocumento.tsx # Detalhes de um documento
│   ├── SubmeterDocumento.tsx# Formulário de submissão de PDF
│   ├── MeusCertificados.tsx # Certificados do estudante
│   ├── Perfil.tsx           # Edição de perfil
│   ├── Usuarios.tsx         # CRUD de usuários (admin)
│   ├── Alunos.tsx           # Lista de alunos (coordenador)
│   ├── Instituicoes.tsx     # CRUD de instituições (admin)
│   ├── Cursos.tsx           # CRUD de cursos (admin)
│   ├── Verificar.tsx        # Verificação pública de certificado
│   └── NaoEncontrado.tsx    # Página 404
│
├── components/
│   ├── Layout.tsx           # Layout principal com sidebar responsiva
│   ├── PrivateRoute.tsx     # Guard de rota (auth + perfil)
│   └── ui/                  # Componentes reutilizáveis (botões, inputs, etc.)
│
├── contexts/
│   ├── AuthContext.tsx       # Estado de autenticação (token, usuário, login/logout)
│   ├── ToastContext.tsx      # Notificações toast
│   └── ThemeContext.tsx      # Tema claro/escuro
│
├── services/
│   ├── api.ts               # Instância Axios com interceptor de auth
│   ├── auth.ts              # Chamadas de login e cadastro
│   ├── documentos.ts        # Chamadas da API de documentos
│   ├── certificados.ts      # Chamadas da API de certificados
│   ├── cursos.ts            # Chamadas da API de cursos
│   ├── usuarios.ts          # Chamadas da API de usuários
│   └── instituicoes.ts      # Chamadas da API de instituições
│
├── hooks/                   # Hooks customizados
├── types/                   # Interfaces TypeScript
└── lib/
    └── queryClient.ts       # Configuração do TanStack Query

Roteamento

Rota Página Acesso Descrição
/ Apresentacao Público Landing page
/login Login Público Tela de login
/cadastro Cadastro Público Auto-cadastro de estudante
/verificar/:hash Verificar Público Verificação de certificado
/dashboard Dashboard Autenticado Painel principal
/documentos Documentos Autenticado Lista de documentos
/documentos/:id DetalheDocumento Autenticado Detalhes do documento
/documentos/novo SubmeterDocumento Estudante Submissão de documento
/certificados MeusCertificados Estudante Certificados do estudante
/alunos Alunos Coordenador Lista de alunos do curso
/usuarios Usuarios Admin Gerenciamento de usuários
/instituicoes Instituicoes Admin Gerenciamento de instituições
/cursos Cursos Admin Gerenciamento de cursos
/perfil Perfil Autenticado Edição de perfil

Gerenciamento de Estado

flowchart TB
    subgraph Providers["Providers — main.tsx"]
        Auth["AuthProvider\ntoken, usuário, login/logout"]
        Query["QueryClientProvider\nTanStack Query — cache do servidor"]
        Toast["ToastProvider\nNotificações visuais"]
        Theme["ThemeProvider\nTema claro/escuro"]
    end
    Providers --> App["App.tsx\nRoteamento + Páginas"]
Loading
  • AuthContext: armazena token JWT e dados do usuário no localStorage. Fornece login(), logout() e usuario para toda a aplicação.
  • TanStack Query: gerencia estado do servidor (documentos, certificados, usuários, cursos) com cache automático, refetch e invalidação.
  • ToastContext: sistema de notificações visuais.
  • ThemeContext: alternância de tema.

Comunicação com a API

O arquivo services/api.ts cria uma instância Axios centralizada:

  1. Base URL: lida a partir de VITE_API_URL (variável de ambiente do Vite).
  2. Interceptor de requisição: injeta automaticamente o header Authorization: Bearer <token> em todas as chamadas.
  3. Interceptor de resposta: ao receber 401 Unauthorized, limpa o localStorage e redireciona para /login.
flowchart TD
    A["Componente React"] --> B["useQuery() / useMutation()\nTanStack Query"]
    B --> C["services/documentos.ts\nCamada de serviço"]
    C --> D["services/api.ts — Axios\nInterceptors: auth + error handling"]
    D --> E["Backend API — Express"]
Loading

6. Banco de Dados

Diagrama Entidade-Relacionamento

erDiagram
    instituicoes ||--o{ cursos : "1:N"
    cursos ||--o{ usuarios : "1:N"
    cursos ||--o{ documentos : "1:N"
    cursos ||--o{ coordenadores_cursos : "N:N"
    usuarios ||--o{ coordenadores_cursos : "N:N"
    usuarios ||--o{ documentos : "estudante"
    documentos ||--o| certificados : "1:1"
    documentos ||--o{ historico_validacoes : "1:N"

    instituicoes {
        uuid id PK
        varchar nome
        varchar sigla
        varchar cnpj
        text[] dominios_email
        boolean ativa
    }

    cursos {
        uuid id PK
        uuid instituicao_id FK
        varchar nome
        varchar codigo
        int carga_horaria_complementar
        varchar turno
        varchar modalidade
        boolean ativo
    }

    usuarios {
        uuid id PK
        varchar nome
        varchar email UK
        varchar senha_hash
        perfil_usuario perfil
        varchar matricula
        varchar cpf
        uuid curso_id FK
        boolean ativo
    }

    coordenadores_cursos {
        uuid coordenador_id FK
        uuid curso_id FK
    }

    documentos {
        uuid id PK
        varchar titulo
        tipo_documento_enum tipo
        int carga_horaria
        uuid estudante_id FK
        uuid curso_id FK
        status_documento status
        uuid coordenador_id FK
        text observacoes
        varchar caminho_arquivo
    }

    certificados {
        uuid id PK
        uuid documento_id FK
        uuid estudante_id FK
        varchar hash UK
        varchar caminho_arquivo
    }

    historico_validacoes {
        uuid id PK
        uuid documento_id FK
        uuid usuario_id FK
        varchar status_anterior
        varchar status_novo
        text observacoes
        jsonb metadados
    }
Loading

Tabelas Principais

Tabela Propósito
instituicoes Instituições de ensino, com domínios de e-mail permitidos
cursos Cursos vinculados a instituições
usuarios Estudantes, coordenadores e admins
coordenadores_cursos Relação N:N entre coordenadores e cursos
documentos Documentos comprobatórios submetidos
certificados Certificados gerados (1:1 com documento aprovado)
historico_validacoes Trilha de auditoria de todas as decisões

Tipos Enumerados

  • perfil_usuario: estudante, coordenador, admin
  • status_documento: pendente, em_analise, aprovado, reprovado, revisao_solicitada, cancelado
  • tipo_documento_enum: certificado_curso, certificado_evento, declaracao_participacao, comprovante_atividade, artigo_publicado, outro

Migrações

O schema base está em infra/banco.sql e as migrações incrementais em backend/src/banco/migrations/:

Arquivo Descrição
001_add_certificados.sql Criação da tabela certificados
002_add_senha.sql Adição da coluna senha_hash com senha padrão
003_update_tipo_documento_enum.sql Atualização dos tipos de documento
004_add_coordenadores_cursos.sql Relação N:N coordenador-curso

Acesso a Dados

O backend não usa ORM. Cada módulo possui um repositorio.ts com queries SQL explícitas executadas via Pool do driver pg:

flowchart LR
    A["Rota — Express"] --> B["Repositório — SQL"] --> C["Pool PostgreSQL"] --> D[("Banco")]
Loading

7. Armazenamento de Arquivos (S3)

O sistema usa armazenamento compatível com S3 para PDFs de documentos e certificados.

Ambientes

Ambiente Serviço Endpoint
Desenvolvimento MinIO http://localhost:9000
Produção AWS S3 https://s3.amazonaws.com

Buckets

Bucket Variável de Ambiente Conteúdo
Documentos AWS_S3_BUCKET PDFs originais submetidos pelos estudantes
Certificados AWS_S3_BUCKET_CERTIFICADOS PDFs de certificados gerados pelo sistema

Fluxo de Upload (Documentos)

flowchart TD
    A["Estudante envia PDF"] --> B["Multer — Express\nRecebe multipart/form-data\nlimite 10 MB"]
    B --> C["armazenamento.ts\nPutObjectCommand"]
    C --> D[("MinIO / AWS S3\ndocumentos/id/filename")]
Loading

Fluxo de Download

flowchart TD
    A["Usuário clica em Baixar"] --> B["GET /api/documentos/:id/download"]
    B --> C["armazenamento.ts\nGetObjectCommand + S3 Presigner"]
    C --> D["URL assinada\nexpira em 1 hora"]
    D --> E["Navegador baixa o PDF\ndireto do S3"]
Loading

8. Fluxos de Uso

8.1 Cadastro de Estudante (4 Etapas)

flowchart LR
    E1["Etapa 1\nSelecionar\nInstituição"] --> E2["Etapa 2\nSelecionar\nCurso + Turno"]
    E2 --> E3["Etapa 3\nNome, E-mail,\nMatrícula"]
    E3 --> V{"Validação do\ndomínio de e-mail"}
    V -->|Válido| E4["Etapa 4\nDefinir Senha\nmin 6 chars"]
    V -->|Inválido| Erro["Erro:\ndomínio não autorizado"]
    E4 --> OK["Cadastro concluído\nToken JWT retornado"]
Loading

O que acontece por trás:

  1. Frontend chama GET /api/instituicoes para listar instituições.
  2. Ao selecionar instituição, chama GET /api/cursos?instituicao_id=X para listar cursos.
  3. Ao preencher o formulário completo, chama POST /api/auth/cadastro.
  4. Backend valida domínio do e-mail, cria hash bcrypt da senha, insere o usuário com perfil: 'estudante'.
  5. Backend retorna token JWT e dados do usuário. Frontend armazena no localStorage e redireciona ao Dashboard.

8.2 Login

flowchart LR
    E1["Etapa 1\nInformar E-mail"] --> E2["Etapa 2\nInformar Senha"]
    E2 --> D["Dashboard"]
Loading

O que acontece por trás:

  1. Frontend chama POST /api/auth/login com { email, senha }.
  2. Backend busca usuário pelo e-mail, verifica senha com bcrypt.compare().
  3. Valida domínio do e-mail contra a instituição.
  4. Gera token JWT com payload: { sub, email, nome, perfil, matricula, curso_id, curso_ids, instituicao_id, instituicao_nome }.
  5. Retorna { token, usuario } ao frontend.
  6. Frontend armazena no localStorage, atualiza o AuthContext e redireciona ao /dashboard.

8.3 Submissão de Documento (Estudante)

flowchart LR
    A["Estudante preenche\nformulário:\n• Título\n• Tipo\n• Carga horária\n• Arquivo PDF"] --> B["Backend recebe\ne processa:\n• Valida com Zod\n• Upload S3\n• Insert no BD\n• Emite evento"]
    B --> C["Coordenadores\nsão notificados"]
Loading

Fluxo detalhado:

  1. Estudante acessa /documentos/novo e preenche: título, tipo de documento, carga horária, arquivo PDF.
  2. Frontend envia POST /api/documentos com multipart/form-data.
  3. Backend (Multer) recebe o arquivo, valida tipo (PDF) e tamanho (máx 10 MB).
  4. Faz upload do PDF para o bucket S3.
  5. Insere registro na tabela documentos com status: 'pendente'.
  6. Emite evento documento_submetido no barramento.
  7. Handler do evento busca coordenadores ativos do curso e envia notificação.
  8. Retorna 201 Created ao frontend com os dados do documento.

8.4 Avaliação de Documento (Coordenador)

flowchart LR
    C["Coordenador\navalia\ndocumento"] -->|Aprovar| AP["APROVADO"]
    C -->|Reprovar| RE["REPROVADO"]
    C -->|Solicitar revisão| RS["REVISÃO SOLICITADA"]

    AP --> CERT["Gera certificado PDF + QR Code\nNotifica estudante"]
    RE --> NOTI1["Notifica estudante\nobservações obrigatórias"]
    RS --> NOTI2["Notifica estudante\nobservações obrigatórias"]
Loading

Fluxo de aprovação detalhado:

  1. Coordenador acessa /documentos e vê documentos dos cursos que coordena.
  2. Clica em um documento para ver detalhes em /documentos/:id.
  3. Faz download do PDF original para analisar.
  4. Decide: aprovar, reprovar ou solicitar revisão.
  5. Se aprova (PATCH /api/documentos/:id/aprovar):
    • Backend atualiza status → 'aprovado' e coordenador_id.
    • Insere registro em historico_validacoes.
    • Emite evento documento_aprovado.
    • Handler gera certificado PDF com QR Code (PDFKit).
    • Calcula hash SHA-256 único para o certificado.
    • Faz upload do certificado PDF para bucket S3.
    • Insere registro em certificados.
    • Notifica o estudante.

8.5 Verificação Pública de Certificado

flowchart LR
    A["Visitante\nescaneia\nQR Code"] --> B["Frontend carrega\n/verificar/:hash"]
    B --> C["GET /api/publica/verificar/:hash"]
    C -->|Hash encontrado| D["Certificado Válido\nNome, título, data"]
    C -->|Hash não encontrado| E["Erro:\ncertificado inválido"]
Loading

O que acontece:

  1. Qualquer pessoa escaneia o QR Code impresso no certificado.
  2. QR Code redireciona para {FRONTEND_URL}/verificar/{hash}.
  3. Frontend faz GET /api/publica/verificar/:hash (sem autenticação).
  4. Backend busca o certificado pelo hash SHA-256.
  5. Se encontrado: retorna nome do estudante, título do documento, tipo, carga horária e data de aprovação.
  6. Frontend exibe card com selo "Certificado Válido".
  7. Se não encontrado: exibe mensagem de erro.

8.6 Ciclo de Vida de um Documento

stateDiagram-v2
    [*] --> PENDENTE : Estudante submete

    PENDENTE --> EM_ANALISE : Coordenador visualiza
    PENDENTE --> CANCELADO : Estudante cancela

    EM_ANALISE --> APROVADO : Coordenador aprova
    EM_ANALISE --> REPROVADO : Coordenador reprova
    EM_ANALISE --> REVISAO_SOLICITADA : Coordenador solicita revisão

    APROVADO --> CERTIFICADO_GERADO : Geração automática PDF + QR

    REVISAO_SOLICITADA --> PENDENTE : Estudante reenvia

    CERTIFICADO_GERADO --> [*]
    REPROVADO --> [*]
    CANCELADO --> [*]
Loading

Status possíveis:

  • pendente — documento submetido, aguardando análise
  • em_analise — coordenador visualizou o documento
  • aprovado — coordenador aprovou, certificado gerado automaticamente
  • reprovado — coordenador reprovou com justificativa
  • revisao_solicitada — coordenador pediu correções
  • cancelado — estudante cancelou a submissão (apenas se ainda pendente)

9. Autenticação e Autorização

Autenticação (JWT)

sequenceDiagram
    participant F as Frontend
    participant B as Backend

    F->>B: POST /api/auth/login { email, senha }
    B-->>F: { token, usuario }
    Note over F: Armazena token no localStorage

    F->>B: GET /api/documentos<br/>Authorization: Bearer token
    Note over B: Middleware valida JWT
    B-->>F: { documentos: [...] }
Loading

Payload do Token JWT:

{
  "sub": "uuid-do-usuario",
  "email": "estudante@instituicao.edu.br",
  "nome": "Nome do Estudante",
  "perfil": "estudante",
  "matricula": "2024001",
  "curso_id": "uuid-do-curso",
  "curso_ids": [],
  "instituicao_id": "uuid-da-instituicao",
  "instituicao_nome": "Nome da Instituição"
}

Autorização (RBAC)

O middleware exigirPerfil() verifica se o perfil do token corresponde aos perfis autorizados para a rota:

Perfil Permissões
Estudante Submeter documentos, ver próprios documentos, ver próprios certificados, cancelar submissão pendente, editar perfil
Coordenador Avaliar documentos dos cursos que coordena, ver alunos dos seus cursos, editar perfil
Admin Tudo: CRUD de instituições, cursos, usuários, vincular coordenadores, ver todos os documentos

Segurança

  • Senhas armazenadas com hash bcrypt (custo 10)
  • Token JWT assinado com JWT_SECRET (obrigatório em produção)
  • Expiração configurável via JWT_EXPIRES_IN (padrão: 7 dias)
  • Headers de segurança via helmet
  • CORS restrito a allowlist (CORS_ORIGIN)
  • Validação de entrada com zod
  • HTTPS obrigatório em produção (Nginx + Let's Encrypt)

10. Multi-Tenancy

A aplicação suporta múltiplas instituições de ensino de forma isolada, seguindo um modelo hierárquico:

flowchart TB
    I["Instituição\nex: Católica SC\ndominios_email: catolicasc.org.br"]

    subgraph CA["Curso A — Engenharia de Software"]
        C1["Coordenador 1\nvê apenas docs do Curso A"]
        E1["Estudante 1\nvê apenas próprios docs"]
        E2["Estudante 2\nvê apenas próprios docs"]
    end

    subgraph CB["Curso B — Ciência da Computação"]
        C2["Coordenador 2\nvê apenas docs do Curso B"]
        E3["Estudante 3\nvê apenas próprios docs"]
    end

    I --> CA
    I --> CB
Loading

Mecanismos de Isolamento

  1. Domínio de e-mail: no cadastro e login, o domínio do e-mail é validado contra instituicoes.dominios_email. Apenas e-mails com domínios autorizados podem acessar o sistema.

  2. Filtragem por curso (Coordenador): coordenadores possuem vínculo N:N com cursos via coordenadores_cursos. Ao listar documentos, o backend filtra: WHERE curso_id IN (cursos_do_coordenador).

  3. Filtragem por propriedade (Estudante): estudantes veem apenas documentos onde estudante_id = usuario_logado.

  4. Acesso total (Admin): admins veem todos os recursos sem filtro.


11. Sistema de Eventos

A aplicação usa um barramento de eventos baseado no EventEmitter do Node.js para desacoplar ações assíncronas da resposta HTTP.

Diagrama do Fluxo de Eventos

sequenceDiagram
    participant Client as Cliente
    participant Rota as Rota de Validação
    participant BD as Banco de Dados
    participant Bus as Barramento de Eventos
    participant Handler as Handler Assíncrono
    participant S3 as MinIO / S3

    Client->>Rota: PATCH /documentos/:id/aprovar
    Rota->>BD: UPDATE status → aprovado
    Rota->>Bus: emitir('documento_aprovado', payload)
    Rota-->>Client: 200 OK (resposta imediata)

    Note over Bus,Handler: Processamento assíncrono

    Bus->>Handler: documento-aprovado.ts
    Handler->>Handler: Gera PDF (PDFKit + QR Code)
    Handler->>S3: Upload certificado PDF
    Handler->>BD: INSERT certificados
    Handler->>Handler: Notifica estudante
Loading

Eventos Disponíveis

Evento Gatilho Handler
documento_submetido Estudante submete um documento Notifica coordenadores do curso
documento_aprovado Coordenador aprova um documento Gera certificado PDF e notifica estudante
documento_reprovado Coordenador reprova um documento Notifica estudante com motivo
documento_revisao_solicitada Coordenador solicita revisão Notifica estudante com observações

12. Geração e Verificação de Certificados

Geração do Certificado PDF

Quando um documento é aprovado, o handler documento-aprovado.ts aciona o gerador-certificado.ts:

flowchart TD
    A["Documento aprovado"] --> B["PDFKit cria PDF A4 Landscape"]

    B --> B1["Bordas decorativas — tema azul"]
    B --> B2["Título: CERTIFICADO"]
    B --> B3["Nome do estudante"]
    B --> B4["Tipo de atividade + Carga horária"]
    B --> B5["Data de aprovação + Coordenador"]
    B --> B6["QR Code 80x80px\nURL: /verificar/hash"]

    B1 & B2 & B3 & B4 & B5 & B6 --> C["Hash SHA-256 gerado\ndocumentoId + timestamp + 16 bytes"]
    C --> D["Upload para S3\ncertificados/docId/hash.pdf"]
    D --> E["INSERT na tabela certificados"]
Loading

Verificação Pública

Qualquer pessoa pode verificar a autenticidade de um certificado:

  1. Escaneia o QR Code ou acessa {URL}/verificar/{hash}.
  2. O frontend chama GET /api/publica/verificar/:hash.
  3. O backend busca na tabela certificados pelo hash.
  4. Se encontrado, retorna dados públicos (nome, título, data).
  5. Nenhuma autenticação necessária.

13. Monitoramento e Observabilidade

Prometheus

Métricas coletadas automaticamente pelo middleware medirRequisicoes:

Métrica Tipo Labels Descrição
http_request_duration_seconds Histogram method, route, status Duração das requisições HTTP
http_requests_total Counter method, route, status Total de requisições HTTP
Métricas padrão do Node.js Diversos CPU, memória, event loop, GC

Endpoint: GET /metrics (formato texto Prometheus)

Grafana

  • Acesso: http://localhost:3001 (dev) ou via SSH tunnel (prod)
  • Datasource: Prometheus
  • Dashboards provisionados automaticamente via infra/grafana/provisioning/

Logging (Winston)

Destino Conteúdo Rotação
Console Todos os níveis (colorizado)
logs/erro.log Apenas erros 5 MB, até 5 arquivos
logs/combinado.log Todos os níveis 5 MB, até 5 arquivos

Nível configurável via LOG_LEVEL (padrão: info).


14. Infraestrutura e Deploy

Ambiente de Desenvolvimento

docker compose -f docker-compose.dev.yml up -d
Serviço Porta Descrição
PostgreSQL 5432 Banco de dados (inicializado com infra/banco.sql + seed)
Redis 6379 Cache (provisionado)
MinIO 9000 (API), 9001 (Console) Armazenamento S3 local
Prometheus 9090 Coleta de métricas
Grafana 3001 Dashboards

Após os containers, rodar backend e frontend localmente:

npm run dev   # Inicia backend (porta 3000) e frontend (porta 5173) simultaneamente

Ambiente de Produção

flowchart TB
    Internet(["Internet"]) --> Nginx

    subgraph Servidor["Servidor de Produção"]
        Nginx["Nginx\nPorta 80 → 301 HTTPS\nPorta 443 — TLS"]
        Nginx --> Frontend["Frontend\nNginx estático\nservindo build React"]
        Nginx --> Backend["Backend\nExpress API\nporta 3000"]

        Backend --> PG[("PostgreSQL\nporta 5432")]
        Backend --> Redis[("Redis\nporta 6379")]

        Prometheus["Prometheus\nlocalhost:9090"] -. scrape .-> Backend
        Grafana["Grafana\nlocalhost:3001"] -. query .-> Prometheus

        Certbot["Certbot\nRenovação automática SSL"]
        Certbot -. "Let's Encrypt" .-> Nginx
    end
Loading

Variáveis de Ambiente Essenciais

Variável Obrigatória Descrição
DB_HOST Sim Host do PostgreSQL
DB_PORT Sim Porta do PostgreSQL (5432)
DB_USER Sim Usuário do banco
DB_PASSWORD Sim Senha do banco
DB_NAME Sim Nome do banco
JWT_SECRET Sim Segredo para assinar tokens JWT
JWT_EXPIRES_IN Não Tempo de expiração do token (padrão: 7d)
AWS_REGION Sim Região AWS / MinIO
AWS_ACCESS_KEY_ID Sim Chave de acesso S3
AWS_SECRET_ACCESS_KEY Sim Segredo de acesso S3
AWS_S3_BUCKET Sim Bucket para documentos
AWS_S3_BUCKET_CERTIFICADOS Sim Bucket para certificados
S3_ENDPOINT Dev Endpoint MinIO (ex: http://localhost:9000)
S3_FORCE_PATH_STYLE Dev true para MinIO
CORS_ORIGIN Sim Origem permitida para CORS
FRONTEND_URL Sim URL do frontend (para QR Codes)
VITE_API_URL Sim URL da API para o frontend
LOG_LEVEL Não Nível de log Winston (padrão: info)

15. CI/CD

O projeto usa GitHub Actions para integração e deploy contínuos.

Pipeline

flowchart TD
    A["Push / Pull Request"] --> B["Testes\nBackend — Jest\nFrontend — Vitest"]
    B --> C["Lint + Format\nESLint · Prettier"]
    C --> D["SonarCloud\nAnálise estática de qualidade"]
    D --> E["Build Docker\nFrontend image · Backend image"]
    E --> F["Push Images\nDocker Hub / Registry"]
    F --> G["Deploy via SSH\ndocker compose pull & up"]
Loading

Qualidade de Código

  • ESLint: linting TypeScript para backend e frontend
  • Prettier: formatação consistente
  • SonarCloud: análise estática (bugs, vulnerabilidades, code smells, cobertura)
  • Testes automatizados: Jest + Supertest (backend), Vitest + Testing Library (frontend)

Valida AI — Plataforma de validação de horas complementares acadêmicas com emissão automática de certificados verificáveis.

Clone this wiki locally