Skip to main content

Initial Setup & Configuration

After Bundle Deployment, this guide covers the Frappe provisioning that creates the CTMS data model, RBAC, and seed data.

Automated by zynctl.sh

The zynctl.sh deploy command runs all 5 stages automatically via the ctms-init container. This page is a reference for what each stage creates and how to run them manually if needed.


Frappe Provisioning Overview

The CTMS platform extends Frappe Cloud with a data model created in 5 stages:

StageCreatesCount
1Custom DocTypes34 (across 4 dependency phases)
2Custom Fields on built-in DocTypes15 fields
3RBAC data (Frappe native roles, CTMS roles, resources, permissions)539 records
4Master/seed data (lookups, drugs, sites, study events)127 records
5Default Healthcare Practitioner1 record

Automated Provisioning (Docker)

The ctms-init container runs all 5 stages automatically:

docker compose --env-file .env.production --profile init up ctms-init

Selective or dry-run:

# Run only stages 3 and 4
CTMS_INIT_STAGES=3,4 docker compose --env-file .env.production run --rm ctms-init

# Run only Stage 5 (default practitioner)
CTMS_INIT_STAGES=5 docker compose --env-file .env.production run --rm ctms-init

# Preview without making changes
CTMS_INIT_DRY_RUN=true docker compose --env-file .env.production run --rm ctms-init
Idempotent

The init scripts are idempotent — they skip existing records. Safe to re-run at any time.

Manual Provisioning (Python Scripts)

For granular control, run each stage individually using the Python seed scripts.

Prerequisites

  • Python 3.10+ installed
  • The environment file configured with Frappe credentials:
FRAPPE_URL=https://your-frappe-instance.frappe.cloud
FRAPPE_API_TOKEN=api-key:api-secret

The scripts support both FRAPPE_API_TOKEN=key:secret and separate FRAPPE_API_KEY / FRAPPE_API_SECRET formats.

# One-time setup
cd ctms.devops/scripts/frappe-seed
python -m venv venv
source venv/bin/activate
pip install requests python-dotenv structlog

Step 1: Create Custom DocTypes

Create all 34 custom DocTypes in the correct dependency order across 4 phases:

PhaseCountDocTypesDescription
1 – Standalone15CTMS Role, CTMS Resource, CTMS Action, Study Status, Study Type, Study Phase, Event Type, Site Status, Intervention Model, Masking, Control, Allocation, Classification, Purpose, zynomi_drug_masterNo dependencies on other custom DocTypes
2 – Links Phase 15CTMS Permission, CTMS Navigation, Study Event, Site Location, StudyLink fields reference Phase 1 DocTypes
3 – Links Phase 25CTMS Nav Permission, Site, Subject, Consent, FamilyMedicalHistoryLink fields reference Phase 2 DocTypes
4 – Links Phase 39Study Sites, study_personnel, PhysicalExamination, AdverseEvents, Study CRF, CRF_FORM_MICRONUTRIENTS_ANTIOXIDANTS_HIV_INFECTION, 3 CRF formsLink fields reference Phase 3 DocTypes

The DocTypes break down into three functional categories:

  • RBAC (6): CTMS Role, Resource, Action, Permission, Navigation, Nav Permission
  • Study Design (7): Intervention Model, Masking, Control, Allocation, Classification, Purpose, zynomi_drug_master
  • Clinical / CRF (21): Study, Subject, Site, Consent, CRF forms, Study CRF, etc.

Running the Script

cd ctms.devops/scripts/frappe-seed
source venv/bin/activate

# Preview (dry run)
python frappe_setup_custom_doctypes.py --dry-run --env ../../.env.example

# Create ALL 34 custom DocTypes
python frappe_setup_custom_doctypes.py --env ../../.env.example

# Create subsets
python frappe_setup_custom_doctypes.py --rbac-only --env ../../.env.example # 6 RBAC DocTypes
python frappe_setup_custom_doctypes.py --clinical-only --env ../../.env.example # 28 clinical DocTypes
FlagDescription
--env <path>Path to environment file (e.g., ../../.env.example)
--dry-runPreview what would be created without making changes
--rbac-onlyCreate only the 6 CTMS RBAC DocTypes
--clinical-onlyCreate only the 28 clinical/study-design/CRF DocTypes
--log-levelLogging verbosity: DEBUG, INFO, WARNING, ERROR (default: INFO)
Order Matters

DocTypes must be created in phase order because later phases reference earlier ones via Link fields. The script handles this automatically.


Step 2: Create Custom Fields on Built-in DocTypes

Add custom fields to Frappe's built-in DocTypes. These extend standard Healthcare module entities with CTMS-specific attributes.

What Gets Created

Built-in DocTypeFieldTypeDescription
Healthcare PractitionereducationTextEducational qualifications
Healthcare PractitionerexperienceIntYears of professional experience
Healthcare PractitionerbiographyText EditorProfessional biography (rich text)
Healthcare PractitionersurgeriesIntNumber of surgeries performed
Vital Signsstudy_eventLink → Study EventAssociates vital signs with a study event
Vital SignsstudyLink → StudyAssociates vital signs with a study
PatientheightDataPatient height
PatientweightDataPatient weight
Drug Prescriptionsend_remindersCheckEnable medication reminders
Drug Prescriptionsnooze_afterSmall TextSnooze reminder configuration
Drug Prescriptionstart_dateDatePrescription start date
Drug Prescriptionend_dateDatePrescription end date
Nursing Taskclinical_trialSelectAssociate nursing task with a clinical trial

Total: 15 custom fields across 5 built-in DocTypes.

Running the Script

# Preview
python frappe_setup_custom_fields.py --dry-run --env ../../.env.example

# Create all custom fields
python frappe_setup_custom_fields.py --env ../../.env.example

# Create fields for a specific DocType
python frappe_setup_custom_fields.py --doctype "Healthcare Practitioner" --env ../../.env.example
FlagDescription
--env <path>Path to environment file
--dry-runPreview without making changes
--doctype <name>Create custom fields for a specific DocType only
--log-levelLogging verbosity (default: INFO)
Idempotent

Existing fields are skipped. Safe to re-run at any time.


Step 3: Seed RBAC Data

Seed the complete RBAC (Role-Based Access Control) configuration from the baseline application.

What Gets Seeded

DocTypeCountDescription
Role (Frappe native)4Platform Administrator, Study Designer, Study Coordinator, Principal Investigator — created in Frappe's built-in Role DocType so user signup can assign roles via Link fields
CTMS Role4Same 4 roles in the CTMS custom DocType — used by the RBAC permission matrix
CTMS Resource24Protected resources (study, subject, site, form, event, user, etc.)
CTMS Action8create, read, update, delete, export, import, bulk_delete, generate
CTMS Permission488Complete role × resource × action permission matrix
CTMS Navigation11Dashboard, Studies, Subjects, Sites, eCRF Designer, Reports, Management, etc.

Running the Script

# Seed all RBAC data
python frappe_seed_rbac.py --seed-defaults --env ../../.env.example

# Preview changes
python frappe_seed_rbac.py --seed-defaults --dry-run --env ../../.env.example
FlagDescription
--seed-defaultsSeed default roles, resources, actions, permissions, and navigation
--allCreate RBAC DocTypes and seed data (legacy — prefer Step 1 + --seed-defaults)
--dry-runPreview without making changes
--env <path>Path to environment file
--log-levelLogging verbosity (default: INFO)
Verification

After seeding, verify at your Frappe instance:

  • Frappe native Roles: https://your-frappe-url/api/resource/Role?filters=[["name","in",["Platform Administrator","Study Designer","Study Coordinator","Principal Investigator"]]]
  • CTMS Roles: https://your-frappe-url/app/ctms-role
  • Permissions: https://your-frappe-url/app/ctms-permission

Expected totals: 4 Frappe native roles, 4 CTMS roles, 24 resources, 8 actions, 488 permissions (539 total records).

Idempotent & Safe

Uses upsert logic: creates missing records, updates records that differ, skips unchanged records.


Step 4: Seed Master / Reference Data

Populate study-design lookup tables, medical departments, laboratory items, the drug catalogue, clinical trial sites, and study events.

What Gets Seeded

Study-Design Lookups

DocTypeCountDescription
Intervention Model4Crossover, Factorial, Parallel, Single Group
Masking5Open Label, Single / Double / Triple / Quadruple Blind
Control5Active, Dose Comparison, Historical, No Treatment, Placebo
Allocation3Randomized, Non-Randomized, Not Applicable
Classification7Bioavailability, Bioequivalence, Efficacy, PK, PD, Safety, Safety/Efficacy
Purpose7Basic Science, Diagnostic, HSR, Prevention, Screening, Supportive Care, Treatment
Event Type3Common, Screening, Visit Based
Study Type2Interventional, Observational
Study Phase4Phase I, Phase II, Phase III, Phase IV
Study Status5Planning, Recruiting, Active, Completed, Suspended
Site Status3Active, Inactive, Pending

Clinical Infrastructure

