Skip to main content

Laboratory Service — User Stories

Service: laboratory-service Story prefix: LAB-US Last updated: 2026-04-18


Stories

LAB-US-001 — Manage test catalog with LOINC mapping

FieldValue
Issue typeStory
SummaryLab admin creates and maintains test catalog items with optional LOINC codes
Epic linkLAB-EPIC-01
StatusTo Do
PriorityMust
Story points3
Labelsservice:laboratory, type:backend, slice:S0
Componentscatalog
FR referencesFR-LAB-001
Legacy FR refsFR-LIS-001
Dependenciescross-service: TERM-US-001

User story: As a lab administrator, when I configure the lab system, I want to create test catalog items with LOINC codes, specimen types, and reference ranges so that technologists have consistent test definitions to work from.

Acceptance criteria (Gherkin):

  • Given an admin with lab:admin scope, when they POST a catalog item with valid LOINC code, then the item is created and the LOINC code is validated against terminology-service.
  • Given an invalid LOINC code, when the admin submits, then the system returns LAB_LOINC_INVALID 422.
  • Given a duplicate LOINC code for the same tenant, when submitted, then LAB_CATALOG_DUPLICATE 409 is returned.

Technical notes:

  • POST /v1/laboratory/catalog; terminology-service call for validation
  • Catalog items with tenantId=null are global; tenant-scoped items visible only to their tenant

Definition of Done:

  • Unit + integration tests; coverage ≥ 80%; OpenAPI updated; Pact green; event schema registered; telemetry spans added; docs updated.

LAB-US-002 — Create accession from order

FieldValue
Issue typeStory
SummaryLab clerk opens an accession from a ServiceRequest order
Epic linkLAB-EPIC-01
StatusTo Do
PriorityMust
Story points5
Labelsservice:laboratory, type:backend, slice:S0
Componentsaccessions
FR referencesFR-LAB-002
Legacy FR refsFR-LIS-002
Dependenciescross-service: ORDERS-US-001

User story: As a lab clerk, when I receive a lab order, I want to create an accession and generate a printable label with accession number, patient identifiers, and collection timestamp so that the specimen can be tracked.

Acceptance criteria (Gherkin):

  • Given a valid ServiceRequest order ID, when I create an accession, then a unique accession number is generated and a diag.laboratory.accession.created event is published.
  • Given the same order ID submitted twice with the same Idempotency-Key, when processed, then only one accession is created.
  • Given a non-existent order ID, when submitted, then LAB_ORDER_NOT_FOUND 404 is returned.

Technical notes:

  • POST /v1/laboratory/accessions; Idempotency-Key required; UNIQUE(tenant_id, order_id) constraint
  • Accession number format: {tenantShortCode}-{YYYYMMDD}-{seq6}

Definition of Done:

  • Unit + integration tests; coverage ≥ 80%; outbox.spec.ts green; OpenAPI updated; docs updated.

LAB-US-003 — Record specimen collection

FieldValue
Issue typeStory
SummaryLab collector records specimen collection details and updates accession status
Epic linkLAB-EPIC-01
StatusTo Do
PriorityMust
Story points3
Labelsservice:laboratory, type:backend, slice:S0
Componentsspecimens
FR referencesFR-LAB-003, FR-LAB-004
Legacy FR refsFR-LIS-003, FR-LIS-004
DependenciesLAB-US-002

User story: As a phlebotomist, when I collect a specimen, I want to record collection time, my identity, and specimen condition so that the chain of custody is documented.

Acceptance criteria (Gherkin):

  • Given an accession in ordered state, when I record collection, then specimen status becomes collected and accession transitions to collected.
  • Given specimen marked unsatisfactory, when submitted, then a note is appended and recollection workflow is triggered.
  • Given an already-canceled accession, when collection is attempted, then LAB_INVALID_STATE_TRANSITION 409 is returned.

Technical notes:

  • POST /v1/laboratory/accessions/{id}/specimens; state machine enforced in domain layer

Definition of Done:

  • Unit + integration tests; state machine all transitions tested; docs updated.

LAB-US-004 — Receive specimen at lab

FieldValue
Issue typeStory
SummaryLab staff confirms specimen receipt and updates status
Epic linkLAB-EPIC-01
StatusTo Do
PriorityMust
Story points2
Labelsservice:laboratory, type:backend, slice:S0
Componentsspecimens
FR referencesFR-LAB-003
Legacy FR refsFR-LIS-003
DependenciesLAB-US-003

User story: As a lab receiving technician, when a specimen arrives at the lab, I want to confirm receipt so that the system shows it is ready for processing.

Acceptance criteria (Gherkin):

  • Given a collected specimen, when I mark it received, then specimen status becomes received and accession moves to received.
  • Given a specimen not in collected state, when received is attempted, then state transition error is returned.

Technical notes:

  • POST /v1/laboratory/specimens/{id}/receive

Definition of Done:

  • Integration tests; state machine tests; docs updated.

LAB-US-005 — Enter lab result

FieldValue
Issue typeStory
SummaryLab technologist enters analyte result value, unit, and flags
Epic linkLAB-EPIC-02
StatusTo Do
PriorityMust
Story points5
Labelsservice:laboratory, type:backend, slice:S0
Componentsresults
FR referencesFR-LAB-005
Legacy FR refsFR-LIS-005
DependenciesLAB-US-003

User story: As a lab technologist, when I have a result from the analyzer or manual reading, I want to enter the value, unit, reference range, and flags so that the result is captured accurately.

Acceptance criteria (Gherkin):

  • Given an in-process accession, when I enter a result with quantity and unit, then the result is saved with status draft and abnormal flag calculated.
  • Given a value below critical threshold, when entered, then criticalFlag=true is set automatically.
  • Given a missing unit on a numeric result, when submitted, then VALIDATION_FAILED 400 is returned.

Technical notes:

  • POST /v1/laboratory/accessions/{id}/results; CriticalValuePolicyEngine.evaluate() called on entry

Definition of Done:

  • Unit tests for flag calculation; integration tests; coverage ≥ 80%; docs updated.

LAB-US-006 — Verify lab result

FieldValue
Issue typeStory
SummaryTechnologist verifies entered result, authorizing it for release
Epic linkLAB-EPIC-02
StatusTo Do
PriorityMust
Story points3
Labelsservice:laboratory, type:backend, slice:S0
Componentsverification
FR referencesFR-LAB-006
Legacy FR refsFR-LIS-006
DependenciesLAB-US-005

User story: As a lab technologist with verification privileges, when I review a draft result, I want to mark it as verified so that it is ready for pathologist sign-off and release.

Acceptance criteria (Gherkin):

  • Given a draft result and a user with svc:laboratory:verify scope, when verify is called, then result status becomes verified and LabResultVerified event is published.
  • Given a user without verify scope, when verify is attempted, then 403 is returned.
  • Given an already-verified result, when verify is called again, then idempotent 200 returned.

Technical notes:

  • POST /v1/laboratory/results/{id}/verify; scope guard enforced at controller layer

Definition of Done:

  • RBAC test for scope; integration tests; docs updated.

LAB-US-007 — Release results to chart

FieldValue
Issue typeStory
SummaryPathologist releases verified results; FHIR Observation and DiagnosticReport are filed
Epic linkLAB-EPIC-02
StatusTo Do
PriorityMust
Story points8
Labelsservice:laboratory, type:backend, slice:S0
Componentsresults, fhir-publish
FR referencesFR-LAB-006
Legacy FR refsFR-LIS-006, FR-RES-001
DependenciesLAB-US-006, cross-service: INTEROP-US-001

User story: As a pathologist, when I sign off on verified results, I want them released to the clinical chart so that clinicians can review them.

Acceptance criteria (Gherkin):

  • Given all results in verified state and no unacked critical flags, when release is triggered, then FHIR Observation and DiagnosticReport are created and diag.laboratory.result.released is published.
  • Given an unacknowledged critical result, when release is attempted, then LAB_CRITICAL_ACK_REQUIRED 422 is returned.
  • Given FHIR gateway is temporarily unavailable, when release is triggered, then publish is queued in outbox and retried.

