Adds auth pages

This commit is contained in:
2026-06-21 00:15:28 +02:00
parent 7dfc3a9692
commit ab93a5c7d1
28 changed files with 2785 additions and 45 deletions
@@ -0,0 +1,188 @@
# Domain Entities — Unit 2: Authentication Pages
## Overview
Unit 2 introduces client-side domain models for authentication guards, system initialization, and invitation completion. Several entities (`User`, `AuthSession`, `SetupStatus`) are inherited from Unit 1; this document defines those that are new or extended.
---
## Inherited from Unit 1 (reference only)
| Entity | Source | Description |
|---|---|---|
| `User` | `src/api/types.ts` | `{ id, name, email, role }` — from `AuthContext` |
| `AuthSession` | `src/contexts/auth-context.ts` | In-memory `{ user, accessToken }` |
| `SetupStatus` | `src/api/types.ts` | `{ initialized: boolean }` — from `GET /Setup/status` |
| `AuthResponse` | `src/api/types.ts` | `{ accessToken, name }` — returned by login/refresh |
---
## New Entities
### UserRole
The application uses three roles, enforced by both backend and frontend guards.
```
UserRole = 'Owner' | 'Admin' | 'User'
```
| Role | Description |
|---|---|
| `Owner` | Full access to all routes, including `/settings` and `/cms` |
| `Admin` | Access to `/users`; no access to `/settings` or `/cms` |
| `User` | Access to `/dashboard` and `/profile` only |
---
### SetupFormData
Collected by the `SetupPage` form. Submitted to `POST /Setup`.
| Field | Type | Constraint |
|---|---|---|
| `name` | `string` | Required; min 1 character |
| `email` | `string` | Required; valid email format |
| `password` | `string` | Required; see BR-U2-0105 |
| `confirmPassword` | `string` | Required; must match `password` (BR-U2-06) |
| `locale` | `'en' \| 'nl'` | Required; user's preferred UI language |
**Notes**:
- `locale` defaults to the browser's detected language if supported, otherwise `'en'`
- The `locale` preference is applied immediately when changed (live preview), using `i18n.changeLanguage()`
- The backend `POST /Setup` payload includes `name`, `email`, `password``locale` is applied client-side only (stored in localStorage via i18n or browser preference)
---
### InvitationToken
Represents the token extracted from the URL query string on the `InviteCompletePage`.
| Field | Type | Description |
|---|---|---|
| `token` | `string` | Raw JWT or opaque token from `?token=xxx` in the URL |
---
### InvitationValidation
Returned by `GET /Invitation/validate?token=xxx` (stub in Unit 2; full implementation in Unit 5).
| Field | Type | Description |
|---|---|---|
| `email` | `string` | The email address the invitation was sent to |
| `name` | `string \| null` | Pre-filled name (optional, may be null) |
| `isValid` | `boolean` | Whether the token is still valid and not yet used |
| `errorCode` | `'EXPIRED' \| 'USED' \| 'NOT_FOUND' \| null` | Error reason when `isValid = false` |
---
### InviteCompleteFormData
Collected by the `InviteCompletePage` form. Submitted to `POST /Invitation/complete`.
| Field | Type | Constraint |
|---|---|---|
| `email` | `string` | Read-only; populated from `InvitationValidation.email` |
| `name` | `string` | Required; min 1 character |
| `password` | `string` | Required; see BR-U2-0105 |
| `confirmPassword` | `string` | Required; must match `password` (BR-U2-06) |
---
### FormBannerError
Represents an API-level or network-level error surfaced as a dismissible banner above a form (BR-U2-21/22).
| Field | Type | Description |
|---|---|---|
| `message` | `string` | User-facing error message |
| `type` | `'api' \| 'network'` | Source of the error |
---
### TokenValidationState
Represents the loading/success/error lifecycle of the invitation token validation on page mount.
| State | Description |
|---|---|
| `loading` | Token validation in progress (spinner shown) |
| `valid` | Token is valid; invitation form is shown |
| `invalid` | Token is expired, used, or not found; error message shown |
---
## Entity Relationship Diagram
```mermaid
classDiagram
class User {
+string id
+string name
+string email
+UserRole role
}
class UserRole {
<<enumeration>>
Owner
Admin
User
}
class AuthSession {
+User user
+string accessToken
}
class SetupStatus {
+boolean initialized
}
class SetupFormData {
+string name
+string email
+string password
+string confirmPassword
+string locale
}
class InvitationToken {
+string token
}
class InvitationValidation {
+string email
+string name
+boolean isValid
+string errorCode
}
class InviteCompleteFormData {
+string email
+string name
+string password
+string confirmPassword
}
class FormBannerError {
+string message
+string type
}
class TokenValidationState {
<<enumeration>>
loading
valid
invalid
}
User --> UserRole : has
AuthSession --> User : contains
InvitationToken --> InvitationValidation : resolves to
InviteCompleteFormData --> InvitationValidation : pre-filled from
TokenValidationState --> InviteCompleteFormData : gates display of
```
Text alternative: `User` has a `UserRole` (Owner/Admin/User); `AuthSession` holds a `User` and `accessToken`; `InvitationToken` resolves to `InvitationValidation` which pre-fills `InviteCompleteFormData`; `TokenValidationState` controls whether the form or error state is shown.