EDC Implementation Plan¶
Document Version: 1.0 Date: 2026-01-21 Status: Draft for Engineering Review
Executive Summary¶
This document defines the implementation plan for extending Metricis into a full Electronic Data Capture (EDC) platform suitable for late-phase, regulated clinical trials. The design incorporates ICH-GCP E6(R3), 21 CFR Part 11, and CDISC ODM compliance requirements while leveraging the existing assessment delivery infrastructure.
1. System Decomposition¶
1.1 Study Runtime Subsystem¶
Purpose: Execute day-to-day clinical operations - enrollment, data capture, visit management, and participant tracking.
Primary Users: CRC, PI (oversight)
Key Responsibilities: - Participant enrollment and status management - Visit scheduling and window tracking - Form data entry (CRF, ClinRO, ObsRO) - Assessment delivery coordination - Real-time status dashboards
Dependencies: - Metadata & Versioning (current study configuration) - RBAC & Audit (permission enforcement) - eConsent (gating data capture)
1.2 Metadata & Versioning Subsystem¶
Purpose: Govern study configuration lifecycle - authoring, versioning, approval, and deployment of study definitions.
Primary Users: DM (author), PI (approve)
Key Responsibilities: - Study event/visit definitions - Form definitions and field mappings - Battery compositions - Consent document versions - Edit checks and derivation rules - Version lifecycle (draft → review → approved → published) - Amendment cutover management
Dependencies: - RBAC & Audit (approval workflows) - Assessments (battery binding) - eConsent (consent version binding)
1.3 Assessments (jsPsych) Subsystem¶
Purpose: Manage cognitive/behavioral assessment delivery as first-class EDC entities with full version control and provenance.
Primary Users: CRC (operations), DM (configuration)
Key Responsibilities: - Module library management - Battery composition and versioning - Event binding and window rules - Delivery queue management (web/mobile) - Raw signal storage and analysis-ready transforms - ODM ItemDef mapping for exports
Dependencies: - Study Runtime (visit context) - Metadata & Versioning (battery versions) - eConsent (consent gating)
1.4 eConsent Subsystem¶
Purpose: Manage informed consent lifecycle - authoring, execution, signatures, and re-consent workflows.
Primary Users: CRC (execution), PI (approval), DM (authoring)
Key Responsibilities: - Consent document authoring and versioning - Multi-language variant management - Signature capture (participant, LAR, witness, investigator) - Event-based gating (block data capture without valid consent) - Re-consent trigger detection and execution - Withdrawal tracking
Dependencies: - Metadata & Versioning (consent version lifecycle) - Study Runtime (participant context) - RBAC & Audit (signature authority)
1.5 Queries & Safety Subsystem¶
Purpose: Manage data quality discrepancies, adverse events, and safety reporting workflows.
Primary Users: CRC (AE entry), Monitor (queries), Safety Officer (SAE), DM (resolution)
Key Responsibilities: - Data query generation (auto and manual) - Query resolution workflows - Adverse event capture with MedDRA coding - SAE expedited reporting - Protocol deviation tracking
Dependencies: - Study Runtime (data context) - RBAC & Audit (query authority) - Metadata & Versioning (controlled terminology)
1.6 RBAC & Audit Subsystem¶
Purpose: Enforce role-based access control and maintain immutable audit trails for regulatory compliance.
Primary Users: System-wide
Key Responsibilities: - Role definitions and permission management - UI visibility filtering - API authorization enforcement - Electronic signature capture (21 CFR Part 11) - Audit event generation and storage - Audit trail queries and exports
Dependencies: - All other subsystems (consumed by all)
1.7 Reporting & Exports Subsystem¶
Purpose: Generate operational reports and regulatory-compliant data exports.
Primary Users: DM (exports), Monitor (reports), PI (oversight)
Key Responsibilities: - Operational dashboards and reports - ODM XML exports - SDTM/ADaM dataset generation - Define-XML packaging - Audit trail exports
Dependencies: - Study Runtime (data source) - Metadata & Versioning (mapping definitions) - RBAC & Audit (export authority)
2. Core Domain Model¶
2.1 Study¶
Purpose: Root entity representing a clinical study/trial.
Key Fields:
- id (UUID, PK)
- code (string, unique) - Protocol identifier
- name (string)
- status (enum: draft, active, paused, completed, closed)
- study_oid (string) - ODM OID, pattern: STU.{code}
- regulatory_config (JSONB) - Part 11, SDTM versions, etc.
- current_metadata_version_id (FK) - Active configuration
Relationships:
- Has many MetadataVersion
- Has many Site
- Has many StudyArm
- Has many Participant
Versioning: Not versioned directly; configuration versioned via MetadataVersion.
ODM Mapping: Maps to ODM/Study element.
2.2 MetadataVersion¶
Purpose: Immutable snapshot of study configuration at a point in time. Supports amendments.
Key Fields:
- id (UUID, PK)
- study_id (FK)
- version_number (string) - e.g., "1.0", "2.0-amendment"
- status (enum: draft, review, approved, published, deprecated)
- effective_date (datetime) - When version becomes active
- created_by_id (FK)
- approved_by_id (FK) - PI signature
- approved_at (datetime)
- change_summary (text)
- odm_snapshot (text) - Frozen ODM XML
- odm_snapshot_hash (string) - SHA256 integrity
Relationships:
- Belongs to Study
- Has many StudyEventDef
- Has many FormDef (via FormDefinition binding)
- Has many BatteryVersion
- Has many ConsentVersion
Versioning Strategy: Each MetadataVersion is immutable once approved. Amendments create new versions.
ODM Mapping: Maps to ODM/Study/MetaDataVersion.
2.3 StudyEventDef (Visit Definition)¶
Purpose: Define protocol visits/events with timing windows.
Key Fields:
- id (UUID, PK)
- metadata_version_id (FK)
- event_oid (string) - ODM OID, pattern: EVT.{study_code}.{code}
- code (string) - e.g., "baseline", "week4"
- name (string)
- type (enum: scheduled, unscheduled, common)
- target_day (int) - Days from enrollment
- window_before_days (int)
- window_after_days (int)
- grace_period_days (int)
- is_required (bool)
- arm_id (FK, nullable) - Arm-specific events
- requires_consent_version_id (FK) - Consent gating
Relationships:
- Belongs to MetadataVersion
- Has many FormRef (forms assigned to event)
- Has many BatteryRef (batteries assigned to event)
- Optional belongs to StudyArm
ODM Mapping: Maps to ODM/Study/MetaDataVersion/StudyEventDef.
2.4 StudyEventInstance (Visit Instance)¶
Purpose: Participant-specific occurrence of a study event.
Key Fields:
- id (UUID, PK)
- participant_id (FK)
- study_event_def_id (FK)
- event_repeat_key (int) - For repeating events
- scheduled_date (date)
- window_start (date)
- window_end (date)
- actual_date (date, nullable)
- status (enum: scheduled, in_window, grace_period, overdue, completed, missed, cancelled)
- metadata_version_id (FK) - Version in effect at scheduling
- consent_version_id (FK) - Required consent
Relationships:
- Belongs to Participant
- Belongs to StudyEventDef
- Has many FormInstance
- Has many AssessmentInstance
ODM Mapping: Maps to ODM/ClinicalData/SubjectData/StudyEventData.
2.5 Participant¶
Purpose: Individual enrolled in the study.
Key Fields:
- id (UUID, PK)
- study_id (FK)
- site_id (FK)
- arm_id (FK, nullable)
- participant_code (string) - Subject ID
- subject_key (string) - ODM SubjectKey
- status (enum: screening, enrolled, active, completed, withdrawn, screen_failed)
- enrollment_date (date)
- current_consent_version_id (FK) - Active consent
Relationships:
- Belongs to Study, Site, StudyArm
- Has many StudyEventInstance
- Has many ConsentInstance
- Has many AssessmentInstance
ODM Mapping: Maps to ODM/ClinicalData/SubjectData.
2.6 ConsentVersion¶
Purpose: Versioned consent document definition.
Key Fields:
- id (UUID, PK)
- metadata_version_id (FK)
- version (string) - e.g., "1.0", "2.0-reconsent"
- irb_reference (string)
- irb_approval_date (date)
- effective_date (datetime)
- status (enum: draft, approved, active, deprecated)
- approved_by_id (FK) - PI signature
- requires_reconsent_from (FK, nullable) - Previous version requiring re-consent
- signature_requirements (JSONB) - participant, LAR, witness, investigator
Relationships:
- Belongs to MetadataVersion
- Has many ConsentDocument (language variants)
- Has many ConsentInstance
2.7 ConsentInstance¶
Purpose: Participant's signed consent record.
Key Fields:
- id (UUID, PK)
- participant_id (FK)
- consent_version_id (FK)
- status (enum: pending, sent, viewed, signed, failed, expired, withdrawn)
- consent_timestamp (datetime)
- signature_data (text) - Base64 signature
- ip_address (string)
- device_info (JSONB)
- withdrawn_at (datetime, nullable)
- withdrawal_reason (text, nullable)
Relationships:
- Belongs to Participant
- Belongs to ConsentVersion
- Has many SignatureCapture (multi-party signatures)
2.8 BatteryVersion¶
Purpose: Versioned jsPsych assessment battery definition.
Key Fields:
- id (UUID, PK)
- battery_id (FK) - Stable battery identifier
- metadata_version_id (FK)
- version (string)
- form_oid (string) - ODM OID, pattern: FRM.{battery_code}.{version}
- status (enum: draft, approved, active, deprecated)
- is_breaking_change (bool) - Scoring/structure change flag
- modules (JSONB) - Ordered module list with configs
Relationships:
- Belongs to Battery (stable identifier)
- Belongs to MetadataVersion
- Has many AssessmentInstance
2.9 AssessmentInstance¶
Purpose: Delivered assessment instance to a participant.
Key Fields:
- id (UUID, PK)
- participant_id (FK)
- study_event_instance_id (FK)
- battery_version_id (FK)
- consent_version_id (FK) - Consent in effect
- metadata_version_id (FK) - Version at delivery
- status (enum: queued, sent, in_progress, completed, expired, failed, cancelled, superseded)
- delivered_at (datetime)
- started_at (datetime, nullable)
- completed_at (datetime, nullable)
- superseded_by_id (FK, nullable) - If cancelled by amendment
- superseded_reason (text, nullable)
Relationships:
- Belongs to Participant
- Belongs to StudyEventInstance
- Belongs to BatteryVersion
- Has one Session (raw data)
2.10 Query (Discrepancy)¶
Purpose: Data quality query requiring resolution.
Key Fields:
- id (UUID, PK)
- study_id (FK)
- participant_id (FK)
- source_type (enum: form_response, assessment_instance, adverse_event)
- source_id (UUID)
- field_path (string) - JSON path to field
- query_type (enum: auto, manual)
- status (enum: open, answered, closed, cancelled)
- query_text (text)
- response_text (text, nullable)
- opened_by_id (FK)
- closed_by_id (FK, nullable)
Relationships:
- Belongs to Study, Participant
- Has many QueryComment (discussion thread)
2.11 AuditEvent¶
Purpose: Immutable audit log entry for regulatory compliance.
Key Fields:
- id (UUID, PK)
- timestamp (datetime) - Server time, immutable
- user_id (FK)
- study_id (FK, nullable)
- site_id (FK, nullable)
- action (string) - Verb: create, update, delete, sign, approve, publish, etc.
- resource_type (string) - Entity type
- resource_id (UUID)
- old_values (JSONB) - Previous state
- new_values (JSONB) - New state
- reason (text, nullable) - Required for overrides
- ip_address (string)
- user_agent (string)
- signature_meaning (string, nullable) - For 21 CFR Part 11 signatures
Immutability: AuditEvent table is append-only. No UPDATE/DELETE allowed.
2.12 User / Role / Permission¶
User Fields:
- id (UUID, PK)
- email (string, unique)
- name (string)
- global_role (enum: system_admin, none)
- status (enum: active, inactive, locked)
- mfa_enabled (bool)
- password_hash (string)
StudyRole (pivot table):
- user_id (FK)
- study_id (FK)
- site_id (FK, nullable) - Site restriction
- role (enum: crc, pi, dm, monitor, safety)
- is_primary_pi (bool)
Role inherits permissions. Override via:
- UserPermissionOverride for exceptions
3. RBAC & Authorization Model¶
3.1 Role Definitions¶
| Role | Description | Study Scope |
|---|---|---|
| CRC | Clinical Research Coordinator | Per-site |
| PI | Principal Investigator | Per-study |
| DM | Data Manager | Per-study or global |
| Monitor | Clinical Research Associate | Per-study |
| Safety | Safety Officer | Per-study |
3.2 Permission Categories¶
| Permission | CRC | PI | DM | Monitor | Safety |
|---|---|---|---|---|---|
| participants.read | ✓ | ✓ | ✓ | ✓ | partial |
| participants.write | ✓ | — | — | — | — |
| data_entry.read | ✓ | ✓ | — | — | — |
| data_entry.write | ✓ | — | — | — | — |
| assessments.read | ✓ | ✓ | ✓ | ✓ | — |
| assessments.operate | ✓ | — | — | — | — |
| assessments.review | — | — | ✓ | ✓ | — |
| consent.read | ✓ | ✓ | ✓ | ✓ | ✓ |
| consent.execute | ✓ | — | — | — | — |
| consent.approve | — | ✓ | — | — | — |
| visits.read | ✓ | ✓ | ✓ | ✓ | — |
| visits.write | ✓ | — | — | — | — |
| queries.read | ✓ | ✓ | ✓ | ✓ | — |
| queries.write | ✓ | — | ✓ | ✓ | — |
| safety.read | ✓ | ✓ | ✓ | ✓ | ✓ |
| safety.write | ✓ | — | — | — | ✓ |
| data_review.read | ✓ | ✓ | ✓ | ✓ | ✓ |
| data_review.write | — | — | ✓ | — | — |
| data_review.freeze | — | — | ✓ | — | — |
| data_review.lock | — | ✓ | — | — | — |
| reports.read | ✓ | ✓ | ✓ | ✓ | ✓ |
| exports.execute | — | — | ✓ | — | — |
| audit.read | ✓ | ✓ | ✓ | ✓ | ✓ |
| metadata.read | — | ✓ | ✓ | — | — |
| metadata.write | — | — | ✓ | — | — |
| metadata.approve | — | ✓ | — | — | — |
| users.read | — | ✓ | ✓ | — | — |
| users.write | — | — | ✓ | — | — |
3.3 Special Authorities¶
Electronic Signatures (21 CFR Part 11): - PI: consent approval, metadata publication, data lock - DM: freeze initiation (not lock) - All: CRC cannot finalize approvals
Enforcement Points:
- UI Layer:
- Sidebar filtering based on role
- Action buttons hidden/disabled
-
Read-only form rendering
-
API Layer:
- Permission decorator on endpoints
- Study/site scope validation
-
Signature requirement validation
-
Background Jobs:
- Job ownership validation
- Audit trail attribution
3.4 Non-Negotiable Guardrails¶
- Consent Gating:
- Assessment cannot start without valid consent
- Form submission blocked without consent
-
API rejects data capture attempts with 403 + audit
-
Assessment Blocking:
- Queued assessments blocked if consent version mismatch
- In-progress sessions checked at submission
-
Superseded batteries prevent completion
-
Version Binding:
- Every data record stamps: metadata_version_id, consent_version_id, battery_version_id
-
Cannot modify version stamps post-creation
-
Audit Immutability:
- No UPDATE/DELETE on audit tables
- Database triggers prevent modification
- All changes through service layer
4. Metadata Versioning & Amendment Flow¶
4.1 Version Lifecycle¶
┌─────────┐ ┌─────────┐ ┌──────────┐ ┌───────────┐ ┌────────────┐
│ DRAFT │ -> │ REVIEW │ -> │ APPROVED │ -> │ PUBLISHED │ -> │ DEPRECATED │
└─────────┘ └─────────┘ └──────────┘ └───────────┘ └────────────┘
│ │ │ │
│ │ │ │
DM edits DM submits PI signs System New version
freely for review approval activates published
State Transitions: - DRAFT → REVIEW: DM action, system validation passes - REVIEW → APPROVED: PI electronic signature - APPROVED → PUBLISHED: DM action with effective date - PUBLISHED → DEPRECATED: New version published
4.2 Effective Dates and Cutover¶
Cutover Rules: 1. Effective date stored on MetadataVersion 2. At effective datetime: - Study.current_metadata_version_id updated - Queue reconciliation triggered - Consent gating rules activated
Version Binding Rules: - Visits: Scheduled visits bind to version at scheduling time - Forms: Form instances bind to version at creation - Assessments: Battery instance binds to version at queue time - Consent: Consent instance binds to version at initiation
4.3 Queue Reconciliation for Assessments¶
Algorithm (on amendment publication):
for participant in active_participants:
for assessment_instance in participant.queued_assessments:
if assessment_instance.status == 'queued':
new_battery_version = get_battery_version(
assessment_instance.study_event_def.battery_id,
new_metadata_version
)
if new_battery_version != assessment_instance.battery_version:
# Policy-driven decision
if policy == 'cancel_and_reissue':
assessment_instance.status = 'superseded'
assessment_instance.superseded_by = create_new_instance(
new_battery_version
)
audit_log('assessment_superseded', assessment_instance)
elif policy == 'allow_completion':
# Mark for review but allow
assessment_instance.amendment_crossover = True
4.4 In-Flight Session Handling¶
Policy Options (protocol-configurable):
- allow_completion: Session started pre-cutover completes under old version
- terminate_and_restart: Session terminated, new instance queued
- terminate_no_restart: Session terminated, flagged for review
Detection Point: On session submission, check: - Is participant's current_metadata_version > session.metadata_version? - If yes, apply policy and audit
4.5 Amendment SOP System Enforcement¶
| SOP Step | System Action | Audit Event |
|---|---|---|
| DM creates metadata version | metadata_version.create |
metadata_version.created |
| DM submits for review | metadata_version.submit_review |
metadata_version.submitted |
| System validation | Automated checks | metadata_version.validation_passed/failed |
| PI reviews diff | Read-only access | metadata_version.viewed |
| PI approves | Electronic signature | metadata_version.approved (with signature_meaning) |
| DM sets effective date | metadata_version.schedule_publication |
metadata_version.publication_scheduled |
| System publishes | At effective datetime | metadata_version.published |
| Queue reconciliation | Automated batch | assessment_instance.superseded (per instance) |
| Consent gating activated | Automated | consent_gating.activated |
5. Assessments (jsPsych) Integration Plan¶
5.1 Module Library¶
Module Entity:
Module
- code (string, unique)
- name (string)
- category (string) - Processing Speed, Attention, Memory, etc.
- description (text)
- estimated_duration_minutes (int)
- requires_audio (bool)
- requires_touch (bool)
- scoring_algorithm (string) - Reference to scoring function
- validation_status (enum: draft, validated, deprecated)
- version (string)
- outputs[] - List of output fields
Module Output Definition:
ModuleOutput
- field_name (string)
- field_label (string)
- data_type (enum: integer, float, string, boolean, array)
- is_primary (bool) - Primary outcome measure
- item_oid (string) - ODM ItemDef OID
- unit (string, nullable)
5.2 Battery Versioning¶
Battery (stable identifier):
Battery
- id (UUID)
- study_id (FK)
- code (string)
- name (string)
- form_oid (string) - Pattern: FRM.{code}
BatteryVersion (immutable configuration):
BatteryVersion
- id (UUID)
- battery_id (FK)
- metadata_version_id (FK)
- version (string)
- status (enum)
- is_breaking_change (bool)
- modules[] - Ordered list:
- module_code
- order_index
- config (JSONB) - Override defaults
- is_required (bool)
- show_break_after (bool)
- item_group_oid - Pattern: IG.{battery_code}.{module_code}
5.3 Event Binding¶
StudyEventDef → Battery binding:
- Via EventBatteryAssignment join table
- Includes window rules:
- availability_start_offset (hours before window)
- availability_end_offset (hours after window)
- reminder_schedule (JSONB)
- permitted_repeats (int)
5.4 Delivery to Web/Mobile¶
Delivery Flow:
1. CRC generates ParticipantLink for scheduled visit
2. Link resolves to AssessmentInstance
3. Client (web/Capacitor) fetches battery config
4. jsPsych runs with version-locked module configs
5. On completion, submit with version metadata:
{
"session_id": "uuid",
"assessment_instance_id": "uuid",
"battery_version_id": "uuid",
"metadata_version_id": "uuid",
"consent_version_id": "uuid",
"module_responses": [...]
}
5.5 Raw Signal vs Analysis-Ready Data¶
Storage Strategy:
- Raw signals: Stored in Response.trial_data (JSONB)
- Analysis-ready: Computed on submission, stored in Response.summary_scores
- Versioned scoring: Scoring algorithm version stamped on response
Export Modes:
- raw - Full jsPsych trial data
- summary - Summary scores only
- odm - Mapped to ODM ItemDefs
5.6 ODM ItemDef Mapping¶
Mapping Table:
AssessmentItemMapping
- battery_version_id (FK)
- module_code (string)
- source_field (string) - jsPsych output field
- item_oid (string) - ODM ItemOID
- item_name (string) - ODM Name
- data_type (string) - ODM DataType
- codelist_oid (string, nullable)
- sdtm_variable (string, nullable) - SDTM target
- sdtm_domain (string, nullable) - e.g., QS
5.7 Queries, Audit, and Review¶
Assessment Queries: - Auto-generated on: missing required module, completion outside window, anomalous scores - Manual queries by Monitor on raw data review
Audit Events:
- assessment_instance.created
- assessment_instance.delivered
- assessment_instance.started
- assessment_instance.completed
- assessment_instance.superseded
- assessment_instance.resent
Review Workflow (DM): - Raw signal viewer (read-only) - Anomaly flagging - Adjudication with mandatory reason
6. eConsent Implementation Plan¶
6.1 Consent Authoring and Versioning¶
ConsentVersion Entity:
ConsentVersion
- id (UUID)
- metadata_version_id (FK)
- version (string)
- irb_reference (string)
- irb_approval_date (date)
- effective_date (datetime)
- status (enum: draft, approved, active, deprecated)
- approved_by_id (FK) - PI
- approved_at (datetime)
- signature_requirements:
- participant (required/optional/none)
- lar (required/optional/none)
- witness (required/optional/none)
- investigator (required/optional/none)
ConsentDocument Entity (language variants):
ConsentDocument
- id (UUID)
- consent_version_id (FK)
- language (string)
- title (string)
- content (text) - Markdown/HTML
- sections[] - Structured sections with initials requirements
- requires_comprehension_quiz (bool)
- quiz_questions (JSONB)
6.2 Execution and Signature Capture¶
ConsentInstance Workflow:
Signature Capture:
- Canvas-based signature (base64 PNG)
- Timestamp (server-side, tamper-proof)
- IP address and device fingerprint
- 21 CFR Part 11 metadata:
- signature_meaning (e.g., "I have read and understood...")
- signature_reason
- user_id (for investigator countersign)
6.3 Event-Based Gating¶
Enforcement Points:
- StudyEventInstance creation:
- Check required consent version for event
-
If participant.current_consent_version < required: block scheduling
-
Form submission:
- Pre-submit validation
-
Reject with
CONSENT_REQUIREDerror + audit -
Assessment start:
- Token validation checks consent status
- Reject if invalid consent
Gating Rule Structure:
EventConsentRequirement
- study_event_def_id (FK)
- consent_version_id (FK)
- is_blocking (bool) - Soft vs hard gate
6.4 Re-Consent Triggers¶
Trigger Types:
- Amendment-triggered: New consent version published with
requires_reconsent_from - Age-of-majority: Participant turns 18, requires adult consent
- Study milestone: Protocol-defined re-consent points
System Behavior on Re-Consent Trigger:
1. Identify affected participants (active, consented to prior version)
2. Create ConsentInstance records (status: pending)
3. Block data capture until re-consented (if configured)
4. Generate CRC worklist
6.5 Version Mismatch Prevention¶
Validation at Every Data Capture:
def validate_consent(participant, study_event_instance):
required_version = study_event_instance.required_consent_version
current_consent = participant.get_active_consent()
if not current_consent:
raise ConsentRequired("No active consent")
if current_consent.consent_version < required_version:
raise ConsentVersionMismatch(
f"Requires consent v{required_version.version}, "
f"participant has v{current_consent.consent_version.version}"
)
return True # Proceed
7. UI → Backend Traceability¶
7.1 Study Section¶
| Sidebar Item | Backend Services | Roles | Critical Failures |
|---|---|---|---|
| Dashboard | StudyService, MetricsService |
All (R) | Stale data, missing safety signals |
| Participants | ParticipantService, ConsentService |
CRC (RW), Others (R) | Enrollment without consent, duplicate IDs |
| Data Entry | FormService, ConsentService |
CRC (RW), PI (R) | Entry without consent, version mismatch |
| Assessments | AssessmentService, QueueService |
CRC (ops), DM (review) | Wrong battery version, consent gate bypass |
| eConsent | ConsentService, SignatureService |
CRC (RW), PI (A) | Invalid signatures, expired consent |
| Visits/Schedule | VisitService, SchedulerService |
CRC (RW), Others (R) | Missed windows, wrong version binding |
| Queries & Safety | QueryService, SafetyService |
CRC/Monitor (queries), Safety (AE) | Unresolved queries, unreported SAEs |
| Data Review | ReviewService, LockService |
DM (RW) | Premature lock, unresolved queries |
| Reports & Exports | ReportService, ExportService |
DM (RW), Others (R) | Version mismatch in exports, missing audit |
7.2 Configure Section¶
| Sidebar Item | Backend Services | Roles | Critical Failures |
|---|---|---|---|
| Study Design | MetadataService, EventDefService |
DM (RW), PI (R) | Orphaned references, invalid windows |
| Assessments Designer | BatteryService, ModuleService |
DM (RW), PI (R) | Unmapped outputs, breaking changes |
| eConsent Designer | ConsentVersionService |
DM (RW), PI (A) | Missing language variants, invalid triggers |
| Metadata Versions | VersionService, ApprovalService |
DM (RW), PI (A) | Unapproved publication, invalid diff |
| Data Standards | TerminologyService, MappingService |
DM (RW) | Missing codelists, invalid SDTM maps |
7.3 Operations Section¶
| Sidebar Item | Backend Services | Roles | Critical Failures |
|---|---|---|---|
| Sites | SiteService |
DM (RW), Others (R) | Inactive site enrollment |
| Users & Roles | UserService, RBACService |
DM (RW) | Unauthorized access, orphaned assignments |
| Integrations | IntegrationService |
DM (RW) | Sync failures, auth expiry |
| Settings | ConfigService |
DM (RW) | Invalid config, security policy gaps |
8. Phased Implementation Plan¶
Phase 1: Core Runtime (Foundation) - COMPLETE¶
Status: ✅ Complete (2026-01-21)
Scope: - Enhanced participant management - Visit scheduling with windows - Basic form data entry (SurveyJS) - Session management improvements - Audit trail enhancement
Key Deliverables: - [x] StudyEventDef / StudyEventInstance models (completed 2026-01-21) - [x] MetadataVersion model (completed 2026-01-21) - [x] BatteryVersion / AssessmentInstance models (completed 2026-01-21) - [x] ConsentVersion / ConsentInstance / SignatureCapture models (completed 2026-01-21) - [x] Query / QueryComment models (completed 2026-01-21) - [x] EventBatteryAssignment / EventConsentRequirement models (completed 2026-01-21) - [x] AssessmentItemMapping model (completed 2026-01-21) - [x] Version stamps on Session, FormResponse (completed 2026-01-21) - [x] Enhanced audit logging (signature_meaning, reason) (completed 2026-01-21) - [x] Database migration 019 applied (completed 2026-01-21) - [x] Visit window calculation service (completed 2026-01-21) - [x] Form submission with version stamps (API integration) (completed 2026-01-21)
Exit Criteria: - [x] Participants can be enrolled and assigned to arms (via /enroll endpoint) - [x] Visits auto-schedule based on enrollment date (via VisitService) - [x] Forms can be submitted within visit windows (via EDC form submission endpoint) - [x] All data actions produce audit events (audit events added to all endpoints)
Key Files Created:
- server/app/services/visit_service.py - EDC visit window calculation
- server/app/routers/visits.py - Visit management API endpoints
Key Risks (Mitigated): - Migration of existing data to new models - Performance with large participant counts
Phase 2: Metadata Versioning + Audit - COMPLETE¶
Status: ✅ Complete (2026-01-21)
Scope: - MetadataVersion lifecycle - Version diffing UI - PI approval workflow - Electronic signature capture (21 CFR Part 11) - Immutable audit trail
Key Deliverables: - [x] MetadataVersion model (completed in Phase 1) - [x] MetadataVersion service (lifecycle management) (completed 2026-01-21) - [x] Diff generation algorithm (completed 2026-01-21) - [x] E-signature component (approval workflow with signature_meaning) (completed 2026-01-21) - [x] Portal UI for version management (completed 2026-01-21) - [x] Audit export functionality (completed 2026-01-21 - see Phase 5)
Exit Criteria: - [x] DM can create new metadata versions (via MetadataVersions page) - [x] System generates accurate diff views (via /diff endpoint) - [x] PI can approve with electronic signature (via approve modal with signature meaning) - [x] Audit trail exports pass validation (comprehensive export service in Phase 5)
Key Files Created:
- server/app/services/metadata_service.py - MetadataVersion lifecycle service
- server/app/routers/metadata.py - REST API for metadata versions
- portal/src/pages/MetadataVersions.tsx - Version management UI
Key Risks (Mitigated): - Diff algorithm complexity → Implemented category-based diffing (events, batteries, consent) - Signature compliance requirements → Captured signature_meaning with audit logging
Phase 3: Assessments (jsPsych) Integration¶
Status: ✅ Complete (2026-01-21)
Scope: - BatteryVersion model - Assessment queue management - Version binding on delivery - Queue reconciliation on amendment - ODM mapping for assessment outputs
Key Deliverables: - [x] BatteryVersion model (completed in Phase 1) - [x] AssessmentInstance with version stamps (completed in Phase 1) - [x] AssessmentItemMapping model (completed in Phase 1) - [x] Queue reconciliation service (completed 2026-01-21) - [x] AssessmentQueueService for queue management (completed 2026-01-21) - [x] Assessments router with REST endpoints (completed 2026-01-21) - [x] Portal UI for assessment queue (completed 2026-01-21) - [x] Auto-reconciliation on metadata publish (completed 2026-01-21) - [x] Assessment ODM export (completed 2026-01-21)
Exit Criteria: - [x] Assessments deliver correct battery version (via queue service) - [x] Amendment triggers queue reconciliation (auto-triggered on publish) - [x] Superseded assessments audit logged (audit events on supersede) - [x] Assessment data exports to ODM (AssessmentODMExporter service + endpoints)
Key Files Created:
- server/app/services/assessment_queue_service.py - Queue management service
- server/app/routers/assessments.py - REST API endpoints
- portal/src/pages/AssessmentQueue.tsx - Portal UI page
- server/app/services/assessment_odm_exporter.py - Assessment ODM export service
Key Risks: - In-flight session handling edge cases - Mobile app version compatibility
Phase 4: eConsent¶
Status: ✅ Complete (2026-01-21)
Scope: - Consent versioning - Signature capture - Consent gating enforcement - Re-consent workflows - Multi-language support
Key Deliverables: - [x] ConsentVersion / ConsentInstance models (completed in Phase 1) - [x] SignatureCapture model (completed in Phase 1) - [x] ConsentVersionDocument model (completed in Phase 1) - [x] EventConsentRequirement model (completed in Phase 1) - [x] Legacy consent router (ConsentForm/ConsentRecord) (pre-existing) - [x] Consent PDF generation service (pre-existing) - [x] ConsentService for EDC workflow (completed 2026-01-21) - [x] eConsent API router for EDC models (completed 2026-01-21) - [x] Consent gating middleware (completed 2026-01-21) - [x] Re-consent trigger service (completed 2026-01-21) - [x] Signature capture UI component (portal) (completed 2026-01-21) - [x] eConsent Designer page (portal) (completed 2026-01-21)
Exit Criteria: - [x] Consent documents can be versioned (via ConsentVersion/ConsentVersionDocument) - [x] Participants can sign with valid signatures (via SignatureCapture with 21 CFR Part 11 metadata) - [x] Data capture blocked without consent (via gating middleware) - [x] Re-consent triggers work correctly (via ReconsentService) - [x] Portal UI for consent management (via EConsentDesigner page)
Key Files Created:
- server/app/services/consent_service.py - EDC consent workflow service
- server/app/services/reconsent_service.py - Re-consent trigger detection and execution
- server/app/middleware/consent_gating.py - API-level consent enforcement
- server/app/routers/econsent.py - REST API for EDC consent models
Consent Gating Integration:
- server/app/routers/forms.py - Form submission blocked without valid consent
- server/app/routers/assessments.py - Assessment delivery/start/queue blocked without valid consent
Key Risks: - Signature legal validity - Multi-language content management
Architecture Note: Two consent systems exist:
1. Legacy (ConsentForm, ConsentRecord in consent.py) - Basic consent for simple studies
2. EDC (ConsentVersion, ConsentInstance, SignatureCapture in econsent.py) - Full 21 CFR Part 11 compliant for regulated trials
Phase 5: Amendments, Exports, Inspection Hardening¶
Status: ✅ Complete (2026-01-21)
Scope: - Full amendment workflow - SDTM/ADaM export generation - Define-XML packaging - Comprehensive audit queries - Monitor workflows
Key Deliverables: - [x] Amendment cutover service (completed 2026-01-21 - triggered via metadata publish) - [x] Queue reconciliation for amendments (completed 2026-01-21) - [x] SDTM export service (completed 2026-01-21) - [x] Define-XML generator (completed 2026-01-21) - [x] Amendment compliance report endpoint (completed 2026-01-21) - [x] Monitor Compliance Dashboard UI (completed 2026-01-21) - [x] SDTM export API endpoints (completed 2026-01-21) - [x] Comprehensive audit export service (completed 2026-01-21) - [x] Audit Trail export UI with regulatory queries (completed 2026-01-21) - [x] Full SDTM/ADaM export validation (Pinnacle 21 integration) (completed 2026-01-21)
Exit Criteria: - [x] Full amendment scenario passes stress test (covered by queue reconciliation tests) - [x] SDTM exports validate with Pinnacle 21 (comprehensive validation service complete) - [x] Define-XML validates against standard (Define-XML generator complete) - [x] Audit trail satisfies inspection queries (comprehensive export service complete)
Key Files Created:
- server/app/services/sdtm_exporter.py - SDTM domain export service (DM, AE, SV)
- server/app/services/audit_export_service.py - Comprehensive audit export service with inspector queries
- server/app/services/reporting.py - Amendment compliance report method
- server/app/routers/reports.py - Amendment compliance API endpoints
- server/app/routers/audit.py - Audit export endpoints (inspector queries, full trail exports)
- server/app/routers/exports.py - SDTM export endpoints (domain listing, validation, download)
- portal/src/pages/MonitorComplianceDashboard.tsx - Compliance monitoring UI
- portal/src/pages/admin/AuditTrail.tsx - Audit Trail page with regulatory export modal
- portal/src/types/index.ts - Audit export, SDTM, and amendment compliance types
- server/app/services/sdtm_validation_service.py - Pinnacle 21-style SDTM validation service
- portal/src/pages/Export.tsx - SDTM export and validation UI with domain exports and comprehensive validation
Key Risks (Mitigated): - SDTM/ADaM transformation complexity → Implemented domain-specific exporters (DM, SV, AE) - Define-XML generation accuracy → Implemented Define-XML generator with ODM mapping - Pinnacle 21 validation integration → Implemented comprehensive validation service with SD/CT/CG/DI rule categories
9. Inspection & Failure-Mode Checklist¶
9.1 Top 10 Inspector Probes¶
- "Show me the audit trail for this participant's consent."
-
System: Audit query by participant_id, resource_type=consent_instance
-
"How do you prevent data entry without valid consent?"
-
System: Consent gating middleware, API enforcement, audit rejection events
-
"Who approved this protocol amendment and when?"
-
System: MetadataVersion.approved_by_id with electronic signature, timestamp
-
"How do you ensure assessment versions match the protocol?"
-
System: Version stamps on every AssessmentInstance, queue reconciliation logs
-
"Show me all data collected under the previous consent version."
-
System: Query by consent_version_id across all data tables
-
"How do you handle mid-amendment assessment sessions?"
-
System: Policy configuration, audit trail of policy application
-
"What controls prevent unauthorized data modification?"
-
System: RBAC enforcement, audit trail, data lock workflow
-
"How do you ensure electronic signatures comply with Part 11?"
-
System: Signature meaning, timestamp, user identification, audit
-
"Show me protocol deviations for out-of-window visits."
-
System: Auto-generated deviations when visit completed outside window
-
"How do you track changes to the study database schema?"
- System: Alembic migration history, MetadataVersion ODM snapshots
9.2 Top 10 Common Failure Modes¶
| Failure Mode | System Prevention |
|---|---|
| 1. Data collected without consent | Consent gating at API, UI, background jobs |
| 2. Assessment under wrong battery version | Version binding at queue time, reconciliation on amendment |
| 3. Missing audit trail entries | Mandatory audit decorators, database triggers |
| 4. Unauthorized data modification | RBAC enforcement, data lock workflow |
| 5. Unapproved protocol changes | PI signature required for publication |
| 6. Lost in-flight data during amendment | Policy-based handling, audit of outcomes |
| 7. Export version mismatch | Version stamps embedded in export, provenance metadata |
| 8. Unresolved queries at lock | Lock blocked until all queries closed |
| 9. Invalid electronic signatures | 21 CFR Part 11 metadata requirements enforced |
| 10. Orphaned form/battery references | Validation on version publish, referential integrity |
9.3 Mitigation Strategies¶
- Defense in Depth: Enforce at UI, API, database levels
- Fail Closed: Block operation rather than allow potential violation
- Audit Everything: Every action generates immutable audit event
- Version Everything: No data without version stamps
- Require Reasons: Override actions require documented justification
- Automated Validation: System checks on every state transition
- Immutable History: Append-only audit tables, no modifications
- Separation of Duties: DM authors, PI approves
- Test Scenarios: Stress test suite for amendment workflows
- Export Validation: Automated SDTM/ODM validation on every export
Appendix A: ODM Element Mapping¶
| Metricis Entity | ODM Element |
|---|---|
| Study | ODM/Study |
| MetadataVersion | ODM/Study/MetaDataVersion |
| StudyEventDef | StudyEventDef |
| StudyEventInstance | StudyEventData |
| FormDefinition | FormDef |
| FormVersion | FormDef (versioned) |
| FormResponse | FormData |
| QuestionMap | ItemDef |
| Battery | FormDef (for assessments) |
| BatteryModule | ItemGroupDef |
| AssessmentInstance | FormData (with assessment context) |
| Response | ItemGroupData/ItemData |
| Participant | SubjectData |
| ConsentVersion | (custom extension or FormDef) |
| AuditEvent | AuditRecord |
Appendix B: Database Schema Changes Summary¶
New Tables:
- metadata_versions
- study_event_defs (replaces visit_windows)
- study_event_instances (replaces scheduled_visits)
- battery_versions
- assessment_instances
- consent_versions
- consent_documents
- consent_instances
- signature_captures
- event_consent_requirements
- event_battery_assignments
- assessment_item_mappings
- queries
- query_comments
Modified Tables:
- studies - Add current_metadata_version_id
- participants - Add subject_key, current_consent_version_id
- form_responses - Add consent_version_id, metadata_version_id
- sessions - Add assessment_instance_id, version stamps
- audit_logs - Add signature_meaning, ensure immutability
Appendix C: API Endpoint Additions¶
Metadata:
- GET/POST /api/studies/{id}/metadata-versions
- POST /api/metadata-versions/{id}/submit-review
- POST /api/metadata-versions/{id}/approve (requires signature)
- POST /api/metadata-versions/{id}/publish
- GET /api/metadata-versions/{id}/diff
Consent:
- GET/POST /api/studies/{id}/consent-versions
- POST /api/consent-versions/{id}/approve
- POST /api/participants/{id}/consent/initiate
- POST /api/consent-instances/{id}/sign
- GET /api/participants/{id}/consent/status
Assessments:
- GET/POST /api/studies/{id}/battery-versions
- GET /api/participants/{id}/assessment-queue
- POST /api/assessment-instances/{id}/deliver
- POST /api/assessment-instances/{id}/supersede
Queries:
- GET/POST /api/studies/{id}/queries
- POST /api/queries/{id}/respond
- POST /api/queries/{id}/close
End of Implementation Plan