Skip to content

ohcnetwork/mock_analyzer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 

Repository files navigation

Overview

End‑to‑end specification for a Mock HL7 Analyzer with a Vite + React + TypeScript frontend and a Node.js (Express) TypeScript backend. The system simulates a lab analyzer that accepts HL7 v2 orders (OML/ORM) over MLLP, manages a worklist, generates results, and emits ORU/OUL back to CARE. Includes REST APIs, WebSocket feeds, TCP endpoints, UI pages, data contracts, and operational considerations.


1. Architecture

  • Frontend: Vite + React + TS, shadcn/ui, React Router, Zustand (or Redux Toolkit) for state, WebSocket for live logs, Axios for REST.

  • Backend: Node 20 + TypeScript; Express for REST; ws for WebSocket; custom MLLP server/client; Prisma ORM (SQLite dev, Postgres prod); Zod for schema validation; pino for logs; Prometheus metrics.

  • Services:

    • MLLP IN: listens for OML/ORM; ACKs; persists work.
    • Scheduler/Engine: transitions queued→processing→prelim→final; generates values.
    • MLLP OUT: sends ORU/OUL to configured endpoints; handles ACK/Retry.
    • REST & WS: configuration, worklist, scenarios, logs, stats.

2. Networking & Ports

Purpose Port Protocol
Web UI + REST API 8080 HTTP/HTTPS (Express)
Live Logs / Events 8080/ws WebSocket (JSON messages)
MLLP IN (orders) 2575 TCP (MLLP) / optional TLS on 2576
MLLP OUT (results) 2577 TCP (MLLP client to CARE) / optional TLS on 2578

MLLP framing: 0x0B … 0x1C 0x0D.


3. Environment & Config

.env

NODE_ENV=development
PORT_HTTP=8080
PORT_WS=8080
PORT_MLLP_IN=2575
CARE_MLLP_HOST=care-middleware
CARE_MLLP_PORT=2577
MLLP_TLS=false
ACK_TIMEOUT_MS=5000
RETRY_MAX=5
RETRY_BACKOFF_MS=2000
PRELIM_ENABLED=true
DUR_QUEUE_TO_START_MS=3000
DUR_ANALYSIS_MS=5000
DUR_PRELIM_TO_FINAL_MS=4000
DB_URL=file:./dev.db
AUTH_MODE=apikey
API_KEY=change-me

4. Data Model (Prisma/Conceptual)

Patient(id, mrn, name, birthDate, sex)
Specimen(id, accession, type, collectedAt, patientId)
WorkItem(id, specimenId, testCode, loinc, name, status, startedAt, finishedAt, channel, scenarioId)
Result(id, workItemId, value, unit, refLow, refHigh, flag, method, deviceId, status, effectiveAt)
Endpoint(id, name, host, port, tls, mode, ackRequired, lastAckLatencyMs)
CatalogTest(id, deviceCode, loinc, name, unit, refLow, refHigh, dtype, genMin, genMax, dist, abnormalProb)
MessageLog(id, direction, type, raw, parsedJson, sha256, status, correlationKey, createdAt)
Scenario(id, name, stepsJson, createdAt)
User(id, email, role)

status enums: WorkItem: queued|in_process|preliminary|final|corrected. Result: prelim|final|corrected.


5. REST API (Express, JSON; Auth via API key header x-api-key)

5.1 Configuration

  • GET /api/config → Current configuration

  • PUT /api/config → Update config

    {
      "resultsEndpoint": {"host":"care-mw","port":2577,"tls":false,"mode":"ORU"},
      "ackTimeoutMs":5000,
      "retry": {"max":5,"backoffMs":2000},
      "prelimEnabled": true,
      "durations": {"queueToStartMs":3000, "analysisMs":5000, "prelimToFinalMs":4000}
    }

5.2 Catalog & Mappings

  • GET /api/catalog/tests → list
  • PUT /api/catalog/tests → bulk upsert array of tests
  • PUT /api/catalog/mappings/loinc → upsert device↔LOINC
  • PUT /api/catalog/mappings/units → unit normalization map

5.3 Orders & Worklist

  • POST /api/orders/hl7 → Ingest raw HL7 order (bypass MLLP)

    {"hl7":"<raw HL7 string>"}
  • GET /api/worklist?state=queued|in_process|final|*"

  • POST /api/worklist/{id}/start → move to in_process

  • POST /api/worklist/{id}/prelim → mark prelim (optional)

  • POST /api/worklist/{id}/finalize → finalize with optional value override

    {"value":"6.8","unit":"mmol/L","flag":"H","note":"manual override"}

5.4 Results Emission

  • POST /api/results/emit → emit final results as ORU/OUL

    {"workItemIds":["wi_123","wi_456"], "mode":"ORU", "splitPanels":true}
  • POST /api/results/correct → send corrected result (OBX-11=C)

    {"observationId":"obs_1","newValue":"7.1","reason":"delta check"}

5.5 Scenarios & Failures

  • POST /api/scenarios → define & run scenario

    {
      "name":"lost-ack-then-retry",
      "steps":[
        {"action":"ingest-hl7","template":"oml_o21","vars":{ "SR":"SR-001", "ACC":"ACC-789", "TEST":"2345-7"}},
        {"action":"set-failure","type":"drop-ack","count":1},
        {"action":"advance","state":"final","afterMs":4000},
        {"action":"emit-results"}
      ]
    }
  • POST /api/failures → inject transient failures

    {"type":"bad-unit"}

5.6 Messages, Audit & Stats

  • GET /api/messages?direction=in|out&type=ORM,OML,ORU,OUL,ACK&limit=100
  • GET /api/messages/{id} → raw + parsed + ack chain
  • GET /api/stats → throughput, ack latency, errors, queue depth

6. WebSocket Feed (/ws)

  • Event types: mllp_in, mllp_out, ack, state_change, error, metric.
  • Payload example:
{"type":"mllp_out","ts":"2025-10-18T12:34:56Z","messageType":"ORU^R01","msgId":"MSG123","correlationKey":"MSG123.SR-001.ACC-789"}

7. MLLP Services (Backend)

7.1 MLLP IN (Orders)

  • Listens on PORT_MLLP_IN (2575). Accepts OML^O21 / ORM^O01.
  • Parses MSH, PID, ORC, OBR, [SPM] → creates Patient (if needed), Specimen, WorkItems.
  • Returns ACK (MSA|AA) or AE/AR on parse error.
  • Idempotency: {MSH-10}.{ORC-2}.{ORC-3}.

7.2 Scheduler/Engine

  • Cron/timers move items through states using DUR_* config.
  • Deterministic generator by seed + test distribution; optional random noise.

7.3 MLLP OUT (Results)

  • Composes ORU^R01 (default) or OUL^R22 (LAW mode).
  • Handles ACK wait (ACK_TIMEOUT_MS), retry with backoff up to RETRY_MAX.
  • Dead-letter queue on exhausted retries; surfaces via /api/stats and WS.

8. HL7 Message Templates

8.1 Inbound Order (OML^O21)

MSH|^~\&|CARE|CAREHOSP|MOCKDEV|ANALYZER|{DTM}||OML^O21|{MSGID}|P|2.5.1
PID|1||{MRN}^^^CARE^MR||{LAST}^{FIRST}||{DOB}|{SEX}
ORC|NW|{PLACER}|{FILLER}
OBR|1|{PLACER}|{FILLER}|{TEST}^{NAME}^{LN}
SPM|1|{ACCESSION}|||{COLLDT}

8.2 Outbound Result (ORU^R01)

MSH|^~\&|MOCKDEV|LAB|CARE|HOSP|{DTM}||ORU^R01|{MSGID}|P|2.5.1
PID|1||{MRN}^^^CARE^MR||{LAST}^{FIRST}||{DOB}|{SEX}
ORC|RE|{PLACER}|{FILLER}
OBR|1|{PLACER}|{FILLER}|{TEST}^{NAME}^{LN}||||||||||||||||||F
SPM|1|{ACCESSION}
OBX|1|NM|{TEST}^{NAME}^{LN}||{VALUE}|{UCUM}^{UCUM}^UCUM|{LOW}-{HIGH}|{FLAG}|F|||{EFFT}|||{METHOD}|{DEVICEID}

9. Frontend (Vite React TS)