Technical notes:

  • POST /v1/laboratory/accessions/{id}/release; outbox pattern for FHIR publish

Definition of Done:

  • Integration test for full release flow; outbox.spec.ts; FHIR conformance test; docs updated.

LAB-US-008 — Correct a released result

FieldValue
Issue typeStory
SummaryLab technologist submits correction to a released result, creating a new version
Epic linkLAB-EPIC-02
StatusTo Do
PriorityMust
Story points5
Labelsservice:laboratory, type:backend, slice:S1
Componentscorrections
FR referencesFR-LAB-006
Legacy FR refsFR-LIS-006, FR-RES-030
DependenciesLAB-US-007

User story: As a lab technologist, when I identify an error in a released result, I want to submit a correction with a reason so that the chart reflects the correct value and the correction is auditable.

Acceptance criteria (Gherkin):

  • Given a released result, when a correction is submitted with reason, then a new result version is created linked to the prior, and the prior result's status becomes superseded.
  • Given a correction, when processed, then LabResultCorrected event is published and the chart service receives the updated observation.
  • Given a correction without a reason, when submitted, then VALIDATION_FAILED 400 is returned.

Technical notes:

  • POST /v1/laboratory/results/{id}/correct; FHIR Observation updated with status amended; prior set to entered-in-error

Definition of Done:

  • Unit test for correction chain; integration test; docs updated.

LAB-US-009 — Detect and flag critical values

FieldValue
Issue typeStory
SummarySystem auto-flags results that cross configured critical thresholds
Epic linkLAB-EPIC-03
StatusTo Do
PriorityMust
Story points5
Labelsservice:laboratory, type:backend, slice:S1
Componentscritical-values
FR referencesFR-LAB-007
Legacy FR refsFR-LIS-007
DependenciesLAB-US-005

User story: As a patient safety officer, when a result value crosses a critical threshold, I want the system to flag it immediately so that clinicians are alerted before any harm occurs.

Acceptance criteria (Gherkin):

  • Given a critical value policy for potassium with low_critical=2.5, when a result of 2.1 is entered, then criticalFlag=true is set and diag.laboratory.critical.triggered is published.
  • Given no policy configured for a test, when a result is entered, then no critical flag is set.
  • Given a critical flag on a result, when release is attempted without ack, then LAB_CRITICAL_ACK_REQUIRED blocks release.

Technical notes:

  • CriticalValuePolicyEngine evaluates on EnterLabResultCommand; event published via outbox

Definition of Done:

  • Unit tests for all threshold combinations; integration test; docs updated.

LAB-US-010 — Critical result acknowledgment by clinician

FieldValue
Issue typeStory
SummaryClinician acknowledges a critical result, unblocking release
Epic linkLAB-EPIC-03
StatusTo Do
PriorityMust
Story points3
Labelsservice:laboratory, type:backend, slice:S1
Componentscritical-values, acknowledgment
FR referencesFR-LAB-007
Legacy FR refsFR-LIS-007, FR-RES-022
DependenciesLAB-US-009

User story: As a responsible clinician, when I receive a critical value alert, I want to acknowledge it with an action type so that the lab can proceed with release and the system records my response.

Acceptance criteria (Gherkin):

  • Given a critical flagged result, when I POST an ack with type reviewed, then LabResultAcknowledged event is published and release is unblocked.
  • Given the same ack submitted twice, when processed, then idempotent — no duplicate ack created.

Technical notes:

  • POST /v1/laboratory/results/{id}/acknowledge; ack unblocks release gating

Definition of Done:

  • Integration test; idempotency test; docs updated.

LAB-US-011 — Critical result escalation if unacknowledged

FieldValue
Issue typeStory
SummarySystem escalates critical result alert if not acknowledged within policy window
Epic linkLAB-EPIC-03
StatusTo Do
PriorityMust
Story points5
Labelsservice:laboratory, type:backend, slice:S1
Componentscritical-values, escalation
FR referencesFR-LAB-007
Legacy FR refsFR-LIS-007, FR-RES-023
DependenciesLAB-US-009, cross-service: COMMS-US-001

User story: As a patient safety officer, when a critical result is not acknowledged within the configured window, I want the system to escalate the alert to the next responsible role so that no critical value goes unnoticed.

Acceptance criteria (Gherkin):

  • Given a published diag.laboratory.critical.triggered event and no ack after 30 minutes, when the escalation timer fires, then a second alert is dispatched to the escalation role.
  • Given an ack is received before the escalation window, when checked, then no escalation event is published.

Technical notes:

  • Escalation managed by communication-service consuming diag.laboratory.critical.triggered; laboratory-service tracks critical_ack_attempts

Definition of Done:

  • E2E test for escalation flow; integration test with communication-service mock; docs updated.

LAB-US-012 — Lab worklist with priority filtering

FieldValue
Issue typeStory
SummaryLab technologist views filtered worklist by status, priority, and bench
Epic linkLAB-EPIC-04
StatusTo Do
PriorityShould
Story points3
Labelsservice:laboratory, type:backend, slice:S1
Componentsworklist
FR referencesFR-LAB-009
Legacy FR refsFR-LIS-009
DependenciesLAB-US-002

User story: As a lab technologist, when I start my shift, I want to see a prioritized worklist of pending accessions filtered by bench and urgency so that I work on the most critical samples first.

Acceptance criteria (Gherkin):

  • Given accessions with mixed priorities, when I query ?priority=stat, then only stat accessions are returned, sorted by createdAt ascending.
  • Given worklist query, when executed, then p95 response time is < 2 s.

Technical notes:

  • GET /v1/laboratory/accessions?status=in-process&priority=stat&bench=chemistry
  • Indexed on (tenant_id, status, priority, created_at)

Definition of Done:

  • Performance test; integration tests; docs updated.

LAB-US-013 — TAT reporting for accessions

FieldValue
Issue typeStory
SummaryLab supervisor views turnaround time metrics by priority
Epic linkLAB-EPIC-04
StatusTo Do
PriorityShould
Story points5
Labelsservice:laboratory, type:backend, slice:S1
Componentsreporting
FR referencesFR-LAB-010
Legacy FR refsFR-LIS-010
DependenciesLAB-US-007

User story: As a lab supervisor, when I review daily operations, I want to see TAT metrics by priority and test type so that I can identify bottlenecks and enforce SLAs.

Acceptance criteria (Gherkin):

  • Given released accessions, when TAT report is queried with date range, then median and p95 TAT by priority are returned.
  • Given an accession not yet released, when included, then it is excluded from TAT calculation.

Technical notes:

  • GET /v1/laboratory/reports/tat?from=&to=&priority=; computed from created_at to released_at

Definition of Done:

  • Integration test; docs updated.

LAB-US-014 — Receive HL7 v2 ORU results from external analyzer

FieldValue
Issue typeStory
SummaryExternal analyzer results ingest via HL7 v2 ORU through interop-service
Epic linkLAB-EPIC-05
StatusTo Do
PriorityShould
Story points8
Labelsservice:laboratory, type:backend, slice:S2
Componentshl7v2-adapter
FR referencesFR-LAB-008
Legacy FR refsFR-LIS-001 (interop), FR-INT-006, FR-INT-007
Dependenciescross-service: INTEROP-US-005

User story: As a lab system integrator, when an analyzer sends HL7 v2 ORU results, I want them automatically ingested into the accession so that manual transcription is eliminated.

Acceptance criteria (Gherkin):

  • Given a valid ORU^R01 message, when received via interop-service, then results are created in the matching accession.
  • Given a duplicate ORU with same message control ID, when processed, then idempotent — no duplicate result.
  • Given an ORU with no matching order, when processed, then result is stored as unlinked with patient ID and logged for admin review.

Technical notes:

  • interop-service maps ORU → FHIR Observation and POSTs to laboratory-service FHIR endpoint

Definition of Done:

  • Integration test with sample ORU fixture; deduplication test; docs updated.

LAB-US-015 — Cancellation of accession with reason

FieldValue
Issue typeStory
SummaryLab supervisor cancels an accession with audit trail
Epic linkLAB-EPIC-05
StatusTo Do
PriorityMust
Story points2
Labelsservice:laboratory, type:backend, slice:S0
Componentsaccessions
FR referencesFR-LAB-008
Legacy FR refsFR-LIS-008
DependenciesLAB-US-002

User story: As a lab supervisor, when an accession must be canceled, I want to record a reason so that the audit trail explains why the test was not completed.

Acceptance criteria (Gherkin):

  • Given an accession in ordered or collected state, when canceled with reason, then status becomes canceled and LabAccessionCanceled event is published.
  • Given an already-released accession, when cancellation is attempted, then LAB_ACCESSION_ALREADY_RELEASED 409 is returned.

Technical notes:

  • POST /v1/laboratory/accessions/{id}/cancel; reason required

Definition of Done:

  • State machine test; integration test; docs updated.

LAB-US-016 — Clinician result acknowledgment queue

FieldValue
Issue typeStory
SummaryClinician views unreviewed and critical results in their inbox
Epic linkLAB-EPIC-06
StatusTo Do
PriorityMust
Story points5
Labelsservice:laboratory, type:backend, slice:S1
Componentsresult-acknowledgment
FR referencesFR-LAB-011
Legacy FR refsFR-RES-020, FR-RES-021
DependenciesLAB-US-007

User story: As a clinician, when I start my rounds, I want to see a queue of unreviewed and critical results requiring my attention so that I don't miss important findings.

Acceptance criteria (Gherkin):

  • Given released results with no ack, when I query the queue, then unreviewed results for my patients are returned sorted by criticality and time.
  • Given a result I acknowledged, when I query, then it no longer appears in the unreviewed queue.
  • Given a critical result, when listed, then it is visually distinguished in the API response with criticalFlag: true.

Technical notes:

  • GET /v1/laboratory/results/queue?assigneeId=&status=unreviewed

Definition of Done:

  • Integration tests; docs updated.

LAB-US-017 — Acknowledge lab result

FieldValue
Issue typeStory
SummaryClinician records an acknowledgment action on a released result
Epic linkLAB-EPIC-06
StatusTo Do
PriorityMust
Story points3
Labelsservice:laboratory, type:backend, slice:S1
Componentsresult-acknowledgment
FR referencesFR-LAB-011
Legacy FR refsFR-RES-022
DependenciesLAB-US-016

User story: As a clinician, when I review a result, I want to acknowledge it with a specific action type so that the system knows I have seen it and how I responded.

Acceptance criteria (Gherkin):

  • Given a released result, when I POST ack with type plan-documented, then LabResultAcknowledged event is published and result removed from unreviewed queue.
  • Given a correction applied after my ack, when processed, then the corrected result re-enters my unreviewed queue.

Technical notes:

  • POST /v1/laboratory/results/{id}/acknowledge; ack_type validated against allowed enum

Definition of Done:

  • Integration test; re-ack-after-correction test; docs updated.

FieldValue
Issue typeStory
SummaryClinician views time-series trend for a LOINC-coded analyte
Epic linkLAB-EPIC-06
StatusTo Do
PriorityShould
Story points5
Labelsservice:laboratory, type:backend, slice:S2
Componentstrending
FR referencesFR-LAB-011
Legacy FR refsFR-RES-011
DependenciesLAB-US-007

User story: As a clinician, when I review a patient's lab history, I want to see a time-series trend for a specific analyte so that I can assess whether the patient's condition is improving or deteriorating.

Acceptance criteria (Gherkin):

  • Given 12 months of released potassium results for a patient, when I query trend for LOINC 2823-3, then a sorted list of {effectiveAt, value, unit, abnormalFlag} is returned.
  • Given a trend query, when executed, then response time < 2 s p95.

Technical notes:

  • GET /v1/laboratory/patients/{id}/trend?code=2823-3&from=&to=
  • Indexes on (tenant_id, test_code, released_at DESC) support efficient retrieval

Definition of Done:

  • Performance test; integration test; docs updated.