services:
  keycloak:
    image: quay.io/keycloak/keycloak:26.0
    container_name: certifai-keycloak
    environment:
      KC_BOOTSTRAP_ADMIN_USERNAME: admin
      KC_BOOTSTRAP_ADMIN_PASSWORD: admin
      KC_DB: dev-mem
      KC_HEALTH_ENABLED: "true"
    ports:
      - "8080:8080"
    command:
      - start-dev
      - --import-realm
    volumes:
      - ./keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json:ro
      - ./keycloak/themes/certifai:/opt/keycloak/themes/certifai:ro
    healthcheck:
      test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/8080 && echo -e 'GET /realms/master HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3 && head -1 <&3 | grep -q '200 OK'"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 30s

  mongo:
    image: mongo:latest
    restart: unless-stopped
    ports:
      - 27017:27017
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: example

  searxng:
    image: searxng/searxng:latest
    container_name: certifai-searxng
    restart: unless-stopped
    ports:
      - "8888:8080"
    environment:
      - SEARXNG_BASE_URL=http://localhost:8888
    volumes:
      - ./searxng:/etc/searxng:rw

  librechat:
    image: ghcr.io/danny-avila/librechat:latest
    container_name: certifai-librechat
    restart: unless-stopped
    # Use host networking so localhost:8080 (Keycloak) is reachable for
    # OIDC discovery, and the browser redirect URLs match the issuer.
    network_mode: host
    depends_on:
      keycloak:
        condition: service_healthy
      mongo:
        condition: service_started
    environment:
      # LiteLLM API key (used by librechat.yaml endpoint config)
      LITELLM_API_KEY: ${LITELLM_API_KEY:-}
      # MongoDB (use localhost since we're on host network)
      MONGO_URI: mongodb://root:example@localhost:27017/librechat?authSource=admin
      DOMAIN_CLIENT: http://localhost:3080
      DOMAIN_SERVER: http://localhost:3080
      # Allow HTTP for local dev OIDC (Keycloak on localhost without TLS)
      NODE_TLS_REJECT_UNAUTHORIZED: "0"
      NODE_ENV: development
      # Keycloak OIDC SSO
      OPENID_ISSUER: http://localhost:8080/realms/certifai
      OPENID_CLIENT_ID: certifai-librechat
      OPENID_CLIENT_SECRET: certifai-librechat-secret
      OPENID_SESSION_SECRET: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6"
      OPENID_CALLBACK_URL: /oauth/openid/callback
      OPENID_SCOPE: openid profile email
      OPENID_BUTTON_LABEL: Login with CERTifAI
      # Disable local auth (SSO only)
      ALLOW_EMAIL_LOGIN: "false"
      ALLOW_REGISTRATION: "false"
      ALLOW_SOCIAL_LOGIN: "true"
      ALLOW_SOCIAL_REGISTRATION: "true"
      # JWT / encryption secrets (required by LibreChat)
      CREDS_KEY: "97e95d72cdda06774a264f9fb7768097a6815dc1e930898d2e39c9a3a253b157"
      CREDS_IV: "2ea456ab25279089b0ff9e7aca1df6e6"
      JWT_SECRET: "767b962176666eab56e180e6f2d3fe95145dc6b978e37d4eb8d1da5421c5fb26"
      JWT_REFRESH_SECRET: "51a43a1fca4b7b501b37e226a638645d962066e0686b82248921f3160e96501e"
      # App settings
      APP_TITLE: CERTifAI Chat
      CUSTOM_FOOTER: CERTifAI - Sovereign GenAI Infrastructure
      HOST: 0.0.0.0
      PORT: "3080"
      NO_INDEX: "true"
    volumes:
      - ./librechat/librechat.yaml:/app/librechat.yaml:ro
      - ./librechat/logo.svg:/app/client/public/assets/logo.svg:ro
      # Patch: allow HTTP issuer for local dev (openid-client v6 enforces HTTPS)
      - ./librechat/openidStrategy.js:/app/api/strategies/openidStrategy.js:ro
      - librechat-data:/app/data

  langflow:
    image: langflowai/langflow:latest
    container_name: certifai-langflow
    restart: unless-stopped
    ports:
      - "7860:7860"
    environment:
      LANGFLOW_AUTO_LOGIN: "true"

  langgraph:
    image: langchain/langgraph-trial:3.12
    container_name: certifai-langgraph
    restart: unless-stopped
    depends_on:
      langgraph-db:
        condition: service_started
      langgraph-redis:
        condition: service_started
    ports:
      - "8123:8000"
    environment:
      DATABASE_URI: postgresql://langgraph:langgraph@langgraph-db:5432/langgraph
      REDIS_URI: redis://langgraph-redis:6379

  langgraph-db:
    image: postgres:16
    container_name: certifai-langgraph-db
    restart: unless-stopped
    environment:
      POSTGRES_USER: langgraph
      POSTGRES_PASSWORD: langgraph
      POSTGRES_DB: langgraph
    volumes:
      - langgraph-db-data:/var/lib/postgresql/data

  langgraph-redis:
    image: redis:7-alpine
    container_name: certifai-langgraph-redis
    restart: unless-stopped

  langfuse:
    image: langfuse/langfuse:3
    container_name: certifai-langfuse
    restart: unless-stopped
    depends_on:
      keycloak:
        condition: service_healthy
      langfuse-db:
        condition: service_healthy
      langfuse-clickhouse:
        condition: service_healthy
      langfuse-redis:
        condition: service_healthy
      langfuse-minio:
        condition: service_healthy
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://langfuse:langfuse@langfuse-db:5432/langfuse
      NEXTAUTH_URL: http://localhost:3000
      NEXTAUTH_SECRET: certifai-langfuse-dev-secret
      SALT: certifai-langfuse-dev-salt
      ENCRYPTION_KEY: "0000000000000000000000000000000000000000000000000000000000000000"
      # Keycloak OIDC SSO - shared realm with CERTifAI dashboard
      AUTH_KEYCLOAK_CLIENT_ID: certifai-langfuse
      AUTH_KEYCLOAK_CLIENT_SECRET: certifai-langfuse-secret
      AUTH_KEYCLOAK_ISSUER: http://keycloak:8080/realms/certifai
      AUTH_KEYCLOAK_ALLOW_ACCOUNT_LINKING: "true"
      # Disable local email/password auth (SSO only)
      AUTH_DISABLE_USERNAME_PASSWORD: "true"
      CLICKHOUSE_URL: http://langfuse-clickhouse:8123
      CLICKHOUSE_MIGRATION_URL: clickhouse://langfuse-clickhouse:9000
      CLICKHOUSE_USER: clickhouse
      CLICKHOUSE_PASSWORD: clickhouse
      CLICKHOUSE_CLUSTER_ENABLED: "false"
      REDIS_HOST: langfuse-redis
      REDIS_PORT: "6379"
      REDIS_AUTH: langfuse-dev-redis
      LANGFUSE_S3_EVENT_UPLOAD_BUCKET: langfuse
      LANGFUSE_S3_EVENT_UPLOAD_REGION: auto
      LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID: minio
      LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: miniosecret
      LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT: http://langfuse-minio:9000
      LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE: "true"
      LANGFUSE_S3_MEDIA_UPLOAD_BUCKET: langfuse
      LANGFUSE_S3_MEDIA_UPLOAD_REGION: auto
      LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID: minio
      LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: miniosecret
      LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT: http://langfuse-minio:9000
      LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: "true"

  langfuse-db:
    image: postgres:16
    container_name: certifai-langfuse-db
    restart: unless-stopped
    environment:
      POSTGRES_USER: langfuse
      POSTGRES_PASSWORD: langfuse
      POSTGRES_DB: langfuse
    volumes:
      - langfuse-db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U langfuse"]
      interval: 5s
      timeout: 5s
      retries: 10

  langfuse-clickhouse:
    image: clickhouse/clickhouse-server:latest
    container_name: certifai-langfuse-clickhouse
    restart: unless-stopped
    user: "101:101"
    environment:
      CLICKHOUSE_DB: default
      CLICKHOUSE_USER: clickhouse
      CLICKHOUSE_PASSWORD: clickhouse
    ulimits:
      nofile:
        soft: 262144
        hard: 262144
    volumes:
      - langfuse-clickhouse-data:/var/lib/clickhouse
      - langfuse-clickhouse-logs:/var/log/clickhouse-server
    healthcheck:
      test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1"]
      interval: 5s
      timeout: 5s
      retries: 10

  langfuse-redis:
    image: redis:7-alpine
    container_name: certifai-langfuse-redis
    restart: unless-stopped
    command: redis-server --requirepass langfuse-dev-redis
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "langfuse-dev-redis", "ping"]
      interval: 5s
      timeout: 5s
      retries: 10

  langfuse-minio:
    image: cgr.dev/chainguard/minio
    container_name: certifai-langfuse-minio
    restart: unless-stopped
    entrypoint: sh
    command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
    environment:
      MINIO_ROOT_USER: minio
      MINIO_ROOT_PASSWORD: miniosecret
    healthcheck:
      test: ["CMD-SHELL", "mc ready local || exit 1"]
      interval: 5s
      timeout: 5s
      retries: 10

volumes:
  librechat-data:
  langgraph-db-data:
  langfuse-db-data:
  langfuse-clickhouse-data:
  langfuse-clickhouse-logs:
