API Node.js/Express para coletar, salvar e consultar cotacoes de graos das fontes Coamo, C.Vale, LAR e Granos.
A aplicacao usa Puppeteer para scraping, cache em memoria para respostas rapidas e Neon/Postgres para manter historico e ultimo snapshot valido por fonte.
- Coleta de cotacoes via scraping com Puppeteer.
- Consulta atual por fonte: Coamo, C.Vale, LAR e Granos.
- Consulta consolidada com contrato parcial por fonte em
/api/cotacoes/todos. - Filtros por grao, local, descricao, fornecedor e unidade.
- Melhor preco, comparativo entre fontes, variacao historica e exportacao CSV.
- Persistencia em Neon/Postgres com historico e ultima cotacao por fonte.
- Cache em memoria aquecido a partir do banco na subida da API.
- Scheduler automatico com
node-cron. - Health check simples para uptime e health check profundo para operacao.
- Documentacao OpenAPI servida via Swagger UI.
- Node.js
>=18 <25 - Express
- Puppeteer
- node-cron
- PostgreSQL/Neon via
pg - Swagger UI + OpenAPI
- Node.js
>=18 <25 - npm
- Banco PostgreSQL/Neon acessivel por
DATABASE_URL - Chrome do Puppeteer instalado ou disponivel no ambiente
git clone <URL_DO_REPOSITORIO>
cd AgroSmartAPI
npm installCrie o .env com base no exemplo:
Copy-Item .env.example .envNo Linux/macOS:
cp .env.example .envDepois valide o Chrome usado pelo Puppeteer:
npm run check:chromeO npm install executa o postinstall e baixa para .cache/puppeteer a revisao de Chrome esperada pela versao do Puppeteer. Em deploys como Render, mantenha a faixa de Node do package.json para evitar versoes atuais demais, como Node 26, antes das dependencias estarem validadas.
Use .env.example como referencia.
PORT=3000
APP_TIMEZONE=America/Sao_Paulo
AUTH_ENABLED=true
API_TOKEN=troque-este-token-por-um-valor-seguro
DATABASE_URL=postgresql://USER:PASSWORD@HOST/DBNAME?sslmode=require
DATABASE_SSL=true
PUPPETEER_HEADLESS=true
SCHEDULER_ENABLED=true
SCHEDULER_TIMEZONE=America/Sao_Paulo
SCHEDULER_CRON_1=0 11 * * *
SCHEDULER_CRON_2=0 14 * * *
SCRAPER_PARALLEL_COLLECTION=false
SCRAPER_NAV_TIMEOUT_MS=90000
SCRAPER_SELECTOR_TIMEOUT_MS=45000
SCRAPER_RETRY_MAX_ATTEMPTS=3
SCRAPER_RETRY_DELAY_MS=180000Observacoes importantes:
AUTH_ENABLED=trueprotege as rotas/api/cotacoes/*.DATABASE_SSL=truee recomendado para Neon.SCHEDULER_ENABLED=falsedesliga coletas automaticas.SCRAPER_PARALLEL_COLLECTION=falsee mais conservador para ambientes pequenos./api/cotacoes/todosrespeitaSCRAPER_PARALLEL_COLLECTIONmesmo usando resposta parcial por fonte.force=trueem rotas de consulta dispara scraping ao vivo, trafego externo e escrita no banco.
npm startSobe a API em modo producao com node src/app.js.
npm run devSobe a API em modo desenvolvimento com node --watch.
npm run check:chromeVerifica se o Chrome do Puppeteer esta disponivel.
npm testAtualmente falha de proposito com no test specified; ainda nao ha suite de testes configurada.
Base local: http://localhost:3000
GET /: status simples da API.GET /health: health check leve para uptime.GET /health/deep: diagnostico operacional completo.GET /docs: Swagger UI.GET /openapi.yaml: contrato OpenAPI bruto.
/health/deep verifica banco, snapshots recentes, Chrome do Puppeteer e scheduler. Ele retorna ok, degraded ou fail e nao executa scraping.
Quando AUTH_ENABLED=true, todas as rotas em /api/cotacoes/* exigem token.
Formatos aceitos:
Authorization: Bearer <API_TOKEN>x-api-token: <API_TOKEN>
Exemplo:
curl -H "Authorization: Bearer SEU_TOKEN" http://localhost:3000/api/cotacoes/todosFontes aceitas em parametros: all, coamo, cvale, lar, granos.
GET /api/cotacoes/coamo: cotacoes atuais da Coamo.GET /api/cotacoes/cvale: cotacoes atuais da C.Vale.GET /api/cotacoes/lar: cotacoes atuais da LAR.GET /api/cotacoes/granos: cotacoes atuais da Granos.GET /api/cotacoes/todos: resposta consolidada das fontes oficiais.GET /api/cotacoes/filtro: cotacoes atuais filtradas.GET /api/cotacoes/melhor-preco: maior preco encontrado para um grao.GET /api/cotacoes/comparativo: comparativo entre fontes para um grao.GET /api/cotacoes/variacao: variacao historica de uma fonte especifica.GET /api/cotacoes/periodo: itens historicos dentro de um periodo.GET /api/cotacoes/exportar: exporta cotacoes filtradas em CSV.GET /api/cotacoes/historico: snapshots historicos salvos.
Parametros comuns:
force=true: ignora cache e tenta uma nova coleta.fonte=all|coamo|cvale|lar|granos: seleciona a origem quando a rota permite.grao,local,descricao,fornecedor,unidade: filtros textuais.dataInicio=YYYY-MM-DDedataFim=YYYY-MM-DD: periodo historico.limit=50: limite de snapshots ou itens, conforme a rota.
Exemplos:
curl -H "Authorization: Bearer SEU_TOKEN" "http://localhost:3000/api/cotacoes/filtro?fonte=all&grao=soja"curl -H "Authorization: Bearer SEU_TOKEN" "http://localhost:3000/api/cotacoes/melhor-preco?fonte=all&grao=milho"curl -H "Authorization: Bearer SEU_TOKEN" "http://localhost:3000/api/cotacoes/periodo?fonte=coamo&dataInicio=2026-06-01&dataFim=2026-06-24"A rota consolidada nao deve derrubar a resposta inteira quando uma fonte falha. Ela retorna version: 2, partial e um envelope por fonte:
{
"version": 2,
"partial": true,
"coamo": {
"ok": true,
"data": [],
"stale": false,
"error": null
},
"cvale": {
"ok": true,
"data": [],
"stale": true,
"error": {
"message": "Falha ao coletar cotacoes da C.Vale",
"statusCode": 502,
"details": null
}
},
"larAgro": {
"ok": false,
"data": [],
"stale": false,
"error": {
"message": "Falha ao coletar cotacoes da LAR",
"statusCode": 502,
"details": null
}
},
"granos": {
"ok": true,
"data": [],
"stale": false,
"error": null
}
}stale=true significa que a API devolveu o ultimo dado valido conhecido porque a coleta atual falhou.
- A API sobe, valida configuracoes, valida Chrome, inicializa o banco e aquece o cache com
cotacoes_ultima. - Uma consulta sem
force=trueusa cache em memoria, depois banco, depois scraping se nao houver dado salvo. - Uma consulta com
force=trueexecuta scraping ao vivo. - Coleta bem-sucedida:
- insere um snapshot em
cotacoes_historico; - atualiza o ultimo snapshot em
cotacoes_ultima; - atualiza o cache em memoria.
- insere um snapshot em
- Coleta com erro ou payload vazio nao salva dado novo.
Tabelas criadas automaticamente na subida:
cotacoes_historicocotacoes_ultimalogs_requisicoes
src/app.js: bootstrap da API, middlewares, Swagger, health e rotas.src/routes/cotacoesRoutes.js: definicao das rotas HTTP de cotacoes.src/services/cotacaoService.js: ponto unico de exportacao dos services.src/services/cotacoes/currentCotacaoService.js: cache, scraping, retry e snapshots atuais.src/services/cotacoes/analysisCotacaoService.js: filtros, melhor preco, comparativo e CSV.src/services/cotacoes/historyCotacaoService.js: historico, periodo e variacao.src/services/healthService.js: diagnostico operacional profundo.src/scrapers/: scrapers Puppeteer de Coamo, C.Vale, LAR, Granos e fontes experimentais.src/database/: conexao, schema e repositorios Postgres.src/utils/: normalizacao, filtros, datas, CSV e utilitarios do Puppeteer.src/jobs/cotacaoScheduler.js: jobs automaticos de coleta.scripts/: instalacao e verificacao do Chrome do Puppeteer.openapi.yaml: contrato publico da API.docs/: documentacao tecnica e relatorios.
- O scheduler roda dentro do mesmo processo da API.
- Em plataformas com sleep/scale-to-zero, os jobs nao executam enquanto o processo estiver parado.
- Em ambiente limitado, mantenha
SCRAPER_PARALLEL_COLLECTION=false. - Se houver timeout de scraping, ajuste
SCRAPER_NAV_TIMEOUT_MSeSCRAPER_SELECTOR_TIMEOUT_MS. - A C.Vale pode ficar indisponivel fora dos horarios aceitos pelo site de origem.
- Nao exponha
.env,DATABASE_URL,API_TOKENou tokens de plataforma.
- Swagger UI:
http://localhost:3000/docs - OpenAPI bruto:
http://localhost:3000/openapi.yaml - Arquivo fonte:
openapi.yaml
Quando uma rota, parametro, contrato de resposta ou variavel de ambiente mudar, atualize este README e o openapi.yaml.
ISC