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
2.7 KiB
2.7 KiB
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/meto retrieve the current user's profile. - Provide
PUT /users/meto update name and email with validation. - Provide
POST /users/me/avatarto upload an avatar image (PNG/JPG, max 2MB). - Store uploaded avatars locally under
apps/api/uploads/avatars/. - Add a frontend
/profilepage 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
-
Add a dedicated
/usersrouter instead of extending/auth/me- Rationale: cleaner separation of concerns; auth routes handle login/logout, user routes handle profile data.
- Alternative: extend
/auth/meto support PUT. Rejected to keep auth router focused.
-
Use
UploadFilefrom 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.
-
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.
-
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
- Create backend users router with GET/PUT/avatar endpoints.
- Register router in main.py.
- Create frontend profile page, API methods, and routing.
- Update app shell with profile link.
- 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.)