Skip to main content

Patient Chart Service — User Stories

Service: patient-chart-service Story prefix: CHART-US Last updated: 2026-04-18

Stories


CHART-US-001 — Add problem to patient chart

FieldValue
Issue typeStory
SummaryClinician adds coded problem to patient problem list
Epic linkCHART-EPIC-01
StatusTo Do
PriorityMust
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service, terminology-service
FR referencesFR-CHART-001
Legacy FR refsFR-PROB-001
Dependenciescross-service: TERM-US-001

User story: As a clinician, when I diagnose a patient, I want to add a coded problem (ICD-10/11 or SNOMED CT) to the problem list so that the condition is part of the permanent longitudinal record and visible to all providers.

Acceptance criteria (Gherkin):

  • Given a valid patient ID and an ICD-10 code resolved via terminology-service, when I POST to /v1/problems, then a Problem is created with clinicalStatus=active and patient_chart.problem.added.v1 is emitted.
  • Given an ICD-10 code is not available, when I submit free-text, then the problem is created with codingPending=true and a codingTask flag.
  • Given the same coded condition is already active, when I attempt to add it again, then 422 CHART_DUPLICATE_PROBLEM is returned.

Technical notes:

  • Terminology lookup via TerminologyClient port.
  • prb_ ULID prefix; ProblemHistoryEntry created on each status change.

Definition of Done:

  • Unit: all state transitions tested. Integration: tenant-isolation, outbox, duplicate-problem.
  • FHIR Condition read surface verified.

CHART-US-002 — Update problem status (resolve, inactivate)

FieldValue
Issue typeStory
SummaryClinician resolves or inactivates an existing problem
Epic linkCHART-EPIC-01
StatusTo Do
PriorityMust
Story points3
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service
FR referencesFR-CHART-002
Legacy FR refsFR-PROB-002
DependenciesCHART-US-001

User story: As a clinician, when a patient's condition has resolved or is no longer active, I want to update the problem status so that the problem list accurately reflects the current clinical state.

Acceptance criteria (Gherkin):

  • Given an active problem, when I PATCH status to resolved with an abatementDate, then patient_chart.problem.resolved.v1 is emitted.
  • Given a resolved problem, when I attempt to set abatementDate on an active problem without changing status, then 422 is returned.
  • Given an entered-in-error status, when I attempt to reverse it, then 422 CHART_PROBLEM_IMMUTABLE is returned.

Technical notes:

  • Optimistic concurrency via version field.
  • ProblemHistoryEntry appended on each status change.

Definition of Done:

  • All six state transitions unit tested; history entry created in integration test.

CHART-US-003 — Mark problem entered-in-error

FieldValue
Issue typeStory
SummaryClinician corrects erroneously recorded problem
Epic linkCHART-EPIC-01
StatusTo Do
PriorityShould
Story points2
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service
FR referencesFR-CHART-003
Legacy FR refsFR-PROB-003
DependenciesCHART-US-001

User story: As a clinician, when a problem was entered in error, I want to mark it as entered-in-error with a reason so that the record is corrected without destroying the history.

Acceptance criteria (Gherkin):

  • Given an active or resolved problem, when I mark it entered-in-error with a reason, then verificationStatus=entered-in-error and patient_chart.problem.entered_in_error.v1 is emitted.
  • Given reason is absent, when entered-in-error is attempted, then 422 with validation error.
  • Given the problem is already entered-in-error, when any further mutation is attempted, then 422 CHART_PROBLEM_IMMUTABLE.

Definition of Done:

  • Unit test: reason required. Integration test: entered_in_error.v1 emitted.

CHART-US-004 — Record allergy/intolerance

FieldValue
Issue typeStory
SummaryClinician records medication or food allergy with reactions
Epic linkCHART-EPIC-02
StatusTo Do
PriorityMust
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service
FR referencesFR-CHART-004
Legacy FR refsFR-ALG-001
DependenciesCHART-US-001

User story: As a clinician, when a patient reports an allergy or adverse reaction, I want to record the substance, category, reactions (manifestation + severity), and verification status so that the allergy drives safety checks at order entry.

Acceptance criteria (Gherkin):

  • Given no active NKA, when I POST a medication allergy with reactions, then Allergy created with active status and patient_chart.allergy.added.v1 emitted.
  • Given an active NKA record, when I attempt to add a substance allergy, then 422 CHART_NKA_CONFLICT.
  • Given the same coded substance is already active, when I add a duplicate, then 422 CHART_DUPLICATE_ALLERGY.

Technical notes:

  • alg_ ULID prefix. AllergyReaction stored per reaction within the aggregate.
  • Event consumed by medication-service to refresh allergy-safety-check cache.

Definition of Done:

  • NKA conflict, NKDA conflict, duplicate allergy tested in integration.
  • Contract test: allergy.added.v1 schema conforms.

CHART-US-005 — Assert No Known Allergies (NKA / NKDA)

FieldValue
Issue typeStory
SummaryClinician asserts NKA or NKDA status
Epic linkCHART-EPIC-02
StatusTo Do
PriorityMust
Story points3
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service
FR referencesFR-CHART-004
Legacy FR refsFR-ALG-002
DependenciesCHART-US-004

User story: As a clinician, when a patient has no known allergies, I want to explicitly assert NKA or NKDA so that the absence of allergies is a documented clinical finding rather than simply missing data.

Acceptance criteria (Gherkin):

  • Given no active allergies, when I assert NKA, then an Allergy with nka=true is created.
  • Given an active NKA, when a new substance allergy is added, then NKA is automatically inactivated before the new allergy is created.
  • Given an active NKDA, when NKA is asserted, then NKDA is inactivated.

Definition of Done:

  • NKDA auto-inactivation on NKA assert tested. Advisory reflects NKA status.

CHART-US-006 — Allergy advisory API

FieldValue
Issue typeStory
SummarySync allergy advisory for medication-service and orders-service
Epic linkCHART-EPIC-02
StatusTo Do
PriorityMust
Story points3
Labelsservice:patient-chart-service, type:api, slice:S0
Componentspatient-chart-service, medication-service, orders-service
FR referencesFR-CHART-005
Legacy FR refsFR-ALG-003
DependenciesCHART-US-004, cross-service: MED-US-001, ORDERS-US-001

User story: As the medication or orders service, when a prescriber selects a drug, I want to synchronously check the patient's allergy record so that the prescriber is alerted to potential allergic reactions before the order is committed.

Acceptance criteria (Gherkin):

  • Given a patient with a penicillin allergy, when orders-service calls GET /v1/allergies/advisory?patientId=pat_X&rxnorm=7980, then the response includes the matching allergy with highestSeverity=severe.
  • Given a patient with active NKA, when advisory is called, then { matches: [], isNKA: true } is returned.
  • Given the patient has no allergies and no NKA, when advisory is called, then { matches: [], isNKA: false }.

Technical notes:

  • Advisory is synchronous; P95 target < 300 ms.
  • Callers implement fail-open; chart service does not block on advisory failure.

Definition of Done:

  • Pact consumer test from medication-service and orders-service.
  • Advisory integration test with concurrent allergy write.

CHART-US-007 — Inactivate / entered-in-error allergy

FieldValue
Issue typeStory
SummaryClinician inactivates or corrects an allergy record
Epic linkCHART-EPIC-02
StatusTo Do
PriorityMust
Story points2
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service
FR referencesFR-CHART-006
Legacy FR refsFR-ALG-004
DependenciesCHART-US-004

User story: As a clinician, when a patient's allergy is no longer clinically relevant or was recorded in error, I want to inactivate or mark it entered-in-error so that it no longer drives safety checks.

Acceptance criteria (Gherkin):

  • Given an active allergy, when I PATCH to inactive, then patient_chart.allergy.inactivated.v1 emitted; medication-service cache updated.
  • Given an allergy is entered-in-error, when advisory is queried, then it is excluded from the response.

Definition of Done:

  • Medication-service allergy cache refresh tested in integration.

CHART-US-008 — Record vital signs panel

FieldValue
Issue typeStory
SummaryClinician records a VitalsSet panel with LOINC-coded observations
Epic linkCHART-EPIC-03
StatusTo Do
PriorityMust
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service
FR referencesFR-CHART-007
Legacy FR refsFR-VIT-001
DependenciesCHART-US-001

User story: As a nurse, when I take a patient's vital signs, I want to record the measurements as a panel so that they are stored with LOINC codes and UCUM units and any abnormal values are immediately flagged.

Acceptance criteria (Gherkin):

  • Given valid measurement values, when I POST /v1/vitals, then a VitalsSet + Observation rows are created and patient_chart.vitals.recorded.v1 is emitted.
  • Given a SpO₂ value of 85 %, when the panel is recorded, then patient_chart.vitals.abnormal_flagged.v1 is emitted with severity=HIGH.
  • Given hard-stop range policy for heart rate, when value 300 bpm is submitted, then 422 CHART_VITALS_RANGE_REJECTED.
  • Given height and weight are present, when the set is recorded, then BMI observation is derived and stored with derivedFrom links.

Technical notes:

  • vit_ ULID for VitalsSet; obs_ ULID for each Observation.
  • LOINC code required; system=local if unmapped.

Definition of Done:

  • BMI derivation unit test. Abnormal flag integration test. Range validation tests for warn and reject modes.

CHART-US-009 — Correct vital signs (new version)

FieldValue
Issue typeStory
SummaryClinician corrects an erroneously recorded vitals set
Epic linkCHART-EPIC-03
StatusTo Do
PriorityShould
Story points3
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service
FR referencesFR-CHART-008
Legacy FR refsFR-VIT-004
DependenciesCHART-US-008

User story: As a clinician, when vital signs were entered incorrectly, I want to record a correction as a new version of the measurement so that both the original and corrected values are preserved in the audit trail.

Acceptance criteria (Gherkin):

  • Given an existing VitalsSet, when I POST a correction with a reason, then a new VitalsSet version is created; original is immutable; patient_chart.vitals.updated.v1 emitted.
  • Given no reason is provided, when correction is attempted, then 422 validation error.

Definition of Done:

  • Original immutability verified in integration test.

CHART-US-010 — Create clinical note draft

FieldValue
Issue typeStory
SummaryClinician creates structured note draft with template-defined sections
Epic linkCHART-EPIC-04
StatusTo Do
PriorityMust
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service
FR referencesFR-CHART-010
Legacy FR refsFR-NOTES-001
DependenciesCHART-US-001

User story: As a clinician, when I need to document a patient encounter, I want to create a structured draft note using a template (SOAP, H&P, consult, etc.) so that I can organize my documentation in a consistent format.

Acceptance criteria (Gherkin):

  • Given a valid templateId and author, when I POST /v1/clinical-notes, then a ClinicalNote with status=draft and template-defined NoteSection rows is created.
  • Given the note is in draft, when I PATCH section content, then patient_chart.note.updated_draft.v1 is emitted.
  • Given an encounter is in planned status, when I attempt to sign the note, then 422 is returned.

Technical notes:

  • note_ ULID prefix.
  • Template definitions fetched from config-service or static registry.

Definition of Done:

  • Draft creation and section edit integration tests. note.created.v1 schema conformance.

CHART-US-011 — Sign clinical note

FieldValue
Issue typeStory
SummaryClinician signs note creating legal record and PDF in document-service
Epic linkCHART-EPIC-04
StatusTo Do
PriorityMust
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service, document-service
FR referencesFR-CHART-011
Legacy FR refsFR-NOTES-003
DependenciesCHART-US-010, cross-service: DOC-US-001

User story: As a clinician, when my documentation is complete, I want to sign the note so that it becomes the immutable legal record and a PDF is archived in the document management system.

Acceptance criteria (Gherkin):

  • Given a draft note without cosign requirement, when I POST sign, then status=signed, signedAt and signedBy set atomically, note.signed.v1 emitted, PDF uploaded to document-service.
  • Given cosign policy requires attending attestation, when a resident signs, then status=pending_cosign and note.cosign_requested.v1 emitted.
  • Given a signed note, when any section content is edited, then 422 CHART_NOTE_SIGNED_IMMUTABLE.

Technical notes:

  • PDF upload via DocumentServiceClient port → HTTP adapter.
  • If doc-service unavailable, signing completes; PDF upload retried via outbox.

Definition of Done:

  • Immutability integration test. PDF upload retry via outbox tested. Cosign block tested.

CHART-US-012 — AI-assist chunk accept in note

FieldValue
Issue typeStory
SummaryClinician accepts AI-suggested content into note section with provenance
Epic linkCHART-EPIC-06
StatusTo Do
PriorityShould
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S3
Componentspatient-chart-service, ai-gateway-service
FR referencesFR-CHART-016
Legacy FR refsFR-NOTES-009
DependenciesCHART-US-010, cross-service: AIGW-US-001, AIGW-US-009

User story: As a clinician, when the AI assistant suggests content for a note section, I want to explicitly accept the suggestion so that the AI-generated text is incorporated with a traceable provenance record linking it to the model and my acceptance action.

Acceptance criteria (Gherkin):

  • Given an accepted AIDecision from ai-gateway-service, when I POST AcceptAIChunk with provenanceId, then section content is updated, NoteAIProvenance row is written, patient_chart.note.ai_accepted.v1 emitted.
  • Given no provenanceId is provided, when AcceptAIChunk is called, then 422 CHART_AI_PROVENANCE_MISSING.
  • Given the note is signed, when AcceptAIChunk is called, then 422 CHART_NOTE_SIGNED_IMMUTABLE.

Technical notes:

  • NoteAIProvenance written atomically with section content update in same DB transaction.
  • note.ai_accepted.v1 carries provenanceId, featureKey, modelVersion.

Definition of Done:

  • AI provenance missing error tested. Pact consumer test against ai-gateway.

CHART-US-013 — Chart summary composition (widgets)

FieldValue
Issue typeStory
SummaryGET chart summary fans out to owned and remote aggregates
Epic linkCHART-EPIC-05
StatusTo Do
PriorityMust
Story points8
Labelsservice:patient-chart-service, type:backend, slice:S1
Componentspatient-chart-service, medication-service, laboratory-service
FR referencesFR-CHART-013
Legacy FR refsFR-PCHART-001
DependenciesCHART-EPIC-01..04, cross-service: MED-EPIC-01, LAB-EPIC-01

User story: As a clinician at the bedside, when I open a patient's chart, I want to see a unified summary of problems, allergies, recent vitals, current medications, recent labs, imaging, immunizations, and active care plans in a single view so that I have the full clinical picture without navigating multiple screens.

Acceptance criteria (Gherkin):

  • Given a valid patient, when I call GET /v1/chart/summary?patientId=X&widgets=problems,allergies,vitals,medications, then each requested widget is populated with current data in < 800 ms P95.
  • Given medication-service is unavailable, when summary is requested, then the medications widget shows an error state and other widgets are still populated.
  • Given a different tenant's patientId, when summary is requested, then 403 CHART_CROSS_TENANT_REFERENCE.

Technical notes:

  • Fan-out via Promise.allSettled; partial results served on downstream failure.
  • Circuit breaker per downstream dependency.

Definition of Done:

  • Partial failure scenario integration test. P95 < 800 ms load test.

CHART-US-014 — Chart timeline (cursor-paginated)

FieldValue
Issue typeStory
SummaryLongitudinal timeline with cursor pagination across all chart event types
Epic linkCHART-EPIC-05
StatusTo Do
PriorityShould
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S1
Componentspatient-chart-service
FR referencesFR-CHART-014
Legacy FR refsFR-PCHART-002
DependenciesCHART-US-013

User story: As a clinician, when I review a patient's history, I want to scroll through a reverse-chronological timeline of all chart events (notes, problems, vitals, orders, results) so that I can understand the patient's journey over time.

Acceptance criteria (Gherkin):

  • Given a patient with 100 chart events, when I call GET /v1/chart/timeline?patientId=X&limit=20, then 20 events are returned with a nextCursor.
  • Given a nextCursor, when I call the timeline with it, then the next 20 events are returned without duplicates.
  • Given types=problems,notes filter, when timeline is called, then only problem and note events appear.

Definition of Done:

  • Cursor pagination integration test. Type filter tested.

CHART-US-015 — Chart banner (demographics + alerts)

FieldValue
Issue typeStory
SummaryChart header banner with demographics proxy and active alerts
Epic linkCHART-EPIC-05
StatusTo Do
PriorityMust
Story points3
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service, registration-service
FR referencesFR-CHART-015
Legacy FR refsFR-PCHART-003
DependenciesCHART-US-001, cross-service: REG-US-001

User story: As a clinician, when I open a patient chart, I want to see the patient banner with name, DOB, MRN, active allergy alerts, and current encounter context so that I confirm patient identity and see critical safety information immediately.

Acceptance criteria (Gherkin):

  • Given a valid patientId, when I call GET /v1/chart/banner?patientId=X, then demographics (from registration-service), active allergy count, and encounter context are returned in < 500 ms.
  • Given registration-service is unavailable, when banner is called, then cached demographics are returned with a dataStale=true flag.

Definition of Done:

  • Stale-cache fallback integration test. P95 < 500 ms.

CHART-US-016 — Chart snapshot export (handoff)

FieldValue
Issue typeStory
SummaryExport structured handoff snapshot for patient transition
Epic linkCHART-EPIC-07
StatusTo Do
PriorityShould
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S2
Componentspatient-chart-service, document-service
FR referencesFR-CHART-020
Legacy FR refsFR-PCHART-007
DependenciesCHART-US-013