DocTypeCountDescription
Medical Department1Clinical Trial
Item (Laboratory)4Laboratory, Imaging, USG Abdomen, X-Ray Chest
Location1Princeton - College Road

Study Events

DocTypeCountDescription
Study Event17Screening Visit, Baseline Visit, Cycle 1 Day 1/8/15, Cycle 2 Day 1/8/15, Cycle 3 Day 1, End of Treatment, 30-Day Follow-up, Final Visit, Early Termination, Unscheduled Visit (repeating), Adverse Event (repeating), Visit 1, Visit 2

Study events represent milestones and visits in a clinical trial schedule. They are used to link CRF forms, Adverse Events, Vital Signs, and other clinical data to specific timepoints.

Demo Sites (Sample Data)

Demo Data

Site Locations and Sites are sample/demo data for multi-site clinical trial demonstrations. Replace or extend these with your actual site information for production use.

DocTypeCountDescription
Site Location2Memorial Cancer Center (New York, NY), Johns Hopkins Oncology Center (Baltimore, MD)
Site2Memorial Cancer Center - Oncology Trials Unit (120 participants), Johns Hopkins - Sidney Kimmel Clinical Trials (80 participants)

Drug Catalogue

DocTypeCountDescription
zynomi_drug_master52Drug catalogue with ATC codes, dosage forms, and status

Summary

CategoryRecords
Study-design lookups48
Clinical infrastructure6
Study events17
Demo sites (locations + sites)4
Drug catalogue52
Total127

Running the Script

# Seed all master data
python frappe_seed_master_data.py --env ../../.env.example

# Preview changes
python frappe_seed_master_data.py --dry-run --env ../../.env.example

# Seed subsets
python frappe_seed_master_data.py --lookups-only --env ../../.env.example # 31 lookup records
python frappe_seed_master_data.py --drugs-only --env ../../.env.example # 52 drug records
FlagDescription
--env <path>Path to environment file
--dry-runPreview without creating
--lookups-onlySeed only study-design lookup tables (31 records)
--drugs-onlySeed only drug master catalogue (52 records)
--log-levelLogging verbosity (default: INFO)
Verification

After seeding, verify at your Frappe instance:

  • Study Design: https://your-frappe-url/app/intervention-model, /app/masking, /app/control, etc.
  • Study Events: https://your-frappe-url/app/study-event
  • Sites: https://your-frappe-url/app/site
  • Site Locations: https://your-frappe-url/app/site-location
  • Drug Master: https://your-frappe-url/app/zynomi_drug_master

Expected totals: 48 lookups + 6 clinical infra + 17 study events + 4 demo sites + 52 drugs = 127 records.

Idempotent

Skips records that already exist (matched by name or drug_code). Safe to re-run.


Step 5: Create Default Healthcare Practitioner

Create the default Healthcare Practitioner used by the CTMS platform. The practitioner's auto-generated ID is referenced as NEXT_PUBLIC_DEFAULT_PRACTITIONER_ID in all deployment .env files.

What Gets Created

DocTypeCountDescription
Healthcare Practitioner1Mary Williams — default practitioner (naming series: HLC-PRAC-.YYYY.-)

Practitioner details:

FieldValue
First NameMary
Last NameWilliams
GenderFemale
DepartmentClinical Trial (created in Stage 4)
StatusActive
Practitioner TypeExternal

Running the Script

# Create the default practitioner
python frappe_seed_practitioner.py --env ../../.env.example

# Preview (dry run)
python frappe_seed_practitioner.py --dry-run --env ../../.env.example
FlagDescription
--env <path>Path to environment file
--dry-runPreview without making changes
--log-levelLogging verbosity (default: INFO)

Environment variable overrides:

VariableDefaultDescription
PRACTITIONER_FIRST_NAMEMaryFirst name
PRACTITIONER_LAST_NAMEWilliamsLast name
PRACTITIONER_GENDERFemaleGender
PRACTITIONER_DEPARTMENTClinical TrialMedical department (must exist)
PRACTITIONER_STATUSActiveStatus
PRACTITIONER_TYPEExternalPractitioner type

Output

After creation, the script prints the auto-generated practitioner ID:

  ┌─────────────────────────────────────────────────────┐
│ NEXT_PUBLIC_DEFAULT_PRACTITIONER_ID=HLC-PRAC-2026-00001
│ PRACTITIONER_NAME="Mary Williams"
│ │
│ Update these values in your .env / .env.<instance> │
└─────────────────────────────────────────────────────┘

Copy these values into your .env / .env.<instance> file.

Idempotent