9.1 Routes / Pages

  1. / Dashboard: summary metrics, connection status, queue depth, ACK latency.
  2. /worklist Worklist: table (Accession, Patient, Test, Status, Value, Actions).
  3. /analyzer Analyzer view: channels, sliders (throughput, error prob), start/finalize.
  4. /mappings Test catalog & code↔LOINC mappings editor.
  5. /endpoints Configure outbound endpoints, ACK policy, TLS; test connection.
  6. /messages Message log: live stream + filters; detail drawer (raw HL7 | parsed JSON | ACK chain).
  7. /scenarios Scenario runner & failure injection.
  8. /settings App settings, API key management, PII redaction toggle.

9.2 Core Components

  • StatusBar (MLLP lights, mode switch, metrics)
  • WorklistTable (virtualized); row actions: Start, Prelim, Finalize, Emit, Correct
  • MessageViewer (syntax-highlight HL7, JSON pane)
  • EndpointForm, MappingGrid, ScenarioBuilder
  • MetricsCards (Prometheus snapshots via REST)

9.3 State & Data Fetching

  • Zustand slices: config, worklist, messages, scenarios, metrics.
  • WebSocket listener → dispatches live events to stores.
  • Axios instance with API key and retry; Zod schemas for responses.

9.4 UX Flows

  • Happy path: Order arrives → appears in Worklist (queued) → auto start → prelim/final → Emit → ACK OK.
  • Correction: Select final row → Correct → input new value → emit corrected ORU (OBX-11=C).
  • Failure test: Run scenario → UI shows dropped ACK, retries, eventual success or DLQ.

10. Security

  • REST: API key or JWT; CORS locked to expected origins.
  • Optional mTLS for MLLP.
  • Roles: operator, engineer, admin (feature gating in UI and REST guards).
  • PII masking in logs (configurable); raw HL7 accessible to engineer/admin only.

11. Observability

  • /api/stats for UI cards; /metrics Prometheus: mllp_in_total, mllp_out_total, ack_latency_seconds, order_queue_depth, retries_total, dlq_total.
  • Pino structured logs (JSON); request/response IDs; correlation keys included.

12. Docker & Dev

docker-compose.yml (excerpt)

services:
  analyzer:
    build: ./server
    env_file: .env
    ports:
      - "8080:8080"
      - "2575:2575"
    depends_on: [db]
  web:
    build: ./web
    environment:
      - VITE_API_BASE=http://localhost:8080
    ports:
      - "5173:5173"
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD=dev
      POSTGRES_DB=mock_analyzer
    ports:
      - "5432:5432"

13. Testing Strategy

  • Unit: HL7 parser/serializer, value generator, MLLP framing.
  • Integration: send OML via MLLP; assert ACK; transition to final; emit ORU; assert CARE ACK (use a mock MLLP server in CI).
  • E2E: Cypress/Playwright for UI flows; record/replay HL7 samples; scenario runs.
  • Conformance: validate messages with HL7 v2 profiles (z-schema/Zod for fields; optional NIST tooling offline).

14. Minimal Contracts (Schemas)

14.1 WorkItem DTO

export type WorkItemDTO = {
  id: string;
  accession: string;
  patient: { mrn: string; name: string };
  test: { deviceCode: string; loinc?: string; name: string };
  status: 'queued'|'in_process'|'preliminary'|'final'|'corrected';
  value?: string; unit?: string; flag?: 'L'|'N'|'H';
  startedAt?: string; finishedAt?: string;
};

14.2 Config DTO

export type ConfigDTO = {
  resultsEndpoint: { host: string; port: number; tls: boolean; mode: 'ORU'|'OUL' };
  ackTimeoutMs: number;
  retry: { max: number; backoffMs: number };
  prelimEnabled: boolean;
  durations: { queueToStartMs: number; analysisMs: number; prelimToFinalMs: number };
};

15. Acceptance Criteria (MVP)

  1. Receive OML/ORM on 2575; respond with ACK; order visible in Worklist within 1s.
  2. Auto-process to final within configured durations; REST reflects state transitions.
  3. Emit ORU to configured CARE endpoint; receive ACK within ACK_TIMEOUT_MS; retries on failure.
  4. Message logs store raw HL7 + parsed JSON + correlation keys; searchable via REST & visible in UI.
  5. WebSocket broadcasts events for UI real-time updates.
  6. Security: API key enforced for all REST write ops; PII masking toggle works.

About

Mock Lab Analyzer for testing HL7 Lab Interfacing

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published