services: postgres: image: pgvector/pgvector:pg16 environment: POSTGRES_DB: ${POSTGRES_DB:-ai_ticket_platform} POSTGRES_USER: ${POSTGRES_USER:-ai_ticket} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} volumes: - postgres-data:/var/lib/postgresql/data restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 10 redis: image: redis:7-alpine command: ["redis-server", "--appendonly", "yes"] volumes: - redis-data:/data restart: unless-stopped healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 10 minio: image: minio/minio:latest command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: ${MINIO_ROOT_USER:?MINIO_ROOT_USER is required} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?MINIO_ROOT_PASSWORD is required} volumes: - minio-data:/data restart: unless-stopped healthcheck: test: ["CMD", "mc", "ready", "local"] interval: 10s timeout: 5s retries: 10 clamav: image: clamav/clamav:stable volumes: - clamav-data:/var/lib/clamav restart: unless-stopped healthcheck: test: ["CMD-SHELL", "echo PING | nc 127.0.0.1 3310 | grep PONG"] interval: 30s timeout: 10s retries: 10 start_period: 60s backend: build: context: .. dockerfile: infra/backend.Dockerfile entrypoint: ["/entrypoint.sh"] command: [ "gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3", "--timeout", "300", "--access-logfile", "-" ] env_file: ../.env restart: unless-stopped depends_on: postgres: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy clamav: condition: service_healthy healthcheck: test: [ "CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/system/health/ready', timeout=5)" ] interval: 15s timeout: 8s retries: 10 worker: build: context: .. dockerfile: infra/backend.Dockerfile command: ["celery", "-A", "config.celery", "worker", "-l", "info"] env_file: ../.env restart: unless-stopped depends_on: backend: condition: service_healthy beat: build: context: .. dockerfile: infra/backend.Dockerfile command: ["celery", "-A", "config.celery", "beat", "-l", "info"] env_file: ../.env restart: unless-stopped depends_on: backend: condition: service_healthy frontend: build: context: .. dockerfile: infra/frontend-prod.Dockerfile ports: - "${HTTP_PORT:-8080}:80" restart: unless-stopped depends_on: backend: condition: service_healthy healthcheck: test: ["CMD", "wget", "-q", "-O", "-", "http://127.0.0.1/"] interval: 15s timeout: 5s retries: 10 prometheus: image: prom/prometheus:v3.5.0 profiles: ["monitoring"] command: - --config.file=/etc/prometheus/prometheus.yml - --storage.tsdb.path=/prometheus - --storage.tsdb.retention.time=${PROMETHEUS_RETENTION:-30d} volumes: - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro - ./monitoring/alerts.yml:/etc/prometheus/alerts.yml:ro - prometheus-data:/prometheus secrets: - metrics_token ports: - "127.0.0.1:${PROMETHEUS_PORT:-9090}:9090" restart: unless-stopped depends_on: backend: condition: service_healthy alertmanager: condition: service_started alertmanager: image: prom/alertmanager:v0.28.1 profiles: ["monitoring"] command: - --config.file=/etc/alertmanager/alertmanager.yml - --storage.path=/alertmanager volumes: - ./monitoring/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro - alertmanager-data:/alertmanager secrets: - alert_webhook_url ports: - "127.0.0.1:${ALERTMANAGER_PORT:-9093}:9093" restart: unless-stopped volumes: postgres-data: redis-data: minio-data: clamav-data: prometheus-data: alertmanager-data: secrets: metrics_token: file: ${METRICS_TOKEN_FILE:-./secrets/metrics_token.example} alert_webhook_url: file: ${ALERT_WEBHOOK_URL_FILE:-./secrets/alert_webhook_url.example}