Essa é uma visualização multi-página imprimível desta seção. Aperte aqui para imprimir a página.

Return to the regular view of this page.

Arquitetura

Arquitetura do Ademir

Visão Geral da Arquitetura

O Ademir adota uma arquitetura monolítica modular, composta por frontend, backend e banco de dados.

Para desenvolvimento, os serviços são executados via Docker Compose, conectados em uma rede interna.
Em produção, as imagens são publicadas no Harbor e orquestradas em Kubernetes, garantindo escalabilidade, resiliência e facilidade de atualização.

Além disso, o sistema integra serviços externos, como Amazon S3 para armazenamento de arquivos e Nodemailer para envio de e-mails.

1 - Backend

Visão Geral

O backend do projeto Ademir foi desenvolvido para ser modular, escalável e de fácil manutenção, combinando Node.js + Express com um ecossistema moderno de bibliotecas e ferramentas. Ele é responsável por processar regras de negócio, gerenciar usuários, lidar com autenticação, envio de e-mails, geração de relatórios e integração com serviços externos como Amazon S3.

Tecnologias Utilizadas

  • Node.js + Express: Base do servidor HTTP e da lógica de negócio.

  • TypeScript: Linguagem principal, trazendo tipagem estática, maior robustez e escalabilidade.

  • Sequelize (ORM): Abstração para o banco de dados PostgreSQL, com suporte a migrações, associações e queries estruturadas.

  • PostgreSQL: Banco relacional principal, armazena usuários, permissões, relacionamentos e metadados.

  • Amazon S3 (via @aws-sdk/client-s3): Armazenamento de arquivos.

    • As chaves (keys) dos arquivos ficam no banco de dados.
    • Os arquivos binários ficam salvos diretamente no bucket do S3.
  • Nodemailer: Envio de e-mails (ex.: confirmação de cadastro, notificações).

  • Argon2: Hashing seguro de senhas.

  • Swagger (swagger-jsdoc + swagger-ui-express): Documentação de API interativa, gerada a partir de anotações no código.

  • Morgan + CORS: Middlewares para log de requisições HTTP e configuração de acesso cross-origin.

  • Formidable: Upload de arquivos.

  • pdfmake + PapaParse + JSZip: Geração de relatórios em PDF, CSV e pacotes ZIP com dados/documentos.

  • Node-cron: Agendamento de tarefas automáticas (jobs).

Testes

Estratégia

O fluxo de testes foi estruturado para ser independente, confiável e previsível. Cada entidade é testada de forma isolada, com foco exclusivo em sua funcionalidade. Durante os testes, é criado um usuário temporário no banco de dados, responsável por gerar o token de autenticação necessário para acessar rotas protegidas.

Esse token é então usado em cada requisição de teste (criação, leitura, atualização e exclusão de dados). Ao final da execução, todas as alterações feitas no banco são removidas automaticamente, garantindo que o ambiente esteja sempre limpo e consistente.

Ferramentas

  • Jest: Estrutura de testes unitários e de integração.
  • Supertest: Simulação de requisições HTTP para validar endpoints de forma realista.

CI/CD

O projeto conta com pipeline de Integração Contínua (CI) que roda automaticamente a cada commit ou pull request:

  • Execução de testes (Jest + Supertest).
  • Verificação de lint (ESLint).
  • Checagem de tipagem com TypeScript (tsc).
  • Build do código com pnpm.

Na etapa de Entrega Contínua (CD), os artefatos são empacotados e preparados para deploy.

Scripts Principais (package.json)

  • pnpm start → Compila (tsc) e inicia o servidor (node dist/server.js).
  • pnpm test → Sobe ambiente de testes (NODE_ENV=testing), compila e executa Jest + Supertest.
  • pnpm lint → Roda ESLint.
  • pnpm prod → Build para produção e inicialização.

Fluxo de Armazenamento de Arquivos

  1. Usuário faz upload de um documento via API.
  2. O arquivo é enviado para o bucket S3.
  3. Apenas a key do arquivo é salva no Postgres.
  4. Para acessar o documento novamente, a aplicação gera uma URL assinada temporária (presigned URL).

Ferramentas de Desenvolvimento

  • pnpm: Gerenciador de pacotes rápido e eficiente.
  • dotenv: Carregamento das variáveis de ambiente a partir de arquivos .env.
  • typescript-eslint: Integração de ESLint com TypeScript para padronização de código.

Estrutura de Qualidade e Segurança

  • Autenticação: JWT.
  • Hash de senhas: Argon2.
  • Linting: ESLint configurado para boas práticas.
  • Documentação da API: Swagger acessível em rota dedicada.
  • Logs: Morgan, com possibilidade de integração a observabilidade no futuro.

2 - Banco de Dados

Visão Geral

O banco de dados da aplicação foi construído em PostgreSQL, garantindo robustez, escalabilidade e suporte a operações complexas. Ele é estruturado com diversas tabelas que representam as entidades do laboratório (estudantes, professores, técnicos, projetos, documentos, processos seletivos, permissões e contratos). O acesso ao banco é feito pelo ORM Sequelize, que abstrai queries SQL e facilita a manipulação de dados com segurança contra SQL Injection.

Tecnologias

  • PostgreSQL: SGBD relacional open source, usado como base de dados principal.
  • Sequelize: ORM para Node.js que gerencia migrações, associações, validações e abstração de queries SQL.

Migrações

O uso de migrações via Sequelize permite:

  • Controle de versão do banco.
  • Criação e atualização de tabelas de forma automatizada.
  • Rastreabilidade de mudanças na estrutura de dados.

Dump do Banco

O esquema completo do banco de dados pode ser acessado em: Esquema do banco de dados.

Estrutura de Tabelas

As principais tabelas são:

  • students → Armazena dados de bolsistas (informações pessoais, curso, GRR, renda, documentos).
  • professor → Registro de professores vinculados ao laboratório.
  • technician → Cadastro de técnicos.
  • clt → Trabalhadores contratados via CLT.
  • scholarship_type → Tipos de bolsas (nacionais ou não, valores, categorias).
  • student_scholarships → Relação entre estudantes e bolsas.
  • projects → Informações de projetos (datas, status, valor, integrantes).
  • partners → Parceiros vinculados ao laboratório.
  • partners_project → Relação entre parceiros e projetos.
  • documents → Documentos armazenados no S3, apenas a bucket_key é salva no banco.
  • document_permission → Relação entre documentos e permissões de acesso.
  • ps (processos seletivos) → Editais e informações de processos seletivos.
  • ps_form → Detalhes dos participantes em processos seletivos.
  • ps_relation → Relação entre participantes e processos seletivos.
  • ps_evaluation → Feedback dos processos seletivos.
  • user_system → Usuários do sistema, com suporte a autenticação, verificação de e-mail e permissões.
  • permissions → Lista de permissões disponíveis (admin, common, manager).
  • user_permissions → Relação entre usuários e permissões.
  • student_project_participation → Relação de estudantes com projetos.
  • professor_project_participation → Relação de professores com projetos.
  • technician_project_participation → Relação de técnicos com projetos.
  • clt_project_participation → Relação de CLTs com projetos.
  • partner_student → Relação entre parceiros e estudantes.
  • scholarship_ps_relation → Liga bolsas a processos seletivos.
  • student_contract → Contratos de estudantes.
  • student_contract_relation → Relação entre estudantes e contratos.
  • contract_amendments → Termos aditivos de contratos (armazenados no S3).
  • project_contract_amendments → Relação entre aditivos e projetos.
  • logs → Registro de logs de acesso (método, status_code, URL, IP, user_agent, etc.).

Permissões Padrão

O sistema garante que as permissões iniciais existam ao criar o banco:

  • admin
  • common
  • manager

Essas permissões são inseridas automaticamente caso ainda não existam.

Integração com S3

  • Os arquivos (como documentos e aditivos) não ficam armazenados no banco, apenas as referências (bucket keys).
  • O acesso real é feito via Amazon S3, garantindo escalabilidade e redução de sobrecarga no Postgres.

Conclusão

A modelagem foi feita para representar a realidade do laboratório, permitindo o gerenciamento de pessoas, projetos, bolsas, permissões, documentos e processos seletivos de forma completa. A combinação PostgreSQL + Sequelize + S3 garante robustez, segurança e flexibilidade para evoluir o sistema no futuro.

3 - Esquema do banco de dados

BEGIN;

CREATE TABLE IF NOT EXISTS students (
    id SERIAL, 
    name TEXT,
    init_date TIMESTAMP, -- data de ingresso no c3sl
    gender TEXT,
    skin_color TEXT, -- cor
    ethnicity TEXT, -- etnia
    grr TEXT UNIQUE,
    semester INT,
    email_ufpr TEXT,
    email_inf TEXT,
    phone TEXT,
    avg_fml_income INT, -- renda média familiar do bolsista (valor)
    email TEXT,
    is_pos BOOLEAN,
    is_capes BOOLEAN,
    pos_name TEXT,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    rg TEXT,
    "comprovanteDeMatricula" TEXT,
    ctps TEXT,
    "fotoCartao" TEXT,
    image TEXT,
    exited_at TIMESTAMP,
    is_trash BOOLEAN,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS professor (
    id SERIAL, 
    name TEXT,
    init_date TIMESTAMP, -- data de ingresso no c3sl
    gender TEXT,
    skin_color TEXT, -- cor
    ethnicity TEXT, -- etnia
    registration TEXT UNIQUE, -- número de registro de funcionário
    email TEXT,
    image TEXT,
    exited_at TIMESTAMP,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    is_trash BOOLEAN,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS technician (
    id SERIAL, 
    name TEXT,
    init_date TIMESTAMP, -- data de ingresso no c3sl
    gender TEXT,
    skin_color TEXT, -- cor
    ethnicity TEXT, -- etnia
    registration TEXT UNIQUE,
    email TEXT,
    image TEXT,
    exited_at TIMESTAMP,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    is_trash BOOLEAN,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS scholarship_type( -- tipo de bolsa
    id SERIAL,
    type TEXT UNIQUE, -- tipo de bolsa (bacharelado, mestrado, doutorado)
    category TEXT, -- categoria da bolsa (1-inicial; 2-2o ano C3SL; 3-3o ano curso; ...)
    amount INT, -- valor da bolsa
    is_national BOOLEAN, -- booleano
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    is_trash BOOLEAN,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS student_scholarships ( -- relaciona as tabelas student e scholarship_type
    id SERIAL,
    student_id INT,
    scholarship_type_id INT,
    starting_date TIMESTAMP DEFAULT now(),
    ending_date TIMESTAMP,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    FOREIGN KEY (student_id) REFERENCES students(id)  ON DELETE CASCADE,
    FOREIGN KEY (scholarship_type_id) REFERENCES scholarship_type(id) ON DELETE CASCADE,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS clt ( 
    id SERIAL, 
    name TEXT,
    init_date TIMESTAMP, -- data de ingresso no c3sl
    gender TEXT,
    skin_color TEXT,
    ethnicity TEXT,
    education_degree TEXT, -- escolaridade
    is_student BOOLEAN, 
    email TEXT,
    image TEXT,
    exited_at TIMESTAMP,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    is_trash BOOLEAN,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS projects ( 
    id SERIAL,
    name TEXT UNIQUE,
    starting_date TIMESTAMP, -- data de início do projeto
    ending_date TIMESTAMP, -- data de finalização do projeto. Valor nulo caso o projeto esteja em andamento
    status TEXT,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    is_trash BOOLEAN,
    value INT,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS documents ( -- tabela de documentos (guardados no S3)
    id SERIAL,
    name TEXT UNIQUE,
    type TEXT, -- tipo de documento (relatório, formulário, ...) 
    bucket_key TEXT UNIQUE, --nome/chave do arquivo no bucket
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    is_trash BOOLEAN,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS user_system ( 
    id SERIAL,
    name TEXT UNIQUE,
    email TEXT UNIQUE,
    password TEXT, 
    is_active BOOLEAN, -- booleano que define se o usuário está ativo
    register_date TIMESTAMP, -- data em que o cadastro foi feito
    "isEmailVerified" BOOLEAN,
    verification_date TIMESTAMP,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    last_login TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS ps_form ( -- relaciona as tabelas technician e projects
    id SERIAL,
    was_transfered BOOLEAN,
    is_email_verified BOOLEAN,
    name TEXT,
    grr TEXT,
    email TEXT,
    is_ufpr BOOLEAN,
    email_ufpr TEXT,
    email_inf TEXT,
    course TEXT,
    done_prog1 BOOLEAN,
    done_prog2 BOOLEAN,
    done_alg1 BOOLEAN,
    done_bd BOOLEAN,
    done_redes2 BOOLEAN,
    done_ihc BOOLEAN,
    semester INT,
    rg TEXT,
    motivation_letter TEXT,
    academic_background TEXT,
    curriculo TEXT,
    declaracao_nao_beneficiario TEXT,
    notes TEXT,
    ethnicity TEXT,
    skin_color TEXT,
    avg_fml_income INT,
    gender TEXT,
    is_pos BOOLEAN,
    is_capes BOOLEAN,
    pos_name TEXT,
    in_interview BOOLEAN,
    confirmed_presence BOOLEAN,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS ps ( -- relaciona as tabelas technician e projects
    id SERIAL,
    name TEXT UNIQUE,
    edital TEXT,
    starting_date TIMESTAMP, 
    ending_date TIMESTAMP, 
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS ps_relation ( -- relaciona as tabelas technician e projects
    id SERIAL,
    participant_id INT,
    ps_id INT, 
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    FOREIGN KEY (participant_id) REFERENCES ps_form(id) ON DELETE CASCADE,
    FOREIGN KEY (ps_id) REFERENCES ps(id) ON DELETE CASCADE, 
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS permissions (
    id SERIAL,
    name TEXT UNIQUE, -- nome da permissão do usuário
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS partners (
    id SERIAL,
    name TEXT UNIQUE,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    is_trash BOOLEAN,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS user_permissions ( -- relaciona as tabelas user_system e permissions
    id SERIAL, 
    id_permission INT,
    id_system_user INT,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    PRIMARY KEY (id),
    FOREIGN KEY (id_permission) REFERENCES permissions (id) ON DELETE CASCADE,
    FOREIGN KEY (id_system_user) REFERENCES user_system (id) ON DELETE CASCADE
);

-- cria as permissões para funcionar

-- Inserir a permissão 'admin' se não existir
INSERT INTO permissions (name, "createdAt", "updatedAt")
SELECT 'admin', NOW(), NOW()
WHERE NOT EXISTS (
    SELECT 1 FROM permissions WHERE name = 'admin'
);

-- Inserir a permissão 'common' se não existir
INSERT INTO permissions (name, "createdAt", "updatedAt")
SELECT 'common', NOW(), NOW()
WHERE NOT EXISTS (
    SELECT 1 FROM permissions WHERE name = 'common'
);

INSERT INTO permissions (name, "createdAt", "updatedAt")
SELECT 'manager', NOW(), NOW()
WHERE NOT EXISTS (
    SELECT 1 FROM permissions WHERE name = 'manager'
);


CREATE TABLE IF NOT EXISTS partners_project (
    id SERIAL,
    partner_id INT,
    project_id INT,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    FOREIGN KEY (partner_id) REFERENCES partners(id) ON DELETE CASCADE,
    FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS student_project_participation ( -- relaciona as tabelas student e projects
    id SERIAL,
    project_id INT,
    student_id INT,
    starting_date TIMESTAMP DEFAULT now(),
    ending_date TIMESTAMP,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE,
    FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS professor_project_participation ( -- relaciona as tabelas professor e projects
    id SERIAL,
    project_id INT,
    professor_id INT,
    starting_date TIMESTAMP DEFAULT now(),
    ending_date TIMESTAMP,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    FOREIGN KEY (professor_id) REFERENCES professor(id) ON DELETE CASCADE,
    FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS technician_project_participation ( -- relaciona as tabelas technician e projects
    id SERIAL,
    project_id INT,
    technician_id INT,
    starting_date TIMESTAMP DEFAULT now(),
    ending_date TIMESTAMP,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    FOREIGN KEY (technician_id) REFERENCES technician(id) ON DELETE CASCADE,
    FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS clt_project_participation ( -- relaciona as tabelas clt e projects
    id SERIAL,
    project_id INT,
    clt_id INT,
    starting_date TIMESTAMP DEFAULT now(),
    ending_date TIMESTAMP,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    FOREIGN KEY (clt_id) REFERENCES clt(id) ON DELETE CASCADE,
    FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS partner_student (
    id SERIAL,
    partner_id INT,
    student_id INT,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    FOREIGN KEY (partner_id) REFERENCES partners(id) ON DELETE CASCADE,
    FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS scholarhip_ps_relation (
    id SERIAL,
    ps_id INT,
    scholarship_id INT,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    FOREIGN KEY (ps_id) REFERENCES ps(id) ON DELETE CASCADE,
    FOREIGN KEY (scholarship_id) REFERENCES scholarship_type(id) ON DELETE CASCADE,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS ps_evaluation (
    id SERIAL,
    ps_name TEXT,
    general_experience TEXT,
    clearness TEXT,
    respect TEXT,
    information_clearness INT,
    information_clearness_comment TEXT,
    ease INT,
    ease_comment TEXT,
    communication INT,
    communication_comment TEXT,
    time_spent INT,
    time_spent_comment TEXT,
    transparency INT,
    transparency_comment TEXT,
    liked_most TEXT,
    improvement_sugestion TEXT,
    confusing TEXT,
    comment TEXT,
    consent BOOLEAN,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS document_permission (
    id SERIAL,
    permission_id INT,
    document_id INT,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE,
    FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS student_financing_project (
    id SERIAL,
    financing_project_id INT,
    student_id INT,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    FOREIGN KEY (financing_project_id) REFERENCES projects(id) ON DELETE CASCADE,
    FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS logs (
  id SERIAL,
  ip TEXT,
  method TEXT,
  url TEXT,
  status_code INT,
  size INT,
  referer TEXT,
  answer_bytes INT,
  user_agent TEXT,
  "createdAt" TIMESTAMP DEFAULT now() DEFAULT now(),
  "updatedAt" TIMESTAMP DEFAULT now() DEFAULT now(),
  PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS student_contract (
  id SERIAL,
  starting_date TIMESTAMP,
  ending_date TIMESTAMP,
  signed_date TIMESTAMP, -- data que foi assinado, se nao foi assinado ainda é nulo
  contract TEXT,
  is_trash BOOLEAN DEFAULT FALSE,
  "createdAt" TIMESTAMP DEFAULT now(),
  "updatedAt" TIMESTAMP DEFAULT now(),
  PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS student_contract_relation (
  id SERIAL,
  student_id INT,
  contract_id INT,
  FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE,
  FOREIGN KEY (contract_id) REFERENCES student_contract(id) ON DELETE CASCADE,
  "createdAt" TIMESTAMP DEFAULT now(),
  "updatedAt" TIMESTAMP DEFAULT now(),
  PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS contract_amendments ( -- tabela de termos aditivos do projeto (guardados no S3)
    id SERIAL,
    name TEXT UNIQUE,
    project_ending_date DATE, -- novo prazo do projeto
    bucket_key TEXT UNIQUE, --nome/chave do arquivo no bucket
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    is_trash BOOLEAN,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS project_contract_amendments ( -- tabela de relação entre termos aditivos e projeto
    id SERIAL,
    project_id INT,
    contract_id INT UNIQUE, -- 1 : n entre projeto e contrato (cada projeto pode ter varios contratos, mas um contrato so pode ser ligado a um projeto)
    FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
    FOREIGN KEY (contract_id) REFERENCES contract_amendments(id) ON DELETE CASCADE,
    "createdAt" TIMESTAMP DEFAULT now(),
    "updatedAt" TIMESTAMP DEFAULT now(),
    PRIMARY KEY (id)
);

COMMIT;

4 - Frontend

Visão Geral

O frontend da aplicação foi desenvolvido com Next.js, aproveitando suas funcionalidades de Server-Side Rendering (SSR) e Static Site Generation (SSG) para melhor performance e SEO. A interface do usuário é construída com React e estilizada com TailwindCSS em conjunto com a biblioteca de componentes shadcn/ui, garantindo consistência visual, rapidez no desenvolvimento e uma experiência moderna e responsiva.

Tecnologias Utilizadas

  • Next.js: Framework React utilizado para criação das páginas, rotas e otimizações de performance.
  • React: Biblioteca para construção da interface do usuário.
  • TailwindCSS + tailwind-merge + tailwindcss-animate: Framework utilitário para estilização, com suporte a animações e composição de classes.
  • shadcn/ui (Radix UI + Lucide Icons): Conjunto de componentes acessíveis e prontos para uso, como diálogos, formulários e ícones.
  • Axios: Cliente HTTP para comunicação com o backend.
  • Framer Motion: Biblioteca para animações fluidas e interativas.
  • Recharts: Gráficos para visualização de dados.
  • React Day Picker + date-fns: Manipulação e seleção de datas.
  • React Dropzone + @files-ui/react: Upload de arquivos e manipulação de inputs.
  • File Saver: Download de arquivos direto pelo navegador.

Páginas

  • Login (/): Tela para autenticação de usuários.
  • Cadastro (/): Registro de novos usuários na plataforma.
  • Home (/home): Página principal com acesso centralizado às funcionalidades do sistema.
  • Tabelas (/home): Exibição de entidades do laboratório (bolsistas, professores, documentos).
  • Inserção (/home): Formulário para adicionar novas entidades.
  • Dashboard Processo Seletivo (/home): Exibição dos processos seletivos ativos e finalizados.
  • Detalhes do Processo Seletivo (/home): Lista de participantes e submissões, com possibilidade de apagar dados sensíveis após finalização.
  • Detalhes do Projeto (/home): Mostra os integrantes do projeto, com opção de inserir ou remover membros.
  • Detalhes de Entidade (/home): Exibição detalhada de uma entidade.
  • Edição de Entidade (/home): Formulário para edição, restrito a administradores.
  • Processo Seletivo (/processoseletivo): Tela para submissão de candidaturas pelos participantes.

CI/CD

O pipeline de Integração Contínua (CI) e Entrega Contínua (CD) do frontend garante qualidade e estabilidade a cada commit ou pull request:

  • Execução de testes automatizados (ex.: Jest, Cypress).
  • Validação de lint com ESLint.
  • Checagem de build com Next.js para prevenir erros de configuração ou dependências.

Esse processo assegura que a aplicação seja confiável, seguindo padrões de código e pronta para deploy em produção.

Scripts Principais (package.json)

  • pnpm dev → Inicia o servidor de desenvolvimento Next.js.
  • pnpm build → Gera o build otimizado para produção.
  • pnpm start → Inicia a aplicação em modo de produção.
  • pnpm lint → Roda o ESLint para verificação de estilo e boas práticas.
  • pnpm prod → Cria a imagem Docker e roda o container localmente.

Estrutura de Qualidade e Usabilidade

  • UI consistente: shadcn/ui + TailwindCSS garantem padronização visual.
  • Acessibilidade: Radix UI assegura que os componentes sigam boas práticas de acessibilidade.
  • Responsividade: Layouts otimizados para diferentes dispositivos.
  • Experiência do Usuário: Animações com Framer Motion e feedback visual imediato.