feat: implement user profile management and oauth/traefik integration
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
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
## 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.)
|
||||
@@ -0,0 +1,24 @@
|
||||
## Why
|
||||
|
||||
The platform has authentication but users cannot view or edit their own profile information. Implementing profile management is essential for personalization and account management.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add authenticated user profile API endpoints (read, update, avatar upload).
|
||||
- Add a frontend profile page with editable form and avatar upload.
|
||||
- Validate avatar file type and size on upload.
|
||||
- Store avatars locally and update the user's avatar_url.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `user-profile-management`: Users can view and edit their profile (name, email) and upload an avatar.
|
||||
|
||||
### Modified Capabilities
|
||||
- `auth-oauth`: Extend /auth/me or add dedicated /users/me endpoint for richer profile data.
|
||||
|
||||
## Impact
|
||||
|
||||
- Backend changes in `apps/api/src/api/` (new users router) and storage for avatars.
|
||||
- Frontend changes in `apps/web/src/` (new profile page, API methods, routing).
|
||||
- No schema migrations required (avatar_url already exists on User model).
|
||||
@@ -0,0 +1,50 @@
|
||||
# User Profile Management Specification
|
||||
|
||||
## Purpose
|
||||
|
||||
Manage user profiles including personal information and avatar.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Profile Retrieval
|
||||
|
||||
The system SHALL allow users to view their profile.
|
||||
|
||||
#### Scenario: View profile
|
||||
- GIVEN an authenticated user
|
||||
- WHEN they access the profile page
|
||||
- THEN their name, email, and avatar are displayed
|
||||
|
||||
### Requirement: Profile Updates
|
||||
|
||||
The system SHALL allow users to update their profile.
|
||||
|
||||
#### Scenario: Update name and email
|
||||
- GIVEN an authenticated user
|
||||
- WHEN they submit profile changes
|
||||
- THEN the system validates the input
|
||||
- AND updates the user record
|
||||
|
||||
### Requirement: Avatar Upload
|
||||
|
||||
The system SHALL support local avatar storage.
|
||||
|
||||
#### Scenario: Upload avatar
|
||||
- GIVEN an authenticated user
|
||||
- WHEN they upload an image file
|
||||
- THEN the system validates the file type and size
|
||||
- AND stores it locally
|
||||
- AND updates the user's avatar URL
|
||||
|
||||
## Dependencies
|
||||
|
||||
- auth-oauth (authenticated users)
|
||||
- Database models: User
|
||||
|
||||
## Quality Gates
|
||||
|
||||
- `pytest` must pass
|
||||
- `mypy .` must pass
|
||||
- `ruff check .` must pass
|
||||
- `npm run typecheck` must pass
|
||||
- `npm run lint` must pass
|
||||
@@ -0,0 +1,28 @@
|
||||
## 1. Backend profile API
|
||||
|
||||
- [x] 1.1 Create `apps/api/src/api/users.py` with `GET /users/me`, `PUT /users/me`, and `POST /users/me/avatar` endpoints.
|
||||
- [x] 1.2 Add Pydantic schemas for `UserProfileResponse` and `UserProfileUpdate`.
|
||||
- [x] 1.3 Implement avatar upload: validate file type (image/png, image/jpeg), max 2MB, save to `uploads/avatars/` with UUID filename, update `avatar_url`.
|
||||
- [x] 1.4 Register users router in `apps/api/src/main.py`.
|
||||
- [x] 1.5 Add backend tests for profile read, update, and avatar upload.
|
||||
|
||||
## 2. Frontend profile page
|
||||
|
||||
- [x] 2.1 Create `apps/web/src/api/profile.ts` with API methods for getProfile, updateProfile, and uploadAvatar.
|
||||
- [x] 2.2 Create `apps/web/src/pages/profile.tsx` with profile display, edit form (name, email), and avatar upload.
|
||||
- [x] 2.3 Add `/profile` route in `apps/web/src/router.tsx`.
|
||||
- [x] 2.4 Update `apps/web/src/components/app-shell.tsx` to link to `/profile` from the user chip.
|
||||
- [x] 2.5 Update `apps/web/src/types.ts` to include `avatar_url` in `SessionUser` if needed.
|
||||
- [ ] 2.6 Add frontend tests for profile page rendering and interactions.
|
||||
|
||||
## 3. Verification and OpenSpec tracking
|
||||
|
||||
- [x] 3.1 Run backend checks (`pytest`, `ruff check src tests`, `mypy src`) and fix findings.
|
||||
- [x] 3.2 Run frontend checks (`npm test`, `npm run typecheck`, `npm run lint`, `npm run build`) and fix findings.
|
||||
- [x] 3.3 Update this tasks file with completed checkboxes and document blockers/follow-ups.
|
||||
|
||||
## Blockers / Follow-ups
|
||||
|
||||
- No blocking issues remain for this change.
|
||||
- Frontend tests for profile page (task 2.6) were skipped to keep the change focused; existing tests pass (12/12). Profile page tests can be added in a follow-up.
|
||||
- Vite deprecation warnings from `vite:react-babel` plugin are non-blocking and pre-existing.
|
||||
Reference in New Issue
Block a user