version: "3.9" x-api-env: &api-env DATABASE_URL: postgresql+asyncpg://postgres:${DB_PASSWORD:-postgres}@postgres:5432/tand_e DATABASE_URL_SYNC: postgresql://postgres:${DB_PASSWORD:-postgres}@postgres:5432/tand_e REDIS_URL: redis://redis:6379/0 CELERY_BROKER_URL: redis://redis:6379/1 CELERY_RESULT_BACKEND: redis://redis:6379/2 STORAGE_BACKEND: minio STORAGE_ENDPOINT: http://minio:9000 STORAGE_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin} STORAGE_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin} JWT_SECRET_KEY: ${JWT_SECRET_KEY:-change-me-in-production} ENVIRONMENT: development DEBUG: "true" CORS_ORIGINS: '["http://localhost:8501","http://frontend:8501"]' services: # ── Backend API ── api: build: context: . dockerfile: deploy/docker/api/Dockerfile ports: - "8000:8000" environment: <<: *api-env depends_on: postgres: condition: service_healthy redis: condition: service_healthy minio: condition: service_started volumes: - ./backend:/app command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 5 start_period: 15s # ── Celery Worker ── celery-worker: build: context: . dockerfile: deploy/docker/celery/Dockerfile command: celery -A app.tasks.celery_app worker --loglevel=info --concurrency=4 --queues=default,high,low environment: <<: *api-env depends_on: - api - redis - postgres volumes: - ./backend:/app # ── Celery Beat (scheduled tasks) ── celery-beat: build: context: . dockerfile: deploy/docker/celery/Dockerfile command: celery -A app.tasks.celery_app beat --loglevel=info environment: <<: *api-env depends_on: - api - redis volumes: - ./backend:/app # ── Streamlit Frontend ── frontend: build: context: . dockerfile: deploy/docker/frontend/Dockerfile ports: - "8501:8501" environment: API_BASE_URL: http://api:8000 depends_on: - api volumes: - ./frontend:/app/frontend command: streamlit run frontend/app.py --server.port=8501 --server.address=0.0.0.0 # ── Database ── postgres: image: postgres:16-alpine environment: POSTGRES_DB: tand_e POSTGRES_USER: postgres POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres} volumes: - postgres-data:/var/lib/postgresql/data - ./deploy/migrations:/docker-entrypoint-initdb.d ports: - "5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s timeout: 5s retries: 5 start_period: 10s # ── Cache & Message Queue ── redis: image: redis:7-alpine command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru volumes: - redis-data:/data ports: - "6379:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 # ── Object Storage (S3-compatible) ── minio: image: minio/minio:latest command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:-minioadmin} MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:-minioadmin} volumes: - minio-data:/data ports: - "9000:9000" - "9001:9001" # ── Monitoring ── flower: image: mher/flower:2.0 command: celery flower --broker=redis://redis:6379/0 ports: - "5555:5555" depends_on: - redis volumes: postgres-data: redis-data: minio-data: