Files
leadcast/docker-compose.yml
T
2026-07-28 20:23:41 -03:00

126 lines
5.0 KiB
YAML

name: leads-extractor
services:
postgres:
image: postgres:18
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB:-leads_extractor}
POSTGRES_USER: ${POSTGRES_USER:-leads}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-leads}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
interval: 5s
timeout: 5s
retries: 20
start_period: 10s
volumes:
- postgres_data:/var/lib/postgresql
networks:
- internal
backend:
build:
context: ./backend
dockerfile: Dockerfile
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
SERVER_HOST: 0.0.0.0
SERVER_PORT: 8080
FRONTEND_ORIGIN: ${FRONTEND_URL:-http://localhost:8090}
DATABASE_URL: postgres://${POSTGRES_USER:-leads}:${POSTGRES_PASSWORD:-leads}@postgres:5432/${POSTGRES_DB:-leads_extractor}
MEDIA_DIR: /data/media
RUST_LOG: ${RUST_LOG:-backend=info}
AUTH_USERNAME: ${AUTH_USERNAME}
AUTH_PASSWORD: ${AUTH_PASSWORD}
AUTH_SESSION_TTL_SECS: ${AUTH_SESSION_TTL_SECS:-43200}
AUTH_COOKIE_SECURE: ${AUTH_COOKIE_SECURE:-false}
AUTH_COOKIE_SAME_SITE: ${AUTH_COOKIE_SAME_SITE:-strict}
RATE_LIMIT_ENABLED: ${RATE_LIMIT_ENABLED:-true}
RATE_LIMIT_BURST_SIZE: ${RATE_LIMIT_BURST_SIZE:-120}
RATE_LIMIT_PERIOD_MS: ${RATE_LIMIT_PERIOD_MS:-200}
RATE_LIMIT_LOGIN_BURST_SIZE: ${RATE_LIMIT_LOGIN_BURST_SIZE:-5}
RATE_LIMIT_LOGIN_PERIOD_SECS: ${RATE_LIMIT_LOGIN_PERIOD_SECS:-30}
OPENROUTER_API_KEY: ${OPENROUTER_API_KEY}
OPENROUTER_BASE_URL: ${OPENROUTER_BASE_URL:-https://openrouter.ai/api/v1}
OPENROUTER_PRIMARY_MODEL: ${OPENROUTER_PRIMARY_MODEL:-nvidia/nemotron-3-ultra-550b-a55b:free}
OPENROUTER_FALLBACK_MODEL: ${OPENROUTER_FALLBACK_MODEL:-xiaomi/mimo-v2.5-pro}
OPENROUTER_TIMEOUT_SECS: ${OPENROUTER_TIMEOUT_SECS:-120}
OPENROUTER_MAX_RETRIES: ${OPENROUTER_MAX_RETRIES:-6}
OPENROUTER_PRIMARY_INPUT_COST_PER_1M_USD: ${OPENROUTER_PRIMARY_INPUT_COST_PER_1M_USD:-0.00}
OPENROUTER_PRIMARY_OUTPUT_COST_PER_1M_USD: ${OPENROUTER_PRIMARY_OUTPUT_COST_PER_1M_USD:-0.00}
OPENROUTER_FALLBACK_INPUT_COST_PER_1M_USD: ${OPENROUTER_FALLBACK_INPUT_COST_PER_1M_USD:-0.348}
OPENROUTER_FALLBACK_OUTPUT_COST_PER_1M_USD: ${OPENROUTER_FALLBACK_OUTPUT_COST_PER_1M_USD:-0.696}
OPENROUTER_MONTHLY_BUDGET_USD: ${OPENROUTER_MONTHLY_BUDGET_USD:-50.00}
DATA_COST_PER_GB_USD: ${DATA_COST_PER_GB_USD:-1.00}
DATAIMPULSE_PROXY_ENABLED: ${DATAIMPULSE_PROXY_ENABLED:-true}
DATAIMPULSE_PROXY_SCHEME: ${DATAIMPULSE_PROXY_SCHEME:-http}
DATAIMPULSE_PROXY_HOST: ${DATAIMPULSE_PROXY_HOST:-gw.dataimpulse.com}
DATAIMPULSE_PROXY_PORT: ${DATAIMPULSE_PROXY_PORT:-823}
DATAIMPULSE_PROXY_USERNAME: ${DATAIMPULSE_PROXY_USERNAME}
DATAIMPULSE_PROXY_PASSWORD: ${DATAIMPULSE_PROXY_PASSWORD}
DATAIMPULSE_PROXY_COUNTRY: ${DATAIMPULSE_PROXY_COUNTRY:-br}
DATAIMPULSE_PROXY_STICKY: ${DATAIMPULSE_PROXY_STICKY:-false}
WORKER_CONCURRENCY: ${WORKER_CONCURRENCY:-8}
BROWSER_CONCURRENCY: ${BROWSER_CONCURRENCY:-4}
PAGE_CONCURRENCY: ${PAGE_CONCURRENCY:-3}
JOB_POLL_INTERVAL_MS: ${JOB_POLL_INTERVAL_MS:-750}
REQUEST_TIMEOUT_SECS: ${REQUEST_TIMEOUT_SECS:-45}
BROWSER_TIMEOUT_SECS: ${BROWSER_TIMEOUT_SECS:-75}
BROWSER_NO_SANDBOX: ${BROWSER_NO_SANDBOX:-true}
BROWSER_MIN_NAVIGATION_DELAY_MS: ${BROWSER_MIN_NAVIGATION_DELAY_MS:-2500}
BROWSER_MAX_NAVIGATION_DELAY_MS: ${BROWSER_MAX_NAVIGATION_DELAY_MS:-15000}
BROWSER_MACRO_PAUSE_EVERY_MIN: ${BROWSER_MACRO_PAUSE_EVERY_MIN:-15}
BROWSER_MACRO_PAUSE_EVERY_MAX: ${BROWSER_MACRO_PAUSE_EVERY_MAX:-20}
BROWSER_MACRO_PAUSE_MIN_SECS: ${BROWSER_MACRO_PAUSE_MIN_SECS:-30}
BROWSER_MACRO_PAUSE_MAX_SECS: ${BROWSER_MACRO_PAUSE_MAX_SECS:-90}
CRAWL_MAX_DEPTH: ${CRAWL_MAX_DEPTH:-2}
CRAWL_MAX_PAGES_PER_INTERVIEWEE: ${CRAWL_MAX_PAGES_PER_INTERVIEWEE:-20}
MAX_INTERVIEWEES_PER_RUN: ${MAX_INTERVIEWEES_PER_RUN:-0}
volumes:
- media_data:/data/media
ports:
- "${BACKEND_PORT:-8081}:8080"
healthcheck:
# /api/health exige sessão autenticada; 401 já indica que o servidor
# está de pé e respondendo (só uma requisição de rede falhando é erro).
test: ["CMD-SHELL", "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/api/health | grep -qE '^(200|401)$'"]
interval: 10s
timeout: 5s
retries: 15
start_period: 10s
networks:
- internal
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
args:
VITE_API_URL: ${BACKEND_URL:-http://localhost:8081}
VITE_API_POLL_INTERVAL: ${VITE_API_POLL_INTERVAL:-6000}
VITE_DEMO_MODE: ${VITE_DEMO_MODE:-false}
restart: unless-stopped
depends_on:
backend:
condition: service_healthy
ports:
- "${FRONTEND_PORT:-8080}:8080"
networks:
- internal
networks:
internal:
volumes:
postgres_data:
media_data: