Rastro — compose Coolify + dados de usuário para migração
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
# ============================================================================
|
||||
# Rastro no Coolify — variáveis de ambiente. Configure no ambiente do recurso
|
||||
# no Coolify (ou cole como .env do Compose). Valores REAIS de segredo/cert/ONE:
|
||||
# copie de /opt/rastro/.env da VPS antiga (posso transferir via scp com segurança).
|
||||
# ============================================================================
|
||||
|
||||
# ---- Imagens (registro Gitea) ----
|
||||
# ATENÇÃO ao hostname: é o MESMO Gitea, com duas rotas.
|
||||
# - PUSH (Makefile, de fora): gitea.EXTERNO.utic.app.br
|
||||
# - PULL (Coolify, interno): gitea.INTERNO.utic.app.br ← use este aqui
|
||||
REGISTRY=gitea.interno.utic.app.br
|
||||
NAMESPACE=ericoalmeida # seu usuário no Gitea
|
||||
TAG=latest
|
||||
|
||||
# ---- Domínios (MUDAM na máquina nova) ----
|
||||
WEB_DOMAIN=rastro.SEU-NOVO-DOMINIO.app.br
|
||||
ADMIN_DOMAIN=admin.rastro.SEU-NOVO-DOMINIO.app.br
|
||||
|
||||
# ---- Banco ----
|
||||
POSTGRES_USER=rastro
|
||||
POSTGRES_PASSWORD=troque-por-senha-forte # rotacione ao migrar
|
||||
POSTGRES_DB=rastro
|
||||
|
||||
# ---- Fila ----
|
||||
RABBITMQ_DEFAULT_USER=rastro
|
||||
RABBITMQ_DEFAULT_PASS=troque-por-senha-forte
|
||||
RASTRO_EXCHANGE=rastro.passagens
|
||||
RASTRO_QUEUE=rastro.passagens.processar
|
||||
|
||||
# ---- Object storage ----
|
||||
MINIO_ROOT_USER=rastro
|
||||
MINIO_ROOT_PASSWORD=troque-por-senha-forte
|
||||
MINIO_BUCKET=rastro-photos
|
||||
|
||||
# ---- Segurança do backend ----
|
||||
JWT_SECRET=troque-por-uma-chave-aleatoria-longa
|
||||
SESSION_COOKIE_NAME=rastro_session
|
||||
RATE_LIMIT_MAX=1000
|
||||
|
||||
# ---- Tetos de conexão por processo (soma < max_connections do Postgres) ----
|
||||
DB_CONNECTION_LIMIT_BACKEND=12
|
||||
DB_CONNECTION_LIMIT_PROCESSOR=8
|
||||
DB_CONNECTION_LIMIT_DFE_WORKER=12
|
||||
DB_CONNECTION_LIMIT_INGESTOR=5
|
||||
DB_CONNECTION_LIMIT_MIGRATE=5
|
||||
DB_POOL_TIMEOUT=15
|
||||
|
||||
# ---- Feed ONE / drenagem (copie os reais do .env antigo) ----
|
||||
ONE_TP_AMB=1
|
||||
ONE_HOST=one.svrs.rs.gov.br
|
||||
ONE_TP_DIST=1,4
|
||||
ONE_CUF=41
|
||||
ONE_CNPJ_OPER=
|
||||
ONE_VER_APLIC=rastro-1.0
|
||||
ONE_POLL_INTERVAL=120
|
||||
ONE_MAX_BATCHES=15
|
||||
ONE_BATCH_DELAY_MS=1200
|
||||
ONE_IND_RESUMO=0
|
||||
|
||||
# ---- Certificado A1 (o .pfx precisa ir para a máquina nova — ver runbook) ----
|
||||
CERT_HOST_DIR=/data/rastro/certificado
|
||||
DFE_CERT_PFX_CONTAINER_PATH=/certs/11de260603452f3c.pfx
|
||||
DFE_CERT_PASSPHRASE= # copie do .env antigo
|
||||
DFE_TLS_REJECT_UNAUTHORIZED=false
|
||||
|
||||
# ---- SEFAZ-PR / consultas (copie os reais do .env antigo, se usar) ----
|
||||
SEFAZ_PR_DFE_URL=
|
||||
SEFAZ_PR_DFE_USER=
|
||||
SEFAZ_PR_DFE_PASSWORD=
|
||||
|
||||
# ---- OSRM (só quando levar o grafo do Brasil) ----
|
||||
OSRM_URL=http://osrm:5000
|
||||
OSRM_DATA_DIR=/data/rastro/osrm
|
||||
|
||||
# ---- Inteligência (Python) ----
|
||||
INTEL_TOP_COMPANIES=200
|
||||
INTEL_TOP_COMMODITIES=50
|
||||
INTEL_HORIZON_WEEKS=8
|
||||
INTEL_CYCLE_HOURS=24
|
||||
@@ -0,0 +1,145 @@
|
||||
# Migração do Rastro → máquina nova (Gitea + Coolify)
|
||||
|
||||
Guia para mover a produção do Rastro (hoje em Docker Swarm na VPS 136.0.53.6) para a
|
||||
máquina nova, que usa **Coolify** e um **Gitea interno** (git + registro de imagem Docker).
|
||||
|
||||
**Escopo:** migra a ESTRUTURA (o stack) + só os DADOS DE USUÁRIO/CONFIG. Documentos,
|
||||
passagens, rotas e mídias NÃO vão (já foram limpos; a base voltou a ~1,6 GB).
|
||||
|
||||
---
|
||||
|
||||
## Realidade do Rastro (importante)
|
||||
|
||||
Não é uma imagem única. São **2 imagens custom** + **5 de infra públicas**:
|
||||
|
||||
| Imagem | Origem | Serviços |
|
||||
|---|---|---|
|
||||
| `rastro-node` | build local → **Gitea** | backend, web, admin, ingestor, processor, dfe-worker, migrate |
|
||||
| `rastro-analytics` | build local → **Gitea** | analytics (Python) |
|
||||
| `timescale/timescaledb-ha:pg16` | Docker Hub | db |
|
||||
| `rabbitmq:3-management` | Docker Hub | rabbitmq |
|
||||
| `minio/minio:latest` | Docker Hub | minio |
|
||||
| `gotenberg/gotenberg:8` | Docker Hub | gotenberg |
|
||||
| `osrm/osrm-backend:latest` | Docker Hub | osrm (opcional) |
|
||||
|
||||
Por isso o deploy no Coolify é via **Docker Compose** (`deploy/coolify-compose.yml`), não
|
||||
"1 app = 1 imagem".
|
||||
|
||||
**Registro — mesmo Gitea, duas rotas:**
|
||||
- **PUSH** (build de fora, ex.: VPS antiga/seu Mac): `gitea.externo.utic.app.br` — o único
|
||||
que resolve fora da rede da UTIC (o `interno` deu timeout).
|
||||
- **PULL** (Coolify, que é interno): `gitea.interno.utic.app.br` — é o hostname que a máquina
|
||||
do Coolify enxerga, e sem credencial (interno). É o que vai nas `image:` do compose.
|
||||
|
||||
As imagens já estão publicadas (namespace **ericoalmeida**):
|
||||
`…/ericoalmeida/rastro-node:latest` e `…/ericoalmeida/rastro-analytics:latest`. Veja em
|
||||
`https://gitea.externo.utic.app.br/ericoalmeida/-/packages`. (`docker.bretones.app` que o Leo
|
||||
citou é o registro de OUTRO projeto dele — não é o nosso.)
|
||||
|
||||
---
|
||||
|
||||
## Pré-requisitos (você faz no navegador)
|
||||
|
||||
1. **Usuário no Gitea** em https://gitea.externo.utic.app.br (crie ou use o seu).
|
||||
2. **Token de escrita de pacote:** Settings → Applications → *Generate New Token* com o
|
||||
escopo de **write:package** (registro Docker). Guarde o token.
|
||||
3. Anote seu **namespace** (o usuário/organização — ex.: `erico`). As imagens vão para
|
||||
`gitea.externo.utic.app.br/<namespace>/rastro-node:latest`.
|
||||
|
||||
---
|
||||
|
||||
## Fase 1 — Enviar as imagens para o Gitea
|
||||
|
||||
De uma máquina que **alcança** `gitea.externo.utic.app.br` e tem o repo (a VPS antiga
|
||||
serve — é amd64 e rápida; ou seu Mac). Na raiz do repo:
|
||||
|
||||
```bash
|
||||
make login NAMESPACE=<seu-namespace> # docker login (usuário + token)
|
||||
make deploy NAMESPACE=<seu-namespace> # build + push das 2 imagens
|
||||
```
|
||||
|
||||
> `make deploy` = build (`--platform linux/amd64`) + push. Se a máquina nova for **arm64**,
|
||||
> rode `make deploy PLATFORM=linux/arm64` (buildando no Mac, que é ARM nativo).
|
||||
|
||||
Confirme no Gitea (aba Packages do seu usuário) que `rastro-node` e `rastro-analytics`
|
||||
aparecem.
|
||||
|
||||
---
|
||||
|
||||
## Fase 2 — Subir o stack no Coolify
|
||||
|
||||
1. No Coolify: **New Resource → Docker Compose**.
|
||||
2. Cole o conteúdo de `deploy/coolify-compose.yml`.
|
||||
3. **Environment variables:** use `deploy/.env.coolify.example` como base. Preencha os
|
||||
segredos/cert/ONE com os valores reais (copie de `/opt/rastro/.env` da VPS antiga —
|
||||
posso transferir por scp). Ajuste `WEB_DOMAIN`/`ADMIN_DOMAIN` para os domínios novos e
|
||||
`REGISTRY`/`NAMESPACE`.
|
||||
4. **Registro privado:** aponte o Coolify para o Gitea (Sources/Registries) com o mesmo
|
||||
usuário+token, para ele puxar `rastro-node`/`rastro-analytics`. (Se o Gitea for interno
|
||||
à máquina do Coolify, o pull é direto, sem credencial — como o Leo disse.)
|
||||
5. **Domínios / roteamento (a parte fina):** o front chama a API em **same-origin**
|
||||
(`/api` e `/health` no MESMO domínio). Configure no Coolify:
|
||||
- `web` → `https://${WEB_DOMAIN}` (porta 39000)
|
||||
- `admin`→ `https://${ADMIN_DOMAIN}` (porta 39020)
|
||||
- `backend` → responder `${WEB_DOMAIN}/api`, `${WEB_DOMAIN}/health`,
|
||||
`${ADMIN_DOMAIN}/api`, `${ADMIN_DOMAIN}/health` (porta 39010) — roteamento por PATH.
|
||||
Se o roteamento por path do Coolify complicar, a alternativa é dar ao backend um domínio
|
||||
próprio `api.<dominio>` e **rebuildar** web/admin com `VITE_API_BASE_URL=https://api.<dominio>`
|
||||
(o CORS já cobre isso via `CORS_ORIGINS`).
|
||||
6. Deploy. Na 1ª subida, deixe **ingestor** e **dfe-worker** parados (scale 0) — sobem só
|
||||
quando você quiser puxar dados. O `migrate` roda uma vez (cria o schema) e sai.
|
||||
|
||||
---
|
||||
|
||||
## Fase 3 — Restaurar os dados de usuário
|
||||
|
||||
O dump está em `data-migration/rastro-userdata.sql` (2,1 MB — usuários, RBAC, 5.922
|
||||
pórticos, blacklist, thresholds de calibragem, ncm_ref, cursores).
|
||||
|
||||
Depois que o `migrate` criar o schema, carregue o dump no container do db (ex.: via
|
||||
terminal do Coolify no serviço `db`, ou `docker exec`):
|
||||
|
||||
```bash
|
||||
# copie o arquivo para dentro do container do db, então:
|
||||
psql -U rastro -d rastro -v ON_ERROR_STOP=1 <<'SQL'
|
||||
BEGIN;
|
||||
TRUNCATE app_user, role, permission, role_permission, user_role, user_session,
|
||||
equipment, volante_selection, ingestion_cursor, ingestion_control, ncm_ref,
|
||||
intel_threshold, entity_blacklist, blacklist_event, audit_log, access_request_log,
|
||||
process_lock RESTART IDENTITY CASCADE;
|
||||
SQL
|
||||
psql -U rastro -d rastro -f /caminho/rastro-userdata.sql # tem SET session_replication_role p/ FK circular
|
||||
psql -U rastro -d rastro -c "ANALYZE;"
|
||||
```
|
||||
|
||||
> O `TRUNCATE` antes evita conflito com qualquer linha que o schema-init tenha semeado.
|
||||
> O dump já desabilita os triggers de FK (por causa da FK circular do `app_user`).
|
||||
|
||||
Login: os mesmos usuários da VPS antiga (ex.: ericoengcomp@gmail.com). Se preferir começar
|
||||
com um admin novo, dá pra semear com `pnpm --filter @rastro/db seed` (variáveis `ADMIN_SEED_*`).
|
||||
|
||||
---
|
||||
|
||||
## Fase 4 — Certificado A1 e OSRM (quando precisar)
|
||||
|
||||
- **Certificado A1 (.pfx)** — necessário para a drenagem/consultas SEFAZ. Copie o `.pfx` da
|
||||
VPS antiga (`/opt/rastro/certificado/`) para `CERT_HOST_DIR` na máquina nova e confira
|
||||
`DFE_CERT_PFX_CONTAINER_PATH`/`DFE_CERT_PASSPHRASE`. Sem ele, ingestor/dfe-worker não
|
||||
autenticam no fisco (mas o resto do sistema sobe).
|
||||
- **OSRM (rotas no mapa)** — descomente o serviço `osrm` no compose e leve o grafo do Brasil
|
||||
(`brazil.osrm*`, ~12-15 GB) para `OSRM_DATA_DIR`. Sem ele, o roteamento vira no-op (sem
|
||||
linhas no mapa) — aceitável até haver dado transacional de fato.
|
||||
|
||||
---
|
||||
|
||||
## Verificação
|
||||
|
||||
- `web`/`admin` abrem e o login funciona (usuário do dump).
|
||||
- Admin lista os **5.922 pórticos** (equipment) e as **permissões/roles**.
|
||||
- `migrate` terminou como *complete/exited 0*; sem erro novo nos logs dos serviços.
|
||||
- Banco: `SELECT count(*) FROM equipment;` → 5922; `FROM app_user;` → seus usuários.
|
||||
|
||||
## Rollback
|
||||
|
||||
A VPS antiga (136.0.53.6) continua intacta (stack fora do ar, volumes de 84→2,3 GB
|
||||
preservados). Nada aqui a toca — se algo falhar na máquina nova, a origem segue disponível.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,298 @@
|
||||
# ============================================================================
|
||||
# Rastro — Docker Compose para o COOLIFY (máquina nova).
|
||||
#
|
||||
# Derivado do deploy/stack.yml (Swarm). Diferenças:
|
||||
# - Sem labels do Traefik: no Coolify você define os DOMÍNIOS pela UI (por serviço),
|
||||
# e o proxy do Coolify gera o roteamento. Ver deploy/MIGRACAO-COOLIFY.md.
|
||||
# - Sem rede `erico-net` externa: o Coolify põe todos os serviços do compose na
|
||||
# MESMA rede — eles se acham pelo nome do serviço (db, rabbitmq, minio, osrm…).
|
||||
# - `shm_size` no db (o Compose respeita, diferente do Swarm que exigia tmpfs).
|
||||
# - `deploy.resources.limits` mantidos (o `docker compose` do Coolify honra) —
|
||||
# ajuste conforme a capacidade da máquina nova.
|
||||
# - `migrate` roda só o SCHEMA (sem seed/bootstrap): os usuários/config vêm do
|
||||
# dump data-migration/rastro-userdata.sql (restaurado depois). Ver runbook.
|
||||
# - As imagens custom vêm do Gitea; as de infra, do Docker Hub.
|
||||
#
|
||||
# Variáveis ${...} → configure no ambiente do recurso no Coolify (ou .env).
|
||||
# ============================================================================
|
||||
|
||||
x-app-env: &app-env
|
||||
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public
|
||||
RABBITMQ_URL: amqp://${RABBITMQ_DEFAULT_USER}:${RABBITMQ_DEFAULT_PASS}@rabbitmq:5672
|
||||
RASTRO_EXCHANGE: ${RASTRO_EXCHANGE:-rastro.passagens}
|
||||
RASTRO_QUEUE: ${RASTRO_QUEUE:-rastro.passagens.processar}
|
||||
|
||||
services:
|
||||
# ------------------------------------------------------------------ Infra
|
||||
db:
|
||||
image: timescale/timescaledb-ha:pg16
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
shm_size: 1gb
|
||||
volumes:
|
||||
- db_data:/home/postgres/pgdata
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 15
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '4.0', memory: 6G }
|
||||
|
||||
rabbitmq:
|
||||
image: rabbitmq:3-management
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER}
|
||||
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS}
|
||||
volumes:
|
||||
- rabbitmq_data:/var/lib/rabbitmq
|
||||
healthcheck:
|
||||
test: ['CMD', 'rabbitmq-diagnostics', '-q', 'ping']
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '1.0', memory: 640M }
|
||||
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
restart: unless-stopped
|
||||
command: server /data --console-address ":9001"
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '1.0', memory: 640M }
|
||||
|
||||
gotenberg:
|
||||
image: gotenberg/gotenberg:8
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- gotenberg
|
||||
- --chromium-disable-javascript=false
|
||||
- --api-timeout=60s
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '2.0', memory: 1536M }
|
||||
|
||||
# OSRM (roteamento por vias) — OPCIONAL na 1ª subida. Precisa do grafo do Brasil
|
||||
# (~12-15GB) em OSRM_DATA_DIR. Sem ele, deixe COMENTADO e o app sobe sem rotas;
|
||||
# o processor/dfe-worker caem para no-op de roteamento. Habilite quando levar o grafo.
|
||||
# osrm:
|
||||
# image: osrm/osrm-backend:latest
|
||||
# restart: unless-stopped
|
||||
# command: ['osrm-routed', '--algorithm', 'mld', '--mmap', '--max-matching-size', '2000', '/data/brazil.osrm']
|
||||
# volumes:
|
||||
# - ${OSRM_DATA_DIR:-/data/rastro/osrm}:/data:ro
|
||||
# deploy:
|
||||
# resources:
|
||||
# limits: { cpus: '2.0', memory: 6G }
|
||||
|
||||
# ------------------------------------------------------------- Init (roda 1x)
|
||||
# SÓ SCHEMA (sem seed/bootstrap): os usuários/config vêm do dump. Roda uma vez e sai.
|
||||
migrate:
|
||||
image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest}
|
||||
restart: "no"
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
<<: *app-env
|
||||
NODE_ENV: production
|
||||
DB_CONNECTION_LIMIT: ${DB_CONNECTION_LIMIT_MIGRATE:-5}
|
||||
DB_POOL_TIMEOUT: ${DB_POOL_TIMEOUT:-15}
|
||||
command: >
|
||||
sh -c "wait-for-db &&
|
||||
pnpm --filter @rastro/db migrate &&
|
||||
pnpm --filter @rastro/db postgis &&
|
||||
pnpm --filter @rastro/db timescale &&
|
||||
pnpm --filter @rastro/db intel &&
|
||||
pnpm --filter @rastro/db analyze"
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '2.0', memory: 1536M }
|
||||
|
||||
# ---------------------------------------------------------------- Drenagem
|
||||
# OBS: para migração inicial LEVE, deixe ingestor/dfe-worker parados (scale 0 no
|
||||
# Coolify) até querer puxar dados. O sistema serve os dados existentes sem eles.
|
||||
ingestor:
|
||||
image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest}
|
||||
restart: unless-stopped
|
||||
depends_on: { db: { condition: service_healthy } }
|
||||
environment:
|
||||
<<: *app-env
|
||||
NODE_ENV: production
|
||||
DB_CONNECTION_LIMIT: ${DB_CONNECTION_LIMIT_INGESTOR:-5}
|
||||
DB_POOL_TIMEOUT: ${DB_POOL_TIMEOUT:-15}
|
||||
ONE_TP_AMB: ${ONE_TP_AMB:-1}
|
||||
ONE_VER_APLIC: ${ONE_VER_APLIC:-rastro-1.0}
|
||||
ONE_HOST: ${ONE_HOST:-one.svrs.rs.gov.br}
|
||||
ONE_TP_DIST: ${ONE_TP_DIST:-1,4}
|
||||
ONE_CUF: ${ONE_CUF:-41}
|
||||
ONE_CNPJ_OPER: ${ONE_CNPJ_OPER:-}
|
||||
ONE_POLL_INTERVAL: ${ONE_POLL_INTERVAL:-120}
|
||||
ONE_MAX_BATCHES: ${ONE_MAX_BATCHES:-15}
|
||||
ONE_BATCH_DELAY_MS: ${ONE_BATCH_DELAY_MS:-1200}
|
||||
ONE_IND_RESUMO: ${ONE_IND_RESUMO:-0}
|
||||
DFE_CERT_PFX_PATH: ${DFE_CERT_PFX_CONTAINER_PATH:-/certs/11de260603452f3c.pfx}
|
||||
DFE_CERT_PASSPHRASE: ${DFE_CERT_PASSPHRASE:-}
|
||||
CERT_DIR: /certs
|
||||
DFE_TLS_REJECT_UNAUTHORIZED: ${DFE_TLS_REJECT_UNAUTHORIZED:-false}
|
||||
MINIO_ENDPOINT: minio
|
||||
MINIO_PORT: '9000'
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
MINIO_BUCKET: ${MINIO_BUCKET:-rastro-photos}
|
||||
command: sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/ingestor start"
|
||||
volumes:
|
||||
- ${CERT_HOST_DIR:-/data/rastro/certificado}:/certs:ro
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '1.0', memory: 640M }
|
||||
|
||||
processor:
|
||||
image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest}
|
||||
restart: unless-stopped
|
||||
depends_on: { db: { condition: service_healthy } }
|
||||
environment:
|
||||
<<: *app-env
|
||||
NODE_ENV: production
|
||||
DB_CONNECTION_LIMIT: ${DB_CONNECTION_LIMIT_PROCESSOR:-8}
|
||||
DB_POOL_TIMEOUT: ${DB_POOL_TIMEOUT:-15}
|
||||
SEFAZ_PR_DFE_URL: ${SEFAZ_PR_DFE_URL:-}
|
||||
SEFAZ_PR_DFE_USER: ${SEFAZ_PR_DFE_USER:-}
|
||||
SEFAZ_PR_DFE_PASSWORD: ${SEFAZ_PR_DFE_PASSWORD:-}
|
||||
OSRM_URL: ${OSRM_URL:-http://osrm:5000}
|
||||
REROUTE_STALE_INTERVAL_MIN: ${REROUTE_STALE_INTERVAL_MIN:-15}
|
||||
command: sh -c "wait-for-db schema rabbitmq && pnpm --filter @rastro/processor start"
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '2.0', memory: 1G }
|
||||
|
||||
dfe-worker:
|
||||
image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest}
|
||||
restart: unless-stopped
|
||||
depends_on: { db: { condition: service_healthy } }
|
||||
environment:
|
||||
<<: *app-env
|
||||
NODE_ENV: production
|
||||
DB_CONNECTION_LIMIT: ${DB_CONNECTION_LIMIT_DFE_WORKER:-12}
|
||||
DB_POOL_TIMEOUT: ${DB_POOL_TIMEOUT:-15}
|
||||
SEFAZ_PR_DFE_URL: ${SEFAZ_PR_DFE_URL:-}
|
||||
SEFAZ_PR_DFE_USER: ${SEFAZ_PR_DFE_USER:-}
|
||||
SEFAZ_PR_DFE_PASSWORD: ${SEFAZ_PR_DFE_PASSWORD:-}
|
||||
OSRM_URL: ${OSRM_URL:-http://osrm:5000}
|
||||
DFE_GEN_INTERVAL: ${DFE_GEN_INTERVAL:-20}
|
||||
DFE_GEN_BATCH: ${DFE_GEN_BATCH:-25}
|
||||
DFE_GEN_CONCURRENCY: ${DFE_GEN_CONCURRENCY:-6}
|
||||
DFE_REFRESH_TTL_HOURS: ${DFE_REFRESH_TTL_HOURS:-12}
|
||||
DFE_GEN_ROUTE: ${DFE_GEN_ROUTE:-true}
|
||||
SEFAZ_WS_TP_AMB: ${SEFAZ_WS_TP_AMB:-1}
|
||||
SEFAZ_WS_ENDPOINTS: ${SEFAZ_WS_ENDPOINTS:-}
|
||||
SEFAZ_WS_MAX_CTE: ${SEFAZ_WS_MAX_CTE:-20}
|
||||
SEFAZ_ARQUIVOXML_ENDPOINTS: ${SEFAZ_ARQUIVOXML_ENDPOINTS:-}
|
||||
SEFAZ_ARQUIVOXML_CUF: ${SEFAZ_ARQUIVOXML_CUF:-41}
|
||||
SEFAZ_ARQUIVOXML_ORGAO: ${SEFAZ_ARQUIVOXML_ORGAO:-SEFA-PARANA}
|
||||
SEFAZ_ARQUIVOXML_SETOR: ${SEFAZ_ARQUIVOXML_SETOR:-AGAA}
|
||||
SEFAZ_ARQUIVOXML_VERAPLIC: ${SEFAZ_ARQUIVOXML_VERAPLIC:-PR_Rastro_v1}
|
||||
SEFAZ_ARQUIVOXML_MATR: ${SEFAZ_ARQUIVOXML_MATR:-999999}
|
||||
SEFAZ_ARQUIVOXML_MAX_NFE: ${SEFAZ_ARQUIVOXML_MAX_NFE:-40}
|
||||
SEFAZ_CONSULTADFE_ENDPOINTS: ${SEFAZ_CONSULTADFE_ENDPOINTS:-}
|
||||
DFE_CERT_PFX_PATH: ${DFE_CERT_PFX_CONTAINER_PATH:-/certs/11de260603452f3c.pfx}
|
||||
DFE_CERT_PASSPHRASE: ${DFE_CERT_PASSPHRASE:-}
|
||||
CERT_DIR: /certs
|
||||
DFE_TLS_REJECT_UNAUTHORIZED: ${DFE_TLS_REJECT_UNAUTHORIZED:-false}
|
||||
command: sh -c "wait-for-db schema && pnpm --filter @rastro/processor start:worker"
|
||||
volumes:
|
||||
- ${CERT_HOST_DIR:-/data/rastro/certificado}:/certs:ro
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '2.0', memory: 1G }
|
||||
|
||||
analytics:
|
||||
image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-analytics:${TAG:-latest}
|
||||
restart: unless-stopped
|
||||
depends_on: { db: { condition: service_healthy } }
|
||||
environment:
|
||||
<<: *app-env
|
||||
INTEL_TOP_COMPANIES: ${INTEL_TOP_COMPANIES:-200}
|
||||
INTEL_TOP_COMMODITIES: ${INTEL_TOP_COMMODITIES:-50}
|
||||
INTEL_HORIZON_WEEKS: ${INTEL_HORIZON_WEEKS:-8}
|
||||
INTEL_CYCLE_HOURS: ${INTEL_CYCLE_HOURS:-24}
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '2.0', memory: 1536M }
|
||||
|
||||
# ---------------------------------------------------------------- Backend / Fronts
|
||||
# No Coolify, atribua os DOMÍNIOS a estes 3 serviços pela UI (ver runbook). O
|
||||
# backend precisa responder /api e /health NO MESMO domínio do web e do admin
|
||||
# (o front chama same-origin). Configure isso pelo roteamento por path do Coolify.
|
||||
backend:
|
||||
image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest}
|
||||
restart: unless-stopped
|
||||
depends_on: { db: { condition: service_healthy } }
|
||||
environment:
|
||||
<<: *app-env
|
||||
NODE_ENV: production
|
||||
DB_CONNECTION_LIMIT: ${DB_CONNECTION_LIMIT_BACKEND:-12}
|
||||
DB_POOL_TIMEOUT: ${DB_POOL_TIMEOUT:-15}
|
||||
BACKEND_PORT: '39010'
|
||||
JWT_SECRET: ${JWT_SECRET}
|
||||
SESSION_COOKIE_NAME: ${SESSION_COOKIE_NAME:-rastro_session}
|
||||
CORS_ORIGINS: https://${WEB_DOMAIN},https://${ADMIN_DOMAIN}
|
||||
RATE_LIMIT_MAX: ${RATE_LIMIT_MAX:-1000}
|
||||
GOTENBERG_URL: http://gotenberg:3000
|
||||
MINIO_ENDPOINT: minio
|
||||
MINIO_PORT: '9000'
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
MINIO_BUCKET: ${MINIO_BUCKET:-rastro-photos}
|
||||
command: sh -c "wait-for-db schema && pnpm --filter @rastro/backend start"
|
||||
# Porta interna do backend (aponte o domínio do Coolify para 39010, path /api e /health)
|
||||
expose:
|
||||
- "39010"
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '2.0', memory: 1G }
|
||||
|
||||
web:
|
||||
image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
<<: *app-env
|
||||
VITE_DEV_HELPERS: 'false'
|
||||
PREVIEW_ALLOWED_HOSTS: ${WEB_DOMAIN}
|
||||
command: sh -c "pnpm --filter web preview --host 0.0.0.0 --port 39000"
|
||||
expose:
|
||||
- "39000"
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '1.0', memory: 640M }
|
||||
|
||||
admin:
|
||||
image: ${REGISTRY:-gitea.interno.utic.app.br}/${NAMESPACE:-ericoalmeida}/rastro-node:${TAG:-latest}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
<<: *app-env
|
||||
VITE_DEV_HELPERS: 'false'
|
||||
PREVIEW_ALLOWED_HOSTS: ${ADMIN_DOMAIN}
|
||||
command: sh -c "pnpm --filter admin preview --host 0.0.0.0 --port 39020"
|
||||
expose:
|
||||
- "39020"
|
||||
deploy:
|
||||
resources:
|
||||
limits: { cpus: '1.0', memory: 640M }
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
rabbitmq_data:
|
||||
minio_data:
|
||||
Reference in New Issue
Block a user