Permissions¶
The admin dashboard uses react-admin RBAC permissions loaded from the backend to control UI visibility.
Permission Format¶
Permissions are loaded from GET /api/v1/users/me as an array:
interface Permission {
action: string | string[];
resource: string;
type?: "deny";
record?: { id: string };
}
Examples:
[
{"action": "list", "resource": "borrowers"},
{"action": ["show", "edit"], "resource": "loans"},
{"action": "*", "resource": "*"},
{"type": "deny", "action": "show", "resource": "borrowers", "record": {"ssn": true}}
]
hasPermission() Utility¶
The core permission-checking function:
function hasPermission(
permissions: Permission[] | undefined,
action: string,
resource: string,
): boolean
Logic:
- Returns
falseif permissions is undefined - Iterates through permissions, skipping any with
type: "deny" - Checks if the permission's action matches (supports
"*"wildcard) - Checks if the permission's resource matches (supports
"*"wildcard) - Returns
trueif any permission matches
Superadmins receive {"action": "*", "resource": "*"} which matches everything.
Menu Gating¶
The sidebar menu uses permissions to conditionally render items:
function Menu() {
const { permissions } = usePermissions<Permission[]>();
const can = (resource: string) =>
canAccessResource(permissions, resource);
return (
<RaMenu>
{can("borrowers") && (
<RaMenu.ResourceItem name="borrowers" />
)}
{can("loans") && (
<RaMenu.ResourceItem name="loans" />
)}
</RaMenu>
);
}
The helper canAccessResource() checks for either "list" or "show" action on the resource.
Resource Screen Gating¶
Within resource screens, permissions control action buttons and form fields:
function LoanShow() {
const { permissions } = usePermissions<Permission[]>();
return (
<Show>
<SimpleShowLayout>
<TextField source="loan_number" />
{hasPermission(permissions, "approve", "loans") && (
<ActionButton action="approve" label="Approve" />
)}
</SimpleShowLayout>
</Show>
);
}
Permission Sources¶
The backend merges three sources into the final permission array:
- Tenant role mapping --- Role-based defaults from
common/rbac.py - Django auth permissions --- Group and Permission model assignments
- Object-level grants --- django-guardian per-object access
Role Hierarchy¶
| Role | Access Level |
|---|---|
viewer |
Read-only access to all resources |
collector |
Viewer + collection actions, cases |
loan_officer |
Collector + loan origination, servicing, borrower management |
admin |
Loan officer + user management, configuration, GL operations |
superadmin |
Full access (wildcard *) |
Field-Level Deny¶
SSN access is denied for all roles via a deny permission:
This prevents the SSN field from being displayed in borrower detail views.
See Also¶
- Users API ---
/users/meendpoint and permission format - Auth Provider --- How permissions are loaded