126 lines
5.0 KiB
YAML
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:
|