services: db: image: timescale/timescaledb:latest-pg17-oss environment: POSTGRES_DB: tokhub POSTGRES_USER: tokhub POSTGRES_PASSWORD: tokhub volumes: - tokhub-db:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U tokhub -d tokhub"] interval: 5s timeout: 5s retries: 20 redis: image: redis:8-alpine volumes: - tokhub-redis:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 20 nats: image: nats:2-alpine command: ["-js", "-sd", "/data", "-m", "8222"] volumes: - tokhub-nats:/data healthcheck: test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:8222/healthz"] interval: 5s timeout: 3s retries: 20 deepseek-web-bridge: profiles: ["lab"] image: ghcr.io/cjackhwang/ds2api:v4.6.1@sha256:afa05fa8d4f7ee886d11798a8c573f9df0aff8b12f9ac2635f8efd2ce7b55232 restart: unless-stopped environment: PORT: "5001" LOG_LEVEL: WARN DS2API_ADMIN_KEY: ${TOKHUB_DEEPSEEK_WEB_BRIDGE_ADMIN_KEY:-dev-only-change-deepseek-bridge-admin-key} DS2API_CONFIG_JSON: >- {"keys":[],"accounts":[],"runtime":{"account_max_inflight":1,"account_max_queue":1,"global_max_inflight":1},"auto_delete":{"mode":"single"},"current_input_file":{"enabled":false}} DS2API_ENV_WRITEBACK: "0" read_only: true tmpfs: - /tmp:rw,noexec,nosuid,size=64m,mode=1777 - /app/data:rw,noexec,nosuid,size=64m,mode=1777 cap_drop: - ALL security_opt: - no-new-privileges:true networks: - deepseek-bridge healthcheck: test: ["CMD", "/usr/local/bin/busybox", "wget", "-qO-", "http://localhost:5001/healthz"] interval: 10s timeout: 5s retries: 12 migrate: build: . environment: TOKHUB_ROLE: migrate TOKHUB_ENV: ${TOKHUB_ENV:-development} DATABASE_URL: postgres://tokhub:tokhub@db:5432/tokhub?sslmode=disable depends_on: db: condition: service_healthy restart: "no" seed: build: . environment: TOKHUB_ROLE: seed TOKHUB_ENV: ${TOKHUB_ENV:-development} TOKHUB_PUBLIC_URL: ${TOKHUB_PUBLIC_URL:-http://localhost:8080} TOKHUB_ADMIN_EMAIL: ${TOKHUB_ADMIN_EMAIL:-admin@tokhub.local} TOKHUB_ADMIN_USERNAME: ${TOKHUB_ADMIN_USERNAME:-admin} TOKHUB_ADMIN_PASSWORD: ${TOKHUB_ADMIN_PASSWORD:-admin@tokhub.local} TOKHUB_SECRET_KEY: ${TOKHUB_SECRET_KEY:-dev-only-change-this-secret-key-32b} TOKHUB_CREDENTIAL_ACTIVE_KEY_ID: ${TOKHUB_CREDENTIAL_ACTIVE_KEY_ID:-legacy-v1} TOKHUB_CREDENTIAL_ENCRYPTION_KEYS: ${TOKHUB_CREDENTIAL_ENCRYPTION_KEYS:-} TOKHUB_CREDENTIAL_ACTIVE_FINGERPRINT_KEY_ID: ${TOKHUB_CREDENTIAL_ACTIVE_FINGERPRINT_KEY_ID:-legacy-v1} TOKHUB_CREDENTIAL_FINGERPRINT_KEYS: ${TOKHUB_CREDENTIAL_FINGERPRINT_KEYS:-} TOKHUB_SEED_MODE: ${TOKHUB_SEED_MODE:-prod} TOKHUB_UPSTREAM_MODE: ${TOKHUB_UPSTREAM_MODE:-mock} TOKHUB_SESSION_SECURE: ${TOKHUB_SESSION_SECURE:-false} TOKHUB_REGISTRATION_OPEN: ${TOKHUB_REGISTRATION_OPEN:-true} TOKHUB_EXPOSE_DEV_TOKENS: ${TOKHUB_EXPOSE_DEV_TOKENS:-} DATABASE_URL: postgres://tokhub:tokhub@db:5432/tokhub?sslmode=disable depends_on: migrate: condition: service_completed_successfully restart: "no" app: build: . environment: TOKHUB_ROLE: all TOKHUB_ENV: ${TOKHUB_ENV:-development} TOKHUB_PUBLIC_URL: ${TOKHUB_PUBLIC_URL:-http://localhost:8080} TOKHUB_ADMIN_EMAIL: ${TOKHUB_ADMIN_EMAIL:-admin@tokhub.local} TOKHUB_ADMIN_USERNAME: ${TOKHUB_ADMIN_USERNAME:-admin} TOKHUB_SECRET_KEY: ${TOKHUB_SECRET_KEY:-dev-only-change-this-secret-key-32b} TOKHUB_CREDENTIAL_ACTIVE_KEY_ID: ${TOKHUB_CREDENTIAL_ACTIVE_KEY_ID:-legacy-v1} TOKHUB_CREDENTIAL_ENCRYPTION_KEYS: ${TOKHUB_CREDENTIAL_ENCRYPTION_KEYS:-} TOKHUB_CREDENTIAL_ACTIVE_FINGERPRINT_KEY_ID: ${TOKHUB_CREDENTIAL_ACTIVE_FINGERPRINT_KEY_ID:-legacy-v1} TOKHUB_CREDENTIAL_FINGERPRINT_KEYS: ${TOKHUB_CREDENTIAL_FINGERPRINT_KEYS:-} TOKHUB_SEED_MODE: ${TOKHUB_SEED_MODE:-prod} TOKHUB_UPSTREAM_MODE: ${TOKHUB_UPSTREAM_MODE:-mock} TOKHUB_SESSION_SECURE: ${TOKHUB_SESSION_SECURE:-false} TOKHUB_REGISTRATION_OPEN: ${TOKHUB_REGISTRATION_OPEN:-true} TOKHUB_EXPOSE_DEV_TOKENS: ${TOKHUB_EXPOSE_DEV_TOKENS:-} DATABASE_URL: postgres://tokhub:tokhub@db:5432/tokhub?sslmode=disable REDIS_URL: redis://redis:6379/0 NATS_URL: nats://nats:4222 SMTP_URL: ${SMTP_URL:-} TOKHUB_AI_WEB_AUTH_ENABLED: ${TOKHUB_AI_WEB_AUTH_ENABLED:-false} TOKHUB_AI_LAB_MODE: ${TOKHUB_AI_LAB_MODE:-false} TOKHUB_AI_OFFICIAL_CLIENT_ENABLED: ${TOKHUB_AI_OFFICIAL_CLIENT_ENABLED:-false} TOKHUB_AI_OFFICIAL_CLIENT_TASK_TIMEOUT: ${TOKHUB_AI_OFFICIAL_CLIENT_TASK_TIMEOUT:-3m} TOKHUB_AI_OFFICIAL_CLIENT_TRUSTED_PROXY_CIDRS: ${TOKHUB_AI_OFFICIAL_CLIENT_TRUSTED_PROXY_CIDRS:-} TOKHUB_AI_OPENAI_KILL_SWITCH: ${TOKHUB_AI_OPENAI_KILL_SWITCH:-false} TOKHUB_AI_GEMINI_KILL_SWITCH: ${TOKHUB_AI_GEMINI_KILL_SWITCH:-false} TOKHUB_AI_DEEPSEEK_KILL_SWITCH: ${TOKHUB_AI_DEEPSEEK_KILL_SWITCH:-false} TOKHUB_AI_GROK_KILL_SWITCH: ${TOKHUB_AI_GROK_KILL_SWITCH:-false} TOKHUB_AI_OPENAI_TERMS_DIGEST: ${TOKHUB_AI_OPENAI_TERMS_DIGEST:-} TOKHUB_AI_GEMINI_TERMS_DIGEST: ${TOKHUB_AI_GEMINI_TERMS_DIGEST:-} TOKHUB_AI_DEEPSEEK_TERMS_DIGEST: ${TOKHUB_AI_DEEPSEEK_TERMS_DIGEST:-} TOKHUB_AI_GROK_TERMS_DIGEST: ${TOKHUB_AI_GROK_TERMS_DIGEST:-} TOKHUB_AI_GEMINI_OAUTH_ENABLED: ${TOKHUB_AI_GEMINI_OAUTH_ENABLED:-false} TOKHUB_AI_DEEPSEEK_GUIDED_ENABLED: ${TOKHUB_AI_DEEPSEEK_GUIDED_ENABLED:-true} TOKHUB_AI_DEEPSEEK_WEB_EXPERIMENTAL: ${TOKHUB_AI_DEEPSEEK_WEB_EXPERIMENTAL:-false} TOKHUB_AI_DEEPSEEK_WEB_BRIDGE_URL: ${TOKHUB_AI_DEEPSEEK_WEB_BRIDGE_URL:-http://deepseek-web-bridge:5001} TOKHUB_AI_DEEPSEEK_WEB_ACK: ${TOKHUB_AI_DEEPSEEK_WEB_ACK:-} TOKHUB_AI_OPENCLI_BROWSER_EXPERIMENTAL: ${TOKHUB_AI_OPENCLI_BROWSER_EXPERIMENTAL:-false} TOKHUB_AI_OPENCLI_BROWSER_ACK: ${TOKHUB_AI_OPENCLI_BROWSER_ACK:-} TOKHUB_AI_OPENCLI_BROWSER_TASK_TIMEOUT: ${TOKHUB_AI_OPENCLI_BROWSER_TASK_TIMEOUT:-2m} TOKHUB_AI_OPENCLI_CHATGPT_ENABLED: ${TOKHUB_AI_OPENCLI_CHATGPT_ENABLED:-true} TOKHUB_AI_OPENCLI_GEMINI_ENABLED: ${TOKHUB_AI_OPENCLI_GEMINI_ENABLED:-true} TOKHUB_AI_OPENCLI_DEEPSEEK_ENABLED: ${TOKHUB_AI_OPENCLI_DEEPSEEK_ENABLED:-true} TOKHUB_AI_OPENCLI_CHATGPT_MIN_INTERVAL: ${TOKHUB_AI_OPENCLI_CHATGPT_MIN_INTERVAL:-10s} TOKHUB_AI_OPENCLI_GEMINI_MIN_INTERVAL: ${TOKHUB_AI_OPENCLI_GEMINI_MIN_INTERVAL:-10s} TOKHUB_AI_OPENCLI_DEEPSEEK_MIN_INTERVAL: ${TOKHUB_AI_OPENCLI_DEEPSEEK_MIN_INTERVAL:-15s} TOKHUB_AI_OPENCLI_CHATGPT_HOURLY_LIMIT: ${TOKHUB_AI_OPENCLI_CHATGPT_HOURLY_LIMIT:-30} TOKHUB_AI_OPENCLI_GEMINI_HOURLY_LIMIT: ${TOKHUB_AI_OPENCLI_GEMINI_HOURLY_LIMIT:-30} TOKHUB_AI_OPENCLI_DEEPSEEK_HOURLY_LIMIT: ${TOKHUB_AI_OPENCLI_DEEPSEEK_HOURLY_LIMIT:-20} TOKHUB_AI_OPENCLI_CHATGPT_DAILY_LIMIT: ${TOKHUB_AI_OPENCLI_CHATGPT_DAILY_LIMIT:-120} TOKHUB_AI_OPENCLI_GEMINI_DAILY_LIMIT: ${TOKHUB_AI_OPENCLI_GEMINI_DAILY_LIMIT:-120} TOKHUB_AI_OPENCLI_DEEPSEEK_DAILY_LIMIT: ${TOKHUB_AI_OPENCLI_DEEPSEEK_DAILY_LIMIT:-80} TOKHUB_AI_CHATGPT_CODEX_EXPERIMENTAL: ${TOKHUB_AI_CHATGPT_CODEX_EXPERIMENTAL:-false} TOKHUB_AI_OAUTH_TTL: ${TOKHUB_AI_OAUTH_TTL:-10m} TOKHUB_AI_OAUTH_REFRESH_SKEW: ${TOKHUB_AI_OAUTH_REFRESH_SKEW:-5m} TOKHUB_AI_OAUTH_REFRESH_WORKERS: ${TOKHUB_AI_OAUTH_REFRESH_WORKERS:-8} TOKHUB_AI_OAUTH_PROVIDER_CONCURRENCY: ${TOKHUB_AI_OAUTH_PROVIDER_CONCURRENCY:-4} TOKHUB_AI_OAUTH_PROVIDER_QPS: ${TOKHUB_AI_OAUTH_PROVIDER_QPS:-2} TOKHUB_AI_OAUTH_REFRESH_ATTEMPT_TIMEOUT: ${TOKHUB_AI_OAUTH_REFRESH_ATTEMPT_TIMEOUT:-20s} TOKHUB_GOOGLE_OAUTH_CLIENT_ID: ${TOKHUB_GOOGLE_OAUTH_CLIENT_ID:-} TOKHUB_GOOGLE_OAUTH_CLIENT_SECRET: ${TOKHUB_GOOGLE_OAUTH_CLIENT_SECRET:-} TOKHUB_GOOGLE_OAUTH_PROJECT_ID: ${TOKHUB_GOOGLE_OAUTH_PROJECT_ID:-} TOKHUB_AI_EXPERIMENTAL_BRIDGE_ACK: ${TOKHUB_AI_EXPERIMENTAL_BRIDGE_ACK:-} ports: - "${TOKHUB_HOST_PORT:-8080}:8080" networks: - default - deepseek-bridge depends_on: db: condition: service_healthy redis: condition: service_healthy nats: condition: service_healthy seed: condition: service_completed_successfully healthcheck: test: ["CMD", "/app/tokhub", "healthcheck"] interval: 10s timeout: 5s retries: 20 volumes: tokhub-db: tokhub-redis: tokhub-nats: networks: deepseek-bridge: