# Phase 2: Users & Authentication - Discussion Log > **Audit trail only.** Do not use as input to planning, research, or execution agents. > Decisions are captured in CONTEXT.md — this log preserves the alternatives considered. **Date:** 2026-05-22 **Phase:** 2-Users & Authentication **Areas discussed:** Email transport, Admin bootstrap, API auth scope, Frontend auth UX --- ## Email Transport | Option | Description | Selected | |--------|-------------|----------| | SMTP via env vars | SMTP_HOST/PORT/USER/PASSWORD/FROM env vars; dev fallback to stdout | ✓ | | Resend / Mailgun API | Third-party transactional email API; one env var (API key) | | | Console-only for now | Print reset link to stdout only; not production-ready | | **User's choice:** SMTP via env vars --- | Option | Description | Selected | |--------|-------------|----------| | Log reset link to stdout | Developer sees link in docker compose logs; zero extra config | ✓ | | Return token in API response | Token in JSON response when SMTP not set; easier for testing | | | Return 503 | Hard failure if SMTP not configured; breaks local dev | | **User's choice:** Log the reset link to backend stdout when SMTP not configured --- | Option | Description | Selected | |--------|-------------|----------| | Celery task (async) | Email enqueued; API returns 202 immediately; Redis already wired | ✓ | | Synchronous inline | Email sent during request; SMTP timeout blocks user | | **User's choice:** Celery task — async dispatch, 202 returned immediately --- ## Admin Bootstrap | Option | Description | Selected | |--------|-------------|----------| | ENV-var bootstrap on startup | ADMIN_EMAIL + ADMIN_PASSWORD; seeded on startup if no users exist; idempotent | ✓ | | Alembic seed migration | Admin row inserted in migration; credentials from env at migration time | | | CLI management command | Manual python manage.py create-admin step after deploy | | | First-user-is-admin | First registered user becomes admin; race-condition risk | | **User's choice:** ENV-var bootstrap on startup --- | Option | Description | Selected | |--------|-------------|----------| | Skip silently if not set | App starts normally; admin can be created later | | | Warn in startup logs if not set | WARNING logged; app starts; helpful reminder | ✓ | | Refuse to start if not set | Startup fails; blocks headless/CI environments | | **User's choice:** Warn in startup logs (app still starts) --- | Option | Description | Selected | |--------|-------------|----------| | Same 100 MB default quota | Consistent; every users row gets a quotas row | ✓ | | Unlimited quota for admin | Signals admins are operators, not subject to storage limits | | | No quota row for admin | Admin doesn't upload; but requires special-casing in enforcement | | **User's choice:** Same 100 MB default quota as regular users --- ## API Auth Scope | Option | Description | Selected | |--------|-------------|----------| | Only new auth endpoints; existing stay public | Phase 2 ships /api/auth/* only; D-03 nullable user_id preserved | ✓ | | Lock down all endpoints in Phase 2 | All endpoints get get_current_user + NOT NULL migration | | **User's choice:** Only new auth endpoints; existing document/topics/settings stay public --- | Option | Description | Selected | |--------|-------------|----------| | /api/admin/* prefix | All admin under /api/admin/; get_current_admin on every handler | ✓ | | /api/users/* with role check | Shared prefix, role-based access control | | | /admin/* separate mount | Separate path, possible separate FastAPI sub-application | | **User's choice:** /api/admin/* prefix with get_current_admin dependency --- | Option | Description | Selected | |--------|-------------|----------| | CORS_ORIGINS env var (comma-separated) | Pydantic parses as list; default localhost:5173 | ✓ | | Hardcode origins per environment | Config file per environment or build-time injection | | | Keep allow_origins=['*'] | Not recommended with auth cookies now in play | | **User's choice:** CORS_ORIGINS env var, comma-separated --- ## Frontend Auth UX | Option | Description | Selected | |--------|-------------|----------| | Full auth wall | beforeEach guard redirects to /login if no access token | ✓ | | Partial — auth only gates account/admin | Documents/topics still accessible without login | | **User's choice:** Full auth wall — entire app requires login --- | Option | Description | Selected | |--------|-------------|----------| | useAuthStore + fetch interceptor | In-memory token; auto-refresh on 401; redirect on refresh failure | ✓ | | Token in composable with manual headers | More explicit but repetitive across API calls | | | You decide | Defer to downstream agents | | **User's choice:** useAuthStore with in-memory token + fetch interceptor --- | Option | Description | Selected | |--------|-------------|----------| | /admin route, separate AdminView | Route guard (role=admin); sub-navigation; sidebar link conditionally shown | ✓ | | Integrated into /settings as Admin tab | Mixes admin and personal settings | | | You decide | Defer to UI researcher | | **User's choice:** /admin route with dedicated AdminView; sidebar link visible for admin role only --- | Option | Description | Selected | |--------|-------------|----------| | Full TOTP enrollment UI in Phase 2 | QR code + backup codes + acknowledgment; aligned with success criteria | ✓ | | Backend-only; UI deferred to Phase 3 | Misaligns with Phase 2 success criterion #2 | | **User's choice:** Full TOTP enrollment UI in Phase 2 --- ## Claude's Discretion None — all areas had a clear user preference. ## Deferred Ideas None — discussion stayed within phase scope.