Medication Service — Migration Plan
Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template
1. Scope
Merges two legacy modules into the single medication-service:
medication-management(CLIN-MEDS)pharmacy(PHARM-RX)
Legacy databases / schemas and event streams are preserved during a dual-publish window; final cut-over removes legacy subjects.
2. Phases
Phase 0 — Scaffold (M1-Sprint 1)
- Create
medication-servicewith domain/app/infra/presentation layers. - Apply DATA_MODEL Postgres schema under new schema
medication. - Wire Kong routes; all traffic still served by legacy until Phase 2.
Phase 1 — Dual-write (M1-Sprint 2–3)
- New writes go through
medication-servicecontrollers; legacy modules stopped accepting new writes. - Legacy
medication-management+pharmacyact as read-only archive. - Events emitted on both legacy subjects and new
medication.*subjects.
Phase 2 — Backfill (M1-Sprint 3–4)
- Backfill job copies legacy rows into new schema:
medication-management.medication_orders→medication.prescriptionsmedication-management.medication_administrations→medication.medication_administrationspharmacy.prescriptions(fulfillment rows) →medication.prescriptions(merged bygateway_medication_request_fhir_id)pharmacy.dispensing_events→medication.dispensing_eventspharmacy.stock_items→medication.stock_itemspharmacy.alert_overrides→medication.alert_overrides
- Idempotent ETL with checksum comparison; reconciliation report.
Phase 3 — Read cut-over (M2-Sprint 1)
- Reads served from new service.
- Legacy FHIR endpoints redirect
/fhir/R4/Medication*to new service viafhir-gateway. - Clinical shell and pharmacy portal consume new
medication.*events only.
Phase 4 — Legacy sunset (M2-Sprint 4)
- Turn off legacy modules' write endpoints.
- Legacy event subjects marked deprecated; dual-publish ends.
- Legacy schemas archived to cold storage; read-only views kept for 7y per retention.
3. ID / FR Mapping
| Legacy FR | New FR |
|---|---|
| FR-MEDS-001..003 | FR-MED-001..003 (medication list) |
| FR-MEDS-010..012 | FR-MED-010..012 (prescribing) |
| FR-MEDS-020..021 | FR-MED-020..021 (reconciliation) |
| FR-MEDS-030..032 | FR-MED-030..032 (safety checks) |
| FR-PHARM-009 | FR-MED-040 (gateway MR ingestion) |
| FR-PHARM-010 | FR-MED-041 (NCPDP optional) |
| FR-PHARM-033..034 | FR-MED-050..051 (CS dispense) |
| FR-PHARM-040..046 | FR-MED-060..066 (dispensing) |
| FR-PHARM-050..056 | FR-MED-070..076 (inventory) |
| FR-PHARM-060..064 | FR-MED-080..084 (pharmacy portal) |
| FR-PHARM-070..073 | FR-MED-090..093 (audit & compliance) |
Legacy FR IDs preserved in EPICS/USER_STORIES "Legacy ref" column.
4. Event Migration
Dual-publish during M1–M2:
- Old:
MEDICATION.medication.signed,PHARMACY.dispensing.completed, etc. - New:
medication.prescription.signed.v1,medication.dispensing.completed.v1.
Consumers migrate one at a time. Subject retirement after 100% of consumers confirm on new subjects.
5. Tenant On-boarding Sequence
- Tenant created in tenant-service.
- Medication module licensing enabled.
- Formulary bootstrap (WHO EML default + tenant-specific additions).
- Pharmacy location hierarchy imported.
- Initial stock receipt loaded via
POST /api/v1/stock-itemsin bulk. - Clinician + pharmacist users provisioned.
- Smoke: test prescription + test dispense (in sandbox patient).
6. Rollback
- Phase 1: rollback by disabling new writes, legacy re-accepts. Data loss: zero.
- Phase 2: rollback requires reverse-ETL — only if corruption found; document reverse script before Phase 2 ends.
- Phase 3: after read cut-over, rollback = route reads back to legacy; new writes retained and backfilled on retry.
- Phase 4: sunset — no rollback.
7. Risks
See SERVICE_RISK_REGISTER MED-R-009 (legacy event residue) and MED-R-011 (volume at scale).