Skip to main content

CTMS RBAC Data Model

This document provides a comprehensive reference for the RBAC (Role-Based Access Control) data model used in the HB Life Science CTMS platform. It covers all roles, resources, actions, and the conventions used for permission record naming.


Overview​

The RBAC system is built on four core DocTypes in Frappe that work together to create a flexible permission matrix:

🔐 Permission = Role + Resource + Action + is_enabled

A permission record defines whether a specific role can perform a specific action on a specific resource.


Core DocTypes​

CTMS Role​

Defines the user roles in the system. Each user is assigned exactly one role.

Role NameDescriptionPrimary Responsibilities
Platform AdministratorFull system accessSystem configuration, user management, all study operations
Study DesignerStudy setup and configurationCreate studies, design CRFs, define protocols
Study CoordinatorDay-to-day study operationsSubject enrollment, data entry, visit scheduling
Data ManagerData quality and exportsQuery resolution, data validation, exports
Medical MonitorSafety oversightReview adverse events, medical data review
AuditorRead-only access for complianceView all data without modification

CTMS Resource​

Resources are the protected entities in the system. Each resource maps to a module or feature area.

CTMS Action​

Actions are the operations that can be performed on resources.

ActionDescriptionTypical Usage
createCreate new recordsAdd buttons, new record forms
readView recordsPage access, data display
updateModify existing recordsEdit buttons, inline editing
deleteRemove single recordsDelete button in table rows
bulk_deleteRemove multiple recordsBulk delete with checkboxes
exportExport dataExport to CSV/Excel buttons
generateGenerate records/reportsGenerate CRF, Generate Report

CTMS Permission​

The junction table that combines Role + Resource + Action with an enabled/disabled flag.


Resource Categories​

Resources are organized into three functional categories for easier navigation:

1. Administration Resources​

System-wide configuration and management resources.

ResourceDescriptionExample Permissions
studyClinical studies/trialsCreate studies, update status, delete
siteTrial sites/locationsAdd sites, assign personnel
personnelStudy team membersAdd coordinators, investigators
reportSystem reportsGenerate enrollment reports

2. Design Resources​

Study design and protocol configuration resources.

ResourceDescriptionExample Permissions
eventsStudy events/visitsDefine screening, week 1, etc.
eligibilityInclusion/exclusion criteriaConfigure eligibility rules
ecrf_designerElectronic CRF builderDesign data collection forms
overviewStudy overview/dashboardView study summary

3. Execution Resources​

Day-to-day study operations resources.

ResourceDescriptionExample Permissions
subjectStudy subjects (participants)Enroll, update status, withdraw
patientPatient master recordsCreate patient records
crfCase Report Form dataEnter CRF data
consentConsent formsRecord consent
demographicsSubject demographicsView/edit demographics
vitalsVital signsRecord vitals
physical_examinationPhysical exam findingsRecord exam data
adverse_eventsAdverse event reportsReport AEs, update severity
family_medical_historyFamily health historyRecord family history
social_historySocial historyRecord lifestyle data
medical_historyMedical historyRecord past conditions
concomitant_medicationsConcurrent medicationsRecord medications
prescriptionsStudy drug prescriptionsIssue prescriptions
lab_ordersLaboratory ordersOrder lab tests
lab_resultsLaboratory resultsView/enter results
study_siteStudy-site relationshipsAssign sites to studies
study_subjectStudy-subject relationshipsManage subject enrollment

Complete Resource Reference​

All resources currently defined in the system:

const ALL_RESOURCES = [
// Administration
'study',
'site',
'personnel',
'report',

// Design
'events',
'eligibility',
'ecrf_designer',
'overview',

// Execution
'subject',
'patient',
'crf',
'consent',
'demographics',
'vitals',
'physical_examination',
'adverse_events',
'family_medical_history',
'social_history',
'medical_history',
'concomitant_medications',
'prescriptions',
'lab_orders',
'lab_results',
'study_site',
'study_subject'
];

Naming Conventions​

Permission Record Names​

Each permission record follows a strict naming convention:

{Role}-{resource}-{action}

Examples:

  • Platform Administrator-study-create
  • Study Designer-events-update
  • Study Coordinator-subject-bulk_delete
  • Data Manager-crf-export
  • Auditor-adverse_events-read

Key Rules​

RuleDescriptionExample
Role namesUse display name with spaces"Study Coordinator" not "study_coordinator"
Resource namesUse snake_case"adverse_events" not "AdverseEvents"
Action namesUse snake_case"bulk_delete" not "bulkDelete"
SeparatorSingle hyphen between partsRole-resource-action

Name Parsing​

The permission name can be parsed to extract components:

function parsePermissionName(name: string) {
// Find last two hyphens (action is last, resource is second-to-last)
const lastHyphen = name.lastIndexOf('-');
const secondLastHyphen = name.lastIndexOf('-', lastHyphen - 1);

return {
role: name.substring(0, secondLastHyphen), // "Study Coordinator"
resource: name.substring(secondLastHyphen + 1, lastHyphen), // "subject"
action: name.substring(lastHyphen + 1) // "bulk_delete"
};
}

Permission Matrix​

Matrix Structure​

Permissions are organized into a 3-dimensional matrix:

Role → Resource → Action → is_enabled

Example for Study Coordinator:

Resourcecreatereadupdatedeletebulk_deleteexport
subject✅✅✅❌❌❌
crf✅✅✅❌❌❌
vitals✅✅✅✅❌❌
study❌✅❌❌❌❌

Total Permission Records​

The total number of permission records is calculated as:

Total = Roles × Resources × Actions
= 6 × 21 × 8
= ~1,008 possible combinations

