marriott-box-image-video-ta.../docker-compose.yml
DJP 30ac050af9 Env-tunable per-run caps (MAX_FILES_PER_RUN, MAX_RUN_DURATION_SECS)
The two per-run limiters in main.py now read from the environment with
their current hardcoded values as defaults. Lets us tune cadence (e.g.
200 → 500 newly-tagged files per click) without rebuilding the image —
edit .env and `docker compose up -d --force-recreate api`.

docker-compose.yml threads both vars into the api container.
.env.example documents them with empty defaults.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:10:22 -04:00

77 lines
3.7 KiB
YAML

# Per ~/.claude/CLAUDE.md Docker policy: every compose file must pin a unique
# top-level `name:` so multiple apps sharing a server (or `deploy/` parent dir)
# don't collide on container/volume names.
name: marriott-tagging
services:
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-marriott}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-marriott}
POSTGRES_DB: ${POSTGRES_DB:-marriott_tagging}
# 127.0.0.1: binding — Postgres must NOT be reachable from outside the
# host. On the dev server this prevents the DB from sitting on the
# public internet; on a local mac it's a no-op for `psql` from the
# same machine. Pick a non-default port via $POSTGRES_HOST_PORT if
# 5432 is taken locally (the deploy script auto-picks on the server).
ports:
- "127.0.0.1:${POSTGRES_HOST_PORT:-5432}:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-marriott} -d ${POSTGRES_DB:-marriott_tagging}"]
interval: 5s
timeout: 5s
retries: 10
# ── Manual-only mode ─────────────────────────────────────────────────────────
# The nightly APScheduler container (`tagger`) was intentionally removed so the
# app only runs Gemini against new files when a human clicks "Run now" in the
# SPA (or `curl -X POST .../api/runs`). The pipeline still lives in main.py
# and scheduler.py is kept in the repo — re-add a `tagger` service here using
# the previous block in git history if you want cron-driven passes back.
api:
build: .
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-marriott}:${POSTGRES_PASSWORD:-marriott}@db:5432/${POSTGRES_DB:-marriott_tagging}
GEMINI_API_KEY: ${GEMINI_API_KEY}
# One or more Box folder IDs to walk recursively (comma-separated).
# Empty → falls back to the hardcoded default in main.py.
BOX_FOLDER_IDS: ${BOX_FOLDER_IDS:-}
# Per-run caps (newly-tagged file count and wall-clock seconds). Defaults
# in main.py are 200 and 14400 (4h); override here to tune without a rebuild.
MAX_FILES_PER_RUN: ${MAX_FILES_PER_RUN:-}
MAX_RUN_DURATION_SECS: ${MAX_RUN_DURATION_SECS:-}
TZ: ${TZ:-UTC}
# Auth — set DEV_AUTH_BYPASS=true to skip MSAL while you wire it up.
DEV_AUTH_BYPASS: ${DEV_AUTH_BYPASS:-true}
AZURE_TENANT_ID: ${AZURE_TENANT_ID:-}
AZURE_CLIENT_ID: ${AZURE_CLIENT_ID:-}
# Comma-separated list of admin emails — only these accounts can hit
# POST /api/runs and POST /api/backfill. Everyone else is read-only.
ADMIN_EMAILS: ${ADMIN_EMAILS:-}
DEV_AUTH_EMAIL: ${DEV_AUTH_EMAIL:-dev@oliver.agency}
DEV_AUTH_NAME: ${DEV_AUTH_NAME:-Dev User}
# In DEV_AUTH_BYPASS mode the dev user is admin by default; flip to
# false here if you want to test the non-admin UX without enabling SSO.
DEV_AUTH_IS_ADMIN: ${DEV_AUTH_IS_ADMIN:-true}
# CORS for local dev: when Vite is on :5173 and FastAPI on host:8004.
# Empty in prod — Apache serves SPA and API under the same origin.
CORS_ORIGINS: ${CORS_ORIGINS:-}
command: ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8000"]
ports:
- "127.0.0.1:${MARRIOTT_API_PORT:-8004}:8000"
volumes:
# The API may trigger a tagging pass via /api/runs, which calls into the
# same Box+Gemini pipeline → it needs the same JWT config.
- ./box_config.json:/app/box_config.json:ro
volumes:
pgdata: