843 lines
33 KiB
Markdown
843 lines
33 KiB
Markdown
# User Page Requirements
|
|
|
|
This document contains the complete frontend requirements for all user management pages and components. All UI components are dynamically generated from backend metadata—no hardcoding required.
|
|
|
|
**IMPORTANT:** All user management pages are **admin-only**. Non-admin users should not see navigation links or be able to access these pages. The frontend must check user privileges before rendering user management UI.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Overview](#overview)
|
|
2. [Page Structure and Layout](#page-structure-and-layout)
|
|
3. [User Interactions and Functionality](#user-interactions-and-functionality)
|
|
4. [Backend Routes and API Integration](#backend-routes-and-api-integration)
|
|
5. [Field and Attribute Reference](#field-and-attribute-reference)
|
|
6. [Dynamic Rendering Guidelines](#dynamic-rendering-guidelines)
|
|
7. [Admin Access Control](#admin-access-control)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
The user management page enables administrators to manage users within their mandate. The frontend consists of a single page (`/users`) with different views/states:
|
|
|
|
- **List View** - Browse, search, filter, and sort users (admin-only)
|
|
- **Detail View** - View complete user information (admin-only)
|
|
- **Edit View** - Edit user properties (admin-only)
|
|
- **Create View** - Create new users (admin-only)
|
|
|
|
All views use backend-driven UI generation, meaning field definitions, labels, validation rules, and UI structure come entirely from backend metadata through the `/api/attributes/User` endpoint. Views are managed through component state and routing within the same page, not as separate routes.
|
|
|
|
---
|
|
|
|
## Page Structure and Layout
|
|
|
|
### User Management Page (`/users`)
|
|
|
|
**Access Control:** Admin-only. Non-admin users should not see this page or navigation links to it.
|
|
|
|
The user management page uses different views/states to handle different user interactions. Views are managed through component state and routing within the same page component.
|
|
|
|
### List View
|
|
|
|
**State:** `view === 'list'` or `selectedUserId === null`
|
|
|
|
**What the administrator sees:**
|
|
|
|
- **Main Content Area:**
|
|
- Table or card grid displaying all users in the mandate
|
|
- Each user row/card shows: username, email, full name, privilege badge, enabled toggle (interactive switch), authentication authority
|
|
- Enabled toggle is clickable and immediately updates user status with optimistic update
|
|
- Clickable rows/cards that switch to Detail View (set selectedUserId and view state)
|
|
|
|
- **Search and Filter Controls:**
|
|
- General search input box (searches across all text fields)
|
|
- Field-specific filter controls (one filter per visible field)
|
|
- Active filter indicators (chips/badges showing applied filters)
|
|
- "Clear all filters" button when filters are active
|
|
|
|
- **Sorting Controls:**
|
|
- Clickable column headers with sort indicators (up/down arrows)
|
|
- Visual indication of current sort field and direction
|
|
- Support for multi-level sorting
|
|
|
|
- **Pagination Controls:**
|
|
- Page information display ("Page X of Y", "Showing 1-20 of 45 users")
|
|
- Previous/Next page buttons
|
|
- Page number buttons
|
|
- Page size selector (10, 20, 50, 100 items per page)
|
|
|
|
- **Action Buttons:**
|
|
- "Create User" button (admin-only) - switches to Create View
|
|
|
|
### Detail View
|
|
|
|
**State:** `view === 'detail'` and `selectedUserId !== null`
|
|
|
|
**Access Control:** Admin-only.
|
|
|
|
**What the administrator sees:**
|
|
|
|
- **User Header Section:**
|
|
- Username (editable indicator if user has permission)
|
|
- Full name (if available)
|
|
- Privilege badge with color coding
|
|
- Enabled status indicator
|
|
|
|
- **User Information Section:**
|
|
- All user properties displayed as formatted fields
|
|
- Read-only fields shown as formatted text
|
|
- Editable fields shown with edit indicators (if admin has permission)
|
|
- Special formatting:
|
|
- Privilege → Color-coded badge (User/Admin/SysAdmin)
|
|
- Enabled → Checkmark icon or "Enabled"/"Disabled" text
|
|
- Authentication Authority → Badge with icon
|
|
- Email → Clickable mailto link
|
|
|
|
- **Action Buttons:**
|
|
- Edit button (if admin has permission and editable fields exist) - switches to Edit View
|
|
- Reset Password button (admin-only)
|
|
- Revoke Sessions button (admin-only)
|
|
- Delete button (if admin has permission)
|
|
|
|
### Edit View
|
|
|
|
**State:** `view === 'edit'` and `selectedUserId !== null`
|
|
|
|
**Access Control:** Admin-only.
|
|
|
|
**What the administrator sees:**
|
|
|
|
- **Form Section:**
|
|
- Dynamic form with editable user fields only
|
|
- Field labels with required indicators (asterisk for required fields)
|
|
- Help text/tooltips from field descriptions
|
|
- Input validation errors displayed inline
|
|
|
|
- **Action Buttons:**
|
|
- Save button (submits form)
|
|
- Cancel button (switches back to Detail View)
|
|
|
|
### Create View
|
|
|
|
**State:** `view === 'create'`
|
|
|
|
**Access Control:** Admin-only.
|
|
|
|
**What the administrator sees:**
|
|
|
|
- **Form Section:**
|
|
- Dynamic form with all editable user fields
|
|
- Password field (special field, not in User model attributes)
|
|
- Confirm password field (frontend-only validation)
|
|
- Field labels with required indicators
|
|
- Help text/tooltips from field descriptions
|
|
- Input validation errors displayed inline
|
|
|
|
- **Action Buttons:**
|
|
- Create button (submits form)
|
|
- Cancel button (switches back to List View)
|
|
|
|
- **Confirmation Dialogs:**
|
|
- Delete confirmation dialog (on user detail page)
|
|
- Password reset confirmation dialog
|
|
|
|
---
|
|
|
|
## User Interactions and Functionality
|
|
|
|
### Admin Access Control
|
|
|
|
**Before Rendering Any User Management UI:**
|
|
|
|
1. Check if current user has admin or sysadmin privilege
|
|
2. If not admin:
|
|
- Hide navigation links to user management pages
|
|
- Redirect if user tries to access pages directly
|
|
- Show unauthorized access message
|
|
3. If admin:
|
|
- Render user management UI normally
|
|
- Handle 403 errors gracefully (may occur if permissions change)
|
|
|
|
### Browsing and Discovery
|
|
|
|
**Search Functionality:**
|
|
- Administrator types in general search box
|
|
- Frontend debounces input (300-500ms delay)
|
|
- Search applies across all text fields in user objects
|
|
- Results update automatically
|
|
- Page resets to page 1 when search changes
|
|
|
|
**Field Filtering:**
|
|
- Administrator selects field to filter by
|
|
- Frontend shows appropriate filter UI based on field type:
|
|
- Text fields → Text input with operator selection (contains, equals, startsWith, endsWith)
|
|
- Select fields → Dropdown with options from backend metadata
|
|
- Email fields → Email input filter
|
|
- Checkbox fields → Boolean toggle (true/false/any)
|
|
- Administrator applies filter → Filter appears as active chip/badge
|
|
- Administrator can remove individual filters
|
|
- Multiple filters work together (AND logic)
|
|
- Page resets to page 1 when filters change
|
|
|
|
**Sorting:**
|
|
- Administrator clicks column header
|
|
- Sort direction toggles (asc → desc → remove)
|
|
- Multiple columns can be sorted (multi-level sorting)
|
|
- Sort indicators show on column headers
|
|
- All filters and search preserved when sorting
|
|
|
|
**Pagination:**
|
|
- Administrator clicks page number or navigation button
|
|
- Page updates and data refetches
|
|
- All filters, search, and sort preserved
|
|
- Administrator changes page size → Page resets to 1, data refetches
|
|
|
|
**View Switching:**
|
|
- Administrator clicks user row/card → Switches to Detail View (set `selectedUserId` and `view: 'detail'`)
|
|
- Administrator clicks username → Switches to Detail View (set `selectedUserId` and `view: 'detail'`)
|
|
|
|
### Viewing User Details
|
|
|
|
**Information Display:**
|
|
- All user fields displayed using dynamic rendering
|
|
- Read-only fields shown as formatted text
|
|
- Editable fields shown with edit indicators
|
|
- Special fields formatted appropriately (privilege badges, enabled status, email links)
|
|
|
|
**Action Availability:**
|
|
- Edit button shown if editable fields exist and admin has permission
|
|
- Reset Password button always shown (admin-only action)
|
|
- Revoke Sessions button always shown (admin-only action)
|
|
- Delete button shown if admin has permission
|
|
|
|
### Creating Users
|
|
|
|
**Form Interaction:**
|
|
- Administrator clicks "Create User" button → Switches to Create View (set `view: 'create'`)
|
|
- Form shows all editable fields plus password field
|
|
- Administrator fills in fields
|
|
- Client-side validation shows errors immediately
|
|
- Administrator clicks Create → Form validates and submits
|
|
- Administrator clicks Cancel → Switches back to List View (set `view: 'list'`, `selectedUserId: null`)
|
|
|
|
**Form Validation:**
|
|
- Required field validation (shows error if empty)
|
|
- Type validation (e.g., email fields must be valid email format)
|
|
- Select field validation (value must be in options array)
|
|
- Password validation (minimum 8 characters)
|
|
- Password confirmation validation (must match password)
|
|
- Validation errors displayed inline below fields
|
|
|
|
**Form Submission:**
|
|
- User data sent as User object
|
|
- Password sent as separate field in request body
|
|
- Success → Switch to Detail View for created user (set `selectedUserId` to new user ID, `view: 'detail'`)
|
|
- Error handling:
|
|
- 403 (permission denied) → Show permission error
|
|
- 400 (validation errors) → Display backend validation errors
|
|
- Other errors → Show generic error message
|
|
|
|
### Editing Users
|
|
|
|
**Form Interaction:**
|
|
- Administrator clicks "Edit" button → Switches to Edit View (set `view: 'edit'`)
|
|
- Form pre-populated with current user values
|
|
- Administrator modifies fields
|
|
- Client-side validation shows errors immediately
|
|
- Administrator clicks Save → Form validates and submits
|
|
- Administrator clicks Cancel → Switches back to Detail View (set `view: 'detail'`)
|
|
|
|
**Form Validation:**
|
|
- Required field validation (shows error if empty)
|
|
- Type validation (e.g., email fields must be valid email format)
|
|
- Select field validation (value must be in options array)
|
|
- Validation errors displayed inline below fields
|
|
|
|
**Form Submission:**
|
|
- Only changed fields sent (or all form data)
|
|
- Success → Switch back to Detail View (set `view: 'detail'`) and show success message
|
|
- Error handling:
|
|
- 403 (permission denied) → Show permission error
|
|
- 400 (validation errors) → Display backend validation errors
|
|
- Other errors → Show generic error message
|
|
|
|
### Enabling and Disabling Users
|
|
|
|
**Toggle Interaction:**
|
|
- Administrator views user list table
|
|
- Table displays enabled/disabled status as toggle switch in "Enabled" column
|
|
- Administrator clicks toggle switch for a user
|
|
- Frontend immediately updates toggle state (optimistic update)
|
|
- Frontend sends PUT request to update user's enabled property
|
|
- Administrator sees immediate feedback (toggle changes instantly)
|
|
|
|
**Toggle Submission:**
|
|
- Success → Keep optimistic update, refetch user list to ensure consistency
|
|
- Error → Revert toggle to original state, show error message
|
|
- No confirmation dialog needed - toggle is immediate and reversible
|
|
|
|
**Implementation Notes:**
|
|
- Toggle should be part of the main table column
|
|
- Use optimistic updates for instant feedback
|
|
- Refetch list after successful update
|
|
- Handle errors gracefully by reverting toggle state
|
|
|
|
### Customer Journey 5: Enabling and Disabling Users
|
|
|
|
> **📋 Complete customer journey documentation is available in [User Customer Journeys](./user-page-customer-journeys.md#customer-journey-5-enabling-and-disabling-users)**
|
|
|
|
### Resetting User Passwords
|
|
|
|
**Password Reset Interaction:**
|
|
- Administrator clicks "Reset Password" button
|
|
- Password reset dialog appears
|
|
- Administrator enters new password
|
|
- Administrator confirms new password
|
|
- Client-side validation:
|
|
- Password must be at least 8 characters
|
|
- Passwords must match
|
|
- Administrator clicks Reset → Password reset request sent
|
|
- Administrator clicks Cancel → Dialog closes, no action
|
|
|
|
**Password Reset Submission:**
|
|
- Success → Show success message, close dialog
|
|
- Backend automatically revokes all user tokens
|
|
- Error handling:
|
|
- 403 (permission denied) → Show permission error
|
|
- 400 (password too short) → Show validation error
|
|
- Other errors → Show generic error message
|
|
|
|
### Revoking User Sessions
|
|
|
|
**Session Revocation Interaction:**
|
|
- Administrator clicks "Revoke Sessions" button
|
|
- Session revocation dialog appears
|
|
- Administrator optionally selects authority filter:
|
|
- All authorities (default) - revokes all sessions
|
|
- Local only - revokes only local authentication sessions
|
|
- Google only - revokes only Google OAuth sessions
|
|
- Microsoft only - revokes only Microsoft OAuth sessions
|
|
- Administrator optionally enters reason (for audit logging)
|
|
- Administrator clicks "Revoke Sessions" → Session revocation request sent
|
|
- Administrator clicks Cancel → Dialog closes, no action
|
|
|
|
**Session Revocation Submission:**
|
|
- Success → Show success message with count of revoked sessions, close dialog
|
|
- User will need to log in again on all affected devices
|
|
- Error handling:
|
|
- 403 (permission denied) → Show permission error
|
|
- 400 (invalid parameters) → Show validation error
|
|
- Other errors → Show generic error message
|
|
|
|
**Use Cases:**
|
|
- Security incident: User's account may have been compromised
|
|
- Device management: User lost a device or needs to log out of specific service
|
|
- Account suspension: Temporarily disable user access
|
|
- Force re-authentication: Make user log in again without changing password
|
|
|
|
**Password Reset Interaction:**
|
|
- Administrator clicks "Reset Password" button
|
|
- Password reset dialog appears
|
|
- Administrator enters new password
|
|
- Administrator confirms new password
|
|
- Client-side validation:
|
|
- Password must be at least 8 characters
|
|
- Passwords must match
|
|
- Administrator clicks Reset → Password reset request sent
|
|
- Administrator clicks Cancel → Dialog closes, no action
|
|
|
|
**Password Reset Submission:**
|
|
- Success → Show success message, close dialog
|
|
- Backend automatically revokes all user tokens
|
|
- Error handling:
|
|
- 403 (permission denied) → Show permission error
|
|
- 400 (password too short) → Show validation error
|
|
- Other errors → Show generic error message
|
|
|
|
### Customer Journey 7: Revoking User Sessions
|
|
|
|
> **📋 Complete customer journey documentation is available in [User Customer Journeys](./user-page-customer-journeys.md#customer-journey-7-revoking-user-sessions)**
|
|
|
|
### Deleting Users
|
|
|
|
**Delete Action:**
|
|
- Administrator clicks delete button (on detail page or list)
|
|
- Confirmation dialog appears with user name/username
|
|
- Warning about permanent deletion
|
|
- Administrator confirms → User deleted
|
|
- Administrator cancels → Dialog closes, no action
|
|
|
|
**Delete Success Handling:**
|
|
- Success message displayed
|
|
- If in Detail View → Switch back to List View (set `view: 'list'`, `selectedUserId: null`)
|
|
- If in List View → Remove user from list or refresh
|
|
|
|
---
|
|
|
|
## Backend Routes and API Integration
|
|
|
|
### Complete Route Reference
|
|
|
|
All backend routes used by user pages:
|
|
|
|
| Route | Method | Purpose | When Used | Access Control |
|
|
|-------|--------|---------|-----------|----------------|
|
|
| `/api/users/` | GET | Get all users (with pagination) | Initial page load, pagination changes, sort changes, filter changes, search changes | All authenticated users (filtered by mandate) |
|
|
| `/api/users/{userId}` | GET | Get user details | Detail page load, edit page load | All authenticated users |
|
|
| `/api/users/{userId}` | PUT | Update user | Edit form submission | All authenticated users |
|
|
| `/api/users/{userId}` | DELETE | Delete user | User confirms deletion | All authenticated users |
|
|
| `/api/users` | POST | Create user | Create form submission | All authenticated users |
|
|
| `/api/users/{userId}/reset-password` | POST | Reset user password | Admin confirms password reset | **Admin-only** |
|
|
| `/api/admin/tokens/revoke/user` | POST | Revoke all active sessions for a user | Admin confirms session revocation | **Admin-only** |
|
|
| `/api/users/change-password` | POST | Change current user's password | User changes own password | Current user only (not admin-only) |
|
|
| `/api/attributes/User` | GET | Get field definitions | Page load (once per page) - used to generate all UI components | All authenticated users |
|
|
|
|
### API Request Patterns
|
|
|
|
**Pagination Request:**
|
|
```
|
|
GET /api/users/?pagination={"page":1,"pageSize":20,"sort":[],"filters":null}
|
|
```
|
|
- `pagination` parameter is JSON-encoded string
|
|
- If user wants all users: omit `pagination` parameter entirely
|
|
- Filters structure: `{"search":"query","fieldName":"value",...}`
|
|
- Optional `mandateId` query parameter to filter by mandate
|
|
|
|
**Create Request:**
|
|
```
|
|
POST /api/users
|
|
Content-Type: application/json
|
|
Body: {
|
|
"username": "john.doe",
|
|
"email": "john@example.com",
|
|
"fullName": "John Doe",
|
|
"language": "en",
|
|
"enabled": true,
|
|
"privilege": "user",
|
|
"authenticationAuthority": "local",
|
|
"password": "securepassword123"
|
|
}
|
|
```
|
|
- Password is sent as separate field in body (not part of User model)
|
|
- All User model fields sent as User object
|
|
- Handle 403 (permission denied) and 400 (validation errors)
|
|
|
|
**Update Request:**
|
|
```
|
|
PUT /api/users/{userId}
|
|
Content-Type: application/json
|
|
Body: {fieldName: value, ...}
|
|
```
|
|
- Send only changed fields or all form data
|
|
- Handle 403 (permission denied) and 400 (validation errors)
|
|
|
|
**Password Reset Request:**
|
|
```
|
|
POST /api/users/{userId}/reset-password
|
|
Content-Type: application/json
|
|
Body: {"newPassword": "newsecurepassword123"}
|
|
```
|
|
- **Admin-only endpoint**
|
|
- Password must be at least 8 characters
|
|
- Backend automatically revokes all user tokens
|
|
- Handle 403 (permission denied) and 400 (validation errors)
|
|
|
|
**Session Revocation Request:**
|
|
```
|
|
POST /api/admin/tokens/revoke/user
|
|
Content-Type: application/json
|
|
Body: {
|
|
"userId": "user-id-here",
|
|
"authority": "local", // Optional: "local", "google", "msft", or omit for all
|
|
"reason": "Security incident" // Optional reason for audit logging
|
|
}
|
|
```
|
|
- **Admin-only endpoint**
|
|
- `userId` is required
|
|
- `authority` is optional - if omitted, revokes all sessions regardless of authority
|
|
- `reason` is optional - defaults to "admin revoke" if not provided
|
|
- Returns `{"revoked": count}` - number of sessions revoked
|
|
- Handle 403 (permission denied) and 400 (validation errors)
|
|
|
|
**Delete Requests:**
|
|
```
|
|
DELETE /api/users/{userId}
|
|
```
|
|
- Delete operation requires user confirmation
|
|
- Handle 403 (permission denied) and 404 (not found) gracefully
|
|
|
|
### Response Handling
|
|
|
|
**Paginated Response:**
|
|
```json
|
|
{
|
|
"items": [...],
|
|
"pagination": {
|
|
"currentPage": 1,
|
|
"pageSize": 20,
|
|
"totalItems": 45,
|
|
"totalPages": 3,
|
|
"sort": [...],
|
|
"filters": {...}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
- 403 Forbidden → Show permission error message (admin-only actions)
|
|
- 404 Not Found → Show "not found" error message
|
|
- 400 Bad Request → Display validation errors from response
|
|
- 500 Internal Server Error → Show generic error message
|
|
|
|
---
|
|
|
|
## Field and Attribute Reference
|
|
|
|
### Complete Field List
|
|
|
|
The following is a comprehensive list of all parameters, attributes, and fields that will be displayed for users. All of these are provided by the backend through the `/api/attributes/User` endpoint and should never be hardcoded in the frontend.
|
|
|
|
#### Core User Fields
|
|
|
|
**Identification Fields:**
|
|
- `id` - Unique user identifier (text, readonly, not required, visible)
|
|
- `mandateId` - ID of the mandate this user belongs to (text, readonly, not required, visible)
|
|
|
|
**Account Fields:**
|
|
- `username` - Username for login (text, editable, required, visible)
|
|
- `email` - Email address of the user (email, editable, required, visible)
|
|
- `fullName` - Full name of the user (text, editable, not required, visible)
|
|
|
|
**Configuration Fields:**
|
|
- `language` - Preferred language of the user (select, editable, required, visible)
|
|
- Options: "de", "en", "fr", "it"
|
|
- Each option has localized labels (en/fr)
|
|
- `enabled` - Indicates whether the user is enabled (checkbox, editable, not required, visible)
|
|
- `privilege` - Permission level (select, editable, required, visible)
|
|
- Options: "user", "admin", "sysadmin"
|
|
- Each option has localized labels (en/fr)
|
|
- `authenticationAuthority` - Primary authentication authority (select, readonly, not required, visible)
|
|
- Options: "local", "google", "msft"
|
|
- Each option has localized labels (en/fr)
|
|
|
|
**Special Fields (Not in User Model):**
|
|
- `password` - Password field for create forms (password, not in attributes, required for creation)
|
|
- `confirmPassword` - Password confirmation (password, frontend-only, required for creation)
|
|
|
|
### Pagination Parameters
|
|
|
|
**Request Parameters (`PaginationParams`):**
|
|
- `page` - Current page number (1-based, minimum 1)
|
|
- `pageSize` - Number of items per page (minimum 1, maximum 1000)
|
|
- `sort` - Array of sort field configurations
|
|
- Each sort field contains:
|
|
- `field` - Field name to sort by (must match a user field name)
|
|
- `direction` - Sort direction: "asc" or "desc"
|
|
- `filters` - Filter criteria dictionary
|
|
- `search` - General search term (searches across all text fields, case-insensitive)
|
|
- Field-specific filters: `{fieldName: value}` or `{fieldName: {operator: "operator", value: value}}`
|
|
- Supported operators: "equals", "contains", "startsWith", "endsWith", "in", "notIn"
|
|
|
|
**Response Metadata (`PaginationMetadata`):**
|
|
- `currentPage` - Current page number (1-based)
|
|
- `pageSize` - Number of items per page
|
|
- `totalItems` - Total number of items across all pages (after filters applied)
|
|
- `totalPages` - Total number of pages (calculated from totalItems / pageSize)
|
|
- `sort` - Current sort configuration applied (array of SortField objects)
|
|
- `filters` - Current filters applied (mirrors request filters)
|
|
|
|
### Attribute Definition Structure
|
|
|
|
Each field returned from `/api/attributes/User` contains:
|
|
|
|
- `name` - Field name (e.g., "username", "email", "privilege")
|
|
- `type` - Field data type (e.g., "text", "email", "select", "checkbox")
|
|
- `label` - Localized field label (object with language keys: {"en": "English Label", "fr": "French Label"})
|
|
- `description` - Field description text
|
|
- `required` - Boolean indicating if field is required
|
|
- `readonly` - Boolean indicating if field is read-only
|
|
- `editable` - Boolean indicating if field can be edited (inverse of readonly)
|
|
- `visible` - Boolean indicating if field should be displayed in UI
|
|
- `options` - Array of options for select fields (each option has `value` and localized `label`)
|
|
|
|
---
|
|
|
|
## Dynamic Rendering Guidelines
|
|
|
|
The frontend must render all UI components dynamically based on backend metadata. No field definitions, labels, validation rules, or UI structure should be hardcoded.
|
|
|
|
### Table Column Generation
|
|
|
|
When rendering the user list table:
|
|
|
|
1. Fetch attribute definitions from `/api/attributes/User`
|
|
2. Filter attributes where `visible: true` to determine which columns to display
|
|
3. Use `label` property for column headers (select appropriate language based on user preference)
|
|
4. Use `type` property to determine how to format cell values:
|
|
- `text` fields → Display as plain text
|
|
- `email` fields → Display as clickable mailto link
|
|
- `select` fields → Display value using label from options array (match value to option.value, then display option.label)
|
|
- `checkbox` fields → Display as checkmark icon or "Enabled"/"Disabled" text
|
|
5. Use `readonly` property to determine if column should be sortable (readonly fields may still be sortable, but editable fields definitely are)
|
|
6. Generate click handlers for column headers to update sort parameters and refetch data
|
|
|
|
### Filter Control Generation
|
|
|
|
When rendering filter controls:
|
|
|
|
1. Fetch attribute definitions from `/api/attributes/User`
|
|
2. Filter attributes where `visible: true` to determine which filters to show
|
|
3. For each visible field, generate appropriate filter UI based on `type`:
|
|
- `text` fields → Text input filter (supports "contains", "equals", "startsWith", "endsWith" operators)
|
|
- `email` fields → Email input filter
|
|
- `select` fields → Dropdown filter with options from `options` array (use localized labels)
|
|
- `checkbox` fields → Boolean toggle filter (true/false/any)
|
|
4. Use `label` property for filter labels (localized)
|
|
5. When administrator applies filter, update `filters` object in pagination parameters and refetch data
|
|
6. Display active filters as chips/badges showing field label and value
|
|
7. Allow removing individual filters by removing them from `filters` object
|
|
|
|
### Search Implementation
|
|
|
|
For general search functionality:
|
|
|
|
1. Display a single search input box (not field-specific)
|
|
2. When administrator types, update `filters.search` in pagination parameters
|
|
3. Debounce search input (wait 300-500ms after user stops typing before sending request)
|
|
4. Search applies across all text fields in the user object
|
|
5. Reset to page 1 when search query changes
|
|
6. Combine search with field-specific filters (both are in the `filters` object)
|
|
|
|
### Form Field Generation
|
|
|
|
When rendering edit forms:
|
|
|
|
1. Fetch attribute definitions from `/api/attributes/User`
|
|
2. Filter attributes where `visible: true` AND `editable: true` to determine which fields to show
|
|
3. For each editable field, generate appropriate form input based on `type`:
|
|
- `text` fields → Text input
|
|
- `email` fields → Email input
|
|
- `select` fields → Dropdown/select input with options from `options` array (use localized labels)
|
|
- `checkbox` fields → Checkbox input
|
|
4. Use `label` property for field labels (localized)
|
|
5. Use `required` property to show required indicators (asterisk, etc.)
|
|
6. Use `description` property to show help text or tooltips
|
|
7. Validate form before submission:
|
|
- Check all `required: true` fields have values
|
|
- Validate types (e.g., email fields must be valid email format)
|
|
- Validate select fields (value must be in options array)
|
|
8. On submit, send only changed fields or all form data to update endpoint
|
|
|
|
### Create Form Field Generation
|
|
|
|
When rendering create forms:
|
|
|
|
1. Follow same pattern as edit forms for User model fields
|
|
2. **Add password field** (not in User model attributes):
|
|
- Password input field
|
|
- Confirm password input field (frontend-only validation)
|
|
- Both fields required for creation
|
|
- Validate password strength (minimum 8 characters)
|
|
- Validate passwords match
|
|
3. On submit, send User object fields plus `password` as separate field in request body
|
|
|
|
### Display Formatting
|
|
|
|
When displaying field values:
|
|
|
|
1. Use `type` property to determine formatting:
|
|
- `text` → Display as-is (may need HTML escaping)
|
|
- `email` → Display as clickable mailto link
|
|
- `select` → Look up value in `options` array and display localized label
|
|
- `checkbox` → Display as checkmark icon or "Enabled"/"Disabled" text
|
|
2. Handle `null` or `undefined` values gracefully (show "-" or "Not set")
|
|
3. Use `readonly` property to determine if field should show edit indicators
|
|
4. Special formatting for privilege field:
|
|
- Color-code badges (User = blue, Admin = orange, SysAdmin = red)
|
|
- Use localized labels from options
|
|
|
|
### Localization
|
|
|
|
All labels and options support multiple languages:
|
|
|
|
1. Use user's preferred language (from user settings or browser locale)
|
|
2. Access localized labels from `label` object: `label[userLanguage]` or `label.en` as fallback
|
|
3. For select options, use `option.label[userLanguage]` or `option.label.en` as fallback
|
|
4. If label for current language is missing, fall back to English
|
|
|
|
### Key Principles
|
|
|
|
- Never hardcode field names, labels, types, or validation rules
|
|
- Always fetch attribute definitions from backend before rendering UI
|
|
- Use attribute metadata to determine what to display and how to display it
|
|
- Support all field types dynamically - if backend adds new types, frontend should handle them
|
|
- Respect `visible`, `editable`, `readonly`, and `required` flags from backend
|
|
- Use localized labels from backend metadata
|
|
- Generate filters, forms, and tables entirely from attribute definitions
|
|
- When backend adds new fields, frontend should automatically display them without code changes
|
|
- Handle all error cases gracefully (403, 404, 400, 500)
|
|
- Provide user feedback for all actions (loading states, success messages, error messages)
|
|
- **Always check admin privileges before rendering user management UI**
|
|
|
|
---
|
|
|
|
## Admin Access Control
|
|
|
|
### Frontend Access Control
|
|
|
|
The frontend must implement access control to ensure only administrators can access user management pages:
|
|
|
|
**1. Navigation Link Visibility:**
|
|
```typescript
|
|
// Only show user management link if user is admin
|
|
{currentUser?.privilege === 'admin' || currentUser?.privilege === 'sysadmin' ? (
|
|
<NavLink to="/users">Manage Users</NavLink>
|
|
) : null}
|
|
```
|
|
|
|
**2. Route Protection:**
|
|
```typescript
|
|
// Protect route with admin check - single route for all views
|
|
function UserManagementPage() {
|
|
const { currentUser } = useAuth();
|
|
const [view, setView] = useState<'list' | 'detail' | 'edit' | 'create'>('list');
|
|
const [selectedUserId, setSelectedUserId] = useState<string | null>(null);
|
|
|
|
// Check admin status
|
|
if (currentUser?.privilege !== 'admin' && currentUser?.privilege !== 'sysadmin') {
|
|
return <UnauthorizedAccess />;
|
|
}
|
|
|
|
// Render appropriate view based on state
|
|
if (view === 'list') {
|
|
return <ListView onUserSelect={(id) => { setSelectedUserId(id); setView('detail'); }} onCreate={() => setView('create')} />;
|
|
} else if (view === 'detail' && selectedUserId) {
|
|
return <DetailView userId={selectedUserId} onEdit={() => setView('edit')} onBack={() => { setSelectedUserId(null); setView('list'); }} />;
|
|
} else if (view === 'edit' && selectedUserId) {
|
|
return <EditView userId={selectedUserId} onSave={() => setView('detail')} onCancel={() => setView('detail')} />;
|
|
} else if (view === 'create') {
|
|
return <CreateView onSave={(userId) => { setSelectedUserId(userId); setView('detail'); }} onCancel={() => setView('list')} />;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
```
|
|
|
|
**3. Component-Level Checks:**
|
|
```typescript
|
|
// Check admin status before rendering components
|
|
function ListView({ onUserSelect }) {
|
|
const { currentUser } = useAuth();
|
|
|
|
if (currentUser?.privilege !== 'admin' && currentUser?.privilege !== 'sysadmin') {
|
|
return <UnauthorizedAccess />;
|
|
}
|
|
|
|
// Render list view UI
|
|
return (
|
|
<div>
|
|
<Button onClick={() => onUserSelect(null)}>Create User</Button>
|
|
{/* List table */}
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
**4. Error Handling:**
|
|
```typescript
|
|
// Handle 403 errors gracefully
|
|
try {
|
|
const response = await fetch('/api/users/userId/reset-password', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ newPassword })
|
|
});
|
|
|
|
if (response.status === 403) {
|
|
showError('You do not have permission to reset passwords');
|
|
return;
|
|
}
|
|
|
|
// Handle other responses
|
|
} catch (error) {
|
|
showError('Failed to reset password');
|
|
}
|
|
```
|
|
|
|
**5. View State Management:**
|
|
```typescript
|
|
// Manage views within the same page component
|
|
function UserManagementPage() {
|
|
const [view, setView] = useState<'list' | 'detail' | 'edit' | 'create'>('list');
|
|
const [selectedUserId, setSelectedUserId] = useState<string | null>(null);
|
|
|
|
// Switch to detail view
|
|
const handleUserSelect = (userId: string) => {
|
|
setSelectedUserId(userId);
|
|
setView('detail');
|
|
};
|
|
|
|
// Switch to edit view
|
|
const handleEdit = () => {
|
|
setView('edit');
|
|
};
|
|
|
|
// Switch to create view
|
|
const handleCreate = () => {
|
|
setSelectedUserId(null);
|
|
setView('create');
|
|
};
|
|
|
|
// Switch back to list view
|
|
const handleBackToList = () => {
|
|
setSelectedUserId(null);
|
|
setView('list');
|
|
};
|
|
|
|
// Render based on view state
|
|
return (
|
|
<>
|
|
{view === 'list' && <ListView onUserSelect={handleUserSelect} onCreate={handleCreate} />}
|
|
{view === 'detail' && selectedUserId && <DetailView userId={selectedUserId} onEdit={handleEdit} onBack={handleBackToList} />}
|
|
{view === 'edit' && selectedUserId && <EditView userId={selectedUserId} onSave={() => setView('detail')} onCancel={() => setView('detail')} />}
|
|
{view === 'create' && <CreateView onSave={(userId) => { setSelectedUserId(userId); setView('detail'); }} onCancel={handleBackToList} />}
|
|
</>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Admin-Only Actions
|
|
|
|
The following actions are admin-only and should only be available to administrators:
|
|
|
|
- **Reset User Password** (`POST /api/users/{userId}/reset-password`)
|
|
- Only admins can reset other users' passwords
|
|
- Backend enforces this with privilege check
|
|
- Frontend should hide button for non-admins
|
|
|
|
- **User Management Page**
|
|
- The user management page should be admin-only
|
|
- Navigation links should be hidden for non-admins
|
|
- Direct URL access should show unauthorized message for non-admins
|
|
|
|
### Security Best Practices
|
|
|
|
1. **Never trust frontend-only checks** - Backend always enforces permissions
|
|
2. **Handle 403 errors gracefully** - Show appropriate error messages
|
|
3. **Hide UI elements** - Don't show admin actions to non-admins
|
|
4. **Redirect unauthorized access** - Redirect non-admins away from admin pages
|
|
5. **Log security events** - Backend logs admin actions (handled by backend)
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
This document provides complete frontend requirements for all user management pages and components. All requirements follow the principle of **backend-driven UI generation**—no hardcoding of field definitions, labels, or validation rules. The frontend should dynamically generate all UI components from backend metadata provided through the `/api/attributes/User` endpoint.
|
|
|
|
**Critical Security Requirement:** All user management pages are **admin-only**. The frontend must:
|
|
- Check user privileges before rendering navigation links
|
|
- Check user privileges before allowing access to pages
|
|
- Handle 403 Forbidden errors gracefully
|
|
- Never expose user management UI to non-admin users
|
|
|
|
For generic patterns that apply across all entity types (not just users), see the [Dynamic Forms and Pagination documentation](./dynamic-forms-and-pagination.md).
|
|
|