version: "3.9" services: # ── PostgreSQL ───────────────────────────────────────────── postgres: image: postgres:16-alpine container_name: copilot_postgres environment: POSTGRES_USER: copilot POSTGRES_PASSWORD: copilot POSTGRES_DB: copilot_db volumes: - postgres_data:/var/lib/postgresql/data ports: - "5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U copilot -d copilot_db"] interval: 10s timeout: 5s retries: 5 networks: - copilot_net # ── Redis ───────────────────────────────────────────────── redis: image: redis:7-alpine container_name: copilot_redis command: redis-server --appendonly yes volumes: - redis_data:/data ports: - "6379:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - copilot_net # ── Qdrant ──────────────────────────────────────────────── qdrant: image: qdrant/qdrant:v1.12.0 container_name: copilot_qdrant volumes: - qdrant_data:/qdrant/storage ports: - "6333:6333" - "6334:6334" networks: - copilot_net # ── FastAPI Backend ──────────────────────────────────────── backend: build: context: .. dockerfile: backend/Dockerfile container_name: copilot_backend env_file: - ../.env environment: - PYTHONPATH=/app:/agents:/services:. - DATABASE_URL=postgresql+asyncpg://copilot:copilot@postgres:5432/copilot_db - REDIS_URL=redis://redis:6379/0 - QDRANT_URL=http://qdrant:6333 - CELERY_BROKER_URL=redis://redis:6379/1 - DEPLOY_MODE=local volumes: - ../backend:/app - ../agents:/agents - ../services:/services - ../scripts:/scripts - ../tests:/tests - uploads_data:/uploads ports: - "8000:8000" depends_on: postgres: condition: service_healthy redis: condition: service_healthy qdrant: condition: service_started command: > sh -c "alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload" networks: - copilot_net # ── Celery Worker ────────────────────────────────────────── celery_worker: build: context: .. dockerfile: backend/Dockerfile container_name: copilot_celery env_file: - ../.env environment: - PYTHONPATH=/app:/agents:/services:. - DATABASE_URL=postgresql+asyncpg://copilot:copilot@postgres:5432/copilot_db - REDIS_URL=redis://redis:6379/0 - QDRANT_URL=http://qdrant:6333 - CELERY_BROKER_URL=redis://redis:6379/1 - DEPLOY_MODE=local volumes: - ../backend:/app - ../agents:/agents - ../services:/services - uploads_data:/uploads command: celery -A app.core.celery_app worker --loglevel=info --concurrency=2 depends_on: - redis - postgres networks: - copilot_net # ── React Frontend ───────────────────────────────────────── frontend: build: context: ../frontend dockerfile: Dockerfile container_name: copilot_frontend volumes: - ../frontend/src:/app/src ports: - "3000:3000" environment: - VITE_API_URL=http://localhost:8000 networks: - copilot_net # ── Nginx Reverse Proxy ──────────────────────────────────── nginx: image: nginx:alpine container_name: copilot_nginx ports: - "8080:80" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: - backend - frontend networks: - copilot_net # ── Prometheus ──────────────────────────────────────────── prometheus: image: prom/prometheus:latest container_name: copilot_prometheus volumes: - ../monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro - prometheus_data:/prometheus ports: - "9090:9090" command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' networks: - copilot_net # ── Grafana ─────────────────────────────────────────────── grafana: image: grafana/grafana:latest container_name: copilot_grafana environment: - GF_SECURITY_ADMIN_PASSWORD=admin - GF_USERS_ALLOW_SIGN_UP=false volumes: - grafana_data:/var/lib/grafana - ../monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards:ro ports: - "3001:3000" depends_on: - prometheus networks: - copilot_net volumes: postgres_data: redis_data: qdrant_data: uploads_data: prometheus_data: grafana_data: networks: copilot_net: driver: bridge