Radiation Treatment Plan Spine
Entity architecture: five E-PHIS RT requirements hanging off the Radiation Treatment Plan (Course) entity.
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 |