feature: RBAC + Clinical Audit Logging
This commit is contained in:
@@ -2,11 +2,11 @@
|
||||
|
||||
A production-quality clinical backend built with ASP.NET Core 8, PostgreSQL, Apache Kafka, RabbitMQ, Elasticsearch, Redis, and MinIO. The domain models the observe-alert-acknowledge lifecycle at the center of any clinical monitoring system: patient encounters, continuous vital sign and lab result ingest, real-time sepsis and NEWS2 scoring, and clinician notification with automatic escalation.
|
||||
|
||||
**Implementation status:** Twenty-four planned phases are complete through Phase 29 — from schema and CRUD through Kafka, Elasticsearch CQRS, sepsis detection, RabbitMQ paging with DLQ escalation, reconciliation jobs, Prometheus/Grafana observability, the MinIO Parquet data lake, clinical data model expansion, warning alerts and orders, the NEWS2 composite scoring engine, trend detection with alert suppression, qSOFA bedside screening, medication administration with alert correlation annotations, the console replay simulator, the **Vue 3 ward dashboard**, clinician feedback mode, **Glasgow Coma Scale (GCS) scoring**, **SOFA organ-dysfunction scoring with baseline tracking and delta sepsis alerts**, the **Sepsis-3 clinical refactor** (SIRS removed, qSOFA repositioned as screening, SOFA delta ≥ 2 triggers bundles), **frontend GCS entry and SOFA display**, and **expanded simulator scenarios with clinical validation**. See [Implemented Phases](#implemented-phases) for the full breakdown. Guides: [dashboard-guide.md](docs/dashboard-guide.md) (technical), [clinical-testing-guide.md](docs/clinical-testing-guide.md) (doctors & nurses).
|
||||
**Implementation status:** Twenty-five planned phases are complete through Phase 30 — from schema and CRUD through Kafka, Elasticsearch CQRS, sepsis detection, RabbitMQ paging with DLQ escalation, reconciliation jobs, Prometheus/Grafana observability, the MinIO Parquet data lake, clinical data model expansion, warning alerts and orders, the NEWS2 composite scoring engine, trend detection with alert suppression, qSOFA bedside screening, medication administration with alert correlation annotations, the console replay simulator, the **Vue 3 ward dashboard**, clinician feedback mode, **Glasgow Coma Scale (GCS) scoring**, **SOFA organ-dysfunction scoring with baseline tracking and delta sepsis alerts**, the **Sepsis-3 clinical refactor** (SIRS removed, qSOFA repositioned as screening, SOFA delta ≥ 2 triggers bundles), **frontend GCS entry and SOFA display**, **expanded simulator scenarios with clinical validation**, and the **FHIR R4 Inbound Facade** for EHR integration. See [Implemented Phases](#implemented-phases) for the full breakdown. Guides: [dashboard-guide.md](docs/dashboard-guide.md) (technical), [clinical-testing-guide.md](docs/clinical-testing-guide.md) (doctors & nurses).
|
||||
|
||||
## Domain Model — How It Maps to a Real Clinical System
|
||||
|
||||
In a hospital, a patient presents for care and an encounter is opened. Bedside monitors and lab systems post observations continuously against that encounter. A rules engine evaluates each observation against configured thresholds and flags abnormal values as clinical alerts. Composite scoring engines (NEWS2, GCS, SOFA, qSOFA) aggregate multiple vitals and labs into acuity scores. The sepsis pathway follows Sepsis-3 consensus: qSOFA ≥ 2 creates a bedside screening alert recommending SOFA labs; when SOFA delta ≥ 2 from baseline confirms organ dysfunction, a `SOFA_SEPSIS` alert triggers the treatment bundle. Clinicians acknowledge and resolve alerts. If a critical alert goes unacknowledged for five minutes, the system escalates to the on-call backup. All events flow through Kafka so the Elasticsearch dashboard, scoring engines, and data lake writer consume the same stream independently.
|
||||
In a hospital, a patient presents for care and an encounter is opened. Bedside monitors and lab systems post observations continuously against that encounter — either directly via the REST API or through the FHIR R4 inbound facade that maps HL7 FHIR resources from integration engines (Mirth Connect, Rhapsody) into the internal domain. A rules engine evaluates each observation against configured thresholds and flags abnormal values as clinical alerts. Composite scoring engines (NEWS2, GCS, SOFA, qSOFA) aggregate multiple vitals and labs into acuity scores. The sepsis pathway follows Sepsis-3 consensus: qSOFA ≥ 2 creates a bedside screening alert recommending SOFA labs; when SOFA delta ≥ 2 from baseline confirms organ dysfunction, a `SOFA_SEPSIS` alert triggers the treatment bundle. Clinicians acknowledge and resolve alerts. If a critical alert goes unacknowledged for five minutes, the system escalates to the on-call backup. All events flow through Kafka so the Elasticsearch dashboard, scoring engines, and data lake writer consume the same stream independently.
|
||||
|
||||
```
|
||||
Patient ─────────────────────────── one patient = one MRN, many lifetime encounters
|
||||
@@ -73,6 +73,7 @@ An `OutboxEvent` is written in the same transaction as any observation or alert,
|
||||
- **Medication Correlation Annotations** — `MedicationCorrelationHelper` appends medication context to warning and NEWS2 alert details when a mapped drug was administered within the correlation window (default 90 min); drug-to-vital mappings in `MedicationCorrelation` config (`appsettings.json`); annotates rather than suppresses — alerts still fire; sepsis, trend, and critical sync-path alerts are never annotated; design rationale in `docs/decisions/medication-correlation-design.md`
|
||||
- **Ward Dashboard APIs** — `GET /encounters` returns paginated `WardEncounterSummary` rows (patient name/MRN, room/bed, department, status, latest NEWS2 score, live qSOFA criteria count from Redis, sepsis bundle status, open alert count); filterable by `status` and `department`; `GET /encounters/:id/qsofa/current` exposes Redis-backed qSOFA state; CORS policy `Dashboard` allows configured origins (default `http://localhost:5173`)
|
||||
- **Ward Dashboard Frontend** — Vue 3 SPA (`vigilcare-dashboard/`) with virtual ward table (NEWS2-sorted), patient detail (vitals, scores, alerts, orders, sepsis bundle, GCS entry form, SOFA score panel), alert center (global acknowledge/resolve), vital sign trend charts with local replay scrubbing, NEWS2 history chart, alert reasoning with optional medication context, and clinician feedback on every alert; polls API every 5–10 s; guides in `docs/dashboard-guide.md` and `docs/clinical-testing-guide.md`
|
||||
- **FHIR R4 Inbound Facade** — `POST /fhir/R4/{Patient,Encounter,Observation,MedicationAdministration}` accepts FHIR R4 JSON resources (`application/fhir+json`); `POST /fhir/R4` processes transaction Bundles (Patient → Encounter → Observation in dependency order); `GET /fhir/R4/metadata` returns a CapabilityStatement; LOINC-to-internal code mapping (19 observation codes + SNOMED CT fallbacks); Fahrenheit-to-Celsius unit conversion; `ExternalResourceIdentifier` table links hospital MRNs and visit numbers to internal UUIDs for idempotent upserts; `FhirApiKeyMiddleware` authenticates via `X-Api-Key` header; `FhirExceptionFilter` returns FHIR `OperationOutcome` on errors; configurable identifier systems, department codes, and encounter class mappings via `Fhir` config section; Prometheus `fhir_ingest_total` and `fhir_mapping_errors_total`; integration guide for Mirth Connect HL7v2→FHIR channels in `docs/integration/mirth-fhir-channels.md`
|
||||
- **Clinician Feedback Mode** — six quick ratings per alert (useful, too early, too late, false positive, missing context, would act); optional notes; Feedback Summary with aggregate stats and JSON/CSV export; client-side persistence for product research
|
||||
- **Console Replay Simulator** — standalone `VigilCare.Simulator` .NET console app replays JSON scenario files against the live API with configurable speed (`--speed 0` instant, `60` = 60× faster); commands: `replay`, `replay-all`, `validate`, `dry-run`; optional `--poll` shows alerts, NEWS2, GCS, SOFA, and sepsis bundle state during replay; eleven sample scenarios in `VigilCare.Simulator/Scenarios/List/` (including GCS neurological decline, SOFA sepsis progression, and SpO₂/FiO₂ fallback); user guide in `docs/simulator-guide.md`
|
||||
- **RabbitMQ Notification Workers** — `NotificationPublisherService` reads `alert.generated` from Kafka and publishes paging jobs to `alerts.paging.queue`; `PagingWorkerService` sends the page and waits for acknowledgment; if no ack arrives before timeout it NACKs to `alerts.paging.dlq` with `x-message-ttl = 300000ms`; if the host is stopping, in-flight paging messages are NACKed with `requeue=true` so they are retried after restart and do not false-escalate; `EscalationWorkerService` pages the on-call backup and sets alert status to `escalated`; `DischargeSummaryWorkerService` reads `encounter.status.changed`, generates a discharge summary, and stores it in MinIO under `/discharge-summaries/{encounterId}/summary.pdf`
|
||||
@@ -89,9 +90,10 @@ An `OutboxEvent` is written in the same transaction as any observation or alert,
|
||||
|
||||
```
|
||||
HTTP request
|
||||
→ FhirApiKeyMiddleware (X-Api-Key guard for /fhir/* routes)
|
||||
→ CorrelationIdMiddleware
|
||||
→ ExceptionHandlerMiddleware
|
||||
→ Controllers
|
||||
→ Controllers (REST API + FHIR R4 ingest)
|
||||
→ Services
|
||||
├── PostgreSQL (EF Core — writes, keyed reads)
|
||||
├── Redis (threshold cache, qSOFA state, NEWS2 parameter state, GCS state, SOFA lab cache, trend history, alert suppression keys)
|
||||
@@ -143,6 +145,7 @@ IHostedServices (background):
|
||||
| Metrics | prometheus-net.AspNetCore (`GET /metrics`) |
|
||||
| Dashboards | Prometheus 2.52 + Grafana 10.4 |
|
||||
| Data lake format | Parquet.Net 4.x |
|
||||
| FHIR | Hl7.Fhir.R4 (Firely SDK — parsing, serialization, model) |
|
||||
| Docs | Swagger / OpenAPI (Swashbuckle) |
|
||||
| Validation | FluentValidation.AspNetCore |
|
||||
| Testing | xUnit + Testcontainers + WebApplicationFactory |
|
||||
@@ -169,6 +172,8 @@ VigilCareClinicalAPI/
|
||||
│ ├── GcsController.cs # Latest GCS score per encounter
|
||||
│ ├── SofaController.cs # Current SOFA score and cursor-paginated history
|
||||
│ ├── SepsisBundlesController.cs # Current bundle per encounter, bundle detail by ID
|
||||
│ ├── FhirIngestController.cs # FHIR R4 ingest: Patient, Encounter, Observation, MedicationAdministration, Bundle
|
||||
│ ├── FhirMetadataController.cs # FHIR R4 CapabilityStatement (GET /fhir/R4/metadata)
|
||||
│ └── AnalyticsController.cs # Elasticsearch-backed patient search, trend, alert summary, population
|
||||
├── Domains/
|
||||
│ ├── Entities/
|
||||
@@ -185,7 +190,8 @@ VigilCareClinicalAPI/
|
||||
│ │ ├── ReconciliationAlert.cs
|
||||
│ │ ├── SepsisBundle.cs # Four-element treatment bundle with 1-hour compliance deadline
|
||||
│ │ ├── SepsisBundleElement.cs # Individual bundle element linked to a clinical order
|
||||
│ │ └── MedicationAdministration.cs # Drug administration record per encounter
|
||||
│ │ ├── MedicationAdministration.cs # Drug administration record per encounter
|
||||
│ │ └── ExternalResourceIdentifier.cs # Links external system identifiers (MRN, visit#) to internal UUIDs
|
||||
│ └── Enums/
|
||||
│ ├── EncounterStatus.cs # Scheduled, Active, Discharged, Cancelled
|
||||
│ ├── EncounterType.cs # Inpatient, Outpatient, Emergency
|
||||
@@ -197,11 +203,28 @@ VigilCareClinicalAPI/
|
||||
│ ├── SepsisBundleComplianceStatus.cs # InProgress, Compliant, NonCompliant
|
||||
│ ├── SepsisBundleElementStatus.cs # Pending, Completed
|
||||
│ ├── SepsisBundleElementType.cs # BloodCultures, SerumLactate, BroadSpectrumAntibiotics, IvFluidResuscitation
|
||||
│ ├── ExternalResourceType.cs # Patient, Encounter — for external identifier linking
|
||||
│ └── OrderType.cs / ReconciliationCheckType.cs / Department.cs / OrderStatus.cs
|
||||
│ └── Json/
|
||||
│ ├── ObservationSourceJsonConverter.cs
|
||||
│ ├── DepartmentJsonConverter.cs
|
||||
│ └── BloodTypeJsonConverter.cs # Clinical notation (A+, AB-) in JSON API
|
||||
├── Fhir/
|
||||
│ ├── Codes/
|
||||
│ │ ├── LoincCodeMapper.cs # LOINC → internal observation code (19 codes + SNOMED CT fallbacks)
|
||||
│ │ ├── LoincMapping.cs # Code mapping record (InternalCode, ExpectedUnit, AllowFahrenheit)
|
||||
│ │ └── FhirUnitConverter.cs # Fahrenheit→Celsius conversion for temperature observations
|
||||
│ ├── Mapping/
|
||||
│ │ ├── PatientFhirMapper.cs # FHIR Patient ↔ internal Patient upsert
|
||||
│ │ ├── EncounterFhirMapper.cs # FHIR Encounter ↔ internal Encounter upsert (ACT class, department, status)
|
||||
│ │ ├── ObservationFhirMapper.cs # FHIR Observation → IngestObservationRequest (single + component)
|
||||
│ │ ├── MedicationAdministrationFhirMapper.cs # FHIR MedicationAdministration → CreateMedicationAdministrationRequest
|
||||
│ │ ├── FhirReferenceResolver.cs # Resolves FHIR references (identifier or UUID) to internal IDs
|
||||
│ │ └── FhirMappingHelpers.cs # DateTimeOffset extraction, reference parsing utilities
|
||||
│ ├── FhirBundleProcessor.cs # Transaction Bundle processing in dependency order (Patient→Encounter→Obs)
|
||||
│ ├── FhirExceptionFilter.cs # Converts exceptions to FHIR OperationOutcome responses
|
||||
│ ├── FhirMappingException.cs # Typed exception for FHIR mapping failures
|
||||
│ └── FhirOperationOutcomeBuilder.cs # Builds FHIR OperationOutcome from exceptions and error codes
|
||||
├── Services/
|
||||
│ ├── Interfaces/ # IPatientService, IEncounterService, …
|
||||
│ ├── PatientService.cs
|
||||
@@ -218,6 +241,7 @@ VigilCareClinicalAPI/
|
||||
│ ├── SepsisBundleService.cs # Bundle creation, element completion, compliance evaluation
|
||||
│ ├── MedicationService.cs # Medication CRUD; GetRecentForEncounterAsync for correlation
|
||||
│ ├── QsofaService.cs # Redis-backed qSOFA criteria count for API/dashboard
|
||||
│ ├── ExternalIdentifierService.cs # Links/resolves external system identifiers to internal UUIDs
|
||||
│ ├── WarningEvaluator.cs # Warning-range evaluation; suppression + medication annotation; idempotent INSERT
|
||||
│ ├── AnalyticsService.cs # Elasticsearch query wrappers
|
||||
│ └── PlausibilityValidator.cs # Per-code numeric range guard
|
||||
@@ -264,6 +288,7 @@ VigilCareClinicalAPI/
|
||||
│ ├── RabbitMqOptions.cs / MinioOptions.cs
|
||||
│ ├── ReconciliationJobOptions.cs
|
||||
│ ├── MedicationCorrelationOptions.cs # Drug-vital mappings + correlation window
|
||||
│ ├── FhirOptions.cs # API key, identifier systems, department/class maps, defaults
|
||||
│ └── DashboardOptions.cs # CORS origins for ward dashboard frontend
|
||||
├── Sepsis/
|
||||
│ ├── AlertCreationGuard.cs # Prevents creation of deprecated alert types (SEPSIS_WARNING)
|
||||
@@ -315,6 +340,7 @@ VigilCareClinicalAPI/
|
||||
│ ├── DomainException.cs
|
||||
│ └── ValidationException.cs
|
||||
├── Middlewares/
|
||||
│ ├── FhirApiKeyMiddleware.cs # X-Api-Key guard for /fhir/* routes; returns OperationOutcome on 401
|
||||
│ ├── CorrelationIdMiddleware.cs
|
||||
│ └── ExceptionHandlerMiddleware.cs
|
||||
└── Migrations/
|
||||
@@ -355,7 +381,9 @@ tests/
|
||||
├── EncountersListTests.cs # Ward encounter list filters and summary fields
|
||||
├── QsofaCurrentTests.cs # qSOFA current API — Redis state, criteria breakdown
|
||||
├── GcsScoringTests.cs # GCS component scoring, alerts, NEWS2/qSOFA integration paths
|
||||
└── SofaScoringTests.cs # SOFA organ scores, baseline, delta alerts, carry-forward, vasopressors
|
||||
├── SofaScoringTests.cs # SOFA organ scores, baseline, delta alerts, carry-forward, vasopressors
|
||||
└── Fhir/
|
||||
└── FhirIngestTests.cs # FHIR R4 patient upsert idempotency, observation LOINC mapping, unknown code 422, transaction bundle
|
||||
|
||||
VigilCare.Simulator/ # Phase 16 — console replay simulator (HTTP-only, no direct DB/Kafka)
|
||||
├── Program.cs # CLI: replay, replay-all, validate, dry-run
|
||||
@@ -397,7 +425,8 @@ scripts/
|
||||
├── run-phase26-verification.sh # Phase 26 — SOFA scoring integration tests + baseline/delta API checks
|
||||
├── run-phase27-verification.sh # Phase 27 — Sepsis-3 refactor: SIRS removal, QSOFA_SCREEN, SOFA bundle trigger
|
||||
├── run-phase28-verification.sh # Phase 28 — Frontend GCS entry + SOFA display + sepsis UI refactor
|
||||
└── run-phase29-verification.sh # Phase 29 — Simulator scenario expansion + clinical validation
|
||||
├── run-phase29-verification.sh # Phase 29 — Simulator scenario expansion + clinical validation
|
||||
└── run-phase30-verification.sh # Phase 30 — FHIR R4 ingest integration tests + manual bundle/metadata checks
|
||||
|
||||
docs/
|
||||
├── plans/ # Phase implementation and verification guides
|
||||
@@ -405,6 +434,8 @@ docs/
|
||||
├── dashboard-guide.md # VigilCare Dashboard user guide (ward, patient detail, charts)
|
||||
├── patient-encounter-api-lifecycle.md # Full API walkthrough: registration → active stay → discharge
|
||||
├── simulator-guide.md # VigilCare.Simulator user guide
|
||||
├── integration/
|
||||
│ └── mirth-fhir-channels.md # Mirth Connect HL7v2→FHIR channel mapping (ADT A01/A03/A08, ORU R01)
|
||||
├── decisions/
|
||||
│ ├── data-lake-design.md # Parquet vs JSON, partitioning, replay rationale
|
||||
│ ├── sepsis-engine-design.md # Sepsis-3 qSOFA screening and idempotent alert design
|
||||
@@ -613,6 +644,7 @@ Integration tests use `WebApplicationFactory` with a `Testing` environment and T
|
||||
| `QsofaCurrentTests` | — | `GET /qsofa/current` — criteria count and breakdown from Redis |
|
||||
| `GcsScoringTests` | 25 | GCS component scoring, classification, alerts, CNS integration with SOFA |
|
||||
| `SofaScoringTests` | 26 | SOFA organ scores, baseline eligibility, delta alerts, carry-forward, vasopressors |
|
||||
| `FhirIngestTests` | 30 | FHIR R4 patient upsert idempotency, LOINC observation mapping, unknown code 422, transaction bundle |
|
||||
|
||||
### Verification Scripts
|
||||
|
||||
@@ -628,6 +660,7 @@ With the API running (`dotnet run`) and Docker Compose up:
|
||||
./scripts/run-phase14-verification.sh # qSOFA, sepsis bundle compliance, Phase 14 integration tests
|
||||
./scripts/run-phase15-verification.sh # Medication administration + correlation annotation pipeline
|
||||
./scripts/run-phase27-verification.sh # Sepsis-3 refactor: SIRS removal, QSOFA_SCREEN, SOFA bundle trigger
|
||||
./scripts/run-phase30-verification.sh # FHIR R4 ingest integration tests + manual bundle/metadata checks
|
||||
```
|
||||
|
||||
Phase 25 — GCS scoring (requires running API + Docker Compose; set an active encounter UUID):
|
||||
@@ -709,6 +742,8 @@ See `docs/plans/phase-8-plan.md` through `docs/plans/phase-12-plan.md` for manua
|
||||
| `alerts_unacknowledged_gauge` | Gauge | — | `AlertsUnacknowledgedCollector` — open CRITICAL alerts older than 5 minutes |
|
||||
| `outbox_pending_events` | Gauge | — | `OutboxPendingCollector` — unprocessed outbox rows |
|
||||
| `kafka_consumer_lag` | Gauge | `consumer_group` | `KafkaConsumerLagCollector` — `es-indexer`, `sepsis-engine`, `notification-publisher`, `data-lake-writer` |
|
||||
| `fhir_ingest_total` | Counter | `resource_type`, `outcome` | `FhirIngestController` — per resource type (`Patient`, `Encounter`, `Observation`, `MedicationAdministration`, `Bundle`) with `success` / `error` outcome |
|
||||
| `fhir_mapping_errors_total` | Counter | `resource_type` | `FhirExceptionFilter` — mapping/validation failures by resource type |
|
||||
|
||||
Prometheus scrapes the API via `infra/prometheus/prometheus.yml` (`job: vigilcare_api` → `host.docker.internal:5270`). Grafana loads the clinical dashboard from `infra/grafana/dashboards/vigilcare.json`.
|
||||
|
||||
@@ -1031,6 +1066,27 @@ Bundles are created automatically by `SepsisAlertHandler` when a `SOFA_SEPSIS` a
|
||||
|
||||
When a correlated drug was given within the `MedicationCorrelation.CorrelationWindowMinutes` window (default 90), subsequent warning and NEWS2 alerts for affected vitals include an annotation in `details` — e.g. `— note: metoprolol 25mg (PO) administered 45 min ago`. See `docs/decisions/medication-correlation-design.md`.
|
||||
|
||||
### FHIR R4 Ingest
|
||||
|
||||
All FHIR endpoints are under `/fhir/R4`, accept `application/fhir+json`, and return FHIR R4 JSON responses. Authentication is via `X-Api-Key` header (configured in `Fhir:ApiKey`; disabled when blank). Errors return a FHIR `OperationOutcome` with appropriate issue codes.
|
||||
|
||||
| Method | Path | Description |
|
||||
|---|---|---|
|
||||
| GET | `/fhir/R4/metadata` | CapabilityStatement — supported resource types and interactions |
|
||||
| POST | `/fhir/R4/Patient` | Upsert a Patient by hospital identifier (MRN); idempotent |
|
||||
| POST | `/fhir/R4/Encounter` | Upsert an Encounter by visit identifier; resolves patient by identifier |
|
||||
| POST | `/fhir/R4/Observation` | Ingest an Observation; maps LOINC/SNOMED codes to internal codes; supports component observations |
|
||||
| POST | `/fhir/R4/MedicationAdministration` | Record a medication administration; resolves encounter by identifier |
|
||||
| POST | `/fhir/R4` | Process a transaction Bundle (Patient → Encounter → Observation/MedicationAdministration in dependency order) |
|
||||
|
||||
**Identifier resolution:** FHIR resources reference each other by hospital identifiers (e.g. MRN in `Patient.identifier`, visit number in `Encounter.identifier`). The `ExternalResourceIdentifier` table maps these to internal UUIDs. On first ingest, a new internal record is created and the identifier is linked. Subsequent requests with the same identifier update the existing record (idempotent upsert).
|
||||
|
||||
**LOINC code mapping:** 19 LOINC codes and 3 SNOMED CT fallback codes map to internal observation codes (see `LoincCodeMapper`). Unsupported codes return `422` with an `OperationOutcome`. Temperature observations in Fahrenheit (`[degF]`) are automatically converted to Celsius.
|
||||
|
||||
**Transaction Bundles:** `POST /fhir/R4` accepts `Bundle.type=transaction`. Entries are processed in dependency order (Patient first, then Encounter, then Observation/MedicationAdministration). On first failure, processing stops (transaction semantics) and the response includes the `OperationOutcome`.
|
||||
|
||||
**Integration with Mirth Connect:** HL7v2 ADT messages (A01 admit, A03 discharge, A08 update) and ORU R01 lab results can be mapped to FHIR Bundles via Mirth channels. See `docs/integration/mirth-fhir-channels.md`.
|
||||
|
||||
---
|
||||
|
||||
## Data Models
|
||||
@@ -1254,6 +1310,19 @@ processedAt DateTimeOffset?
|
||||
|
||||
Partial index: `(created_at) WHERE processed_at IS NULL`
|
||||
|
||||
### ExternalResourceIdentifier
|
||||
|
||||
```
|
||||
id Guid PK
|
||||
resourceType string PATIENT | ENCOUNTER
|
||||
internalId Guid FK → Patient or Encounter (logical, not enforced)
|
||||
system string required — identifier system URI (e.g. http://hospital.example/mrn)
|
||||
value string required — identifier value (e.g. MRN-001)
|
||||
createdAt DateTimeOffset
|
||||
```
|
||||
|
||||
Unique index: `(resource_type, system, value)` — one mapping per external identifier
|
||||
|
||||
### ReconciliationAlert
|
||||
|
||||
```
|
||||
@@ -1522,7 +1591,7 @@ Observation history uses cursor pagination on `(recorded_at DESC, id DESC)`. Off
|
||||
|
||||
## Implemented Phases
|
||||
|
||||
Twenty-four phases from the project roadmap are implemented and verified, including the **Sepsis-3 clinical refactor** (Phases 27–29). Integration tests (`dotnet test`) and per-phase verification scripts cover Phases 8–15, 25–29. Phases 17–19 add the Vue dashboard and clinician feedback (Vitest in `vigilcare-dashboard/`).
|
||||
Twenty-five phases from the project roadmap are implemented and verified, including the **Sepsis-3 clinical refactor** (Phases 27–29) and the **FHIR R4 Inbound Facade** (Phase 30). Integration tests (`dotnet test`) and per-phase verification scripts cover Phases 8–15, 25–30. Phases 17–19 add the Vue dashboard and clinician feedback (Vitest in `vigilcare-dashboard/`).
|
||||
|
||||
| Phase | Feature | Status |
|
||||
|---|---|---|
|
||||
@@ -1550,6 +1619,7 @@ Twenty-four phases from the project roadmap are implemented and verified, includ
|
||||
| 27 | **Sepsis-3 clinical refactor** — SIRS removed (`SirsDetector`, `SirsEvaluator` deleted); qSOFA repositioned as bedside screening (`QSOFA_SCREEN` replaces `QSOFA_WARNING`); sepsis bundle now triggered only by `SOFA_SEPSIS` (delta ≥ 2) via `SepsisAlertHandler`; `AlertCreationGuard` prevents deprecated `SEPSIS_WARNING` creation; legacy alert types retained `[Obsolete]` for historical queries; migration `AddQsofaScreenAlertType`; `SepsisRefactorTests`, `AlertCreationGuardTests`; `run-phase27-verification.sh` | Done |
|
||||
| 28 | **Frontend GCS + SOFA + sepsis UI refactor** — `GcsEntryForm.vue` (bedside GCS component entry); `SofaScorePanel.vue` (organ-system breakdown with staleness indicators); `useGcs` / `useSofa` composables; `scoring` Pinia store; `ScoresPanel` updated with GCS/SOFA display; `SepsisBundlePanel` and `AlertReasoning` refactored for Sepsis-3 alert types; Vitest tests for GCS entry, SOFA panel, scores panel, alert labels; `run-phase28-verification.sh` | Done |
|
||||
| 29 | **Simulator scenario expansion + clinical validation** — three new scenarios (`neurological-decline-gcs-01`, `sepsis-sofa-progression-01`, `sofa-partial-spo2-fallback-01`); existing scenarios enriched with GCS/SOFA observations; `ScenarioReplayHelper` for end-to-end test replay; `ClinicalRefactorEndToEndTests` validates qSOFA screen → SOFA labs → bundle workflow; simulator polls GCS/SOFA scores; `run-phase29-verification.sh` | Done |
|
||||
| 30 | **FHIR R4 Inbound Facade** — `FhirIngestController` (`POST /fhir/R4/{Patient,Encounter,Observation,MedicationAdministration}`); `FhirMetadataController` (CapabilityStatement); `FhirBundleProcessor` (transaction Bundles in dependency order); `LoincCodeMapper` (19 LOINC + 3 SNOMED CT → internal codes); `FhirUnitConverter` (°F→°C); `ExternalResourceIdentifier` table + `ExternalIdentifierService` for hospital MRN/visit number ↔ internal UUID linking; `FhirApiKeyMiddleware` (`X-Api-Key` auth); `FhirExceptionFilter` (→ OperationOutcome); `PatientFhirMapper`, `EncounterFhirMapper`, `ObservationFhirMapper`, `MedicationAdministrationFhirMapper`, `FhirReferenceResolver`; idempotent patient/encounter upserts (`RegisterOrUpdateByIdentifierAsync`, `OpenOrUpdateByIdentifierAsync`); configurable identifier systems, department codes, encounter class maps (`FhirOptions`); Prometheus `fhir_ingest_total`, `fhir_mapping_errors_total`; Mirth Connect integration guide; `FhirIngestTests`; `run-phase30-verification.sh` | Done |
|
||||
|
||||
**Ward dashboard:** backend APIs (`GET /encounters` ward list, `GET /qsofa/current`, CORS) and frontend SPA — `EncountersListTests`, `QsofaCurrentTests`, `vigilcare-dashboard` Vitest suite (replay scrubbing, feedback store, FeedbackButtons, FeedbackSummary, alert components, charts, ward table, GCS entry, SOFA panel, scores panel, alert labels).
|
||||
|
||||
@@ -1557,4 +1627,6 @@ Twenty-four phases from the project roadmap are implemented and verified, includ
|
||||
|
||||
**Sepsis-3 refactor (Phases 27–29):** SIRS removed; qSOFA repositioned as bedside screening (`QSOFA_SCREEN`); SOFA delta ≥ 2 triggers `SOFA_SEPSIS` → sepsis bundle. Frontend gains GCS entry form and SOFA score panel. Eleven simulator scenarios validate the full clinical pipeline end-to-end.
|
||||
|
||||
**FHIR R4 integration (Phase 30):** Inbound facade accepts FHIR R4 JSON from integration engines (Mirth Connect, Rhapsody). Supports per-resource endpoints and transaction Bundles for ADT admit workflows. LOINC/SNOMED code mapping, Fahrenheit conversion, and external identifier linking enable drop-in EHR integration without changing the internal clinical pipeline.
|
||||
|
||||
**Optional follow-up:** execute and document the Kafka replay demonstration for the data lake (reset `data-lake-writer` offsets, clear MinIO prefixes, restart API, confirm Parquet rebuild). See `docs/plans/phase-9-plan.md` § Replay demonstration.
|
||||
|
||||
Reference in New Issue
Block a user