Orders Service — User Stories
Service: orders-service Story prefix: ORDERS-US Last updated: 2026-04-18
Stories
ORDERS-US-001 — Create medication order with full CDS evaluation
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | Clinician creates a medication order with CDS allergy/DDI checks |
| Epic link | ORDERS-EPIC-01 |
| Status | To Do |
| Priority | Must |
| Story points | 8 |
| Labels | service:orders, type:backend, type:api, slice:S1 |
| Components | orders-service, cds-engine |
| FR references | FR-ORDERS-001 |
| Legacy FR refs | FR-CPOE-001 |
| Dependencies | ORDERS-US-006 (CDS gate), cross-service: REG-US-001 |
User story: As a prescriber, when I enter a new medication order during an active patient encounter, I want the system to run allergy and drug interaction checks before saving so that I am alerted to potential patient safety issues before the order is activated.
Acceptance criteria (Gherkin):
- Given a prescriber has an active encounter for a patient with a known penicillin allergy, when they submit
POST /v1/orderswithorderType: "medication"andmedicationCode: amoxicillin, then the order is saved indraftstatus and the response includescdsAlerts[{level: "hard-stop", ruleId: "ALLERGY_PENICILLIN"}]. - Given a prescriber submits a medication order with no known conflicts, when all CDS checks pass, then the order is created in
draftstatus with emptycdsAlerts[]and HTTP 201. - Given a medication order with a drug-drug interaction warning (not hard-stop), when the prescriber submits, then the order is saved in
draftwithcdsAlerts[{level: "warning"}]and the prescriber can proceed to acknowledge and activate.
Technical notes:
POST /v1/orderswithorderType: "medication".- CDS checks: allergy, drug-drug interaction, duplicate, dosing range — all run synchronously in
CreateOrderUseCase. - Hard-stop: order saved as
draftbutActivateOrderCommandblocked until ADMIN override. - Event:
clinical.orders.order.created.v1published via outbox.
Definition of Done:
- Unit + integration tests added; domain ≥ 95% coverage; CDS guard paths tested.
- OpenAPI contract updated; Pact consumer tests green.
outbox.spec.tspassing.- Telemetry spans:
orders.create,orders.cds.allergy_check,orders.cds.drug_interaction. - Documentation updated.
ORDERS-US-002 — Create laboratory order and route to lab worklist
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | Clinician creates lab order that appears in laboratory-service worklist |
| Epic link | ORDERS-EPIC-03 |
| Status | To Do |
| Priority | Must |
| Story points | 5 |
| Labels | service:orders, type:backend, type:api, slice:S1 |
| Components | orders-service, laboratory-service, NATS |
| FR references | FR-ORDERS-009 |
| Legacy FR refs | FR-REQ-001, FR-CPOE-006 |
| Dependencies | ORDERS-US-001, cross-service: LAB-US-001 |
User story: As a clinician, when I activate a laboratory order, I want it to automatically appear in the laboratory service worklist so that lab technicians can process it without any manual re-entry.
Acceptance criteria (Gherkin):
- Given a clinician has a draft lab order in
activestatus, whenPOST /v1/orders/:id/activatesucceeds, thenclinical.orders.order.activated.v1event is published to NATS withorderType: "laboratory". - Given the event is published, when laboratory-service consumes it, then the order appears in the lab worklist within 30 seconds.
- Given NATS is temporarily unavailable at activation, when NATS recovers, then the outbox relay delivers the event and the lab worklist is updated (eventual consistency within SLA).
Technical notes:
- Activation:
POST /v1/orders/:id/activate. - NATS subject:
clinical.orders.{patientId}. - Event:
clinical.orders.order.activated.v1— consumed by laboratory-service consumer group. - Outbox pattern: event written transactionally with order state change.
Definition of Done:
outbox.spec.tsgreen; NATS event verified in integration test.- Pact contract:
clinical.orders.order.activated.v1verified against laboratory-service consumer. - Coverage ≥ 80%.
ORDERS-US-003 — Activate order with CDS warning acknowledgement
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | Prescriber acknowledges CDS warning before activating medication order |
| Epic link | ORDERS-EPIC-02 |
| Status | To Do |
| Priority | Must |
| Story points | 5 |
| Labels | service:orders, type:backend, type:api, slice:S1 |
| Components | orders-service, cds-engine |
| FR references | FR-ORDERS-007 |
| Legacy FR refs | FR-CPOE-005 |
| Dependencies | ORDERS-US-001 |
User story: As a prescriber, when I have a medication order with a CDS warning (drug interaction), I want to acknowledge the warning with a clinical reason before activating the order so that my override is documented for audit purposes.
Acceptance criteria (Gherkin):
- Given a draft medication order has a CDS
warningalert, when the prescriber callsPOST /v1/orders/:alertId/acknowledgewithreason: "Benefit outweighs risk; monitoring plan in place", then the alert is marked acknowledged and the order can proceed to activation. - Given a CDS warning has not been acknowledged, when the prescriber calls
POST /v1/orders/:id/activate, then the response is 422 withCDS_WARNING_UNACKNOWLEDGED. - Given a CDS hard-stop alert, when a CLINICIAN attempts to acknowledge, then 403 is returned — only ADMIN can acknowledge hard-stops.
Technical notes:
POST /v1/orders/:orderId/cds-alerts/:alertId/acknowledgewith body{ reason: string }.- Acknowledgement stored immutably in
orders.cds_alerts.acknowledged_at,acknowledged_by,acknowledgement_reason. - Audit event:
CDS_WARNING_ACKNOWLEDGEDwith actor, reason, rule ID.
Definition of Done:
- Immutability of acknowledgement record tested.
- Audit log integration test verifying record stored.
- OpenAPI schema updated.
ORDERS-US-004 — Cancel an active order
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | Clinician cancels an active order with documented reason |
| Epic link | ORDERS-EPIC-01 |
| Status | To Do |
| Priority | Must |
| Story points | 3 |
| Labels | service:orders, type:backend, type:api, slice:S1 |
| Components | orders-service |
| FR references | FR-ORDERS-004 |
| Legacy FR refs | FR-CPOE-003 |
| Dependencies | ORDERS-US-001 |
User story: As a clinician, when I need to stop an active order (wrong medication, clinical decision change), I want to cancel it with a documented reason so that downstream services stop processing it and the reason is visible in the patient record.
Acceptance criteria (Gherkin):
- Given an active order, when the clinician calls
DELETE /v1/orders/:idwith body{ reason: "Patient allergic — new allergy identified" }, then the order transitions tocancelled,order.cancelledevent is emitted, and 200 is returned. - Given a completed order, when a clinician attempts cancellation, then 409
ORDER_TERMINAL_STATEis returned. - Given a NURSE role cancelling an order they did not create, when the order is a nursing order, then cancellation succeeds. For other order types, 403 is returned.
Technical notes:
DELETE /v1/orders/:idwith JSON body{ cancelReason: string }.- Terminal state guard:
completedandentered-in-errorcannot be cancelled. - Event:
clinical.orders.order.cancelled.v1.
Definition of Done:
- State machine terminal guard unit tests.
- Role-based cancel permission integration test.
- Pact:
order.cancelled.v1verified against downstream consumers.
ORDERS-US-005 — View all orders for a patient encounter
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | Clinician views all orders for a specific encounter |
| Epic link | ORDERS-EPIC-01 |
| Status | To Do |
| Priority | Must |
| Story points | 3 |
| Labels | service:orders, type:backend, type:api, slice:S1 |
| Components | orders-service |
| FR references | FR-ORDERS-005 |
| Legacy FR refs | FR-CPOE-002 |
| Dependencies | ORDERS-US-001 |
User story: As a clinician, when I open a patient encounter in the EHR, I want to see all orders associated with that encounter grouped by type and status so that I have a complete view of the current care plan.
Acceptance criteria (Gherkin):
- Given an encounter with 5 orders of mixed types, when
GET /v1/orders?encounterId=enc_01J...is called, then all 5 orders are returned with correct type, status, and priority. - Given a request with no
encounterIdorpatientId, when the query is submitted, then 400MISSING_REQUIRED_FILTERis returned. - Given a NURSE role querying orders for an encounter, when the encounter belongs to a different tenant, then 0 results (RLS enforced, not 403).
Technical notes:
GET /v1/orders?encounterId=&type=&status=&cursor=— cursor pagination.- Filterable by
orderType,status,priority, date range. - RLS enforces tenant isolation; no cross-tenant rows returned.
Definition of Done:
tenant-isolation.spec.tscovers this query path.- Cursor pagination tested with > 100 records.
ORDERS-US-006 — CDS hard-stop blocks medication order activation
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | Medication order with confirmed allergy cannot be activated without ADMIN override |
| Epic link | ORDERS-EPIC-02 |
| Status | To Do |
| Priority | Must |
| Story points | 8 |
| Labels | service:orders, type:backend, slice:S1, type:patient-safety |
| Components | orders-service, cds-engine |
| FR references | FR-ORDERS-006 |
| Legacy FR refs | FR-CPOE-004 |
| Dependencies | ORDERS-US-001 |
User story: As a platform safety system, when a clinician tries to activate a medication order that triggers a CDS hard-stop (confirmed allergy), I want to block activation until an ADMIN provides a documented clinical override reason so that patient safety is enforced at every order entry point.
Acceptance criteria (Gherkin):
- Given an order with an unacknowledged
hard-stopCDS alert, when any role callsPOST /v1/orders/:id/activate, then 422CDS_HARD_STOPis returned and order remainsdraft. - Given an ADMIN acknowledges the hard-stop with a clinical reason, when
POST /v1/orders/:id/activateis called, then the order transitions toactiveand the override is logged immutably. - Given CDS engine is unavailable, when a medication order is submitted, then
CDS_DEGRADEDsoft alert is recorded and medication activation is blocked until CDS recovers (unless ADMIN overrides withCDS_DEGRADED_OVERRIDE).
Technical notes:
- Hard-stop acknowledgement: ADMIN role only (
POST /v1/orders/:orderId/cds-alerts/:alertId/acknowledge). - Audit event:
CDS_HARD_STOP_BLOCKED,CDS_HARD_STOP_ADMIN_OVERRIDE. - 7-year immutable retention on all CDS override records.
Definition of Done:
- CDS degraded mode tested in integration.
- ADMIN-only gate for hard-stop tested.
- 7-year retention policy documented in DATA_MODEL.md.
ORDERS-US-007 — Duplicate order detection
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | System warns when identical order already active within 24 hours |
| Epic link | ORDERS-EPIC-02 |
| Status | To Do |
| Priority | Must |
| Story points | 5 |
| Labels | service:orders, type:backend, slice:S1, type:patient-safety |
| Components | orders-service, cds-engine |
| FR references | FR-ORDERS-008 |
| Legacy FR refs | FR-CPOE-005 |
| Dependencies | ORDERS-US-001 |
User story: As a prescriber, when I attempt to create an order that is identical to one already active for the same patient within 24 hours, I want to receive a duplicate order CDS warning so that I can intentionally confirm or cancel the redundant order.
Acceptance criteria (Gherkin):
- Given a patient has an active amoxicillin order, when a prescriber creates a new amoxicillin order for the same patient and encounter, then a
warningCDS alert withruleId: "DUPLICATE_ORDER_24H"is returned. - Given the duplicate warning is shown, when the prescriber acknowledges it with a reason, then the order can proceed to activation.
- Given two orders with different drug codes (amoxicillin vs azithromycin), when a new order is created, then no duplicate CDS alert fires.
Technical notes:
- Duplicate check: same
orderCode.code+orderType+ active status within 24 h for samepatientId. - CDS rule:
DUPLICATE_ORDER_24H, severity:warning. - Idempotency check (
client_mutation_idDB constraint) is separate from CDS duplicate check.
Definition of Done:
- Unit tests for duplicate detection boundary conditions.
- Integration test: duplicate warning fires; acknowledgement allows activation.
ORDERS-US-008 — Create radiology order and route to radiology service
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | Clinician creates radiology order routed to radiology-service worklist |
| Epic link | ORDERS-EPIC-03 |
| Status | To Do |
| Priority | Must |
| Story points | 5 |
| Labels | service:orders, type:backend, type:api, slice:S1 |
| Components | orders-service, radiology-service, NATS |
| FR references | FR-ORDERS-010 |
| Legacy FR refs | FR-REQ-002 |
| Dependencies | ORDERS-US-001, cross-service: RAD-US-001 |
User story: As a clinician, when I activate a radiology order (X-ray, CT, MRI), I want the imaging request to appear immediately in the radiology worklist so that radiographers can schedule and perform the study without manual transcription.
Acceptance criteria (Gherkin):
- Given a draft radiology order with
orderType: "radiology"andradiologyDetail: { modality: "CT", region: "Chest", contrastRequired: true }, when activated, thenclinical.orders.order.activated.v1is published with fullradiologyDetailpayload. - Given the event is consumed by radiology-service, when it creates a worklist entry, then the modality, region, laterality, and contrast fields are correctly mapped.
- Given a radiology order without a
radiologyDetailblock, when submitted, then 400MISSING_DETAIL_FOR_ORDER_TYPEis returned.
Technical notes:
radiologyDetailrequired fororderType: "radiology".- FHIR mapping:
ServiceRequestwithcategory: [{"code":"imaging"}]. - Pact:
clinical.orders.order.activated.v1verified against radiology-service consumer.
Definition of Done:
- Validation of required detail block per order type tested.
- Pact contract test passing.
ORDERS-US-009 — Create and track internal referral
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | Clinician creates internal referral with scheduling coordination |
| Epic link | ORDERS-EPIC-04 |
| Status | To Do |
| Priority | Must |
| Story points | 8 |
| Labels | service:orders, type:backend, type:api, slice:S1 |
| Components | orders-service, scheduling-service, communication-service |
| FR references | FR-ORDERS-020 |
| Legacy FR refs | FR-REF-001 |
| Dependencies | ORDERS-US-001, cross-service: SCHED-US-001, COMMS-US-001 |
User story: As a clinician, when I need to refer a patient to a specialist within our facility network, I want to create a referral order that automatically triggers the scheduling team to arrange the appointment so that the patient does not fall through the cracks of a manual referral process.
Acceptance criteria (Gherkin):
- Given a clinician creates a referral order with
referralType: "internal",referToSpecialty: "cardiology",urgency: "routine", when activated, thenclinical.orders.referral.created.v1is published. - Given the event is consumed by scheduling-service, when it creates an appointment proposal, then the referral status in orders-service transitions to
pending_scheduling. - Given a referral is pending scheduling for > 72 hours, when no scheduling event is received, then the
OrdersReferralOverduePrometheus alert fires.
Technical notes:
POST /v1/orderswithorderType: "referral",referralDetailrequired.clinical.orders.referral.created.v1consumed by scheduling-service and communication-service.- Referral status updates received via
SCHEDULING.appointment.fulfilled.v1event.
Definition of Done:
- Referral overdue alert configured with 72 h threshold.
referral.created.v1Pact contract test against scheduling-service consumer.- Referral status update via event integration test.
ORDERS-US-010 — Instantiate order set for patient
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | Clinician applies an order set template creating multiple draft orders at once |
| Epic link | ORDERS-EPIC-05 |
| Status | To Do |
| Priority | Should |
| Story points | 8 |
| Labels | service:orders, type:backend, type:api, slice:S1 |
| Components | orders-service |
| FR references | FR-ORDERS-030 |
| Legacy FR refs | FR-CPOE-010 |
| Dependencies | ORDERS-US-001 |
User story: As a clinician, when I need to order a standard clinical protocol (e.g., pre-operative blood work), I want to apply an order set template to the patient with one action so that all required orders are created in draft simultaneously and I can review CDS alerts before activating each one.
Acceptance criteria (Gherkin):
- Given an order set template
ords_01J...with 3 order entries (CBC, metabolic panel, coagulation screen), whenPOST /v1/order-sets/:id/instantiateis called withpatientIdandencounterId, then 3 draft orders are returned in the response. - Given one order entry triggers a CDS warning, when instantiation completes, then the response includes
cdsAlertson that specific order andsuccessCount: 2, warningCount: 1. - Given one order entry fails to create (e.g., encounter inactive), when instantiation is called, then the response shows
failedTemplates: [{templateId, reason}]and successfully created orders are persisted.
Technical notes:
POST /v1/order-sets/:id/instantiate— body:{ patientId, encounterId, overrides? }.- Each order created in independent transaction.
- Partial failure:
failedTemplates[]in response; already-created orders persisted.
Definition of Done:
- Partial failure scenario tested (some orders created, some failed).
ORDER_SET_PARTIAL_FAILUREaudit event tested.
ORDERS-US-011 — Read order as FHIR ServiceRequest
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | External FHIR client reads order as FHIR R4 ServiceRequest |
| Epic link | ORDERS-EPIC-06 |
| Status | To Do |
| Priority | Should |
| Story points | 5 |
| Labels | service:orders, type:backend, type:api, slice:S1 |
| Components | orders-service, interop-service |
| FR references | FR-ORDERS-040 |
| Legacy FR refs | FR-CPOE-020 |
| Dependencies | ORDERS-US-001, cross-service: INTEROP-US-001 |
User story: As a national HMIS system or partner EMR, when I query the FHIR endpoint for a patient's orders, I want to receive them as FHIR R4 ServiceRequest and MedicationRequest resources so that I can integrate without platform-specific APIs.
Acceptance criteria (Gherkin):
- Given an active lab order
ord_01J...exists, whenGET /fhir/R4/ServiceRequest/ord_01J...is called via interop-service, then a valid FHIR R4ServiceRequestis returned with correctstatus,category,code, andsubjectfields. - Given a FHIR search
GET /fhir/R4/ServiceRequest?patient=Patient/pat_01J..., when executed, then aBundleof typesearchsetis returned with all non-entered-in-errororders for the patient. - Given an invalid FHIR resource ID, when read is attempted, then FHIR
OperationOutcomewithnot-foundissue is returned.
Technical notes:
- Internal FHIR surface:
GET /internal/fhir/ServiceRequest/:id— proxied by interop-service from external/fhir/R4/. - Mapping:
Order→ServiceRequest;medicationDetail→MedicationRequest. - US Core ServiceRequest profile validation in contract tests.
Definition of Done:
- FHIR profile conformance test green (
test/contract/serviceRequest.fhir.schema.spec.ts). - OperationOutcome tested for not-found and auth denial.
ORDERS-US-012 — Migrate legacy CPOE orders to unified schema
| Field | Value |
|---|---|
| Issue type | Story |
| Summary | Historical CPOE orders migrated to orders-service with validated record counts |
| Epic link | ORDERS-EPIC-07 |
| Status | To Do |
| Priority | Must |
| Story points | 13 |
| Labels | service:orders, type:backend, slice:S0 |
| Components | orders-service, migration-scripts |
| FR references | FR-ORDERS-050 |
| Legacy FR refs | FR-CPOE-030 |
| Dependencies | ORDERS-EPIC-01 |
User story: As a platform migration engineer, when I run the CPOE migration scripts, I want all historical orders to be present in the new orders-service with zero data loss so that clinicians see a continuous order history after cut-over.
Acceptance criteria (Gherkin):
- Given legacy CPOE has 50,000 order records, when the migration script runs to completion, then the validation script reports 50,000 migrated records with 0 discrepancy.
- Given the migration script runs twice (idempotency), when it completes the second run, then the count remains 50,000 with no duplicates (upsert behaviour verified).
- Given a legacy order has no
encounterId, when migrated, then it is assigned to a synthetic encounter and flagged withmigration_no_encounter: truefor clinical review.
Technical notes:
- Migration scripts:
scripts/migrate-cpoe-orders.ts,scripts/migrate-lab-requisitions.ts. - Idempotent via upsert on
id. - 10% sample clinical validation required before go-live.
Definition of Done:
- Migration scripts committed and reviewed.
- Validation script report documented.
- Rollback plan tested in staging.