However, not all combinations are meaningful. The actual number of records depends on which resources support which actions.


Action Availability by Resource​

Not all actions apply to all resources. Here's the typical action availability:

Full CRUD Resources​

Resources that support all actions:

  • subject, patient, site, personnel
  • vitals, adverse_events, prescriptions
  • lab_orders, lab_results
Actions: create, read, update, delete, bulk_delete, export

Read-Heavy Resources​

Resources with limited write actions:

  • report (read, generate)
  • overview (read only)

Design Resources​

Resources for study configuration:

  • events, eligibility, ecrf_designer
  • Actions: create, read, update, delete

Role Permission Patterns​

Platform Administrator​

Full access to everything:

All Resources → All Actions → is_enabled: true

Study Designer​

Focus on study setup and design:

Administration: Full CRUD
Design: Full CRUD
Execution: Read only (mostly)

Study Coordinator​

Focus on day-to-day operations:

Administration: Read only
Design: Read only
Execution: Full CRUD (except delete for sensitive data)

Auditor​

Read-only across the board:

All Resources → read → is_enabled: true
All Resources → other actions → is_enabled: false

API Reference​

Fetch All Permissions​

GET /api/v1/doctype/CTMS Permission
?limit_page_length=0
&fields=["name","role","resource","action","is_enabled"]

Fetch Permissions by Role​

GET /api/v1/doctype/CTMS Permission
?filters=[["role","=","Study Coordinator"]]
&limit_page_length=0

Update Permission​

PUT /api/v1/doctype/CTMS Permission/{name}
Content-Type: application/json

{
"is_enabled": 1
}

Batch Create Permissions​

# Using the bot_sync_permissions_to_frappe.py script
python scripts/bot_sync_permissions_to_frappe.py

Database Schema​

The underlying Frappe database tables:

tabCTMS Role​

ColumnTypeDescription
nameVARCHAR(140)Primary key (role name)
descriptionTEXTRole description
creationDATETIMECreated timestamp
modifiedDATETIMELast modified

tabCTMS Resource​

ColumnTypeDescription
nameVARCHAR(140)Primary key (resource name)
descriptionTEXTResource description
categoryVARCHAR(140)Administration, Design, Execution
display_orderINTSort order in UI

tabCTMS Action​

ColumnTypeDescription
nameVARCHAR(140)Primary key (action name)
descriptionTEXTAction description

tabCTMS Permission​

ColumnTypeDescription
nameVARCHAR(140)Primary key (Role-resource-action)
roleVARCHAR(140)Foreign key to CTMS Role
resourceVARCHAR(140)Foreign key to CTMS Resource
actionVARCHAR(140)Foreign key to CTMS Action
is_enabledINT0 = disabled, 1 = enabled

Seeding Permissions​

When setting up a new environment, the complete RBAC configuration is seeded from the baseline application using a single Python script. The seed data includes all roles, resources, actions, and the full 488-entry permission matrix.

Dual Role System

Frappe has two role systems that must both be populated:

  • Frappe native Role DocType — Used by Frappe's User system to assign roles via Link fields (required for user signup/creation)
  • CTMS Role custom DocType — Used by the CTMS RBAC permission matrix to control resource access

Stage 3 creates entries in both DocTypes. All 4 roles (Platform Administrator, Study Designer, Study Coordinator, Principal Investigator) are created with desk_access=1 and disabled=0 in the native Role DocType.

# Full setup — DocTypes + all seed data
cd ctms.devops/scripts/frappe-seed
python frappe_seed_rbac.py --all --env ../../.env.example

The seeder is idempotent — it uses upsert logic to create missing records, update records that differ from the baseline, and skip records that are already correct. See Initial Setup — Step 4.1 for the full setup guide with CLI options and prerequisites.

Permission Matrix Structure​

The permission matrix is defined as a list of tuples in the seed script, with one entry per role × resource × action combination:

# (role, resource, action, is_enabled, sort_order)
PERMISSIONS = [
("Platform Administrator", "study", "create", 1, 1),
("Platform Administrator", "study", "read", 1, 2),
("Platform Administrator", "study", "update", 1, 3),
("Study Designer", "study", "create", 1, 1),
("Study Designer", "study", "read", 1, 2),
# ... 488 total entries covering all 4 roles × 24 resources × 8 actions
]

Each entry generates a CTMS Permission record in Frappe with the naming convention:

{Role}-{resource}-{action}

For example: Platform Administrator-study-create.

Baseline Data Totals​

DocTypeCount
Role (Frappe native)4
CTMS Role4
CTMS Resource24
CTMS Action8
CTMS Permission488

Troubleshooting​

Permission Record Not Found​

If the UI shows "Permission record not found":

  1. Check if the record exists in Frappe: https://your-frappe-url/app/ctms-permission
  2. Re-run the seed script: python frappe_seed_rbac.py --seed-defaults --env ../../.env.example
  3. Verify the naming convention matches (Role-resource-action)

Permission Not Working​

If permission changes don't take effect:

  1. Clear browser cache (permissions may be cached client-side)
  2. Check API response for cache headers
  3. Verify is_enabled is set to 1 (not 0)

Missing Resource in UI​

If a resource doesn't appear in the permission management UI:

  1. Verify the CTMS Resource record exists in Frappe
  2. Check that the resource has a category assigned (Administration, Design, or Execution)
  3. Re-run the seed script to create any missing records

Environment Sync Drift​

If an environment's RBAC data has drifted from the baseline:

  1. Run the seed with --dry-run to preview differences:
    python frappe_seed_rbac.py --seed-defaults --dry-run --env ../../.env.example
  2. Run without --dry-run to apply corrections — the upsert logic will update only the records that differ