Palliative AI Module
A capacity-bounded queue for inpatient palliative-care AI, with dual-role views for the palliative team and primary hospitalist. Portfolio project for clinical-AI product management.
🔗 Live demo: (add Vercel URL after deployment)
📄 Full case study: CASE_STUDY.md — product thinking, key decisions, measurement plan
What is this?
A working prototype of what a clinical-AI deployment for inpatient palliative care looks like after you accept the model prediction as given. The interesting design work isn't the model — it's:
- How much of the prediction do you expose, to whom, and when
- How do you keep a high-risk signal from becoming alert fatigue
- How do you design feedback surfaces that will actually give the next model version better labels
Two user views sit on top of one underlying mortality signal:
- Palliative team → a capacity-bounded queue of the top 12 patients, with full score visibility and Accept / Defer / Dismiss decision flow
- Primary hospitalist → a subtle chart flag on a subset of their census, no score shown, with Request / Dismiss affordances
Both views follow Epic's Storyboard + BPA visual grammar so the prototype reads as a plausible EHR deployment, not a generic dashboard.
Key product decisions
Full reasoning in CASE_STUDY.md. Short version:
| Decision | What it does |
|---|---|
| Top-K capacity bound (not a score threshold) | Matches the palliative team's real daily throughput; makes the "rank 13+ suppressed" tradeoff explicit |
| Asymmetric rendering per role | Palliative sees score, primary doesn't — avoids AI anchoring on the broader user |
| Three-way decision (Accept / Defer / Dismiss) | Separates the capacity signal from the correctness signal |
| Structured chips + "Other" free text | Analyzable labels where we can predict the category, open capture where we can't |
| Inline T+1 feedback (no modal) | Lower friction → higher-quality labels |
| Cross-role signal loop | Human concurrence surfaces above raw AI score in the queue |
Screenshots
See CASE_STUDY.md for the full six-shot visual tour.
Running locally
npm install
npm run dev
Default dev server: http://localhost:5180
Type-check:
npx tsc --noEmit
Production build:
npm run build
npm run preview
Tech stack
- React 19 + TypeScript 6 + Vite 8
- Tailwind CSS v4 (via
@tailwindcss/vite) - lucide-react for iconography
- State is plain React
useState— no Redux, no Zustand. The prototype is small enough that adding a store would obscure the product decisions rather than clarify them.
Project structure
src/
├── App.tsx # Top-level view router (guide / palliative / primary) + state handlers
├── data/
│ └── patients.ts # 27 synthetic patients (12 flagged, 15 census fill)
└── components/
├── Header.tsx # Epic deep-red ribbon + toolbar + role tabs
├── EpicFooter.tsx # Sticky bottom status bar
├── DemoGuide.tsx # Landing page explaining the demo
├── PalliativeTeamView.tsx # Top-12 queue with tier groups
├── PrimaryTeamView.tsx # Dr. Chen's 18-patient census with Palliative column
├── PatientListTable.tsx # Shared table primitives
└── PatientDetail.tsx # Dual-role patient chart (branches on role prop)
Status
✅ Phase 1 — Palliative team queue + decision flow ✅ Phase 2 — Primary team census + asymmetric chart view ✅ Phase 3 — Epic visual language (Storyboard, BPA, right panel, footer) ✅ Phase 4 — Structured reason capture + inline T+1 feedback 🟡 Phase 5 — Portfolio packaging: case study ✓, live deployment (next), screenshots (next)
Author
Lexie Gu — MBBS, PM transitioning into clinical-AI product. This repo is a portfolio artifact; not a deployed product.