version: '3.8'

# Xpeditis - Stack PRODUCTION
# Portainer Stack avec Traefik reverse proxy
# Domaines: xpeditis.com (frontend) | api.xpeditis.com (backend)

services:
  # PostgreSQL Database
  postgres-prod:
    image: postgres:15-alpine
    container_name: xpeditis-postgres-prod
    restart: always
    environment:
      POSTGRES_DB: ${POSTGRES_DB:-xpeditis_prod}
      POSTGRES_USER: ${POSTGRES_USER:-xpeditis}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?error}
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - postgres_data_prod:/var/lib/postgresql/data
      - postgres_backups_prod:/backups
    networks:
      - xpeditis_internal_prod
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-xpeditis}"]
      interval: 10s
      timeout: 5s
      retries: 5
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 4G
        reservations:
          cpus: '1'
          memory: 2G

  # Redis Cache
  redis-prod:
    image: redis:7-alpine
    container_name: xpeditis-redis-prod
    restart: always
    command: redis-server --requirepass ${REDIS_PASSWORD:?error} --maxmemory 1gb --maxmemory-policy allkeys-lru --appendonly yes
    volumes:
      - redis_data_prod:/data
    networks:
      - xpeditis_internal_prod
    healthcheck:
      test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 1.5G
        reservations:
          cpus: '0.5'
          memory: 1G

  # Backend API (NestJS) - Instance 1
  backend-prod-1:
    image: ${DOCKER_REGISTRY:-docker.io}/${BACKEND_IMAGE:-xpeditis/backend}:${BACKEND_TAG:-latest}
    container_name: xpeditis-backend-prod-1
    restart: always
    depends_on:
      postgres-prod:
        condition: service_healthy
      redis-prod:
        condition: service_healthy
    environment:
      # Application
      NODE_ENV: production
      PORT: 4000
      INSTANCE_ID: backend-prod-1

      # Database
      DATABASE_HOST: postgres-prod
      DATABASE_PORT: 5432
      DATABASE_NAME: ${POSTGRES_DB:-xpeditis_prod}
      DATABASE_USER: ${POSTGRES_USER:-xpeditis}
      DATABASE_PASSWORD: ${POSTGRES_PASSWORD:?error}
      DATABASE_SYNC: "false"
      DATABASE_LOGGING: "false"
      DATABASE_POOL_MIN: 10
      DATABASE_POOL_MAX: 50

      # Redis
      REDIS_HOST: redis-prod
      REDIS_PORT: 6379
      REDIS_PASSWORD: ${REDIS_PASSWORD:?error}

      # JWT
      JWT_SECRET: ${JWT_SECRET:?error}
      JWT_ACCESS_EXPIRATION: 15m
      JWT_REFRESH_EXPIRATION: 7d

      # CORS
      CORS_ORIGIN: https://xpeditis.com,https://www.xpeditis.com

      # Sentry (Monitoring)
      SENTRY_DSN: ${SENTRY_DSN:?error}
      SENTRY_ENVIRONMENT: production
      SENTRY_TRACES_SAMPLE_RATE: 0.1
      SENTRY_PROFILES_SAMPLE_RATE: 0.05

      # AWS S3
      AWS_REGION: ${AWS_REGION:-eu-west-3}
      AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:?error}
      AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:?error}
      S3_BUCKET_DOCUMENTS: ${S3_BUCKET_DOCUMENTS:-xpeditis-prod-documents}
      S3_BUCKET_UPLOADS: ${S3_BUCKET_UPLOADS:-xpeditis-prod-uploads}

      # Email (AWS SES)
      EMAIL_SERVICE: ses
      EMAIL_FROM: ${EMAIL_FROM:-noreply@xpeditis.com}
      EMAIL_FROM_NAME: Xpeditis
      AWS_SES_REGION: ${AWS_SES_REGION:-eu-west-1}

      # Carrier APIs (Production)
      MAERSK_API_URL: ${MAERSK_API_URL:-https://api.maersk.com}
      MAERSK_API_KEY: ${MAERSK_API_KEY:?error}
      MSC_API_URL: ${MSC_API_URL:-}
      MSC_API_KEY: ${MSC_API_KEY:-}
      CMA_CGM_API_URL: ${CMA_CGM_API_URL:-}
      CMA_CGM_API_KEY: ${CMA_CGM_API_KEY:-}

      # Security
      RATE_LIMIT_GLOBAL: 100
      RATE_LIMIT_AUTH: 5
      RATE_LIMIT_SEARCH: 30
      RATE_LIMIT_BOOKING: 20

    volumes:
      - backend_logs_prod:/app/logs
    networks:
      - xpeditis_internal_prod
      - traefik_network
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik_network"

      # HTTPS Route
      - "traefik.http.routers.xpeditis-backend-prod.rule=Host(`api.xpeditis.com`)"
      - "traefik.http.routers.xpeditis-backend-prod.entrypoints=websecure"
      - "traefik.http.routers.xpeditis-backend-prod.tls=true"
      - "traefik.http.routers.xpeditis-backend-prod.tls.certresolver=letsencrypt"
      - "traefik.http.routers.xpeditis-backend-prod.priority=200"
      - "traefik.http.services.xpeditis-backend-prod.loadbalancer.server.port=4000"
      - "traefik.http.routers.xpeditis-backend-prod.middlewares=xpeditis-backend-prod-headers,xpeditis-backend-prod-security,xpeditis-backend-prod-ratelimit"

      # HTTP → HTTPS Redirect
      - "traefik.http.routers.xpeditis-backend-prod-http.rule=Host(`api.xpeditis.com`)"
      - "traefik.http.routers.xpeditis-backend-prod-http.entrypoints=web"
      - "traefik.http.routers.xpeditis-backend-prod-http.priority=200"
      - "traefik.http.routers.xpeditis-backend-prod-http.middlewares=xpeditis-backend-prod-redirect"
      - "traefik.http.routers.xpeditis-backend-prod-http.service=xpeditis-backend-prod"
      - "traefik.http.middlewares.xpeditis-backend-prod-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.xpeditis-backend-prod-redirect.redirectscheme.permanent=true"

      # Middleware Headers
      - "traefik.http.middlewares.xpeditis-backend-prod-headers.headers.customRequestHeaders.X-Forwarded-Proto=https"
      - "traefik.http.middlewares.xpeditis-backend-prod-headers.headers.customRequestHeaders.X-Forwarded-For="
      - "traefik.http.middlewares.xpeditis-backend-prod-headers.headers.customRequestHeaders.X-Real-IP="

      # Security Headers (Strict Production)
      - "traefik.http.middlewares.xpeditis-backend-prod-security.headers.frameDeny=true"
      - "traefik.http.middlewares.xpeditis-backend-prod-security.headers.contentTypeNosniff=true"
      - "traefik.http.middlewares.xpeditis-backend-prod-security.headers.browserXssFilter=true"
      - "traefik.http.middlewares.xpeditis-backend-prod-security.headers.stsSeconds=63072000"
      - "traefik.http.middlewares.xpeditis-backend-prod-security.headers.stsIncludeSubdomains=true"
      - "traefik.http.middlewares.xpeditis-backend-prod-security.headers.stsPreload=true"
      - "traefik.http.middlewares.xpeditis-backend-prod-security.headers.forceSTSHeader=true"

      # Rate Limiting (Stricter in Production)
      - "traefik.http.middlewares.xpeditis-backend-prod-ratelimit.ratelimit.average=50"
      - "traefik.http.middlewares.xpeditis-backend-prod-ratelimit.ratelimit.burst=100"
      - "traefik.http.middlewares.xpeditis-backend-prod-ratelimit.ratelimit.period=1m"

      # Health Check
      - "traefik.http.services.xpeditis-backend-prod.loadbalancer.healthcheck.path=/health"
      - "traefik.http.services.xpeditis-backend-prod.loadbalancer.healthcheck.interval=30s"
      - "traefik.http.services.xpeditis-backend-prod.loadbalancer.healthcheck.timeout=5s"

      # Load Balancing (Sticky Sessions)
      - "traefik.http.services.xpeditis-backend-prod.loadbalancer.sticky.cookie=true"
      - "traefik.http.services.xpeditis-backend-prod.loadbalancer.sticky.cookie.name=xpeditis_backend_route"
      - "traefik.http.services.xpeditis-backend-prod.loadbalancer.sticky.cookie.secure=true"
      - "traefik.http.services.xpeditis-backend-prod.loadbalancer.sticky.cookie.httpOnly=true"

    healthcheck:
      test: ["CMD", "node", "-e", "require('http').get('http://localhost:4000/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G

  # Backend API (NestJS) - Instance 2 (High Availability)
  backend-prod-2:
    image: ${DOCKER_REGISTRY:-docker.io}/${BACKEND_IMAGE:-xpeditis/backend}:${BACKEND_TAG:-latest}
    container_name: xpeditis-backend-prod-2
    restart: always
    depends_on:
      postgres-prod:
        condition: service_healthy
      redis-prod:
        condition: service_healthy
    environment:
      # Application
      NODE_ENV: production
      PORT: 4000
      INSTANCE_ID: backend-prod-2

      # Database
      DATABASE_HOST: postgres-prod
      DATABASE_PORT: 5432
      DATABASE_NAME: ${POSTGRES_DB:-xpeditis_prod}
      DATABASE_USER: ${POSTGRES_USER:-xpeditis}
      DATABASE_PASSWORD: ${POSTGRES_PASSWORD:?error}
      DATABASE_SYNC: "false"
      DATABASE_LOGGING: "false"
      DATABASE_POOL_MIN: 10
      DATABASE_POOL_MAX: 50

      # Redis
      REDIS_HOST: redis-prod
      REDIS_PORT: 6379
      REDIS_PASSWORD: ${REDIS_PASSWORD:?error}

      # JWT
      JWT_SECRET: ${JWT_SECRET:?error}
      JWT_ACCESS_EXPIRATION: 15m
      JWT_REFRESH_EXPIRATION: 7d

      # CORS
      CORS_ORIGIN: https://xpeditis.com,https://www.xpeditis.com

      # Sentry (Monitoring)
      SENTRY_DSN: ${SENTRY_DSN:?error}
      SENTRY_ENVIRONMENT: production
      SENTRY_TRACES_SAMPLE_RATE: 0.1
      SENTRY_PROFILES_SAMPLE_RATE: 0.05

      # AWS S3
      AWS_REGION: ${AWS_REGION:-eu-west-3}
      AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:?error}
      AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:?error}
      S3_BUCKET_DOCUMENTS: ${S3_BUCKET_DOCUMENTS:-xpeditis-prod-documents}
      S3_BUCKET_UPLOADS: ${S3_BUCKET_UPLOADS:-xpeditis-prod-uploads}

      # Email (AWS SES)
      EMAIL_SERVICE: ses
      EMAIL_FROM: ${EMAIL_FROM:-noreply@xpeditis.com}
      EMAIL_FROM_NAME: Xpeditis
      AWS_SES_REGION: ${AWS_SES_REGION:-eu-west-1}

      # Carrier APIs (Production)
      MAERSK_API_URL: ${MAERSK_API_URL:-https://api.maersk.com}
      MAERSK_API_KEY: ${MAERSK_API_KEY:?error}
      MSC_API_URL: ${MSC_API_URL:-}
      MSC_API_KEY: ${MSC_API_KEY:-}
      CMA_CGM_API_URL: ${CMA_CGM_API_URL:-}
      CMA_CGM_API_KEY: ${CMA_CGM_API_KEY:-}

      # Security
      RATE_LIMIT_GLOBAL: 100
      RATE_LIMIT_AUTH: 5
      RATE_LIMIT_SEARCH: 30
      RATE_LIMIT_BOOKING: 20

    volumes:
      - backend_logs_prod:/app/logs
    networks:
      - xpeditis_internal_prod
      - traefik_network
    labels:
      # Same Traefik labels as backend-prod-1 (load balanced)
      - "traefik.enable=true"
      - "traefik.docker.network=traefik_network"
      - "traefik.http.routers.xpeditis-backend-prod.rule=Host(`api.xpeditis.com`)"
      - "traefik.http.services.xpeditis-backend-prod.loadbalancer.server.port=4000"
    healthcheck:
      test: ["CMD", "node", "-e", "require('http').get('http://localhost:4000/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G

  # Frontend (Next.js) - Instance 1
  frontend-prod-1:
    image: ${DOCKER_REGISTRY:-docker.io}/${FRONTEND_IMAGE:-xpeditis/frontend}:${FRONTEND_TAG:-latest}
    container_name: xpeditis-frontend-prod-1
    restart: always
    depends_on:
      - backend-prod-1
      - backend-prod-2
    environment:
      NODE_ENV: production
      NEXT_PUBLIC_API_URL: https://api.xpeditis.com
      NEXT_PUBLIC_APP_URL: https://xpeditis.com
      NEXT_PUBLIC_SENTRY_DSN: ${NEXT_PUBLIC_SENTRY_DSN:?error}
      NEXT_PUBLIC_SENTRY_ENVIRONMENT: production
      NEXT_PUBLIC_GA_MEASUREMENT_ID: ${NEXT_PUBLIC_GA_MEASUREMENT_ID:?error}

      # Backend API for SSR (internal load balanced)
      API_URL: http://backend-prod-1:4000

    networks:
      - xpeditis_internal_prod
      - traefik_network
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik_network"

      # HTTPS Route
      - "traefik.http.routers.xpeditis-frontend-prod.rule=Host(`xpeditis.com`) || Host(`www.xpeditis.com`)"
      - "traefik.http.routers.xpeditis-frontend-prod.entrypoints=websecure"
      - "traefik.http.routers.xpeditis-frontend-prod.tls=true"
      - "traefik.http.routers.xpeditis-frontend-prod.tls.certresolver=letsencrypt"
      - "traefik.http.routers.xpeditis-frontend-prod.priority=200"
      - "traefik.http.services.xpeditis-frontend-prod.loadbalancer.server.port=3000"
      - "traefik.http.routers.xpeditis-frontend-prod.middlewares=xpeditis-frontend-prod-headers,xpeditis-frontend-prod-security,xpeditis-frontend-prod-compress,xpeditis-frontend-prod-www-redirect"

      # HTTP → HTTPS Redirect
      - "traefik.http.routers.xpeditis-frontend-prod-http.rule=Host(`xpeditis.com`) || Host(`www.xpeditis.com`)"
      - "traefik.http.routers.xpeditis-frontend-prod-http.entrypoints=web"
      - "traefik.http.routers.xpeditis-frontend-prod-http.priority=200"
      - "traefik.http.routers.xpeditis-frontend-prod-http.middlewares=xpeditis-frontend-prod-redirect"
      - "traefik.http.routers.xpeditis-frontend-prod-http.service=xpeditis-frontend-prod"
      - "traefik.http.middlewares.xpeditis-frontend-prod-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.xpeditis-frontend-prod-redirect.redirectscheme.permanent=true"

      # WWW → non-WWW Redirect
      - "traefik.http.middlewares.xpeditis-frontend-prod-www-redirect.redirectregex.regex=^https://www\\.(.+)"
      - "traefik.http.middlewares.xpeditis-frontend-prod-www-redirect.redirectregex.replacement=https://$${1}"
      - "traefik.http.middlewares.xpeditis-frontend-prod-www-redirect.redirectregex.permanent=true"

      # Middleware Headers
      - "traefik.http.middlewares.xpeditis-frontend-prod-headers.headers.customRequestHeaders.X-Forwarded-Proto=https"
      - "traefik.http.middlewares.xpeditis-frontend-prod-headers.headers.customRequestHeaders.X-Forwarded-For="
      - "traefik.http.middlewares.xpeditis-frontend-prod-headers.headers.customRequestHeaders.X-Real-IP="

      # Security Headers (Strict Production)
      - "traefik.http.middlewares.xpeditis-frontend-prod-security.headers.frameDeny=true"
      - "traefik.http.middlewares.xpeditis-frontend-prod-security.headers.contentTypeNosniff=true"
      - "traefik.http.middlewares.xpeditis-frontend-prod-security.headers.browserXssFilter=true"
      - "traefik.http.middlewares.xpeditis-frontend-prod-security.headers.stsSeconds=63072000"
      - "traefik.http.middlewares.xpeditis-frontend-prod-security.headers.stsIncludeSubdomains=true"
      - "traefik.http.middlewares.xpeditis-frontend-prod-security.headers.stsPreload=true"
      - "traefik.http.middlewares.xpeditis-frontend-prod-security.headers.forceSTSHeader=true"
      - "traefik.http.middlewares.xpeditis-frontend-prod-security.headers.contentSecurityPolicy=default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://api.xpeditis.com;"

      # Compression
      - "traefik.http.middlewares.xpeditis-frontend-prod-compress.compress=true"

      # Health Check
      - "traefik.http.services.xpeditis-frontend-prod.loadbalancer.healthcheck.path=/api/health"
      - "traefik.http.services.xpeditis-frontend-prod.loadbalancer.healthcheck.interval=30s"
      - "traefik.http.services.xpeditis-frontend-prod.loadbalancer.healthcheck.timeout=5s"

      # Load Balancing (Sticky Sessions)
      - "traefik.http.services.xpeditis-frontend-prod.loadbalancer.sticky.cookie=true"
      - "traefik.http.services.xpeditis-frontend-prod.loadbalancer.sticky.cookie.name=xpeditis_frontend_route"
      - "traefik.http.services.xpeditis-frontend-prod.loadbalancer.sticky.cookie.secure=true"
      - "traefik.http.services.xpeditis-frontend-prod.loadbalancer.sticky.cookie.httpOnly=true"

    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:3000/api/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G

  # Frontend (Next.js) - Instance 2 (High Availability)
  frontend-prod-2:
    image: ${DOCKER_REGISTRY:-docker.io}/${FRONTEND_IMAGE:-xpeditis/frontend}:${FRONTEND_TAG:-latest}
    container_name: xpeditis-frontend-prod-2
    restart: always
    depends_on:
      - backend-prod-1
      - backend-prod-2
    environment:
      NODE_ENV: production
      NEXT_PUBLIC_API_URL: https://api.xpeditis.com
      NEXT_PUBLIC_APP_URL: https://xpeditis.com
      NEXT_PUBLIC_SENTRY_DSN: ${NEXT_PUBLIC_SENTRY_DSN:?error}
      NEXT_PUBLIC_SENTRY_ENVIRONMENT: production
      NEXT_PUBLIC_GA_MEASUREMENT_ID: ${NEXT_PUBLIC_GA_MEASUREMENT_ID:?error}

      # Backend API for SSR (internal load balanced)
      API_URL: http://backend-prod-2:4000

    networks:
      - xpeditis_internal_prod
      - traefik_network
    labels:
      # Same Traefik labels as frontend-prod-1 (load balanced)
      - "traefik.enable=true"
      - "traefik.docker.network=traefik_network"
      - "traefik.http.routers.xpeditis-frontend-prod.rule=Host(`xpeditis.com`) || Host(`www.xpeditis.com`)"
      - "traefik.http.services.xpeditis-frontend-prod.loadbalancer.server.port=3000"
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:3000/api/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G

networks:
  xpeditis_internal_prod:
    driver: bridge
    name: xpeditis_internal_prod
  traefik_network:
    external: true

volumes:
  postgres_data_prod:
    name: xpeditis_postgres_data_prod
  postgres_backups_prod:
    name: xpeditis_postgres_backups_prod
  redis_data_prod:
    name: xpeditis_redis_data_prod
  backend_logs_prod:
    name: xpeditis_backend_logs_prod
