services: # ── PostgreSQL Database ────────────────────────────── postgres: image: postgres:15-alpine container_name: job_radar_postgres environment: POSTGRES_USER: radar POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: job_radar volumes: - postgres_data:/var/lib/postgresql/data ports: - "5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U radar -d job_radar"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped # ── FastAPI Backend ─────────────────────────────────── fastapi: build: ./backend container_name: job_radar_api command: ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] env_file: .env environment: DATABASE_URL: postgresql://radar:${DB_PASSWORD}@postgres:5432/job_radar ports: - "8000:8000" depends_on: postgres: condition: service_healthy volumes: - ./backend:/app restart: unless-stopped # ── n8n Workflow Engine ─────────────────────────────── n8n: image: n8nio/n8n:latest container_name: job_radar_n8n env_file: .env environment: N8N_BASIC_AUTH_ACTIVE: "true" N8N_BASIC_AUTH_USER: ${N8N_USER} N8N_BASIC_AUTH_PASSWORD: ${N8N_PASS} WEBHOOK_URL: http://localhost:5678/ N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY} N8N_BLOCK_ENV_ACCESS_IN_NODE: "false" DB_TYPE: postgresdb DB_POSTGRESDB_DATABASE: n8n DB_POSTGRESDB_HOST: postgres DB_POSTGRESDB_PORT: 5432 DB_POSTGRESDB_USER: radar DB_POSTGRESDB_PASSWORD: ${DB_PASSWORD} EXECUTIONS_DATA_SAVE_ON_ERROR: all EXECUTIONS_DATA_SAVE_ON_SUCCESS: last ports: - "5678:5678" volumes: - n8n_data:/home/node/.n8n - ./n8n/workflows:/home/node/.n8n/workflows depends_on: postgres: condition: service_healthy restart: unless-stopped # ── Redis (used by Evolution API) ───────────────────── redis: image: redis:7-alpine container_name: job_radar_redis command: redis-server --appendonly yes volumes: - redis_data:/data restart: unless-stopped # ── Evolution API — WhatsApp Gateway ────────────────── evolution: image: atendai/evolution-api:latest container_name: job_radar_evolution environment: SERVER_URL: http://evolution:8080 AUTHENTICATION_API_KEY: ${EVOLUTION_API_KEY:-jobradar_evolution_key} AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES: "true" DATABASE_ENABLED: "true" DATABASE_PROVIDER: postgresql DATABASE_CONNECTION_URI: postgresql://radar:${DB_PASSWORD}@postgres:5432/evolution DATABASE_CONNECTION_CLIENT_NAME: evolution_client DATABASE_SAVE_DATA_INSTANCE: "true" DATABASE_SAVE_DATA_NEW_MESSAGE: "true" DATABASE_SAVE_MESSAGE_UPDATE: "true" DATABASE_SAVE_DATA_CONTACTS: "true" DATABASE_SAVE_DATA_CHATS: "true" DATABASE_SAVE_DATA_LABELS: "true" DATABASE_SAVE_DATA_HISTORIC: "true" CACHE_REDIS_ENABLED: "true" CACHE_REDIS_URI: redis://redis:6379/6 CACHE_REDIS_PREFIX_KEY: evolution CACHE_REDIS_SAVE_INSTANCES: "false" CACHE_LOCAL_ENABLED: "false" QRCODE_LIMIT: 30 QRCODE_COLOR: "#000000" DEL_INSTANCE: "false" LOG_LEVEL: ERROR LOG_COLOR: "true" LANGUAGE: en ports: - "8080:8080" volumes: - evolution_data:/evolution/instances depends_on: postgres: condition: service_healthy redis: condition: service_started restart: unless-stopped # ── OpenWA — WhatsApp Gateway ──────────────────────────────────────────── openwa: image: ghcr.io/rmyndharis/openwa:latest container_name: job_radar_openwa environment: API_KEY_ENABLED: "true" API_MASTER_KEY: jobradar_wa_key STORE_TYPE: sqlite DATABASE_ENABLED: "true" DATABASE_TYPE: sqlite DATABASE_SYNCHRONIZE: "true" ENGINE_TYPE: whatsapp-web.js PUPPETEER_HEADLESS: "true" PUPPETEER_ARGS: "--no-sandbox,--disable-setuid-sandbox,--disable-dev-shm-usage,--disable-gpu,--single-process,--no-zygote" SSRF_ALLOWED_HOSTS: "n8n,fastapi" WEBHOOK_SSRF_PROTECT: "true" ports: - "2785:2785" - "2886:2886" volumes: - openwa_data:/app/data restart: unless-stopped # ── Next.js Dashboard ───────────────────────────────── dashboard: build: context: ./dashboard args: NEXT_PUBLIC_API_URL: http://localhost:8000 container_name: job_radar_dashboard ports: - "3000:3000" depends_on: - fastapi restart: unless-stopped volumes: postgres_data: n8n_data: redis_data: evolution_data: openwa_data: