Medication Service — Domain Model
Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template · FHIR-first
1. Aggregates
| Aggregate | Root entity | Key invariants |
|---|---|---|
| MedicationListItem | MedicationListItem | One active entry per (patient, medicationCode, source); status transitions follow FHIR MedicationRequest.status vocabulary |
| Prescription | Prescription | Signed prescriptions cannot modify dose/drug; discontinued is terminal; refillsDispensed ≤ refillsAuthorized |
| DispensingEvent | DispensingEvent | Dispense requires active prescription; atomic inventory decrement; Schedule II requires counter-sign by distinct actor |
| StockItem | StockItem | quantity_on_hand ≥ 0; expired or recalled lots blocked from dispense |
| MedicationAdministration | MedicationAdministration | Immutable once recorded; corrections are new entries linked to prior |
| ReconciliationSession | ReconciliationSession | One open session per (patient, encounter, type); completion freezes diff decisions |
| AlertOverride | AlertOverride | Reason ≥ 10 chars; drug-KB snapshot version required; actor distinct from system |
2. Prescription State Machine
3. Entities & Value Objects
| Name | Type | Notes |
|---|---|---|
Medication | VO | Code (RxNorm/ATC/NDC/local), display, form, strength, isControlled, schedule |
Sig | VO | Dose amount + unit, route, frequency, duration, PRN indication, additional instructions |
Quantity | VO | Amount + unit (UCUM) |
Dose | VO | Amount + unit; includes min/max range for check |
PrescriberSignature | VO | Actor ID, signed_at, credential ref, signing device |
CounterSign | VO | Actor ID (≠ dispenser), timestamp, reason |
LotNumber | VO | Manufacturer lot identifier |
ExpiryDate | VO | ISO date; validation at receipt + dispense |
ReferenceRange | VO | For dose sanity, context: pediatric/adult/renal |
KbSnapshot | VO | Drug KB version + hash at alert evaluation |
RouteCode | VO | Coded route (oral, IV, IM, SC, topical, ophthalmic, etc.) |
4. Aggregate Relationships
5. Domain Events
| Event | Emitted when | FHIR resource |
|---|---|---|
medication.prescription.drafted.v1 | Prescriber starts a draft | MedicationRequest.status=draft |
medication.prescription.signed.v1 | Sign action, passes safety checks or override | MedicationRequest.status=active |
medication.prescription.discontinued.v1 | Discontinue with reason | MedicationRequest.status=stopped |
medication.prescription.held.v1 | Hold | MedicationRequest.status=on-hold |
medication.prescription.resumed.v1 | Resume | MedicationRequest.status=active |
medication.alert.overridden.v1 | Prescriber overrides blocking alert | DetectedIssue |
medication.dispensing.completed.v1 | Pharmacist completes dispense | MedicationDispense |
medication.dispensing.partial.v1 | Partial dispense | MedicationDispense.status=in-progress |
medication.dispensing.returned.v1 | Return/undispense | MedicationDispense.status=cancelled |
medication.administration.recorded.v1 | MAR event | MedicationAdministration |
medication.reconciliation.completed.v1 | Reconciliation session complete | MedicationStatement[] |
medication.inventory.stock_received.v1 | GRN | SupplyDelivery |
medication.inventory.reorder_alert.v1 | Below reorder point | n/a |
medication.inventory.expiry_alert.v1 | Within expiry horizon | n/a |
medication.inventory.recall_triggered.v1 | Lot marked recalled | DetectedIssue |
medication.controlled_substance.dispensed.v1 | Schedule II–V dispense | MedicationDispense + Provenance |
6. Ubiquitous Language
| Term | Definition |
|---|---|
| Sig | Structured prescription instructions (dose/route/frequency/duration) |
| MAR | Medication Administration Record; list of MedicationAdministration events |
| DAW | Dispense As Written — brand substitution prohibited |
| Counter-sign | Second-actor signature required for controlled-substance dispense |
| Accessioning (pharmacy) | Inventory receipt registration (not same as LIS) |
| Formulary | Tenant-curated list of allowed medications with substitution rules |
| Reconciliation | Comparing "home meds" vs facility meds with explicit continue/discontinue/modify per line |
| KB snapshot | Version hash of drug knowledge base at alert evaluation time |
| Partial dispense | Dispense of quantity < total authorized, with remaining balance |
| Emergency override | Pharmacist override of blocking check (insufficient stock, expired lot) with captured reason |
7. Invariants (enforced in domain)
- Prescription may only be signed after safety checks pass or every blocking alert has an
AlertOverride. - Dispense cannot proceed against expired or recalled lot — even with prescription active.
- Schedule II dispense requires
counterSign.actor ≠ dispenser.actor. - Inventory atomic decrement:
quantity_on_handmust not go negative. - Reconciliation completion requires each list item explicitly actioned (continue / discontinue / modify).
- A discontinued prescription cannot be re-signed; a new prescription replaces it.
- Override reason must be ≥ 10 printable characters.
8. Open Questions
- Licensed drug KB vendor choice (First Databank vs Medi-Span vs local+WHO EML) — pending tenant policy.
- Pediatric dose-range computations for weight-banded sigs: formulary-driven vs KB-driven.