version: '3.9' services: # ── FastAPI backend ────────────────────────────────────────────────────── api: build: context: . dockerfile: Dockerfile.api ports: - "8000:8000" environment: - OPENAI_API_KEY=${OPENAI_API_KEY} - REDIS_URL=redis://redis:6379/0 - CELERY_BROKER_URL=redis://redis:6379/1 - DISKCACHE_DIR=/data/diskcache - RESULTS_DIR=/data/results volumes: - ./results:/data/results - agent_cache:/data/diskcache depends_on: - redis restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"] interval: 10s timeout: 5s retries: 3 # ── Next.js frontend ───────────────────────────────────────────────────── frontend: build: context: ./frontend dockerfile: Dockerfile.frontend ports: - "3000:3000" environment: - NEXT_PUBLIC_API_URL=http://localhost:8000 - NEXT_PUBLIC_WS_URL=ws://localhost:8000 depends_on: - api restart: unless-stopped # ── Redis (task queue + pub/sub) ───────────────────────────────────────── redis: image: redis:7-alpine ports: - "6379:6379" volumes: - redis_data:/data restart: unless-stopped healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 # ── Sandbox executor ───────────────────────────────────────────────────── sandbox: build: context: ./sandbox dockerfile: Dockerfile network_mode: none read_only: true tmpfs: - /tmp:size=512m security_opt: - no-new-privileges:true cap_drop: - ALL mem_limit: 2g cpus: 2.0 restart: "no" # single-use containers, spawned per task volumes: redis_data: agent_cache: