5.3 KiB
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-01–05 |
confirmPassword |
string |
Required; must match password (BR-U2-06) |
locale |
'en' | 'nl' |
Required; user's preferred UI language |
Notes:
localedefaults to the browser's detected language if supported, otherwise'en'- The
localepreference is applied immediately when changed (live preview), usingi18n.changeLanguage() - The backend
POST /Setuppayload includesname,email,password—localeis 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-01–05 |
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
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.