If a practitioner with the same first name and last name already exists, the script skips creation and prints the existing practitioner's ID.

Manual Alternative (API Gateway)

If you prefer to create the practitioner manually (e.g., via the API Gateway or Frappe UI):

Option A: REST API via API Gateway

# Create Healthcare Practitioner via API Gateway
curl -X POST "https://your-frappe-url/api/resource/Healthcare%20Practitioner" \
-H "Authorization: token <api_key>:<api_secret>" \
-H "Content-Type: application/json" \
-d '{
"naming_series": "HLC-PRAC-.YYYY.-",
"first_name": "Mary",
"last_name": "Williams",
"gender": "Female",
"status": "Active",
"practitioner_type": "External",
"department": "Clinical Trial"
}'

The response data.name field contains the practitioner ID (e.g., HLC-PRAC-2026-00001).

Option B: Frappe UI

  1. Navigate to https://your-frappe-url/app/healthcare-practitioner/new.
  2. Fill in: First Name: Mary, Last Name: Williams, Gender: Female, Department: Clinical Trial, Status: Active, Type: External.
  3. Click Save. The practitioner ID will appear in the URL bar.

After Manual Creation

Update your .env file:

NEXT_PUBLIC_DEFAULT_PRACTITIONER_ID=HLC-PRAC-2026-XXXXX
PRACTITIONER_NAME="Mary Williams"
Prerequisite

The "Clinical Trial" medical department must exist before creating the practitioner (it is created in Stage 4). If running manually, ensure Stage 4 has been completed first, or create the department manually at https://your-frappe-url/app/medical-department/new.


Supabase Table Provisioning (Required for All Deployments)

In addition to Frappe provisioning, the ctms-supabase-seed container creates CTMS-specific tables in the Supabase PostgreSQL database. This is required for both cloud and self-hosted Supabase.

docker compose --env-file .env.production --profile init run --rm ctms-supabase-seed

This creates:

  • profiles table (auto-linked to auth.users via trigger)
  • devices table
  • medication_consumption_logs table
  • notification_logs table
  • get_medication_status() function
  • Row-Level Security policies on all tables

For cloud Supabase, set DATABASE_URL and SUPABASE_AUTH_URL in your .env file to point to your managed instance.

Already Created Tables Manually?

If you previously created these tables via the Supabase SQL Editor, the seed container will detect them and skip creation. The container approach is recommended as it creates all tables, functions, and RLS policies consistently.


Branding & Logo Configuration

Customize the platform's logo and branding by providing logo files and setting environment variables.

Environment Variables

VariableDescriptionExample
NEXT_PUBLIC_LOGO_PREFIXPath prefix to logo files (without extension)/i/mycompany/logo
NEXT_PUBLIC_LOGO_EXTFile extensionpng or svg
NEXT_PUBLIC_BRAND_NAMEClient brand name (leave blank for unbranded)MyCompany
NEXT_PUBLIC_SITE_URLSite URL for SEOhttps://your-domain.com
NEXT_PUBLIC_SITE_DESCRIPTIONDescription for search enginesClinical Trial Management
NEXT_PUBLIC_OG_IMAGEOpenGraph image path/og-image.png

Required Logo Files

Based on the prefix and extension, provide these four files in the public/ folder:

File PatternUsageExample
{prefix}.{ext}Main logo (light/default)/i/mycompany/logo.png
{prefix}-dark.{ext}Main logo (dark variant for sidebar)/i/mycompany/logo-dark.png
{prefix}-mark.{ext}Logo mark/icon (light/default)/i/mycompany/logo-mark.png
{prefix}-mark-dark.{ext}Logo mark (dark variant for collapsed sidebar)/i/mycompany/logo-mark-dark.png

Logo Usage by Context

ContextLogo Used
Login / Signup pagesMain logo ({prefix}.{ext})
Sidebar (expanded)Dark variant ({prefix}-dark.{ext})
Sidebar (collapsed)Mark dark variant ({prefix}-mark-dark.{ext})
VariableDescription
NUXT_PUBLIC_APP_NAMEApp name shown in Sublink
NUXT_PUBLIC_APP_TAGLINEApp tagline
tip

For best results, use transparent PNG or SVG files. Dark variants should be visible on dark/colored backgrounds (typically white or light-colored logos).


Setup Checklist

StepActionStatus
1Create 34 custom DocTypes
2Create 15 custom fields on built-in DocTypes
3Seed 539 RBAC records (incl. 4 Frappe native roles)
4Seed 88 master data records
5Create default Healthcare Practitioner
6Configure branding & logo files

Next Steps