Adds user management

This commit is contained in:
2026-06-22 21:14:22 +02:00
parent 5331be4279
commit 6976eb4337
40 changed files with 3392 additions and 146 deletions
@@ -0,0 +1,114 @@
# Business Rules — Unit 5: User Management
## Rule Index
| ID | Rule | Enforced In |
|---|---|---|
| BR-U5-01 | Only Owner and Administrator can access UsersPage | Frontend (RoleGuard), Backend (AdminOnly policy) |
| BR-U5-02 | Owner role cannot be assigned via invitation | Frontend (role selector), Backend |
| BR-U5-03 | At least one Owner must exist at all times | Backend (change role endpoint) |
| BR-U5-04 | Owner can change any user's role (subject to BR-U5-03) | Backend (change role endpoint) |
| BR-U5-05 | Administrator can only promote User to Administrator | Backend (change role endpoint) |
| BR-U5-06 | Copy invite link action is only shown for users where invitationPending = true | Frontend (conditional rendering) |
| BR-U5-07 | Invite form requires valid email format and role selection | Frontend (zod validation) |
| BR-U5-08 | An email already registered cannot be invited again | Backend (invite endpoint validation) |
---
## Decision Flow 1 — Invite User Authorization
```mermaid
graph TD
invite_req["Invite User request"]
check_access{"Requester is Owner\nor Administrator?"}
check_email{"Email has valid format?"}
check_registered{"Email already registered?"}
check_role{"Role is Administrator\nor User?"}
success_invite["Create invitation token\nReturn inviteLink"]
deny_403["403 Forbidden"]
err_email["Validation error\nInvalid email format"]
err_registered["Validation error\nEmail already in use"]
err_role["Validation error\nOwner role cannot be invited"]
invite_req --> check_access
check_access -->|No| deny_403
check_access -->|Yes| check_email
check_email -->|No| err_email
check_email -->|Yes| check_registered
check_registered -->|Yes| err_registered
check_registered -->|No| check_role
check_role -->|Owner| err_role
check_role -->|Administrator or User| success_invite
classDef start_node fill:#2196F3,stroke:#0d47a1,stroke-width:1px,color:#000
classDef decision_node fill:#FF9800,stroke:#e65100,stroke-width:1px,color:#000
classDef success_node fill:#4CAF50,stroke:#2e7d32,stroke-width:1px,color:#000
classDef error_node fill:#F44336,stroke:#b71c1c,stroke-width:1px,color:#000
class invite_req start_node
class check_access,check_email,check_registered,check_role decision_node
class success_invite success_node
class deny_403,err_email,err_registered,err_role error_node
```
Text alternative: Invite request checked for requester access, email validity, registration status, and role — only valid Administrator/User invites proceed; all others are blocked.
---
## Decision Flow 2 — Change Role Authorization
```mermaid
graph TD
change_req["Change Role request\nPUT /Users/{userId}/role"]
req_role{"Requester role?"}
deny_user["403 Forbidden\nUser role cannot change roles"]
admin_target{"Target user's current role?"}
deny_admin["403 Forbidden\nAdmin cannot change Owner or Admin roles"]
owner_check{"Would this leave\nzero Owners?"}
deny_last["Blocked\nAt least 1 Owner required"]
success_change["Update user role\nReturn 200 OK"]
change_req --> req_role
req_role -->|User| deny_user
req_role -->|Administrator| admin_target
req_role -->|Owner| owner_check
admin_target -->|Owner or Administrator| deny_admin
admin_target -->|User| success_change
owner_check -->|Yes| deny_last
owner_check -->|No| success_change
classDef start_node fill:#2196F3,stroke:#0d47a1,stroke-width:1px,color:#000
classDef decision_node fill:#FF9800,stroke:#e65100,stroke-width:1px,color:#000
classDef success_node fill:#4CAF50,stroke:#2e7d32,stroke-width:1px,color:#000
classDef error_node fill:#F44336,stroke:#b71c1c,stroke-width:1px,color:#000
class change_req start_node
class req_role,admin_target,owner_check decision_node
class success_change success_node
class deny_user,deny_admin,deny_last error_node
```
Text alternative: Role change checked for requester level — User is blocked; Administrator can only change User-role targets; Owner can change any role, blocked only if it would leave zero Owners.
---
## Frontend Validation Rules (InviteUserForm — zod schema)
```typescript
const inviteUserSchema = z.object({
email: z.string().email({ message: 'Valid email address required' }),
role: z.enum(['Administrator', 'User'], {
required_error: 'Role selection is required',
}),
});
```
## Frontend Access Control Rules (RoleGuard / conditional rendering)
| Element | Visibility condition |
|---|---|
| UsersPage route | `role === 'Owner' \|\| role === 'Administrator'` |
| Invite User button | Always visible on UsersPage (same role requirement as page) |
| Copy invite link action | `user.invitationPending === true` |
| Change role dropdown | Visible to all UsersPage visitors; available target roles differ by requester role (see BR-U5-04, BR-U5-05) |
| Owner option in role dropdown | Only shown when requester is Owner |