Skip to main content

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-service with 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-service controllers; legacy modules stopped accepting new writes.
  • Legacy medication-management + pharmacy act 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_ordersmedication.prescriptions
    • medication-management.medication_administrationsmedication.medication_administrations
    • pharmacy.prescriptions (fulfillment rows) → medication.prescriptions (merged by gateway_medication_request_fhir_id)
    • pharmacy.dispensing_eventsmedication.dispensing_events
    • pharmacy.stock_itemsmedication.stock_items
    • pharmacy.alert_overridesmedication.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 via fhir-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 FRNew FR
FR-MEDS-001..003FR-MED-001..003 (medication list)
FR-MEDS-010..012FR-MED-010..012 (prescribing)
FR-MEDS-020..021FR-MED-020..021 (reconciliation)
FR-MEDS-030..032FR-MED-030..032 (safety checks)
FR-PHARM-009FR-MED-040 (gateway MR ingestion)
FR-PHARM-010FR-MED-041 (NCPDP optional)
FR-PHARM-033..034FR-MED-050..051 (CS dispense)
FR-PHARM-040..046FR-MED-060..066 (dispensing)
FR-PHARM-050..056FR-MED-070..076 (inventory)
FR-PHARM-060..064FR-MED-080..084 (pharmacy portal)
FR-PHARM-070..073FR-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

  1. Tenant created in tenant-service.
  2. Medication module licensing enabled.
  3. Formulary bootstrap (WHO EML default + tenant-specific additions).
  4. Pharmacy location hierarchy imported.
  5. Initial stock receipt loaded via POST /api/v1/stock-items in bulk.
  6. Clinician + pharmacist users provisioned.
  7. 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).