-- ordinary record: is the clinical summary card shown only to clinicians? -- role open can-clin card verdict billing_officer ok no hidden consistent clinical_officer ok yes shown consistent consultant ok yes shown consistent doctor ok yes shown consistent finance_manager ok no hidden consistent hospital_administrator ok no hidden consistent icu_nurse ok yes shown consistent lab_technician ok no hidden consistent medical_coder ok no hidden consistent nurse ok yes shown consistent patient ok no hidden consistent pharmacist ok no hidden consistent radiologist ok yes shown consistent receptionist ok no hidden consistent store_keeper ok no hidden consistent system_administrator ok yes shown consistent -- confidential record: only restricted-access holders may open it -- role result expected note billing_officer deny deny clinical_officer deny deny consultant allow allow doctor allow allow finance_manager deny deny hospital_administrator allow allow icu_nurse deny deny lab_technician deny deny medical_coder deny deny nurse deny deny patient deny deny pharmacist deny deny radiologist deny deny receptionist deny deny store_keeper deny deny system_administrator allow allow -- restricted record: printed artefacts (a wristband names the patient too) -- artefact doctor receptionist note card ok HTTP 404 wristband ok HTTP 404 barcode ok HTTP 404 -- restricted record: the list and the CSV must both omit it -- surface doctor receptionist note index ok/has ok/omits export ok/has ok/omits -- every GET route must sit behind auth + a permission -- routes reachable without auth: home [web] public by design (guest): register, login, password.request, password.email, password.reset, password.store -- roles reaching routes they lack the permission for -- role view-clinical view-restricted manage-confidentiality view billing_officer - - NO yes clinical_officer yes - NO yes consultant yes yes yes yes doctor yes yes yes yes finance_manager - - NO yes hospital_administrator - yes yes yes icu_nurse yes - NO - lab_technician - - NO - medical_coder - - NO yes nurse yes - NO - patient - - NO - pharmacist - - NO yes radiologist yes - NO - receptionist - - yes yes store_keeper - - NO - system_administrator yes yes yes yes -- write paths as reception@hms.test -- contact.store (valid guardian) OK created=yes contact.store (bogus relation) OK rejected on: relationship document.store (bogus type) OK rejected on: document_type, file patient.store (bogus blood grp) OK rejected on: blood_group patient.store (valid) OK mrn=MRN-26-00024 -- front-desk tagging: may the clerk classify, and then still reach the record? -- receptionist offers 4/4 restricted tags doctor offers 4/4 restricted tags clerk tags medico_legal OK saved=medico_legal redirect=index clerk reopens what it just made HTTP 404 (expected HTTP 404) doctor opens the tagged record ok (expected ok) doctor's edit form keeps the tag yes doctor saves edit, tag preserved OK -- module routes: is every one behind a permission that exists? -- 60 module routes | without a can: gate: none | naming a permission that does not exist: none -- EMR routes grouped by the permission they demand, and who holds it -- allergies.manage 3 route(s) patients.allergies.destroy patients.allergies.store patients.allergies.update holders: clin-officer consultant doctor icunurse nurse sysadmin diagnoses.create 1 route(s) encounters.diagnoses.store holders: clin-officer consultant doctor sysadmin diagnoses.edit 2 route(s) encounters.diagnoses.destroy encounters.diagnoses.update holders: clin-officer consultant doctor sysadmin emr.view 1 route(s) patients.clinical holders: clin-officer consultant doctor icunurse nurse sysadmin encounters.close 1 route(s) encounters.close holders: clin-officer consultant doctor sysadmin encounters.create 4 route(s) encounters.create encounters.edit encounters.store encounters.update holders: clin-officer consultant doctor sysadmin encounters.view 3 route(s) encounters.index encounters.show worklist.index holders: clin-officer consultant doctor hospadmin icunurse coder nurse sysadmin icd10.view 1 route(s) icd10.search holders: clin-officer consultant doctor coder sysadmin medical-history.manage 3 route(s) patients.histories.destroy patients.histories.store patients.histories.update holders: clin-officer consultant doctor nurse sysadmin notes.create 1 route(s) encounters.notes.store holders: clin-officer consultant doctor icunurse nurse sysadmin notes.edit 1 route(s) encounters.notes.update holders: clin-officer consultant doctor sysadmin notes.sign 1 route(s) encounters.notes.sign holders: consultant doctor sysadmin problem-list.manage 3 route(s) patients.problems.destroy patients.problems.store patients.problems.update holders: clin-officer consultant doctor nurse sysadmin vitals.record 2 route(s) encounters.vitals.destroy encounters.vitals.store holders: clin-officer consultant doctor icunurse nurse sysadmin -- every can: gate in the whole app names a real permission -- none -- navigation entries name a registered route and a real permission -- unregistered routes: Clinical / Prescriptions -> prescriptions.index, Clinical / Ward Board -> admissions.index, Clinical / Bed Management -> beds.index, Clinical / ICU -> icu.index, Clinical / Discharge Summaries -> discharge-summaries.index, Clinical / Immunization -> immunizations.index, Diagnostics / Laboratory -> lab-orders.index, Diagnostics / Radiology -> radiology.index, Diagnostics / Test Catalogue -> lab-catalogue.index, Pharmacy & Stores / Dispensing -> pharmacy.dispense.index, Pharmacy & Stores / Point of Sale -> pharmacy.sales.index, Pharmacy & Stores / Drug Formulary -> drugs.index, Pharmacy & Stores / Stock Items -> inventory.items.index, Pharmacy & Stores / Batches & Expiry -> inventory.batches.index, Pharmacy & Stores / Purchase Orders -> inventory.purchase-orders.index, Pharmacy & Stores / Stock Requisitions -> inventory.requisitions.index, Pharmacy & Stores / Suppliers -> inventory.suppliers.index, Billing & Insurance / Invoices -> billing.invoices.index, Billing & Insurance / Payments -> billing.payments.index, Billing & Insurance / Outstanding Bills -> billing.outstanding, Billing & Insurance / Cash Shifts -> billing.cash-shifts.index, Billing & Insurance / Preauthorization -> insurance.preauth.index, Billing & Insurance / Claims -> insurance.claims.index, Billing & Insurance / Payers & Schemes -> insurance.payers.index, Billing & Insurance / Charge Master -> billing.charge-items.index, Communication / Message Log -> communication.messages.index, Communication / Inbox -> communication.inbox, Communication / Templates -> communication.templates.index, Communication / Campaigns -> communication.campaigns.index, Reporting & ERP / Reports -> reports.index, Reporting & ERP / Expenses -> erp.expenses.index, Reporting & ERP / Chart of Accounts -> erp.accounts.index, Reporting & ERP / Journal Entries -> erp.journals.index, Reporting & ERP / Payroll -> erp.payroll.index, Reporting & ERP / Vaccination Coverage -> reports.vaccination, Patient Portal / My Health Record -> portal.home, Administration / Wards & Rooms -> admin.wards.index | unknown permissions: none -- an appointment and a queue token for a restricted patient -- role show expected on board expected note billing_officer HTTP 404 HTTP 404 omits omits clinical_officer HTTP 404 HTTP 404 omits omits consultant ok ok listed listed doctor ok ok listed listed finance_manager HTTP 404 HTTP 404 omits omits hospital_administrator ok ok listed listed icu_nurse HTTP 404 HTTP 404 omits omits lab_technician HTTP 404 HTTP 404 omits omits medical_coder HTTP 404 HTTP 404 omits omits nurse HTTP 404 HTTP 404 omits omits patient HTTP 404 HTTP 404 omits omits pharmacist HTTP 404 HTTP 404 omits omits radiologist HTTP 404 HTTP 404 omits omits receptionist HTTP 404 HTTP 404 omits omits store_keeper HTTP 404 HTTP 404 omits omits system_administrator ok ok listed listed -- token transitions as the clinic desk -- role call-next manage check-in note billing_officer no no no clinical_officer yes no no consultant yes yes no doctor yes no no finance_manager no no no hospital_administrator yes yes yes icu_nurse no no no lab_technician no no no medical_coder no no no nurse yes yes yes patient no no no pharmacist no no no radiologist no no no receptionist yes yes yes store_keeper no no no system_administrator yes yes yes -- EMR fixtures: the doctor opens a record; a restricted one is planted -- doctor opens an encounter OK ENC-20260925-0003 for MRN-2026-000001 -- the encounter workspace: which panels reach which role -- role open vitals dx notes safety note billing_officer ok hidden hidden hidden hidden consistent clinical_officer ok shown shown shown shown consistent consultant ok shown shown shown shown consistent doctor ok shown shown shown shown consistent finance_manager ok hidden hidden hidden hidden consistent hospital_administrator ok hidden hidden hidden hidden consistent icu_nurse ok shown shown shown shown consistent lab_technician ok hidden hidden hidden hidden consistent medical_coder ok hidden shown shown hidden consistent nurse ok shown shown shown shown consistent patient ok hidden hidden hidden hidden consistent pharmacist ok hidden hidden hidden hidden consistent radiologist ok hidden hidden hidden hidden consistent receptionist ok hidden hidden hidden hidden consistent store_keeper ok hidden hidden hidden hidden consistent system_administrator ok shown shown shown shown consistent -- the clinical hub: which panels reach which role -- role open vitals dx meds encounters note billing_officer ok hidden hidden hidden hidden consistent clinical_officer ok shown shown shown shown consistent consultant ok shown shown shown shown consistent doctor ok shown shown shown shown consistent finance_manager ok hidden hidden hidden hidden consistent hospital_administrator ok hidden hidden hidden shown consistent icu_nurse ok shown shown shown shown consistent lab_technician ok hidden hidden hidden hidden consistent medical_coder ok hidden shown hidden shown consistent nurse ok shown shown shown shown consistent patient ok hidden hidden hidden hidden consistent pharmacist ok hidden hidden hidden hidden consistent radiologist ok hidden hidden hidden hidden consistent receptionist ok hidden hidden hidden hidden consistent store_keeper ok hidden hidden hidden hidden consistent system_administrator ok shown shown shown shown consistent -- a restricted patient's encounter and hub -- role enc.show expected hub expected note billing_officer HTTP 404 HTTP 404 HTTP 404 HTTP 404 clinical_officer HTTP 404 HTTP 404 HTTP 404 HTTP 404 consultant ok ok ok ok doctor ok ok ok ok finance_manager HTTP 404 HTTP 404 HTTP 404 HTTP 404 hospital_administrator ok ok ok ok icu_nurse HTTP 404 HTTP 404 HTTP 404 HTTP 404 lab_technician HTTP 404 HTTP 404 HTTP 404 HTTP 404 medical_coder HTTP 404 HTTP 404 HTTP 404 HTTP 404 nurse HTTP 404 HTTP 404 HTTP 404 HTTP 404 patient HTTP 404 HTTP 404 HTTP 404 HTTP 404 pharmacist HTTP 404 HTTP 404 HTTP 404 HTTP 404 radiologist HTTP 404 HTTP 404 HTTP 404 HTTP 404 receptionist HTTP 404 HTTP 404 HTTP 404 HTTP 404 store_keeper HTTP 404 HTTP 404 HTTP 404 HTTP 404 system_administrator ok ok ok ok -- the EMR write paths -- nurse records observations OK abnormal=flagged bmi=26.37 nurse posts an empty reading OK refused: rejected: temperature nurse posts a 60°C temperature OK refused: rejected: temperature doctor records two diagnoses OK 2 on the encounter, 1 primary doctor codes a 'wizard' diagnosis OK refused: rejected: diagnosis_type nurse writes a SOAP note OK status=draft nurse ticks "sign" on a note OK status=draft signed_by=null doctor writes and signs a note OK status=signed locked=yes doctor rewrites a signed note OK refused (ok) nurse records an allergy OK on file=yes nurse grades it 'catastrophic' OK refused: rejected: severity doctor adds and resolves a problem OK status=resolved resolved_on=2026-09-25 doctor triages it 'medium' OK refused: rejected: priority nurse records past surgery OK on file=yes nurse files it 'past_life' OK refused: rejected: history_type clerk charts on a restricted case OK (expected HTTP 404) doctor closes the encounter OK status=closed nurse deletes a closed chart OK the observation survived access-log rows written by the probes 44 fixtures removed; patients remaining: 1 >>> no page-level access-control problems