feature: Doctor Feedback Mode

This commit is contained in:
voltsrage
2026-06-20 14:32:51 +08:00
parent ebd53f2df6
commit 584d1edd58
17 changed files with 1385 additions and 11 deletions
+312
View File
@@ -0,0 +1,312 @@
# VigilCare Dashboard — User Guide
The **VigilCare Dashboard** (`vigilcare-dashboard/`) is a Vue 3 single-page application that gives clinicians a live view of the virtual ward: who is on the floor, which patients are deteriorating, what alerts need action, and — on the patient detail screen — vital sign trends, NEWS2 history, and plain-language alert reasoning.
It reads from the VigilCare Clinical API over HTTP. It does **not** connect to Kafka, RabbitMQ, or PostgreSQL directly. Polling keeps the UI fresh while the API and background consumers do the clinical work.
---
## Table of Contents
1. [What the dashboard does](#1-what-the-dashboard-does)
2. [Prerequisites](#2-prerequisites)
3. [Quick start](#3-quick-start)
4. [Screens](#4-screens)
5. [Patient detail — clinical review mode](#5-patient-detail--clinical-review-mode)
6. [Working with the simulator](#6-working-with-the-simulator)
7. [Configuration](#7-configuration)
8. [Development](#8-development)
9. [Troubleshooting](#9-troubleshooting)
---
## 1. What the dashboard does
In a real hospital, nurses and physicians need a ward board: acuity at a glance, drill-down into one patient, and a way to act on alerts. This frontend implements that workflow against the VigilCare API.
| Capability | Where in the app | API backing |
|---|---|---|
| Ward overview — active patients sorted by NEWS2 risk | **Virtual Ward** (`/ward`) | `GET /encounters?status=ACTIVE` |
| Department filter | Virtual Ward toolbar | Same list endpoint with `department` |
| Patient drill-down | **Patient Detail** (`/patients/:encounterId`) | `GET /encounters/{id}`, observations, scores, orders |
| Latest vitals snapshot | Patient Detail — Vitals panel | `GET /encounters/{id}/observations` |
| NEWS2 current score | Patient Detail — Scores panel | `GET /encounters/{id}/news2/current` |
| Open alerts per patient | Patient Detail — Active Alerts | `GET /encounters/{id}/alerts` |
| Acknowledge / resolve alerts | Patient Detail or Alert Center | `PATCH /alerts/{id}/acknowledge`, `/resolve` |
| Sepsis bundle status | Patient Detail — Sepsis Bundle panel | `GET /encounters/{id}/sepsis-bundle/current` |
| Clinical orders | Patient Detail — Orders panel | `GET /encounters/{id}/orders` |
| Vital sign trend charts (HR, RR, BP, SpO₂, temp) | Patient Detail — Clinical review section | Observations (Chart.js) |
| NEWS2 score over time | Patient Detail — NEWS2 history chart | `GET /encounters/{id}/news2/history` |
| Alert reasoning (“why did this fire?”) | Patient Detail — click an alert row | Client-side rules + alert `details` |
| Medication context on alerts | Alert reasoning panel | `GET /encounters/{id}/medications` |
| Local replay controls | Patient Detail — replay bar | Scrubs fetched data (not live simulator control) |
| Global alert inbox | **Alert Center** (`/alerts`) | `GET /alerts` with status filter |
| Clinician feedback on alerts | Alert Center, Patient Detail reasoning | Pinia + `localStorage` (client-side) |
| Feedback summary & export | **Feedback Summary** (`/feedback`) | Aggregate stats; export JSON/CSV |
**What it is not:** a full EHR, authentication server, or simulator remote control. Replay controls scrub through data already loaded from the API; they do not pause or speed up the .NET simulator process. Alert feedback is stored in the browser until exported — see [clinical-testing-guide.md](clinical-testing-guide.md) for the clinician workflow.
---
## 2. Prerequisites
- **Node.js 20+** and npm
- **VigilCare Clinical API** running at `http://localhost:5270` (see root [README](../README.md) — Getting Started)
- **CORS:** API `Dashboard` policy must allow the dev origin (`http://localhost:5173` by default)
Optional but recommended for demo data:
- **VigilCare Simulator** — replay a scenario so observations and alerts populate while you watch the dashboard update. See [simulator-guide.md](simulator-guide.md).
---
## 3. Quick start
From the repository root:
```bash
# Terminal 1 — infrastructure + API
docker compose up -d
dotnet run --project VigilCareClinicalAPI
# Terminal 2 — dashboard
cd vigilcare-dashboard
npm install
npm run dev
```
Open **http://localhost:5173**. The app redirects to **Virtual Ward**.
To populate live data, run a simulator scenario in a third terminal:
```bash
dotnet run --project VigilCare.Simulator -- replay \
VigilCare.Simulator/Scenarios/List/uti-sepsis-elderly-01.json \
--speed 60
```
Return to the dashboard, click a patient row, and watch vitals, charts, and alerts update every few seconds.
---
## 4. Screens
### Virtual Ward (`/ward`)
The home screen lists **active encounters** as a responsive table (desktop) or card list (mobile).
- Patients are sorted by **NEWS2 score** (highest risk first).
- A badge shows how many patients have NEWS2 ≥ 7.
- Filter by department: All, ICU, General Medicine, Surgery.
- Click a row to open **Patient Detail**.
Data refreshes every **10 seconds** via polling.
### Alert Center (`/alerts`)
A hospital-wide alert inbox independent of any single patient.
- Filter tabs: **Open**, **Acknowledged**, **Resolved**, **Escalated**.
- Each card shows severity, alert type, details, and triggered time.
- **Ack** opens a confirmation modal (uses clinician ID from settings — default `DR-DEMO`).
- **Resolve** is available after acknowledge.
Use this when you need to triage alerts across the ward without opening each patient first.
### Feedback Summary (`/feedback`)
**Purpose:** Research and evaluation view for structured clinician ratings on alerts.
- Aggregate stats: total ratings, % useful/would act, % false positive, timing issues.
- Breakdown by alert type (sepsis, NEWS2, heart rate warning, etc.).
- Recent feedback entries with notes.
- **Export JSON** / **Export CSV** for study analysis.
Ratings are collected via six buttons on each alert (see [clinical-testing-guide.md](clinical-testing-guide.md) for definitions aimed at doctors and nurses).
### Patient Detail (`/patients/:encounterId`)
The clinical review screen. See [§5](#5-patient-detail--clinical-review-mode) for the full breakdown.
---
## 5. Patient detail — clinical review mode
Layout top to bottom:
```
┌─────────────────────────────────────────────────────────┐
│ ← Ward Patient Name │
├─────────────────────────────────────────────────────────┤
│ Scores (NEWS2) │ Latest Vitals │ Active Alerts │
├─────────────────────────────────────────────────────────┤
│ Alert reasoning panel (after clicking an alert) │
├─────────────────────────────────────────────────────────┤
│ Orders │ Sepsis Bundle (if present) │
├─────────────────────────────────────────────────────────┤
│ Vital sign trend charts (5) │
│ NEWS2 score history chart │
│ Replay controls │
└─────────────────────────────────────────────────────────┘
```
#### Scores panel
Shows the current **NEWS2** total, risk level, and encounter metadata (room/bed, department). If no score has been computed yet, displays `—`.
#### Vitals panel
Latest value per observation code (heart rate, respiratory rate, blood pressure, SpO₂, temperature, etc.), deduplicated to the most recent reading per code.
#### Active alerts
Open alerts for this encounter. Click a row to open the **reasoning panel** below the grid.
- **Ack** / **Resolve** buttons use `@click.stop` so they do not trigger row selection.
- Selected row is highlighted.
#### Alert reasoning
Explains **why** an alert fired in plain language:
| Alert type | Explanation shown |
|---|---|
| `WarningHeartRate`, `WarningSystolicBp`, `WarningTempC` | Threshold range + extracted value from `details` |
| `SepsisWarning` | SIRS criteria summary |
| `QsofaWarning` | qSOFA criteria summary |
| `News2Warning` / `News2Emergency` | NEWS2 risk tier |
| `RapidDeterioration` | Trajectory / rate-of-change |
| Unknown types | Falls back to raw `details` string |
If medications were administered within **90 minutes** before the alert, a **Recent medications** block appears (supports reviewing `medication-false-alarm-01` and similar scenarios).
#### Orders and sepsis bundle
- **Orders** — pending and resulted clinical orders for the encounter.
- **Sepsis bundle** — only rendered when a bundle exists; shows compliance status, deadline, and four treatment elements.
#### Clinical review charts
Five **vital sign trend** line charts (Chart.js via `vue-chartjs`):
- Heart rate, respiratory rate, systolic BP, SpO₂, temperature
- Responsive grid: 1 column (mobile) → 2 (`sm`) → 3 (`xl`)
- Respects `prefers-reduced-motion` (animations disabled when OS setting is on)
**NEWS2 history** chart plots `totalScore` over time with per-point fill colors for risk bands (low / medium / high).
#### Replay controls
Local playback UI for reviewing scenario timelines:
- Pause / resume, speed presets (1×, 60×, 360×, Instant)
- Progress bar and elapsed time display
- **Next Alert →** cycles through open alerts chronologically, selects each for reasoning, and scrolls to the chart section
> Replay state is **client-side only**. It does not send commands to the simulator.
Patient detail data polls every **5 seconds**.
#### Clinician feedback (on alerts)
Below each alert in **Alert Center** and below the **reasoning panel** on Patient Detail:
| Rating | Meaning |
|---|---|
| Useful | Clinically appropriate alert |
| Would act | Would change management based on this alert |
| Too early | Right direction, wrong timing (too soon) |
| Too late | Problem existed; alert came too late |
| False positive | Should not have fired for this context |
| Missing context | Valid concern but insufficient information |
Tap **+ Note** for optional free text. Ratings save automatically in the browser. Export from **Feedback Summary** when the session ends.
---
## 6. Working with the simulator
Typical demo flow:
1. Start API + dashboard (§3).
2. Replay a scenario at moderate speed (`--speed 60`).
3. Open **Virtual Ward** — new or updated encounters appear as the simulator creates them.
4. Click the patient — watch vitals and charts fill in as observations ingest.
5. When alerts fire, click an alert row to read reasoning; try **Next Alert →** on the replay bar.
6. Use **Alert Center** to acknowledge alerts globally.
**Suggested scenarios:**
| Scenario file | What to observe in the dashboard |
|---|---|
| `uti-sepsis-elderly-01.json` | SIRS/qSOFA alerts, sepsis bundle panel, rising acuity |
| `medication-false-alarm-01.json` | HR warnings with medication context in reasoning |
| `news2-deterioration-01.json` (if present) | NEWS2 history chart and score panel |
---
## 7. Configuration
| Setting | Location | Default |
|---|---|---|
| API base URL | `vigilcare-dashboard/.env``VITE_API_URL` | `http://localhost:5270` |
| Clinician ID (acknowledge) | Pinia `settings` store / `localStorage` key `clinicianId` | `DR-DEMO` |
| Dark mode | Header toggle / `localStorage` key `darkMode` | System preference |
| Ward poll interval | `usePolling` in `WardDashboard.vue` | 10 s |
| Patient detail poll | `usePolling` in `PatientDetail.vue` | 5 s |
Example `.env`:
```env
VITE_API_URL=http://localhost:5270
```
---
## 8. Development
```bash
cd vigilcare-dashboard
npm install
npm run dev # http://localhost:5173
npm test # Vitest — composables + component tests
npm run build # production bundle
npm run preview # preview production build
```
**Stack:** Vue 3 (`<script setup>`), Vue Router, Pinia, Tailwind CSS v4, Chart.js + vue-chartjs.
**Key directories:**
```
vigilcare-dashboard/src/
├── api/ # HTTP client + encounter/clinical/alert fetchers
├── components/
│ ├── charts/ # VitalChart, TrendsGrid, News2History
│ ├── replay/ # ReplayControls
│ ├── alerts/ # AlertReasoning, AlertCard, …
│ ├── patient/ # VitalsPanel, ScoresPanel, AlertsList, …
│ └── ward/ # WardTable, PatientRow, PatientCard
├── composables/ # useChartData, useReplayControls, usePolling, chartFormat
├── stores/ # ward, alerts, settings (Pinia)
└── views/ # WardDashboard, PatientDetail, AlertCenter
```
Implementation plans: `docs/plans/phase-17-plan.md` (ward shell + detail), `docs/plans/phase-18-plan.md` (charts, replay, reasoning), `docs/plans/phase-19-plan.md` (clinician feedback).
**Clinician testing:** [clinical-testing-guide.md](clinical-testing-guide.md) — step-by-step guide for doctors and nurses participating in evaluation sessions.
---
## 9. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Blank ward / network errors in console | API not running or wrong URL | Start API; check `VITE_API_URL` |
| CORS error in browser | Dashboard origin not allowed | Add origin to API `DashboardOptions` in `appsettings.json` |
| Charts crash on mount | Chart data not unwrapped | Ensure `VitalTrendChart` wrapper is used (see `TrendsGrid.vue`) |
| No patients listed | No active encounters | Run simulator or use seeded API data |
| NEWS2 chart empty | Scores not computed yet | Wait for Kafka `news2-scoring` consumer after observations ingest |
| Acknowledge fails 400 | Invalid clinician ID | Set `clinicianId` in localStorage or settings store |
For API and infrastructure issues, see the root [README](../README.md) and [docker-compose-usage-and-troubleshooting.md](docker-compose-usage-and-troubleshooting.md).