Adds profile and settings pages

This commit is contained in:
2026-06-22 23:59:04 +02:00
parent 6976eb4337
commit 2544e20b3c
49 changed files with 2741 additions and 34 deletions
@@ -0,0 +1,112 @@
# Business Rules — Unit 6: Profile, Settings & CMS Placeholder
## Access Control Rules
```mermaid
graph TD
Request["Incoming Route Request"]
IsAuth{"Authenticated?"}
Route{"Which route?"}
IsOwner{"Role = Owner?"}
AccessDenied["403 AccessDeniedPage"]
NotFound["404 NotFoundPage"]
Profile["ProfilePage"]
Settings["SettingsPage"]
Cms["CmsPage"]
Login["Redirect to /login"]
Request --> IsAuth
IsAuth -->|No| Login
IsAuth -->|Yes| Route
Route -->|/profile| Profile
Route -->|/settings| IsOwner
Route -->|/cms| IsOwner
Route -->|unknown path| NotFound
IsOwner -->|Yes| Settings
IsOwner -->|Yes| Cms
IsOwner -->|No| AccessDenied
classDef guard fill:#FF9800,stroke:#e65100,color:#000
classDef page fill:#2196F3,stroke:#0d47a1,color:#000
classDef error fill:#F44336,stroke:#b71c1c,color:#000
classDef start fill:#9C27B0,stroke:#4a148c,color:#000
class IsAuth guard
class IsOwner guard
class Route guard
class Profile page
class Settings page
class Cms page
class AccessDenied error
class NotFound error
class Login error
class Request start
```
Text alternative: All routes require authentication (redirect to /login if not). /settings and /cms additionally require Owner role; non-Owners are shown 403. Unknown paths show 404.
---
## BR-01: Profile Access
- **Rule**: Any authenticated user can access `/profile`
- **Implementation**: ProfilePage is a child of `_authenticated.tsx` (inherits ProtectedRoute); no additional RoleGuard
- **Data**: Profile data is read from AuthContext (no extra API call for display)
## BR-02: Profile — Name and Email are Editable
- **Rule**: The logged-in user may update their own `name` and `email`
- **Validation** (frontend, mirrors backend):
- `name`: required, non-empty
- `email`: required, valid email format
- **Endpoint**: `PUT /api/v1/Users/me`
- **After save**: Call `POST /api/v1/Auth/refresh` to synchronize AuthContext with updated values
## BR-03: Profile — Role is Read-Only
- **Rule**: A user cannot change their own role from the profile page
- **Display**: Role shown as a static badge; no edit controls rendered
## BR-04: Change Password
- **Rule**: The logged-in user may change their own password via a dialog on ProfilePage
- **Validation** (frontend, mirrors backend password policy):
- `currentPassword`: required, non-empty
- `newPassword`: required, min 8 chars, at least 1 uppercase, 1 lowercase, 1 digit, 1 special character
- `confirmPassword` (UI-only field): must match `newPassword`
- **Endpoint**: `POST /api/v1/Auth/change-password`
- **On success**: Close dialog, show success toast; no AuthContext update needed (password change does not affect access token)
## BR-05: Settings — Owner Only
- **Rule**: Only users with role `Owner` may access `/settings`
- **Implementation**: `RoleGuard` with `allowedRoles={["Owner"]}` wraps SettingsPage
- **On violation**: Redirect to `/403`
## BR-06: Settings — Availability Management
- **Rule**: Owner may change the system availability status from SettingsPage
- **Allowed modes**: `Available`, `Maintenance`, `Unavailable`
- **Endpoint**: `POST /api/v1/Availability/admin/status` (OwnerOnly — already enforced by backend)
- **Message field**: Optional free-text reason displayed to end-users
- **On save**: Invalidate `useAvailabilityStatus` query cache to reflect new status immediately
## BR-07: CMS Page — Owner Only
- **Rule**: Only users with role `Owner` may access `/cms`
- **Implementation**: `RoleGuard` with `allowedRoles={["Owner"]}` wraps CmsPage
- **On violation**: Redirect to `/403`
- **Content**: Placeholder only — no functional CMS features in this unit
## BR-08: 403 Access Denied Page
- **Rule**: Rendered when `RoleGuard` rejects a route request
- **Content**: Heading "Access Denied" + explanatory message + "Back to Dashboard" button (navigates to `/`)
- **No authentication required**: 403 is a public route (unauthenticated users hitting protected routes are redirected to `/login` by ProtectedRoute first)
## BR-09: 404 Not Found Page
- **Rule**: Rendered when TanStack Router cannot match any registered route
- **Content**: Heading "Page Not Found" + brief message + "Back to Dashboard" button (navigates to `/`)
- **Implementation**: TanStack Router catch-all route (`$404.tsx`)
## BR-10: Backend — New Endpoints Required
The following new backend endpoints must be added as part of Unit 6:
| Endpoint | Method | Policy | Purpose |
|----------|--------|--------|---------|
| `/api/v1/Users/me` | PUT | Authenticated | Update own name and email |
| `/api/v1/Auth/change-password` | POST | Authenticated | Change own password |
Both endpoints operate on the currently authenticated user (identified via JWT claims).