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,118 @@
# Business Logic Model — Unit 5: User Management
## Process Overview
Unit 5 covers three main user flows:
1. **Invite User** — two-step dialog: fill in email + role → copy generated invite link
2. **Copy Pending Invite Link** — one-click copy from the user table row for pending invitations
3. **Change Role** — dropdown action in the user table row; optimistic or confirmed update
---
## Flow 1 — Invite User
```mermaid
sequenceDiagram
box rgba(246,224,94,0.4) Browser
participant U as Gebruiker
participant FE as UsersPage
participant DLG as InviteUserDialog
end
box rgba(99,179,237,0.4) Backend
participant API as Users API
end
U->>FE: Click Invite User button
FE->>DLG: Open dialog at Step 1
DLG-->>U: Show form with email and role fields
U->>DLG: Enter email and select role
U->>DLG: Submit form
DLG->>DLG: Validate with zod schema
alt Validation fails
DLG-->>U: Show inline field errors
else Validation passes
DLG->>API: POST /api/v1/Users/invite with email and role
alt API error
API-->>DLG: 400 or 409 error response
DLG-->>U: Show FormErrorBanner with error message
else API success
API-->>DLG: 200 with inviteLink
DLG->>DLG: Advance to Step 2
DLG-->>U: Show invite link with Copy button
U->>DLG: Click Copy to clipboard
DLG->>FE: Invalidate useUsers query
FE->>API: GET /api/v1/Users
API-->>FE: Updated user list with new pending user
FE-->>U: Table refreshed
U->>DLG: Close dialog
end
end
```
Text alternative: User opens dialog, fills email and role, submits; on success the backend returns an invite link shown in Step 2 with a copy button; closing the dialog triggers a user list refresh.
---
## Flow 2 — Copy Pending Invite Link from Table Row
```mermaid
sequenceDiagram
box rgba(246,224,94,0.4) Browser
participant U as Gebruiker
participant Row as UserTableRow
end
U->>Row: Click copy-link icon on pending user row
Row->>Row: Read inviteLink from UserListItem
Row->>Row: navigator.clipboard.writeText with inviteLink
Row-->>U: Show toast "Invite link copied to clipboard"
```
Text alternative: Copy invite link is a client-side operation — the link is already in the fetched user list (inviteLink field); no API call required.
---
## Flow 3 — Change User Role
```mermaid
sequenceDiagram
box rgba(246,224,94,0.4) Browser
participant U as Gebruiker
participant Row as UserTableRow
participant FE as UsersPage
end
box rgba(99,179,237,0.4) Backend
participant API as Users API
end
U->>Row: Open role dropdown for a user
Row-->>U: Show available roles based on requester role
U->>Row: Select new role
Row->>API: PUT /api/v1/Users/{userId}/role with newRole
alt API error
API-->>Row: 403 or 409 error
Row-->>U: Show toast with error message
else API success
API-->>Row: 200 OK
Row->>FE: Invalidate useUsers query
FE->>API: GET /api/v1/Users
API-->>FE: Updated user list with new role
FE-->>U: Table row updated with new role badge
end
```
Text alternative: User selects a new role from a dropdown in the table row; on backend success the user list is re-fetched to reflect the updated role.
---
## useInvitation.ts Migration (supporting InviteCompletePage)
`useInvitation.ts` was created in Unit 2 with raw `useState`/`useEffect`. In Unit 5 it is migrated to TanStack Query for consistency. This does not change the behavior of `InviteCompletePage` — only the internal implementation of the hooks changes.
| Hook | Before (Unit 2) | After (Unit 5) |
|---|---|---|
| `useValidateInvitation(token)` | useState + useEffect | useQuery (auto-fetches on mount) |
| `useCompleteInvitation()` | useState + useCallback | useMutation |
| Types | Local interfaces in useInvitation.ts | Shared types from types.ts |
Local types (`InvitationValidationResponse`, `InvitationCompleteRequest`, `InvitationCompleteResponse`) are removed and replaced with `InvitationValidation` and `InviteCompleteRequest` from `types.ts`.