FHIR Complete

Roles & Permissions

Multi-role privilege-based access control system

Overview

The system uses a multi-role, privilege-based access control system. Users can have multiple roles per organization, and each role maps to a set of privileges.

Roles

RoleDescription
doctorHealthcare practitioner — clinical access
managerAdministrative manager — operations
receptionistFront desk staff — scheduling, patient intake
adminSystem administrator — full access
nurseNursing staff — clinical support
pharmacistPharmacy staff — medication management
lab_techLaboratory technician — lab operations
hr_adminHR administrator — workforce management

Privileges

PrivilegeDescription
view_patientsView patient list and details
manage_patientsCreate and edit patient records
manage_encountersStart/end encounters, clinical documentation
manage_medicationsPrescribe and manage medications
manage_appointmentsSchedule and manage appointments
view_reportsAccess analytics and reports
manage_organizationEdit organization settings
manage_rolesGrant/revoke roles for other users
manage_hrHR workforce management
manage_inventoryInventory management
view_inventoryView inventory data
dispense_medicationDispense medications from pharmacy
manage_billingBilling and invoicing
manage_documentsDocument management
manage_communicationMessaging and communication

Permission Matrix

Patient Permissions

ActionDoctorManagerReceptionistAdmin
View patient listYYYY
View patient detailsYYYY
Create patientY-YY
Edit patientY-YY
Delete patient---Y
View medical historyY--Y

Clinical Permissions

ActionDoctorNursePharmacistAdmin
Start encounterY--Y
Write clinical notesYY-Y
Prescribe medicationY--Y
Dispense medication--YY
Order lab testsY--Y
View lab resultsYY-Y

How Roles Resolve

A user holds a set of roles per organization, not a single role — someone can be a doctor and an HR administrator in the same place, and a different thing again in another organization.

Roles are not checked directly at the point of use. Each role maps to a set of privileges, and the application authorizes against the privilege:

roles: ["doctor", "hr_admin"]
     ↓ resolved at login
privileges: ["view_patients", "manage_encounters", "manage_hr", ...]

Both the roles and the resolved privileges are carried in the access token, so a client can render the right UI without asking, and the server never has to re-derive them per request.

The indirection is the point: adding a capability to a role changes one mapping rather than every call site that would otherwise be testing role === "doctor".

Auditing

Every grant and revoke is recorded — who was changed, which role, who made the change, in which organization, and when. Role changes are not silent.

Frontend Usage

import { usePermissions } from '@/hooks/usePermissions';
 
function MyComponent() {
  const { hasPrivilege, isDoctor, isAdmin } = usePermissions();
 
  return (
    <>
      {hasPrivilege('manage_encounters') && <StartEncounterButton />}
      {hasPrivilege('manage_roles') && <SecurityLink />}
    </>
  );
}

Security Page

The /security page (requires manage_roles privilege) allows:

  • Viewing all staff members and their roles
  • Granting/revoking roles per user
  • Viewing audit log of role changes