services: db: image: pgvector/pgvector:pg16 restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER:-glycemicgpt} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-glycemicgpt} POSTGRES_DB: ${POSTGRES_DB:-glycemicgpt} volumes: - postgres_data:/var/lib/postgresql/data ports: # Loopback-only: reachable from host dev tools, never from the LAN. # Override the bind host via env if you need remote access. - "${DB_BIND_HOST:-127.0.0.1}:5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-glycemicgpt}"] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine restart: unless-stopped # Optional auth (off by default for local dev). Set REDIS_PASSWORD to # require it; mirrors docker-compose.prod.yml. command: > sh -c '[ -n "$$REDIS_PASSWORD" ] && exec redis-server --requirepass "$$REDIS_PASSWORD" || exec redis-server' environment: REDIS_PASSWORD: ${REDIS_PASSWORD:-} ports: # Loopback-only: reachable from host dev tools, never from the LAN. - "${REDIS_BIND_HOST:-127.0.0.1}:6379:6379" volumes: - redis_data:/data healthcheck: # Only authenticate when a password is set; an empty REDISCLI_AUTH makes # redis-cli attempt AUTH against a passwordless server (noisy stderr). test: ["CMD-SHELL", "if [ -n \"$$REDIS_PASSWORD\" ]; then export REDISCLI_AUTH=\"$$REDIS_PASSWORD\"; fi; redis-cli ping | grep -q PONG"] interval: 10s timeout: 5s retries: 5 ai-sidecar: build: context: ./sidecar dockerfile: Dockerfile restart: unless-stopped volumes: - sidecar_auth:/home/sidecar/.config - sidecar_codex:/home/sidecar/.codex environment: LOG_LEVEL: ${LOG_LEVEL:-info} SIDECAR_API_KEY: ${SIDECAR_API_KEY:-} # Dev-only escape hatch: lets the sidecar start with an empty key since # it is not published to the host here. Production templates require a # key; setting SIDECAR_API_KEY above enforces auth regardless of this. SIDECAR_ALLOW_UNAUTHENTICATED: ${SIDECAR_ALLOW_UNAUTHENTICATED:-true} # Sentry error monitoring (own project) -- empty default = disabled. # Runtime-only; never baked into the image (see PRIVACY.md). GLYCEMICGPT_SIDECAR_SENTRY_DSN: ${GLYCEMICGPT_SIDECAR_SENTRY_DSN:-} GLYCEMICGPT_SIDECAR_SENTRY_ENVIRONMENT: ${GLYCEMICGPT_SIDECAR_SENTRY_ENVIRONMENT:-development} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3456/health"] interval: 15s timeout: 5s retries: 3 start_period: 10s # Not exposed to host — only reachable by api on the internal network api: build: context: ./apps/api dockerfile: Dockerfile # The Medtronic Connect desktop-helper Go binaries are cross-compiled in # a builder stage and baked into the image; the helper sources live at # repo root so we expose them as an additional build context here. See # apps/api/Dockerfile (FROM golang:1.26 AS connect-helper-builder). additional_contexts: helper-src: ./tools/connect-helper restart: unless-stopped ports: - "8000:8000" environment: DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-glycemicgpt}:${POSTGRES_PASSWORD:-glycemicgpt}@db:5432/${POSTGRES_DB:-glycemicgpt} # When REDIS_PASSWORD is set, override REDIS_URL in .env: # REDIS_URL=redis://:@redis:6379/0 REDIS_URL: ${REDIS_URL:-redis://redis:6379/0} LOG_FORMAT: ${LOG_FORMAT:-json} SECRET_KEY: ${SECRET_KEY:-change-me-in-production} AI_SIDECAR_URL: http://ai-sidecar:3456 AI_SIDECAR_API_KEY: ${SIDECAR_API_KEY:-} CORS_ORIGINS: ${CORS_ORIGINS:-["http://localhost:3000"]} FASTEMBED_CACHE_PATH: /app/.cache/fastembed # Meal-photo carb estimation -- BETA, off by default. Requires a # vision-capable AI provider. MEAL_INTELLIGENCE_ENABLED: ${MEAL_INTELLIGENCE_ENABLED:-false} # Sentry error monitoring (Sentry for Good) -- empty default = disabled. # Set only in the project's own dev/CI/staging; never in a distributed build. GLYCEMICGPT_SENTRY_DSN: ${GLYCEMICGPT_SENTRY_DSN:-} GLYCEMICGPT_SENTRY_ENVIRONMENT: ${GLYCEMICGPT_SENTRY_ENVIRONMENT:-development} volumes: - embedding_cache:/app/.cache/fastembed # Private, owner-scoped meal-photo storage. Never web-served. - food_uploads:/uploads depends_on: db: condition: service_healthy redis: condition: service_healthy ai-sidecar: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s web: build: context: ./apps/web dockerfile: Dockerfile restart: unless-stopped ports: - "3000:3000" environment: API_URL: http://api:8000 # Sentry error monitoring (own project, SERVER-SIDE only) -- empty = disabled. # Runtime-only; never baked into the image or browser bundle (see PRIVACY.md). GLYCEMICGPT_WEB_SENTRY_DSN: ${GLYCEMICGPT_WEB_SENTRY_DSN:-} GLYCEMICGPT_WEB_SENTRY_ENVIRONMENT: ${GLYCEMICGPT_WEB_SENTRY_ENVIRONMENT:-development} depends_on: api: condition: service_healthy healthcheck: test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:3000 || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 30s volumes: postgres_data: redis_data: sidecar_auth: sidecar_codex: embedding_cache: food_uploads: