Disciplina: ESW424 - Prática de Engenharia de Software (2025/02)
Professor: João Dionisio Paraiba
Aluno: Marques Vinícius Melo Martins
O AgroMark é um sistema administrativo-financeiro voltado ao agronegócio. Na Etapa 1 entregamos o fluxo de upload de notas fiscais (PDF) e extração estruturada via Google Gemini. A Etapa 2 (peso 60%) adiciona persistência relacional com PostgreSQL + Prisma, verificação automática de cadastros e lançamento de movimentos financeiros com parcelas, classificações e controle de status (inativar/reativar).
- Backend: Node.js, Express, Prisma ORM
- Banco: PostgreSQL (Docker/Compose)
- Frontend: React (CRA) + Tailwind CSS
- IA: Google Gemini 2.5 Flash
- Outros: Multer/PDF-Parse (upload NF), Helmet, CORS, Rate limiting
- Infra Etapa 2: Dockerfiles (backend/frontend) + docker-compose para backend, frontend e banco
- Upload + Extração (Etapa 1 mantida): upload do PDF, extração formatada/JSON via Gemini.
- Verificação em Banco: botão “Verificar no Banco” consulta Postgres e exibe badges “EXISTE — ID” ou “NÃO EXISTE” para fornecedor, faturado e classificação de despesa.
- Criação Condicional: botão “Criar/Atualizar e Lançar” cria cadastros faltantes, registra movimento APAGAR, parcelas e classificações (N:N) em transação Prisma.
- Soft-delete por status: Pessoas e classificações possuem
status(ATIVO/INATIVO). Endpoints PATCH para inativar/reativar. - Seeds: Classificações padrão da Etapa 1 pré-cadastradas.
- Validações e rate limiting: Normalização/validação de CPF/CNPJ, retorno 400/409 adequado, proteção em
/api/create/*e/api/movimentos. - Dockerização completa: Containers independentes para Postgres, backend (com
prisma migrate deployno start) e frontend (build estático via Nginx).
- Node.js 18+
- PostgreSQL (local ou dentro do Docker Compose)
- Git
# Clone o repositório
git clone https://github.com/marquesvinicius/agromark.git
cd agromark
# Instale dependências
npm --prefix backend install
npm --prefix frontend installCrie backend/.env com base em backend/env.example:
NODE_ENV=development
PORT=5000
# Ajuste o host conforme sua instalação do Postgres
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/agromark?schema=public
GEMINI_API_KEY=SUA_CHAVE_GEMINI_AQUI
MAX_FILE_SIZE=10485760Atenção: a chave da Gemini não deve ser utilizada em health-checks. O endpoint
/api/readiness-llmé separado, com cache e executado apenas manualmente.
# Gerar cliente Prisma
dnpm --prefix backend run prisma:generate
# Criar/aplicar migrações (modo dev)
npm --prefix backend run prisma:migrate
# Inserir seeds (classificações de despesa)
npm --prefix backend run prisma:seednpm --prefix backend run dev # Backend → http://localhost:5000
npm --prefix frontend start # Frontend → http://localhost:3000npm --prefix backend run prisma:migrate→ cria/aplica migrações em dev.npm --prefix backend run prisma:seed→ executa seeds.npm --prefix backend run prisma:generate→ atualiza client após alterar schema.npm --prefix backend run prisma:deploy→ aplica migrações em produção.npx prisma studio --schema backend/prisma/schema.prisma→ abre Prisma Studio.
Ideal para correção do professor.
- Instale Docker Desktop: https://www.docker.com/products/docker-desktop/
- Crie
backend/.env: copiebackend/env.example, editeGEMINI_API_KEY. - Suba os containers:
docker compose up --build -d- Acesse:
- Frontend: http://localhost:3000
- Backend/API: http://localhost:5000/api
postgres: banco com volume persistentepgdatae healthcheck.backend: Express + Prisma; rodaprisma migrate deployautomaticamente no start. Incluiapp.set('trust proxy', 1)para funcionar atrás do Nginx do frontend.frontend: build React servido via Nginx; proxy de todas as chamadas/apipara o backend (Docker). O build do React recebeREACT_APP_API_URL=/apivia ARG.
- Subir:
docker compose up --build -d - Parar:
docker compose down - Parar e remover dados:
docker compose down -v - Ver logs:
docker compose logs -f backend - Prisma Studio (via container backend):
docker compose exec backend npx prisma studio
- GUI (DBeaver/TablePlus)
- Host:
localhost - Port:
5432 - Database:
agromark - User:
postgres - Password:
postgres
- Host:
- CLI dentro do container
Comandos no psql:
docker compose exec postgres psql -U postgres -d agromark\dt,SELECT COUNT(*) FROM pessoa;,\q
- CPF/CNPJ (acadêmico): validação relaxada (apenas quantidade de dígitos) para permitir documentos genéricos (ex.:
999.999.999-99). - Classificação: se não vier descrição, o backend assume
OUTROS. - Lançamento de movimentos (
POST /api/movimentos):- Bloqueio de duplicidade por NF + fornecedor →
409 MOVIMENTO_JA_EXISTEcom mensagem amigável. - Identificação de parcelas é única. Agora utiliza padrão
numeroNF-<idMovimento>-parcela-XXpara evitar colisões históricas. - Caso ainda ocorra colisão, o backend adiciona sufixo único de segurança.
- Bloqueio de duplicidade por NF + fornecedor →
- Exclusão de movimentos:
DELETE /api/movimentos/:idremove movimento, parcelas e vínculos em transação.
- Página “Movimentos”: adicionada coluna Ações com botão de lixeira (cores do tema) para exclusão. Após excluir, a lista é recarregada.
- Página principal: fluxo “Verificar no Banco” ➜ “Registrar Movimento” com toasts e mensagens do backend (inclui 409 amigável quando repetido).
- CORS: produção aceita domínios
.vercel.appe os domínios listados noserver.js; desenvolvimento aceitahttp://localhost:3000. - Rate limiting: health-check de plataforma foi isolado – a rota
/api/healthfica fora do rate limiter global para evitar429em health checks. - Proxy/Nginx (frontend Docker): todo request à API deve ir para
/api/.... O frontend usaREACT_APP_API_URLdefinido como/apino build do Docker. - Se ver
ValidationError: The 'X-Forwarded-For' header...habiliteapp.set('trust proxy', 1)(já aplicado).
- Importar o repositório e definir Root Directory:
frontend. - Variáveis de ambiente:
REACT_APP_API_URL: URL pública do backend +/api, ex.:https://agromark-backend.onrender.com/api
- Build Command/Output: deixe nos padrões da Vercel (CRA) — sem override.
- Criar banco PostgreSQL gerenciado e copiar a Internal Database URL.
- Criar Web Service do backend com Root Directory
backend(Dockerfile detectado). - Variáveis de ambiente:
DATABASE_URL= Internal Database URLGEMINI_API_KEY
- Build/Deploy:
- Build: padrão (usa Dockerfile do backend) e aplica
npx prisma migrate deploydurante o start.
- Build: padrão (usa Dockerfile do backend) e aplica
- Seed (plano gratuito, sem jobs):
- Temporariamente altere o Start Command para
npx prisma db seed && npm start. - Aguarde o deploy, verifique os dados, e retorne o Start Command para
npm start.
- Temporariamente altere o Start Command para
- 404 ao chamar
/healthna Vercel: lembre-se de setarREACT_APP_API_URLcom/apiao final no valor. - 429 na Render (health): a rota
/api/healthjá está fora do rate limiter. - 405 no Docker ao fazer upload: verifique
frontend/nginx.conf(proxy de/api/para o backend) e reconstrução comdocker compose up --build.
- Frontend (Vercel/Docker build):
REACT_APP_API_URL(Vercel:https://.../api, Docker:/apivia ARG no Dockerfile do frontend)
- Backend (Render/Docker):
DATABASE_URLGEMINI_API_KEYPORT,MAX_FILE_SIZE(opcional)
Todos retornam JSON.
curl -X POST http://localhost:5000/api/check/all \
-H "Content-Type: application/json" \
-d '{
"fornecedor": {"cnpj":"12.345.678/0001-90","razaoSocial":"IGUAÇU MAQUINAS LTDA"},
"faturado": {"cpf":"999.999.999-99","nomeCompleto":"BELTRANO DA SILVA"},
"classificacaoDespesa":"MANUTENÇÃO E OPERAÇÃO",
"numeroNota":"000123456","dataEmissao":"2025-01-15",
"parcelas":[{"dataVencimento":"2025-02-15","valor":1250.00}],
"valorTotal":1250.00,
"itensDescricao":["Óleo diesel"]
}'| Método | Endpoint | Descrição |
|---|---|---|
| POST | /api/check/fornecedor |
Verifica fornecedor por CNPJ |
| POST | /api/check/faturado |
Verifica faturado por CPF/CNPJ |
| POST | /api/check/despesa |
Verifica classificação de despesa |
| POST | /api/create/necessary |
Cria fornecedor/faturado/classificação se não existirem |
| POST | /api/movimentos |
Cria movimento, parcelas e vínculos N:N (transação Prisma) |
| PATCH | /api/pessoas/:id/inativar |
Marca pessoa como INATIVA |
| PATCH | /api/pessoas/:id/reativar |
Marca pessoa como ATIVA |
| PATCH | /api/classificacoes/:id/inativar |
Inativa classificação |
| PATCH | /api/classificacoes/:id/reativar |
Reativa classificação |
| GET | /api/upload/categories |
Lista classificações de despesa ativas |
| GET | /api/health |
Health check leve (sem IA) |
| GET | /api/readiness-llm |
Teste manual/cacheado da LLM |
Pessoa: tipos FORNECEDOR/FATURADO/CLIENTE; documento único por tipo; status ATIVO/INATIVO.Classificacao: tipos DESPESA/RECEITA; descrição única por tipo; status.MovimentoContas: tipo APAGAR/ARECEBER (usamos APAGAR); ligação com fornecedor/faturado; valor total; status; N:N com classificações.ParcelaContas: 1..N parcelas por movimento; identificação única (numeroNF-parcela-NN); controle de saldo e status da parcela.MovimentoClassificacao: tabela de junção (N:N) com chave composta.
Seeds inserem as classificações utilizadas na Etapa 1.
- Layout da Etapa 1 mantido.
- Novos botões:
- Verificar no Banco: chama
/api/check/alle exibe badges “EXISTE — ID” ou “NÃO EXISTE”. - Criar/Atualizar e Lançar: chama
/api/create/necessaryseguido de/api/movimentos; exibe toast verde “Registro lançado com sucesso (Movimento #ID)”.
- Verificar no Banco: chama
- Fallbacks para campos ausentes: UI orienta revisar JSON antes de lançar.
-
npm run devcontinua funcional (upload + extração). -
/api/check/allretorna EXISTE/NÃO EXISTE com IDs. -
/api/create/necessarycria cadastros ausentes. -
/api/movimentosregistra movimento + parcelas + classificações em transação. - PATCH (inativar/reativar) funcionando.
- Seeds aplicados.
- Health sem IA; readiness LLM separado/cacheado.
- UI mostra blocos exigidos + toast de sucesso.
-
docker compose up --buildsobe Postgres + Backend + Front.
agromark/
├── backend/
│ ├── prisma/
│ │ ├── schema.prisma
│ │ └── seed.js
│ ├── routes/
│ │ ├── check.js
│ │ ├── create.js
│ │ ├── movimentos.js
│ │ ├── pessoas.js
│ │ └── classificacoes.js
│ ├── utils/
│ │ ├── documentUtils.js
│ │ └── prismaClient.js
│ ├── middleware/rateLimiter.js
│ ├── config.js
│ ├── server.js
│ └── env.example
├── frontend/
│ ├── src/components/ResultsDisplay.js
│ ├── src/services/apiService.js
│ ├── Dockerfile
│ ├── nginx.conf
│ └── ...
├── docker-compose.yml
├── README.md
└── docs/
- Frontend (React): Vercel → https://agromark-esw424.vercel.app
- Backend (Node.js): Render → https://agromark-backend.onrender.com/api
Configure GEMINI_API_KEY, DATABASE_URL e afins nas plataformas de deploy.
Projeto acadêmico de Marques Vinícius Melo Martins para ESW424 – Prática de Engenharia de Software.