# docker-compose.prod.yml — Endnutzer-Deployment (vorgebaute GHCR-Images)
# Server-Mode: Gateway + 6 Services + Redis + 6 physisch getrennte DBs + Frontend.
# Usage:    docker compose -f docker-compose.prod.yml up -d
# Download: https://xebia.github.io/SwissTD-Playground/download/
#
# DB-Init: die 6 DBs nutzen postgres:16-alpine + die im Paket enthaltenen
# SQL-Skripte (./db/retailer/*, via cp -r app/db mitgeliefert) — identisch zum
# dev-Stack. Kein separates DB-Image mehr.
#
# Sicherheit (Server-Mode Phase D): NUR Nginx (8080) ist extern; Gateway (3000)
# ist an 127.0.0.1 gebunden -> Config-Mutationen nur vom Docker-Host. Services,
# DBs und Redis haben gar keinen Host-Port (nur internes swisstd-Netz).

name: swisstd

services:
  # ─── 6 physisch getrennte Postgres-Instanzen ───
  shop-db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment: { POSTGRES_DB: shop_db, POSTGRES_USER: shop_user, POSTGRES_PASSWORD: shop_pass_2026 }
    volumes:
      - shop-pgdata:/var/lib/postgresql/data
      - ./db/retailer/01-shop.sql:/docker-entrypoint-initdb.d/10-schema.sql:ro
      - ./db/retailer/seed/01-shop-seed.sql:/docker-entrypoint-initdb.d/20-seed.sql:ro
      - ./db/retailer/seed/01b-product-images.sql:/docker-entrypoint-initdb.d/21-images.sql:ro
      - ./db/retailer/seed/01c-academy-seed.sql:/docker-entrypoint-initdb.d/22-academy.sql:ro
      - ./db/retailer/session-init.sql:/docker-entrypoint-initdb.d/90-session-init.sql:ro
    healthcheck: { test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U shop_user -d shop_db"], interval: 5s, timeout: 3s, retries: 5, start_period: 30s }
    networks: [swisstd]

  log-db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment: { POSTGRES_DB: log_db, POSTGRES_USER: log_user, POSTGRES_PASSWORD: log_pass_2026 }
    volumes:
      - log-pgdata:/var/lib/postgresql/data
      - ./db/retailer/02-log.sql:/docker-entrypoint-initdb.d/10-schema.sql:ro
      - ./db/retailer/seed/02-log-seed.sql:/docker-entrypoint-initdb.d/20-seed.sql:ro
      - ./db/retailer/session-init.sql:/docker-entrypoint-initdb.d/90-session-init.sql:ro
    healthcheck: { test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U log_user -d log_db"], interval: 5s, timeout: 3s, retries: 5, start_period: 30s }
    networks: [swisstd]

  fin-db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment: { POSTGRES_DB: fin_db, POSTGRES_USER: fin_user, POSTGRES_PASSWORD: fin_pass_2026 }
    volumes:
      - fin-pgdata:/var/lib/postgresql/data
      - ./db/retailer/03-fin.sql:/docker-entrypoint-initdb.d/10-schema.sql:ro
      - ./db/retailer/seed/03-fin-seed.sql:/docker-entrypoint-initdb.d/20-seed.sql:ro
      - ./db/retailer/session-init.sql:/docker-entrypoint-initdb.d/90-session-init.sql:ro
    healthcheck: { test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U fin_user -d fin_db"], interval: 5s, timeout: 3s, retries: 5, start_period: 30s }
    networks: [swisstd]

  post-db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment: { POSTGRES_DB: post_db, POSTGRES_USER: post_user, POSTGRES_PASSWORD: post_pass_2026 }
    volumes:
      - post-pgdata:/var/lib/postgresql/data
      - ./db/retailer/04-post.sql:/docker-entrypoint-initdb.d/10-schema.sql:ro
      - ./db/retailer/seed/04-post-seed.sql:/docker-entrypoint-initdb.d/20-seed.sql:ro
      - ./db/retailer/seed/04b-plz-database.sql:/docker-entrypoint-initdb.d/21-plz.sql:ro
      - ./db/retailer/session-init.sql:/docker-entrypoint-initdb.d/90-session-init.sql:ro
    healthcheck: { test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U post_user -d post_db"], interval: 5s, timeout: 3s, retries: 5, start_period: 30s }
    networks: [swisstd]

  pay-db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment: { POSTGRES_DB: pay_db, POSTGRES_USER: pay_user, POSTGRES_PASSWORD: pay_pass_2026 }
    volumes:
      - pay-pgdata:/var/lib/postgresql/data
      - ./db/retailer/05-pay.sql:/docker-entrypoint-initdb.d/10-schema.sql:ro
      - ./db/retailer/seed/05-pay-seed.sql:/docker-entrypoint-initdb.d/20-seed.sql:ro
      - ./db/retailer/session-init.sql:/docker-entrypoint-initdb.d/90-session-init.sql:ro
    healthcheck: { test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U pay_user -d pay_db"], interval: 5s, timeout: 3s, retries: 5, start_period: 30s }
    networks: [swisstd]

  procurement-db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment: { POSTGRES_DB: procurement_db, POSTGRES_USER: procurement_user, POSTGRES_PASSWORD: procurement_pass_2026 }
    volumes:
      - procurement-pgdata:/var/lib/postgresql/data
      - ./db/retailer/06-procurement.sql:/docker-entrypoint-initdb.d/10-schema.sql:ro
      - ./db/retailer/seed/06-procurement-seed.sql:/docker-entrypoint-initdb.d/20-seed.sql:ro
      - ./db/retailer/session-init.sql:/docker-entrypoint-initdb.d/90-session-init.sql:ro
    healthcheck: { test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U procurement_user -d procurement_db"], interval: 5s, timeout: 3s, retries: 5, start_period: 30s }
    networks: [swisstd]

  # ─── Redis 7 (Event Bus + Session-Config + ensured-Cache) ───
  redis:
    image: redis:7-alpine
    restart: unless-stopped
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks: [swisstd]

  # ─── Gateway (API-Routing, :3000) — nur 127.0.0.1 (Host-Mutation) ───
  gateway:
    image: ghcr.io/xebia/swisstd-playground/gateway:latest
    restart: unless-stopped
    user: root  # Docker-Socket-Zugriff für Container-Management (System-Diagramm)
    ports: ["127.0.0.1:3000:3000"]
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      SERVICE_NAME: gateway
      SERVICE_PORT: "3000"
      REDIS_URL: redis://redis:6379/0
      CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:8080,http://localhost:3000,http://127.0.0.1:8080,http://127.0.0.1:3000}
      ADMIN_API_KEY: ${ADMIN_API_KEY:-SwissTD-2026-Admin}
      SHOP_URL: http://shop-service:3001
      LOG_URL: http://log-service:3002
      FIN_URL: http://fin-service:3003
      POST_URL: http://post-service:3004
      PAY_URL: http://pay-service:3005
      PROCUREMENT_URL: http://procurement-service:3006
      SHOP_DB_URL: postgresql://shop_user:shop_pass_2026@shop-db:5432/shop_db
      LOG_DB_URL: postgresql://log_user:log_pass_2026@log-db:5432/log_db
      FIN_DB_URL: postgresql://fin_user:fin_pass_2026@fin-db:5432/fin_db
      POST_DB_URL: postgresql://post_user:post_pass_2026@post-db:5432/post_db
      PAY_DB_URL: postgresql://pay_user:pay_pass_2026@pay-db:5432/pay_db
      PROC_DB_URL: postgresql://procurement_user:procurement_pass_2026@procurement-db:5432/procurement_db
    depends_on:
      redis: { condition: service_healthy }
      shop-db: { condition: service_healthy }
      log-db: { condition: service_healthy }
      fin-db: { condition: service_healthy }
      post-db: { condition: service_healthy }
      pay-db: { condition: service_healthy }
      procurement-db: { condition: service_healthy }
    networks: [swisstd]

  # ─── 6 Services (kein Host-Port; nur internes Netz) ───
  shop-service:
    image: ghcr.io/xebia/swisstd-playground/shop:latest
    restart: unless-stopped
    environment:
      SERVICE_NAME: shop
      SERVICE_PORT: "3001"
      DATABASE_URL: postgresql://shop_user:shop_pass_2026@shop-db:5432/shop_db
      REDIS_URL: redis://redis:6379/0
      GATEWAY_URL: http://gateway:3000
    depends_on:
      shop-db: { condition: service_healthy }
      redis: { condition: service_healthy }
    networks: [swisstd]

  log-service:
    image: ghcr.io/xebia/swisstd-playground/log:latest
    restart: unless-stopped
    environment:
      SERVICE_NAME: log
      SERVICE_PORT: "3002"
      DATABASE_URL: postgresql://log_user:log_pass_2026@log-db:5432/log_db
      REDIS_URL: redis://redis:6379/0
      GATEWAY_URL: http://gateway:3000
    depends_on:
      log-db: { condition: service_healthy }
      redis: { condition: service_healthy }
    networks: [swisstd]

  fin-service:
    image: ghcr.io/xebia/swisstd-playground/fin:latest
    restart: unless-stopped
    environment:
      SERVICE_NAME: fin
      SERVICE_PORT: "3003"
      DATABASE_URL: postgresql://fin_user:fin_pass_2026@fin-db:5432/fin_db
      REDIS_URL: redis://redis:6379/0
      GATEWAY_URL: http://gateway:3000
    depends_on:
      fin-db: { condition: service_healthy }
      redis: { condition: service_healthy }
    networks: [swisstd]

  post-service:
    image: ghcr.io/xebia/swisstd-playground/post:latest
    restart: unless-stopped
    environment:
      SERVICE_NAME: post
      SERVICE_PORT: "3004"
      DATABASE_URL: postgresql://post_user:post_pass_2026@post-db:5432/post_db
      REDIS_URL: redis://redis:6379/0
      GATEWAY_URL: http://gateway:3000
    depends_on:
      post-db: { condition: service_healthy }
      redis: { condition: service_healthy }
    networks: [swisstd]

  pay-service:
    image: ghcr.io/xebia/swisstd-playground/pay:latest
    restart: unless-stopped
    environment:
      SERVICE_NAME: pay
      SERVICE_PORT: "3005"
      DATABASE_URL: postgresql://pay_user:pay_pass_2026@pay-db:5432/pay_db
      REDIS_URL: redis://redis:6379/0
      GATEWAY_URL: http://gateway:3000
    depends_on:
      pay-db: { condition: service_healthy }
      redis: { condition: service_healthy }
    networks: [swisstd]

  procurement-service:
    image: ghcr.io/xebia/swisstd-playground/procurement:latest
    restart: unless-stopped
    environment:
      SERVICE_NAME: procurement
      SERVICE_PORT: "3006"
      DATABASE_URL: postgresql://procurement_user:procurement_pass_2026@procurement-db:5432/procurement_db
      REDIS_URL: redis://redis:6379/0
      GATEWAY_URL: http://gateway:3000
    depends_on:
      procurement-db: { condition: service_healthy }
      redis: { condition: service_healthy }
    networks: [swisstd]

  # ─── Nginx (Frontend + Reverse Proxy, :8080) — einziger externer Port ───
  frontend:
    image: ghcr.io/xebia/swisstd-playground/frontend:latest
    restart: unless-stopped
    ports: ["8080:80"]
    depends_on: [gateway]
    networks: [swisstd]

  # ─── Adminer (DB-Verwaltung, :8081) — nur 127.0.0.1 (Host) ───
  adminer:
    image: adminer:latest
    restart: unless-stopped
    ports: ["127.0.0.1:8081:8080"]
    environment:
      # Startet auf shop-db; die anderen 5 im Login waehlbar.
      ADMINER_DEFAULT_SERVER: shop-db
      ADMINER_DESIGN: dracula
    depends_on: [shop-db]
    networks: [swisstd]

volumes:
  shop-pgdata:
  log-pgdata:
  fin-pgdata:
  post-pgdata:
  pay-pgdata:
  procurement-pgdata:
  redis-data:

networks:
  swisstd:
    driver: bridge
