577b052c05
User Profile (US-004): - Add authenticated profile endpoints (GET/PUT /users/me) - Add avatar upload with file validation (PNG/JPEG, max 2MB) - Create frontend profile page with edit form and avatar upload - Update app shell to link to profile page OAuth/Traefik Integration: - Externalize all Authentik URLs to environment variables - Add domain configuration (API_DOMAIN, WEB_DOMAIN, AUTHENTIK_DOMAIN) - Create docker-compose.traefik.yml for reverse proxy deployment - Update OAuth redirect/callback URLs to use configured domains - Add VITE_APP_URL for frontend public URL configuration Quality gates: pytest (50 passed), ruff, mypy, npm test (12 passed), typecheck, lint, build
58 lines
2.7 KiB
Markdown
58 lines
2.7 KiB
Markdown
## Context
|
|
|
|
The user-profile spec requires authenticated users to view and update their profile (name, email, avatar). The User model already has `email`, `name`, and `avatar_url` fields. The auth system provides cookie-based JWT authentication. This change connects those pieces into a working profile management flow.
|
|
|
|
## Goals / Non-Goals
|
|
|
|
**Goals:**
|
|
- Provide `GET /users/me` to retrieve the current user's profile.
|
|
- Provide `PUT /users/me` to update name and email with validation.
|
|
- Provide `POST /users/me/avatar` to upload an avatar image (PNG/JPG, max 2MB).
|
|
- Store uploaded avatars locally under `apps/api/uploads/avatars/`.
|
|
- Add a frontend `/profile` page with edit form and avatar upload UI.
|
|
- Update the app shell to link to the profile page.
|
|
|
|
**Non-Goals:**
|
|
- Social features or public profile pages.
|
|
- External avatar providers (Gravatar, etc.).
|
|
- Image resizing or cropping.
|
|
|
|
## Decisions
|
|
|
|
1. **Add a dedicated `/users` router instead of extending `/auth/me`**
|
|
- Rationale: cleaner separation of concerns; auth routes handle login/logout, user routes handle profile data.
|
|
- Alternative: extend `/auth/me` to support PUT. Rejected to keep auth router focused.
|
|
|
|
2. **Use `UploadFile` from FastAPI for avatar uploads**
|
|
- Rationale: standard FastAPI pattern, handles multipart parsing and streaming.
|
|
- Alternative: raw bytes in JSON body. Rejected as it complicates client and server.
|
|
|
|
3. **Store avatars as files locally, not in the database**
|
|
- Rationale: keeps the database lightweight; files are served statically.
|
|
- Alternative: bytea/blob column. Rejected for performance and simplicity.
|
|
|
|
4. **Use a simple form-based profile page in the frontend**
|
|
- Rationale: consistent with existing project pages and forms.
|
|
- Alternative: modal or inline editing. Rejected to keep implementation straightforward.
|
|
|
|
## Risks / Trade-offs
|
|
|
|
- **[File storage path]** -> use an environment-configurable upload directory; default to `apps/api/uploads/avatars`.
|
|
- **[Filename collisions]** -> use UUID-based filenames to avoid collisions.
|
|
- **[Unauthorized access to avatars]** -> for now, serve via static mount; later can add auth if needed.
|
|
- **[Frontend state sync]** -> after profile update, refresh auth context so the app shell shows updated name.
|
|
|
|
## Migration Plan
|
|
|
|
1. Create backend users router with GET/PUT/avatar endpoints.
|
|
2. Register router in main.py.
|
|
3. Create frontend profile page, API methods, and routing.
|
|
4. Update app shell with profile link.
|
|
5. Run quality gates (pytest, mypy, ruff, typecheck, lint).
|
|
|
|
Rollback:
|
|
- Remove users router and frontend page; no database changes needed.
|
|
|
|
## Open Questions
|
|
|
|
- Should old avatars be deleted on new upload? (Yes, to avoid disk bloat.) |