name: orcheo
# Note: Services using 'env_file: .env' load variables from .env file.
# Environment variables explicitly defined in the 'environment' section take precedence
# over those from env_file. This allows overriding .env values when needed.
services:
  postgres:
    image: postgres:16-alpine
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: ${ORCHEO_POSTGRES_USER:-orcheo}
      POSTGRES_PASSWORD: ${ORCHEO_POSTGRES_PASSWORD:?set ORCHEO_POSTGRES_PASSWORD}
      POSTGRES_DB: ${ORCHEO_POSTGRES_DB:-orcheo}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${ORCHEO_POSTGRES_USER:-orcheo}"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes --appendfsync everysec
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  backend:
    image: ${ORCHEO_STACK_IMAGE:-ghcr.io/shaojiejiang/orcheo-stack:latest}
    env_file: .env
    ports:
      - "8000:8000"
    volumes:
      - orcheo_data:/data
      - ./chatkit_widgets:/app/examples/chatkit_widgets/widgets:ro
    environment:
      REDIS_URL: redis://redis:6379/0
      ORCHEO_POSTGRES_DSN: postgresql://${ORCHEO_POSTGRES_USER}:${ORCHEO_POSTGRES_PASSWORD}@postgres:5432/${ORCHEO_POSTGRES_DB}
      ORCHEO_REPOSITORY_BACKEND: postgres
      ORCHEO_CHECKPOINT_BACKEND: postgres
      ORCHEO_CHATKIT_BACKEND: postgres
      ORCHEO_VAULT_BACKEND: postgres
      ORCHEO_VAULT_ENCRYPTION_KEY: ${ORCHEO_VAULT_ENCRYPTION_KEY:?set ORCHEO_VAULT_ENCRYPTION_KEY}
      ORCHEO_AUTH_SERVICE_TOKEN_BACKEND: postgres
      ORCHEO_AUTH_MODE: ${ORCHEO_AUTH_MODE:-required}
      ORCHEO_AUTH_JWKS_URL: ${ORCHEO_AUTH_JWKS_URL:-}
      ORCHEO_AUTH_AUDIENCE: ${ORCHEO_AUTH_AUDIENCE:-}
      ORCHEO_AUTH_ISSUER: ${ORCHEO_AUTH_ISSUER:-}
      ORCHEO_AUTH_DEV_LOGIN_ENABLED: ${ORCHEO_AUTH_DEV_LOGIN_ENABLED:-false}
      ORCHEO_AUTH_BOOTSTRAP_SERVICE_TOKEN: ${ORCHEO_AUTH_BOOTSTRAP_SERVICE_TOKEN:-}
      ORCHEO_CHATKIT_PUBLIC_BASE_URL: ${ORCHEO_CHATKIT_PUBLIC_BASE_URL:-http://localhost:5173}
      ORCHEO_CORS_ALLOW_ORIGINS: ${ORCHEO_CORS_ALLOW_ORIGINS:-http://localhost:5173,http://127.0.0.1:5173}
      ORCHEO_MCP_STDIO_LOG: /dev/stderr
    depends_on:
      redis:
        condition: service_healthy
      postgres:
        condition: service_healthy
    command: python -m uvicorn orcheo_backend.app:app --host 0.0.0.0 --port 8000

  worker:
    image: ${ORCHEO_STACK_IMAGE:-ghcr.io/shaojiejiang/orcheo-stack:latest}
    env_file: .env
    volumes:
      - orcheo_data:/data
      - ./chatkit_widgets:/app/examples/chatkit_widgets/widgets:ro
    environment:
      REDIS_URL: redis://redis:6379/0
      ORCHEO_POSTGRES_DSN: postgresql://${ORCHEO_POSTGRES_USER}:${ORCHEO_POSTGRES_PASSWORD}@postgres:5432/${ORCHEO_POSTGRES_DB}
      ORCHEO_REPOSITORY_BACKEND: postgres
      ORCHEO_CHECKPOINT_BACKEND: postgres
      ORCHEO_CHATKIT_BACKEND: postgres
      ORCHEO_VAULT_BACKEND: postgres
      ORCHEO_VAULT_ENCRYPTION_KEY: ${ORCHEO_VAULT_ENCRYPTION_KEY:?set ORCHEO_VAULT_ENCRYPTION_KEY}
      ORCHEO_AUTH_SERVICE_TOKEN_BACKEND: postgres
      ORCHEO_AUTH_MODE: ${ORCHEO_AUTH_MODE:-required}
      ORCHEO_AUTH_JWKS_URL: ${ORCHEO_AUTH_JWKS_URL:-}
      ORCHEO_AUTH_AUDIENCE: ${ORCHEO_AUTH_AUDIENCE:-}
      ORCHEO_AUTH_ISSUER: ${ORCHEO_AUTH_ISSUER:-}
      ORCHEO_AUTH_BOOTSTRAP_SERVICE_TOKEN: ${ORCHEO_AUTH_BOOTSTRAP_SERVICE_TOKEN:-}
      ORCHEO_CHATKIT_PUBLIC_BASE_URL: ${ORCHEO_CHATKIT_PUBLIC_BASE_URL:-http://localhost:5173}
      ORCHEO_MCP_STDIO_LOG: /dev/stderr
    depends_on:
      redis:
        condition: service_healthy
      postgres:
        condition: service_healthy
    command: python -m celery -A orcheo_backend.worker.celery_app worker --loglevel=info

  celery-beat:
    image: ${ORCHEO_STACK_IMAGE:-ghcr.io/shaojiejiang/orcheo-stack:latest}
    env_file: .env
    volumes:
      - orcheo_data:/data
      - ./chatkit_widgets:/app/examples/chatkit_widgets/widgets:ro
    environment:
      REDIS_URL: redis://redis:6379/0
      ORCHEO_POSTGRES_DSN: postgresql://${ORCHEO_POSTGRES_USER}:${ORCHEO_POSTGRES_PASSWORD}@postgres:5432/${ORCHEO_POSTGRES_DB}
      ORCHEO_REPOSITORY_BACKEND: postgres
      ORCHEO_CHECKPOINT_BACKEND: postgres
      ORCHEO_CHATKIT_BACKEND: postgres
      ORCHEO_VAULT_BACKEND: postgres
      ORCHEO_VAULT_ENCRYPTION_KEY: ${ORCHEO_VAULT_ENCRYPTION_KEY:?set ORCHEO_VAULT_ENCRYPTION_KEY}
      ORCHEO_AUTH_SERVICE_TOKEN_BACKEND: postgres
      ORCHEO_AUTH_MODE: ${ORCHEO_AUTH_MODE:-required}
      ORCHEO_AUTH_JWKS_URL: ${ORCHEO_AUTH_JWKS_URL:-}
      ORCHEO_AUTH_AUDIENCE: ${ORCHEO_AUTH_AUDIENCE:-}
      ORCHEO_AUTH_ISSUER: ${ORCHEO_AUTH_ISSUER:-}
      ORCHEO_AUTH_BOOTSTRAP_SERVICE_TOKEN: ${ORCHEO_AUTH_BOOTSTRAP_SERVICE_TOKEN:-}
      ORCHEO_CHATKIT_PUBLIC_BASE_URL: ${ORCHEO_CHATKIT_PUBLIC_BASE_URL:-http://localhost:5173}
      ORCHEO_MCP_STDIO_LOG: /dev/stderr
      CELERY_BEAT_SCHEDULE_FILE: /data/celerybeat-schedule
    depends_on:
      redis:
        condition: service_healthy
      postgres:
        condition: service_healthy
    command: >
      sh -c 'python -m celery -A orcheo_backend.worker.celery_app beat --loglevel=info -s "$$CELERY_BEAT_SCHEDULE_FILE"'

  canvas:
    image: node:20-alpine
    working_dir: /app
    env_file: .env
    ports:
      - "5173:5173"
    volumes:
      - canvas_node_modules:/app/node_modules
    environment:
      VITE_ORCHEO_BACKEND_URL: ${VITE_ORCHEO_BACKEND_URL:-http://localhost:8000}
      VITE_ORCHEO_AUTH_ISSUER: ${VITE_ORCHEO_AUTH_ISSUER:-}
      VITE_ORCHEO_AUTH_CLIENT_ID: ${VITE_ORCHEO_AUTH_CLIENT_ID:-}
      VITE_ORCHEO_AUTH_REDIRECT_URI: ${VITE_ORCHEO_AUTH_REDIRECT_URI:-}
      VITE_ORCHEO_AUTH_SCOPES: ${VITE_ORCHEO_AUTH_SCOPES:-openid profile email}
      VITE_ORCHEO_AUTH_AUDIENCE: ${VITE_ORCHEO_AUTH_AUDIENCE:-}
      VITE_ORCHEO_AUTH_ORGANIZATION: ${VITE_ORCHEO_AUTH_ORGANIZATION:-}
      VITE_ORCHEO_AUTH_PROVIDER_PARAM: ${VITE_ORCHEO_AUTH_PROVIDER_PARAM:-}
      VITE_ORCHEO_AUTH_PROVIDER_GOOGLE: ${VITE_ORCHEO_AUTH_PROVIDER_GOOGLE:-}
      VITE_ORCHEO_AUTH_PROVIDER_GITHUB: ${VITE_ORCHEO_AUTH_PROVIDER_GITHUB:-}
      VITE_ORCHEO_CHATKIT_DOMAIN_KEY: ${VITE_ORCHEO_CHATKIT_DOMAIN_KEY:?set VITE_ORCHEO_CHATKIT_DOMAIN_KEY}
      VITE_ALLOWED_HOSTS: ${VITE_ALLOWED_HOSTS:-localhost}
    depends_on:
      - backend
    command: >
      sh -c "npm config set update-notifier false
      && npm config set fund false
      && npm config set audit false
      && npm init -y >/dev/null
      && npm install --silent orcheo-canvas
      && npm --prefix node_modules/orcheo-canvas run dev -- --host 0.0.0.0"
    healthcheck:
      test: ["CMD-SHELL", "node -e \"require('http').get('http://localhost:5173/', r => { r.resume(); process.exit(r.statusCode === 200 ? 0 : 1); }).on('error', () => process.exit(1))\""]
      interval: 15s
      timeout: 5s
      retries: 20
      start_period: 180s

volumes:
  postgres_data:
  redis_data:
  orcheo_data:
  canvas_node_modules:
