REDCap to Metricis Role Mapping¶
This document maps REDCap's conceptual user roles to Metricis's RBAC implementation, identifies gaps, and recommends modifications.
Role Mapping Matrix¶
| REDCap Role | Metricis Role | Mapping Status | Notes |
|---|---|---|---|
| Project Administrator | owner |
✅ Mapped | Full control, can delete study |
| Principal Investigator (PI) | admin |
✅ Mapped | Broad visibility, manage users |
| Study Coordinator / Data Manager | coordinator |
✅ Mapped | Operational control, edit participants |
| Data Entry User | data_entry |
⚠️ NEW | Can edit, cannot export |
| Read-Only / Monitor | viewer |
✅ Mapped | View only, no editing or export |
| Statistician / Analyst | researcher |
✅ Mapped | Export data, no editing |
| Survey-Only User | N/A | ℹ️ External | Participants (external, no portal access) |
| API / Integration User | System-level | ℹ️ Separate | API tokens, not study-role based |
Detailed Role Comparison¶
1. Project Administrator → owner¶
REDCap Permissions: - Create and modify instruments - Enable production mode - Manage users and roles - Configure data access groups (DAGs) - Export data (including identifiers)
Metricis owner Permissions:
- VIEW_STUDY, EDIT_STUDY, DELETE_STUDY
- VIEW_PARTICIPANTS, EDIT_PARTICIPANTS
- VIEW_SESSIONS, EXPORT_DATA
- MANAGE_BATTERIES, MANAGE_USERS, VIEW_AUDIT_LOG
✅ Full match - Owner has all permissions.
2. Principal Investigator (PI) → admin¶
REDCap Permissions: - View all data - Export data (often with identifiers) - Review project status and logs - Limited design permissions
Metricis admin Permissions:
- All permissions except DELETE_STUDY
- Can manage users
- Can view audit log
✅ Good match - Admin role fits PI oversight needs.
3. Study Coordinator / Data Manager → coordinator¶
REDCap Permissions: - Enter and edit data - Resolve queries - Lock/unlock records - Import/export data - Monitor completeness
Metricis coordinator Permissions:
- VIEW_STUDY, VIEW_PARTICIPANTS, EDIT_PARTICIPANTS
- VIEW_SESSIONS, EXPORT_DATA
- MANAGE_BATTERIES
✅ Good match - Coordinator has operational control.
4. Data Entry User → data_entry (NEW)¶
REDCap Permissions: - Enter and edit data - View assigned records - No exports - No design or user management
Current Gap:
- Metricis has no role with edit capability but export restriction
- coordinator has both edit AND export
- viewer has no edit capability
Proposed data_entry Permissions:
- VIEW_STUDY
- VIEW_PARTICIPANTS, EDIT_PARTICIPANTS
- VIEW_SESSIONS
- ❌ EXPORT_DATA (explicitly denied)
⚠️ NEW ROLE NEEDED - See implementation below.
5. Read-Only / Monitor → viewer¶
REDCap Permissions: - View data only - Access reports and dashboards - No editing or exporting
Metricis viewer Permissions:
- VIEW_STUDY, VIEW_PARTICIPANTS, VIEW_SESSIONS
- No export, no edit
✅ Exact match
6. Statistician / Analyst → researcher¶
REDCap Permissions: - Export data (often de-identified) - View reports - No data entry or editing
Metricis researcher Permissions:
- VIEW_STUDY, VIEW_PARTICIPANTS, VIEW_SESSIONS
- EXPORT_DATA
- No edit permissions
✅ Exact match - Researcher can view and export but not edit.
7. Survey-Only User → External (Participants)¶
REDCap Permissions: - Complete surveys via public/authenticated links - No access to project backend
Metricis Implementation: - Handled via participant assessment sessions - No portal access required - Authentication via session tokens, not user accounts
ℹ️ Not a portal role - Participants use the assessment client, not the researcher portal.
8. API / Integration User → System-Level¶
REDCap Permissions: - API read/write access (scoped) - Often no UI access
Metricis Implementation:
- API tokens are generated per-user
- Could add is_api_user flag to User model
- API permissions inherit from user's study roles
ℹ️ Handled differently - API access is token-based, not a separate role.
Gap Analysis¶
Gap 1: Missing data_entry Role¶
Problem: No way to give a user edit permissions without export permissions.
Solution: Add DATA_ENTRY to StudyRole enum:
class StudyRole(str, Enum):
OWNER = "owner"
ADMIN = "admin"
COORDINATOR = "coordinator"
DATA_ENTRY = "data_entry" # NEW
RESEARCHER = "researcher"
VIEWER = "viewer"
Permissions for data_entry:
StudyRole.DATA_ENTRY: {
Permission.VIEW_STUDY,
Permission.VIEW_PARTICIPANTS,
Permission.EDIT_PARTICIPANTS,
Permission.VIEW_SESSIONS,
# No EXPORT_DATA
# No MANAGE_BATTERIES
# No MANAGE_USERS
},
Gap 2: Role Hierarchy Update¶
Current hierarchy: VIEWER < RESEARCHER < COORDINATOR < ADMIN < OWNER
New hierarchy: VIEWER < DATA_ENTRY < RESEARCHER < COORDINATOR < ADMIN < OWNER
Rationale:
- DATA_ENTRY has edit but no export → more trusted than VIEWER but less than RESEARCHER
- RESEARCHER has export but no edit → parallel concern but more access to data
- In clinical research, data entry is often done by less senior staff while statisticians need export
Implementation Plan¶
Step 1: Add DATA_ENTRY Role¶
File: server/app/services/access_control.py
class StudyRole(str, Enum):
OWNER = "owner"
ADMIN = "admin"
COORDINATOR = "coordinator"
DATA_ENTRY = "data_entry" # ADD
RESEARCHER = "researcher"
VIEWER = "viewer"
ROLE_PERMISSIONS: dict[StudyRole, set[Permission]] = {
# ... existing ...
StudyRole.DATA_ENTRY: {
Permission.VIEW_STUDY,
Permission.VIEW_PARTICIPANTS,
Permission.EDIT_PARTICIPANTS,
Permission.VIEW_SESSIONS,
},
}
Step 2: Update Role Hierarchy¶
role_hierarchy = [
StudyRole.VIEWER,
StudyRole.DATA_ENTRY, # INSERT
StudyRole.RESEARCHER,
StudyRole.COORDINATOR,
StudyRole.ADMIN,
StudyRole.OWNER,
]
Step 3: Database Migration¶
The role field in user_studies table accepts any string, so no migration needed. The new role value will work immediately.
Test Users Matrix¶
| Test User | Global Role | Study Role | Use Case |
|---|---|---|---|
admin@test.com |
admin |
N/A | System admin (sees all studies) |
pi@test.com |
researcher |
admin |
PI with admin access to specific study |
coordinator@test.com |
researcher |
coordinator |
Study coordinator |
data_entry@test.com |
researcher |
data_entry |
Research assistant doing data entry |
analyst@test.com |
researcher |
researcher |
Biostatistician needing export |
monitor@test.com |
researcher |
viewer |
Clinical monitor (read-only) |
Endpoint Permission Requirements¶
| Endpoint | Required Permission | Roles with Access |
|---|---|---|
GET /api/studies |
N/A (filtered by access) | All authenticated |
GET /api/studies/{id} |
VIEW_STUDY |
All study roles |
PATCH /api/studies/{id} |
EDIT_STUDY |
owner, admin |
DELETE /api/studies/{id} |
DELETE_STUDY |
owner only |
GET /api/studies/{id}/participants |
VIEW_PARTICIPANTS |
All study roles |
POST /api/studies/{id}/participants |
EDIT_PARTICIPANTS |
owner, admin, coordinator, data_entry |
GET /api/studies/{id}/sessions |
VIEW_SESSIONS |
All study roles |
GET /api/exports/* |
EXPORT_DATA |
owner, admin, coordinator, researcher |
GET /api/batteries |
MANAGE_BATTERIES |
owner, admin, coordinator |
POST /api/studies/{id}/users |
MANAGE_USERS |
owner, admin |
Data Access Groups (DAGs)¶
Metricis implements REDCap-style Data Access Groups (DAGs) to restrict users to specific sites in multi-site studies. This is controlled via the site_id field in the UserStudy association.
How DAG Filtering Works¶
UserStudy.site_id |
Behavior |
|---|---|
NULL |
User can access all sites in the study |
<uuid> |
User can only access participants at that site |
Endpoints with DAG Filtering¶
The following endpoints enforce DAG filtering:
Participants Router:
- GET /api/studies/{id}/participants - List filtered by user's site
- GET /api/studies/{id}/participants/{id} - Returns 404 if outside user's site
- POST /api/studies/{id}/participants - Creates at user's site by default
- PATCH /api/studies/{id}/participants/{id} - Cannot move to different site
- DELETE /api/studies/{id}/participants/{id} - Returns 404 if outside user's site
Exports Router:
- GET /api/exports/studies/{id}/participants - Filtered by user's site
- GET /api/exports/studies/{id}/sessions - Filtered by user's site
- GET /api/exports/studies/{id}/responses - Filtered by user's site
- GET /api/exports/studies/{id}/scheduled-visits - Filtered by user's site
- GET /api/exports/studies/{id}/consent-records - Filtered by user's site
- GET /api/exports/studies/{id}/full - Filtered by user's site
- GET /api/exports/studies/{id}/wide - Filtered by user's site
- GET /api/exports/studies/{id}/long - Filtered by user's site
Security Behavior¶
| Scenario | Response |
|---|---|
| Access participant outside DAG | 404 Not Found (not 403, to prevent enumeration) |
| Create participant at different site | 403 Forbidden |
| Move participant to different site | 403 Forbidden |
| Export with DAG restriction | Data filtered to user's site only |
System Admin Bypass¶
Users with global role='admin' bypass DAG filtering and see all sites in all studies.
Example: Multi-Site Study Setup¶
# Site A coordinator - can only see Site A participants
UserStudy(
user_id=coordinator_a_id,
study_id=study_id,
role="coordinator",
site_id=site_a_id, # DAG restriction
)
# Central PI - can see all sites
UserStudy(
user_id=pi_id,
study_id=study_id,
role="admin",
site_id=None, # No DAG restriction
)
Security Considerations (Per REDCap Best Practices)¶
- Separate design authority from data entry - Implemented via role separation
- Limit identifier exports -
EXPORT_DATApermission controls this - Use DAGs for multi-site - Implemented via
site_idfiltering in participants and exports - Create dedicated API users - Supported via API token system
- Document role templates - This document serves that purpose