services: postgres: image: pgvector/pgvector:pg17 container_name: afw-postgres environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - "0.0.0.0:5432:5432" volumes: - ./postgres_data:/var/lib/postgresql/data restart: unless-stopped backend: build: context: ./backend dockerfile: Dockerfile.dev container_name: afw-backend extra_hosts: - "host.docker.internal:host-gateway" environment: - DB_HOST=postgres - DB_PORT=5432 - DB_USER=${DB_USER} - DB_PASSWORD=${DB_PASSWORD} - DB_USERS=ai_gateway_users - DB_DATA=ai_gateway_data - DB_LOGS=ai_gateway_logs - LOG_STORE_DRIVER=postgresql - LOG_PG_HOST=postgres - LOG_PG_PORT=5432 - LOG_PG_USER=${LOG_PG_USER} - LOG_PG_PASSWORD=${LOG_PG_PASSWORD} - LOG_PG_DB=ai_gateway_logs - JWT_SECRET=${JWT_SECRET} - JWT_ACCESS_EXPIRES=15m - JWT_REFRESH_EXPIRES=7d - PORT=3635 - NODE_ENV=development - ADMIN_USERNAME=${ADMIN_USERNAME} - ADMIN_EMAIL=${ADMIN_EMAIL} - ADMIN_PASSWORD=${ADMIN_PASSWORD} - GATEWAY_API_KEY_GRACE_PERIOD=${GATEWAY_API_KEY_GRACE_PERIOD:-86400} - PLATFORM_KEY_SECRET=${PLATFORM_KEY_SECRET} - NODE_TLS_REJECT_UNAUTHORIZED=0 - SSRF_PRIVATE_ALLOWED=true volumes: - ./backend:/app - /app/node_modules healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--timeout=5", "http://127.0.0.1:3635/health", "-O", "/dev/null"] interval: 15s timeout: 5s retries: 5 start_period: 60s restart: unless-stopped frontend: build: context: ./frontend dockerfile: Dockerfile.dev container_name: afw-frontend environment: - VITE_BACKEND_URL=http://backend:3635 - VITE_BUILD_TYPE=development volumes: - ./frontend:/app - /app/node_modules restart: unless-stopped nginx: image: nginx:alpine container_name: afw-nginx ports: - "3634:3634" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: frontend: condition: service_started backend: condition: service_healthy restart: unless-stopped gateway-engine: build: context: ./gateway-engine dockerfile: Dockerfile container_name: afw-gateway ports: - "8082:8082" environment: - LOG_PG_HOST=postgres - LOG_PG_PORT=${LOG_PG_PORT:-5432} - LOG_PG_USER=${LOG_PG_USER} - LOG_PG_PASSWORD=${LOG_PG_PASSWORD} - LOG_PG_DB=ai_gateway_logs - DATA_PG_HOST=postgres - DATA_PG_PORT=${DATA_PG_PORT:-5432} - DATA_PG_USER=${DATA_PG_USER} - DATA_PG_PASSWORD=${DATA_PG_PASSWORD} - DATA_PG_DB=ai_gateway_data # Decrypts provider/embedding API keys and encrypts sensitive log fields at rest (must match backend's value) - PLATFORM_KEY_SECRET=${PLATFORM_KEY_SECRET} - RATE_LIMIT_RPM=${RATE_LIMIT_RPM} # Pre-auth per-IP rate limit (requests/min); default 300. Applies before body read. - PREAUTH_RATE_LIMIT_RPM=${PREAUTH_RATE_LIMIT_RPM:-300} # Trusted reverse-proxy hops for X-Forwarded-For; 0 = use TCP socket addr (default). - TRUSTED_PROXY_DEPTH=${TRUSTED_PROXY_DEPTH:-1} # CIDR(s) of trusted reverse proxies (comma-separated); required for XFF to be honored. - TRUSTED_PROXY_IPS=${TRUSTED_PROXY_IPS:-172.16.0.0/12} # Fail-closed scanning: true = block on embedding/classifier errors; default false. - SCAN_FAIL_CLOSED=${SCAN_FAIL_CLOSED:-false} # Allow private IPs for upstream providers in dev (dev/test only — not for production) - SSRF_PRIVATE_ALLOWED=${SSRF_PRIVATE_ALLOWED:-true} - GATEWAY_INSTANCE_ID=${GATEWAY_INSTANCE_ID} # Response cache — deploy-time ceilings (see response_cache_config in the console # for the admin-tunable on/off + exact/semantic toggles). Master kill switch is # RESPONSE_CACHE_ENABLED — if false here, no amount of console/app toggling can # enable caching (see semantic_caching.md). - RESPONSE_CACHE_ENABLED=${RESPONSE_CACHE_ENABLED:-false} - RESPONSE_CACHE_MAX_TTL_SECONDS=${RESPONSE_CACHE_MAX_TTL_SECONDS:-900} - RESPONSE_CACHE_DEFAULT_TTL_SECONDS=${RESPONSE_CACHE_DEFAULT_TTL_SECONDS:-300} - RESPONSE_CACHE_CLEANUP_INTERVAL_SECONDS=${RESPONSE_CACHE_CLEANUP_INTERVAL_SECONDS:-120} - RESPONSE_CACHE_LOOKUP_TIMEOUT_MS=${RESPONSE_CACHE_LOOKUP_TIMEOUT_MS:-50} # Observability (opt-in — set OTEL_ENABLED=true to export traces/logs) - OTEL_ENABLED=${OTEL_ENABLED:-false} - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://otel-collector:4317} - OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-gateway-engine} - OTEL_TRACES_SAMPLER=${OTEL_TRACES_SAMPLER:-parentbased_traceidratio} - OTEL_TRACES_SAMPLER_ARG=${OTEL_TRACES_SAMPLER_ARG:-0.1} - DEPLOYMENT_ENV=${DEPLOYMENT_ENV:-docker} - RUST_LOG=${RUST_LOG:-info} ulimits: nofile: soft: 65536 hard: 65536 deploy: resources: limits: cpus: '4' memory: 512M reservations: cpus: '0.5' memory: 64M healthcheck: test: ["CMD", "curl", "-sf", "http://localhost:8082/health"] interval: 15s timeout: 5s retries: 3 start_period: 10s restart: unless-stopped volumes: postgres_data: