* fix(compose): pass --proxy-headers to uvicorn so OAuth callbacks resolve to https When the app runs behind a reverse proxy (Caddy, nginx, Cloudflare Tunnel), uvicorn's default policy of trusting X-Forwarded-* only from 127.0.0.1 means the request the container sees still looks like http://localhost:8000/..., even when the user is on https://. The OAuth provider then sends Google a callback URL Google has never seen — Error 400: redirect_uri_mismatch. --proxy-headers + --forwarded-allow-ips '*' tell uvicorn to honor those headers from any source. The container only ever sees its own docker network anyway; trusting it everywhere is safe in this deployment shape. Adds docs/auth-google-oauth.md with the full operator gotcha list — env vars that have to be set, instance.yaml fields that silently fall back to defaults, and the DB workaround for ad-hoc role promotion when SEED_ADMIN_EMAIL was missed on first boot. * docs(claude): codify vendor-agnostic OSS rule for AI agents and humans Adds a "Vendor-agnostic OSS" section to CLAUDE.md spelling out what cannot land in this repo (specific deployments, internal hostnames/projects, cross- references to private repos, customer-specific paths) and how to phrase abstractions instead. Plus a pre-PR grep checklist in the existing "Git Commits & Pull Requests" section. This trips up agents and humans alike — the previous version of #39 had private-deployment references in the body and a customer domain in a doc example. Surfacing the rule once in the file every Claude/Cursor/Aider session reads should prevent that on the next PR. * docs(oauth): cover DOMAIN + SERVER_URL env vars introduced by PR #48 PR #48 (merged) added DOMAIN-gated Secure cookie in google.py and documented SERVER_URL in .env.template, but this operator doc was drafted before that merge and didn't reference either variable. Adding both to the env table and extending the common-failure-modes table with a sticky-cookie / redirect-URI-mismatch entry that references SERVER_URL as the host-header-independent fix. Also aligns the compose command snippet with the `='*'` syntax that actually ships on main post-PR #48. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Vojtech Rysanek <vrysanek@groupon.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
135 lines
3.1 KiB
YAML
135 lines
3.1 KiB
YAML
services:
|
|
app:
|
|
build: .
|
|
# --proxy-headers + --forwarded-allow-ips make uvicorn honor the
|
|
# X-Forwarded-Proto / X-Forwarded-Host headers any reverse proxy (Caddy,
|
|
# nginx, Cloudflare Tunnel) sets. Without it, request.url_for() emits
|
|
# http://localhost:8000/... even when the user is on https://, which
|
|
# breaks OAuth callbacks (redirect_uri_mismatch). Belt-and-suspenders —
|
|
# FORWARDED_ALLOW_IPS=* in .env does the same via env var.
|
|
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips='*'
|
|
ports:
|
|
- "8000:8000"
|
|
volumes:
|
|
- data:/data
|
|
- ./config:/app/config:ro
|
|
# - ./custom-connectors:/app/connectors/custom:ro # Tier A: AI-generated connectors
|
|
env_file: .env
|
|
environment:
|
|
- DATA_DIR=/data
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-sf", "http://localhost:8000/api/health"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
restart: unless-stopped
|
|
|
|
# One-shot: run extractor then rebuild orchestrator views
|
|
extract:
|
|
build: .
|
|
command: >
|
|
sh -c "python -m connectors.keboola.extractor &&
|
|
python -c 'from src.orchestrator import SyncOrchestrator; print(SyncOrchestrator().rebuild())'"
|
|
volumes:
|
|
- data:/data
|
|
- ./config:/app/config:ro
|
|
env_file: .env
|
|
environment:
|
|
- DATA_DIR=/data
|
|
profiles:
|
|
- extract
|
|
|
|
scheduler:
|
|
build: .
|
|
command: python -m services.scheduler
|
|
volumes:
|
|
- data:/data
|
|
- ./config:/app/config:ro
|
|
env_file: .env
|
|
environment:
|
|
- DATA_DIR=/data
|
|
- API_URL=http://app:8000
|
|
- SEED_ADMIN_EMAIL=${SEED_ADMIN_EMAIL:-}
|
|
depends_on:
|
|
app:
|
|
condition: service_healthy
|
|
restart: unless-stopped
|
|
|
|
telegram-bot:
|
|
build: .
|
|
command: python -m services.telegram_bot
|
|
volumes:
|
|
- data:/data
|
|
env_file: .env
|
|
environment:
|
|
- DATA_DIR=/data
|
|
depends_on:
|
|
- app
|
|
profiles:
|
|
- full
|
|
restart: unless-stopped
|
|
|
|
ws-gateway:
|
|
build: .
|
|
command: python -m services.ws_gateway
|
|
volumes:
|
|
- data:/data
|
|
env_file: .env
|
|
environment:
|
|
- DATA_DIR=/data
|
|
depends_on:
|
|
- app
|
|
profiles:
|
|
- full
|
|
restart: unless-stopped
|
|
|
|
corporate-memory:
|
|
build: .
|
|
command: python -m services.corporate_memory
|
|
volumes:
|
|
- data:/data
|
|
env_file: .env
|
|
environment:
|
|
- DATA_DIR=/data
|
|
depends_on:
|
|
- app
|
|
profiles:
|
|
- full
|
|
restart: unless-stopped
|
|
|
|
session-collector:
|
|
build: .
|
|
command: python -m services.session_collector
|
|
volumes:
|
|
- data:/data
|
|
env_file: .env
|
|
environment:
|
|
- DATA_DIR=/data
|
|
depends_on:
|
|
- app
|
|
profiles:
|
|
- full
|
|
restart: unless-stopped
|
|
|
|
caddy:
|
|
image: caddy:2-alpine
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
- caddy_data:/data
|
|
- caddy_config:/config
|
|
environment:
|
|
- DOMAIN=${DOMAIN:-localhost}
|
|
depends_on:
|
|
app:
|
|
condition: service_healthy
|
|
restart: unless-stopped
|
|
profiles:
|
|
- production
|
|
|
|
volumes:
|
|
data:
|
|
caddy_data:
|
|
caddy_config:
|