Patient Chart Service — Migration Plan
Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template · SERVICE_OVERVIEW §11 Source Reconciliation
1. Migration context
The patient-chart-service consolidates five legacy modules — patient-chart, problem-list, allergies, vitals, and clinical-notes — each previously operating as a separate module with its own schema prefix, outbox, and NATS subjects. This migration plan covers:
- Data migration from five legacy schemas into the unified
patient_chartschema. - NATS subject migration from legacy patterns to canonical
patient_chart.{aggregate}.{event}.v{N}. - Consumer service cutover from legacy REST paths to the new unified API surface.
- Decommissioning of legacy modules post-migration.
2. Legacy state inventory
| Legacy module | DB schema/prefix | NATS subjects | API prefix | Status |
|---|---|---|---|---|
patient-chart | chart.* | CHART.* | /api/v1/chart/* | Consolidate → patient_chart |
problem-list | problems.* | PROBLEMS.* | /api/v1/problems-legacy/* | Consolidate |
allergies | allergies.* | ALLERGIES.* | /api/v1/allergies-legacy/* | Consolidate |
vitals | vitals.* | VITALS.* | /api/v1/vitals-legacy/* | Consolidate |
clinical-notes | notes.* | CLINICAL_NOTES.* | /api/v1/notes-legacy/* | Consolidate |
3. Migration phases
4. Data migration tasks
Phase 1 — Schema and data migration
| Task | Description | Rollback |
|---|---|---|
Create patient_chart schema | Drizzle migration; no data yet | Drop schema (no data) |
Migrate problems.* → patient_chart.problem | ETL script; maps legacy ids to prb_* ULID; preserves history in problem_history_entry | Restore from pre-migration snapshot |
Migrate allergies.* → patient_chart.allergy | Map to alg_* ULID; preserve allergy_reaction sub-rows | Snapshot restore |
Migrate vitals.* → patient_chart.vitals_set + observation | Map measurement rows to per-observation model; group by recorded_at + patient_id + recorder_id | Snapshot restore |
Migrate notes.* → patient_chart.clinical_note + note_section + note_signature | Map status values; preserve cosign records | Snapshot restore |
ID remapping table: A legacy_id_map table in the migration schema tracks (legacy_module, legacy_id) → new_ulid for foreign-key re-stitching and cross-reference lookups during transition.
Phase 2 — Dual-publish NATS subjects
During M0→M1, the service publishes events on BOTH legacy and canonical subjects:
| Legacy subject | Canonical subject | Dual-publish until |
|---|---|---|
PROBLEMS.PROBLEM.ADDED | patient_chart.problem.added.v1 | End of M1 |
PROBLEMS.PROBLEM.UPDATED | patient_chart.problem.updated.v1 | End of M1 |
ALLERGIES.ALLERGY.ADDED | patient_chart.allergy.added.v1 | End of M1 |
VITALS.VITALS_SET.RECORDED | patient_chart.vitals.recorded.v1 | End of M1 |
CLINICAL_NOTES.NOTE.SIGNED | patient_chart.note.signed.v1 | End of M1 |
After M1 consumer cutover is confirmed, dual-publish is disabled and legacy subjects are deprecated.
5. API migration
| Legacy path | New path | Change |
|---|---|---|
GET /api/v1/problems-legacy/:id | GET /v1/problems/:id | New response shape (FHIR-aligned) |
POST /api/v1/problems-legacy | POST /v1/problems | Renamed + schema changes |
GET /api/v1/allergies-legacy/:patientId | GET /v1/allergies?patientId= | Query param-based |
POST /api/v1/vitals-legacy | POST /v1/vitals | Panel payload shape |
POST /api/v1/notes-legacy/draft | POST /v1/clinical-notes | Unified note create |
Kong routes updated to forward traffic to new paths; legacy routes kept active until M1 consumer cutover.
6. Consumer service cutover
| Consumer | Legacy event / API used | New event / API | Cutover milestone |
|---|---|---|---|
| medication-service | ALLERGIES.ALLERGY.ADDED | patient_chart.allergy.added.v1 | M1 |
| orders-service | GET /api/v1/allergies-legacy/advisory | GET /v1/allergies/advisory | M1 |
| population-health-service | PROBLEMS.*, VITALS.* | patient_chart.problem.*, patient_chart.vitals.* | M1 |
| patient-portal-service | Legacy chart read APIs | New /v1/chart/*, /v1/problems/*, etc. | M1 |
| interop-service (FHIR) | Condition, AllergyIntolerance, Observation FHIR reads | Same paths via new service | No change (FHIR paths unchanged) |
7. Tenant migration notes
- All existing tenants have their chart data migrated in Phase 1 with zero downtime (read path from legacy; write path switched after validation).
- The
legacy_id_maptable is kept alive for 90 days post-cutover for cross-reference lookups, then archived. - Tenants using FHIR read surface see no disruption;
interop-serviceFHIR paths are unchanged.
8. Rollback plan
| Phase | Rollback action | Data loss risk |
|---|---|---|
| Phase 1 (data migration) | Restore pre-migration DB snapshot; re-point Kong to legacy modules | Zero — snapshot taken immediately before |
| Phase 2 (dual-publish) | Disable canonical subject publish; revert to legacy subjects | Zero — legacy consumers unaffected during dual-publish |
| Phase 3 (API cutover) | Re-enable legacy Kong routes; dual-publish restored | Zero — traffic falls back to legacy |
9. Open questions
- Confirm
vitalsgrouping heuristic: what defines aVitalsSetboundary for legacy ungrouped measurements? - Determine fate of
requisitions-referralscross-links in clinical-notes (legacy ADR-0046 redirected to orders-service).