services: postgres: image: postgres:16-alpine environment: POSTGRES_USER: tradepilot POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required; set it in .env}" POSTGRES_DB: tradepilot volumes: - tradepilot_postgres:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U tradepilot -d tradepilot"] interval: 5s timeout: 3s retries: 12 restart: unless-stopped security_opt: - no-new-privileges:true db-init: build: context: . target: runner command: ["node", "scripts/init-db.mjs"] environment: NODE_ENV: production PGHOST: postgres PGPORT: "5432" PGUSER: tradepilot PGPASSWORD: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required; set it in .env}" PGDATABASE: tradepilot PGSSLMODE: disable TRADEPILOT_ADMIN_EMAIL: "${TRADEPILOT_ADMIN_EMAIL:?TRADEPILOT_ADMIN_EMAIL is required; set it in .env}" TRADEPILOT_ADMIN_PASSWORD: "${TRADEPILOT_ADMIN_PASSWORD:?TRADEPILOT_ADMIN_PASSWORD is required; set it in .env}" TRADEPILOT_WORKSPACE_SLUG: "${TRADEPILOT_WORKSPACE_SLUG:-tradepilot-admin}" TRADEPILOT_RESET_ADMIN_PASSWORD: "${TRADEPILOT_RESET_ADMIN_PASSWORD:-false}" depends_on: postgres: condition: service_healthy restart: "no" security_opt: - no-new-privileges:true tradepilot: build: context: . target: runner ports: - "${BIND_ADDRESS:-127.0.0.1}:${PORT:-3461}:3456" volumes: - tradepilot_data:/app/data - ./plugins:/app/plugins environment: NODE_ENV: production TRADEPILOT_PORT: "3456" TRADEPILOT_DATA_DIR: /app/data PGHOST: postgres PGPORT: "5432" PGUSER: tradepilot PGPASSWORD: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required; set it in .env}" PGDATABASE: tradepilot PGSSLMODE: disable TRADEPILOT_WORKSPACE_SLUG: "${TRADEPILOT_WORKSPACE_SLUG:-tradepilot-admin}" TRADEPILOT_START_VIDEO_WORKER: "false" AUTH_SECRET: "${AUTH_SECRET:?AUTH_SECRET is required; run bash install.sh or set it in .env}" TRADEPILOT_CONFIG_KEY: "${TRADEPILOT_CONFIG_KEY:-}" METRICS_TOKEN: "${METRICS_TOKEN:-}" TRADEPILOT_TRUSTED_CLIENT_IP_HEADER: "${TRADEPILOT_TRUSTED_CLIENT_IP_HEADER:-}" TRADEPILOT_PROXY_AUTH_SECRET: "${TRADEPILOT_PROXY_AUTH_SECRET:-}" AI_PLATFORM_MONTHLY_REQUEST_LIMIT: "${AI_PLATFORM_MONTHLY_REQUEST_LIMIT:-10000}" AI_PLATFORM_MONTHLY_TOKEN_LIMIT: "${AI_PLATFORM_MONTHLY_TOKEN_LIMIT:-10000000}" FIRECRAWL_TENANT_DAILY_REQUEST_LIMIT: "${FIRECRAWL_TENANT_DAILY_REQUEST_LIMIT:-20}" TRADEPILOT_MAIL_PRIVATE_ALLOWLIST: "${TRADEPILOT_MAIL_PRIVATE_ALLOWLIST:-}" MARKETING_POLICY_VERSION: "${MARKETING_POLICY_VERSION:-2026-10-07}" STRIPE_SECRET_KEY: "${STRIPE_SECRET_KEY:-}" STRIPE_WEBHOOK_SECRET: "${STRIPE_WEBHOOK_SECRET:-}" TRADEPILOT_MEDIA_MAX_BYTES: "${TRADEPILOT_MEDIA_MAX_BYTES:-104857600}" S3_BUCKET: "${S3_BUCKET:-}" S3_REGION: "${S3_REGION:-auto}" S3_ENDPOINT: "${S3_ENDPOINT:-}" S3_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-}" S3_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-}" S3_FORCE_PATH_STYLE: "${S3_FORCE_PATH_STYLE:-false}" S3_SERVER_SIDE_ENCRYPTION: "${S3_SERVER_SIDE_ENCRYPTION:-}" OPENAI_API_KEY: "${OPENAI_API_KEY:-}" OPENAI_REALTIME_MODEL: "${OPENAI_REALTIME_MODEL:-gpt-realtime}" OPENAI_REALTIME_VOICE: "${OPENAI_REALTIME_VOICE:-marin}" OPENAI_TRANSCRIPTION_MODEL: "${OPENAI_TRANSCRIPTION_MODEL:-gpt-4o-mini-transcribe}" MONEYPRINTERTURBO_API_KEY: "${MONEYPRINTERTURBO_API_KEY:-}" AUTH_URL: "${AUTH_URL:-http://localhost:3461}" TRADEPILOT_ADMIN_EMAIL: "${TRADEPILOT_ADMIN_EMAIL:?TRADEPILOT_ADMIN_EMAIL is required; run bash install.sh or set it in .env}" TRADEPILOT_ADMIN_PASSWORD: "${TRADEPILOT_ADMIN_PASSWORD:?TRADEPILOT_ADMIN_PASSWORD is required; run bash install.sh or set it in .env}" TRADEPILOT_SELF_REGISTRATION: "${TRADEPILOT_SELF_REGISTRATION:-false}" OPENMONTAGE_WORKER_URL: http://video-worker:8787 MONEYPRINTERTURBO_URL: http://moneyprinterturbo:8080 FIRECRAWL_API_URL: "${FIRECRAWL_API_URL:-}" FIRECRAWL_API_KEY: "${FIRECRAWL_API_KEY:-}" LIVEKIT_URL: "${LIVEKIT_URL:-}" LIVEKIT_API_KEY: "${LIVEKIT_API_KEY:-}" LIVEKIT_API_SECRET: "${LIVEKIT_API_SECRET:-}" LIVEKIT_AGENT_NAME: "${LIVEKIT_AGENT_NAME:-tradepilot-customer-service}" depends_on: db-init: condition: service_completed_successfully healthcheck: test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3456/api/health/ready').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"] interval: 30s timeout: 10s retries: 3 start_period: 30s restart: unless-stopped security_opt: - no-new-privileges:true livekit-agent: profiles: ["voice"] build: context: ./agents/customer-service volumes: - tradepilot_data:/app/data:ro environment: TRADEPILOT_DATA_DIR: /app/data TRADEPILOT_CONFIG_KEY: "${TRADEPILOT_CONFIG_KEY:-${AUTH_SECRET}}" LIVEKIT_URL: "${LIVEKIT_URL:-}" LIVEKIT_API_KEY: "${LIVEKIT_API_KEY:-}" LIVEKIT_API_SECRET: "${LIVEKIT_API_SECRET:-}" LIVEKIT_AGENT_NAME: "${LIVEKIT_AGENT_NAME:-tradepilot-customer-service}" OPENAI_API_KEY: "${OPENAI_API_KEY:-}" OPENAI_REALTIME_MODEL: "${OPENAI_REALTIME_MODEL:-gpt-realtime}" OPENAI_REALTIME_VOICE: "${OPENAI_REALTIME_VOICE:-marin}" OPENAI_TRANSCRIPTION_MODEL: "${OPENAI_TRANSCRIPTION_MODEL:-gpt-4o-mini-transcribe}" init: true restart: unless-stopped stop_grace_period: 60s security_opt: - no-new-privileges:true video-worker: build: context: . target: runner command: ["node", "workers/openmontage-adapter/server.mjs"] expose: - "8787" volumes: - video_worker_data:/app/openmontage-workspace environment: OPENMONTAGE_ADAPTER_PORT: "8787" OPENMONTAGE_ADAPTER_HOST: "0.0.0.0" OPENMONTAGE_WORKSPACE: /app/openmontage-workspace OPENMONTAGE_PUBLIC_URL: http://video-worker:8787 healthcheck: test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8787/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"] interval: 5s timeout: 3s retries: 12 restart: unless-stopped security_opt: - no-new-privileges:true moneyprinterturbo: image: ghcr.io/harry0703/moneyprinterturbo:v1.3.2 command: ["python3", "main.py"] expose: - "8080" volumes: - ./deploy/moneyprinterturbo/config.toml:/MoneyPrinterTurbo/config.toml:ro - moneyprinterturbo_storage:/MoneyPrinterTurbo/storage depends_on: redis: condition: service_healthy healthcheck: test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/api/v1/tasks?page=1&page_size=1', timeout=3)"] interval: 10s timeout: 5s retries: 18 start_period: 20s restart: unless-stopped security_opt: - no-new-privileges:true redis: image: public.ecr.aws/docker/library/redis:7.4-alpine command: ["redis-server", "--appendonly", "yes", "--requirepass", "tradepilot-video"] expose: - "6379" volumes: - moneyprinterturbo_redis:/data healthcheck: test: ["CMD", "redis-cli", "-a", "tradepilot-video", "ping"] interval: 5s timeout: 3s retries: 12 restart: unless-stopped security_opt: - no-new-privileges:true volumes: tradepilot_postgres: tradepilot_data: video_worker_data: moneyprinterturbo_storage: moneyprinterturbo_redis: