# AEGIS CYBER — On-Prem Docker Compose
#
# Brings up the platform (`app`) backed by a bundled PostgreSQL 16
# (`postgres`). Both services share a private bridge network; only the
# app's port 5000 is published to the host. Persistent state lives in
# three named volumes: pgdata (database), exports (generated reports),
# backups (pg_dump artefacts).
#
# Prereq: copy .env.template to .env and fill in REQUIRED values.
# Bring up: docker compose up -d
# Tail logs: docker compose logs -f app
# Stop:     docker compose down               (keeps volumes)
# Reset:    docker compose down -v            (wipes data — destructive)

services:
  postgres:
    image: postgres:16-alpine
    container_name: aegis-postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-aegis}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set in .env}
      POSTGRES_DB: ${POSTGRES_DB:-aegis_cyber}
    volumes:
      - aegis-pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-aegis} -d ${POSTGRES_DB:-aegis_cyber}"]
      interval: 5s
      timeout: 5s
      retries: 20
      start_period: 10s
    networks:
      - aegis-net

  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: aegis-cyber:phase1
    container_name: aegis-app
    restart: unless-stopped
    # Inject the full .env so ALL boot-guard-required secrets reach the container
    # (the explicit `environment:` block below only mapped the older 9-secret set;
    # the current image also requires ENCRYPTION_KEY, PII_AES/HMAC_MASTER_KEY,
    # ENGINEER_OKOT/OKELLO_PASSWORD, MLCO_PASSWORD, AUDIT_SNAPSHOT_SIGNING_KEY).
    # `environment:` entries still take precedence over env_file where both set.
    env_file:
      - .env
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      NODE_ENV: production
      PORT: 5000
      # Platform clock = East Africa Time (Kampala, UTC+3). POSIX TZ string
      # (sign inverted): "EAT-3" => UTC+3, no DST (Uganda has none), needs no tzdata.
      TZ: EAT-3
      # Assembled DATABASE_URL points at the compose-bundled postgres.
      # Override by setting DATABASE_URL in .env to point at an external
      # PostgreSQL instance instead.
      DATABASE_URL: ${DATABASE_URL:-postgresql://${POSTGRES_USER:-aegis}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-aegis_cyber}}
      PGHOST: postgres
      PGPORT: 5432
      PGUSER: ${POSTGRES_USER:-aegis}
      PGPASSWORD: ${POSTGRES_PASSWORD}
      PGDATABASE: ${POSTGRES_DB:-aegis_cyber}
      # Boot-guard signing secrets (server refuses to start without all 9 + SESSION_SECRET).
      SESSION_SECRET: ${SESSION_SECRET:?SESSION_SECRET must be set in .env}
      WAVE10_SIGNING_SECRET: ${WAVE10_SIGNING_SECRET:?WAVE10_SIGNING_SECRET must be set in .env}
      WAVE10_PDF_SECRET: ${WAVE10_PDF_SECRET:?WAVE10_PDF_SECRET must be set in .env}
      DEMO_PACK_SIGNING_SECRET: ${DEMO_PACK_SIGNING_SECRET:?DEMO_PACK_SIGNING_SECRET must be set in .env}
      SLSA_SIGNING_SECRET: ${SLSA_SIGNING_SECRET:?SLSA_SIGNING_SECRET must be set in .env}
      ONBOARD_SIGNING_SECRET: ${ONBOARD_SIGNING_SECRET:?ONBOARD_SIGNING_SECRET must be set in .env}
      CROSS_PILLAR_SIGNING_SECRET: ${CROSS_PILLAR_SIGNING_SECRET:?CROSS_PILLAR_SIGNING_SECRET must be set in .env}
      TENANT_EXPORT_SIGNING_SECRET: ${TENANT_EXPORT_SIGNING_SECRET:?TENANT_EXPORT_SIGNING_SECRET must be set in .env}
      TENANT_EXPORT_KEY: ${TENANT_EXPORT_KEY:?TENANT_EXPORT_KEY must be set in .env}
      EXAMINER_TOKEN_SALT: ${EXAMINER_TOKEN_SALT:?EXAMINER_TOKEN_SALT must be set in .env}
      # Initial admin user passwords. Leave blank to have the platform
      # generate a one-time random password printed once at first boot.
      AEGIS_ADMIN_PASSWORD: ${AEGIS_ADMIN_PASSWORD:-}
      AEGIS_CISO_PASSWORD: ${AEGIS_CISO_PASSWORD:-}
      AEGIS_AUDITOR_PASSWORD: ${AEGIS_AUDITOR_PASSWORD:-}
      # Optional regulator-demo seed (read-only auditor account for BoU/FIA demos).
      REGULATOR_SEED_PASSWORD: ${REGULATOR_SEED_PASSWORD:-}
      # Optional AI threat scoring; platform runs on deterministic rules without it.
      ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
      # Session cookie Secure flag override. Default (unset) keeps cookies
      # Secure-only in production — correct for any deployment behind a TLS
      # terminator (nginx, F5, cloud LB). Set COOKIE_SECURE=false in .env
      # ONLY for plain-HTTP localhost demos (browsers silently drop Secure
      # cookies over HTTP). NEVER set this in a real bank deployment.
      COOKIE_SECURE: ${COOKIE_SECURE:-}
      # Defence-in-depth confirmation flag. Required to be "true" if
      # COOKIE_SECURE=false is set in production — without it, the boot
      # guard refuses to start. Closes the template-default-drift path
      # where a bank deployment could silently run with non-Secure
      # session cookies. See server/routes.ts cookie boot guard.
      AEGIS_ALLOW_INSECURE_COOKIE: ${AEGIS_ALLOW_INSECURE_COOKIE:-}
      # Persistent volume paths inside the container (mounted below).
      EXPORT_DIR: /var/aegis/exports
      BACKUP_DIR: /var/aegis/backups
      # Dynamic KYT configuration (2026-05-23). The platform reads its KYT
      # rule set from this file at boot and re-reads every 30s. The host's
      # ./config directory is bind-mounted writeable at /app/config; the
      # operator can edit the file on the host or change it via the
      # apply-config API, and the container picks up the change either
      # synchronously (API path) or on the next poll tick (direct edit).
      KYT_CONFIG_PATH: /app/config/kyt-rules.json
    volumes:
      - aegis-exports:/var/aegis/exports
      - aegis-backups:/var/aegis/backups
      # KYT rules config — bind-mount, writeable. The apply-config API
      # endpoint writes the file in-place from inside the container, so
      # `:rw` is required for that path to work. If only host-side edits
      # are used (operator's text editor) and the apply-config API is
      # never called, change `:rw` to `:ro` for defence-in-depth — the
      # poller will still pick up host-side changes within 30s. See
      # docs/regulatory/KYT_CONFIG_RUNBOOK.md.
      - ./config:/app/config:rw
    ports:
      - "${HOST_PORT:-5000}:5000"
    networks:
      - aegis-net

volumes:
  aegis-pgdata:
  aegis-exports:
  aegis-backups:

networks:
  aegis-net:
    driver: bridge
