# =============================================================================
# Sovereign Workflows — Alpha Test Docker Compose
# =============================================================================
# Quick start:
#   1. Copy .env.example to .env and set passwords
#   2. Place your license file at ./license.lic
#   3. docker compose up -d
#   4. Open http://localhost:4723 — you should see the Workflows UI
#
# All configurable values use ${VARIABLE} syntax — see .env.example for details.
# =============================================================================

services:

  # ---------------------------------------------------------------------------
  # Reverse Proxy (nginx) — Single entry point for the entire stack
  # ---------------------------------------------------------------------------
  # Routes traffic: / → UI, /api → Engine, /auth → Auth, /mcp → MCP Server
  # This is the only port alpha testers need to remember.
  reverse-proxy:
    image: ghcr.io/nemoriontechnologies/sovereign-reverse-proxy:${SOVEREIGN_VERSION:-latest}
    container_name: sovereign-reverse-proxy
    ports:
      - "${PROXY_PORT:-4723}:80"
    depends_on:
      ui:
        condition: service_healthy
      engine-api:
        condition: service_healthy
    networks:
      - sovereign-network
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://127.0.0.1/"]
      interval: 30s
      timeout: 3s
      retries: 3
    restart: unless-stopped

  # ---------------------------------------------------------------------------
  # Workflows UI — Visual workflow editor and dashboard
  # ---------------------------------------------------------------------------
  # Vite-built React SPA served by nginx. Create workflows, view executions,
  # manage connectors — all from the browser.
  ui:
    image: ghcr.io/nemoriontechnologies/sovereign-workflows-ui:${SOVEREIGN_VERSION:-latest}
    container_name: sovereign-ui
    environment:
      NODE_ENV: production
    networks:
      sovereign-network:
        aliases:
          - ui
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://127.0.0.1/"]
      interval: 30s
      timeout: 3s
      start_period: 5s
      retries: 3
    restart: unless-stopped

  # ---------------------------------------------------------------------------
  # Infrastructure: PostgreSQL
  # ---------------------------------------------------------------------------
  # Single shared database instance. Auth service uses a separate logical
  # database (auth) on the same server for isolation without extra containers.
  postgres:
    image: postgres:16-alpine@sha256:16bc17c64a573ef34162af9298258d1aec548232985b33ed7b1eac33ba35c229
    container_name: sovereign-postgres
    command: postgres -c track_commit_timestamp=on
    environment:
      POSTGRES_DB: ${POSTGRES_DB:-dataworkflows}
      POSTGRES_USER: ${POSTGRES_USER:-postgres}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
    ports:
      - "${POSTGRES_PORT:-5432}:5432"
    volumes:
      - postgres-data:/var/lib/postgresql/data
      # Init script creates the auth and spicedb databases on first start
      - ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
    networks:
      - sovereign-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  # ---------------------------------------------------------------------------
  # Infrastructure: RabbitMQ
  # ---------------------------------------------------------------------------
  # Message broker for workflow step dispatch and result routing.
  # Management UI available at http://localhost:${RABBITMQ_MGMT_PORT:-15672}
  rabbitmq:
    image: rabbitmq:3.13-management-alpine@sha256:606d8c0d6b3c18d1da9afc53bc7cdb2a8d5486df91b5a9830e9e07626c9ae281
    container_name: sovereign-rabbitmq
    environment:
      RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-workflow}
      RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:?RABBITMQ_PASSWORD is required}
      RABBITMQ_DEFAULT_VHOST: /
    ports:
      - "${RABBITMQ_PORT:-5672}:5672"
      - "${RABBITMQ_MGMT_PORT:-15672}:15672"
    volumes:
      - rabbitmq-data:/var/lib/rabbitmq
    networks:
      - sovereign-network
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  # ---------------------------------------------------------------------------
  # Infrastructure: SpiceDB Migrations
  # ---------------------------------------------------------------------------
  # Runs schema migrations for SpiceDB's backing store on first start.
  spicedb-migrate:
    image: authzed/spicedb:latest@sha256:f2ba6c78b6c5bfc465d975ef5c0b8f7f4dce57049c3c02fd1f3155be819895f7
    container_name: sovereign-spicedb-migrate
    command: migrate head --datastore-engine=postgres --datastore-conn-uri=postgres://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@postgres:5432/spicedb?sslmode=disable
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - sovereign-network
    restart: "no"

  # ---------------------------------------------------------------------------
  # Infrastructure: SpiceDB — Authorization service (Zanzibar-inspired ReBAC)
  # ---------------------------------------------------------------------------
  # Provides fine-grained authorization. gRPC API on 50051, HTTP on 8443.
  spicedb:
    image: authzed/spicedb:latest@sha256:f2ba6c78b6c5bfc465d975ef5c0b8f7f4dce57049c3c02fd1f3155be819895f7
    container_name: sovereign-spicedb
    command: >-
      serve
      --datastore-engine=postgres
      --datastore-conn-uri=postgres://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@postgres:5432/spicedb?sslmode=disable
      --grpc-preshared-key=${SPICEDB_PRESHARED_KEY:?SPICEDB_PRESHARED_KEY is required}
      --http-enabled=true
    ports:
      - "${SPICEDB_GRPC_PORT:-50051}:50051"
      - "${SPICEDB_HTTP_PORT:-8443}:8443"
    depends_on:
      spicedb-migrate:
        condition: service_completed_successfully
      postgres:
        condition: service_healthy
    networks:
      - sovereign-network
    healthcheck:
      test: ["CMD", "grpc_health_probe", "-addr=localhost:50051"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  # ---------------------------------------------------------------------------
  # Infrastructure: Redis
  # ---------------------------------------------------------------------------
  # Distributed caching and locking (Auth service, future rate limiting).
  redis:
    image: redis:7-alpine@sha256:6ab0b6e7381779332f97b8ca76193e45b0756f38d4c0dcda72dbb3c32061ab99
    container_name: sovereign-redis
    command: redis-server --appendonly yes
    volumes:
      - redis-data:/data
    networks:
      - sovereign-network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  # ---------------------------------------------------------------------------
  # Auth API — Authentication and credential management
  # ---------------------------------------------------------------------------
  # In Alpha, runs in Bypass mode — no login required.
  # Issues JWTs, manages OAuth 2.1 flows, stores encrypted credentials.
  auth-api:
    image: ghcr.io/nemoriontechnologies/sovereign-auth-api:${SOVEREIGN_VERSION:-latest}
    container_name: sovereign-auth-api
    environment:
      ASPNETCORE_ENVIRONMENT: Development
      ASPNETCORE_URLS: http://+:80
      # Auth DB — separate logical database on the shared Postgres instance
      ConnectionStrings__AuthDb: "Host=postgres;Port=5432;Database=${AUTH_DB:-auth};Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}"
      # Redis for distributed caching
      ConnectionStrings__Redis: "redis:6379"
      # Bypass mode — no login required for alpha testing
      Auth__Mode: Bypass
      # Encryption for credential storage
      Encryption__MasterKeyId: alpha-key-01
      Encryption__MasterKey: ${AUTH_ENCRYPTION_KEY:-alpha-test-encryption-key-change-me}
      Encryption__Algorithm: AES-256-GCM
      # Platform token signing
      Auth__PlatformToken__SigningKey__Source: File
      Auth__PlatformToken__SigningKey__Path: /app/keys/signing.key
      Auth__PlatformToken__SigningKey__GenerateIfMissing: "true"
    volumes:
      - auth-keys:/app/keys
    healthcheck:
      test: ["CMD", "/app/healthcheck", "http://localhost:80/health"]
      interval: 10s
      timeout: 5s
      retries: 5
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      sovereign-network:
        aliases:
          - auth-service
    restart: unless-stopped

  # ---------------------------------------------------------------------------
  # Engine API — Workflow orchestration and management
  # ---------------------------------------------------------------------------
  # The central brain: stores workflow definitions, orchestrates execution,
  # manages connector registration, and exposes the REST API.
  engine-api:
    image: ghcr.io/nemoriontechnologies/sovereign-engine-api:${SOVEREIGN_VERSION:-latest}
    container_name: sovereign-engine-api
    environment:
      ASPNETCORE_ENVIRONMENT: Production
      ASPNETCORE_URLS: http://+:80
      ConnectionStrings__Postgres: "Host=postgres;Port=5432;Database=${POSTGRES_DB:-dataworkflows};Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}"
      # License file mounted as a volume
      License__FilePath: /etc/workflows/license.lic
      # Auth service (Bypass mode — no service key needed)
      AuthService__BaseUrl: http://auth-service:80
      Auth__Mode: Bypass
      # Orchestration settings
      Orchestration__MaxParallelActions: ${MAX_PARALLEL_ACTIONS:-10}
      Orchestration__DefaultActionTimeout: ${DEFAULT_ACTION_TIMEOUT:-00:05:00}
      Orchestration__DefaultWorkflowTimeout: ${DEFAULT_WORKFLOW_TIMEOUT:-01:00:00}
      Orchestration__MaxWorkflowNestingDepth: ${MAX_NESTING_DEPTH:-5}
      Orchestration__AllowSubworkflowRecursion: "false"
      Orchestration__AllowAsyncSubworkflows: "false"
      # RabbitMQ
      RabbitMQ__Host: rabbitmq
      RabbitMQ__Port: "5672"
      RabbitMQ__Username: ${RABBITMQ_USER:-workflow}
      RabbitMQ__Password: ${RABBITMQ_PASSWORD:?RABBITMQ_PASSWORD is required}
      RabbitMQ__VirtualHost: /
    volumes:
      - ${LICENSE_FILE_PATH:-./license.lic}:/etc/workflows/license.lic:ro
    healthcheck:
      test: ["CMD", "/app/healthcheck", "http://localhost:80/health/live"]
      interval: 10s
      timeout: 5s
      retries: 5
    depends_on:
      postgres:
        condition: service_healthy
      rabbitmq:
        condition: service_healthy
      auth-api:
        condition: service_healthy
    networks:
      sovereign-network:
        aliases:
          - engine
          - enterprise-engine
    restart: unless-stopped

  # ---------------------------------------------------------------------------
  # Executor Worker — Workflow step execution
  # ---------------------------------------------------------------------------
  # Pulls steps from RabbitMQ, dispatches them to connectors, reports results.
  # Scales horizontally — increase replicas for more throughput.
  executor-worker:
    image: ghcr.io/nemoriontechnologies/sovereign-executor-worker:${SOVEREIGN_VERSION:-latest}
    environment:
      DOTNET_ENVIRONMENT: Production
      ConnectionStrings__DefaultConnection: "Host=postgres;Port=5432;Database=${POSTGRES_DB:-dataworkflows};Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}"
      # License file
      License__FilePath: /etc/workflows/license.lic
      # Auth service (Bypass mode)
      AuthService__BaseUrl: http://auth-service:80
      # RabbitMQ
      RabbitMQ__Host: rabbitmq
      RabbitMQ__Port: "5672"
      RabbitMQ__Username: ${RABBITMQ_USER:-workflow}
      RabbitMQ__Password: ${RABBITMQ_PASSWORD:?RABBITMQ_PASSWORD is required}
      RabbitMQ__VirtualHost: /
      # Worker identity (auto-set per replica via hostname)
      WorkerId: ${HOSTNAME}
      # Service key for connector host authentication
      ServiceKeyAuthentication__GlobalServiceKey: ${CONNECTOR_GLOBAL_SERVICE_KEY:?CONNECTOR_GLOBAL_SERVICE_KEY is required}
      # Connector URLs — executor dispatches actions to these endpoints
      ConnectorUrls__sample: http://connector-host:80
      ConnectorUrls__llm: http://llm-connector:80
    volumes:
      - ${LICENSE_FILE_PATH:-./license.lic}:/etc/workflows/license.lic:ro
    depends_on:
      postgres:
        condition: service_healthy
      rabbitmq:
        condition: service_healthy
      engine-api:
        condition: service_healthy
    networks:
      - sovereign-network
    deploy:
      replicas: ${EXECUTOR_REPLICAS:-2}
    restart: unless-stopped

  # ---------------------------------------------------------------------------
  # Connector Host — Multi-connector runtime
  # ---------------------------------------------------------------------------
  # Loads connector plugins from a volume. Ships with the sample connector.
  # Mount additional connector DLLs into the plugins volume.
  connector-host:
    image: ghcr.io/nemoriontechnologies/sovereign-connector-host:${SOVEREIGN_VERSION:-latest}
    container_name: sovereign-connector-host
    environment:
      ASPNETCORE_ENVIRONMENT: Production
      ASPNETCORE_URLS: http://+:80
      ConnectorRegistration__EngineUrl: http://enterprise-engine:80
      ConnectorHost__ConfigDirectory: /etc/workflows/connectors
      ConnectorHost__PluginsDirectory: /etc/workflows/connector-plugins
      ServiceKeyAuthentication__GlobalServiceKey: ${CONNECTOR_GLOBAL_SERVICE_KEY:?CONNECTOR_GLOBAL_SERVICE_KEY is required}
    volumes:
      - connector-configs:/etc/workflows/connectors
      - connector-plugins:/etc/workflows/connector-plugins
    healthcheck:
      test: ["CMD", "/app/healthcheck", "http://localhost:80/health/live"]
      interval: 10s
      timeout: 5s
      retries: 5
    depends_on:
      engine-api:
        condition: service_healthy
    networks:
      sovereign-network:
        aliases:
          - connector-host
    restart: unless-stopped

  # ---------------------------------------------------------------------------
  # LLM Connector — AI-powered workflow actions
  # ---------------------------------------------------------------------------
  # Provides llm.chat, llm.chat-with-session, and llm.store-memory actions.
  # Pre-configured with a Nemorion-provided API key for alpha testing.
  # To use your own key or switch providers, see:
  # https://portal.nemorion.com/docs/guides/llm-configuration
  llm-connector:
    image: ghcr.io/nemoriontechnologies/sovereign-llm-connector:${SOVEREIGN_VERSION:-latest}
    container_name: sovereign-llm-connector
    environment:
      ASPNETCORE_ENVIRONMENT: Production
      ASPNETCORE_URLS: http://+:80
      ConnectionStrings__Postgres: "Host=postgres;Port=5432;Database=${POSTGRES_DB:-dataworkflows};Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}"
      ConnectorRegistration__EngineUrl: http://enterprise-engine:80
      ServiceKeyAuthentication__GlobalServiceKey: ${CONNECTOR_GLOBAL_SERVICE_KEY:?CONNECTOR_GLOBAL_SERVICE_KEY is required}
      # To override the baked-in API key, uncomment and set in .env:
      # GEMINI_API_KEY: ${GEMINI_API_KEY}
      Llm__DefaultProvider: gemini
      Llm__DefaultModel: ${LLM_DEFAULT_MODEL:-gemini-2.5-pro}
    healthcheck:
      test: ["CMD", "/app/healthcheck", "http://localhost:80/health/live"]
      interval: 10s
      timeout: 5s
      retries: 5
    depends_on:
      postgres:
        condition: service_healthy
      engine-api:
        condition: service_healthy
    networks:
      sovereign-network:
        aliases:
          - llm-connector
    restart: unless-stopped

  # ---------------------------------------------------------------------------
  # MCP Server — Agentic workflow interface
  # ---------------------------------------------------------------------------
  # Provides REST/SSE API for AI agent sessions. Connects to Engine for
  # workflow execution and tool dispatch. Supports Claude, GPT, etc.
  mcp-server:
    image: ghcr.io/nemoriontechnologies/sovereign-mcp-server:${SOVEREIGN_VERSION:-latest}
    container_name: sovereign-mcp-server
    environment:
      ASPNETCORE_ENVIRONMENT: Production
      ASPNETCORE_URLS: http://+:80
      ConnectionStrings__Postgres: "Host=postgres;Port=5432;Database=${POSTGRES_DB:-dataworkflows};Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}"
      # Auth service
      AuthService__BaseUrl: http://auth-service:80
      # RabbitMQ
      RabbitMQ__Host: rabbitmq
      RabbitMQ__Port: "5672"
      RabbitMQ__Username: ${RABBITMQ_USER:-workflow}
      RabbitMQ__Password: ${RABBITMQ_PASSWORD:?RABBITMQ_PASSWORD is required}
      RabbitMQ__VirtualHost: /
      # Engine API for tool execution
      EngineApi__BaseUrl: http://enterprise-engine:80
      # Self URL for connector registration (internal Docker network)
      MCP_SERVER_BASE_URL: http://mcp-server:80
      # To override the baked-in API key, uncomment and set in .env:
      # GEMINI_API_KEY: ${GEMINI_API_KEY}
    healthcheck:
      test: ["CMD", "/app/healthcheck", "http://localhost:80/health"]
      interval: 10s
      timeout: 5s
      retries: 5
    depends_on:
      postgres:
        condition: service_healthy
      rabbitmq:
        condition: service_healthy
      auth-api:
        condition: service_healthy
    networks:
      sovereign-network:
        aliases:
          - mcp-server
    restart: unless-stopped

# =============================================================================
# Volumes — Persistent data storage
# =============================================================================
volumes:
  postgres-data:
    driver: local
  rabbitmq-data:
    driver: local
  redis-data:
    driver: local
  auth-keys:
    driver: local
  connector-configs:
    driver: local
  connector-plugins:
    driver: local

# =============================================================================
# Network — Single bridge network for all services
# =============================================================================
networks:
  sovereign-network:
    driver: bridge