User story: As a discharging physician, when a patient is transferred to another care setting, I want to export a structured handoff snapshot so that the receiving provider has a complete, current clinical picture.

Acceptance criteria (Gherkin):

  • Given appropriate permissions, when I POST /v1/chart/snapshot?patientId=X, then a structured snapshot (active problems, allergies, recent vitals, critical results, active goals, current medications) is returned and chart.snapshot_exported.v1 is emitted.
  • Given the export request, when it is processed, then an AuditEntry of type BULK_EXPORT is recorded in audit-service.

Definition of Done:

  • Audit event emitted on every snapshot. Permission gate integration test.

CHART-US-017 — Clinical note AI assist request

FieldValue
Issue typeStory
SummaryClinician requests AI-assisted note section draft
Epic linkCHART-EPIC-06
StatusTo Do
PriorityShould
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S3
Componentspatient-chart-service, ai-gateway-service
FR referencesFR-CHART-017
Legacy FR refsFR-NOTES-010
DependenciesCHART-US-010, cross-service: AIGW-US-001

User story: As a clinician writing a note, when I want an AI suggestion for a section, I want to trigger AI assist from the note editor so that I receive a draft suggestion that I can review, edit, and accept or discard.

Acceptance criteria (Gherkin):

  • Given a draft note and active AI assist feature, when I request assist for a section, then the service calls ai-gateway-service and returns { draftText, decisionId, provenanceId } to the client.
  • Given the AI gateway is unavailable, when assist is requested, then { aiAssistAvailable: false } is returned; note authoring continues.
  • Given HITL is required for the feature, when assist is requested, then { status: "under_review", decisionId } is returned; clinician is notified when review completes.

Technical notes:

  • AIGatewayHttpAdapter implements AIGatewayPort.
  • Assist result is not automatically inserted; clinician must call AcceptAIChunk.

Definition of Done:

  • Graceful degradation when ai-gateway unavailable tested. Pact consumer test against ai-gateway.

CHART-US-018 — Cosign routing and attestation

FieldValue
Issue typeStory
SummaryResident note routed for attending cosign before finalising
Epic linkCHART-EPIC-04
StatusTo Do
PriorityMust
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service, communication-service
FR referencesFR-CHART-012
Legacy FR refsFR-NOTES-006
DependenciesCHART-US-011, cross-service: COMMS-US-001

User story: As an attending physician, when a resident signs a note that requires my attestation, I want to receive a notification and be able to review and cosign the note so that the legal attestation requirements for supervised practice are met.

Acceptance criteria (Gherkin):

  • Given cosign policy for the resident's role, when the resident signs, then status=pending_cosign and note.cosign_requested.v1 emitted; communication-service sends notification.
  • Given the attending cosigns, when attestation is submitted, then status=signed, note.cosigned.v1 and note.signed.v1 emitted.
  • Given cosign is rejected, when the attending rejects, then status=draft and the resident is notified.

Definition of Done:

  • Cosign workflow E2E test. pending_cosign block on further resign tested.

CHART-US-019 — Break-glass emergency chart access

FieldValue
Issue typeStory
SummaryClinician invokes break-glass with reason for restricted chart access
Epic linkCHART-EPIC-07
StatusTo Do
PriorityShould
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S2
Componentspatient-chart-service, audit-service
FR referencesFR-CHART-018
Legacy FR refsFR-PCHART-005
Dependenciescross-service: AUDIT-US-001

User story: As an emergency physician, when a patient requires urgent care but their chart is restricted, I want to invoke break-glass with a documented reason so that I can access the chart to provide emergency care, with my access logged in the audit trail.

Acceptance criteria (Gherkin):

  • Given a valid reason and duration, when I POST /v1/chart/break-glass, then chart access is granted and patient_chart.breakglass.invoked.v1 is emitted (immediately ingested by audit-service).
  • Given no reason is provided, when break-glass is attempted, then 422 CHART_BREAKGLASS_REASON_MISSING.
  • Given break-glass was invoked, when I query audit-service, then the entry is present with reason, actor, timestamp, and patientId.

Definition of Done:

  • Reason-required integration test. Audit entry verified. Break-glass spike alert configured.

CHART-US-020 — Sensitive segment access control

FieldValue
Issue typeStory
SummaryMental health / sexual health records gated by sensitive segment policy
Epic linkCHART-EPIC-07
StatusTo Do
PriorityShould
Story points5
Labelsservice:patient-chart-service, type:backend, slice:S2
Componentspatient-chart-service
FR referencesFR-CHART-019
Legacy FR refsFR-PCHART-006
DependenciesCHART-US-019

User story: As a compliance officer, when a clinician accesses a note flagged as a sensitive segment (mental health, sexual health), I want access to be gated by sensitive-segment policy so that patient privacy is protected and all access is logged.

Acceptance criteria (Gherkin):

  • Given a note with sensitiveCategory=mental_health and no sensitive-segment access, when a clinician without access reads the note, then 403 CHART_SENSITIVE_NOT_AUTHORIZED.
  • Given a clinician with sensitive-segment access, when they read the note, then patient_chart.sensitive_access.recorded.v1 is emitted.

Definition of Done:

  • Access denied and access granted both unit tested. Audit event schema conformance.

CHART-US-021 — Append addendum to signed note

FieldValue
Issue typeStory
SummaryClinician appends addendum to signed note without modifying original
Epic linkCHART-EPIC-04
StatusTo Do
PriorityMust
Story points3
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service
FR referencesFR-CHART-011
Legacy FR refsFR-NOTES-005
DependenciesCHART-US-011

User story: As a clinician, when I need to add information to a note I have already signed, I want to append an addendum so that the original signed content is preserved immutably and the addition is clearly identified as an amendment.

Acceptance criteria (Gherkin):

  • Given a signed note, when I POST an addendum with body + reason, then NoteAddendum is created, status=amended, patient_chart.note.addendum_created.v1 emitted.
  • Given a signed note, when I attempt to edit section body directly, then 422 CHART_NOTE_SIGNED_IMMUTABLE.

Definition of Done:

  • Original content immutability unit tested. Multiple addendum chain tested.

CHART-US-022 — Five-module data migration script

FieldValue
Issue typeStory
SummaryETL scripts migrate legacy module data to unified patient_chart schema
Epic linkCHART-EPIC-08
StatusTo Do
PriorityMust
Story points8
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service, platform-eng
FR referencesFR-CHART-021
Legacy FR refs
DependenciesCHART-EPIC-01..04

User story: As a platform engineer, when the legacy five-module deployment needs to be consolidated, I want idempotent ETL scripts that migrate all historical data to the unified patient_chart schema so that no clinical records are lost or corrupted.

Acceptance criteria (Gherkin):

  • Given a legacy problems.* schema, when the migration script runs, then all rows are present in patient_chart.problem with ULID-mapped ids; row counts match.
  • Given the script is run twice, when it completes, then no duplicate rows are created (idempotent).
  • Given a migration failure mid-run, when the script exits, then no partial data is committed (transactional rollback).

Technical notes:

  • legacy_id_map table tracks (module, legacy_id) → new_ulid.
  • Each module migration is a separate script; run order: problems → allergies → vitals → notes → chart.
  • Dry-run mode (no DB writes) required.

Definition of Done:

  • Row count reconciliation verified in staging. Idempotency test. Dry-run mode working.

CHART-US-023 — Dual-publish NATS subjects during migration

FieldValue
Issue typeStory
SummaryService dual-publishes legacy and canonical NATS subjects during M0→M1 transition
Epic linkCHART-EPIC-08
StatusTo Do
PriorityMust
Story points3
Labelsservice:patient-chart-service, type:backend, slice:S0
Componentspatient-chart-service
FR referencesFR-CHART-021
Legacy FR refs
DependenciesCHART-US-022

User story: As a platform engineer, during the migration transition period, I want the service to publish events on both legacy and canonical NATS subjects so that downstream consumers can cut over at their own pace without service interruption.

Acceptance criteria (Gherkin):

  • Given dual-publish mode enabled via feature flag, when a problem is added, then both PROBLEMS.PROBLEM.ADDED and patient_chart.problem.added.v1 are published.
  • Given dual-publish mode disabled (post-cutover), when a problem is added, then only patient_chart.problem.added.v1 is published.
  • Given a downstream consumer has confirmed cutover, when dual-publish is disabled, then no duplicate processing occurs.

Technical notes:

  • Dual-publish controlled via DUAL_PUBLISH_SUBJECTS_ENABLED config flag.
  • Legacy subjects deprecated after all consumers confirmed on canonical.

Definition of Done:

  • Feature flag integration test. Consumer deduplication (idempotent on sourceEventId) verified.