redesigdn docs
This commit is contained in:
512
docs/swift/archive/nextgen-epd-mvp-prioritering-ephemeral-ui.md
Normal file
512
docs/swift/archive/nextgen-epd-mvp-prioritering-ephemeral-ui.md
Normal file
@@ -0,0 +1,512 @@
|
||||
# MVP & Prioritering Ephemeral UI EPD
|
||||
|
||||
**Document:** MVP Scope en Implementatie Prioritering
|
||||
**Datum:** december 2024
|
||||
**Status:** Definitief
|
||||
|
||||
---
|
||||
|
||||
## 1. MVP Definitie
|
||||
|
||||
### 1.1 Eén Zin
|
||||
|
||||
> **MVP = Een Command Center waarmee je met tekst of voice een dagnotitie of rapportage maakt, met automatische patient herkenning.**
|
||||
|
||||
### 1.2 MVP Scope
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ MVP SCOPE │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ IN SCOPE (Must Have) │
|
||||
│ ───────────────────── │
|
||||
│ ✓ Command Center pagina │
|
||||
│ ✓ Text input met intent herkenning │
|
||||
│ ✓ Voice input (Deepgram - bestaat al) │
|
||||
│ ✓ Dagnotitie blok │
|
||||
│ ✓ Zoeken blok │
|
||||
│ ✓ Patient pre-fill uit input │
|
||||
│ ✓ Fallback blok-picker │
|
||||
│ │
|
||||
│ SHOULD HAVE (Demo Enhanced) │
|
||||
│ ─────────────────────────── │
|
||||
│ ○ Rapportage blok │
|
||||
│ ○ Overdracht blok met AI │
|
||||
│ ○ Recent actions tracking │
|
||||
│ ○ Context bar (dienst info) │
|
||||
│ │
|
||||
│ OUT OF SCOPE (v1) │
|
||||
│ ───────────────── │
|
||||
│ ✗ Behandelplan blok │
|
||||
│ ✗ Intake blok │
|
||||
│ ✗ Agenda blok │
|
||||
│ ✗ Metingen blok │
|
||||
│ ✗ Ambient listening │
|
||||
│ ✗ Multi-user realtime │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1.3 Waarom Deze Scope?
|
||||
|
||||
| Keuze | Rationale |
|
||||
|-------|-----------|
|
||||
| Dagnotitie eerst | Hoogste frequentie (20x/dag), simpelste form |
|
||||
| Zoeken als fundament | Elke actie begint met "wie" - zonder zoeken geen pre-fill |
|
||||
| Voice must-have | "Ik draag handschoenen" - zorg context vereist hands-free |
|
||||
| Fallback verplicht | Vertrouwen: nooit een doodlopende straat |
|
||||
| Geen behandelplan | Te complex, lage frequentie, bestaande UI voldoet |
|
||||
|
||||
---
|
||||
|
||||
## 2. Hergebruik Bestaande Code
|
||||
|
||||
### 2.1 Direct Herbruikbaar
|
||||
|
||||
| Component | Locatie | Hergebruik |
|
||||
|-----------|---------|------------|
|
||||
| **Speech Recorder** | `components/speech-recorder.tsx` | 100% - drop-in |
|
||||
| **Deepgram API** | `api/deepgram/transcribe/route.ts` | 100% - werkt |
|
||||
| **Toast System** | `lib/hooks/use-toast.ts` | 100% - feedback |
|
||||
| **Command (cmdk)** | `components/ui/command.tsx` | 90% - zoek basis |
|
||||
| **Dagregistratie Form** | `app/epd/dagregistratie/` | 80% - wrap als blok |
|
||||
| **Report Types** | `lib/types/report.ts` | 100% - validatie |
|
||||
| **Verpleegkundig API** | `api/reports/route.ts` | 100% - save |
|
||||
|
||||
### 2.2 Gedeeltelijk Herbruikbaar
|
||||
|
||||
| Component | Locatie | Aanpassing Nodig |
|
||||
|-----------|---------|------------------|
|
||||
| **Patient List** | `app/epd/verpleegrapportage/` | → PatientCard voor zoeken |
|
||||
| **EPD Layout** | `app/epd/layout.tsx` | → Command Center layout |
|
||||
| **Report Composer** | `app/epd/patients/[id]/rapportage/` | → RapportageBlock wrapper |
|
||||
|
||||
### 2.3 Nieuw te Bouwen
|
||||
|
||||
| Component | Geschatte Effort | Prioriteit |
|
||||
|-----------|------------------|------------|
|
||||
| `/app/command-center/page.tsx` | 4h | P1 |
|
||||
| `/api/intent/classify/route.ts` | 6h | P1 |
|
||||
| `CommandInput.tsx` | 3h | P1 |
|
||||
| `BlockContainer.tsx` | 2h | P1 |
|
||||
| `DagnotitieBlock.tsx` | 3h | P1 |
|
||||
| `ZoekenBlock.tsx` | 4h | P1 |
|
||||
| `FallbackPicker.tsx` | 2h | P1 |
|
||||
| `PatientResolver.ts` | 2h | P1 |
|
||||
| `useCommandCenter.ts` (store) | 3h | P1 |
|
||||
| **Totaal MVP** | **~29h** | - |
|
||||
|
||||
---
|
||||
|
||||
## 3. Prioritering: MoSCoW
|
||||
|
||||
### 3.1 Must Have (Release Blocker)
|
||||
|
||||
```
|
||||
M1. Command Center Layout
|
||||
└── Centrale pagina met input field
|
||||
└── Route: /command-center
|
||||
|
||||
M2. Intent Classification
|
||||
└── API endpoint dat input analyseert
|
||||
└── Returns: { intent, entities, confidence }
|
||||
|
||||
M3. Dagnotitie Blok
|
||||
└── Simpele form: patient, categorie, tekst
|
||||
└── Pre-fill support
|
||||
└── 1-click save
|
||||
|
||||
M4. Zoeken Blok
|
||||
└── Patient search met cmdk
|
||||
└── PatientCard met quick actions
|
||||
└── Set active patient
|
||||
|
||||
M5. Voice Input
|
||||
└── Deepgram integratie in Command input
|
||||
└── Live transcript display
|
||||
|
||||
M6. Fallback Picker
|
||||
└── Grid met blok icons
|
||||
└── Toont bij lage confidence of onbekende intent
|
||||
|
||||
M7. Patient Pre-fill
|
||||
└── Entity extraction uit input
|
||||
└── Patient name → ID resolver
|
||||
```
|
||||
|
||||
### 3.2 Should Have (Demo Value)
|
||||
|
||||
```
|
||||
S1. Rapportage Blok
|
||||
└── Wrapper rond bestaande ReportComposer
|
||||
└── Voice dictation in editor
|
||||
└── AI structurering knop
|
||||
|
||||
S2. Overdracht Blok
|
||||
└── AI samenvatting (API bestaat)
|
||||
└── Multi-patient view
|
||||
└── Bronverwijzingen
|
||||
|
||||
S3. Recent Actions
|
||||
└── Badge strip onder input
|
||||
└── Click to re-open
|
||||
|
||||
S4. Context Bar
|
||||
└── "Ochtend dienst | 8 patiënten"
|
||||
└── Shift awareness
|
||||
```
|
||||
|
||||
### 3.3 Could Have (Nice to Have)
|
||||
|
||||
```
|
||||
C1. Categorie Herkenning
|
||||
└── "medicatie" → Medicatie category
|
||||
└── Keyword mapping
|
||||
|
||||
C2. Animaties
|
||||
└── Block slide-in
|
||||
└── Pre-fill highlight
|
||||
└── Success celebration
|
||||
|
||||
C3. Keyboard Shortcuts
|
||||
└── Cmd+K → focus input
|
||||
└── Enter → submit
|
||||
└── Esc → close block
|
||||
|
||||
C4. Onboarding Hints
|
||||
└── "Probeer: notitie jan"
|
||||
└── First-time user guidance
|
||||
```
|
||||
|
||||
### 3.4 Won't Have (Explicit Out)
|
||||
|
||||
```
|
||||
W1. Behandelplan Blok - te complex, lage frequentie
|
||||
W2. Intake Blok - wizard is complex, 1x/maand
|
||||
W3. Agenda Blok - bestaande werkt, lage urgentie
|
||||
W4. Metingen Blok - lage waarde-perceptie
|
||||
W5. Ambient Listening - v2+ feature
|
||||
W6. Offline Mode - v2+ feature
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Implementatie Volgorde
|
||||
|
||||
### 4.1 Dependency Graph
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ Command Center │
|
||||
│ Layout │
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌──────────────┼──────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ Voice │ │ Intent │ │ Fallback │
|
||||
│ Input │ │ API │ │ Picker │
|
||||
└────┬─────┘ └────┬─────┘ └──────────┘
|
||||
│ │
|
||||
│ ┌───────┴───────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ Zoeken │ │ Dagnotitie │
|
||||
│ Blok │ │ Blok │
|
||||
└──────┬───────┘ └──────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ Pre-fill │
|
||||
│ Logic │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
### 4.2 Sprint Planning
|
||||
|
||||
#### Sprint 1: Foundation (Dag 1-3)
|
||||
|
||||
| # | Taak | Afhankelijk van | Output |
|
||||
|---|------|-----------------|--------|
|
||||
| 1.1 | Command Center page layout | - | `/app/command-center/page.tsx` |
|
||||
| 1.2 | CommandInput component | 1.1 | Text input met submit |
|
||||
| 1.3 | BlockContainer wrapper | 1.1 | Generic block frame |
|
||||
| 1.4 | Zustand store setup | - | `useCommandCenter` hook |
|
||||
| 1.5 | Voice integratie | 1.2 | Mic button in input |
|
||||
|
||||
**Deliverable:** Command Center opent, voice werkt, geen blokken nog.
|
||||
|
||||
#### Sprint 2: Intent & Zoeken (Dag 4-6)
|
||||
|
||||
| # | Taak | Afhankelijk van | Output |
|
||||
|---|------|-----------------|--------|
|
||||
| 2.1 | Intent API route | - | `/api/intent/classify` |
|
||||
| 2.2 | Entity extraction | 2.1 | Patient name uit tekst |
|
||||
| 2.3 | Patient search API | - | `/api/patients/search` |
|
||||
| 2.4 | ZoekenBlock | 1.3, 2.3 | Patient cards + select |
|
||||
| 2.5 | Fallback picker | 1.3 | Grid met blok icons |
|
||||
|
||||
**Deliverable:** "zoek jan" werkt, patient selectie mogelijk.
|
||||
|
||||
#### Sprint 3: Dagnotitie Flow (Dag 7-9)
|
||||
|
||||
| # | Taak | Afhankelijk van | Output |
|
||||
|---|------|-----------------|--------|
|
||||
| 3.1 | DagnotitieBlock | 1.3 | Quick entry form |
|
||||
| 3.2 | Pre-fill logic | 2.2, 3.1 | Patient + categorie auto |
|
||||
| 3.3 | Save flow | 3.1 | Toast + recent badge |
|
||||
| 3.4 | Intent → Block routing | 2.1, 3.1 | "notitie jan" → block |
|
||||
|
||||
**Deliverable:** "notitie voor jan: medicatie gegeven" werkt end-to-end.
|
||||
|
||||
#### Sprint 4: Polish & Demo (Dag 10-12)
|
||||
|
||||
| # | Taak | Afhankelijk van | Output |
|
||||
|---|------|-----------------|--------|
|
||||
| 4.1 | RapportageBlock | 1.3 | Wrapper rond composer |
|
||||
| 4.2 | Recent actions strip | 3.3 | Clickable badges |
|
||||
| 4.3 | Animaties | All | Smooth transitions |
|
||||
| 4.4 | Demo scenarios | All | 3 happy paths |
|
||||
| 4.5 | Bug fixes | All | Stability |
|
||||
|
||||
**Deliverable:** Demo-ready voor stakeholders.
|
||||
|
||||
---
|
||||
|
||||
## 5. Technische Beslissingen
|
||||
|
||||
### 5.1 State Management
|
||||
|
||||
**Besluit:** Zustand
|
||||
|
||||
```typescript
|
||||
// stores/command-center.ts
|
||||
interface CommandCenterState {
|
||||
// Active state
|
||||
activeBlock: 'dagnotitie' | 'zoeken' | 'rapportage' | 'overdracht' | null
|
||||
activePatient: Patient | null
|
||||
|
||||
// Input state
|
||||
inputValue: string
|
||||
isListening: boolean
|
||||
transcript: string
|
||||
|
||||
// Pre-fill data
|
||||
prefillData: {
|
||||
patientName?: string
|
||||
category?: string
|
||||
text?: string
|
||||
}
|
||||
|
||||
// History
|
||||
recentActions: Action[]
|
||||
|
||||
// Actions
|
||||
processInput: (text: string) => Promise<void>
|
||||
openBlock: (type: BlockType, prefill?: object) => void
|
||||
closeBlock: () => void
|
||||
setActivePatient: (patient: Patient) => void
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 Intent Classification
|
||||
|
||||
**Besluit:** Two-tier approach
|
||||
|
||||
```typescript
|
||||
// Tier 1: Local keyword matching (instant)
|
||||
const quickMatch = (input: string) => {
|
||||
if (/notitie|dagnotitie/i.test(input)) return { intent: 'dagnotitie', confidence: 0.9 }
|
||||
if (/zoek|vind|wie is/i.test(input)) return { intent: 'zoeken', confidence: 0.9 }
|
||||
if (/overdracht|dienst/i.test(input)) return { intent: 'overdracht', confidence: 0.9 }
|
||||
if (/rapport|gesprek/i.test(input)) return { intent: 'rapportage', confidence: 0.85 }
|
||||
return null
|
||||
}
|
||||
|
||||
// Tier 2: Claude API (fallback)
|
||||
const aiClassify = async (input: string) => {
|
||||
// Only called if quickMatch returns null or low confidence
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 Patient Resolution
|
||||
|
||||
**Besluit:** Fuzzy search met Supabase
|
||||
|
||||
```typescript
|
||||
// Fuzzy match op naam
|
||||
const searchPatients = async (query: string) => {
|
||||
const { data } = await supabase
|
||||
.from('patients')
|
||||
.select('id, name, birth_date')
|
||||
.ilike('name', `%${query}%`)
|
||||
.limit(5)
|
||||
return data
|
||||
}
|
||||
|
||||
// Als 1 match → auto-select
|
||||
// Als >1 match → toon ZoekenBlock
|
||||
// Als 0 matches → "Geen patient gevonden"
|
||||
```
|
||||
|
||||
### 5.4 Block Architecture
|
||||
|
||||
**Besluit:** Wrapper pattern
|
||||
|
||||
```typescript
|
||||
// Elk blok krijgt dezelfde interface
|
||||
interface BlockProps {
|
||||
prefill?: Record<string, unknown>
|
||||
onComplete: (result: unknown) => void
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
// BlockContainer handelt header, minimize, close
|
||||
<BlockContainer title="Dagnotitie" icon={FileText}>
|
||||
<DagnotitieBlock prefill={prefill} onComplete={handleComplete} />
|
||||
</BlockContainer>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Risico's & Mitigaties
|
||||
|
||||
| Risico | Kans | Impact | Mitigatie |
|
||||
|--------|------|--------|-----------|
|
||||
| Intent accuracy <80% | Medium | Hoog | Fallback picker altijd zichtbaar |
|
||||
| Voice niet goed in NL | Laag | Medium | Deepgram NL model + tekst fallback |
|
||||
| Pre-fill verkeerde patient | Medium | Hoog | Altijd confirmation, nooit blind save |
|
||||
| Latency AI calls | Medium | Medium | Local-first matching, AI als backup |
|
||||
| Demo deadline druk | Medium | Hoog | Scope strict houden, no feature creep |
|
||||
|
||||
---
|
||||
|
||||
## 7. Success Metrics
|
||||
|
||||
### 7.1 MVP Success (Must Hit)
|
||||
|
||||
| Metric | Target | Hoe Meten |
|
||||
|--------|--------|-----------|
|
||||
| "notitie jan" → save | <30 sec | Timestamp logs |
|
||||
| Intent accuracy | >85% | Correct block / total |
|
||||
| Voice transcription | >90% accuracy | Manual review sample |
|
||||
| Fallback usage | <25% | Picker clicks / total |
|
||||
|
||||
### 7.2 Demo Success
|
||||
|
||||
| Metric | Target |
|
||||
|--------|--------|
|
||||
| 3 scenario's foutloos | 100% |
|
||||
| Stakeholder "wow" moment | Ja |
|
||||
| Concrete vervolgafspraak | Ja |
|
||||
|
||||
---
|
||||
|
||||
## 8. Definition of Done
|
||||
|
||||
### 8.1 Per Sprint
|
||||
|
||||
- [ ] Alle taken in sprint completed
|
||||
- [ ] Geen console errors
|
||||
- [ ] Happy path werkt
|
||||
- [ ] Code reviewed
|
||||
|
||||
### 8.2 MVP Done
|
||||
|
||||
- [ ] Command Center bereikbaar op `/command-center`
|
||||
- [ ] Voice input werkt
|
||||
- [ ] "notitie voor [patient]" opent DagnotitieBlock
|
||||
- [ ] "zoek [naam]" toont PatientCards
|
||||
- [ ] Pre-fill werkt voor patient naam
|
||||
- [ ] Fallback picker werkt
|
||||
- [ ] Save + toast feedback werkt
|
||||
- [ ] Geen blocking bugs
|
||||
- [ ] 3 demo scenario's gedocumenteerd
|
||||
|
||||
---
|
||||
|
||||
## 9. Demo Scenario's
|
||||
|
||||
### Scenario 1: Snelle Dagnotitie (30 sec)
|
||||
|
||||
```
|
||||
1. Open Command Center
|
||||
2. Type of spreek: "notitie voor Jan de Vries: medicatie uitgereikt"
|
||||
3. System:
|
||||
- Herkent intent: dagnotitie
|
||||
- Herkent patient: Jan de Vries
|
||||
- Pre-fills categorie: Medicatie
|
||||
- Pre-fills tekst: "medicatie uitgereikt"
|
||||
4. User: Review → Opslaan
|
||||
5. Toast: "Notitie opgeslagen"
|
||||
6. Recent badge verschijnt
|
||||
```
|
||||
|
||||
### Scenario 2: Patient Zoeken + Notitie (45 sec)
|
||||
|
||||
```
|
||||
1. Type: "notitie marie"
|
||||
2. System: Meerdere "Marie" gevonden
|
||||
3. Toont: ZoekenBlock met 3 matches
|
||||
4. User: Selecteert "Marie van den Berg"
|
||||
5. System: Opent DagnotitieBlock met patient ingevuld
|
||||
6. User: Typt notitie → Opslaan
|
||||
```
|
||||
|
||||
### Scenario 3: Voice Flow (40 sec)
|
||||
|
||||
```
|
||||
1. Klik mic button
|
||||
2. Spreek: "Mevrouw Jansen heeft goed gegeten en haar medicatie ingenomen"
|
||||
3. System:
|
||||
- Transcribeert real-time
|
||||
- Herkent: patient = Jansen, categorie = ADL + Medicatie
|
||||
4. Toont: DagnotitieBlock met alles ingevuld
|
||||
5. User: Review → Opslaan
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Appendix: File Structure
|
||||
|
||||
```
|
||||
app/
|
||||
├── command-center/
|
||||
│ ├── page.tsx # Main Command Center
|
||||
│ └── components/
|
||||
│ ├── command-input.tsx # Text + voice input
|
||||
│ ├── voice-indicator.tsx # Listening state UI
|
||||
│ ├── block-container.tsx # Generic block wrapper
|
||||
│ ├── fallback-picker.tsx # Block selection grid
|
||||
│ └── recent-actions.tsx # Recent badges strip
|
||||
|
||||
├── api/
|
||||
│ └── intent/
|
||||
│ └── classify/
|
||||
│ └── route.ts # Intent classification API
|
||||
|
||||
components/
|
||||
└── building-blocks/
|
||||
├── dagnotitie-block.tsx # Quick entry form
|
||||
├── zoeken-block.tsx # Patient search
|
||||
├── rapportage-block.tsx # Report composer wrapper
|
||||
└── overdracht-block.tsx # Handover summary
|
||||
|
||||
stores/
|
||||
└── command-center.ts # Zustand store
|
||||
|
||||
lib/
|
||||
├── intent/
|
||||
│ ├── classifier.ts # Intent classification logic
|
||||
│ ├── entity-extractor.ts # Extract patient, category
|
||||
│ └── patient-resolver.ts # Name → Patient lookup
|
||||
└── types/
|
||||
└── command-center.ts # TypeScript types
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*Dit document is de single source of truth voor MVP scope en prioritering.*
|
||||
Reference in New Issue
Block a user