# Single-host production deployment.
#
# Differences from ``docker-compose.yml`` (dev):
#   - Ports bound to ``127.0.0.1`` only — expects a reverse proxy on
#     the host (e.g. Caddy) to terminate TLS and forward.
#   - A one-shot ``consentos-bootstrap`` init container owns all
#     database setup (alembic + initial admin provisioning); every
#     long-running service that touches the DB waits for it via
#     ``service_completed_successfully``.
#   - Per-service resource limits, healthchecks, and dependency
#     ordering so ``docker compose up -d`` gives a consistent start.
#   - The scanner gets its own scoped ``environment:`` block rather
#     than ``env_file: .env`` so unrelated variables (``PORT``,
#     ``HOST``, …) from the shared env can't rebind its settings.
#   - ``shm_size: 1gb`` on the scanner — Playwright/Chromium crashes
#     under the default 64 MB ``/dev/shm``.

services:
  # ── Init container: migrations + initial admin bootstrap ──────────
  consentos-bootstrap:
    build:
      context: apps/api
      dockerfile: Dockerfile
    container_name: consentos-bootstrap
    env_file: .env
    working_dir: /app
    command:
      - "sh"
      - "-c"
      - "python -m alembic upgrade head && python -m src.cli.bootstrap_admin && python -m src.cli.seed_known_cookies"
    restart: "no"
    depends_on:
      postgres:
        condition: service_healthy
    deploy:
      resources:
        limits:
          memory: 256M

  # ── API ──────────────────────────────────────────────────────────
  consentos-api:
    build:
      context: apps/api
      dockerfile: Dockerfile
    container_name: consentos-api
    env_file: .env
    environment:
      CONSENTOS_DEPLOYMENT: docker-compose
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 5s
      start_period: 15s
      retries: 3
    ports:
      - "127.0.0.1:11001:8000"
    networks:
      # ``api`` alias matches the dev compose service name so the
      # admin-UI nginx ``proxy_pass http://api:8000`` works unchanged
      # in prod (container_name is ``consentos-api``).
      default:
        aliases:
          - api
    deploy:
      resources:
        limits:
          memory: 512M
    depends_on:
      consentos-bootstrap:
        condition: service_completed_successfully
      redis:
        condition: service_healthy

  # ── Celery worker ────────────────────────────────────────────────
  consentos-worker:
    build:
      context: apps/api
      dockerfile: Dockerfile
    container_name: consentos-worker
    env_file: .env
    environment:
      CONSENTOS_DEPLOYMENT: docker-compose
    working_dir: /app
    command: >
      celery -A src.celery_app worker
      --loglevel=info --concurrency=2
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "celery -A src.celery_app inspect ping -d celery@$${HOSTNAME} || exit 1"]
      interval: 30s
      timeout: 10s
      start_period: 30s
      retries: 3
    depends_on:
      consentos-bootstrap:
        condition: service_completed_successfully
      consentos-scanner:
        condition: service_healthy
      redis:
        condition: service_healthy
    deploy:
      resources:
        limits:
          memory: 512M

  # ── Celery beat ──────────────────────────────────────────────────
  consentos-beat:
    build:
      context: apps/api
      dockerfile: Dockerfile
    container_name: consentos-beat
    env_file: .env
    environment:
      CONSENTOS_DEPLOYMENT: docker-compose
    working_dir: /app
    command: >
      celery -A src.celery_app beat
      --loglevel=info
    restart: unless-stopped
    # Beat has no HTTP surface and no inspect endpoint — rely on the
    # container exit status rather than a fake healthcheck so it
    # doesn't permanently show as "unhealthy".
    healthcheck:
      disable: true
    depends_on:
      consentos-bootstrap:
        condition: service_completed_successfully
      redis:
        condition: service_healthy
    deploy:
      resources:
        limits:
          memory: 256M

  # ── Scanner (Playwright / Chromium) ──────────────────────────────
  consentos-scanner:
    build:
      context: apps/scanner
      dockerfile: Dockerfile
    container_name: consentos-scanner
    # Scoped environment — do NOT env_file the shared .env here or
    # vars like PORT bleed across and rebind the scanner off its
    # default 8001 (which is what SCANNER_SERVICE_URL expects).
    environment:
      LOG_LEVEL: ${LOG_LEVEL:-INFO}
      CRAWLER_HEADLESS: "true"
      CRAWLER_TIMEOUT_MS: "30000"
      MAX_PAGES_PER_SCAN: "50"
    restart: unless-stopped
    # Chromium crashes under /dev/shm pressure on sites with many
    # iframes or heavy DOM trees. Default is 64 MB — not enough.
    shm_size: "1gb"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8001/health"]
      interval: 30s
      timeout: 10s
      start_period: 30s
      retries: 3
    deploy:
      resources:
        limits:
          memory: 1G

  # ── Admin UI + banner CDN (single nginx image) ───────────────────
  consentos-admin:
    build:
      # Context is the repo root so the Dockerfile can pull in
      # apps/banner/ alongside apps/admin-ui/ and bake the banner
      # output at the nginx root — see apps/admin-ui/Dockerfile.
      context: .
      dockerfile: apps/admin-ui/Dockerfile
    container_name: consentos-admin
    restart: unless-stopped
    ports:
      - "127.0.0.1:11002:80"
    deploy:
      resources:
        limits:
          memory: 128M

  # ── Postgres ─────────────────────────────────────────────────────
  postgres:
    image: postgres:17-alpine
    container_name: consentos-postgres
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
      interval: 5s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 512M

  # ── Redis ────────────────────────────────────────────────────────
  redis:
    image: redis:7-alpine
    container_name: consentos-redis
    command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
    volumes:
      - redisdata:/data
    healthcheck:
      test: ["CMD-SHELL", "redis-cli -a $$REDIS_PASSWORD ping"]
      interval: 2s
      timeout: 3s
      retries: 10
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 128M

volumes:
  pgdata:
  redisdata:
