services:
  postgres:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: docuvault
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./docker/postgres/initdb.d:/docker-entrypoint-initdb.d:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d docuvault"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

  minio:
    image: minio/minio:latest
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: ${MINIO_ROOT_USER}
      MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
      # RESEARCH.md Finding 3, T-03-09: allow browser CORS preflight for direct PUT uploads.
      # Use FRONTEND_URL (plain string) not CORS_ORIGINS (pydantic JSON list format).
      MINIO_API_CORS_ALLOW_ORIGIN: ${FRONTEND_URL:-http://localhost:5173}
      MINIO_SERVER_URL: http://localhost:9000
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - minio_data:/data
    healthcheck:
      test: ["CMD", "mc", "ready", "local"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 15s

  minio-init:
    image: minio/mc:latest
    depends_on:
      minio:
        condition: service_healthy
    environment:
      MINIO_ROOT_USER: ${MINIO_ROOT_USER}
      MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
      MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
      MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
      MINIO_BUCKET: ${MINIO_BUCKET}
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        set -eu
        mc alias set local http://minio:9000 "$$MINIO_ROOT_USER" "$$MINIO_ROOT_PASSWORD"
        mc mb --ignore-existing "local/$$MINIO_BUCKET"
        mc admin user add local "$$MINIO_ACCESS_KEY" "$$MINIO_SECRET_KEY" || true
        cat > /tmp/docuvault-policy.json <<EOF
        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation"
              ],
              "Resource": [
                "arn:aws:s3:::$$MINIO_BUCKET"
              ]
            },
            {
              "Effect": "Allow",
              "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
              ],
              "Resource": [
                "arn:aws:s3:::$$MINIO_BUCKET/*"
              ]
            }
          ]
        }
        EOF
        mc admin policy create local docuvault-app /tmp/docuvault-policy.json || true
        mc admin policy attach local docuvault-app --user "$$MINIO_ACCESS_KEY"

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD}
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5

  migrate:
    build: ./backend
    # One-shot service: runs "alembic upgrade head" then exits 0.
    # All application services depend on this with condition: service_completed_successfully.
    # Uses DATABASE_MIGRATE_URL (docuvault_migrate role, DDL-capable) — not DATABASE_URL.
    command: alembic upgrade head
    environment:
      - DATABASE_MIGRATE_URL=${DATABASE_MIGRATE_URL}
      - PYTHONDONTWRITEBYTECODE=1
    volumes:
      - ./backend:/app
    depends_on:
      postgres:
        condition: service_healthy
    read_only: true
    tmpfs:
      - "/tmp:mode=1777"
    cap_drop:
      - ALL
    security_opt:
      - "no-new-privileges:true"
    restart: "no"

  backend:
    build: ./backend
    ports:
      - "8000:8000"
    volumes:
      - ./backend:/app
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - DATABASE_MIGRATE_URL=${DATABASE_MIGRATE_URL}
      - MINIO_ENDPOINT=${MINIO_ENDPOINT}
      - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
      - MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
      - MINIO_BUCKET=${MINIO_BUCKET}
      - MINIO_PUBLIC_ENDPOINT=${MINIO_PUBLIC_ENDPOINT:-localhost:9000}
      - REDIS_URL=${REDIS_URL}
      - SECRET_KEY=${SECRET_KEY}
      - JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY}
      - JWT_PUBLIC_KEY=${JWT_PUBLIC_KEY}
      - ADMIN_EMAIL=${ADMIN_EMAIL}
      - ADMIN_PASSWORD=${ADMIN_PASSWORD}
      - CORS_ORIGINS=${CORS_ORIGINS:-["http://localhost:5173"]}
      - FRONTEND_URL=${FRONTEND_URL:-http://localhost:5173}
      - PYTHONDONTWRITEBYTECODE=1
      - LOG_LEVEL=${LOG_LEVEL:-INFO}
      - LOG_JSON=${LOG_JSON:-true}
      - CLOUD_CREDS_KEY=${CLOUD_CREDS_KEY}
    labels:
      logging: "promtail"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    command: uvicorn main:app --host 0.0.0.0 --port 8000 --workers 2
    depends_on:
      postgres:
        condition: service_healthy
      minio:
        condition: service_healthy
      minio-init:
        condition: service_completed_successfully
      redis:
        condition: service_healthy
      migrate:
        condition: service_completed_successfully
    read_only: true
    tmpfs:
      - "/tmp:mode=1777"
    cap_drop:
      - ALL
    security_opt:
      - "no-new-privileges:true"

  celery-worker:
    build: ./backend
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - MINIO_ENDPOINT=${MINIO_ENDPOINT}
      - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
      - MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
      - MINIO_BUCKET=${MINIO_BUCKET}
      - REDIS_URL=${REDIS_URL}
      - CLOUD_CREDS_KEY=${CLOUD_CREDS_KEY}
      - SECRET_KEY=${SECRET_KEY}
      - JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY}
      - JWT_PUBLIC_KEY=${JWT_PUBLIC_KEY}
      - PYTHONDONTWRITEBYTECODE=1
      - PYTHONPATH=/app
    labels:
      logging: "promtail"
    volumes:
      - ./backend:/app
    extra_hosts:
      - "host.docker.internal:host-gateway"
    command: celery -A celery_app worker --loglevel=info -Q documents
    depends_on:
      postgres:
        condition: service_healthy
      minio:
        condition: service_healthy
      minio-init:
        condition: service_completed_successfully
      redis:
        condition: service_healthy
      migrate:
        condition: service_completed_successfully
    read_only: true
    tmpfs:
      - "/tmp:mode=1777"
    cap_drop:
      - ALL
    security_opt:
      - "no-new-privileges:true"

  celery-beat:
    build: ./backend
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - MINIO_ENDPOINT=${MINIO_ENDPOINT}
      - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
      - MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
      - MINIO_BUCKET=${MINIO_BUCKET}
      - REDIS_URL=${REDIS_URL}
      - PYTHONDONTWRITEBYTECODE=1
      - PYTHONPATH=/app
    extra_hosts:
      - "host.docker.internal:host-gateway"
    command: celery -A celery_app beat --loglevel=info --schedule /tmp/celerybeat-schedule
    depends_on:
      postgres:
        condition: service_healthy
      minio:
        condition: service_healthy
      minio-init:
        condition: service_completed_successfully
      redis:
        condition: service_healthy
      migrate:
        condition: service_completed_successfully
    read_only: true
    tmpfs:
      - "/tmp:mode=1777"
    cap_drop:
      - ALL
    security_opt:
      - "no-new-privileges:true"

  loki:
    image: grafana/loki:latest
    ports:
      - "127.0.0.1:3100:3100"
    volumes:
      - ./docker/loki/loki-config.yaml:/etc/loki/local-config.yaml
      - loki_data:/loki
    command: -config.file=/etc/loki/local-config.yaml

  promtail:
    image: grafana/promtail:latest
    volumes:
      - ./docker/loki/promtail-config.yaml:/etc/promtail/config.yaml
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    command: -config.file=/etc/promtail/config.yaml
    depends_on:
      - loki

  grafana:
    image: grafana/grafana:latest
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      - GF_AUTH_ANONYMOUS_ENABLED=false
      - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER:-admin}
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:?GRAFANA_ADMIN_PASSWORD must be set}
    volumes:
      - grafana_data:/var/lib/grafana
    depends_on:
      - loki

  frontend:
    build: ./frontend
    ports:
      - "5173:5173"
    volumes:
      - ./frontend/src:/app/src
      - ./frontend/index.html:/app/index.html
    depends_on:
      - backend
    command: npm run dev -- --host 0.0.0.0

volumes:
  postgres_data:
  minio_data:
  loki_data:
  grafana_data:
