services: postgres: image: postgres:16-alpine environment: POSTGRES_DB: lumibase POSTGRES_USER: lumibase POSTGRES_PASSWORD: lumibase_dev ports: - "${POSTGRES_PORT:-5432}:5432" volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U lumibase"] interval: 5s timeout: 3s retries: 5 redis: image: redis:7-alpine ports: - "${REDIS_PORT:-6379}:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 minio: image: minio/minio:latest command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin ports: - "${MINIO_API_PORT:-9000}:9000" - "${MINIO_CONSOLE_PORT:-9001}:9001" volumes: - miniodata:/data healthcheck: test: ["CMD", "mc", "ready", "local"] interval: 5s timeout: 3s retries: 5 minio-init: image: minio/mc:latest depends_on: minio: condition: service_healthy entrypoint: > /bin/sh -c " mc alias set local http://minio:9000 minioadmin minioadmin && mc mb --ignore-existing local/lumibase-media " meilisearch: image: getmeili/meilisearch:v1.7 environment: MEILI_MASTER_KEY: lumibase_dev_key MEILI_ENV: development ports: - "${MEILISEARCH_PORT:-7700}:7700" volumes: - meilidata:/meili_data healthcheck: test: ["CMD", "wget", "--no-verbose", "--spider", "http://127.0.0.1:7700/health"] interval: 5s timeout: 3s retries: 5 imgproxy: image: darthsim/imgproxy:latest environment: IMGPROXY_KEY: ${IMGPROXY_KEY:-736563726574} IMGPROXY_SALT: ${IMGPROXY_SALT:-736563726574} IMGPROXY_USE_S3: "true" AWS_ACCESS_KEY_ID: minioadmin AWS_SECRET_ACCESS_KEY: minioadmin IMGPROXY_S3_ENDPOINT: http://minio:9000 ports: - "${IMGPROXY_PORT:-8080}:8080" depends_on: minio: condition: service_healthy cms: build: context: .. dockerfile: docker/Dockerfile.dev environment: LUMIBASE_RUNTIME: docker LUMIBASE_PROCESS_ROLE: ${LUMIBASE_PROCESS_ROLE:-all} DATABASE_URL: postgresql://lumibase:lumibase_dev@postgres:5432/lumibase REDIS_URL: redis://redis:6379 S3_ENDPOINT: http://minio:9000 S3_ACCESS_KEY: minioadmin S3_SECRET_KEY: minioadmin S3_BUCKET: lumibase-media MEILISEARCH_HOST: http://meilisearch:7700 MEILISEARCH_API_KEY: lumibase_dev_key IMGPROXY_URL: http://imgproxy:8080 IMGPROXY_KEY: "736563726574" IMGPROXY_SALT: "736563726574" PORT: "1989" # LLM provider for local testing. Defaults to the no-LLM echo provider; # set LLM_PROVIDER=gemini + GEMINI_API_KEY in docker/.env to exercise the # real Gemini path locally before deploying. LLM_PROVIDER: ${LLM_PROVIDER:-echo} LLM_MODEL: ${LLM_MODEL:-} GEMINI_API_KEY: ${GEMINI_API_KEY:-} # Decision model for POST /api/ai/decisions (TypeSafe Jev). Unset = off. DECISION_PROVIDER: ${DECISION_PROVIDER:-} DECISION_MODEL: ${DECISION_MODEL:-} TYPESAFE_API_KEY: ${TYPESAFE_API_KEY:-} TYPESAFE_BASE_URL: ${TYPESAFE_BASE_URL:-} OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-} DECISION_TIMEOUT_MS: ${DECISION_TIMEOUT_MS:-} DECISION_ATTEMPT_TIMEOUT_MS: ${DECISION_ATTEMPT_TIMEOUT_MS:-} DECISION_MAX_RETRIES: ${DECISION_MAX_RETRIES:-} DECISION_MAX_INPUT_BYTES: ${DECISION_MAX_INPUT_BYTES:-} DECISION_MAX_INPUT_TOKENS: ${DECISION_MAX_INPUT_TOKENS:-} DECISION_LLM_MAX_OUTPUT_TOKENS: ${DECISION_LLM_MAX_OUTPUT_TOKENS:-} DECISION_LLM_THINKING_TOKENS: ${DECISION_LLM_THINKING_TOKENS:-} DECISION_SITE_REQUESTS_PER_HOUR: ${DECISION_SITE_REQUESTS_PER_HOUR:-} DECISION_SITE_MAX_CONCURRENT: ${DECISION_SITE_MAX_CONCURRENT:-} DECISION_SITE_TOKENS_PER_DAY: ${DECISION_SITE_TOKENS_PER_DAY:-} DECISION_REVIEW_RETENTION_DAYS: ${DECISION_REVIEW_RETENTION_DAYS:-} # #564: refused-decision audit dedup window (s) and /api/v1/ai/* per-IP limit (req/min). DECISION_REFUSAL_AUDIT_WINDOW_SECONDS: ${DECISION_REFUSAL_AUDIT_WINDOW_SECONDS:-} LUMIBASE_AI_IP_RATE_LIMIT: ${LUMIBASE_AI_IP_RATE_LIMIT:-} ports: - "${CMS_PORT:-1989}:1989" volumes: - ../apps/cms/src:/app/apps/cms/src - ../packages:/app/packages depends_on: postgres: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy minio-init: condition: service_completed_successfully meilisearch: condition: service_healthy # Scale-out profile (high-load-cache-readiness task 16.3): HTTP replicas + worker. # Usage: docker compose --profile split up -d cms-web cms-worker cms-web: profiles: ["split"] extends: service: cms environment: LUMIBASE_PROCESS_ROLE: web ports: - "${CMS_PORT:-1989}:1989" cms-worker: profiles: ["split"] extends: service: cms environment: LUMIBASE_PROCESS_ROLE: worker LUMIBASE_WORKER_HEALTH_PORT: "1988" ports: !reset - "${CMS_WORKER_HEALTH_PORT:-1988}:1988" bull-board: image: deadly0/bull-board:latest environment: REDIS_HOST: redis REDIS_PORT: "6379" ports: - "${BULL_BOARD_PORT:-3001}:3000" depends_on: redis: condition: service_healthy volumes: pgdata: miniodata: meilidata: