Roles and Permissions Configuration Guide¶
Overview¶
This document provides a comprehensive guide to configuring user roles and permissions in CHAVI-PROM. The system uses Django’s built-in groups and permissions system to implement role-based access control (RBAC).
Default User Groups¶
The following standard groups should be created for typical deployments:
Group Name |
Purpose |
|---|---|
Patients |
Access to questionnaires and personal health data |
Healthcare Providers |
View and manage patients within their institution |
Patient Registration Staff |
Register and manage patient information |
Questionnaire Creators |
Create and manage questionnaires and items |
REDCap Data Managers |
Manage REDCap integration and data export |
1. Patients Group¶
Purpose: Allow patients to complete questionnaires and view their own data.
Required Permissions¶
Permission |
Purpose |
|---|---|
|
See questionnaires assigned to them |
|
Submit responses to questions |
|
Create new submissions |
Configuration¶
from django.contrib.auth.models import Group, Permission
patients_group = Group.objects.create(name='Patients')
# Add permissions
patients_group.permissions.add(
Permission.objects.get(codename='view_patientquestionnaire'),
Permission.objects.get(codename='add_questionnaireitemresponse'),
Permission.objects.get(codename='add_questionnairesubmission'),
)
2. Healthcare Providers Group¶
Purpose: Enable healthcare providers to view and manage patients within their institution.
Core Permissions¶
Permission |
Purpose |
|---|---|
|
View patient information and lists |
|
See assigned questionnaires |
|
Assign questionnaires to patients |
|
Review patient responses |
|
See completed submissions |
Optional Clinical Permissions (Role-Based)¶
Permission |
Purpose |
|---|---|
|
Add diagnoses to patients |
|
Update patient diagnoses |
|
Add treatments to diagnoses |
|
Update patient treatments |
|
Assign patients to projects |
Configuration¶
providers_group = Group.objects.create(name='Healthcare Providers')
# Core permissions
providers_group.permissions.add(
Permission.objects.get(codename='view_patient'),
Permission.objects.get(codename='view_patientquestionnaire'),
Permission.objects.get(codename='add_patientquestionnaire'),
Permission.objects.get(codename='view_questionnaireitemresponse'),
Permission.objects.get(codename='view_questionnairesubmission'),
)
# Optional clinical permissions
providers_group.permissions.add(
Permission.objects.get(codename='add_diagnosis'),
Permission.objects.get(codename='change_diagnosis'),
Permission.objects.get(codename='add_treatment'),
Permission.objects.get(codename='change_treatment'),
Permission.objects.get(codename='add_patientproject'),
)
Security Notes¶
Warning
Institution-based Access Control: Providers can only view/manage patients from their own institution
No Delete Permissions: Intentionally excluded for data integrity and audit trails
Provider Profile Required: Users must have a Provider profile linked to an Institution
Patient Portal Exclusion: Providers should NOT access the patient portal
3. Patient Registration Staff Group¶
Purpose: Administrative staff for patient registration and data management.
Core Permissions¶
Permission |
Purpose |
|---|---|
|
View existing patients, check for duplicates |
|
Register new patients |
|
Update patient information |
|
See available institutions |
Optional Permissions (Extended Role)¶
Permission |
Purpose |
|---|---|
|
Initial diagnosis entry during registration |
|
Update diagnosis information |
|
See available diagnoses |
|
See available treatment types |
|
Add treatments during registration |
|
Assign patients to projects during registration |
Configuration¶
registration_staff_group = Group.objects.create(name='Patient Registration Staff')
# Core permissions
registration_staff_group.permissions.add(
Permission.objects.get(codename='view_patient'),
Permission.objects.get(codename='add_patient'),
Permission.objects.get(codename='change_patient'),
Permission.objects.get(codename='view_institution'),
)
# Optional permissions for extended registration role
registration_staff_group.permissions.add(
Permission.objects.get(codename='add_diagnosis'),
Permission.objects.get(codename='change_diagnosis'),
Permission.objects.get(codename='view_diagnosislist'),
Permission.objects.get(codename='view_treatmenttype'),
Permission.objects.get(codename='add_treatment'),
Permission.objects.get(codename='add_patientproject'),
)
Security Notes¶
Note
Same institution-based filtering applies as for providers
No questionnaire or response access (clinical data only)
No delete permissions
Limited clinical data access based on optional permissions
Can be combined with
add_diagnosisandadd_treatmentfor comprehensive registration workflow
4. Questionnaire Creators Group¶
Purpose: Create and manage questionnaires, items, and scales.
Required Permissions¶
All permissions need View, Add, and Change for the following models:
Model |
Permission Pattern |
|---|---|
Questionnaire |
|
Item |
|
LikertScale |
|
LikertScaleResponseOption |
|
RangeScale |
|
ConstructScale |
|
QuestionnaireItem |
|
Construct |
|
CompositeConstruct |
|
Configuration¶
creators_group = Group.objects.create(name='Questionnaire Creators')
models = [
'questionnaire', 'item', 'likertscale',
'likertscaleresponseoption', 'rangescale',
'constructscale', 'questionnaireitem',
'construct', 'compositeconstruct'
]
for model in models:
creators_group.permissions.add(
Permission.objects.get(codename=f'view_{model}'),
Permission.objects.get(codename=f'add_{model}'),
Permission.objects.get(codename=f'change_{model}'),
)
Notes¶
Delete permissions not recommended except for privileged users
Permissions also allow adding translations to items
5. REDCap Data Managers Group¶
Purpose: Manage REDCap integration, field mappings, and data export.
Required Permissions¶
Model |
Permissions |
|---|---|
|
|
|
|
|
|
|
|
Configuration¶
from django.contrib.contenttypes.models import ContentType
redcap_managers, _ = Group.objects.get_or_create(name='REDCap Data Managers')
# Add all REDCap permissions
redcap_models = [
'redcapformtoquestionnairemapping',
'redcapfieldtoitemmapping',
'redcapstudyidtopatientidmap',
'redcapinstancetosubmissionmapping',
]
for model in redcap_models:
for action in ['view', 'add', 'change', 'delete']:
try:
perm = Permission.objects.get(
codename=f'{action}_{model}',
content_type__app_label='patientapp'
)
redcap_managers.permissions.add(perm)
except Permission.DoesNotExist:
pass # Model may not exist yet (run migrations first)
REDCap Permission Details¶
Generated Permission Codenames¶
Django automatically creates permissions using the pattern {action}_{modelname}:
view_redcapformtoquestionnairemapping– View form mappingsadd_redcapformtoquestionnairemapping– Create new form mappingschange_redcapformtoquestionnairemapping– Edit form mappingsdelete_redcapformtoquestionnairemapping– Delete form mappingsview_redcapfieldtoitemmapping– View field mappingsadd_redcapfieldtoitemmapping– Create field mappingschange_redcapfieldtoitemmapping– Edit field mappingsdelete_redcapfieldtoitemmapping– Remove field mappingsview_redcapstudyidtopatientidmap– View patient ID mappingsadd_redcapstudyidtopatientidmap– Assign study IDs to patientschange_redcapstudyidtopatientidmap– Edit patient ID mappingsdelete_redcapstudyidtopatientidmap– Clear patient ID mappingsview_redcapinstancetosubmissionmapping– View submission matchesadd_redcapinstancetosubmissionmapping– Create submission matcheschange_redcapinstancetosubmissionmapping– Edit submission matches
Permission Mapping to Operations¶
Operation |
Permission |
Notes |
|---|---|---|
View Form Mappings list |
view_redcapformtoquestionnairemapping |
Required to see form mappings page |
Add Form Mapping |
add_redcapformtoquestionnairemapping |
“Add Form Mapping” button visibility |
Edit Form Mapping |
change_redcapformtoquestionnairemapping |
Edit button + update view access |
Delete Form Mapping |
delete_redcapformtoquestionnairemapping |
Delete button + delete view access |
View Field Mappings |
view_redcapfieldtoitemmapping |
Saved mappings section visibility |
Add Field Mappings |
add_redcapfieldtoitemmapping |
Suggested mappings + Save button |
Edit Field Mapping |
change_redcapfieldtoitemmapping |
Edit row toggle + save |
Delete Field Mapping |
delete_redcapfieldtoitemmapping |
Remove button |
Assign Patient Study ID |
change_redcapstudyidtopatientidmap |
Assign/Edit button |
Match Submissions |
change_redcapinstancetosubmissionmapping |
Match link access |
Clear Patient Mapping |
delete_redcapstudyidtopatientidmap |
Clear button + delete view |
REDCap Role Recommendations¶
Role |
Suggested Permissions |
|---|---|
REDCap Data Manager |
All view/add/change/delete permissions on all 4 models |
Project Coordinator |
view/add/change on Form/Field mappings; view/change on Patient IDs; view on Submission matching |
Research Assistant |
view on all models; change on Patient IDs and Submission matching (for data entry) |
Read-only Auditor |
view permissions only on all models |
Additional Requirements¶
Data export requires staff status (
request.user.is_staff)Grant staff status via Django admin for users who need to export data
Permission Matrix Summary¶
Group |
Patient Data |
Clinical Data |
Questionnaires |
REDCap |
Institution Filter |
|---|---|---|---|---|---|
Patients |
Own data only |
View/Submit |
N/A |
||
Healthcare Providers |
View/Manage |
Diagnosis/Treatment |
View/Assign |
Yes |
|
Patient Registration Staff |
Add/Change |
Optional |
Yes |
||
Questionnaire Creators |
Full CRUD |
No |
|||
REDCap Data Managers |
View |
View |
Full CRUD |
Yes |
Implementation Guide¶
Creating Groups Programmatically¶
Run this in Django shell or as a migration/data script:
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
def setup_groups():
"""Create all standard groups with their permissions."""
# 1. Patients Group
patients, _ = Group.objects.get_or_create(name='Patients')
patient_perms = [
'view_patientquestionnaire',
'add_questionnaireitemresponse',
'add_questionnairesubmission',
]
for codename in patient_perms:
perm = Permission.objects.get(codename=codename)
patients.permissions.add(perm)
# 2. Healthcare Providers Group
providers, _ = Group.objects.get_or_create(name='Healthcare Providers')
provider_perms = [
'view_patient',
'view_patientquestionnaire',
'add_patientquestionnaire',
'view_questionnaireitemresponse',
'view_questionnairesubmission',
# Optional clinical
'add_diagnosis',
'change_diagnosis',
'add_treatment',
'change_treatment',
'add_patientproject',
]
for codename in provider_perms:
perm = Permission.objects.get(codename=codename)
providers.permissions.add(perm)
# 3. Patient Registration Staff Group
registration, _ = Group.objects.get_or_create(name='Patient Registration Staff')
reg_perms = [
'view_patient',
'add_patient',
'change_patient',
'view_institution',
# Optional for comprehensive registration
'add_diagnosis',
'change_diagnosis',
'view_diagnosislist',
'view_treatmenttype',
'add_treatment',
'add_patientproject',
]
for codename in reg_perms:
perm = Permission.objects.get(codename=codename)
registration.permissions.add(perm)
# 4. Questionnaire Creators Group
creators, _ = Group.objects.get_or_create(name='Questionnaire Creators')
models = [
'questionnaire', 'item', 'likertscale',
'likertscaleresponseoption', 'rangescale',
'constructscale', 'questionnaireitem',
'construct', 'compositeconstruct'
]
for model in models:
for action in ['view', 'add', 'change']:
perm = Permission.objects.get(codename=f'{action}_{model}')
creators.permissions.add(perm)
# 5. REDCap Data Managers Group
redcap, _ = Group.objects.get_or_create(name='REDCap Data Managers')
redcap_models = [
'redcapformtoquestionnairemapping',
'redcapfieldtoitemmapping',
'redcapstudyidtopatientidmap',
'redcapinstancetosubmissionmapping',
]
for model in redcap_models:
for action in ['view', 'add', 'change', 'delete']:
try:
perm = Permission.objects.get(
codename=f'{action}_{model}',
content_type__app_label='patientapp'
)
redcap.permissions.add(perm)
except Permission.DoesNotExist:
pass
print("All groups and permissions configured successfully!")
# Run the setup
setup_groups()
Assigning Users to Groups¶
Via Django Admin:
Go to
/admin/auth/user/Select user
Add to groups in the “Groups” section
Or programmatically:
from django.contrib.auth.models import User, Group
user = User.objects.get(username='john_doe')
providers_group = Group.objects.get(name='Healthcare Providers')
user.groups.add(providers_group)
Best Practices¶
DO:¶
Use Django groups for role-based access
Apply principle of least privilege
Test permissions thoroughly
Document permission requirements
Use institution-based filtering for providers and registration staff
Grant
add_diagnosisandadd_treatmentto registration staff for comprehensive intake workflow
DON’T:¶
Grant delete permissions without careful consideration
Give providers access to patient portal
Allow cross-institution data access
Hardcode permissions in views
Grant staff status unnecessarily (only for REDCap data export)
Troubleshooting¶
Users Can’t Access Patients¶
Check user has correct group membership
Verify Provider profile exists and is linked to Institution (for providers)
Check patient belongs to user’s institution
Verify permissions are assigned to group
Permission Denied Errors¶
Check user is authenticated
Verify user has required permissions
Check institution-based access control
Review view decorators and mixins
Missing Permissions¶
If permissions don’t exist, run:
python manage.py migrate
python manage.py shell -c "from django.contrib.auth.models import Permission; Permission.objects.all().count()"