agnes-the-ai-analyst/docker-compose.local-dev.yml
Petr Simecek 9b5214ea6f
feat(dev): LOCAL_DEV_MODE for one-command local dev + magic-link fixes (#32)
* feat(dev): add LOCAL_DEV_MODE for one-command local dev

When LOCAL_DEV_MODE=1, every protected route auto-authenticates as a seeded
admin user (default dev@localhost) — no login screen, no Google OAuth config,
no magic-link roundtrip. Startup logs a loud warning to make misuse obvious.

Also fixes two preexisting bugs in the magic-link flow that surfaced while
wiring up the dev fallback:

- /auth/email/verify only accepted POST, but the URL embedded in emails is
  a GET link — clicking from any mail client returned 405. Added a GET
  variant that consumes the token, sets the auth cookie, and redirects to
  /dashboard.
- Token expiry check compared an offset-aware datetime.now(timezone.utc)
  against an offset-naive value from DuckDB, raising TypeError on every
  valid link. Normalize the stored timestamp to UTC before subtracting.

Dev-only fallback (scoped strictly to LOCAL_DEV_MODE to keep test and
production behavior identical): send-link logs the magic link to stderr
and returns it as dev_link in the JSON response when no SMTP is configured.

Usage:
  ./scripts/run-local-dev.sh
  open http://localhost:8000  # lands on /dashboard as admin

* fix(dev): URL-encode magic-link email + avoid /login redirect loop

Two issues surfaced by Devin review on PR #32.

1. _build_magic_link interpolated email into the URL unescaped. For addresses
   with '+' (e.g. user+tag@gmail.com) Starlette's query parser decoded '+'
   as a space on the GET /verify side, so repo.get_by_email returned None
   and every click yielded 401 "Invalid link". quote(email, safe='') fixes
   both the email transport and the dev_link fallback.

2. /login in LOCAL_DEV_MODE unconditionally redirected to /dashboard. If
   dev-user seeding failed at startup (main.py wraps seed in try/except),
   /dashboard 401'd, the HTML redirect handler bounced to /login, and the
   loop repeated until the browser aborted. Now /login checks the dev user
   actually exists before short-circuiting; otherwise it falls through to
   the normal login form so the missing seed is visible.
2026-04-22 14:47:33 +02:00

32 lines
1.1 KiB
YAML

# Local-dev overlay — auth bypass + no real email delivery required.
#
# Usage:
# docker compose -f docker-compose.yml -f docker-compose.local-dev.yml up
# or:
# scripts/run-local-dev.sh
#
# Effect:
# - LOCAL_DEV_MODE=1 makes every protected route auto-login as dev@localhost (role=admin).
# - Magic-link emails are logged to stderr and returned in the response (no SMTP needed).
# - Secrets (JWT, session) auto-generate into /data/state on first boot.
# - No .env file required; nothing else is mandatory.
#
# NEVER deploy this overlay to an environment reachable from the internet.
services:
app:
env_file: [] # Drop the project .env requirement — everything dev-relevant is inline below.
environment:
- DATA_DIR=/data
- LOCAL_DEV_MODE=1
- LOCAL_DEV_USER_EMAIL=dev@localhost
- SERVER_URL=http://localhost:8000
- LOG_LEVEL=info
# Scheduler also reads LOCAL_DEV flag so its auto-auth uses the same seed user.
scheduler:
env_file: []
environment:
- DATA_DIR=/data
- API_URL=http://app:8000
- LOCAL_DEV_MODE=1
- SEED_ADMIN_EMAIL=dev@localhost