Users, Roles, and Organizations
Introduction
This document describes organization onboarding, user management, role and permission management, and organization profile behavior.
Main Files
| File | Responsibility |
|---|---|
pages/LoginPage.tsx | Login entry point |
modules/onboarding/pages/OrganizationRegistrationPage.tsx | Public organization registration |
modules/onboarding/pages/AdminUserRegistrationPage.tsx | User creation during onboarding |
modules/users/pages/UserListPage.tsx | Organization user list route, permissions, and dialog orchestration |
modules/users/partials/UserListTable.tsx | User table and row actions |
modules/users/dialogs/CreateUserDialog.tsx | Create user dialog |
modules/users/dialogs/EditUserDialog.tsx | Edit user dialog |
modules/roles/pages/RoleListPage.tsx | Role list route, permissions, and dialog orchestration |
modules/roles/partials/RoleListTable.tsx | Role table and row actions |
modules/roles/dialogs/CreateRoleDialog.tsx | Create role dialog with permissions |
modules/roles/dialogs/EditRoleDialog.tsx | Edit role dialog with permissions |
modules/organizations/pages/OrganizationDetailPage.tsx | Current organization detail page |
modules/organizations/dialogs/EditOrganizationDialog.tsx | Organization edit dialog |
modules/organizations/pages/ProfilePage.tsx | Current user profile |
modules/organizations/dialogs/EditProfileDialog.tsx | Current user profile edit dialog |
hooks/useApi.ts | User, role, organization, permission hooks |
lib/api.ts | user, role, permission, organization, and location endpoint groups |
Organization Onboarding
/register/user-form
- Load Provinces:
OrganizationFormloads provinces withapi.location.getProvinces(). - Load Cities: When a province is selected, it loads cities with
api.location.getCitiesByProvince(provinceId). - Submit: The organization form submits to
api.organization.create(...). - Backend Response: The backend response is expected to include
organizationandadminRole. - Navigation: The app navigates to
/user-formand passes organization/admin role data in route state. - User Creation:
UserFormcreates the initial user for that organization.
Organization create payload maps UI field names to backend field names:
| UI Field | Submitted Field |
|---|---|
phone_number | phoneNumber |
province | province |
city | city |
oinkcode | oinkcode |
parentId | null |
User Management
- Route:
/dashboard/user - Component:
AllUser
- Context Initialization: Reads current organization/user IDs from auth cookies.
- Data Loading: Loads users with
useOrganizationUsers([deletionFlag, createFlag, editFlag]). - Permission Check: Loads permissions through
useUserPermissions(). - Action Visibility: Shows create, edit, and delete actions according to permissions.
- Validation: Prevents deleting the current user in the UI.
- Form Handling: Uses
CreateUserandEditUserinside dialogs. - State Management: Toggles local flags after create/edit/delete to trigger hook refetch.
API endpoints:
| Operation | API Call |
|---|---|
| List | api.user.getAll() |
| Paginated list | api.user.getPaginated(params) |
| Get one | api.user.get(userId) |
| Create | api.user.create(data) |
| Update | api.user.update(userId, data) |
| Delete | api.user.delete(userId) |
Role Management
- Route:
/dashboard/role - Component:
AllRole
- Data Loading: Loads roles with
useRoles([deletionFlag, createFlag, editFlag]). - Context Check: Fetches current user through
api.auth.me()to identify the current role ID. - Action Visibility: Shows create, edit, and delete actions according to permissions.
- Validation: Prevents deleting the current user's active role in the UI.
- Form Handling: Uses
CreateRoleandEditRoleinside dialogs. - Metrics: Displays permission counts on the list.
Role forms load the permission catalog through api.permission.getAll() and submit selected permission IDs.
API endpoints:
| Operation | API Call |
|---|---|
| List | api.role.getAll() |
| Paginated list | api.role.getPaginated(params) |
| Get one | api.role.get(roleId) |
| Create | api.role.create(data) |
| Update | api.role.update(roleId, data) |
| Delete | api.role.delete(roleId) |
| Permissions | api.permission.getAll() |
Organization Detail
- Route:
/dashboard/organization - Component:
OrganizationDetail
- Context Initialization: Reads current user ID from cookies.
- Data Loading: Calls
useUser(userId, [editFlag]). - Data Mapping: Reads
user.organization. - Render Details: Displays organization name, email, phone, address, province, and city.
- Action Visibility: Shows edit action only when the user has
edit-organization. - Form Handling: Opens
EditOrganizationin a dialog and refetches after closing.
Profile
- Route:
/dashboard/profile
The profile screen displays and edits the current user profile. It follows the same pattern as organization detail: fetch current user, render read-only details, open edit dialog, then refetch after successful edit.
Permissions
Management screens use these slugs:
| Area | Create | Edit | Delete | Read |
|---|---|---|---|---|
| Users | create-user | edit-user | delete-user | read-user |
| Roles | create-role | edit-role | delete-role | read-role |
| Organization | n/a | edit-organization | n/a | n/a |
The backend remains the source of truth for authorization.
Failure Modes
| Scenario | Frontend Behavior |
|---|---|
| Province/city load fails | Error alert is shown and form stays usable |
| Organization create returns invalid data | Throws an error and stops onboarding navigation |
| User/role list load fails | Hook logs error and exposes empty fallback arrays |
| Delete fails | Error alert is shown |
| Permission fetch fails | Action buttons are hidden because permissions become empty |
| Current role/user ID is missing | Current-user delete prevention may not apply |