Pipeline de extração de documentos com LLM. Recebe um documento (PDF/imagem), classifica o tipo, extrai dados estruturados com LLM, valida a saída e expõe tudo via API documentada — com fila, revisão humana e testes. Produção em miniatura, não um script.
Status: 🚧 etapas 1–3 concluídas + página de demo no ar em
/(upload com drag & drop, polling de status, JSON extraído com confidences e métricas). Falta fechar a etapa 4: deploy — ver Roteiro.
flowchart LR
U[Upload API] --> S[(MinIO / S3)]
U --> Q[[Fila: RabbitMQ]]
Q --> W[Worker]
W --> C[1. Classifica<br/>LLM: saída enum]
W --> E[2. Extrai<br/>LLM: JSON estruturado]
W --> V[3. Valida<br/>Zod — reprova → retry c/ feedback]
W --> P[(Postgres via Prisma)]
API[GET /documents/:id] --> P
R[POST /documents/:id/review] --> P
- API (
apps/api): HTTP + Swagger. Recebe upload, enfileira, consulta status/resultado. - Worker (
apps/worker): consome a fila e roda o pipeline (classifica → extrai → valida → persiste). - libs/: código compartilhado atrás de portas isoladas —
prisma,queue(trocável RabbitMQ→SQS),storage(MinIO→S3).
NestJS · Prisma + PostgreSQL · RabbitMQ · MinIO (S3-compatible) · OpenAI (structured outputs) · Zod · Docker Compose · pnpm.
- Node 22+ (há um
.nvmrc;nvm use) - pnpm (
corepack enable pnpm) - Docker + Docker Compose
# 1. Infra local (Postgres, RabbitMQ, MinIO)
docker compose up -d
# 2. Dependências
pnpm install
# 3. Variáveis de ambiente
cp .env.example .env # defina OPENAI_API_KEY — sem ela o worker boota, mas
# todo documento falha com erro explicativo
# 4. Gera o Prisma Client
pnpm prisma:generate
# 5. Builda o front-end da demo (React/Vite → apps/web/dist, servido pela API)
pnpm build:web
# 6. Sobe a API (demo em http://localhost:3000, Swagger em /api)
pnpm start:dev
# 7. (outro terminal) sobe o worker
pnpm start:worker:dev
# Desenvolvimento do front com HMR: pnpm dev:web (http://localhost:5173, proxy pra API)Endpoints de infra:
| Serviço | URL |
|---|---|
| Demo (upload + status) | http://localhost:3000 |
| API / Swagger | http://localhost:3000/api |
| Health | http://localhost:3000/health |
| RabbitMQ (painel) | http://localhost:15672 — docpipe / docpipe |
| MinIO (console) | http://localhost:9001 — docpipe / docpipe123 |
Sem autenticação — é uma demo; em produção entraria auth de verdade na borda.
| Rota | O que faz |
|---|---|
POST /documents |
Upload (multipart, campo file: PDF/JPEG/PNG/WebP até 10 MB) → armazena no MinIO, registra no Postgres e enfileira. Idempotente por sha256: reenviar o mesmo arquivo devolve o registro existente com deduplicated: true. |
GET /documents |
Histórico (mais recentes primeiro; ?limit=1–100, default 20), com extração incluída. |
GET /documents/:id |
Status (QUEUED → PROCESSING → DONE/FAILED), tipo classificado, dados extraídos (extraction.data), confidences por atributo, flag needsReview, tokens usados e motivo de falha (error). |
POST /documents/:id/review |
Correção humana: valida o body contra o mesmo schema Zod da extração, guarda o par original/corrigido (auditável) e limpa o needsReview. |
GET /metrics |
Documentos por status/tipo, pendências de revisão, tokens totais e custo estimado (USD). |
curl -F "file=@nota.pdf" http://localhost:3000/documents
# → {"id":"…","status":"QUEUED","deduplicated":false,…}docpipe/
├─ apps/
│ ├─ api/ # HTTP + Swagger (serve o build do web na raiz)
│ ├─ web/ # front-end da demo (React + Vite + TS)
│ └─ worker/ # consumidor da fila (pipeline)
├─ libs/
│ ├─ contracts/ # schemas zod: mensagens da fila + classificação + extração por tipo
│ ├─ llm/ # adapter LLM atrás de porta (OpenAI structured outputs)
│ ├─ prisma/ # PrismaModule/Service
│ ├─ queue/ # adapter de fila atrás de porta (RabbitMQ → SQS)
│ └─ storage/ # adapter de storage atrás de porta (MinIO → S3)
├─ prisma/ # schema + migrations
├─ docker-compose.yml
└─ .github/workflows/ci.yml
| Comando | O que faz |
|---|---|
pnpm start:dev |
API em watch mode |
pnpm start:worker:dev |
Worker em watch mode |
pnpm dev:web |
Front-end com HMR (Vite, proxy pra API) |
pnpm build |
Compila api + worker |
pnpm build:web |
Typecheck + build do front-end |
pnpm lint |
ESLint (--fix) |
pnpm test |
Testes unitários (Jest) |
pnpm eval |
Roda o golden set contra o pipeline real e mede acurácia (requer API+worker+OPENAI_API_KEY) |
pnpm prisma:migrate |
Cria/aplica migration |
pnpm prisma:studio |
UI do banco |
- Saída estruturada + validação + retry ✅ — o LLM responde sob JSON Schema
strict (structured outputs); a resposta ainda passa pelo Zod do tipo
(validação semântica: datas ISO, moeda ISO 4217). Reprovou → reenvia uma
vez com os erros de validação no prompt; reprovou de novo →
FAILED. Nada de parsear texto solto. - Idempotência ✅ — sha256 do arquivo como chave única (com tratamento da
corrida P2002); redelivery da fila também é idempotente (doc
DONEnão reprocessa). - Custo/observabilidade ✅ — tokens de prompt/completion somados
(classificação + extração) persistidos por documento;
GET /metricsagrega contagens, tokens e custo estimado (preços por 1M configuráveis). - Confiança ✅ — o LLM devolve
confidence(0–1) por atributo; qualquer uma abaixo deCONFIDENCE_THRESHOLD(default 0.7) →needsReview: true, limpo pela revisão humana. - Golden set ✅ — 12 documentos sintéticos (sem dados reais) em
eval/golden-set.json;
pnpm evalgera os PDFs, roda o pipeline real e mede a acurácia campo a campo. - Schema pro LLM ≠ schema de validação — o structured output vai sem regex/formats (suporte irregular no modo strict); a validação semântica (datas ISO, moeda ISO 4217) roda no nosso Zod — e é a reprovação dela que alimenta o retry com feedback.
Batching de requisições ao LLM · cache de resultados por hash · DLQ para falhas · multi-tenant + auth real · storage/fila gerenciados (S3 + SQS). (discussão, não implementado na v1)
| Etapa | Entrega | Status |
|---|---|---|
| 0 | Setup: monorepo + Compose + API/worker bootados + Swagger | ✅ |
| 1 | Upload → S3 → fila (idempotência, worker consumindo, testes unit) | ✅ |
| 2 | Worker: classificação + extração + Zod + retry c/ feedback + persistência (recibo ponta a ponta) | ✅ |
| 3 | Outros 2 tipos, confidence/needs_review, review, /metrics, golden set + eval |
✅ |
| 4 | Página de demo ✅ · README com GIF ✅ · badge CI ✅ · deploy (Railway/Fly.io) ⬜ | 🔶 |
MIT
