# 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.
