update docs and prep for frontend
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
# Medication Correlation Design Decisions
|
||||
|
||||
**Status:** Implemented (Phase 15). Medication administration CRUD, `MedicationCorrelationHelper`, and integration with `WarningEvaluator` and `News2Detector` are in production. Verification: `./scripts/run-phase15-verification.sh` and `MedicationCorrelationTests`. The simulator scenario `VigilCare.Simulator/Scenarios/List/medication-false-alarm-01.json` exercises the end-to-end flow.
|
||||
|
||||
## The problem this solves
|
||||
|
||||
A patient with a blood pressure of 140/90 receives metoprolol (a beta-blocker that
|
||||
@@ -12,7 +14,7 @@ Clinicians who see these false positives repeatedly stop trusting the alert syst
|
||||
that point, the system is worse than useless — it trains people to ignore alerts,
|
||||
including the real ones.
|
||||
|
||||
Phase 15 solves this by **annotating** alerts with medication context. The alert still
|
||||
Phase 15 addresses this by **annotating** alerts with medication context. The alert still
|
||||
fires (the BP is genuinely low and may need monitoring), but the details say:
|
||||
|
||||
> SYSTOLIC_BP value 95 is below warning low of 90. — note: metoprolol 25mg (PO)
|
||||
@@ -25,7 +27,7 @@ medication is working — keep monitoring."
|
||||
|
||||
## How the pieces fit together
|
||||
|
||||
There are six components in Phase 15. Here is how a request flows through them, starting
|
||||
There are six components. Here is how a request flows through them, starting
|
||||
from when a nurse records a medication and ending when an annotated alert is created.
|
||||
|
||||
```
|
||||
@@ -61,7 +63,7 @@ New observation arrives (e.g. SYSTOLIC_BP = 95)
|
||||
│ 1. Load threshold │ (from Redis cache)
|
||||
│ 2. Check breach │ (is 95 < warningLow of 90?)
|
||||
│ 3. Build details │ ("SYSTOLIC_BP value 95 is below warning low of 90.")
|
||||
│ 4. ► Annotate ◄ │ NEW in Phase 15
|
||||
│ 4. ► Annotate ◄ │ MedicationCorrelationHelper
|
||||
│ 5. INSERT alert │ (idempotent — skips if one already open)
|
||||
└────────┬────────────┘
|
||||
│
|
||||
@@ -163,6 +165,10 @@ Drug names in clinical systems come in all forms — "Metoprolol", "METOPROLOL",
|
||||
lookups, the correlation works regardless of how the nurse typed the drug name. This
|
||||
avoids a class of bugs where correlation silently fails because the case doesn't match.
|
||||
|
||||
The shipped `appsettings.json` includes mappings for common cardiovascular, vasopressor,
|
||||
opioid, sedative, diuretic, and antibiotic agents — not just metoprolol. Add or adjust
|
||||
entries under `MedicationCorrelation:DrugVitalMappings` without a migration.
|
||||
|
||||
---
|
||||
|
||||
### 3. MedicationService
|
||||
@@ -307,7 +313,7 @@ Both `WarningEvaluator` and `News2Detector` already follow a pattern:
|
||||
2. Build a details string describing the breach
|
||||
3. INSERT the alert into the database
|
||||
|
||||
Phase 15 adds one step between 2 and 3:
|
||||
Phase 15 inserts one step between 2 and 3:
|
||||
|
||||
```
|
||||
2. Build details string
|
||||
@@ -315,7 +321,7 @@ Phase 15 adds one step between 2 and 3:
|
||||
3. INSERT the alert (with the possibly-annotated details)
|
||||
```
|
||||
|
||||
This minimal insertion point means no changes to the threshold logic, the idempotent
|
||||
This insertion point required no changes to the threshold logic, the idempotent
|
||||
INSERT pattern, the outbox event publishing, or the alert suppression logic. Each of
|
||||
those systems continues to work exactly as before.
|
||||
|
||||
@@ -384,7 +390,7 @@ pharmaceutical review.
|
||||
|
||||
## Testing strategy
|
||||
|
||||
The tests are structured in three files, each targeting a different layer:
|
||||
Twelve tests across three files cover the medication subsystem:
|
||||
|
||||
**MedicationServiceTests (4 tests)** — tests the service layer directly. Can a medication
|
||||
be created on an active encounter? Does a discharged encounter get rejected? Does
|
||||
@@ -393,14 +399,17 @@ pagination work? Does the time-window filter exclude old records? These tests ca
|
||||
|
||||
**MedicationCorrelationTests (5 tests)** — tests the full integration from medication
|
||||
recording through alert creation. These seed a medication into the database, then invoke
|
||||
`WarningEvaluator.EvaluateAsync` and check whether the resulting alert's `details` field
|
||||
contains the medication annotation. This is the most important test file because it
|
||||
verifies the end-to-end behavior that Phase 15 exists to provide.
|
||||
`WarningEvaluator.EvaluateAsync` (and NEWS2 paths where applicable) and check whether the
|
||||
resulting alert's `details` field contains the medication annotation. This is the most
|
||||
important test file because it verifies the end-to-end behavior the feature exists to provide.
|
||||
|
||||
**MedicationValidationTests (3 tests)** — tests the HTTP validation layer. These send
|
||||
invalid requests via `HttpClient` and assert 400 responses. They don't seed encounters
|
||||
because the validator rejects the request before the service layer runs.
|
||||
|
||||
Run with `dotnet test --filter "FullyQualifiedName~Medication"` or
|
||||
`./scripts/run-phase15-verification.sh` (requires API + Docker Compose).
|
||||
|
||||
All tests run against a real PostgreSQL database and real Redis instance (using test
|
||||
containers on different ports). No mocking. This means the tests catch real issues like
|
||||
SQL translation failures, index problems, and configuration registration mistakes that
|
||||
|
||||
Reference in New Issue
Block a user