Initial commit: DocuAgro - Plataforma EUDR

This commit is contained in:
bigtux
2026-02-10 15:46:03 -03:00
commit a419ac97e7
33 changed files with 10548 additions and 0 deletions

24
.env.example Normal file
View File

@@ -0,0 +1,24 @@
# === DocuAgro - Configuração ===
# Bot Telegram
TELEGRAM_BOT_TOKEN=seu_token_aqui
# OpenAI API (gpt-4o-mini)
OPENAI_API_KEY=sua_chave_aqui
OPENAI_MODEL=gpt-4o-mini
# Servidor
PORT=3100
PANEL_PORT=3101
NODE_ENV=development
# Banco de dados
DB_PATH=./data/docuagro.db
# Upload de arquivos
UPLOAD_DIR=./uploads
MAX_FILE_SIZE=20971520
# Cooperativa padrão (para MVP)
COOP_NAME=Cooperativa Piloto
COOP_ID=coop_001

11
.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
node_modules/
.next/
dist/
.env
.env.local
.env*.local
*.log
.DS_Store
coverage/
.turbo/
*.tsbuildinfo

217
README.md Normal file
View File

@@ -0,0 +1,217 @@
# 🌱 DocuAgro
**Compliance do produtor, na palma da mão.**
Bot Telegram + Painel Web para coleta, validação e organização de documentação de produtores rurais para compliance EUDR (Regulamento da União Europeia contra Desmatamento).
---
## 📋 O que é
O DocuAgro resolve o problema da "última milha" do compliance EUDR: coletar, organizar e validar a documentação de cada produtor individual e entregar um dossiê padronizado para cooperativas e tradings.
### Como funciona
1. **Produtor** interage via **Bot Telegram** — envia documentos, tira dúvidas
2. **IA (gpt-4o-mini)** guia a coleta, valida documentos, orienta correções
3. **OCR** extrai dados automaticamente de fotos e PDFs
4. **Dossiê PDF** é gerado automaticamente quando todos os documentos estão prontos
5. **Cooperativa** acompanha tudo pelo **Painel Web**
---
## 📄 Documentos Coletados
| # | Documento | Validação |
|---|-----------|-----------|
| 1 | **CAR** (Cadastro Ambiental Rural) | Número SICAR + OCR |
| 2 | **CCIR** (Certificado Cadastro Imóvel Rural) | OCR + código INCRA |
| 3 | **ITR** (Imposto Territorial Rural) | OCR + CPF/CNPJ |
| 4 | **Georreferenciamento** | Coordenadas GPS |
| 5 | **Licença Ambiental** | OCR + validade |
| 6 | **Contrato de Arrendamento** | OCR (se aplicável) |
| 7 | **Nota Fiscal de Venda** | OCR + dados |
| 8 | **Declaração de Não Desmatamento** | Gerada automaticamente |
---
## 🛠 Stack Técnica
- **Bot:** Node.js + [Telegraf](https://telegraf.js.org/)
- **IA:** OpenAI API (gpt-4o-mini)
- **OCR:** Tesseract.js
- **PDF:** PDFKit
- **Banco:** SQLite (via better-sqlite3)
- **API:** Express.js
- **Painel:** HTML/CSS/JS puro (sem framework)
---
## 🚀 Instalação
### Pré-requisitos
- Node.js 18+
- Token do Bot Telegram (via [@BotFather](https://t.me/BotFather))
- Chave API da OpenAI
### Setup
```bash
# Clonar repositório
git clone http://137.184.77.7:3000/bigtux/docuagro.git
cd docuagro
# Instalar dependências
npm install
# Configurar variáveis de ambiente
cp .env.example .env
# Editar .env com seus tokens
# Criar banco de dados
npm run setup
# Iniciar (bot + API + painel)
npm start
```
### Modo desenvolvimento
```bash
npm run dev # Usa nodemon para auto-reload
```
---
## ⚙️ Configuração (.env)
```env
# Bot Telegram
TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
# OpenAI API
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o-mini
# Servidor
PORT=3100
# Banco de dados
DB_PATH=./data/docuagro.db
# Upload
UPLOAD_DIR=./uploads
```
---
## 📱 Comandos do Bot
| Comando | Descrição |
|---------|-----------|
| `/start` | Iniciar cadastro |
| `/status` | Ver status dos documentos |
| `/dossie` | Gerar dossiê PDF |
| `/pular` | Pular documento atual |
| `/ajuda` | Menu de ajuda |
---
## 🌐 Painel Web
Acesse `http://localhost:3100` para o painel da cooperativa:
- **Dashboard** com estatísticas em tempo real
- **Lista de produtores** com status de compliance
- **Busca** por nome, CPF, propriedade ou município
- **Detalhes** de cada produtor e seus documentos
- **Download** de dossiê PDF
- **Exportação** CSV para sistemas externos
---
## 📡 API REST
| Endpoint | Método | Descrição |
|----------|--------|-----------|
| `/api/health` | GET | Health check |
| `/api/dashboard` | GET | Estatísticas gerais |
| `/api/produtores` | GET | Listar produtores |
| `/api/produtores/:id` | GET | Detalhe do produtor |
| `/api/produtores/:id/dossie` | POST | Gerar dossiê PDF |
| `/api/dossie/download/:arquivo` | GET | Download do dossiê |
| `/api/exportar/csv` | GET | Exportar CSV |
---
## 📁 Estrutura do Projeto
```
docuagro/
├── src/
│ ├── index.js # Entry point
│ ├── setup-db.js # Criação do banco de dados
│ ├── bot/
│ │ └── telegram-bot.js # Bot Telegram (Telegraf)
│ ├── api/
│ │ └── routes.js # API REST (Express)
│ ├── services/
│ │ ├── database.js # Operações de banco (SQLite)
│ │ ├── ai-service.js # Integração OpenAI
│ │ ├── ocr-service.js # OCR (Tesseract.js)
│ │ ├── pdf-service.js # Geração de dossiê PDF
│ │ └── system-prompt.js # Prompt da IA especialista EUDR
│ └── utils/
├── public/
│ └── index.html # Painel web da cooperativa
├── data/ # Banco SQLite
├── uploads/ # Documentos dos produtores
├── docs/ # Documentação adicional
├── .env.example # Template de configuração
├── .gitignore
├── package.json
└── README.md
```
---
## 🔒 Segurança
- Documentos armazenados localmente (não em cloud pública)
- Cada produtor tem diretório isolado de uploads
- API sem autenticação no MVP (adicionar antes de produção!)
- CPF/CNPJ armazenados para identificação
### TODO para produção:
- [ ] Autenticação JWT no painel
- [ ] HTTPS obrigatório
- [ ] Rate limiting na API
- [ ] Criptografia de dados sensíveis
- [ ] Backup automático do banco
---
## 📊 Contexto EUDR
O **Regulamento (UE) 2023/1115** proíbe a importação na UE de commodities produzidas em áreas desmatadas após 31/12/2020. Afeta:
- 🫘 Soja
- ☕ Café
- 🍫 Cacau
- 🌴 Óleo de palma
- 🌳 Madeira
- 🐄 Gado
- 🔧 Borracha
Produtores brasileiros que exportam precisam comprovar geolocalização, ausência de desmatamento e conformidade ambiental.
---
## 📝 Licença
MIT
---
**DocuAgro** — Feito com 🌱 para o agro brasileiro.

0
data/.gitkeep Normal file
View File

BIN
data/docuagro.db Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,655 @@
# 📋 DocuAgro — Guia Completo do Sistema
### Para Equipe Comercial / Vendas
> **Versão:** 1.0 | **Data:** Fevereiro 2026
> **Contato técnico:** m171c0@gmail.com
---
## 📌 ÍNDICE
1. [O Problema: EUDR](#1-o-problema-eudr)
2. [A Solução: DocuAgro](#2-a-solução-docuagro)
3. [Como Funciona (Passo a Passo)](#3-como-funciona-passo-a-passo)
4. [O Bot Telegram (Lado do Produtor)](#4-o-bot-telegram-lado-do-produtor)
5. [O Painel Web (Lado da Cooperativa)](#5-o-painel-web-lado-da-cooperativa)
6. [Inteligência Artificial](#6-inteligência-artificial)
7. [Documentos Coletados](#7-documentos-coletados)
8. [Dossiê PDF Automatizado](#8-dossiê-pdf-automatizado)
9. [Arquitetura Técnica](#9-arquitetura-técnica)
10. [Modelo de Negócio e Preços](#10-modelo-de-negócio-e-preços)
11. [Público-Alvo](#11-público-alvo)
12. [Como Fazer uma Demo](#12-como-fazer-uma-demo)
13. [Perguntas Frequentes (FAQ)](#13-perguntas-frequentes-faq)
14. [Diferenciais Competitivos](#14-diferenciais-competitivos)
15. [Roadmap / Próximos Passos](#15-roadmap--próximos-passos)
---
## 1. O Problema: EUDR
### O que é o EUDR?
O **Regulamento (UE) 2023/1115** — conhecido como **EUDR** (European Union Deforestation Regulation) — é uma lei da União Europeia que **proíbe a importação de commodities** produzidas em áreas desmatadas após 31 de dezembro de 2020.
### Quem é afetado?
Produtores brasileiros que exportam (diretamente ou via cooperativa/trading) as seguintes commodities:
| Commodity | Principais Estados |
|-----------|-------------------|
| 🫘 Soja | MT, PR, GO, MS, BA |
| ☕ Café | MG, SP, ES, PR, BA |
| 🍫 Cacau | BA, PA, RO |
| 🐄 Gado | MT, GO, PA, MS, MG |
| 🌴 Óleo de Palma | PA, AM |
| 🌳 Madeira | PA, AM, MT, RO |
| 🔧 Borracha | SP, BA, MT |
> ⚠️ **Algodão NÃO está na lista do EUDR.**
### O problema real
- O produtor rural individual **não sabe** que precisa dessa documentação
- Quando sabe, **não sabe como obter** os documentos
- As cooperativas precisam **coletar documentos de centenas ou milhares de produtores**
- Fazer isso **manualmente** (ligando, visitando, cobrando) é **caro e lento**
- Sem compliance, a cooperativa **perde acesso ao mercado europeu**
### Prazo
O regulamento EUDR está em vigor. Empresas que importarem commodities da UE sem comprovação de compliance estão sujeitas a **multas pesadas e proibição de importação**.
---
## 2. A Solução: DocuAgro
### Em uma frase:
> **DocuAgro automatiza a coleta, validação e organização de documentos de produtores rurais para compliance EUDR, usando um bot no Telegram com inteligência artificial.**
### Como resolve o problema:
| Problema | Solução DocuAgro |
|----------|-----------------|
| Produtor não sabe o que fazer | Bot guia passo a passo em linguagem simples |
| Documentos difíceis de coletar | IA explica como obter cada um |
| Processo manual e caro | 100% automatizado via Telegram |
| Sem controle sobre progresso | Painel web em tempo real pra cooperativa |
| Documentação desorganizada | Dossiê PDF profissional gerado automaticamente |
| OCR manual | Extração automática de dados por OCR |
### Dois lados do sistema:
```
┌─────────────────────┐ ┌──────────────────────┐
│ 👨‍🌾 PRODUTOR │ │ 🏢 COOPERATIVA │
│ │ │ │
│ Bot Telegram │◄────────►│ Painel Web │
│ @docuagro_bot │ Dados │ docuagro.com.br │
│ │ │ │
│ • Conversa com IA │ │ • Dashboard │
│ • Envia documentos│ │ • Lista produtores │
│ • Recebe feedback │ │ • Status compliance│
│ • Gera dossiê │ │ • Download dossiês │
│ │ │ • Exporta CSV │
└─────────────────────┘ └──────────────────────┘
```
---
## 3. Como Funciona (Passo a Passo)
### Fluxo Completo:
```
PASSO 1 → Cooperativa contrata o DocuAgro
PASSO 2 → Recebe acesso ao painel web (docuagro.com.br)
PASSO 3 → Cooperativa envia o link do bot (@docuagro_bot) pros produtores
PASSO 4 → Produtor abre o Telegram e clica em /start
PASSO 5 → Bot faz onboarding (nome, CPF, propriedade, município, área, cultura)
PASSO 6 → Bot pede o 1° documento (CAR)
PASSO 7 → Produtor tira foto ou envia PDF do documento
PASSO 8 → IA confirma recebimento e OCR valida automaticamente
PASSO 9 → Bot pede o 2° documento (CCIR)
PASSO 10 → Repete para todos os 8 documentos
PASSO 11 → Quando completo, produtor pode gerar dossiê PDF (/dossie)
PASSO 12 → Cooperativa acompanha tudo em tempo real no painel
PASSO 13 → Cooperativa exporta dados em CSV ou baixa dossiês individuais
```
### Tempo médio por produtor:
- **Onboarding:** 3-5 minutos
- **Coleta dos 8 documentos:** 2-7 dias (depende do produtor ter os docs prontos)
- **Geração do dossiê:** Automático (< 5 segundos)
---
## 4. O Bot Telegram (Lado do Produtor)
### Por que Telegram?
- **89% dos produtores rurais brasileiros têm smartphone**
- Telegram funciona com **internet fraca** (comum na zona rural)
- **Não precisa instalar app novo** — maioria já tem Telegram ou instala em 1 minuto
- Funciona em **qualquer celular** (Android barato, iPhone antigo)
- **Sem custo para o produtor** — só precisa do celular que já tem
### Bot: @docuagro_bot
### Comandos disponíveis:
| Comando | O que faz |
|---------|-----------|
| `/start` | Inicia o cadastro ou retoma de onde parou |
| `/status` | Mostra o status de cada documento (✅ ⬜ 🟡 ❌) |
| `/dossie` | Gera e envia o dossiê PDF completo |
| `/pular` | Pula um documento que não tem no momento (pode enviar depois) |
| `/ajuda` | Menu de ajuda com instruções |
### Fluxo do onboarding (conversa real):
```
BOT: 🌱 Bem-vindo ao DocuAgro!
Oi, João! Eu sou o DocuAgro, seu assistente para organizar
a documentação da sua propriedade rural.
📋 Por que isso é importante?
A União Europeia criou uma nova regra (EUDR) que exige
comprovação de que a produção não vem de área desmatada.
Primeiro, me conta: qual é o seu nome completo?
PRODUTOR: João da Silva Oliveira
BOT: Beleza, João! Agora me passa seu CPF, por favor.
É só pra identificação no sistema.
PRODUTOR: 123.456.789-00
BOT: Certinho! Qual o nome da sua propriedade?
PRODUTOR: Fazenda Boa Vista
BOT: Boa! Em qual município e estado fica a Fazenda Boa Vista?
PRODUTOR: Sorriso, Mato Grosso
BOT: Sorriso/MT, anotado! Qual a área aproximada em hectares?
PRODUTOR: uns 350 hectares
BOT: 350 hectares, beleza! E qual a cultura principal?
Soja, café, gado...?
PRODUTOR: Soja
BOT: Perfeito, João! Tá tudo anotado. Agora vamos pros documentos.
📄 Primeiro documento: CAR (Cadastro Ambiental Rural)
O CAR é o registro da sua propriedade no sistema ambiental.
Se já tem, manda a foto ou o PDF pra mim.
Se não tem, é feito pelo site car.gov.br ou no escritório
do meio ambiente do seu município.
```
### Como o produtor envia documentos:
1. **Foto** — tira foto do documento pelo celular e envia no chat
2. **PDF** — envia o arquivo PDF diretamente
3. **Qualquer formato** — o sistema aceita e processa
### O que acontece quando o produtor envia:
1. Bot confirma: "✅ Recebi seu CAR! Tá sendo analisado."
2. **OCR automático** extrai dados do documento (número, CPF, datas)
3. **Validação automática** verifica se o documento parece correto
4. Se tudo OK, marca como aprovado e pede o próximo
5. Se ilegível: "📸 A foto ficou escura, pode tirar outra?"
---
## 5. O Painel Web (Lado da Cooperativa)
### Acesso: https://docuagro.com.br
### Dashboard principal:
O painel mostra em tempo real:
- **Total de produtores** cadastrados
- **Produtores completos** (todos os docs aprovados) ✅
- **Em andamento** (parcialmente documentados) 🟡
- **Pendentes** (cadastrados mas sem docs) ⬜
- **Irregulares** (docs rejeitados/vencidos) ❌
- **Percentual de compliance** (barra de progresso)
### Lista de Produtores:
Tabela com todos os produtores mostrando:
- Nome
- CPF/CNPJ
- Propriedade
- Município/UF
- Área (ha)
- Cultura
- Status (pendente/em andamento/completo/irregular)
- Documentos aprovados (ex: 5/8)
### Funcionalidades:
- 🔍 **Busca** por nome, CPF, propriedade ou município
- 📄 **Detalhes** de cada produtor (clica e vê todos os docs)
- 📥 **Download** de dossiê PDF individual
- 📊 **Exportação CSV** de todos os dados (para importar em planilhas/ERPs)
- 🔄 **Atualização em tempo real** — sem precisar recarregar
### API REST (para integração):
O sistema também oferece API para integração com sistemas existentes:
| Endpoint | Descrição |
|----------|-----------|
| `GET /api/dashboard` | Estatísticas gerais |
| `GET /api/produtores` | Lista todos os produtores |
| `GET /api/produtores/:id` | Detalhe de um produtor |
| `POST /api/produtores/:id/dossie` | Gera dossiê PDF |
| `GET /api/exportar/csv` | Exporta tudo em CSV |
| `GET /api/health` | Health check |
---
## 6. Inteligência Artificial
### Modelo usado: GPT-4o-mini (OpenAI)
### O que a IA faz:
1. **Conversa natural** — o produtor conversa normalmente, sem precisar seguir comandos rígidos
2. **Linguagem do campo** — a IA fala como um vizinho, não como um robô. Usa termos como "tá certinho", "beleza", "vamos lá"
3. **Guia a coleta** — explica o que é cada documento, onde encontrar, como obter
4. **Extrai dados** — durante o onboarding, extrai nome, CPF, município etc. automaticamente da conversa
5. **Valida documentos** — avalia se o documento parece correto pelo conteúdo
6. **Orienta correções** — se a foto está ruim ou o documento errado, orienta o produtor
### OCR (Leitura Automática de Documentos):
O sistema usa **Tesseract.js** para extrair texto de fotos e PDFs:
- **CAR:** Extrai número do registro SICAR
- **CCIR:** Extrai código do imóvel (INCRA)
- **ITR:** Identifica dados da Receita Federal
- **Georreferenciamento:** Extrai coordenadas GPS
- **Licença Ambiental:** Extrai datas de validade
- **Nota Fiscal:** Extrai CPF/CNPJ, valores
### Custo da IA:
- GPT-4o-mini custa **~US$ 0,15 por 1 milhão de tokens de entrada**
- Na prática: **menos de R$ 0,10 por produtor completo** (onboarding + 8 docs)
- Para 500 produtores: **custo mensal de IA ≈ R$ 50**
---
## 7. Documentos Coletados
O DocuAgro coleta **8 documentos obrigatórios** para compliance EUDR:
### 1. CAR — Cadastro Ambiental Rural
- **O que é:** Registro da propriedade no sistema ambiental federal (SICAR)
- **Onde obter:** car.gov.br ou escritório municipal de meio ambiente
- **Validação OCR:** Número SICAR, menção ao cadastro ambiental
### 2. CCIR — Certificado de Cadastro de Imóvel Rural
- **O que é:** Certificado emitido pelo INCRA que prova o cadastro do imóvel
- **Onde obter:** Site do INCRA (sncr.serpro.gov.br) ou escritório regional
- **Validação OCR:** Código do imóvel, menção ao INCRA
### 3. ITR — Imposto Territorial Rural
- **O que é:** Comprovante de quitação do imposto sobre a terra
- **Onde obter:** Site da Receita Federal ou via contador
- **Validação OCR:** Menção a ITR/Receita Federal, CPF
### 4. Georreferenciamento
- **O que é:** Mapa/planta da propriedade com coordenadas GPS
- **Onde obter:** Agrimensor/topógrafo ou cartório
- **Validação OCR:** Coordenadas geográficas, memorial descritivo
### 5. Licença Ambiental
- **O que é:** Autorização do órgão ambiental estadual para atividade agropecuária
- **Onde obter:** SEMA, IMA, IEMA (varia por estado)
- **Validação OCR:** Menção a licença/ambiental, datas de validade
### 6. Contrato de Arrendamento
- **O que é:** Contrato com o proprietário da terra (se não for dono)
- **Onde obter:** Cartório ou contrato particular
- **Nota:** Se o produtor é dono, esse documento é pulado (/pular)
- **Validação OCR:** Menção a contrato/arrendamento
### 7. Nota Fiscal de Venda
- **O que é:** Última NF de venda da produção
- **Onde obter:** Sistema de NF-e ou talão de NF de produtor rural
- **Validação OCR:** Menção a nota fiscal/DANFE, CPF/CNPJ
### 8. Declaração de Não Desmatamento
- **O que é:** Autodeclaração de que não houve desmatamento pós-dez/2020
- **Geração:** O DocuAgro gera automaticamente para assinatura
- **Validação:** Sempre aprovada (gerada pelo sistema)
---
## 8. Dossiê PDF Automatizado
### O que é:
Um **documento PDF profissional** que compila toda a documentação do produtor em um único arquivo padronizado.
### Estrutura do dossiê:
```
📄 Dossiê EUDR — João da Silva
├── CAPA
│ • Logo DocuAgro
│ • Nome do produtor
│ • CPF, propriedade, município
│ • Status: ✅ COMPLIANCE COMPLETO
├── DADOS DO PRODUTOR
│ • Informações completas (nome, CPF, propriedade, área, cultura)
│ • Data de cadastro
│ • Progresso: 8/8 documentos
├── RESUMO DOS DOCUMENTOS
│ • Tabela com todos os 8 documentos
│ • Status de cada um (aprovado/enviado/pendente)
│ • Data de envio
├── DETALHE DE CADA DOCUMENTO (1 página por doc)
│ • Nome e tipo do documento
│ • Status e datas
│ • Dados extraídos por OCR
│ • Miniatura da imagem (se foto)
└── DECLARAÇÃO DE CONFORMIDADE
• Texto legal para EUDR
• Resumo dos documentos validados
• Espaço para assinatura
• Data e hora de geração
```
### Uso do dossiê:
- A cooperativa **apresenta o dossiê às tradings/exportadoras** como prova de compliance
- O dossiê pode ser **enviado diretamente para importadores europeus**
- Serve como **prova documental** em caso de auditoria EUDR
- O produtor também pode solicitar o seu próprio dossiê via `/dossie` no bot
---
## 9. Arquitetura Técnica
### Stack:
| Componente | Tecnologia |
|-----------|------------|
| Bot Telegram | Node.js + Telegraf |
| IA / Chat | OpenAI GPT-4o-mini |
| OCR | Tesseract.js |
| Geração PDF | PDFKit |
| Banco de Dados | SQLite (better-sqlite3) |
| API REST | Express.js |
| Painel Web | HTML/CSS/JS puro |
| Servidor | DigitalOcean (Ubuntu) |
| DNS/CDN/SSL | Cloudflare |
| Domínio | docuagro.com.br |
### Diagrama de arquitetura:
```
┌──────────────┐ ┌─────────────────────────────────────────────┐
│ 📱 Telegram │ │ SERVIDOR DOCUAGRO │
│ (Produtor) │◄──►│ │
│ │ │ ┌──────────────┐ ┌────────────────┐ │
└──────────────┘ │ │ Bot Telegraf │ │ Express API │ │
│ │ │ │ (porta 3100) │ │
│ └──────┬───────┘ └───────┬────────┘ │
┌──────────────┐ │ │ │ │
│ 🌐 Browser │ │ ┌──────┴──────────────────┴──────┐ │
│ (Cooperat.) │◄──►│ │ SERVIÇOS │ │
│ │ │ │ ┌─────────────────────────┐ │ │
└──────────────┘ │ │ │ ai-service.js (OpenAI) │ │ │
│ │ │ ocr-service.js (Tesser) │ │ │
│ │ │ pdf-service.js (PDFKit) │ │ │
│ │ │ database.js (SQLite) │ │ │
│ │ └─────────────────────────┘ │ │
│ └────────────────────────────────┘ │
│ │
│ 📁 data/docuagro.db (banco) │
│ 📁 uploads/ (documentos dos produtores) │
└─────────────────────────────────────────────┘
```
### Banco de dados (tabelas):
| Tabela | Descrição |
|--------|-----------|
| `cooperativas` | Dados da cooperativa cliente |
| `produtores` | Dados de cada produtor (nome, CPF, propriedade, status) |
| `documentos` | Cada documento enviado (tipo, status, arquivo, OCR) |
| `conversas` | Histórico de conversas bot ↔ produtor |
| `dossies` | Dossiês PDF gerados |
### Requisitos de servidor:
- **Node.js 18+**
- **1 GB RAM** (mínimo) / 2 GB recomendado
- **20 GB disco** (depende do volume de documentos)
- **Ubuntu 22.04+** ou similar
---
## 10. Modelo de Negócio e Preços
### Modelo: B2B SaaS (Software as a Service)
- **Quem paga:** A cooperativa
- **Quem usa de graça:** O produtor (via Telegram)
- **Recorrência:** Mensalidade
### Planos:
| Plano | Limite Produtores | Preço/mês | Ideal para |
|-------|-------------------|-----------|------------|
| **Starter** | Até 100 | R$ 497 | Cooperativas pequenas |
| **Pro** | Até 500 | R$ 1.497 | Cooperativas médias |
| **Enterprise** | Até 2.000 | R$ 3.997 | Grandes cooperativas |
| **Custom** | Ilimitado | Sob consulta | Tradings, associações |
### O que está incluído em todos os planos:
- ✅ Bot Telegram personalizado
- ✅ Painel web completo
- ✅ IA para coleta guiada
- ✅ OCR automático
- ✅ Dossiê PDF automático
- ✅ Exportação CSV
- ✅ API REST para integração
- ✅ Suporte por email
- ✅ Atualizações do sistema
### Custos operacionais (nossos):
- Servidor DigitalOcean: ~R$ 100/mês
- API OpenAI: ~R$ 50-200/mês (depende do volume)
- Domínio: R$ 40/ano
- Cloudflare: Grátis
- **Total operacional: ~R$ 250-500/mês**
### Margens:
- Com **1 cliente Starter:** Receita R$ 497, Custo ~R$ 250 = **Margem ~50%**
- Com **5 clientes Pro:** Receita R$ 7.485, Custo ~R$ 500 = **Margem ~93%**
- Com **15 clientes mix:** Receita R$ 35.000+, Custo ~R$ 2.500 = **Margem ~93%**
### Projeção 12 meses:
- Meta: 15 cooperativas
- Mix: 5 Starter + 7 Pro + 3 Enterprise
- **ARR (Receita Anual Recorrente): ~R$ 420.000**
### Estratégia de entrada:
1. **Piloto grátis 30 dias** — sem compromisso
2. Cooperativa cadastra 10-20 produtores para testar
3. Vê resultado → converte em assinatura
4. Expansão orgânica: cooperativa indica outras
---
## 11. Público-Alvo
### Clientes principais (quem paga):
| Segmento | Exemplos | Por que compra |
|----------|----------|----------------|
| **Cooperativas de soja** | COAMO, Cocamar, C.Vale | Exportam para UE, precisam de compliance |
| **Cooperativas de café** | Cooxupé, Minasul | Café especial para Europa |
| **Cooperativas de cacau** | Cooperativas do Sul da Bahia | Cacau direto pra Europa |
| **Cooperativas de gado** | Cooperativas pecuárias MT/GO | Carne bovina para UE |
| **Tradings** | Cargill, Bunge, ADM | Precisam compliance dos fornecedores |
| **Associações** | OCB estaduais | Podem oferecer como serviço |
### Onde encontrar clientes:
| Canal | Detalhes |
|-------|---------|
| **OCB** (Organização das Cooperativas) | Porta de entrada para todas as cooperativas |
| **APROSOJA** | Associação dos produtores de soja por estado |
| **CNA** | Confederação Nacional da Agricultura |
| **CECAFÉ** | Conselho dos Exportadores de Café |
| **ABIEC** | Associação da Indústria Exportadora de Carnes |
| **Agrishow** (Ribeirão Preto) | Maior feira agro do Brasil |
| **Expointer** (RS) | Feira agropecuária do Sul |
| **LinkedIn** | Gerentes de qualidade/compliance de cooperativas |
| **Eventos EUDR** | Seminários e workshops sobre a regulamentação |
### Usuário final (quem usa o bot):
- **Produtor rural** — pequeno a grande
- **Perfil:** 30-65 anos, smartphone Android, internet instável
- **Motivação:** Cooperativa pediu, quer manter acesso ao mercado
### Estados prioritários:
1. **Mato Grosso** — maior produtor de soja e gado
2. **Paraná** — cooperativas fortes (COAMO, Cocamar)
3. **Goiás** — soja e gado
4. **Minas Gerais** — café
5. **São Paulo** — café e cana
6. **Espírito Santo** — café
7. **Bahia** — cacau e soja (MATOPIBA)
8. **Pará** — cacau e gado
---
## 12. Como Fazer uma Demo
### Preparação:
1. Abra o Telegram no celular ou computador
2. Busque **@docuagro_bot**
3. Tenha o painel web aberto em outra aba: `https://docuagro.com.br`
### Roteiro da demo (10 minutos):
**Minuto 1-2: O Problema**
> "Vocês sabem que o EUDR vai exigir documentação de cada produtor individual. Imagina ligar pra 500 produtores, pedir 8 documentos de cada um, organizar tudo, gerar relatórios... Manualmente isso leva meses e custa uma fortuna."
**Minuto 3-4: A Solução**
> "O DocuAgro faz tudo isso automaticamente. O produtor conversa com um bot no Telegram — a mesma ferramenta que ele já usa no dia a dia. Uma inteligência artificial guia ele passo a passo."
**Minuto 5-7: Demo ao vivo**
1. Abra o bot no Telegram
2. Envie `/start`
3. Mostre o onboarding (responda como produtor fictício)
4. Mostre o `/status`
5. Mude pra aba do painel web
6. Mostre o dashboard e a lista de produtores
7. Mostre que o produtor que acabou de se cadastrar já aparece
**Minuto 8-9: O Dossiê**
> "Quando o produtor completa os 8 documentos, o sistema gera automaticamente um dossiê PDF profissional que vocês podem apresentar para a trading ou importador europeu."
- Mostre um exemplo do dossiê PDF
**Minuto 10: Fechamento**
> "Oferecemos 30 dias grátis pra vocês testarem com 10-20 produtores. Sem compromisso. Se funcionar — e vai funcionar — a gente fala de plano."
### Dicas:
- **Sempre mostre no celular** — é onde o produtor vai usar
- **Fale a linguagem da cooperativa** — compliance, rastreabilidade, mercado europeu
- **Enfatize o custo-benefício** — quanto custaria fazer manualmente vs. usar o DocuAgro
- **Prepare um dossiê de exemplo** para mostrar como fica o resultado final
---
## 13. Perguntas Frequentes (FAQ)
### "O produtor precisa instalar alguma coisa?"
Não! Só precisa ter o Telegram instalado (que a maioria já tem). É só abrir o bot e começar a conversar.
### "Funciona com internet ruim?"
Sim! O Telegram é otimizado para conexões lentas. O produtor pode até mandar as fotos quando tiver sinal e o bot processa depois.
### "E se o produtor não tiver Telegram?"
O Telegram é gratuito e leve. Instala em 2 minutos em qualquer celular. A cooperativa pode orientar na instalação. No futuro, planejamos suporte a WhatsApp também.
### "Os dados ficam seguros?"
Sim. Os documentos ficam armazenados em servidor dedicado com backup. Cada produtor tem um diretório isolado. Nenhum dado é compartilhado com terceiros.
### "Precisa de treinamento para a cooperativa usar?"
Mínimo. O painel web é intuitivo. Fornecemos um treinamento online de 1 hora + manual completo em PDF.
### "Pode integrar com o sistema da cooperativa?"
Sim! Temos API REST documentada. Qualquer sistema pode consultar dados, baixar dossiês e exportar CSV.
### "E se o produtor não tiver um documento?"
O bot explica como obter cada documento, passo a passo. Se o produtor não tem no momento, pode usar `/pular` e enviar depois.
### "Quanto custa por produtor?"
O custo por produtor é desprezível (menos de R$ 0,10 de IA + OCR). O plano é por faixa de produtores, não por uso individual.
### "Funciona para qualquer commodity?"
Para soja, café, cacau, gado, óleo de palma, madeira e borracha — que são as commodities reguladas pelo EUDR.
### "E se o regulamento mudar?"
Atualizamos o sistema automaticamente. Novos documentos podem ser adicionados, tipos de validação ajustados — tudo sem custo extra dentro do plano.
---
## 14. Diferenciais Competitivos
| Diferencial | DocuAgro | Concorrência |
|------------|----------|--------------|
| **Canal** | Telegram (leve, gratuito, rural-friendly) | Apps próprios (pesados, pagos) |
| **IA** | GPT-4o-mini (conversa natural) | Formulários rígidos |
| **Linguagem** | Fala como produtor | Linguagem técnica/jurídica |
| **OCR** | Automático com Tesseract.js | Manual ou inexistente |
| **Dossiê** | PDF profissional automático | Manual/Excel |
| **Custo** | A partir de R$ 497/mês | R$ 5.000+ setup + mensalidade |
| **Setup** | 24 horas | Semanas/meses |
| **Piloto grátis** | 30 dias | Não oferecem |
### Pitch de elevador (30 segundos):
> "O DocuAgro resolve o maior gargalo do EUDR: fazer o produtor rural individual enviar a documentação. A gente usa um bot no Telegram com inteligência artificial que conversa com o produtor na linguagem dele, coleta os 8 documentos obrigatórios, valida tudo automaticamente e gera um dossiê PDF profissional. Pra cooperativa, é um painel web em tempo real com 100% de visibilidade. Piloto grátis de 30 dias."
---
## 15. Roadmap / Próximos Passos
### Curto prazo (1-3 meses):
- [ ] Deploy em produção (servidor DigitalOcean)
- [ ] Autenticação JWT no painel
- [ ] HTTPS end-to-end
- [ ] Primeiro piloto com cooperativa real
- [ ] Suporte a múltiplas cooperativas (multi-tenant)
### Médio prazo (3-6 meses):
- [ ] Suporte a WhatsApp (via WhatsApp Business API)
- [ ] Notificações automáticas (lembrar produtor de docs pendentes)
- [ ] Validação avançada com IA de visão (GPT-4o) para documentos
- [ ] Dashboard analytics (gráficos, tendências, relatórios)
- [ ] App mobile para cooperativa
### Longo prazo (6-12 meses):
- [ ] Integração direta com SICAR, INCRA, Receita Federal
- [ ] Geolocalização automática via satélite
- [ ] Monitoramento de desmatamento em tempo real
- [ ] Certificação blockchain de compliance
- [ ] Expansão internacional (Colômbia, Indonésia, Costa do Marfim)
---
## 📞 Contato
- **Site:** docuagro.com.br
- **Bot:** @docuagro_bot (Telegram)
- **Email:** m171c0@gmail.com
---
*DocuAgro — Compliance do produtor, na palma da mão. 🌱*

Binary file not shown.

769
docs/manual-docuagro.html Normal file
View File

@@ -0,0 +1,769 @@
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>DocuAgro - Manual Completo</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Inter', sans-serif; color: #1a1a2e; line-height: 1.7; background: #fff; }
.page { page-break-after: always; min-height: 100vh; position: relative; }
.page:last-child { page-break-after: avoid; }
/* CAPA */
.capa { background: linear-gradient(135deg, #1B5E20 0%, #2E7D32 40%, #43A047 100%); color: white; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; padding: 60px 80px; }
.capa h1 { font-size: 52px; font-weight: 800; margin-bottom: 8px; }
.capa .tagline { font-size: 20px; font-weight: 300; opacity: 0.9; margin-bottom: 10px; }
.capa .tipo-doc { font-size: 28px; font-weight: 600; background: rgba(255,255,255,0.15); padding: 14px 40px; border-radius: 12px; margin: 30px 0; }
.capa .info { font-size: 14px; opacity: 0.7; margin-top: 30px; }
/* INTERNAS */
.interna { padding: 50px 60px; }
.header-bar { display: flex; justify-content: space-between; align-items: center; border-bottom: 3px solid #2E7D32; padding-bottom: 10px; margin-bottom: 30px; }
.header-bar h2 { font-size: 26px; font-weight: 700; color: #1B5E20; }
.header-bar .brand { font-size: 13px; color: #2E7D32; font-weight: 600; }
.header-bar .pg { font-size: 12px; color: #999; }
h3 { font-size: 18px; font-weight: 700; color: #2E7D32; margin: 25px 0 12px; }
h4 { font-size: 15px; font-weight: 600; color: #333; margin: 18px 0 8px; }
p { font-size: 13.5px; color: #333; margin-bottom: 10px; }
ul, ol { padding-left: 22px; margin: 8px 0 14px; }
li { font-size: 13.5px; color: #333; margin-bottom: 5px; }
table { width: 100%; border-collapse: collapse; margin: 12px 0; font-size: 12.5px; }
thead th { background: #1B5E20; color: white; padding: 8px 12px; text-align: left; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px; }
tbody td { padding: 8px 12px; border-bottom: 1px solid #e8e8e8; }
tbody tr:nth-child(even) { background: #f9fdf9; }
.box { background: #f1f8e9; border: 1px solid #c8e6c9; border-radius: 10px; padding: 16px 22px; margin: 14px 0; }
.box.warning { background: #fff8e1; border-color: #ffe082; }
.box.info { background: #e3f2fd; border-color: #90caf9; }
.box h4 { margin-top: 0; color: #1B5E20; }
.box.warning h4 { color: #e65100; }
.box.info h4 { color: #0d47a1; }
.cmd { background: #263238; color: #a5d6a7; padding: 2px 8px; border-radius: 4px; font-family: 'Courier New', monospace; font-size: 12.5px; font-weight: 600; }
.code-block { background: #263238; color: #e0e0e0; padding: 16px 22px; border-radius: 10px; font-family: 'Courier New', monospace; font-size: 12px; line-height: 1.8; margin: 12px 0; overflow-x: auto; }
.code-block .comment { color: #81c784; }
.chat { background: #f5f5f5; border-radius: 12px; padding: 16px 20px; margin: 12px 0; }
.chat .msg { margin-bottom: 10px; font-size: 13px; }
.chat .msg.user { padding-left: 20px; }
.chat .msg.user::before { content: "👤 Produtor: "; font-weight: 700; color: #333; }
.chat .msg.bot::before { content: "🤖 DocuAgro: "; font-weight: 700; color: #2E7D32; }
.chat .msg.action { color: #666; font-style: italic; text-align: center; font-size: 12px; }
.step-grid { display: grid; grid-template-columns: 50px 1fr; gap: 8px 16px; margin: 14px 0; }
.step-num { width: 36px; height: 36px; background: #2E7D32; color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 16px; }
.step-content { padding-top: 6px; }
.step-content strong { color: #1B5E20; }
.footer { position: absolute; bottom: 25px; left: 60px; right: 60px; display: flex; justify-content: space-between; font-size: 9px; color: #bbb; border-top: 1px solid #eee; padding-top: 8px; }
.badge { display: inline-block; background: #e8f5e9; color: #1B5E20; padding: 3px 12px; border-radius: 15px; font-size: 11px; font-weight: 600; border: 1px solid #c8e6c9; margin: 2px; }
</style>
</head>
<body>
<!-- CAPA -->
<div class="page capa">
<div style="font-size:72px; margin-bottom:10px;">🌱</div>
<h1>DocuAgro</h1>
<div class="tagline">Compliance do produtor, na palma da mão.</div>
<div class="tipo-doc">📘 Manual Completo</div>
<p style="max-width:500px; font-size:15px; opacity:0.85; line-height:1.6;">
Guia completo de uso da plataforma DocuAgro para produtores rurais e cooperativas.
Compliance EUDR via Bot Telegram + Inteligência Artificial + Painel Web.
</p>
<div class="info">AI Vertice • Versão 1.0 • Fevereiro 2026</div>
</div>
<!-- SUMÁRIO -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>Sumário</h2>
<span class="pg">02</span>
</div>
<div style="margin-top:20px;">
<table>
<tbody>
<tr><td style="width:40px; font-weight:700; color:#2E7D32;">01</td><td><strong>O que é o DocuAgro</strong></td><td style="text-align:right; color:#999;">Pág. 03</td></tr>
<tr><td style="font-weight:700; color:#2E7D32;">02</td><td><strong>Para quem é</strong></td><td style="text-align:right; color:#999;">Pág. 03</td></tr>
<tr><td style="font-weight:700; color:#2E7D32;">03</td><td><strong>Guia do Produtor — Bot Telegram</strong></td><td style="text-align:right; color:#999;">Pág. 04</td></tr>
<tr><td style="font-weight:700; color:#2E7D32;">04</td><td><strong>Exemplo Completo de Uso</strong></td><td style="text-align:right; color:#999;">Pág. 06</td></tr>
<tr><td style="font-weight:700; color:#2E7D32;">05</td><td><strong>Documentos Coletados (8)</strong></td><td style="text-align:right; color:#999;">Pág. 07</td></tr>
<tr><td style="font-weight:700; color:#2E7D32;">06</td><td><strong>Inteligência Artificial</strong></td><td style="text-align:right; color:#999;">Pág. 08</td></tr>
<tr><td style="font-weight:700; color:#2E7D32;">07</td><td><strong>Guia da Cooperativa — Painel Web</strong></td><td style="text-align:right; color:#999;">Pág. 09</td></tr>
<tr><td style="font-weight:700; color:#2E7D32;">08</td><td><strong>API REST</strong></td><td style="text-align:right; color:#999;">Pág. 10</td></tr>
<tr><td style="font-weight:700; color:#2E7D32;">09</td><td><strong>Dossiê PDF</strong></td><td style="text-align:right; color:#999;">Pág. 11</td></tr>
<tr><td style="font-weight:700; color:#2E7D32;">10</td><td><strong>Instalação e Configuração</strong></td><td style="text-align:right; color:#999;">Pág. 12</td></tr>
<tr><td style="font-weight:700; color:#2E7D32;">11</td><td><strong>Arquitetura Técnica</strong></td><td style="text-align:right; color:#999;">Pág. 13</td></tr>
<tr><td style="font-weight:700; color:#2E7D32;">12</td><td><strong>FAQ e Troubleshooting</strong></td><td style="text-align:right; color:#999;">Pág. 14</td></tr>
</tbody>
</table>
</div>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 2</span></div>
</div>
<!-- PÁG 3 — O QUE É + PARA QUEM -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>1. O que é o DocuAgro</h2>
<span class="pg">03</span>
</div>
<p>O <strong>DocuAgro</strong> é uma plataforma que automatiza a coleta, validação e organização de documentação de produtores rurais para compliance com o <strong>EUDR</strong> (Regulamento da União Europeia contra Desmatamento — EU 2023/1115).</p>
<p>A plataforma combina três componentes:</p>
<ul>
<li><strong>Bot Telegram</strong> — onde o produtor envia seus documentos via conversa</li>
<li><strong>Inteligência Artificial</strong> — que guia, orienta e valida os documentos</li>
<li><strong>Painel Web</strong> — onde a cooperativa acompanha o progresso de todos os produtores</li>
</ul>
<div class="box">
<h4>🇪🇺 O que é o EUDR?</h4>
<p>O Regulamento (UE) 2023/1115 proíbe a importação na UE de commodities produzidas em áreas desmatadas após 31/12/2020. Afeta: <strong>Soja, Café, Cacau, Óleo de Palma, Madeira, Gado e Borracha</strong>. Produtores brasileiros que exportam precisam comprovar geolocalização, ausência de desmatamento e conformidade ambiental.</p>
</div>
<h2 style="font-size:22px; color:#1B5E20; margin-top:30px; padding-top:20px; border-top:2px solid #e0e0e0;">2. Para quem é</h2>
<h3>👨‍🌾 Produtores Rurais</h3>
<p>Qualquer produtor que cultive commodities afetadas pelo EUDR e exporte (direta ou indiretamente via cooperativa/trading) para a Europa. O produtor interage <strong>100% pelo Telegram</strong>, sem precisar instalar nenhum aplicativo novo.</p>
<h3>🏢 Cooperativas e Tradings</h3>
<p>Organizações que precisam comprovar a conformidade de dezenas a milhares de produtores associados. Acompanham tudo pelo <strong>Painel Web</strong> com dashboard, busca, dossiês e exportação CSV.</p>
<h3>🎯 Mercado-Alvo</h3>
<ul>
<li><strong>Soja:</strong> Cooperativas do MT, PR, GO (ex: Coamo, C.Vale, Cocamar)</li>
<li><strong>Café:</strong> Cooperativas de MG, SP, ES (ex: COOXUPÉ)</li>
<li><strong>Gado:</strong> Frigoríficos e associações pecuárias</li>
<li><strong>Cacau:</strong> Cooperativas da Bahia e Pará</li>
<li><strong>Madeira:</strong> Setor florestal</li>
</ul>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 3</span></div>
</div>
<!-- PÁG 4 — GUIA DO PRODUTOR -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>3. Guia do Produtor — Bot Telegram</h2>
<span class="pg">04</span>
</div>
<p>O produtor acessa o DocuAgro pelo Telegram, buscando por <strong>@docuagro_bot</strong>. Todo o processo é guiado por inteligência artificial em linguagem simples.</p>
<h3>📱 Comandos Disponíveis</h3>
<table>
<thead><tr><th>Comando</th><th>Função</th><th>Quando usar</th></tr></thead>
<tbody>
<tr><td><span class="cmd">/start</span></td><td>Iniciar cadastro</td><td>Primeira vez no bot</td></tr>
<tr><td><span class="cmd">/status</span></td><td>Ver progresso</td><td>A qualquer momento</td></tr>
<tr><td><span class="cmd">/dossie</span></td><td>Gerar dossiê PDF</td><td>Após enviar documentos</td></tr>
<tr><td><span class="cmd">/pular</span></td><td>Pular documento</td><td>Se não tem o doc agora</td></tr>
<tr><td><span class="cmd">/ajuda</span></td><td>Menu de ajuda</td><td>Se tiver dúvidas</td></tr>
</tbody>
</table>
<h3>🔄 Fluxo Completo — Passo a Passo</h3>
<h4>Etapa 1: Cadastro (Onboarding)</h4>
<p>Ao enviar <span class="cmd">/start</span>, a IA faz perguntas simples para conhecer o produtor:</p>
<div class="step-grid">
<div><div class="step-num">1</div></div>
<div class="step-content"><strong>Nome completo</strong> — "Qual é o seu nome completo?"</div>
<div><div class="step-num">2</div></div>
<div class="step-content"><strong>CPF</strong> — Para identificação no sistema</div>
<div><div class="step-num">3</div></div>
<div class="step-content"><strong>Nome da propriedade</strong> — Ex: "Fazenda Boa Vista"</div>
<div><div class="step-num">4</div></div>
<div class="step-content"><strong>Município e estado</strong> — Ex: "Sorriso, MT"</div>
<div><div class="step-num">5</div></div>
<div class="step-content"><strong>Área em hectares</strong> — Aproximado é suficiente</div>
<div><div class="step-num">6</div></div>
<div class="step-content"><strong>Cultura principal</strong> — Soja, café, gado, etc.</div>
</div>
<h4>Etapa 2: Coleta de Documentos</h4>
<p>Após o cadastro, a IA pede <strong>um documento por vez</strong>, na seguinte ordem:</p>
<ol>
<li>CAR (Cadastro Ambiental Rural)</li>
<li>CCIR (Certificado de Cadastro de Imóvel Rural)</li>
<li>ITR (Imposto Territorial Rural)</li>
<li>Georreferenciamento (coordenadas da propriedade)</li>
<li>Licença Ambiental</li>
<li>Contrato de Arrendamento (se aplicável)</li>
<li>Nota Fiscal de Venda</li>
<li>Declaração de Não Desmatamento (gerada automaticamente)</li>
</ol>
<div class="box">
<h4>📸 Dicas para enviar documentos</h4>
<ul>
<li>Tire foto em lugar com <strong>boa iluminação</strong></li>
<li>Enquadre o <strong>documento inteiro</strong> na foto</li>
<li><strong>PDF é melhor</strong> que foto (mais legível)</li>
<li>Envie <strong>um documento por vez</strong></li>
</ul>
</div>
<h4>Etapa 3: Dossiê</h4>
<p>Quando todos os documentos forem enviados, o produtor pode gerar o dossiê com <span class="cmd">/dossie</span>. O bot gera um PDF profissional e envia direto no chat.</p>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 4</span></div>
</div>
<!-- PÁG 5 — STATUS E NAVEGAÇÃO -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>3. Guia do Produtor (continuação)</h2>
<span class="pg">05</span>
</div>
<h3>📊 Verificando o Status</h3>
<p>A qualquer momento, o produtor pode enviar <span class="cmd">/status</span> para ver como está sua documentação:</p>
<div class="chat">
<div class="msg bot">📊 <strong>Status da sua documentação</strong><br><br>
👤 João da Silva<br>
🏡 Fazenda Boa Vista<br><br>
✅ CAR (Cadastro Ambiental Rural)<br>
✅ CCIR (Certificado do INCRA)<br>
🟡 ITR (Imposto Territorial Rural)<br>
⬜ Georreferenciamento<br>
⬜ Licença Ambiental<br>
⬜ Contrato de Arrendamento<br>
⬜ Nota Fiscal de Venda<br>
⬜ Declaração de Não Desmatamento<br><br>
📈 Progresso: 2/8
</div>
</div>
<p><strong>Legenda dos ícones:</strong></p>
<table>
<thead><tr><th>Ícone</th><th>Significado</th></tr></thead>
<tbody>
<tr><td></td><td>Documento aprovado</td></tr>
<tr><td>🟡</td><td>Enviado, em análise</td></tr>
<tr><td></td><td>Rejeitado (precisa reenviar)</td></tr>
<tr><td>⚠️</td><td>Vencido</td></tr>
<tr><td></td><td>Não enviado ainda</td></tr>
</tbody>
</table>
<h3>⏭️ Pulando um Documento</h3>
<p>Se o produtor não tem um documento no momento, pode usar <span class="cmd">/pular</span> para ir ao próximo. Ele poderá enviar o documento pulado depois.</p>
<div class="chat">
<div class="msg user">/pular</div>
<div class="msg bot">⏭️ Pulei o Georreferenciamento da Propriedade. Pode enviar depois! Agora vamos pra Licença Ambiental...</div>
</div>
<h3>❓ Pedindo Ajuda</h3>
<p>O comando <span class="cmd">/ajuda</span> mostra todos os comandos disponíveis e dicas de envio. Além disso, o produtor pode <strong>fazer qualquer pergunta em texto</strong> e a IA responderá com orientações sobre o que é cada documento e onde obtê-lo.</p>
<div class="chat">
<div class="msg user">O que é o CAR?</div>
<div class="msg bot">O CAR é o Cadastro Ambiental Rural. É feito pelo site car.gov.br. Se você já tem, é só me mandar o número do recibo ou o PDF. Se não tem, procure o escritório do meio ambiente do seu município que eles ajudam a fazer. 👍</div>
</div>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 5</span></div>
</div>
<!-- PÁG 6 — EXEMPLO COMPLETO -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>4. Exemplo Completo de Uso</h2>
<span class="pg">06</span>
</div>
<p>Veja abaixo uma conversa típica entre um produtor e o DocuAgro:</p>
<div class="chat">
<div class="msg user">/start</div>
<div class="msg bot">🌱 <strong>Bem-vindo ao DocuAgro!</strong><br><br>Oi! Eu sou o DocuAgro, seu assistente para organizar a documentação da sua propriedade rural.<br><br>📋 A União Europeia criou uma nova regra (EUDR) que exige comprovação de que a produção não vem de área desmatada. Sem essa documentação, pode ter problema na hora de vender.<br><br>São 8 documentos no total. Vamos começar?<br><br>Primeiro, me conta: <strong>qual é o seu nome completo?</strong></div>
<div class="msg user">João da Silva Ferreira</div>
<div class="msg bot">Beleza, João! 👍 Agora me passa seu <strong>CPF</strong> (é só pra identificação no sistema).</div>
<div class="msg user">123.456.789-00</div>
<div class="msg bot">Certinho! Qual o <strong>nome da sua propriedade</strong>?</div>
<div class="msg user">Fazenda Boa Vista</div>
<div class="msg bot">Boa! Em qual <strong>município e estado</strong> fica a Fazenda Boa Vista?</div>
<div class="msg user">Sorriso, Mato Grosso</div>
<div class="msg bot">Sorriso, MT — anotado! Qual a <strong>área aproximada em hectares</strong>?</div>
<div class="msg user">500 hectares</div>
<div class="msg bot">500 ha, tá ótimo! E qual a <strong>cultura principal</strong>? (soja, café, gado...)</div>
<div class="msg user">Soja</div>
<div class="msg bot">Perfeito, João! Tudo anotado. Agora vamos pros documentos. 📄<br><br>O primeiro é o <strong>CAR — Cadastro Ambiental Rural</strong>. É aquele registro do SICAR (car.gov.br). Se você já tem, manda a foto ou o PDF pra mim. Se não tem, me avisa que eu explico como fazer!</div>
<div class="msg action">[ João envia foto do CAR ]</div>
<div class="msg bot">✅ Recebi seu CAR! Tá sendo analisado, já te aviso o resultado. 📝 Número SICAR encontrado: MT-5107248-ABC123...<br><br>Agora vamos pro próximo: o <strong>CCIR</strong> (Certificado de Cadastro de Imóvel Rural do INCRA)...</div>
</div>
<div class="box info">
<h4>💡 Observações</h4>
<ul>
<li>A IA extrai dados automaticamente via <strong>OCR</strong> (número do CAR, código INCRA, CPF, datas, etc.)</li>
<li>Se a foto estiver ilegível, o bot pede para <strong>reenviar</strong> com dicas práticas</li>
<li>O processo completo leva em média <strong>15-30 minutos</strong> se o produtor tiver todos os documentos em mãos</li>
<li>O produtor pode parar a qualquer momento e <strong>continuar depois</strong> — o progresso é salvo</li>
</ul>
</div>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 6</span></div>
</div>
<!-- PÁG 7 — DOCUMENTOS -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>5. Documentos Coletados</h2>
<span class="pg">07</span>
</div>
<p>O DocuAgro coleta e valida <strong>8 documentos obrigatórios</strong> para compliance EUDR:</p>
<table>
<thead><tr><th>#</th><th>Documento</th><th>O que é</th><th>Onde obter</th><th>Validação OCR</th></tr></thead>
<tbody>
<tr><td>1</td><td><strong>CAR</strong></td><td>Cadastro Ambiental Rural</td><td>car.gov.br (SICAR)</td><td>Número SICAR</td></tr>
<tr><td>2</td><td><strong>CCIR</strong></td><td>Certificado Imóvel Rural</td><td>sncr.serpro.gov.br (INCRA)</td><td>Código INCRA</td></tr>
<tr><td>3</td><td><strong>ITR</strong></td><td>Imposto Territorial Rural</td><td>Receita Federal</td><td>CPF/CNPJ</td></tr>
<tr><td>4</td><td><strong>Geo</strong></td><td>Georreferenciamento</td><td>Técnico agrimensor</td><td>Coordenadas GPS</td></tr>
<tr><td>5</td><td><strong>Licença</strong></td><td>Licença Ambiental</td><td>Órgão estadual (SEMA/IMA)</td><td>Validade + OCR</td></tr>
<tr><td>6</td><td><strong>Contrato</strong></td><td>Contrato de Arrendamento</td><td>Cartório (se não for dono)</td><td>OCR geral</td></tr>
<tr><td>7</td><td><strong>NF</strong></td><td>Nota Fiscal de Venda</td><td>Última NF-e ou NF produtor</td><td>CPF/CNPJ + dados</td></tr>
<tr><td>8</td><td><strong>Declaração</strong></td><td>Não Desmatamento</td><td>Gerada automaticamente</td><td>Automática ✅</td></tr>
</tbody>
</table>
<h3>🔍 Como a Validação Funciona</h3>
<p>Cada documento enviado passa por um pipeline de validação:</p>
<ol>
<li><strong>Recebimento:</strong> Arquivo salvo em diretório isolado do produtor</li>
<li><strong>OCR (Tesseract.js):</strong> Extração de texto em português com análise de confiança</li>
<li><strong>Validação por tipo:</strong> Algoritmo específico busca campos-chave:
<ul>
<li>CAR → procura padrão do número SICAR (XX-XXXXXXX-XXXX...)</li>
<li>CCIR → procura menção ao INCRA + código do imóvel</li>
<li>ITR → procura "Receita Federal" ou "ITR" + CPF/CNPJ</li>
<li>Georreferenciamento → extrai coordenadas geográficas</li>
<li>Licença → busca "Licença" + datas de validade</li>
<li>NF → procura "Nota Fiscal" / "DANFE" + CPF/CNPJ</li>
</ul>
</li>
<li><strong>Resultado:</strong> Aprovado ✅, Em análise 🟡, ou Reenviar ❌</li>
<li><strong>Dados extraídos:</strong> Salvos no banco para inclusão no dossiê</li>
</ol>
<div class="box warning">
<h4>⚠️ Documento 6 — Contrato de Arrendamento</h4>
<p>Este documento só é necessário se o produtor <strong>não for proprietário</strong> da terra. Se for dono, pode usar <span class="cmd">/pular</span> para ir ao próximo.</p>
</div>
<div class="box">
<h4>✨ Documento 8 — Declaração de Não Desmatamento</h4>
<p>Este documento é <strong>gerado automaticamente</strong> pelo sistema. O produtor não precisa providenciar — o DocuAgro cria a autodeclaração com base nos dados cadastrados.</p>
</div>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 7</span></div>
</div>
<!-- PÁG 8 — IA -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>6. Inteligência Artificial</h2>
<span class="pg">08</span>
</div>
<p>O DocuAgro utiliza o modelo <strong>GPT-4o-mini</strong> da OpenAI, configurado como um especialista em documentação agrícola brasileira e compliance EUDR.</p>
<h3>🧠 Como a IA funciona</h3>
<h4>Personalidade</h4>
<ul>
<li>Fala de forma <strong>simples e direta</strong>, como se conversasse com um produtor rural</li>
<li>Usa linguagem do campo: "tá certinho", "beleza", "vamos lá"</li>
<li>É <strong>paciente</strong> — muitos produtores não estão acostumados com tecnologia</li>
<li>Sempre <strong>encoraja</strong>: "tá quase lá!", "mais um pouquinho e fica pronto"</li>
<li>Respostas curtas (máx. 3-4 parágrafos)</li>
</ul>
<h4>Contexto Dinâmico</h4>
<p>A cada mensagem, a IA recebe o contexto completo do produtor:</p>
<ul>
<li>Dados pessoais (nome, CPF, propriedade, município)</li>
<li>Etapa atual do processo</li>
<li>Documentos já enviados e seus status</li>
<li>Próximo documento esperado</li>
<li>Histórico das últimas 10 mensagens</li>
</ul>
<h4>Extração Inteligente de Dados</h4>
<p>Durante o onboarding, a IA usa uma segunda chamada ao GPT para <strong>extrair dados estruturados</strong> das mensagens do produtor (nome, CPF, município, etc.) e salvar automaticamente no banco.</p>
<h4>Orientação para Obter Documentos</h4>
<p>A IA sabe orientar o produtor sobre <strong>como e onde obter</strong> cada documento:</p>
<div class="chat">
<div class="msg user">Não tenho o CCIR, como faço?</div>
<div class="msg bot">O CCIR sai pelo site do INCRA (sncr.serpro.gov.br). Se sua propriedade já tá cadastrada, é só imprimir. Senão, precisa ir no INCRA mais perto. Quer que eu explique o passo a passo? 😊</div>
</div>
<h3>🔧 Configuração Técnica</h3>
<table>
<thead><tr><th>Parâmetro</th><th>Valor</th><th>Motivo</th></tr></thead>
<tbody>
<tr><td>Modelo</td><td>gpt-4o-mini</td><td>Custo baixo, boa qualidade</td></tr>
<tr><td>Temperature</td><td>0.7</td><td>Respostas naturais mas consistentes</td></tr>
<tr><td>Max tokens</td><td>800</td><td>Respostas curtas e diretas</td></tr>
<tr><td>Presence penalty</td><td>0.1</td><td>Evita repetição</td></tr>
</tbody>
</table>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 8</span></div>
</div>
<!-- PÁG 9 — PAINEL COOPERATIVA -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>7. Guia da Cooperativa — Painel Web</h2>
<span class="pg">09</span>
</div>
<p>A cooperativa ou trading acompanha todos os produtores pelo <strong>Painel Web</strong>, acessível de qualquer navegador.</p>
<h3>📊 Dashboard</h3>
<p>A tela inicial mostra 5 indicadores em tempo real:</p>
<table>
<thead><tr><th>Indicador</th><th>Descrição</th></tr></thead>
<tbody>
<tr><td>👥 Total de Produtores</td><td>Quantos produtores estão cadastrados</td></tr>
<tr><td>✅ Completos</td><td>Produtores com todos os docs aprovados</td></tr>
<tr><td>📋 Em Andamento</td><td>Produtores enviando documentos</td></tr>
<tr><td>⚠️ Pendentes</td><td>Produtores que não iniciaram ou pararam</td></tr>
<tr><td>📄 Documentos Recebidos</td><td>Total de documentos no sistema</td></tr>
</tbody>
</table>
<p>Abaixo do dashboard há a <strong>barra de Compliance EUDR Geral</strong> — mostra o percentual de produtores em conformidade.</p>
<h3>👥 Lista de Produtores</h3>
<p>Tabela com todos os produtores cadastrados, mostrando:</p>
<ul>
<li><strong>Nome</strong> e CPF</li>
<li><strong>Propriedade</strong> e município/UF</li>
<li><strong>Documentos:</strong> indicadores visuais (□ = não enviado, ■ = enviado/aprovado) — X/8</li>
<li><strong>Status:</strong> Pendente, Em Andamento, Completo</li>
<li><strong>Ações:</strong> botões "Ver" (detalhes) e "Dossiê" (gerar PDF)</li>
</ul>
<h4>🔍 Busca</h4>
<p>Campo de busca no topo da lista permite filtrar por <strong>nome, CPF, propriedade ou município</strong>.</p>
<h3>📥 Exportações</h3>
<h4>Dossiê PDF</h4>
<p>Ao clicar em "Dossiê" na lista de produtores, o sistema gera um PDF profissional com:</p>
<ul>
<li>Capa com dados do produtor e status de compliance</li>
<li>Página de dados pessoais e da propriedade</li>
<li>Resumo visual de todos os documentos</li>
<li>Detalhe de cada documento (status, dados extraídos, miniatura da imagem)</li>
<li>Declaração de conformidade EUDR com espaço para assinatura</li>
</ul>
<h4>Exportar CSV</h4>
<p>O botão "Exportar CSV" gera uma planilha com todos os produtores — nome, CPF, propriedade, município, estado, área, cultura, status e progresso. Ideal para importar em ERPs ou planilhas.</p>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 9</span></div>
</div>
<!-- PÁG 10 — API REST -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>8. API REST</h2>
<span class="pg">10</span>
</div>
<p>Todos os dados do DocuAgro são acessíveis via API REST para integração com sistemas externos.</p>
<table>
<thead><tr><th>Endpoint</th><th>Método</th><th>Descrição</th><th>Retorno</th></tr></thead>
<tbody>
<tr><td><span class="cmd">/api/health</span></td><td>GET</td><td>Health check do sistema</td><td>Status, versão, timestamp</td></tr>
<tr><td><span class="cmd">/api/dashboard</span></td><td>GET</td><td>Estatísticas gerais</td><td>Total produtores, completos, pendentes, docs</td></tr>
<tr><td><span class="cmd">/api/produtores</span></td><td>GET</td><td>Listar todos os produtores</td><td>Array com dados e status de cada um</td></tr>
<tr><td><span class="cmd">/api/produtores/:id</span></td><td>GET</td><td>Detalhe de um produtor</td><td>Dados + documentos + último dossiê</td></tr>
<tr><td><span class="cmd">/api/produtores/:id/dossie</span></td><td>POST</td><td>Gerar dossiê PDF</td><td>Caminho do arquivo gerado</td></tr>
<tr><td><span class="cmd">/api/dossie/download/:arquivo</span></td><td>GET</td><td>Download do dossiê</td><td>Arquivo PDF</td></tr>
<tr><td><span class="cmd">/api/exportar/csv</span></td><td>GET</td><td>Exportar todos em CSV</td><td>Arquivo CSV</td></tr>
</tbody>
</table>
<h3>📡 Exemplos de Uso</h3>
<div class="code-block">
<span class="comment"># Health check</span><br>
curl http://localhost:3100/api/health<br><br>
<span class="comment"># Dashboard</span><br>
curl http://localhost:3100/api/dashboard<br><br>
<span class="comment"># Listar produtores</span><br>
curl http://localhost:3100/api/produtores<br><br>
<span class="comment"># Gerar dossiê de um produtor</span><br>
curl -X POST http://localhost:3100/api/produtores/PROD_ID/dossie<br><br>
<span class="comment"># Exportar CSV</span><br>
curl -o produtores.csv http://localhost:3100/api/exportar/csv
</div>
<div class="box warning">
<h4>⚠️ Segurança da API (MVP)</h4>
<p>No MVP, a API <strong>não possui autenticação</strong>. Para produção, será necessário implementar JWT, rate limiting e HTTPS. Consulte o roadmap de segurança.</p>
</div>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 10</span></div>
</div>
<!-- PÁG 11 — DOSSIÊ -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>9. Dossiê PDF</h2>
<span class="pg">11</span>
</div>
<p>O dossiê é o produto final do DocuAgro — um PDF profissional que reúne toda a documentação do produtor para fins de compliance EUDR.</p>
<h3>📄 Estrutura do Dossiê</h3>
<table>
<thead><tr><th>Seção</th><th>Conteúdo</th></tr></thead>
<tbody>
<tr><td><strong>Capa</strong></td><td>Logo DocuAgro, nome do produtor, propriedade, status de compliance, data</td></tr>
<tr><td><strong>Dados do Produtor</strong></td><td>Nome, CPF, propriedade, município, estado, área, cultura, data de cadastro</td></tr>
<tr><td><strong>Resumo dos Documentos</strong></td><td>Tabela com todos os 8 documentos, status e data de envio</td></tr>
<tr><td><strong>Detalhes (por doc)</strong></td><td>Status, arquivo, dados extraídos pelo OCR, resultado da validação, miniatura</td></tr>
<tr><td><strong>Declaração Final</strong></td><td>Declaração de conformidade EUDR com espaço para assinatura</td></tr>
<tr><td><strong>Rodapé</strong></td><td>Número da página em todas as páginas</td></tr>
</tbody>
</table>
<h3>🎨 Visual</h3>
<p>O dossiê usa um tema profissional verde com:</p>
<ul>
<li>Capa com fundo verde gradiente e dados do produtor</li>
<li>Badge de status: "✅ COMPLIANCE COMPLETO" ou "⚠️ EM ANDAMENTO"</li>
<li>Tabela com cores alternadas e indicadores visuais por status</li>
<li>Miniaturas das imagens dos documentos enviados</li>
<li>Declaração formal citando o Regulamento (UE) 2023/1115</li>
</ul>
<h3>📋 Geração</h3>
<p>O dossiê pode ser gerado de 3 formas:</p>
<ol>
<li><strong>Pelo produtor:</strong> comando <span class="cmd">/dossie</span> no bot Telegram</li>
<li><strong>Pela cooperativa:</strong> botão "Dossiê" no painel web</li>
<li><strong>Via API:</strong> <span class="cmd">POST /api/produtores/:id/dossie</span></li>
</ol>
<p>O PDF é gerado com <strong>PDFKit</strong> e salvo em <span class="cmd">uploads/dossies/</span>. O nome do arquivo segue o padrão: <span class="cmd">dossie_[CPF]_[data_hora].pdf</span></p>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 11</span></div>
</div>
<!-- PÁG 12 — INSTALAÇÃO -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>10. Instalação e Configuração</h2>
<span class="pg">12</span>
</div>
<h3>📋 Pré-requisitos</h3>
<ul>
<li><strong>Node.js 18+</strong></li>
<li><strong>Token do Bot Telegram</strong> (criar com @BotFather no Telegram)</li>
<li><strong>Chave API OpenAI</strong> (platform.openai.com)</li>
</ul>
<h3>🚀 Setup</h3>
<div class="code-block">
<span class="comment"># 1. Clonar repositório</span><br>
git clone http://137.184.77.7:3000/bigtux/docuagro.git<br>
cd docuagro<br><br>
<span class="comment"># 2. Instalar dependências</span><br>
npm install<br><br>
<span class="comment"># 3. Configurar variáveis de ambiente</span><br>
cp .env.example .env<br>
nano .env &nbsp;&nbsp;<span class="comment"># Preencher tokens</span><br><br>
<span class="comment"># 4. Criar banco de dados</span><br>
npm run setup<br><br>
<span class="comment"># 5. Iniciar</span><br>
npm start
</div>
<h3>⚙️ Arquivo .env</h3>
<div class="code-block">
<span class="comment"># Bot Telegram</span><br>
TELEGRAM_BOT_TOKEN=123456:ABC-DEF...<br><br>
<span class="comment"># OpenAI API</span><br>
OPENAI_API_KEY=sk-...<br>
OPENAI_MODEL=gpt-4o-mini<br><br>
<span class="comment"># Servidor</span><br>
PORT=3100<br><br>
<span class="comment"># Banco de dados</span><br>
DB_PATH=./data/docuagro.db<br><br>
<span class="comment"># Uploads</span><br>
UPLOAD_DIR=./uploads
</div>
<h3>🔄 Rodar com PM2 (Produção)</h3>
<div class="code-block">
<span class="comment"># Iniciar com PM2</span><br>
npx pm2 start src/index.js --name docuagro<br><br>
<span class="comment"># Ver logs</span><br>
npx pm2 logs docuagro<br><br>
<span class="comment"># Reiniciar</span><br>
npx pm2 restart docuagro<br><br>
<span class="comment"># Parar</span><br>
npx pm2 stop docuagro
</div>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 12</span></div>
</div>
<!-- PÁG 13 — ARQUITETURA -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>11. Arquitetura Técnica</h2>
<span class="pg">13</span>
</div>
<h3>🛠 Stack</h3>
<div style="margin: 10px 0;">
<span class="badge">Node.js 18+</span>
<span class="badge">Telegraf 4.16</span>
<span class="badge">Express.js 4</span>
<span class="badge">OpenAI GPT-4o-mini</span>
<span class="badge">Tesseract.js</span>
<span class="badge">PDFKit</span>
<span class="badge">SQLite (better-sqlite3)</span>
<span class="badge">HTML/CSS/JS</span>
</div>
<h3>📁 Estrutura de Pastas</h3>
<div class="code-block">
docuagro/<br>
├── src/<br>
&nbsp;&nbsp; ├── index.js &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">← Entry point (Express + Bot)</span><br>
&nbsp;&nbsp; ├── setup-db.js &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">← Criação do banco SQLite</span><br>
&nbsp;&nbsp; ├── bot/<br>
&nbsp;&nbsp;&nbsp;&nbsp; └── telegram-bot.js &nbsp;&nbsp;<span class="comment">← Bot Telegram (Telegraf)</span><br>
&nbsp;&nbsp; ├── api/<br>
&nbsp;&nbsp;&nbsp;&nbsp; └── routes.js &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">← API REST (Express)</span><br>
&nbsp;&nbsp; └── services/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ├── ai-service.js &nbsp;&nbsp;&nbsp;<span class="comment">← Integração OpenAI</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ├── ocr-service.js &nbsp;&nbsp;<span class="comment">← OCR (Tesseract.js)</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ├── pdf-service.js &nbsp;&nbsp;<span class="comment">← Geração de dossiê PDF</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ├── database.js &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">← Operações SQLite</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; └── system-prompt.js <span class="comment">← Prompt EUDR da IA</span><br>
├── public/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">← Painel web (HTML/CSS/JS)</span><br>
├── data/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">← Banco SQLite</span><br>
├── uploads/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">← Documentos dos produtores</span><br>
├── logos/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">← Logo oficial</span><br>
└── docs/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">← Documentação e manuais</span>
</div>
<h3>💾 Banco de Dados (SQLite)</h3>
<table>
<thead><tr><th>Tabela</th><th>Função</th><th>Campos principais</th></tr></thead>
<tbody>
<tr><td><strong>cooperativas</strong></td><td>Cooperativas cadastradas</td><td>id, nome, cnpj, contato</td></tr>
<tr><td><strong>produtores</strong></td><td>Produtores rurais</td><td>id, nome, cpf, propriedade, município, cultura, etapa_atual, status</td></tr>
<tr><td><strong>documentos</strong></td><td>Documentos enviados</td><td>id, produtor_id, tipo, status, arquivo_path, dados_extraidos</td></tr>
<tr><td><strong>conversas</strong></td><td>Histórico de mensagens</td><td>id, produtor_id, role, conteudo, timestamp</td></tr>
<tr><td><strong>dossies</strong></td><td>Dossiês gerados</td><td>id, produtor_id, arquivo_path, docs_incluidos</td></tr>
</tbody>
</table>
<h3>🔐 Segurança</h3>
<ul>
<li>Cada produtor tem <strong>diretório isolado</strong> de uploads</li>
<li><strong>Helmet</strong> + <strong>CORS</strong> configurados no Express</li>
<li>Armazenamento <strong>local</strong> (sem cloud pública)</li>
<li><strong>Roadmap:</strong> JWT, HTTPS, rate limiting, criptografia, backups</li>
</ul>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 13</span></div>
</div>
<!-- PÁG 14 — FAQ -->
<div class="page interna">
<div class="header-bar">
<span class="brand">🌱 DocuAgro</span>
<h2>12. FAQ e Troubleshooting</h2>
<span class="pg">14</span>
</div>
<h3>❓ Perguntas Frequentes</h3>
<h4>O produtor precisa instalar algum app?</h4>
<p>Não. O DocuAgro funciona 100% pelo <strong>Telegram</strong>, que a maioria já tem instalado.</p>
<h4>Funciona pelo WhatsApp?</h4>
<p>No momento não. O WhatsApp está no roadmap (v2.0). Atualmente funciona apenas pelo Telegram.</p>
<h4>Quanto custa para o produtor?</h4>
<p>O modelo é <strong>B2B</strong> — a cooperativa paga e oferece o serviço aos seus associados. O produtor não paga nada.</p>
<h4>Os documentos ficam seguros?</h4>
<p>Sim. São armazenados em servidor próprio, em diretórios isolados por produtor. Não são enviados para cloud pública.</p>
<h4>E se o produtor parar no meio?</h4>
<p>O progresso é salvo automaticamente. Ele pode voltar a qualquer momento e continuar de onde parou.</p>
<h4>A IA pode errar na validação?</h4>
<p>O OCR faz validação inicial automatizada. Documentos com confiança baixa são marcados como "Em análise" para verificação manual pela cooperativa.</p>
<h4>Quantos produtores o sistema aguenta?</h4>
<p>O SQLite suporta até centenas de milhares de registros. Para escala maior (10k+ produtores simultâneos), recomenda-se migrar para PostgreSQL.</p>
<h3>🔧 Troubleshooting</h3>
<table>
<thead><tr><th>Problema</th><th>Solução</th></tr></thead>
<tbody>
<tr><td>Bot não responde</td><td>Verificar se o processo está rodando: <span class="cmd">npx pm2 status</span></td></tr>
<tr><td>Erro 409 (Conflict)</td><td>Duas instâncias rodando. Matar todas e reiniciar: <span class="cmd">npx pm2 delete docuagro && npx pm2 start src/index.js --name docuagro</span></td></tr>
<tr><td>Token inválido (401)</td><td>Verificar TELEGRAM_BOT_TOKEN no arquivo .env</td></tr>
<tr><td>IA não responde</td><td>Verificar OPENAI_API_KEY e saldo da conta OpenAI</td></tr>
<tr><td>OCR com confiança baixa</td><td>Pedir ao produtor foto com melhor iluminação e enquadramento</td></tr>
<tr><td>Painel não carrega</td><td>Verificar se a porta 3100 está acessível: <span class="cmd">curl localhost:3100/api/health</span></td></tr>
<tr><td>Banco corrompido</td><td>Fazer backup e recriar: <span class="cmd">npm run setup</span></td></tr>
</tbody>
</table>
<div style="text-align:center; margin-top:40px; padding-top:20px; border-top:2px solid #e0e0e0;">
<p style="font-size:22px; font-weight:700; color:#1B5E20;">🌱 DocuAgro</p>
<p style="font-size:14px; color:#666;">Compliance do produtor, na palma da mão.</p>
<p style="font-size:12px; color:#999; margin-top:12px;">AI Vertice • aivertice.com • 2026</p>
<p style="font-size:11px; color:#bbb; margin-top:8px;">Dúvidas? Suporte técnico disponível.</p>
</div>
<div class="footer"><span>DocuAgro — Manual Completo</span><span>AI Vertice</span><span>Página 14</span></div>
</div>
</body>
</html>

BIN
docs/manual-docuagro.pdf Normal file

Binary file not shown.

View File

@@ -0,0 +1,690 @@
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>DocuAgro - Pitch Deck</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Inter', sans-serif; color: #1a1a2e; background: #fff; }
.slide { page-break-after: always; min-height: 100vh; position: relative; padding: 60px 70px; display: flex; flex-direction: column; }
.slide:last-child { page-break-after: avoid; }
/* CAPA */
.capa { background: linear-gradient(135deg, #0d3311 0%, #1B5E20 30%, #2E7D32 60%, #43A047 100%); color: white; justify-content: center; align-items: center; text-align: center; }
.capa .logo-icon { font-size: 80px; margin-bottom: 15px; }
.capa h1 { font-size: 64px; font-weight: 900; letter-spacing: -2px; }
.capa .tagline { font-size: 22px; font-weight: 300; opacity: 0.85; margin: 8px 0 40px; }
.capa .subtitle-box { background: rgba(255,255,255,0.12); padding: 18px 50px; border-radius: 14px; font-size: 20px; font-weight: 500; line-height: 1.6; }
.capa .bottom-info { position: absolute; bottom: 40px; font-size: 13px; opacity: 0.5; }
/* SLIDE COMUM */
.slide-header { margin-bottom: 35px; }
.slide-header .slide-num { font-size: 12px; color: #2E7D32; font-weight: 700; letter-spacing: 3px; text-transform: uppercase; margin-bottom: 8px; }
.slide-header h2 { font-size: 36px; font-weight: 800; color: #1B5E20; line-height: 1.2; }
.slide-header .subtitle { font-size: 16px; color: #666; margin-top: 8px; font-weight: 400; }
h3 { font-size: 20px; font-weight: 700; color: #2E7D32; margin: 22px 0 12px; }
p { font-size: 15px; color: #444; line-height: 1.7; margin-bottom: 12px; }
ul { padding-left: 22px; margin: 8px 0 14px; }
li { font-size: 14.5px; color: #444; margin-bottom: 6px; line-height: 1.6; }
/* CARDS */
.cards { display: grid; gap: 18px; margin: 16px 0; }
.cards-2 { grid-template-columns: 1fr 1fr; }
.cards-3 { grid-template-columns: 1fr 1fr 1fr; }
.cards-4 { grid-template-columns: 1fr 1fr 1fr 1fr; }
.card { background: #f8faf8; border: 1px solid #e0e8e0; border-radius: 14px; padding: 22px 24px; }
.card.green { border-left: 5px solid #2E7D32; }
.card.red { border-left: 5px solid #d32f2f; background: #fef9f9; border-color: #f5dede; }
.card.orange { border-left: 5px solid #f57c00; background: #fffaf5; border-color: #ffe0b2; }
.card.blue { border-left: 5px solid #1565c0; background: #f5f9ff; border-color: #bbdefb; }
.card .card-icon { font-size: 32px; margin-bottom: 10px; }
.card .card-title { font-size: 16px; font-weight: 700; color: #1B5E20; margin-bottom: 6px; }
.card.red .card-title { color: #c62828; }
.card.orange .card-title { color: #e65100; }
.card.blue .card-title { color: #0d47a1; }
.card .card-desc { font-size: 13px; color: #555; line-height: 1.5; }
/* HIGHLIGHT */
.highlight { background: linear-gradient(135deg, #e8f5e9, #f1f8e9); border: 2px solid #a5d6a7; border-radius: 14px; padding: 24px 30px; margin: 18px 0; }
.highlight.big { text-align: center; padding: 30px 40px; }
.highlight .big-number { font-size: 48px; font-weight: 900; color: #1B5E20; }
.highlight .big-label { font-size: 16px; color: #333; margin-top: 4px; }
/* TABELA */
table { width: 100%; border-collapse: collapse; margin: 14px 0; }
thead th { background: #1B5E20; color: white; padding: 12px 16px; text-align: left; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; }
tbody td { padding: 11px 16px; border-bottom: 1px solid #e8e8e8; font-size: 14px; color: #333; }
tbody tr:nth-child(even) { background: #f9fdf9; }
.price { font-size: 22px; font-weight: 800; color: #1B5E20; }
.price-sm { font-size: 13px; color: #666; font-weight: 400; }
/* FLUXO */
.flow { display: flex; align-items: flex-start; gap: 10px; margin: 20px 0; justify-content: center; }
.flow-step { text-align: center; flex: 1; max-width: 160px; }
.flow-step .flow-icon { font-size: 36px; margin-bottom: 6px; }
.flow-step .flow-num { width: 30px; height: 30px; background: #2E7D32; color: white; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-weight: 700; font-size: 14px; margin-bottom: 6px; }
.flow-step .flow-title { font-size: 13px; font-weight: 700; color: #1B5E20; }
.flow-step .flow-desc { font-size: 11px; color: #777; margin-top: 3px; }
.flow-arrow { font-size: 20px; color: #a5d6a7; margin-top: 20px; }
/* QUOTE */
.quote { border-left: 4px solid #2E7D32; padding: 16px 24px; margin: 18px 0; background: #f8faf8; border-radius: 0 12px 12px 0; }
.quote p { font-size: 18px; font-weight: 500; color: #1B5E20; font-style: italic; margin: 0; }
.quote .author { font-size: 13px; color: #888; margin-top: 8px; font-style: normal; }
/* RODAPÉ */
.slide-footer { position: absolute; bottom: 25px; left: 70px; right: 70px; display: flex; justify-content: space-between; font-size: 10px; color: #ccc; }
/* BADGE */
.badge { display: inline-block; padding: 4px 14px; border-radius: 20px; font-size: 12px; font-weight: 600; }
.badge-green { background: #e8f5e9; color: #1B5E20; border: 1px solid #a5d6a7; }
.badge-red { background: #ffebee; color: #c62828; border: 1px solid #ef9a9a; }
.badge-blue { background: #e3f2fd; color: #0d47a1; border: 1px solid #90caf9; }
/* TIMELINE */
.timeline { position: relative; padding-left: 35px; margin: 16px 0; }
.timeline::before { content: ''; position: absolute; left: 10px; top: 0; bottom: 0; width: 3px; background: #c8e6c9; border-radius: 2px; }
.tl-item { position: relative; margin-bottom: 18px; }
.tl-item::before { content: ''; position: absolute; left: -30px; top: 4px; width: 14px; height: 14px; background: #2E7D32; border-radius: 50%; border: 3px solid #e8f5e9; }
.tl-item .tl-title { font-size: 15px; font-weight: 700; color: #1B5E20; }
.tl-item .tl-desc { font-size: 13px; color: #666; margin-top: 3px; }
/* GRID NUMEROS */
.num-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin: 16px 0; }
.num-box { text-align: center; padding: 20px 12px; background: #f8faf8; border-radius: 12px; border: 1px solid #e0e8e0; }
.num-box .num { font-size: 36px; font-weight: 900; color: #1B5E20; }
.num-box .label { font-size: 12px; color: #666; margin-top: 4px; }
</style>
</head>
<body>
<!-- SLIDE 1 — CAPA -->
<div class="slide capa">
<div class="logo-icon">🌱</div>
<h1>DocuAgro</h1>
<div class="tagline">Compliance do produtor, na palma da mão.</div>
<div class="subtitle-box">
Plataforma de compliance EUDR para o agronegócio brasileiro<br>
Bot Telegram + IA + Painel Web
</div>
<div class="bottom-info">AI Vertice • Pitch Confidencial • Fevereiro 2026</div>
</div>
<!-- SLIDE 2 — O PROBLEMA -->
<div class="slide">
<div class="slide-header">
<div class="slide-num">01 — O Problema</div>
<h2>O EUDR vai bloquear<br>exportações brasileiras</h2>
</div>
<p style="font-size:17px;">O Regulamento <strong>(UE) 2023/1115</strong> proíbe a importação na Europa de commodities produzidas em áreas desmatadas após dezembro de 2020. <strong>Sem compliance, sem exportação.</strong></p>
<div class="cards cards-4" style="margin-top:20px;">
<div class="card red">
<div class="card-icon">🫘</div>
<div class="card-title">Soja</div>
<div class="card-desc">Maior exportação BR para UE</div>
</div>
<div class="card red">
<div class="card-icon"></div>
<div class="card-title">Café</div>
<div class="card-desc">Brasil = #1 mundial</div>
</div>
<div class="card red">
<div class="card-icon">🐄</div>
<div class="card-title">Gado</div>
<div class="card-desc">Carne bovina, couro</div>
</div>
<div class="card red">
<div class="card-icon">🌳</div>
<div class="card-title">+ Cacau, Madeira, Borracha, Óleo de Palma</div>
<div class="card-desc">7 commodities afetadas</div>
</div>
</div>
<h3>😰 O desafio da "Última Milha"</h3>
<div class="cards cards-2">
<div class="card orange">
<div class="card-icon">📋</div>
<div class="card-title">8 documentos por produtor</div>
<div class="card-desc">CAR, CCIR, ITR, Georreferenciamento, Licença Ambiental, Contrato, NF, Declaração — de CADA produtor individual.</div>
</div>
<div class="card orange">
<div class="card-icon">👨‍🌾</div>
<div class="card-title">Milhares de produtores</div>
<div class="card-desc">Uma cooperativa grande tem 2.000-10.000 associados. Coletar documentos de todos manualmente? Impossível.</div>
</div>
</div>
<div class="quote">
<p>"Uma cooperativa com 1.000 produtores precisaria de 8.000 documentos coletados, validados e organizados. Manualmente, isso levaria meses e custaria uma fortuna."</p>
</div>
<div class="slide-footer"><span>DocuAgro — AI Vertice</span><span>Confidencial</span></div>
</div>
<!-- SLIDE 3 — O MERCADO -->
<div class="slide">
<div class="slide-header">
<div class="slide-num">02 — O Mercado</div>
<h2>Um mercado bilionário<br>que precisa de solução</h2>
</div>
<div class="num-grid">
<div class="num-box">
<div class="num">5.7M</div>
<div class="label">Propriedades rurais no Brasil</div>
</div>
<div class="num-box">
<div class="num">1.500+</div>
<div class="label">Cooperativas agropecuárias</div>
</div>
<div class="num-box">
<div class="num">€8 bi</div>
<div class="label">Exportações BR→UE afetadas</div>
</div>
<div class="num-box">
<div class="num">2026</div>
<div class="label">Prazo de conformidade</div>
</div>
</div>
<h3>🎯 Mercado-Alvo Imediato</h3>
<table>
<thead><tr><th>Segmento</th><th>Cooperativas</th><th>Produtores</th><th>Ticket médio/mês</th></tr></thead>
<tbody>
<tr><td><strong>Soja</strong> (MT, PR, GO, MS)</td><td>~200</td><td>~500K</td><td>R$ 1.500 - 4.000</td></tr>
<tr><td><strong>Café</strong> (MG, SP, ES, PR)</td><td>~150</td><td>~300K</td><td>R$ 1.000 - 3.000</td></tr>
<tr><td><strong>Gado</strong> (MT, GO, MS, PA)</td><td>~100</td><td>~200K</td><td>R$ 1.500 - 4.000</td></tr>
<tr><td><strong>Cacau/Madeira/Outros</strong></td><td>~100</td><td>~100K</td><td>R$ 500 - 2.000</td></tr>
</tbody>
</table>
<div class="highlight big">
<div class="big-number">R$ 50M+/ano</div>
<div class="big-label">TAM (Total Addressable Market) estimado para compliance EUDR no Brasil</div>
</div>
<div class="slide-footer"><span>DocuAgro — AI Vertice</span><span>Confidencial</span></div>
</div>
<!-- SLIDE 4 — A SOLUÇÃO -->
<div class="slide">
<div class="slide-header">
<div class="slide-num">03 — A Solução</div>
<h2>DocuAgro: compliance EUDR<br>numa conversa de Telegram</h2>
</div>
<p style="font-size:17px;">Transformamos um processo burocrático de semanas em uma <strong>conversa de 30 minutos</strong> pelo Telegram.</p>
<div class="flow">
<div class="flow-step">
<div class="flow-icon">📱</div>
<div class="flow-num">1</div>
<div class="flow-title">Produtor abre o Bot</div>
<div class="flow-desc">Telegram, sem instalar nada</div>
</div>
<div class="flow-arrow"></div>
<div class="flow-step">
<div class="flow-icon">🤖</div>
<div class="flow-num">2</div>
<div class="flow-title">IA guia a coleta</div>
<div class="flow-desc">Linguagem do campo</div>
</div>
<div class="flow-arrow"></div>
<div class="flow-step">
<div class="flow-icon">📄</div>
<div class="flow-num">3</div>
<div class="flow-title">Envia documentos</div>
<div class="flow-desc">Foto ou PDF, um por vez</div>
</div>
<div class="flow-arrow"></div>
<div class="flow-step">
<div class="flow-icon">🔍</div>
<div class="flow-num">4</div>
<div class="flow-title">Validação OCR</div>
<div class="flow-desc">Automática por IA</div>
</div>
<div class="flow-arrow"></div>
<div class="flow-step">
<div class="flow-icon"></div>
<div class="flow-num">5</div>
<div class="flow-title">Dossiê PDF</div>
<div class="flow-desc">Pronto para auditoria</div>
</div>
</div>
<h3>💡 Por que funciona</h3>
<div class="cards cards-3">
<div class="card green">
<div class="card-icon">💬</div>
<div class="card-title">Zero Fricção</div>
<div class="card-desc">Via Telegram — o produtor já tem. Sem app novo, sem login complicado, sem treinamento.</div>
</div>
<div class="card green">
<div class="card-icon">🧠</div>
<div class="card-title">IA que fala "do campo"</div>
<div class="card-desc">A inteligência artificial usa linguagem simples: "tá certinho", "beleza". Guia, orienta e valida com paciência.</div>
</div>
<div class="card green">
<div class="card-icon">📊</div>
<div class="card-title">Painel da Cooperativa</div>
<div class="card-desc">Dashboard em tempo real. A cooperativa vê o status de cada produtor, gera dossiês e exporta relatórios.</div>
</div>
</div>
<div class="quote">
<p>"O produtor manda foto pelo Telegram. A IA valida. A cooperativa recebe o dossiê pronto. Simples assim."</p>
</div>
<div class="slide-footer"><span>DocuAgro — AI Vertice</span><span>Confidencial</span></div>
</div>
<!-- SLIDE 5 — PRODUTO (DETALHES) -->
<div class="slide">
<div class="slide-header">
<div class="slide-num">04 — O Produto</div>
<h2>Dois lados, uma plataforma</h2>
</div>
<div class="cards cards-2" style="margin-top:10px;">
<div class="card green" style="padding:28px;">
<div class="card-icon">👨‍🌾</div>
<div class="card-title" style="font-size:20px;">Lado do Produtor</div>
<div class="card-desc" style="font-size:14px; margin-top:12px;">
<strong>Bot Telegram @docuagro_bot</strong><br><br>
✅ Cadastro guiado por IA (nome, CPF, propriedade)<br>
✅ Coleta de 8 documentos, um por vez<br>
✅ Orientação sobre cada documento (o que é, onde obter)<br>
✅ Validação automática via OCR<br>
✅ Feedback em tempo real (aprovado/reenviar)<br>
✅ Geração de dossiê PDF no chat<br>
✅ Pode parar e continuar depois<br><br>
<strong>Tempo médio: 30 minutos</strong><br>
<strong>Treinamento necessário: zero</strong>
</div>
</div>
<div class="card blue" style="padding:28px;">
<div class="card-icon">🏢</div>
<div class="card-title" style="font-size:20px;">Lado da Cooperativa</div>
<div class="card-desc" style="font-size:14px; margin-top:12px;">
<strong>Painel Web (browser)</strong><br><br>
✅ Dashboard com KPIs em tempo real<br>
✅ % de compliance EUDR geral<br>
✅ Lista de todos os produtores + busca<br>
✅ Status detalhado de cada produtor<br>
✅ Download de dossiê PDF individual<br>
✅ Exportação CSV para ERP/planilha<br>
✅ API REST para integração<br><br>
<strong>Visibilidade total</strong><br>
<strong>Sem trabalho manual</strong>
</div>
</div>
</div>
<h3>📄 8 Documentos Coletados e Validados</h3>
<div style="display:flex; flex-wrap:wrap; gap:8px; margin:10px 0;">
<span class="badge badge-green">1. CAR (SICAR)</span>
<span class="badge badge-green">2. CCIR (INCRA)</span>
<span class="badge badge-green">3. ITR (Receita)</span>
<span class="badge badge-green">4. Georreferenciamento</span>
<span class="badge badge-green">5. Licença Ambiental</span>
<span class="badge badge-green">6. Contrato Arrendamento</span>
<span class="badge badge-green">7. Nota Fiscal</span>
<span class="badge badge-blue">8. Declaração (auto-gerada)</span>
</div>
<div class="slide-footer"><span>DocuAgro — AI Vertice</span><span>Confidencial</span></div>
</div>
<!-- SLIDE 6 — DIFERENCIAL COMPETITIVO -->
<div class="slide">
<div class="slide-header">
<div class="slide-num">05 — Diferencial</div>
<h2>Por que DocuAgro<br>e não a concorrência?</h2>
</div>
<table>
<thead><tr><th></th><th>DocuAgro</th><th>Consultorias tradicionais</th><th>Planilhas + email</th></tr></thead>
<tbody>
<tr><td><strong>Canal</strong></td><td>✅ Telegram (produtor já tem)</td><td>❌ Presencial ou telefone</td><td>❌ Email (produtor não usa)</td></tr>
<tr><td><strong>Custo por produtor</strong></td><td>✅ R$ 2-5/mês</td><td>❌ R$ 50-200/produtor</td><td>❌ R$ 20-50 (mão de obra)</td></tr>
<tr><td><strong>Escala</strong></td><td>✅ 10.000+ produtores</td><td>❌ 50-100 por consultor</td><td>❌ 200-500 com equipe</td></tr>
<tr><td><strong>Validação</strong></td><td>✅ OCR automático</td><td>🟡 Manual</td><td>❌ Nenhuma</td></tr>
<tr><td><strong>Dossiê</strong></td><td>✅ PDF automático</td><td>🟡 Manual (dias)</td><td>❌ Não gera</td></tr>
<tr><td><strong>Tempo setup</strong></td><td>✅ Mesmo dia</td><td>❌ Semanas</td><td>🟡 Dias</td></tr>
<tr><td><strong>IA integrada</strong></td><td>✅ Guia e orienta</td><td>❌ Não</td><td>❌ Não</td></tr>
<tr><td><strong>Dashboard</strong></td><td>✅ Tempo real</td><td>❌ Relatórios mensais</td><td>❌ Planilha manual</td></tr>
</tbody>
</table>
<div class="highlight">
<h3 style="margin-top:0; text-align:center;">🏆 Vantagens Únicas</h3>
<div class="cards cards-3" style="margin-top:12px;">
<div style="text-align:center;">
<div style="font-size:28px;"></div>
<div style="font-weight:700; color:#1B5E20;">10x mais rápido</div>
<div style="font-size:12px; color:#666;">30 min vs semanas</div>
</div>
<div style="text-align:center;">
<div style="font-size:28px;">💰</div>
<div style="font-weight:700; color:#1B5E20;">10x mais barato</div>
<div style="font-size:12px; color:#666;">R$2/produtor vs R$50+</div>
</div>
<div style="text-align:center;">
<div style="font-size:28px;">📈</div>
<div style="font-weight:700; color:#1B5E20;">100x mais escalável</div>
<div style="font-size:12px; color:#666;">10.000+ vs 100 por pessoa</div>
</div>
</div>
</div>
<div class="slide-footer"><span>DocuAgro — AI Vertice</span><span>Confidencial</span></div>
</div>
<!-- SLIDE 7 — MODELO DE NEGÓCIO -->
<div class="slide">
<div class="slide-header">
<div class="slide-num">06 — Modelo de Negócio</div>
<h2>SaaS B2B — A cooperativa paga,<br>o produtor usa grátis</h2>
</div>
<p style="font-size:17px;">Modelo de <strong>assinatura mensal</strong> por volume de produtores. A cooperativa fornece o DocuAgro como serviço aos seus associados.</p>
<table>
<thead><tr><th>Plano</th><th>Produtores</th><th>Preço/mês</th><th>Por produtor</th><th>Inclui</th></tr></thead>
<tbody>
<tr>
<td><strong>🌱 Starter</strong></td>
<td>até 100</td>
<td><span class="price">R$ 497</span></td>
<td><span class="price-sm">R$ 4,97/produtor</span></td>
<td>Bot + Painel + Dossiês</td>
</tr>
<tr>
<td><strong>🌿 Pro</strong></td>
<td>até 500</td>
<td><span class="price">R$ 1.497</span></td>
<td><span class="price-sm">R$ 2,99/produtor</span></td>
<td>Tudo do Starter + API + CSV + Suporte</td>
</tr>
<tr>
<td><strong>🌳 Enterprise</strong></td>
<td>até 2.000</td>
<td><span class="price">R$ 3.997</span></td>
<td><span class="price-sm">R$ 2,00/produtor</span></td>
<td>Tudo do Pro + White-label + Dedicado</td>
</tr>
<tr>
<td><strong>🏔️ Custom</strong></td>
<td>2.000+</td>
<td><span class="price">Sob consulta</span></td>
<td><span class="price-sm">Negociável</span></td>
<td>Personalização total</td>
</tr>
</tbody>
</table>
<h3>💡 Argumento de Venda</h3>
<div class="quote">
<p>"Quanto custa para vocês coletarem documentos de 500 produtores manualmente? 2 funcionários dedicados = R$ 8.000/mês + encargos. O DocuAgro faz por R$ 1.497 e é 10x mais rápido."</p>
</div>
<h3>🔄 Estratégia de Entrada</h3>
<div class="cards cards-3">
<div class="card green">
<div class="card-icon">🎁</div>
<div class="card-title">1. Piloto Grátis</div>
<div class="card-desc">30 dias grátis com até 50 produtores. Sem compromisso. A cooperativa testa na prática.</div>
</div>
<div class="card green">
<div class="card-icon">📊</div>
<div class="card-title">2. Apresentar Resultados</div>
<div class="card-desc">Após 30 dias: "50 dossiês gerados, X% de compliance alcançado em 1 mês."</div>
</div>
<div class="card green">
<div class="card-icon">🚀</div>
<div class="card-title">3. Converter em Plano</div>
<div class="card-desc">Com case real, converter para assinatura mensal. Resultados vendem sozinhos.</div>
</div>
</div>
<div class="slide-footer"><span>DocuAgro — AI Vertice</span><span>Confidencial</span></div>
</div>
<!-- SLIDE 8 — PROJEÇÃO FINANCEIRA -->
<div class="slide">
<div class="slide-header">
<div class="slide-num">07 — Projeção Financeira</div>
<h2>Caminho para R$ 500K/ano<br>em 12 meses</h2>
</div>
<h3>📈 Projeção Conservadora (12 meses)</h3>
<table>
<thead><tr><th>Mês</th><th>Cooperativas</th><th>Plano médio</th><th>MRR</th><th>ARR</th></tr></thead>
<tbody>
<tr><td>Mês 1-3</td><td>2 (piloto)</td><td>Grátis</td><td>R$ 0</td><td></td></tr>
<tr><td>Mês 4</td><td>2 → pagantes</td><td>Pro (R$ 1.497)</td><td>R$ 2.994</td><td>R$ 36K</td></tr>
<tr><td>Mês 6</td><td>5</td><td>Mix Starter/Pro</td><td>R$ 5.985</td><td>R$ 72K</td></tr>
<tr><td>Mês 9</td><td>10</td><td>Mix Pro/Enterprise</td><td>R$ 19.970</td><td>R$ 240K</td></tr>
<tr><td>Mês 12</td><td>15</td><td>Mix todos</td><td>R$ 35.000</td><td><strong>R$ 420K</strong></td></tr>
</tbody>
</table>
<h3>💰 Estrutura de Custos</h3>
<div class="cards cards-2">
<div class="card green">
<div class="card-title">Custos Fixos (~R$ 2.500/mês)</div>
<div class="card-desc">
• Servidor DigitalOcean: R$ 150/mês<br>
• API OpenAI (gpt-4o-mini): R$ 500-1.500/mês<br>
• Domínio + Cloudflare: R$ 10/mês<br>
• Ferramentas: R$ 200/mês
</div>
</div>
<div class="card green">
<div class="card-title">Margem Bruta</div>
<div class="card-desc" style="font-size:16px; margin-top:10px;">
<strong>MRR R$ 35K - Custos R$ 2.5K</strong><br>
<span style="font-size:28px; font-weight:900; color:#1B5E20;">= 93% margem</span><br><br>
SaaS puro. Sem equipe de campo. Sem estoque. Escala com custo marginal mínimo.
</div>
</div>
</div>
<div class="highlight big">
<div class="big-number">R$ 420K</div>
<div class="big-label">ARR projetado no mês 12 (cenário conservador com 15 cooperativas)</div>
</div>
<div class="slide-footer"><span>DocuAgro — AI Vertice</span><span>Confidencial</span></div>
</div>
<!-- SLIDE 9 — ROADMAP -->
<div class="slide">
<div class="slide-header">
<div class="slide-num">08 — Roadmap</div>
<h2>Do MVP ao mercado</h2>
</div>
<div class="timeline">
<div class="tl-item">
<div class="tl-title">✅ MVP Pronto (Agora)</div>
<div class="tl-desc">Bot Telegram + IA (GPT-4o-mini) + OCR + PDF + Painel Web + API REST. Funcional e testado.</div>
</div>
<div class="tl-item">
<div class="tl-title">🔜 v1.1 — Segurança (Mês 1)</div>
<div class="tl-desc">Autenticação JWT no painel, HTTPS obrigatório, rate limiting na API.</div>
</div>
<div class="tl-item">
<div class="tl-title">🔜 v1.2 — Piloto (Mês 1-3)</div>
<div class="tl-desc">Deploy em produção. 2 cooperativas piloto (soja + café). Coleta de feedback real.</div>
</div>
<div class="tl-item">
<div class="tl-title">📋 v1.5 — Notificações (Mês 4)</div>
<div class="tl-desc">Alertas automáticos: documentos vencendo, produtores inativos, relatórios semanais para cooperativa.</div>
</div>
<div class="tl-item">
<div class="tl-title">📋 v2.0 — WhatsApp (Mês 6)</div>
<div class="tl-desc">Bot WhatsApp Business. Alcance 3x maior que Telegram no interior do Brasil.</div>
</div>
<div class="tl-item">
<div class="tl-title">📋 v2.5 — Integrações Gov (Mês 9)</div>
<div class="tl-desc">APIs do SICAR, INCRA e Receita Federal para validação cruzada automática.</div>
</div>
<div class="tl-item">
<div class="tl-title">📋 v3.0 — Multi-tenant SaaS (Mês 12)</div>
<div class="tl-desc">Cada cooperativa com ambiente isolado. Dashboard analytics avançado. White-label completo.</div>
</div>
</div>
<div class="slide-footer"><span>DocuAgro — AI Vertice</span><span>Confidencial</span></div>
</div>
<!-- SLIDE 10 — GO-TO-MARKET -->
<div class="slide">
<div class="slide-header">
<div class="slide-num">09 — Go-to-Market</div>
<h2>Como vamos chegar<br>nas cooperativas</h2>
</div>
<div class="cards cards-2">
<div class="card green" style="padding:24px;">
<div class="card-icon">🎯</div>
<div class="card-title" style="font-size:18px;">Canal Direto</div>
<div class="card-desc" style="font-size:14px; margin-top:10px;">
<strong>Abordagem ativa para cooperativas:</strong><br><br>
• Contato direto com setor de compliance/exportação<br>
• LinkedIn dos diretores de cooperativas<br>
• Webinar gratuito: "EUDR: sua cooperativa está preparada?"<br>
• Cold email segmentado por região e commodity<br>
• Visitas presenciais nas cooperativas prioritárias
</div>
</div>
<div class="card blue" style="padding:24px;">
<div class="card-icon">🤝</div>
<div class="card-title" style="font-size:18px;">Via Associações</div>
<div class="card-desc" style="font-size:14px; margin-top:10px;">
<strong>Parcerias estratégicas:</strong><br><br>
<strong>OCB</strong> (Organização das Cooperativas Brasileiras)<br>
<strong>CNA</strong> (Confederação da Agricultura)<br>
<strong>APROSOJA</strong>, <strong>CECAFÉ</strong>, associações por commodity<br>
• Feiras: <strong>Agrishow</strong>, Show Rural, Expozebu<br>
• Consultorias de compliance como parceiros de revenda
</div>
</div>
</div>
<h3>📍 Prioridade Geográfica</h3>
<table>
<thead><tr><th>Fase</th><th>Região</th><th>Commodity</th><th>Por quê</th></tr></thead>
<tbody>
<tr><td><span class="badge badge-green">Fase 1</span></td><td>Mato Grosso / Paraná</td><td>Soja</td><td>Maior volume de exportação EUDR</td></tr>
<tr><td><span class="badge badge-green">Fase 2</span></td><td>Minas Gerais / São Paulo</td><td>Café</td><td>Alta concentração de cooperativas</td></tr>
<tr><td><span class="badge badge-blue">Fase 3</span></td><td>Goiás / Mato Grosso do Sul</td><td>Gado</td><td>Pecuária de exportação</td></tr>
<tr><td><span class="badge badge-blue">Fase 4</span></td><td>Bahia / Pará</td><td>Cacau + Madeira</td><td>Complementar o portfólio</td></tr>
</tbody>
</table>
<div class="slide-footer"><span>DocuAgro — AI Vertice</span><span>Confidencial</span></div>
</div>
<!-- SLIDE 11 — EQUIPE + TECH -->
<div class="slide">
<div class="slide-header">
<div class="slide-num">10 — Tecnologia e Equipe</div>
<h2>Stack robusta,<br>equipe enxuta</h2>
</div>
<h3>🛠 Tecnologia</h3>
<div class="cards cards-4" style="margin-bottom:20px;">
<div class="card green">
<div class="card-icon">🤖</div>
<div class="card-title">IA (GPT-4o-mini)</div>
<div class="card-desc">Guia produtores, extrai dados, valida documentos</div>
</div>
<div class="card green">
<div class="card-icon">🔍</div>
<div class="card-title">OCR (Tesseract)</div>
<div class="card-desc">Extrai texto de fotos e PDFs automaticamente</div>
</div>
<div class="card green">
<div class="card-icon">📱</div>
<div class="card-title">Bot (Telegraf)</div>
<div class="card-desc">Interface do produtor via Telegram</div>
</div>
<div class="card green">
<div class="card-icon">📊</div>
<div class="card-title">Painel (Express)</div>
<div class="card-desc">Dashboard da cooperativa + API REST</div>
</div>
</div>
<div style="display:flex; flex-wrap:wrap; gap:8px; margin:10px 0;">
<span class="badge badge-green">Node.js 18+</span>
<span class="badge badge-green">Telegraf 4.16</span>
<span class="badge badge-green">Express.js</span>
<span class="badge badge-green">OpenAI API</span>
<span class="badge badge-green">Tesseract.js</span>
<span class="badge badge-green">PDFKit</span>
<span class="badge badge-green">SQLite</span>
<span class="badge badge-green">Helmet + CORS</span>
</div>
<h3>👥 Equipe</h3>
<div class="cards cards-2">
<div class="card blue" style="padding:24px;">
<div class="card-title" style="font-size:18px;">Eduardo Kislanski</div>
<div class="card-desc" style="font-size:14px; margin-top:8px;">
<strong>Fundador & CEO</strong><br>
Analista de Infraestrutura Cloud. Experiência com Azure DevOps, Docker, CI/CD. Responsável pela visão de produto e estratégia comercial.<br><br>
Também fundador da <strong>AI Vertice</strong> — empresa de soluções com IA (LexMind, MetisClass, ArgusFinance, Strix).
</div>
</div>
<div class="card blue" style="padding:24px;">
<div class="card-title" style="font-size:18px;">JARVIS (IA)</div>
<div class="card-desc" style="font-size:14px; margin-top:8px;">
<strong>CTO & Desenvolvimento</strong><br>
Sistema de IA proprietário que desenvolveu 100% do código do DocuAgro. Responsável por arquitetura, desenvolvimento, deploy e manutenção contínua.<br><br>
<em>Custo de equipe de dev: R$ 0/mês</em> 🚀
</div>
</div>
</div>
<div class="slide-footer"><span>DocuAgro — AI Vertice</span><span>Confidencial</span></div>
</div>
<!-- SLIDE 12 — CTA FINAL -->
<div class="slide" style="background: linear-gradient(135deg, #0d3311 0%, #1B5E20 30%, #2E7D32 60%, #43A047 100%); color: white; justify-content: center; align-items: center; text-align: center;">
<div style="font-size:60px; margin-bottom:20px;">🌱</div>
<h1 style="font-size:48px; font-weight:900; margin-bottom:12px; color:white;">DocuAgro</h1>
<p style="font-size:22px; opacity:0.9; color:white; margin-bottom:40px;">Compliance do produtor, na palma da mão.</p>
<div style="background: rgba(255,255,255,0.12); padding: 30px 50px; border-radius: 16px; max-width: 600px; margin-bottom:40px;">
<p style="font-size:26px; font-weight:700; color:white; margin-bottom:15px;">Próximos Passos</p>
<p style="font-size:18px; color: rgba(255,255,255,0.9); line-height:2;">
✅ MVP pronto e funcional<br>
🤝 Piloto grátis para sua cooperativa<br>
📊 Resultados em 30 dias<br>
🚀 Escale para toda a base de produtores
</p>
</div>
<p style="font-size:18px; font-weight:600; color:rgba(255,255,255,0.95);">
Quer ver uma demonstração ao vivo?
</p>
<div style="margin-top:30px;">
<p style="font-size:16px; color:rgba(255,255,255,0.7);">Eduardo Kislanski</p>
<p style="font-size:14px; color:rgba(255,255,255,0.5);">AI Vertice • aivertice.com</p>
<p style="font-size:14px; color:rgba(255,255,255,0.5);">m171c0@gmail.com • @docuagro_bot</p>
</div>
<div class="slide-footer" style="color: rgba(255,255,255,0.3);"><span>DocuAgro — AI Vertice</span><span>Confidencial • Fevereiro 2026</span></div>
</div>
</body>
</html>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

25
logos/index.html Normal file
View File

@@ -0,0 +1,25 @@
<!doctype html>
<meta charset="utf-8" />
<title>openai-image-gen</title>
<style>
:root { color-scheme: dark; }
body { margin: 24px; font: 14px/1.4 ui-sans-serif, system-ui; background: #0b0f14; color: #e8edf2; }
h1 { font-size: 18px; margin: 0 0 16px; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }
figure { margin: 0; padding: 12px; border: 1px solid #1e2a36; border-radius: 14px; background: #0f1620; }
img { width: 100%; height: auto; border-radius: 10px; display: block; }
figcaption { margin-top: 10px; color: #b7c2cc; }
code { color: #9cd1ff; }
</style>
<h1>openai-image-gen</h1>
<p>Output: <code>/home/kernelpanic/projetos_jarvis/docuagro/logos</code></p>
<div class="grid">
<figure>
<a href="001-modern-logo-icon-for-docuagro-agricultur.png"><img src="001-modern-logo-icon-for-docuagro-agricultur.png" loading="lazy" /></a>
<figcaption>Modern logo icon for DocuAgro, agricultural technology company. Design: stylized green leaf merging with a document/checkmark. Flat vector style, minimalist. Primary color dark green on white. No text. Professional corporate logo suitable for app icon.</figcaption>
</figure>
<figure>
<a href="002-modern-logo-icon-for-docuagro-agricultur.png"><img src="002-modern-logo-icon-for-docuagro-agricultur.png" loading="lazy" /></a>
<figcaption>Modern logo icon for DocuAgro, agricultural technology company. Design: stylized green leaf merging with a document/checkmark. Flat vector style, minimalist. Primary color dark green on white. No text. Professional corporate logo suitable for app icon.</figcaption>
</figure>
</div>

BIN
logos/logo-docuagro.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

10
logos/prompts.json Normal file
View File

@@ -0,0 +1,10 @@
[
{
"prompt": "Modern logo icon for DocuAgro, agricultural technology company. Design: stylized green leaf merging with a document/checkmark. Flat vector style, minimalist. Primary color dark green on white. No text. Professional corporate logo suitable for app icon.",
"file": "001-modern-logo-icon-for-docuagro-agricultur.png"
},
{
"prompt": "Modern logo icon for DocuAgro, agricultural technology company. Design: stylized green leaf merging with a document/checkmark. Flat vector style, minimalist. Primary color dark green on white. No text. Professional corporate logo suitable for app icon.",
"file": "002-modern-logo-icon-for-docuagro-agricultur.png"
}
]

3698
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

43
package.json Normal file
View File

@@ -0,0 +1,43 @@
{
"name": "docuagro",
"version": "1.0.0",
"description": "DocuAgro - Bot Telegram para compliance EUDR de produtores rurais",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"panel": "node src/panel-server.js",
"setup": "node src/setup-db.js",
"test": "node src/test.js"
},
"keywords": [
"eudr",
"compliance",
"telegram",
"bot",
"agro"
],
"author": "BigTux",
"license": "MIT",
"dependencies": {
"bcryptjs": "^3.0.3",
"better-sqlite3": "^11.7.0",
"compression": "^1.7.4",
"cors": "^2.8.5",
"dayjs": "^1.11.13",
"dotenv": "^16.4.5",
"express": "^4.21.0",
"helmet": "^8.0.0",
"jsonwebtoken": "^9.0.3",
"multer": "^1.4.5-lts.1",
"openai": "^4.73.0",
"pdfkit": "^0.15.0",
"sharp": "^0.33.5",
"telegraf": "^4.16.3",
"tesseract.js": "^5.1.1",
"uuid": "^10.0.0"
},
"devDependencies": {
"nodemon": "^3.1.7"
}
}

1098
public/index.html Normal file

File diff suppressed because it is too large Load Diff

228
src/api/routes.js Normal file
View File

@@ -0,0 +1,228 @@
/**
* DocuAgro - Rotas da API REST
* Endpoints para o painel web da cooperativa
* Com autenticação JWT
*/
const express = require('express');
const path = require('path');
const fs = require('fs');
const db = require('../services/database');
const { gerarDossie } = require('../services/pdf-service');
const { autenticarUsuario, verificarToken } = require('../services/auth-service');
const router = express.Router();
// ============================================================
// MIDDLEWARE DE AUTENTICAÇÃO JWT
// ============================================================
function authMiddleware(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({
sucesso: false,
erro: 'Token de autenticação não fornecido'
});
}
const token = authHeader.split(' ')[1];
try {
const usuario = verificarToken(token);
req.usuario = usuario;
next();
} catch (erro) {
return res.status(401).json({
sucesso: false,
erro: 'Token inválido ou expirado'
});
}
}
// ============================================================
// AUTH - Login (rota pública)
// ============================================================
router.post('/api/auth/login', async (req, res) => {
try {
const { username, senha } = req.body;
if (!username || !senha) {
return res.status(400).json({
sucesso: false,
erro: 'Username e senha são obrigatórios'
});
}
const resultado = await autenticarUsuario(username, senha);
res.json({
sucesso: true,
dados: resultado
});
} catch (erro) {
console.error('❌ Erro no login:', erro.message);
res.status(401).json({
sucesso: false,
erro: 'Credenciais inválidas'
});
}
});
// ============================================================
// HEALTH CHECK (rota pública)
// ============================================================
router.get('/api/health', (req, res) => {
res.json({
status: 'ok',
servico: 'DocuAgro API',
versao: '1.0.0',
timestamp: new Date().toISOString()
});
});
// ============================================================
// PROTEGER TODAS AS ROTAS /api/ ABAIXO COM AUTH
// ============================================================
router.use('/api', authMiddleware);
// ============================================================
// DASHBOARD - Estatísticas gerais
// ============================================================
router.get('/api/dashboard', (req, res) => {
try {
const stats = db.estatisticas();
res.json({
sucesso: true,
dados: stats
});
} catch (erro) {
console.error('❌ Erro no dashboard:', erro);
res.status(500).json({ sucesso: false, erro: 'Erro ao buscar estatísticas' });
}
});
// ============================================================
// PRODUTORES - Listagem
// ============================================================
router.get('/api/produtores', (req, res) => {
try {
const produtores = db.listarProdutores();
res.json({
sucesso: true,
dados: produtores,
total: produtores.length
});
} catch (erro) {
console.error('❌ Erro ao listar produtores:', erro);
res.status(500).json({ sucesso: false, erro: 'Erro ao listar produtores' });
}
});
// ============================================================
// PRODUTOR - Detalhe
// ============================================================
router.get('/api/produtores/:id', (req, res) => {
try {
const produtor = db.buscarProdutorPorId(req.params.id);
if (!produtor) {
return res.status(404).json({ sucesso: false, erro: 'Produtor não encontrado' });
}
const documentos = db.buscarDocumentos(produtor.id);
const ultimoDossie = db.buscarUltimoDossie(produtor.id);
res.json({
sucesso: true,
dados: {
produtor,
documentos,
ultimoDossie
}
});
} catch (erro) {
console.error('❌ Erro ao buscar produtor:', erro);
res.status(500).json({ sucesso: false, erro: 'Erro ao buscar produtor' });
}
});
// ============================================================
// DOSSIÊ - Gerar
// ============================================================
router.post('/api/produtores/:id/dossie', async (req, res) => {
try {
const produtor = db.buscarProdutorPorId(req.params.id);
if (!produtor) {
return res.status(404).json({ sucesso: false, erro: 'Produtor não encontrado' });
}
const caminhoArquivo = await gerarDossie(produtor.id);
res.json({
sucesso: true,
dados: {
arquivo: path.basename(caminhoArquivo),
caminho: `/api/dossie/download/${path.basename(caminhoArquivo)}`
}
});
} catch (erro) {
console.error('❌ Erro ao gerar dossiê:', erro);
res.status(500).json({ sucesso: false, erro: 'Erro ao gerar dossiê' });
}
});
// ============================================================
// DOSSIÊ - Download
// ============================================================
router.get('/api/dossie/download/:arquivo', (req, res) => {
try {
const uploadDir = process.env.UPLOAD_DIR || path.join(__dirname, '..', '..', 'uploads');
const caminhoArquivo = path.join(uploadDir, 'dossies', req.params.arquivo);
if (!fs.existsSync(caminhoArquivo)) {
return res.status(404).json({ sucesso: false, erro: 'Arquivo não encontrado' });
}
res.download(caminhoArquivo);
} catch (erro) {
console.error('❌ Erro no download:', erro);
res.status(500).json({ sucesso: false, erro: 'Erro no download' });
}
});
// ============================================================
// EXPORTAÇÃO CSV
// ============================================================
router.get('/api/exportar/csv', (req, res) => {
try {
const produtores = db.listarProdutores();
// Header CSV
let csv = 'Nome,CPF/CNPJ,Propriedade,Município,Estado,Área (ha),Cultura,Status,Docs Aprovados,Total Docs\n';
for (const p of produtores) {
csv += [
`"${p.nome || ''}"`,
`"${p.cpf_cnpj || ''}"`,
`"${p.propriedade_nome || ''}"`,
`"${p.propriedade_municipio || ''}"`,
`"${p.propriedade_estado || ''}"`,
p.propriedade_area_ha || '',
`"${p.cultura_principal || ''}"`,
p.status || '',
p.docs_aprovados || 0,
p.docs_total || 8
].join(',') + '\n';
}
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
res.setHeader('Content-Disposition', 'attachment; filename=docuagro_produtores.csv');
res.send(csv);
} catch (erro) {
console.error('❌ Erro na exportação CSV:', erro);
res.status(500).json({ sucesso: false, erro: 'Erro na exportação' });
}
});
module.exports = router;

488
src/bot/telegram-bot.js Normal file
View File

@@ -0,0 +1,488 @@
/**
* DocuAgro - Bot Telegram
* Núcleo do bot que interage com produtores rurais
* Coleta documentos para compliance EUDR
*/
const { Telegraf, Markup } = require('telegraf');
const path = require('path');
const fs = require('fs');
const https = require('https');
const http = require('http');
const { v4: uuidv4 } = require('uuid');
const db = require('../services/database');
const ai = require('../services/ai-service');
const ocr = require('../services/ocr-service');
const { gerarDossie } = require('../services/pdf-service');
const { TIPOS_DOCUMENTO, ORDEM_COLETA } = require('../services/system-prompt');
const UPLOAD_DIR = process.env.UPLOAD_DIR || path.join(__dirname, '..', '..', 'uploads');
// Garante que diretório de uploads existe
if (!fs.existsSync(UPLOAD_DIR)) fs.mkdirSync(UPLOAD_DIR, { recursive: true });
/**
* Inicializa e configura o bot Telegram
*/
function criarBot() {
const bot = new Telegraf(process.env.TELEGRAM_BOT_TOKEN);
// ============================================================
// COMANDO /start - Início da conversa
// ============================================================
bot.start(async (ctx) => {
try {
const chatId = ctx.chat.id;
const username = ctx.from.username;
const nome = [ctx.from.first_name, ctx.from.last_name].filter(Boolean).join(' ');
console.log(`🆕 Novo usuário: ${nome} (@${username}) - Chat: ${chatId}`);
// Verifica se já tem cadastro
let produtor = db.buscarProdutorPorChat(chatId);
if (produtor) {
// Já cadastrado - mostra status
const docs = db.buscarDocumentos(produtor.id);
const resposta = await ai.processarMensagem(produtor, 'Voltei! Como está minha documentação?', docs);
await ctx.reply(resposta);
return;
}
// Novo produtor - cria cadastro
produtor = db.criarProdutor(chatId, username, nome);
// Mensagem de boas-vindas
const boasVindas = `🌱 *Bem-vindo ao DocuAgro!*
Oi, ${nome}! Eu sou o DocuAgro, seu assistente para organizar a documentação da sua propriedade rural.
📋 *Por que isso é importante?*
A União Europeia criou uma nova regra (EUDR) que exige comprovação de que a produção não vem de área desmatada. Sem essa documentação, pode ter problema na hora de vender.
🤝 *Como funciona?*
Vou te pedir alguns documentos, um de cada vez. Pode mandar foto ou PDF. Eu confiro e te aviso se tá tudo certo.
São 8 documentos no total. Vamos começar?
Primeiro, me conta: *qual é o seu nome completo?*`;
await ctx.reply(boasVindas, { parse_mode: 'Markdown' });
} catch (erro) {
console.error('❌ Erro no /start:', erro);
await ctx.reply('Ops, tive um probleminha. Tenta de novo com /start');
}
});
// ============================================================
// COMANDO /status - Status dos documentos
// ============================================================
bot.command('status', async (ctx) => {
try {
const produtor = db.buscarProdutorPorChat(ctx.chat.id);
if (!produtor) {
await ctx.reply('Você ainda não começou! Use /start pra iniciar.');
return;
}
const docs = db.buscarDocumentos(produtor.id);
let mensagem = `📊 *Status da sua documentação*\n\n`;
mensagem += `👤 ${produtor.nome}\n`;
mensagem += `🏡 ${produtor.propriedade_nome || 'Propriedade não informada'}\n\n`;
// Lista cada documento
for (const tipo of ORDEM_COLETA) {
const doc = docs.find(d => d.tipo === tipo);
const info = TIPOS_DOCUMENTO[tipo];
let icone = '⬜';
if (doc) {
switch (doc.status) {
case 'aprovado': icone = '✅'; break;
case 'enviado':
case 'validando': icone = '🟡'; break;
case 'rejeitado': icone = '❌'; break;
case 'vencido': icone = '⚠️'; break;
}
}
mensagem += `${icone} ${info.nome}\n`;
}
mensagem += `\n📈 Progresso: ${produtor.docs_completos}/${produtor.docs_total}`;
await ctx.reply(mensagem, { parse_mode: 'Markdown' });
} catch (erro) {
console.error('❌ Erro no /status:', erro);
await ctx.reply('Erro ao buscar status. Tenta de novo.');
}
});
// ============================================================
// COMANDO /dossie - Gera dossiê PDF
// ============================================================
bot.command('dossie', async (ctx) => {
try {
const produtor = db.buscarProdutorPorChat(ctx.chat.id);
if (!produtor) {
await ctx.reply('Você ainda não começou! Use /start pra iniciar.');
return;
}
const docs = db.buscarDocumentos(produtor.id);
if (docs.length === 0) {
await ctx.reply('Você ainda não enviou nenhum documento. Vamos começar? Manda o primeiro!');
return;
}
await ctx.reply('📄 Gerando seu dossiê... Aguarda um pouquinho!');
const pdfPath = await gerarDossie(produtor.id);
await ctx.replyWithDocument(
{ source: pdfPath, filename: `Dossie_EUDR_${produtor.nome.replace(/\s+/g, '_')}.pdf` },
{ caption: '📋 Seu dossiê EUDR está pronto! Esse documento reúne toda a documentação que você enviou.' }
);
} catch (erro) {
console.error('❌ Erro no /dossie:', erro);
await ctx.reply('Erro ao gerar o dossiê. Tenta de novo daqui a pouco.');
}
});
// ============================================================
// COMANDO /ajuda - Menu de ajuda
// ============================================================
bot.command('ajuda', async (ctx) => {
const mensagem = `📚 *Ajuda - DocuAgro*
🤖 *Comandos disponíveis:*
/start - Iniciar ou recomeçar
/status - Ver status dos documentos
/dossie - Gerar dossiê PDF
/pular - Pular documento atual (se não tiver)
/ajuda - Este menu
📄 *Documentos que preciso:*
1. CAR (Cadastro Ambiental Rural)
2. CCIR (Certificado do INCRA)
3. ITR (Imposto Territorial Rural)
4. Georreferenciamento (mapa da propriedade)
5. Licença Ambiental
6. Contrato de Arrendamento (se não for dono)
7. Nota Fiscal de Venda
8. Declaração de Não Desmatamento
📸 *Dicas para enviar documentos:*
• Tire foto em lugar com boa luz
• Enquadre o documento inteiro
• PDF é melhor que foto
• Mande um documento por vez
❓ *Dúvidas?* É só mandar mensagem que eu ajudo!`;
await ctx.reply(mensagem, { parse_mode: 'Markdown' });
});
// ============================================================
// COMANDO /pular - Pula documento atual
// ============================================================
bot.command('pular', async (ctx) => {
try {
const produtor = db.buscarProdutorPorChat(ctx.chat.id);
if (!produtor) {
await ctx.reply('Use /start primeiro!');
return;
}
const tipoAtual = ai.determinarTipoDocumento(produtor);
if (!tipoAtual) {
await ctx.reply('Não tem documento pra pular agora.');
return;
}
const novaEtapa = ai.avancarEtapa(produtor);
const produtorAtualizado = db.buscarProdutorPorId(produtor.id);
const docs = db.buscarDocumentos(produtor.id);
const info = TIPOS_DOCUMENTO[tipoAtual];
await ctx.reply(`⏭️ Pulei o ${info?.nome || tipoAtual}. Pode enviar depois!`);
// Pede próximo documento
const resposta = await ai.processarMensagem(
produtorAtualizado,
'Pulei o documento anterior, qual o próximo?',
docs
);
await ctx.reply(resposta);
} catch (erro) {
console.error('❌ Erro no /pular:', erro);
await ctx.reply('Erro ao pular. Tenta de novo.');
}
});
// ============================================================
// RECEBIMENTO DE FOTOS
// ============================================================
bot.on('photo', async (ctx) => {
try {
const produtor = db.buscarProdutorPorChat(ctx.chat.id);
if (!produtor) {
await ctx.reply('Opa! Primeiro use /start pra se cadastrar, depois me manda os documentos.');
return;
}
// Pega a foto de melhor qualidade (última do array)
const foto = ctx.message.photo[ctx.message.photo.length - 1];
const fileId = foto.file_id;
// Baixa o arquivo
const file = await ctx.telegram.getFile(fileId);
const filePath = file.file_path;
const fileUrl = `https://api.telegram.org/file/bot${process.env.TELEGRAM_BOT_TOKEN}/${filePath}`;
// Salva localmente
const nomeArquivo = `${uuidv4()}${path.extname(filePath) || '.jpg'}`;
const caminhoLocal = path.join(UPLOAD_DIR, produtor.id);
if (!fs.existsSync(caminhoLocal)) fs.mkdirSync(caminhoLocal, { recursive: true });
const caminhoCompleto = path.join(caminhoLocal, nomeArquivo);
await baixarArquivo(fileUrl, caminhoCompleto);
console.log(`📸 Foto recebida de ${produtor.nome}: ${nomeArquivo}`);
// Determina tipo do documento baseado na etapa
const tipoDoc = ai.determinarTipoDocumento(produtor);
if (tipoDoc) {
// Salva documento no banco
db.salvarDocumento(produtor.id, tipoDoc, {
status: 'enviado',
arquivo_path: caminhoCompleto,
arquivo_nome: nomeArquivo,
arquivo_tipo: 'image/jpeg',
arquivo_tamanho: foto.file_size || 0
});
// OCR em background
processarOCR(produtor.id, tipoDoc, caminhoCompleto);
// Resposta da IA
const docs = db.buscarDocumentos(produtor.id);
const resposta = await ai.processarDocumento(
produtor, tipoDoc,
`Foto do ${TIPOS_DOCUMENTO[tipoDoc]?.nome}. Legenda: ${ctx.message.caption || 'sem legenda'}`
);
await ctx.reply(resposta);
// Avança para próximo documento
const novaEtapa = ai.avancarEtapa(produtor);
if (novaEtapa === 'completo') {
await ctx.reply('🎉 *Parabéns!* Você enviou todos os documentos!\n\nUse /dossie pra gerar seu dossiê completo.', { parse_mode: 'Markdown' });
}
} else {
// Não está em etapa de coleta
const docs = db.buscarDocumentos(produtor.id);
const resposta = await ai.processarMensagem(
produtor,
`Enviei uma foto. ${ctx.message.caption || ''}`,
docs
);
await ctx.reply(resposta);
}
} catch (erro) {
console.error('❌ Erro ao processar foto:', erro);
await ctx.reply('Tive um problema pra receber a foto. Pode tentar de novo?');
}
});
// ============================================================
// RECEBIMENTO DE DOCUMENTOS (PDF, etc)
// ============================================================
bot.on('document', async (ctx) => {
try {
const produtor = db.buscarProdutorPorChat(ctx.chat.id);
if (!produtor) {
await ctx.reply('Primeiro use /start pra se cadastrar!');
return;
}
const documento = ctx.message.document;
const fileId = documento.file_id;
const fileName = documento.file_name || 'documento';
const mimeType = documento.mime_type || 'application/octet-stream';
// Baixa o arquivo
const file = await ctx.telegram.getFile(fileId);
const fileUrl = `https://api.telegram.org/file/bot${process.env.TELEGRAM_BOT_TOKEN}/${file.file_path}`;
// Salva localmente
const ext = path.extname(fileName) || '.pdf';
const nomeArquivo = `${uuidv4()}${ext}`;
const caminhoLocal = path.join(UPLOAD_DIR, produtor.id);
if (!fs.existsSync(caminhoLocal)) fs.mkdirSync(caminhoLocal, { recursive: true });
const caminhoCompleto = path.join(caminhoLocal, nomeArquivo);
await baixarArquivo(fileUrl, caminhoCompleto);
console.log(`📁 Documento recebido de ${produtor.nome}: ${fileName} (${mimeType})`);
// Determina tipo do documento
const tipoDoc = ai.determinarTipoDocumento(produtor);
if (tipoDoc) {
db.salvarDocumento(produtor.id, tipoDoc, {
status: 'enviado',
arquivo_path: caminhoCompleto,
arquivo_nome: fileName,
arquivo_tipo: mimeType,
arquivo_tamanho: documento.file_size || 0
});
// OCR se for imagem
if (mimeType.startsWith('image/')) {
processarOCR(produtor.id, tipoDoc, caminhoCompleto);
}
const resposta = await ai.processarDocumento(
produtor, tipoDoc,
`Arquivo: ${fileName} (${mimeType}). Legenda: ${ctx.message.caption || 'sem legenda'}`
);
await ctx.reply(resposta);
// Avança etapa
const novaEtapa = ai.avancarEtapa(produtor);
if (novaEtapa === 'completo') {
await ctx.reply('🎉 *Todos os documentos enviados!* Use /dossie pra gerar seu dossiê.', { parse_mode: 'Markdown' });
}
} else {
const docs = db.buscarDocumentos(produtor.id);
const resposta = await ai.processarMensagem(
produtor,
`Enviei um arquivo: ${fileName}. ${ctx.message.caption || ''}`,
docs
);
await ctx.reply(resposta);
}
} catch (erro) {
console.error('❌ Erro ao processar documento:', erro);
await ctx.reply('Tive um problema pra receber o arquivo. Pode tentar de novo?');
}
});
// ============================================================
// MENSAGENS DE TEXTO
// ============================================================
bot.on('text', async (ctx) => {
try {
const produtor = db.buscarProdutorPorChat(ctx.chat.id);
const mensagem = ctx.message.text;
if (!produtor) {
// Cria cadastro automaticamente
const nome = [ctx.from.first_name, ctx.from.last_name].filter(Boolean).join(' ');
const novoProdutor = db.criarProdutor(ctx.chat.id, ctx.from.username, nome);
const resposta = await ai.processarMensagem(null, mensagem, []);
await ctx.reply(resposta);
return;
}
// Envia pra IA processar
const docs = db.buscarDocumentos(produtor.id);
const resposta = await ai.processarMensagem(produtor, mensagem, docs);
await ctx.reply(resposta);
} catch (erro) {
console.error('❌ Erro ao processar mensagem:', erro);
await ctx.reply('Desculpa, tive um problema. Pode repetir?');
}
});
// ============================================================
// ERRO GLOBAL
// ============================================================
bot.catch((erro, ctx) => {
console.error('❌ Erro no bot:', erro);
});
return bot;
}
// ============================================================
// FUNÇÕES AUXILIARES
// ============================================================
/**
* Baixa arquivo de uma URL para o disco
*/
function baixarArquivo(url, destino) {
return new Promise((resolve, reject) => {
const protocolo = url.startsWith('https') ? https : http;
const file = fs.createWriteStream(destino);
protocolo.get(url, (response) => {
response.pipe(file);
file.on('finish', () => {
file.close(resolve);
});
}).on('error', (erro) => {
fs.unlink(destino, () => {}); // Limpa arquivo parcial
reject(erro);
});
});
}
/**
* Processa OCR em background (não bloqueia a resposta)
*/
async function processarOCR(produtorId, tipoDoc, caminhoArquivo) {
try {
console.log(`🔍 Iniciando OCR para ${tipoDoc}...`);
const resultado = await ocr.extrairTexto(caminhoArquivo);
if (resultado.sucesso) {
// Valida o documento
const validacao = ocr.validarDocumento(tipoDoc, resultado.texto);
const doc = db.buscarDocumento(produtorId, tipoDoc);
if (doc) {
const novoStatus = validacao.valido ? 'aprovado' : 'enviado';
db.atualizarValidacao(
doc.id,
novoStatus,
validacao.detalhes.join('; ')
);
// Atualiza dados extraídos
if (Object.keys(validacao.dados_extraidos).length > 0) {
db.db.prepare('UPDATE documentos SET dados_extraidos = ? WHERE id = ?')
.run(JSON.stringify(validacao.dados_extraidos), doc.id);
}
console.log(`✅ OCR ${tipoDoc}: ${novoStatus} - ${validacao.detalhes.join(', ')}`);
}
} else {
console.log(`⚠️ OCR falhou para ${tipoDoc}: confiança baixa`);
}
} catch (erro) {
console.error(`❌ Erro no OCR (${tipoDoc}):`, erro.message);
}
}
module.exports = { criarBot };

95
src/index.js Normal file
View File

@@ -0,0 +1,95 @@
/**
* DocuAgro - Entry Point
* Inicia o bot Telegram e o servidor API
*/
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const compression = require('compression');
const path = require('path');
const { criarBot } = require('./bot/telegram-bot');
const routes = require('./api/routes');
// Valida variáveis de ambiente obrigatórias
const requiredEnv = ['TELEGRAM_BOT_TOKEN', 'OPENAI_API_KEY'];
for (const env of requiredEnv) {
if (!process.env[env]) {
console.error(`❌ Variável de ambiente ${env} não configurada!`);
console.error('📝 Copie .env.example para .env e preencha os valores.');
process.exit(1);
}
}
// Roda setup do banco se não existir
const fs = require('fs');
const dbPath = process.env.DB_PATH || path.join(__dirname, '..', 'data', 'docuagro.db');
if (!fs.existsSync(dbPath)) {
console.log('📦 Banco de dados não encontrado. Criando...');
require('./setup-db');
}
// ============================================================
// SERVIDOR EXPRESS (API + Painel)
// ============================================================
const app = express();
// Middlewares
app.use(helmet({ contentSecurityPolicy: false }));
app.use(compression());
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Arquivos estáticos (painel web)
app.use(express.static(path.join(__dirname, '..', 'public')));
// Rotas da API
app.use(routes);
// Fallback para SPA (painel)
app.get('*', (req, res) => {
if (!req.path.startsWith('/api')) {
res.sendFile(path.join(__dirname, '..', 'public', 'index.html'));
}
});
const PORT = process.env.PORT || 3100;
app.listen(PORT, () => {
console.log(`\n🌐 Servidor API rodando em http://localhost:${PORT}`);
console.log(`📊 Painel web em http://localhost:${PORT}`);
});
// ============================================================
// BOT TELEGRAM
// ============================================================
const bot = criarBot();
bot.launch()
.then(() => {
console.log('🤖 Bot Telegram DocuAgro iniciado!');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log('🌱 DocuAgro v1.0 - Compliance EUDR');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
})
.catch(err => {
console.error('❌ Erro ao iniciar bot:', err.message);
if (err.message.includes('401')) {
console.error('⚠️ Token do Telegram inválido! Verifique TELEGRAM_BOT_TOKEN no .env');
}
});
// Graceful shutdown
process.once('SIGINT', () => {
console.log('\n🛑 Desligando DocuAgro...');
bot.stop('SIGINT');
process.exit(0);
});
process.once('SIGTERM', () => {
bot.stop('SIGTERM');
process.exit(0);
});

213
src/services/ai-service.js Normal file
View File

@@ -0,0 +1,213 @@
/**
* DocuAgro - Serviço de IA (OpenAI gpt-4o-mini)
* Processa mensagens do produtor e gera respostas inteligentes
*/
const OpenAI = require('openai');
const { gerarPrompt, ORDEM_COLETA, TIPOS_DOCUMENTO } = require('./system-prompt');
const db = require('./database');
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
});
const MODEL = process.env.OPENAI_MODEL || 'gpt-4o-mini';
/**
* Processa mensagem de texto do produtor e retorna resposta da IA
*/
async function processarMensagem(produtor, mensagemTexto, documentos) {
try {
// Gera prompt com contexto atual
const systemPrompt = gerarPrompt(produtor, documentos, produtor?.etapa_atual);
// Busca histórico recente da conversa
const historico = produtor ? db.buscarHistorico(produtor.id, 10) : [];
// Monta mensagens para a API
const messages = [
{ role: 'system', content: systemPrompt }
];
// Adiciona histórico
for (const msg of historico) {
messages.push({
role: msg.role,
content: msg.conteudo
});
}
// Adiciona mensagem atual
messages.push({
role: 'user',
content: mensagemTexto
});
// Chama a API
const completion = await openai.chat.completions.create({
model: MODEL,
messages,
temperature: 0.7,
max_tokens: 800,
presence_penalty: 0.1,
frequency_penalty: 0.1
});
const resposta = completion.choices[0]?.message?.content || 'Desculpa, tive um problema aqui. Pode repetir?';
// Salva no histórico
if (produtor) {
db.salvarMensagem(produtor.id, produtor.telegram_chat_id, 'user', mensagemTexto);
db.salvarMensagem(produtor.id, produtor.telegram_chat_id, 'assistant', resposta);
}
// Detecta se precisa atualizar etapa/dados baseado na resposta
await detectarAtualizacoes(produtor, mensagemTexto, resposta);
return resposta;
} catch (erro) {
console.error('❌ Erro na IA:', erro.message);
return 'Ops, tive um probleminha técnico. Pode mandar de novo daqui a pouquinho? 🔧';
}
}
/**
* Processa documento recebido (foto/PDF)
*/
async function processarDocumento(produtor, tipoDoc, descricaoArquivo) {
try {
const systemPrompt = gerarPrompt(produtor, db.buscarDocumentos(produtor.id), produtor.etapa_atual);
const messages = [
{ role: 'system', content: systemPrompt },
{
role: 'user',
content: `Acabei de enviar um arquivo que deveria ser o documento: ${TIPOS_DOCUMENTO[tipoDoc]?.nome || tipoDoc}. Informações do arquivo: ${descricaoArquivo}`
}
];
const completion = await openai.chat.completions.create({
model: MODEL,
messages,
temperature: 0.5,
max_tokens: 500
});
return completion.choices[0]?.message?.content || '✅ Recebi o documento! Estou analisando.';
} catch (erro) {
console.error('❌ Erro ao processar documento:', erro.message);
return '✅ Recebi o documento! Vou analisar e te aviso o resultado.';
}
}
/**
* Detecta se precisa atualizar dados do produtor baseado na conversa
* Usa a IA para extrair informações estruturadas
*/
async function detectarAtualizacoes(produtor, mensagemUsuario, respostaIA) {
if (!produtor) return;
// Se está no onboarding, tenta extrair dados pessoais
if (produtor.etapa_atual === 'onboarding') {
try {
const extraction = await openai.chat.completions.create({
model: MODEL,
messages: [
{
role: 'system',
content: `Extraia dados estruturados da mensagem do produtor rural. Responda APENAS com JSON válido.
Se a informação não estiver na mensagem, use null.
Campos possíveis: nome, cpf_cnpj, propriedade_nome, propriedade_municipio, propriedade_estado, propriedade_area_ha, cultura_principal.
Exemplo: {"nome": "João Silva", "cpf_cnpj": null, "propriedade_nome": null}`
},
{ role: 'user', content: mensagemUsuario }
],
temperature: 0,
max_tokens: 200
});
const texto = extraction.choices[0]?.message?.content || '{}';
// Tenta extrair JSON da resposta
const match = texto.match(/\{[^}]+\}/);
if (match) {
const dados = JSON.parse(match[0]);
const atualizacao = {};
for (const [chave, valor] of Object.entries(dados)) {
if (valor !== null && valor !== undefined && valor !== '') {
atualizacao[chave] = valor;
}
}
if (Object.keys(atualizacao).length > 0) {
db.atualizarProdutor(produtor.id, atualizacao);
console.log(`📝 Dados atualizados para ${produtor.id}:`, atualizacao);
}
// Verifica se onboarding está completo (tem pelo menos nome e município)
const produtorAtual = db.buscarProdutorPorId(produtor.id);
if (produtorAtual.nome && produtorAtual.nome !== 'Novo Produtor' &&
produtorAtual.propriedade_municipio) {
db.atualizarProdutor(produtor.id, { etapa_atual: 'coleta_car' });
console.log(`✅ Onboarding completo para ${produtor.id}, indo para coleta`);
}
}
} catch (e) {
// Erro na extração não é crítico
console.log('⚠️ Erro na extração de dados:', e.message);
}
}
}
/**
* Determina qual tipo de documento o produtor está enviando
* baseado na etapa atual
*/
function determinarTipoDocumento(produtor) {
if (!produtor || !produtor.etapa_atual) return null;
const etapa = produtor.etapa_atual;
// Mapeia etapa para tipo de documento
const mapa = {
'coleta_car': 'car',
'coleta_ccir': 'ccir',
'coleta_itr': 'itr',
'coleta_geo': 'georreferenciamento',
'coleta_licenca': 'licenca_ambiental',
'coleta_contrato': 'contrato_arrendamento',
'coleta_nf': 'nota_fiscal',
'coleta_declaracao': 'declaracao_desmatamento'
};
return mapa[etapa] || null;
}
/**
* Avança para o próximo documento na sequência de coleta
*/
function avancarEtapa(produtor) {
const docs = db.buscarDocumentos(produtor.id);
const tiposEnviados = docs.filter(d => ['enviado', 'aprovado', 'validando'].includes(d.status)).map(d => d.tipo);
const proximo = ORDEM_COLETA.find(t => !tiposEnviados.includes(t));
if (proximo) {
const novaEtapa = TIPOS_DOCUMENTO[proximo].etapa;
db.atualizarProdutor(produtor.id, { etapa_atual: novaEtapa });
return novaEtapa;
} else {
db.atualizarProdutor(produtor.id, { etapa_atual: 'completo', status: 'completo' });
return 'completo';
}
}
module.exports = {
processarMensagem,
processarDocumento,
detectarAtualizacoes,
determinarTipoDocumento,
avancarEtapa
};

View File

@@ -0,0 +1,112 @@
/**
* DocuAgro - Serviço de Autenticação JWT
* Gerencia criação de usuários, login e verificação de tokens
*/
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { v4: uuidv4 } = require('uuid');
const Database = require('better-sqlite3');
const path = require('path');
const JWT_SECRET = process.env.JWT_SECRET || 'docuagro-jwt-secret-2026-production';
const JWT_EXPIRATION = '24h';
// Conecta ao banco (mesmo caminho do database.js)
const dbPath = process.env.DB_PATH || path.join(__dirname, '..', '..', 'data', 'docuagro.db');
function getDb() {
const db = new Database(dbPath);
db.pragma('journal_mode = WAL');
db.pragma('foreign_keys = ON');
return db;
}
/**
* Cria um novo usuário no sistema
*/
async function criarUsuario({ username, senha, nome, role = 'admin', cooperativa_id = 'coop_001' }) {
const db = getDb();
try {
// Verifica se username já existe
const existente = db.prepare('SELECT id FROM usuarios WHERE username = ?').get(username);
if (existente) {
throw new Error('Username já existe');
}
const id = uuidv4();
const senha_hash = await bcrypt.hash(senha, 10);
db.prepare(`
INSERT INTO usuarios (id, cooperativa_id, username, senha_hash, nome, role)
VALUES (?, ?, ?, ?, ?, ?)
`).run(id, cooperativa_id, username, senha_hash, nome || username, role);
return {
id,
username,
nome: nome || username,
role,
cooperativa_id
};
} finally {
db.close();
}
}
/**
* Autentica um usuário com username e senha
* Retorna o token JWT e dados do usuário
*/
async function autenticarUsuario(username, senha) {
const db = getDb();
try {
const usuario = db.prepare('SELECT * FROM usuarios WHERE username = ?').get(username);
if (!usuario) {
throw new Error('Credenciais inválidas');
}
const senhaValida = await bcrypt.compare(senha, usuario.senha_hash);
if (!senhaValida) {
throw new Error('Credenciais inválidas');
}
// Gera token JWT
const payload = {
id: usuario.id,
username: usuario.username,
nome: usuario.nome,
role: usuario.role,
cooperativa_id: usuario.cooperativa_id
};
const token = jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRATION });
return {
token,
usuario: payload
};
} finally {
db.close();
}
}
/**
* Verifica e decodifica um token JWT
* Retorna os dados do usuário se válido
*/
function verificarToken(token) {
try {
const decoded = jwt.verify(token, JWT_SECRET);
return decoded;
} catch (erro) {
throw new Error('Token inválido ou expirado');
}
}
module.exports = {
criarUsuario,
autenticarUsuario,
verificarToken
};

258
src/services/database.js Normal file
View File

@@ -0,0 +1,258 @@
/**
* DocuAgro - Serviço de Banco de Dados
* Todas as operações CRUD para produtores, documentos e dossiês
*/
const Database = require('better-sqlite3');
const path = require('path');
const { v4: uuidv4 } = require('uuid');
const dbPath = process.env.DB_PATH || path.join(__dirname, '..', '..', 'data', 'docuagro.db');
const db = new Database(dbPath);
db.pragma('journal_mode = WAL');
db.pragma('foreign_keys = ON');
// ========== PRODUTORES ==========
/**
* Busca produtor pelo chat_id do Telegram
*/
function buscarProdutorPorChat(chatId) {
return db.prepare('SELECT * FROM produtores WHERE telegram_chat_id = ?').get(String(chatId));
}
/**
* Busca produtor pelo ID
*/
function buscarProdutorPorId(id) {
return db.prepare('SELECT * FROM produtores WHERE id = ?').get(id);
}
/**
* Cria novo produtor a partir do Telegram
*/
function criarProdutor(chatId, username, nome) {
const id = uuidv4();
db.prepare(`
INSERT INTO produtores (id, cooperativa_id, nome, telegram_chat_id, telegram_username, status, etapa_atual)
VALUES (?, 'coop_001', ?, ?, ?, 'pendente', 'onboarding')
`).run(id, nome || 'Novo Produtor', String(chatId), username || null);
return buscarProdutorPorId(id);
}
/**
* Atualiza dados do produtor
*/
function atualizarProdutor(id, dados) {
const campos = [];
const valores = [];
const permitidos = [
'nome', 'cpf_cnpj', 'telefone', 'propriedade_nome',
'propriedade_municipio', 'propriedade_estado', 'propriedade_area_ha',
'cultura_principal', 'status', 'etapa_atual', 'docs_completos'
];
for (const [chave, valor] of Object.entries(dados)) {
if (permitidos.includes(chave)) {
campos.push(`${chave} = ?`);
valores.push(valor);
}
}
if (campos.length === 0) return;
campos.push('atualizado_em = CURRENT_TIMESTAMP');
valores.push(id);
db.prepare(`UPDATE produtores SET ${campos.join(', ')} WHERE id = ?`).run(...valores);
return buscarProdutorPorId(id);
}
/**
* Lista todos os produtores (para painel)
*/
function listarProdutores(cooperativaId = 'coop_001') {
return db.prepare(`
SELECT p.*,
(SELECT COUNT(*) FROM documentos d WHERE d.produtor_id = p.id AND d.status = 'aprovado') as docs_aprovados,
(SELECT COUNT(*) FROM documentos d WHERE d.produtor_id = p.id AND d.status = 'rejeitado') as docs_rejeitados,
(SELECT COUNT(*) FROM documentos d WHERE d.produtor_id = p.id AND d.status = 'enviado') as docs_enviados
FROM produtores p
WHERE p.cooperativa_id = ?
ORDER BY p.criado_em DESC
`).all(cooperativaId);
}
/**
* Estatísticas do dashboard
*/
function estatisticas(cooperativaId = 'coop_001') {
const total = db.prepare('SELECT COUNT(*) as n FROM produtores WHERE cooperativa_id = ?').get(cooperativaId);
const completos = db.prepare("SELECT COUNT(*) as n FROM produtores WHERE cooperativa_id = ? AND status = 'completo'").get(cooperativaId);
const emAndamento = db.prepare("SELECT COUNT(*) as n FROM produtores WHERE cooperativa_id = ? AND status = 'em_andamento'").get(cooperativaId);
const pendentes = db.prepare("SELECT COUNT(*) as n FROM produtores WHERE cooperativa_id = ? AND status = 'pendente'").get(cooperativaId);
const irregulares = db.prepare("SELECT COUNT(*) as n FROM produtores WHERE cooperativa_id = ? AND status = 'irregular'").get(cooperativaId);
const docsTotal = db.prepare('SELECT COUNT(*) as n FROM documentos d JOIN produtores p ON d.produtor_id = p.id WHERE p.cooperativa_id = ?').get(cooperativaId);
const docsAprovados = db.prepare("SELECT COUNT(*) as n FROM documentos d JOIN produtores p ON d.produtor_id = p.id WHERE p.cooperativa_id = ? AND d.status = 'aprovado'").get(cooperativaId);
return {
totalProdutores: total.n,
completos: completos.n,
emAndamento: emAndamento.n,
pendentes: pendentes.n,
irregulares: irregulares.n,
totalDocumentos: docsTotal.n,
documentosAprovados: docsAprovados.n,
percentualCompliance: total.n > 0 ? Math.round((completos.n / total.n) * 100) : 0
};
}
// ========== DOCUMENTOS ==========
/**
* Busca documentos de um produtor
*/
function buscarDocumentos(produtorId) {
return db.prepare('SELECT * FROM documentos WHERE produtor_id = ? ORDER BY tipo').all(produtorId);
}
/**
* Busca documento específico
*/
function buscarDocumento(produtorId, tipo) {
return db.prepare('SELECT * FROM documentos WHERE produtor_id = ? AND tipo = ?').get(produtorId, tipo);
}
/**
* Cria ou atualiza documento
*/
function salvarDocumento(produtorId, tipo, dados) {
const existente = buscarDocumento(produtorId, tipo);
if (existente) {
db.prepare(`
UPDATE documentos SET
status = ?, arquivo_path = ?, arquivo_nome = ?, arquivo_tipo = ?,
arquivo_tamanho = ?, enviado_em = CURRENT_TIMESTAMP,
atualizado_em = CURRENT_TIMESTAMP
WHERE id = ?
`).run(
dados.status || 'enviado',
dados.arquivo_path, dados.arquivo_nome, dados.arquivo_tipo,
dados.arquivo_tamanho || 0, existente.id
);
return buscarDocumento(produtorId, tipo);
}
const id = uuidv4();
db.prepare(`
INSERT INTO documentos (id, produtor_id, tipo, status, arquivo_path, arquivo_nome, arquivo_tipo, arquivo_tamanho, enviado_em)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
`).run(id, produtorId, tipo, dados.status || 'enviado', dados.arquivo_path, dados.arquivo_nome, dados.arquivo_tipo, dados.arquivo_tamanho || 0);
// Atualiza contagem de docs do produtor
atualizarContagemDocs(produtorId);
return buscarDocumento(produtorId, tipo);
}
/**
* Atualiza validação do documento
*/
function atualizarValidacao(docId, resultado, detalhes) {
db.prepare(`
UPDATE documentos SET
status = ?, validacao_resultado = ?, validacao_detalhes = ?,
validado_em = CURRENT_TIMESTAMP, atualizado_em = CURRENT_TIMESTAMP
WHERE id = ?
`).run(resultado, resultado, detalhes, docId);
// Busca o doc pra atualizar contagem
const doc = db.prepare('SELECT produtor_id FROM documentos WHERE id = ?').get(docId);
if (doc) atualizarContagemDocs(doc.produtor_id);
}
/**
* Atualiza contagem de documentos completos do produtor
*/
function atualizarContagemDocs(produtorId) {
const aprovados = db.prepare("SELECT COUNT(*) as n FROM documentos WHERE produtor_id = ? AND status = 'aprovado'").get(produtorId);
const total = db.prepare("SELECT COUNT(*) as n FROM documentos WHERE produtor_id = ?").get(produtorId);
let status = 'pendente';
if (aprovados.n >= 8) status = 'completo';
else if (total.n > 0) status = 'em_andamento';
db.prepare('UPDATE produtores SET docs_completos = ?, status = ?, atualizado_em = CURRENT_TIMESTAMP WHERE id = ?')
.run(aprovados.n, status, produtorId);
}
// ========== CONVERSAS ==========
/**
* Salva mensagem no histórico
*/
function salvarMensagem(produtorId, chatId, role, conteudo, tipo = 'texto') {
db.prepare(`
INSERT INTO conversas (produtor_id, chat_id, role, conteudo, tipo_mensagem)
VALUES (?, ?, ?, ?, ?)
`).run(produtorId, String(chatId), role, conteudo, tipo);
}
/**
* Busca histórico de conversa (últimas N mensagens)
*/
function buscarHistorico(produtorId, limite = 20) {
return db.prepare(`
SELECT role, conteudo, tipo_mensagem, criado_em
FROM conversas
WHERE produtor_id = ?
ORDER BY id DESC
LIMIT ?
`).all(produtorId, limite).reverse();
}
// ========== DOSSIÊS ==========
/**
* Salva registro de dossiê gerado
*/
function salvarDossie(produtorId, arquivoPath, docsIncluidos) {
const id = uuidv4();
const versao = db.prepare('SELECT COALESCE(MAX(versao), 0) + 1 as v FROM dossies WHERE produtor_id = ?').get(produtorId);
db.prepare(`
INSERT INTO dossies (id, produtor_id, arquivo_path, versao, docs_incluidos)
VALUES (?, ?, ?, ?, ?)
`).run(id, produtorId, arquivoPath, versao.v, JSON.stringify(docsIncluidos));
return { id, versao: versao.v, arquivo_path: arquivoPath };
}
/**
* Busca último dossiê de um produtor
*/
function buscarUltimoDossie(produtorId) {
return db.prepare('SELECT * FROM dossies WHERE produtor_id = ? ORDER BY versao DESC LIMIT 1').get(produtorId);
}
module.exports = {
db,
buscarProdutorPorChat,
buscarProdutorPorId,
criarProdutor,
atualizarProdutor,
listarProdutores,
estatisticas,
buscarDocumentos,
buscarDocumento,
salvarDocumento,
atualizarValidacao,
atualizarContagemDocs,
salvarMensagem,
buscarHistorico,
salvarDossie,
buscarUltimoDossie
};

182
src/services/ocr-service.js Normal file
View File

@@ -0,0 +1,182 @@
/**
* DocuAgro - Serviço de OCR
* Extrai texto de imagens e PDFs usando Tesseract.js
*/
const Tesseract = require('tesseract.js');
const path = require('path');
/**
* Extrai texto de uma imagem
* @param {string} imagePath - Caminho da imagem
* @returns {object} - Texto extraído e confiança
*/
async function extrairTexto(imagePath) {
try {
console.log(`🔍 OCR processando: ${path.basename(imagePath)}`);
const resultado = await Tesseract.recognize(imagePath, 'por', {
logger: info => {
if (info.status === 'recognizing text') {
// Log de progresso
}
}
});
const texto = resultado.data.text.trim();
const confianca = resultado.data.confidence;
console.log(`✅ OCR concluído: ${texto.length} caracteres, confiança: ${confianca}%`);
return {
texto,
confianca,
palavras: resultado.data.words?.length || 0,
sucesso: texto.length > 10 && confianca > 30
};
} catch (erro) {
console.error('❌ Erro no OCR:', erro.message);
return {
texto: '',
confianca: 0,
palavras: 0,
sucesso: false,
erro: erro.message
};
}
}
/**
* Valida um documento baseado no texto extraído por OCR
* @param {string} tipoDoc - Tipo do documento
* @param {string} texto - Texto extraído
* @returns {object} - Resultado da validação
*/
function validarDocumento(tipoDoc, texto) {
const textoUpper = texto.toUpperCase();
const resultado = {
valido: false,
detalhes: [],
dados_extraidos: {}
};
switch (tipoDoc) {
case 'car':
// Procura número do CAR (formato: XX-XXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXX)
const carMatch = texto.match(/[A-Z]{2}[-.]?\d{7}[-.]?\w{20,}/i);
if (carMatch) {
resultado.dados_extraidos.numero_car = carMatch[0];
resultado.detalhes.push(`Número CAR encontrado: ${carMatch[0]}`);
resultado.valido = true;
}
// Verifica menções ao SICAR
if (textoUpper.includes('SICAR') || textoUpper.includes('CADASTRO AMBIENTAL')) {
resultado.detalhes.push('Documento parece ser um CAR');
resultado.valido = true;
}
break;
case 'ccir':
// Procura menção ao INCRA
if (textoUpper.includes('INCRA') || textoUpper.includes('CERTIFICADO') && textoUpper.includes('IMÓVEL RURAL')) {
resultado.detalhes.push('Documento parece ser um CCIR');
resultado.valido = true;
}
// Procura código do imóvel
const ccirMatch = texto.match(/\d{3}\.\d{3}\.\d{3}\.\d{3}[-.]?\d/);
if (ccirMatch) {
resultado.dados_extraidos.codigo_imovel = ccirMatch[0];
resultado.detalhes.push(`Código do imóvel: ${ccirMatch[0]}`);
}
break;
case 'itr':
// Procura menção a ITR / Receita Federal
if (textoUpper.includes('ITR') || textoUpper.includes('IMPOSTO TERRITORIAL') || textoUpper.includes('RECEITA FEDERAL')) {
resultado.detalhes.push('Documento parece ser comprovante de ITR');
resultado.valido = true;
}
break;
case 'georreferenciamento':
// Procura coordenadas geográficas
const coordMatch = texto.match(/-?\d{1,3}[.,]\d{2,}/g);
if (coordMatch && coordMatch.length >= 2) {
resultado.dados_extraidos.coordenadas = coordMatch.slice(0, 4);
resultado.detalhes.push(`Coordenadas encontradas: ${coordMatch.length} pontos`);
resultado.valido = true;
}
if (textoUpper.includes('MEMORIAL') || textoUpper.includes('TOPOGR') || textoUpper.includes('GEORREFERENCIA')) {
resultado.valido = true;
resultado.detalhes.push('Documento parece ser georreferenciamento');
}
break;
case 'licenca_ambiental':
if (textoUpper.includes('LICENÇA') || textoUpper.includes('LICENCA') || textoUpper.includes('AMBIENTAL')) {
resultado.detalhes.push('Documento parece ser licença ambiental');
resultado.valido = true;
}
// Procura validade
const dataMatch = texto.match(/\d{2}\/\d{2}\/\d{4}/g);
if (dataMatch) {
resultado.dados_extraidos.datas_encontradas = dataMatch;
resultado.detalhes.push(`Datas encontradas: ${dataMatch.join(', ')}`);
}
break;
case 'contrato_arrendamento':
if (textoUpper.includes('CONTRATO') || textoUpper.includes('ARRENDAMENTO') || textoUpper.includes('PARCERIA')) {
resultado.detalhes.push('Documento parece ser contrato');
resultado.valido = true;
}
break;
case 'nota_fiscal':
if (textoUpper.includes('NOTA FISCAL') || textoUpper.includes('NF-E') || textoUpper.includes('NFE') || textoUpper.includes('DANFE')) {
resultado.detalhes.push('Documento parece ser nota fiscal');
resultado.valido = true;
}
// Procura CPF/CNPJ
const cpfMatch = texto.match(/\d{3}\.\d{3}\.\d{3}[-.]?\d{2}/);
const cnpjMatch = texto.match(/\d{2}\.\d{3}\.\d{3}\/\d{4}[-.]?\d{2}/);
if (cpfMatch) resultado.dados_extraidos.cpf = cpfMatch[0];
if (cnpjMatch) resultado.dados_extraidos.cnpj = cnpjMatch[0];
break;
case 'declaracao_desmatamento':
// Sempre válido - nós geramos esse documento
resultado.valido = true;
resultado.detalhes.push('Declaração de não desmatamento recebida');
break;
default:
resultado.detalhes.push('Tipo de documento não reconhecido para validação automática');
}
// Se não conseguiu validar por tipo, verifica qualidade geral
if (!resultado.valido && texto.length > 50) {
resultado.valido = true;
resultado.detalhes.push('Documento recebido - validação manual pode ser necessária');
}
return resultado;
}
/**
* Extrai CPF ou CNPJ de um texto
*/
function extrairCpfCnpj(texto) {
const cpf = texto.match(/\d{3}\.?\d{3}\.?\d{3}[-.]?\d{2}/);
const cnpj = texto.match(/\d{2}\.?\d{3}\.?\d{3}\/?\d{4}[-.]?\d{2}/);
return {
cpf: cpf ? cpf[0] : null,
cnpj: cnpj ? cnpj[0] : null
};
}
module.exports = {
extrairTexto,
validarDocumento,
extrairCpfCnpj
};

379
src/services/pdf-service.js Normal file
View File

@@ -0,0 +1,379 @@
/**
* DocuAgro - Serviço de Geração de Dossiê PDF
* Compila todos os documentos validados do produtor em um PDF profissional
*/
const PDFDocument = require('pdfkit');
const fs = require('fs');
const path = require('path');
const dayjs = require('dayjs');
const db = require('./database');
const { TIPOS_DOCUMENTO } = require('./system-prompt');
// Cores do tema
const CORES = {
verde: '#2D7D46',
verdeClaro: '#E8F5E9',
amarelo: '#FFA000',
vermelho: '#D32F2F',
cinza: '#616161',
cinzaClaro: '#F5F5F5',
branco: '#FFFFFF',
preto: '#212121'
};
/**
* Gera o dossiê PDF de um produtor
* @param {string} produtorId - ID do produtor
* @returns {string} - Caminho do PDF gerado
*/
async function gerarDossie(produtorId) {
const produtor = db.buscarProdutorPorId(produtorId);
if (!produtor) throw new Error('Produtor não encontrado');
const documentos = db.buscarDocumentos(produtorId);
const uploadDir = process.env.UPLOAD_DIR || path.join(__dirname, '..', '..', 'uploads');
const dossiePath = path.join(uploadDir, 'dossies');
// Cria diretório de dossiês
if (!fs.existsSync(dossiePath)) fs.mkdirSync(dossiePath, { recursive: true });
const nomeArquivo = `dossie_${produtor.cpf_cnpj || produtor.id}_${dayjs().format('YYYYMMDD_HHmmss')}.pdf`;
const caminhoCompleto = path.join(dossiePath, nomeArquivo);
return new Promise((resolve, reject) => {
const doc = new PDFDocument({
size: 'A4',
margins: { top: 60, bottom: 60, left: 50, right: 50 },
info: {
Title: `Dossiê EUDR - ${produtor.nome}`,
Author: 'DocuAgro',
Subject: 'Dossiê de Compliance EUDR',
Creator: 'DocuAgro v1.0'
}
});
const stream = fs.createWriteStream(caminhoCompleto);
doc.pipe(stream);
// === CAPA ===
gerarCapa(doc, produtor);
// === PÁGINA DE DADOS DO PRODUTOR ===
doc.addPage();
gerarDadosProdutor(doc, produtor);
// === PÁGINAS DE DOCUMENTOS ===
doc.addPage();
gerarResumoDocumentos(doc, documentos);
// === DETALHES DE CADA DOCUMENTO ===
for (const documento of documentos) {
doc.addPage();
gerarDetalheDocumento(doc, documento, uploadDir);
}
// === PÁGINA FINAL - DECLARAÇÃO ===
doc.addPage();
gerarDeclaracao(doc, produtor, documentos);
// Rodapé em todas as páginas
const totalPaginas = doc.bufferedPageRange().count;
for (let i = 0; i < totalPaginas; i++) {
doc.switchToPage(i);
gerarRodape(doc, i + 1, totalPaginas);
}
doc.end();
stream.on('finish', () => {
// Salva no banco
const docsIncluidos = documentos.map(d => d.tipo);
db.salvarDossie(produtorId, caminhoCompleto, docsIncluidos);
console.log(`📄 Dossiê gerado: ${nomeArquivo}`);
resolve(caminhoCompleto);
});
stream.on('error', reject);
});
}
/**
* Gera a capa do dossiê
*/
function gerarCapa(doc, produtor) {
// Fundo verde no topo
doc.rect(0, 0, doc.page.width, 200).fill(CORES.verde);
// Título
doc.fontSize(32).fillColor(CORES.branco)
.text('DocuAgro', 50, 60, { align: 'center' });
doc.fontSize(14).fillColor(CORES.branco)
.text('Dossiê de Compliance EUDR', 50, 105, { align: 'center' });
doc.fontSize(10).fillColor(CORES.branco)
.text('Regulamento (UE) 2023/1115', 50, 130, { align: 'center' });
// Dados do produtor na capa
doc.fontSize(18).fillColor(CORES.preto)
.text(produtor.nome || 'Produtor', 50, 250, { align: 'center' });
doc.fontSize(12).fillColor(CORES.cinza);
if (produtor.cpf_cnpj) {
doc.text(`CPF/CNPJ: ${produtor.cpf_cnpj}`, 50, 285, { align: 'center' });
}
if (produtor.propriedade_nome) {
doc.text(`Propriedade: ${produtor.propriedade_nome}`, 50, 310, { align: 'center' });
}
if (produtor.propriedade_municipio) {
doc.text(`${produtor.propriedade_municipio}/${produtor.propriedade_estado}`, 50, 335, { align: 'center' });
}
if (produtor.propriedade_area_ha) {
doc.text(`Área: ${produtor.propriedade_area_ha} hectares`, 50, 360, { align: 'center' });
}
// Data de geração
doc.fontSize(10).fillColor(CORES.cinza)
.text(`Gerado em: ${dayjs().format('DD/MM/YYYY [às] HH:mm')}`, 50, 450, { align: 'center' });
// Status
const statusTexto = produtor.status === 'completo' ? '✅ COMPLIANCE COMPLETO' : '⚠️ COMPLIANCE EM ANDAMENTO';
const statusCor = produtor.status === 'completo' ? CORES.verde : CORES.amarelo;
doc.fontSize(16).fillColor(statusCor)
.text(statusTexto, 50, 500, { align: 'center' });
}
/**
* Gera página com dados do produtor
*/
function gerarDadosProdutor(doc, produtor) {
doc.fontSize(18).fillColor(CORES.verde)
.text('Dados do Produtor', 50, 60);
doc.moveTo(50, 85).lineTo(545, 85).stroke(CORES.verde);
const campos = [
['Nome Completo', produtor.nome || 'Não informado'],
['CPF/CNPJ', produtor.cpf_cnpj || 'Não informado'],
['Telefone', produtor.telefone || 'Não informado'],
['Propriedade', produtor.propriedade_nome || 'Não informada'],
['Município', produtor.propriedade_municipio || 'Não informado'],
['Estado', produtor.propriedade_estado || 'Não informado'],
['Área (hectares)', produtor.propriedade_area_ha ? `${produtor.propriedade_area_ha} ha` : 'Não informada'],
['Cultura Principal', produtor.cultura_principal || 'Não informada'],
['Documentos Aprovados', `${produtor.docs_completos} de ${produtor.docs_total}`],
['Status Compliance', produtor.status || 'Pendente'],
['Data de Cadastro', dayjs(produtor.criado_em).format('DD/MM/YYYY')]
];
let y = 100;
for (const [label, valor] of campos) {
// Fundo alternado
if (campos.indexOf([label, valor]) % 2 === 0) {
doc.rect(50, y - 5, 495, 25).fill(CORES.cinzaClaro);
}
doc.fontSize(10).fillColor(CORES.cinza).text(label, 60, y);
doc.fontSize(10).fillColor(CORES.preto).text(valor, 250, y);
y += 28;
}
}
/**
* Gera resumo dos documentos
*/
function gerarResumoDocumentos(doc, documentos) {
doc.fontSize(18).fillColor(CORES.verde)
.text('Resumo dos Documentos', 50, 60);
doc.moveTo(50, 85).lineTo(545, 85).stroke(CORES.verde);
let y = 100;
// Cabeçalho da tabela
doc.fontSize(9).fillColor(CORES.branco);
doc.rect(50, y - 5, 495, 22).fill(CORES.verde);
doc.text('Documento', 60, y);
doc.text('Status', 320, y);
doc.text('Data Envio', 420, y);
y += 28;
// Lista todos os tipos de documento
const todosOsTipos = [
'car', 'ccir', 'itr', 'georreferenciamento',
'licenca_ambiental', 'contrato_arrendamento',
'nota_fiscal', 'declaracao_desmatamento'
];
for (const tipo of todosOsTipos) {
const docEncontrado = documentos.find(d => d.tipo === tipo);
const info = TIPOS_DOCUMENTO[tipo];
// Fundo alternado
if (todosOsTipos.indexOf(tipo) % 2 === 0) {
doc.rect(50, y - 5, 495, 22).fill(CORES.cinzaClaro);
}
doc.fontSize(9).fillColor(CORES.preto);
doc.text(info?.nome || tipo, 60, y, { width: 250 });
if (docEncontrado) {
const statusCor = {
'aprovado': CORES.verde,
'enviado': CORES.amarelo,
'validando': CORES.amarelo,
'rejeitado': CORES.vermelho,
'pendente': CORES.cinza,
'vencido': CORES.vermelho
}[docEncontrado.status] || CORES.cinza;
doc.fillColor(statusCor).text(docEncontrado.status.toUpperCase(), 320, y);
doc.fillColor(CORES.cinza).text(
docEncontrado.enviado_em ? dayjs(docEncontrado.enviado_em).format('DD/MM/YYYY') : '-',
420, y
);
} else {
doc.fillColor(CORES.cinza).text('NÃO ENVIADO', 320, y);
doc.text('-', 420, y);
}
y += 25;
}
}
/**
* Gera página de detalhe de um documento
*/
function gerarDetalheDocumento(doc, documento, uploadDir) {
const info = TIPOS_DOCUMENTO[documento.tipo];
doc.fontSize(16).fillColor(CORES.verde)
.text(info?.nome || documento.tipo, 50, 60);
doc.moveTo(50, 85).lineTo(545, 85).stroke(CORES.verde);
let y = 100;
// Status com badge colorida
const statusCor = {
'aprovado': CORES.verde,
'enviado': CORES.amarelo,
'rejeitado': CORES.vermelho
}[documento.status] || CORES.cinza;
doc.fontSize(12).fillColor(statusCor)
.text(`Status: ${documento.status.toUpperCase()}`, 50, y);
y += 30;
// Detalhes do arquivo
doc.fontSize(10).fillColor(CORES.cinza);
if (documento.arquivo_nome) {
doc.text(`Arquivo: ${documento.arquivo_nome}`, 50, y); y += 20;
}
if (documento.enviado_em) {
doc.text(`Enviado em: ${dayjs(documento.enviado_em).format('DD/MM/YYYY [às] HH:mm')}`, 50, y); y += 20;
}
if (documento.validado_em) {
doc.text(`Validado em: ${dayjs(documento.validado_em).format('DD/MM/YYYY [às] HH:mm')}`, 50, y); y += 20;
}
// Dados extraídos
if (documento.dados_extraidos) {
y += 10;
doc.fontSize(12).fillColor(CORES.preto).text('Dados Extraídos:', 50, y); y += 20;
try {
const dados = JSON.parse(documento.dados_extraidos);
for (const [chave, valor] of Object.entries(dados)) {
doc.fontSize(9).fillColor(CORES.cinza).text(`${chave}: ${valor}`, 70, y); y += 18;
}
} catch (e) {
doc.fontSize(9).fillColor(CORES.cinza).text(documento.dados_extraidos, 70, y);
}
}
// Resultado da validação
if (documento.validacao_detalhes) {
y += 10;
doc.fontSize(12).fillColor(CORES.preto).text('Validação:', 50, y); y += 20;
doc.fontSize(9).fillColor(CORES.cinza).text(documento.validacao_detalhes, 70, y, { width: 470 });
}
// Tenta incluir miniatura da imagem
if (documento.arquivo_path && fs.existsSync(documento.arquivo_path)) {
const ext = path.extname(documento.arquivo_path).toLowerCase();
if (['.jpg', '.jpeg', '.png'].includes(ext)) {
try {
y += 30;
if (y < 500) {
doc.image(documento.arquivo_path, 50, y, { width: 300, height: 250, fit: [300, 250] });
}
} catch (e) {
// Imagem não pôde ser incluída
}
}
}
}
/**
* Gera página de declaração final
*/
function gerarDeclaracao(doc, produtor, documentos) {
doc.fontSize(18).fillColor(CORES.verde)
.text('Declaração de Conformidade', 50, 60, { align: 'center' });
doc.moveTo(50, 90).lineTo(545, 90).stroke(CORES.verde);
const docsAprovados = documentos.filter(d => d.status === 'aprovado').length;
const totalDocs = 8;
doc.fontSize(11).fillColor(CORES.preto);
const texto = `
Declaro, para os devidos fins e efeitos do Regulamento (UE) 2023/1115 (EUDR - European Union Deforestation Regulation), que o produtor rural abaixo identificado apresentou a documentação solicitada para fins de compliance ambiental e fundiário:
Produtor: ${produtor.nome || 'Não informado'}
CPF/CNPJ: ${produtor.cpf_cnpj || 'Não informado'}
Propriedade: ${produtor.propriedade_nome || 'Não informada'}
Município/UF: ${produtor.propriedade_municipio || '?'}/${produtor.propriedade_estado || '?'}
Área: ${produtor.propriedade_area_ha ? produtor.propriedade_area_ha + ' hectares' : 'Não informada'}
Cultura Principal: ${produtor.cultura_principal || 'Não informada'}
Documentos apresentados e validados: ${docsAprovados} de ${totalDocs}
${docsAprovados >= totalDocs
? 'Todos os documentos obrigatórios foram apresentados e validados. O produtor encontra-se em conformidade com os requisitos documentais para exportação sob o regime EUDR.'
: 'ATENÇÃO: Nem todos os documentos obrigatórios foram apresentados e/ou validados. O dossiê encontra-se INCOMPLETO para fins de compliance EUDR.'}
Este dossiê foi gerado automaticamente pelo sistema DocuAgro em ${dayjs().format('DD/MM/YYYY [às] HH:mm')}.
Os documentos originais encontram-se armazenados digitalmente e disponíveis para verificação.
`;
doc.text(texto.trim(), 50, 110, { width: 495, lineGap: 4 });
// Área de assinatura
const y = 550;
doc.moveTo(150, y).lineTo(450, y).stroke(CORES.cinza);
doc.fontSize(10).fillColor(CORES.cinza)
.text('Assinatura do Responsável / Cooperativa', 150, y + 5, { align: 'center', width: 300 });
doc.moveTo(150, y + 60).lineTo(450, y + 60).stroke(CORES.cinza);
doc.text(`${produtor.nome || 'Produtor'}`, 150, y + 65, { align: 'center', width: 300 });
}
/**
* Rodapé padrão
*/
function gerarRodape(doc, pagina, total) {
const y = doc.page.height - 40;
doc.fontSize(8).fillColor(CORES.cinza);
doc.text(`DocuAgro - Compliance EUDR | Página ${pagina} de ${total}`, 50, y, {
align: 'center',
width: doc.page.width - 100
});
}
module.exports = {
gerarDossie
};

View File

@@ -0,0 +1,172 @@
/**
* DocuAgro - Prompt System da IA Especialista em EUDR
* Este prompt transforma o gpt-4o-mini em um especialista em
* documentação agrícola brasileira e compliance EUDR
*/
const SYSTEM_PROMPT = `Você é o DocuAgro, um assistente virtual especializado em ajudar produtores rurais brasileiros a organizar sua documentação para compliance com o EUDR (Regulamento da União Europeia contra Desmatamento).
## SUA PERSONALIDADE
- Fale de forma SIMPLES e DIRETA, como se estivesse conversando com um produtor rural
- Use linguagem do campo: "tá certinho", "vamos lá", "beleza", "ficou bom"
- Seja PACIENTE - muitos produtores não estão acostumados com tecnologia
- Quando explicar algo técnico, use analogias do campo
- Sempre encoraje o produtor: "tá quase lá!", "mais um pouquinho e fica pronto"
- Use emojis com moderação: 📄 🌱 ✅ ❌ 📸 👍
## O QUE VOCÊ FAZ
Você guia o produtor na coleta e envio de 8 documentos obrigatórios:
1. **CAR** (Cadastro Ambiental Rural) - Número do registro no SICAR
2. **CCIR** (Certificado de Cadastro de Imóvel Rural) - Emitido pelo INCRA
3. **ITR** (Comprovante de quitação do Imposto Territorial Rural)
4. **Georreferenciamento** - Coordenadas/mapa da propriedade
5. **Licença Ambiental** - Autorização de atividade agropecuária
6. **Contrato de Arrendamento** - Se não for proprietário
7. **Nota Fiscal de Venda** - Última NF de venda da produção
8. **Declaração de Não Desmatamento** - Autodeclaração pós-dez/2020
## FLUXO DE CONVERSA
### Onboarding (etapa: onboarding)
Quando o produtor chega pela primeira vez:
1. Apresente-se de forma amigável
2. Explique em 2-3 frases o que é o DocuAgro e por que é importante
3. Pergunte o nome completo do produtor
4. Pergunte o CPF (explique que é só pra identificação)
5. Pergunte o nome da propriedade
6. Pergunte município e estado
7. Pergunte a área em hectares (aproximado tá bom)
8. Pergunte a cultura principal (soja, café, algodão, etc.)
### Coleta de Documentos (etapa: coleta_NOMEDOC)
Para cada documento:
1. Explique O QUE é o documento em linguagem simples
2. Explique ONDE encontrar (site, órgão, cartório)
3. Peça para enviar FOTO ou PDF
4. Quando receber, confirme o recebimento
5. Se o documento parece ilegível ou errado, peça para enviar novamente
### Validação (após receber documento)
- Se parece OK: "✅ Recebi seu [documento]! Tá sendo analisado, já te aviso o resultado."
- Se ilegível: "📸 A foto ficou meio escura/cortada. Pode tirar outra? Dica: tire num lugar com bastante luz."
- Se documento errado: "❌ Parece que esse documento não é o [esperado]. O [documento] é aquele que..."
## REGRAS IMPORTANTES
1. NUNCA invente informações sobre legislação
2. Se não souber algo, diga "Vou verificar isso pra você"
3. Um documento por vez - não peça vários de uma vez
4. Se o produtor mandar mensagem que não tem a ver, responda educadamente e volte ao assunto
5. Se o produtor disser que não tem um documento, explique como obter (passo a passo)
6. Respostas CURTAS - máximo 3-4 parágrafos
7. Sempre termine com uma pergunta ou próximo passo claro
## COMO ORIENTAR PARA OBTER DOCUMENTOS
### CAR
"O CAR é feito pelo site car.gov.br. Se você já tem, é só me mandar o número do recibo ou o PDF. Se não tem, procure o escritório do meio ambiente do seu município que eles ajudam a fazer."
### CCIR
"O CCIR sai pelo site do INCRA (sncr.serpro.gov.br). Se sua propriedade já tá cadastrada, é só imprimir. Senão, precisa ir no INCRA mais perto."
### ITR
"O comprovante do ITR sai pelo site da Receita Federal. Se você declara todo ano, é só baixar o recibo. Pode pedir pro seu contador também."
### Georreferenciamento
"O mapa da propriedade com as coordenadas GPS. Se você tem planta topográfica ou memorial descritivo, serve. Senão, um técnico agrimensor faz isso."
### Licença Ambiental
"É a licença que autoriza a atividade na sua propriedade. Sai pelo órgão ambiental do estado (SEMA, IMA, IEMA, depende do estado)."
### Contrato de Arrendamento
"Se a terra não é sua, precisa do contrato com o dono. Se é proprietário, não precisa desse documento - me avisa que eu pulo."
### Nota Fiscal
"A última nota de venda da sua produção. Pode ser a NF-e (nota eletrônica) ou NF de produtor rural."
### Declaração de Não Desmatamento
"Essa eu mesmo gero pra você! É uma declaração que diz que não teve desmatamento na sua propriedade depois de dezembro de 2020."
## CONTEXTO EUDR
O Regulamento (UE) 2023/1115 (EUDR) proíbe a importação na UE de commodities (soja, café, cacau, óleo de palma, borracha, gado, madeira) produzidas em áreas desmatadas após 31/12/2020.
Produtores brasileiros que exportam (direto ou via cooperativa/trading) precisam comprovar:
- Geolocalização da produção
- Que não houve desmatamento após dez/2020
- Conformidade ambiental da propriedade
## FORMATO DAS RESPOSTAS
Responda SEMPRE em texto puro (sem markdown complexo). Use apenas:
- Negrito com * para destaque
- Emojis com moderação
- Quebras de linha para organizar
ESTADO ATUAL DO PRODUTOR (será injetado dinamicamente):
{ESTADO_PRODUTOR}`;
// Mapa de tipos de documento para nomes amigáveis
const TIPOS_DOCUMENTO = {
car: { nome: 'CAR (Cadastro Ambiental Rural)', etapa: 'coleta_car' },
ccir: { nome: 'CCIR (Certificado de Cadastro de Imóvel Rural)', etapa: 'coleta_ccir' },
itr: { nome: 'ITR (Imposto Territorial Rural)', etapa: 'coleta_itr' },
georreferenciamento: { nome: 'Georreferenciamento da Propriedade', etapa: 'coleta_geo' },
licenca_ambiental: { nome: 'Licença Ambiental', etapa: 'coleta_licenca' },
contrato_arrendamento: { nome: 'Contrato de Arrendamento', etapa: 'coleta_contrato' },
nota_fiscal: { nome: 'Nota Fiscal de Venda', etapa: 'coleta_nf' },
declaracao_desmatamento: { nome: 'Declaração de Não Desmatamento', etapa: 'coleta_declaracao' }
};
// Ordem de coleta dos documentos
const ORDEM_COLETA = [
'car', 'ccir', 'itr', 'georreferenciamento',
'licenca_ambiental', 'contrato_arrendamento',
'nota_fiscal', 'declaracao_desmatamento'
];
/**
* Gera o prompt completo com estado do produtor injetado
*/
function gerarPrompt(produtor, documentos, etapaAtual) {
let estado = '';
if (produtor) {
estado += `\nNome: ${produtor.nome || 'Não informado'}`;
estado += `\nCPF/CNPJ: ${produtor.cpf_cnpj || 'Não informado'}`;
estado += `\nPropriedade: ${produtor.propriedade_nome || 'Não informada'}`;
estado += `\nMunicípio/Estado: ${produtor.propriedade_municipio || '?'}/${produtor.propriedade_estado || '?'}`;
estado += `\nÁrea: ${produtor.propriedade_area_ha ? produtor.propriedade_area_ha + ' ha' : 'Não informada'}`;
estado += `\nCultura: ${produtor.cultura_principal || 'Não informada'}`;
estado += `\nEtapa atual: ${etapaAtual || produtor.etapa_atual}`;
estado += `\nDocumentos completos: ${produtor.docs_completos}/${produtor.docs_total}`;
if (documentos && documentos.length > 0) {
estado += '\n\nDocumentos enviados:';
documentos.forEach(doc => {
const info = TIPOS_DOCUMENTO[doc.tipo];
estado += `\n- ${info ? info.nome : doc.tipo}: ${doc.status}`;
});
}
// Próximo documento a coletar
if (documentos) {
const tiposEnviados = documentos.map(d => d.tipo);
const proximo = ORDEM_COLETA.find(t => !tiposEnviados.includes(t));
if (proximo) {
estado += `\n\nPróximo documento a coletar: ${TIPOS_DOCUMENTO[proximo].nome}`;
} else {
estado += '\n\nTodos os documentos já foram enviados!';
}
}
} else {
estado = '\nProdutor novo - ainda não cadastrado. Iniciar onboarding.';
}
return SYSTEM_PROMPT.replace('{ESTADO_PRODUTOR}', estado);
}
module.exports = {
SYSTEM_PROMPT,
TIPOS_DOCUMENTO,
ORDEM_COLETA,
gerarPrompt
};

179
src/setup-db.js Normal file
View File

@@ -0,0 +1,179 @@
/**
* DocuAgro - Setup do Banco de Dados SQLite
* Cria todas as tabelas necessárias para o MVP
*/
const Database = require('better-sqlite3');
const path = require('path');
const fs = require('fs');
// Garante que o diretório data existe
const dataDir = path.join(__dirname, '..', 'data');
if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });
const dbPath = process.env.DB_PATH || path.join(dataDir, 'docuagro.db');
const db = new Database(dbPath);
// Habilita WAL para melhor performance
db.pragma('journal_mode = WAL');
db.pragma('foreign_keys = ON');
console.log('🌱 Criando banco de dados DocuAgro...\n');
// === Tabela: Cooperativas ===
db.exec(`
CREATE TABLE IF NOT EXISTS cooperativas (
id TEXT PRIMARY KEY,
nome TEXT NOT NULL,
cnpj TEXT,
email TEXT,
telefone TEXT,
senha_hash TEXT,
criado_em DATETIME DEFAULT CURRENT_TIMESTAMP,
atualizado_em DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
console.log('✅ Tabela cooperativas criada');
// === Tabela: Produtores ===
db.exec(`
CREATE TABLE IF NOT EXISTS produtores (
id TEXT PRIMARY KEY,
cooperativa_id TEXT NOT NULL,
nome TEXT NOT NULL,
cpf_cnpj TEXT,
telefone TEXT,
telegram_chat_id TEXT UNIQUE,
telegram_username TEXT,
propriedade_nome TEXT,
propriedade_municipio TEXT,
propriedade_estado TEXT,
propriedade_area_ha REAL,
cultura_principal TEXT,
status TEXT DEFAULT 'pendente' CHECK(status IN ('pendente', 'em_andamento', 'completo', 'irregular')),
etapa_atual TEXT DEFAULT 'onboarding',
docs_completos INTEGER DEFAULT 0,
docs_total INTEGER DEFAULT 8,
criado_em DATETIME DEFAULT CURRENT_TIMESTAMP,
atualizado_em DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (cooperativa_id) REFERENCES cooperativas(id)
)
`);
console.log('✅ Tabela produtores criada');
// === Tabela: Documentos ===
db.exec(`
CREATE TABLE IF NOT EXISTS documentos (
id TEXT PRIMARY KEY,
produtor_id TEXT NOT NULL,
tipo TEXT NOT NULL CHECK(tipo IN (
'car', 'ccir', 'itr', 'georreferenciamento',
'licenca_ambiental', 'contrato_arrendamento',
'nota_fiscal', 'declaracao_desmatamento'
)),
status TEXT DEFAULT 'pendente' CHECK(status IN (
'pendente', 'enviado', 'validando', 'aprovado', 'rejeitado', 'vencido'
)),
arquivo_path TEXT,
arquivo_nome TEXT,
arquivo_tipo TEXT,
arquivo_tamanho INTEGER,
dados_extraidos TEXT,
validacao_resultado TEXT,
validacao_detalhes TEXT,
validade DATE,
enviado_em DATETIME,
validado_em DATETIME,
criado_em DATETIME DEFAULT CURRENT_TIMESTAMP,
atualizado_em DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (produtor_id) REFERENCES produtores(id)
)
`);
console.log('✅ Tabela documentos criada');
// === Tabela: Conversas (histórico) ===
db.exec(`
CREATE TABLE IF NOT EXISTS conversas (
id INTEGER PRIMARY KEY AUTOINCREMENT,
produtor_id TEXT NOT NULL,
chat_id TEXT NOT NULL,
role TEXT NOT NULL CHECK(role IN ('user', 'assistant', 'system')),
conteudo TEXT NOT NULL,
tipo_mensagem TEXT DEFAULT 'texto',
criado_em DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (produtor_id) REFERENCES produtores(id)
)
`);
console.log('✅ Tabela conversas criada');
// === Tabela: Dossiês ===
db.exec(`
CREATE TABLE IF NOT EXISTS dossies (
id TEXT PRIMARY KEY,
produtor_id TEXT NOT NULL,
arquivo_path TEXT NOT NULL,
versao INTEGER DEFAULT 1,
docs_incluidos TEXT,
gerado_em DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (produtor_id) REFERENCES produtores(id)
)
`);
console.log('✅ Tabela dossiês criada');
// === Tabela: Usuarios (autenticação JWT) ===
db.exec(`
CREATE TABLE IF NOT EXISTS usuarios (
id TEXT PRIMARY KEY,
cooperativa_id TEXT,
username TEXT UNIQUE NOT NULL,
senha_hash TEXT NOT NULL,
nome TEXT,
role TEXT DEFAULT 'admin',
criado_em DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
console.log('✅ Tabela usuarios criada');
// === Índices ===
db.exec(`
CREATE INDEX IF NOT EXISTS idx_produtores_cooperativa ON produtores(cooperativa_id);
CREATE INDEX IF NOT EXISTS idx_produtores_telegram ON produtores(telegram_chat_id);
CREATE INDEX IF NOT EXISTS idx_produtores_status ON produtores(status);
CREATE INDEX IF NOT EXISTS idx_documentos_produtor ON documentos(produtor_id);
CREATE INDEX IF NOT EXISTS idx_documentos_tipo ON documentos(tipo);
CREATE INDEX IF NOT EXISTS idx_documentos_status ON documentos(status);
CREATE INDEX IF NOT EXISTS idx_conversas_produtor ON conversas(produtor_id);
CREATE INDEX IF NOT EXISTS idx_conversas_chat ON conversas(chat_id);
`);
console.log('✅ Índices criados');
// === Cooperativa padrão (MVP) ===
const coopExiste = db.prepare('SELECT id FROM cooperativas WHERE id = ?').get('coop_001');
if (!coopExiste) {
db.prepare(`
INSERT INTO cooperativas (id, nome, cnpj, email)
VALUES (?, ?, ?, ?)
`).run('coop_001', 'Cooperativa Piloto', '00.000.000/0001-00', 'contato@cooperativa.com');
console.log('✅ Cooperativa piloto criada');
}
// === Usuário admin padrão ===
const bcrypt = require('bcryptjs');
const { v4: uuidv4 } = require('uuid');
const adminExiste = db.prepare("SELECT id FROM usuarios WHERE username = 'admin'").get();
if (!adminExiste) {
const senhaHash = bcrypt.hashSync('DocuAgro2026!', 10);
db.prepare(`
INSERT INTO usuarios (id, cooperativa_id, username, senha_hash, nome, role)
VALUES (?, 'coop_001', 'admin', ?, 'Administrador', 'admin')
`).run(uuidv4(), senhaHash);
console.log('✅ Usuário admin padrão criado (admin / DocuAgro2026!)');
} else {
console.log(' Usuário admin já existe');
}
console.log('\n🎉 Banco de dados configurado com sucesso!');
console.log(`📁 Arquivo: ${dbPath}\n`);
db.close();

0
uploads/.gitkeep Normal file
View File