medOS ultra

Radiation Treatment Plan Spine

Entity architecture: five E-PHIS RT requirements hanging off the Radiation Treatment Plan (Course) entity.

4 min read diagramsUpdated 2026-05-07docs/architecture/radiation-treatment-plan-spine.md

Overview

Five E-PHIS requirements (3.12.1.1 through 3.12.1.6) all hang off a single spine: the Radiation Treatment Plan (Course) entity. Everything else is either an input that produces it, a decomposition of it, an artifact within it, or a view onto it.

Entity Relationship Diagram

erDiagram
    Patient ||--o{ TumorConferenceNote : "discussed at"
    Patient ||--o{ RadiationTreatmentPlan : "has"
    TumorConferenceNote }o--o{ RadiationTreatmentPlan : "reviews / produces"
    RadiationServiceRequest ||--|| RadiationTreatmentPlan : "initiates"
    RadiationTreatmentPlan ||--|{ TreatmentPhase : "decomposed into"
    TreatmentPhase ||--|| Prescription : "has"
    TreatmentPhase ||--o{ ProcedureCode : "coded as"
    TreatmentPhase ||--|{ Appointment : "scheduled as"
    Appointment ||--o| FractionDelivery : "becomes"
    FractionDelivery }o--o{ ProcedureCode : "billed as"

RadiationTreatmentPlan (= Course in oncology vocabulary) is the spine. TreatmentPhase is your “Cycle” – in EBRT it’s typically initial + boost phases; in brachy it’s insertion sessions; the abstraction holds across modalities.

Where Each Requirement Lives

3.12.1.1 (สั่งรายการการตรวจรักษาด้วยรังสี) – Radiation Service Request

RadiationServiceRequest (FHIR ServiceRequest). The order is the entry point; on accept it either creates or attaches to a RadiationTreatmentPlan. This is what makes RT different from an OPD lab order – one order spawns a longitudinal plan, not a single procedure.

Mini-app: RadiationServiceRequest

3.12.1.2 (Tumor Conference) – MDT Conference Note

TumorConferenceNote. M:N with the plan via a link table, because (a) one conference reviews many patients, and (b) one plan may be re-reviewed at later conferences (re-staging, mid-treatment, post-treatment). Don’t model this 1:1 – you’ll regret it the first time someone re-presents at MDT.

Mini-app: TumorConference

3.12.1.3 (continuous history as cycles or same plan) – Treatment History View

This is not a new table, it’s a view. Given treatment_plan_id, you union all child entities (conference notes, orders, phases, prescriptions, appointments, delivered fractions, codes) ordered by timestamp. The architectural commitment that makes this free is the FK rule below.

Mini-app: RadiationTherapyCycleTracker (Treatment History tab)

3.12.1.4 (รหัสการฉายรังสี) – Procedure Codes

Codes attach at two levels: plan-level (intent: curative/palliative; modality: EBRT/IMRT/VMAT/SBRT/Brachy; ICD-10 diagnosis) and procedure-level (TMLT / ICD-9-CM Vol 3 per fraction or per phase, for สปสช./ประกันสังคม reimbursement). Use a polymorphic coded_concept table joined to whichever entity is being coded.

Mini-app: RadiationProcedureCoding

3.12.1.6 (cycle-based appointments) – Appointment Scheduling

Generated from the prescription, not entered manually. Prescription says “30 fx, Mon-Fri, 2 Gy/fx, start 2026-05-15” -> system bulk-creates 30 Appointment rows, each carrying treatment_plan_id, phase_id, and fraction_number. Reschedule logic operates on the cycle as a unit (delay one fraction -> cascade or hold the rest).

Mini-app: RadiationTherapyCycleTracker (Cycle Appointments tab)

The Single FK Rule That Makes It All Work

Every RT-related row carries treatment_plan_id as a first-class column – orders, conference notes, phases, prescriptions, appointments, fractions, codes, billing entries, even free-text progress notes if they’re RT-scoped. Not nullable for RT-scoped tables.

Once that’s in place:

  • 3.12.1.3 (history view) is a single query.
  • 3.12.1.6 (cycle continuity) is automatic – appointments are children of phases which are children of plans.
  • Cross-cutting concerns (audit, consent, billing rollup, treatment summary letter) all pivot on the same key.

FHIR R4 Mapping (for IN-01 Alignment)

Internal FHIR R4
RadiationServiceRequest ServiceRequest
RadiationTreatmentPlan CarePlan (category = oncology-rt)
TumorConferenceNote ClinicalImpression + Composition (formal note)
TreatmentPhase / Cycle CarePlan.activity (nested) – or a child CarePlan if you want each phase queryable on its own
Prescription (custom; closest is ServiceRequest with detail or MedicationRequest analog)
Appointment Appointment
FractionDelivery Procedure
Codes CodeableConcept everywhere

CarePlan-with-nested-activities is cleaner if phases are tightly coupled to one course; child CarePlans are cleaner if phases need independent lifecycle (status, review, billing rollup). For Thai government hospital workflows where each phase often has its own approval and billing cycle, child CarePlans win – and that’s a registry decision worth locking in early in the workflow_templates / channel_registry layer.

The One Subtle Thing

Tumor Conference is the only entity that’s M:N with the plan. Everything else is a clean parent-child hierarchy. If you put the M:N link table in early (tumor_conference_plan_link with role: ‘pre-treatment’ / ‘mid-treatment’ / ‘post-treatment’ / ‘re-staging’), you get the longitudinal MDT story for free, which is what oncologists actually want to see in the chart.

Mini-App Linking Architecture

All RT mini-apps share a common treatment_plan_id context. Cross-navigation between mini-apps uses the DynamicContentProvider dispatch to open a sibling mini-app with the same plan context:

// Shared context shape -- all RT mini-apps receive this
interface RTContext {
  treatmentPlanId: string;
  patientId: string;
  currentPhaseId?: string;
}

// Navigation helper -- used by link chips in each mini-app
function openRTMiniApp(tabName: DynamicCoreApp, rtContext: RTContext) {
  dispatch(openDynamicContent({
    tabName,
    extraProps: { rtContext },
  }));
}

Mini-App Registry

DynamicCoreApp Enum Mini-App Requirement Role
RADIATION_SERVICE_REQUEST RadiationServiceRequest 3.12.1.1 Order entry -> creates plan
TUMOR_CONFERENCE TumorConference 3.12.1.2 MDT review (M:N with plan)
RADIATION_THERAPY_CYCLE_TRACKER RadiationTherapyCycleTracker 3.12.1.3 + 3.12.1.6 History + scheduling spine
RADIATION_PROCEDURE_CODING RadiationProcedureCoding 3.12.1.4 Code management
RADIATION_ONCOLOGY_INTAKE_PLANNING (existing) Intake forms
RADIATION_ONCOLOGY_TREATMENT_DAILY_CARE (existing) Daily care forms
RADIATION_ONCOLOGY_QUALITY_ASSURANCE (existing) QA forms
RADIATION_ONCOLOGY_POST_TREATMENT_FOLLOWUP (existing) Follow-up forms
Ask Anything