name: jobflow-ai x-n8n: &n8n image: n8nio/n8n:1.106.3 restart: unless-stopped env_file: ${JOBFLOW_ENV_FILE:-.env} environment: DB_TYPE: postgresdb DB_POSTGRESDB_HOST: postgres DB_POSTGRESDB_DATABASE: ${POSTGRES_DB} DB_POSTGRESDB_USER: ${POSTGRES_USER} DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD} EXECUTIONS_MODE: queue QUEUE_BULL_REDIS_HOST: redis QUEUE_HEALTH_CHECK_ACTIVE: "true" N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY} N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: "true" N8N_DIAGNOSTICS_ENABLED: "false" N8N_PERSONALIZATION_ENABLED: "false" API_INTERNAL_URL: http://api:8000 WEBHOOK_SECRET: ${WEBHOOK_SECRET} N8N_URL: http://n8n:5678 N8N_API_KEY: ${N8N_API_KEY:-} depends_on: postgres: { condition: service_healthy } redis: { condition: service_healthy } networks: [jobflow] services: frontend: build: ./frontend restart: unless-stopped environment: NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8000} ports: ["3000:3000"] depends_on: [api] networks: [jobflow] api: build: ./backend restart: unless-stopped env_file: ${JOBFLOW_ENV_FILE:-.env} environment: DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB} QDRANT_URL: ${QDRANT_URL:-http://qdrant:6333} AI_BASE_URL: ${AI_BASE_URL:-http://ollama:11434} ports: ["8000:8000"] depends_on: postgres: { condition: service_healthy } redis: { condition: service_healthy } qdrant: { condition: service_started } healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 15s timeout: 5s retries: 5 networks: [jobflow] n8n: <<: *n8n command: start ports: ["5678:5678"] volumes: - n8n_data:/home/node/.n8n - ./workflows:/workflows:ro n8n-worker: <<: *n8n command: worker --concurrency=5 healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost:5678/healthz/readiness"] interval: 30s timeout: 10s retries: 5 n8n-import: <<: *n8n profiles: ["setup"] restart: "no" entrypoint: /bin/sh command: /scripts/import-workflows.sh volumes: - n8n_data:/home/node/.n8n - ./workflows:/workflows:ro - ./infrastructure/n8n:/scripts:ro postgres: image: pgvector/pgvector:pg16 restart: unless-stopped environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data - ./infrastructure/docker-init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro ports: ["5432:5432"] healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 10 networks: [jobflow] redis: image: redis:7.4-alpine restart: unless-stopped command: redis-server --appendonly yes volumes: ["redis_data:/data"] healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 3s retries: 10 networks: [jobflow] qdrant: image: qdrant/qdrant:v1.15.1 restart: unless-stopped volumes: ["qdrant_data:/qdrant/storage"] ports: ["6333:6333"] networks: [jobflow] ollama: image: ollama/ollama:0.11.4 profiles: ["local-ai"] restart: unless-stopped volumes: ["ollama_data:/root/.ollama"] ports: ["11434:11434"] networks: [jobflow] prometheus: image: prom/prometheus:v3.5.0 restart: unless-stopped command: ["--config.file=/etc/prometheus/prometheus.yml"] volumes: ["./infrastructure/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro"] ports: ["9090:9090"] networks: [jobflow] grafana: image: grafana/grafana:12.1.1 restart: unless-stopped environment: GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER} GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD} volumes: - grafana_data:/var/lib/grafana - ./infrastructure/grafana/provisioning:/etc/grafana/provisioning:ro - ./infrastructure/grafana/dashboards:/var/lib/grafana/dashboards:ro ports: ["3001:3000"] depends_on: [prometheus] networks: [jobflow] volumes: postgres_data: redis_data: qdrant_data: ollama_data: n8n_data: grafana_data: networks: jobflow: driver: bridge