feature: Doctor Feedback Mode
This commit is contained in:
@@ -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).
|
||||
Reference in New Issue
Block a user