From 4b458538688e06f3492ff18ba292ceb3852076a9 Mon Sep 17 00:00:00 2001 From: colinislit Date: Sat, 3 Jan 2026 11:41:26 +0100 Subject: [PATCH] chore(docs): remove duplicate swift docs (moved to docs/archive/swift) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove 39 swift documentation files that were duplicated. Original files are preserved in docs/archive/swift/. πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../archive/PROJECT-STATUS-2024-12-27.md | 294 --- docs/swift/archive/bouwplan-swift-v1.md | 554 ----- docs/swift/archive/bouwplan-swift-v2.md | 971 --------- .../archive/keyboard-shortcuts-reference.md | 173 -- ...-epd-analyse-ephemeral-ui-perspectieven.md | 675 ------ .../archive/nextgen-epd-claude-vision-epd.txt | 217 -- ...xtgen-epd-mvp-prioritering-ephemeral-ui.md | 512 ----- ...en-epd-onderzoeksverslag-ux-ui-patterns.md | 430 ---- .../nextgen-epd-prd-ephemeral-ui-epd.md | 607 ------ ...nextgen-epd-waarde-analyse-ephemeral-ui.md | 551 ----- docs/swift/archive/swift-fo-ai.md | 987 --------- .../archive/swift-fo-diagnostiek-workflow.md | 725 ------- docs/swift/archive/swift-prd.md | 632 ------ .../archive/swift-ux-diagnostiek-workflow.md | 829 -------- docs/swift/archive/swift-ux-v2.1.md | 1070 ---------- docs/swift/archive/taken-en-vragen-analyse.md | 486 ----- .../archive/test-plan-e5-s2-error-handling.md | 232 --- .../test-plan-e5-s3-keyboard-shortcuts.md | 245 --- docs/swift/archive/test-plan-epic3.md | 272 --- docs/swift/archive/to-swift-v1.md | 1257 ------------ docs/swift/bouwplan-swift-agenda-planning.md | 757 ------- ...-swift-diagnostiek-workflow-beoordeling.md | 700 ------- .../bouwplan-swift-diagnostiek-workflow.md | 458 ----- .../swift/bouwplan-swift-standalone-module.md | 215 -- docs/swift/bouwplan-swift-v3.md | 1779 ---------------- docs/swift/competitive-analysis.md | 774 ------- docs/swift/developer-guide-intent-system.md | 1334 ------------ docs/swift/e0-design-tokens-and-components.md | 426 ---- docs/swift/e0-medical-scribe-system-prompt.md | 518 ----- docs/swift/fo-agenda-afspraken.md | 581 ------ docs/swift/fo-swift-agenda-planning.md | 1816 ----------------- docs/swift/fo-swift-medical-scribe-v3.md | 742 ------- docs/swift/haalbaarheidsanalyse-v3.md | 437 ---- .../implementation-e5-s1-action-routing.md | 224 -- .../swift/implementation-e5-s2-chat-prompt.md | 325 --- .../implementation-e5-s3-error-states.md | 399 ---- docs/swift/review-epic2.md | 34 - docs/swift/test-plan-epic3-backend.md | 474 ----- docs/swift/v3-redesign-met-huidige-styling.md | 666 ------ 39 files changed, 24378 deletions(-) delete mode 100644 docs/swift/archive/PROJECT-STATUS-2024-12-27.md delete mode 100644 docs/swift/archive/bouwplan-swift-v1.md delete mode 100644 docs/swift/archive/bouwplan-swift-v2.md delete mode 100644 docs/swift/archive/keyboard-shortcuts-reference.md delete mode 100644 docs/swift/archive/nextgen-epd-analyse-ephemeral-ui-perspectieven.md delete mode 100644 docs/swift/archive/nextgen-epd-claude-vision-epd.txt delete mode 100644 docs/swift/archive/nextgen-epd-mvp-prioritering-ephemeral-ui.md delete mode 100644 docs/swift/archive/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md delete mode 100644 docs/swift/archive/nextgen-epd-prd-ephemeral-ui-epd.md delete mode 100644 docs/swift/archive/nextgen-epd-waarde-analyse-ephemeral-ui.md delete mode 100644 docs/swift/archive/swift-fo-ai.md delete mode 100644 docs/swift/archive/swift-fo-diagnostiek-workflow.md delete mode 100644 docs/swift/archive/swift-prd.md delete mode 100644 docs/swift/archive/swift-ux-diagnostiek-workflow.md delete mode 100644 docs/swift/archive/swift-ux-v2.1.md delete mode 100644 docs/swift/archive/taken-en-vragen-analyse.md delete mode 100644 docs/swift/archive/test-plan-e5-s2-error-handling.md delete mode 100644 docs/swift/archive/test-plan-e5-s3-keyboard-shortcuts.md delete mode 100644 docs/swift/archive/test-plan-epic3.md delete mode 100644 docs/swift/archive/to-swift-v1.md delete mode 100644 docs/swift/bouwplan-swift-agenda-planning.md delete mode 100644 docs/swift/bouwplan-swift-diagnostiek-workflow-beoordeling.md delete mode 100644 docs/swift/bouwplan-swift-diagnostiek-workflow.md delete mode 100644 docs/swift/bouwplan-swift-standalone-module.md delete mode 100644 docs/swift/bouwplan-swift-v3.md delete mode 100644 docs/swift/competitive-analysis.md delete mode 100644 docs/swift/developer-guide-intent-system.md delete mode 100644 docs/swift/e0-design-tokens-and-components.md delete mode 100644 docs/swift/e0-medical-scribe-system-prompt.md delete mode 100644 docs/swift/fo-agenda-afspraken.md delete mode 100644 docs/swift/fo-swift-agenda-planning.md delete mode 100644 docs/swift/fo-swift-medical-scribe-v3.md delete mode 100644 docs/swift/haalbaarheidsanalyse-v3.md delete mode 100644 docs/swift/implementation-e5-s1-action-routing.md delete mode 100644 docs/swift/implementation-e5-s2-chat-prompt.md delete mode 100644 docs/swift/implementation-e5-s3-error-states.md delete mode 100644 docs/swift/review-epic2.md delete mode 100644 docs/swift/test-plan-epic3-backend.md delete mode 100644 docs/swift/v3-redesign-met-huidige-styling.md diff --git a/docs/swift/archive/PROJECT-STATUS-2024-12-27.md b/docs/swift/archive/PROJECT-STATUS-2024-12-27.md deleted file mode 100644 index 9fc8169..0000000 --- a/docs/swift/archive/PROJECT-STATUS-2024-12-27.md +++ /dev/null @@ -1,294 +0,0 @@ -# Swift Project Status Report -**Datum:** 27 december 2024 -**Versie:** v2.5 -**Status:** 🎯 **86% Complete** - MVP binnen handbereik! - ---- - -## πŸ“Š Executive Summary - -| Metric | Waarde | Visualisatie | -|--------|--------|--------------| -| **Voortgang** | 86% | β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘ | -| **Story Points** | 62 / 72 SP | +2 SP vandaag | -| **Stories Compleet** | 27 / 29 | 93% | -| **Epics Compleet** | 4.75 / 5 | Alle major epics done βœ… | -| **Remaining Work** | 2 SP (1 story) | E5.S4 alleen | -| **Target MVP** | 72 SP | 1-2 uur tot compleet | - -**Conclusie:** Project loopt uitstekend! Alle kernfunctionaliteit is af. Alleen smoke tests nog te doen. - ---- - -## 🎯 Vandaag Afgerond (27-12-2024) - -### βœ… E5.S2 - Error Handling (2 SP) -**Implementatie:** -- `lib/swift/error-handler.ts` (301 regels) - Gecentraliseerde error handling -- `components/swift/command-center/offline-banner.tsx` - Offline detection -- Alle blocks + CommandInput gebruiken nieuwe error handler -- User-friendly Nederlandse error messages voor alle HTTP codes (401, 404, 500, etc.) -- Retry logic met exponential backoff (max 3 retries) -- 30s timeout op alle API calls - -**Impact:** Robuste error handling door hele app. Users krijgen duidelijke feedback bij problemen. - -### βœ… E5.S3 - Keyboard Shortcuts (2 SP) -**Implementatie:** -- ⌘Enter / Ctrl+Enter quick submit in CommandInput -- ⌘Enter / Ctrl+Enter quick save in DagnotatieBlock -- Visual hints (βŒ˜β†΅) op buttons -- Geverifieerd: ⌘K, Escape, 1-3 number keys - -**Documentatie:** -- `docs/swift/keyboard-shortcuts-reference.md` (200+ regels) -- `docs/swift/test-plan-e5-s3-keyboard-shortcuts.md` (350+ regels) - -**Impact:** Power users kunnen nu razendsnel werken zonder muis. - ---- - -## πŸ“ˆ Epic Status Overview - -| Epic | Omschrijving | Stories | SP | Status | % | -|------|--------------|---------|----:|--------|---:| -| **E0** | Setup & Foundation | 4/4 | 8/8 | βœ… **DONE** | 100% | -| **E1** | Command Center | 5/5 | 13/13 | βœ… **DONE** | 100% | -| **E2** | Intent Classification | 5/5 | 12/12 | βœ… **DONE** | 100% | -| **E3** | P1 Blocks | 7/7 | 23/23 | βœ… **DONE** | 100% | -| **E4** | Navigation & Auth | 4/4 | 8/8 | βœ… **DONE** | 100% | -| **E5** | Polish & Testing | 3/4 | 6/8 | πŸ”„ **IN PROGRESS** | 75% | - -### E5 - Polish & Testing Breakdown: -- βœ… E5.S1 - Block animaties (2 SP) - DONE 24-12-2024 -- βœ… E5.S2 - Error handling (2 SP) - **DONE 27-12-2024** πŸŽ‰ -- βœ… E5.S3 - Keyboard shortcuts (2 SP) - **DONE 27-12-2024** πŸŽ‰ -- ⏳ E5.S4 - Smoke tests (2 SP) - TO DO (1-2 uur) - ---- - -## πŸš€ GeΓ―mplementeerde Features - -### Core Functionaliteit (E0-E3) -- βœ… Command Center met 4-zone layout -- βœ… Voice input met Deepgram streaming + waveform -- βœ… Two-tier intent classification (local + AI fallback) -- βœ… DagnotatieBlock - patient selectie, 5 categorieΓ«n, save to API -- βœ… ZoekenBlock - fuzzy search, patient selection -- βœ… OverdrachtBlock - AI samenvattingen per patiΓ«nt, period selector -- βœ… PatientContextCard - auto-display na selectie, context view - -### Navigation & Auth (E4) -- βœ… Login met interface preference selector -- βœ… Routing naar Swift/Klassiek EPD -- βœ… User metadata storage -- βœ… FallbackPicker voor onbekende intents - -### Polish & UX (E5) -- βœ… Block animaties - slide up/down, 200ms transitions -- βœ… Error handling - offline banner, retry logic, NL messages -- βœ… Keyboard shortcuts - ⌘K, Escape, ⌘Enter, 1-3 -- βœ… Loading states, toasts, validation errors -- βœ… Responsive design (mobile + desktop) - ---- - -## πŸ“ Code Quality Metrics - -### Lines of Code -| Category | Files | LOC (approx) | -|----------|-------|-------------:| -| Components | 12 | ~2,500 | -| Utilities | 5 | ~800 | -| Stores | 1 | ~170 | -| API Routes | 4 | ~600 | -| **Total** | **22+** | **~4,000+** | - -### Test Coverage (E5.S4 nog te doen) -- ⏳ Unit tests - Intent classifier -- ⏳ Integration tests - API routes -- ⏳ Component tests - Blocks -- ⏳ E2E tests - Smoke tests - -### Documentation -| Document | Status | Lines | -|----------|--------|------:| -| Bouwplan v2.5 | βœ… Up-to-date | 950+ | -| Keyboard Shortcuts Reference | βœ… Complete | 200+ | -| Error Handling Test Plan | βœ… Complete | 350+ | -| Keyboard Shortcuts Test Plan | βœ… Complete | 350+ | -| Test Plan Epic 3 | βœ… Complete | 270+ | -| **Total Documentation** | | **2,000+** | - ---- - -## 🎯 Manual Test Status - -**17/20 test scenarios passed** (85%) - -### Happy Flows (10/10) βœ… -- βœ… Login + Swift interface selector -- βœ… ⌘K focus input -- βœ… ⌘Enter quick submit -- βœ… "notitie jan medicatie" β†’ DagnotatieBlock -- βœ… Dagnotitie save + toast -- βœ… ⌘Enter quick save in block -- βœ… "zoek marie" β†’ ZoekenBlock -- βœ… Patient selectie β†’ PatientContextCard -- βœ… "overdracht" β†’ AI samenvatting -- βœ… Voice input β†’ transcript - -### Error Scenarios (5/5) βœ… -- βœ… Onbekende intent β†’ FallbackPicker -- βœ… Offline mode β†’ banner + error -- βœ… Network error β†’ retry toast -- βœ… Validation errors β†’ duidelijke messages -- βœ… Geen resultaten β†’ empty state - -### Keyboard Shortcuts (2/2) βœ… -- βœ… Escape sluit block -- βœ… 1-3 FallbackPicker quick select - -### Nog Te Testen (3) - E5.S4 -- ⏳ End-to-end smoke test -- ⏳ Performance check (< 100ms) -- ⏳ Cross-browser (Chrome, Safari, Firefox) - ---- - -## ⚠️ Risico's & Issues - -### Huidige Status: **Groen** βœ… - -| Risico | Impact | Status | -|--------|--------|--------| -| Voice accuracy | Middel | βœ… **Gemitigeerd** - Fallback werkt | -| Intent misclassificatie | Laag | βœ… **Gemitigeerd** - FallbackPicker | -| Performance | Laag | βœ… **Gemitigeerd** - <200ms animaties | -| Network errors | Laag | βœ… **Gemitigeerd** - Retry + offline detection | -| Scope creep | Laag | βœ… **Onder controle** - P1 alleen | - -### Nieuwe Risico's (Laag) -- Demo preparatie β†’ Mitigatie: E5.S4 smoke tests -- Cross-browser β†’ Mitigatie: Test in E5.S4 -- Deployment β†’ Post-MVP activiteit - -**Conclusie:** Geen blockers. Project risico's minimaal. - ---- - -## πŸ“… Volgende Stappen - -### Vandaag/Morgen (1-2 uur) -1. **E5.S4 - Smoke Tests** (2 SP) - - Run test checklist uit test-plan-epic3.md - - Performance check (block open < 100ms) - - Cross-browser test (Chrome, Safari, Firefox) - - Document resultaten - -2. **πŸŽ‰ MVP COMPLEET!** (72/72 SP) - -### Na MVP (Week 1) -- Demo rehearsal met stakeholders -- User feedback sessie -- Bug fixes op basis van feedback -- Performance optimalisatie indien nodig - -### Toekomstige Uitbreidingen (Backlog) -- Diagnostiek Workflow (22 SP) - Voor behandelaars -- Meer blocks (P2 scope) -- Advanced analytics -- Mobile app - ---- - -## πŸ’Ύ Technical Debt - -### Opgelost (E5.S2, E5.S3) -- βœ… BlockContainer animaties -- βœ… CanvasArea block rendering -- βœ… Error handling centralisatie -- βœ… Keyboard shortcuts implementatie - -### Nog Te Doen (Post-MVP) -- Type duplicatie fix (`lib/swift/types.ts` als single source) -- Code splitting optimalisatie -- Bundle size analyse -- Accessibility audit (WCAG 2.1 AA) - -**Priority:** Laag - Geen blockers voor MVP - ---- - -## πŸ“Š Changelog Vandaag - -### v2.5 (27-12-2024) -**Nieuwe Features:** -- βœ… Error handling met gecentraliseerde utilities -- βœ… OfflineBanner component voor offline detection -- βœ… safeFetch wrapper met 30s timeout en retry logic -- βœ… Nederlandse error messages voor alle HTTP status codes -- βœ… ⌘Enter / Ctrl+Enter quick submit shortcuts -- βœ… ⌘Enter / Ctrl+Enter quick save in DagnotatieBlock -- βœ… Visual hints voor keyboard shortcuts (βŒ˜β†΅) - -**Documentatie:** -- βœ… Error handling test plan (350+ regels) -- βœ… Keyboard shortcuts reference (200+ regels) -- βœ… Keyboard shortcuts test plan (350+ regels) -- βœ… Bouwplan v2.5 update - -**Impact:** -- +2 SP voltooid (E5.S2, E5.S3) -- 86% β†’ 86% voortgang -- 27/29 stories compleet -- Robustere error handling -- Betere power user experience - ---- - -## 🎯 Success Metrics - -| Metric | Target | Current | Status | -|--------|--------|---------|--------| -| Story Points | 72 SP | 62 SP | 86% βœ… | -| Core Features | 100% | 100% | βœ… Done | -| Error Handling | 100% | 100% | βœ… Done | -| Keyboard Shortcuts | 100% | 100% | βœ… Done | -| Documentation | Complete | Complete | βœ… Done | -| Tests | 80%+ | 0% (E5.S4) | ⏳ In Progress | -| Demo Ready | Yes | Almost | 🎯 1 story away | - ---- - -## πŸ‘₯ Team & Ownership - -| Role | Name | Verantwoordelijk voor | -|------|------|----------------------| -| Developer | Claude | Alle implementatie (E0-E5) | -| Product Owner | Colin | Requirements, prioriteit | -| Architect | Colin | Technische keuzes | - ---- - -## πŸ“ž Contact & Next Steps - -**Voor Colin:** -1. βœ… E5.S2 is compleet - Error handling geΓ―mplementeerd -2. βœ… E5.S3 is compleet - Keyboard shortcuts klaar -3. ⏳ **Volgende:** E5.S4 - Smoke tests (1-2 uur) -4. πŸŽ‰ **Na E5.S4:** MVP COMPLEET! Demo-ready. - -**Vragen/Opmerkingen:** -- Wil je E5.S4 nu doen of later? -- Zijn er specifieke test scenarios die prioriteit hebben? -- Deployment naar Vercel planning? - ---- - -**Project Status:** 🟒 **EXCELLENT** -**Momentum:** πŸš€ **HIGH** -**Risk Level:** 🟒 **LOW** -**MVP Completion:** 🎯 **1-2 HOURS AWAY** - -**Let's finish this! πŸ’ͺ** diff --git a/docs/swift/archive/bouwplan-swift-v1.md b/docs/swift/archive/bouwplan-swift-v1.md deleted file mode 100644 index f1f7788..0000000 --- a/docs/swift/archive/bouwplan-swift-v1.md +++ /dev/null @@ -1,554 +0,0 @@ -# Mission Control β€” Bouwplan Swift v1.0 - -**Projectnaam:** Swift β€” Contextual UI EPD -**Versie:** v1.0 -**Datum:** 23-12-2024 -**Auteur:** Colin Lit / Development Team - ---- - -## 1. Doel en context - -### 1.1 Projectdoel - -Swift is een **Contextual UI** interface voor het Mini-EPD systeem. In plaats van navigatie door menu's spreekt of typt de gebruiker een intentie β€” en het juiste UI-blok verschijnt voorgevuld met relevante data. - -**Kernbelofte:** -> Van 12 klikken en 3 minuten naar 1 zin en 15 seconden. - -### 1.2 Business Case - -| Metric | Huidig | Met Swift | Besparing | -|--------|--------|-----------|-----------| -| Dagnotitie maken | 3-5 min | 15 sec | 95% | -| PatiΓ«nt zoeken | 1-2 min | 5 sec | 95% | -| Overdracht maken | 20-30 min | 5 min | 80% | -| Rapportage schrijven | 8-15 min | 2-3 min | 75% | - -**Per verpleegkundige per dag: ~4 uur terug naar zorg** - -### 1.3 Relatie met Documentatie - -| Document | Beschrijft | Locatie | -|----------|------------|---------| -| PRD | Product visie, requirements | `swift-prd.md` | -| FO | Functionele flows, blocks | `swift-fo-ai.md` | -| TO | Technische architectuur | `to-swift-v1.md` | -| UX | Visuele specificaties | `swift-ux-v2.1.md` | - ---- - -## 2. Uitgangspunten - -### 2.1 Technische Stack - -**Bestaand (hergebruiken):** -| Component | Technologie | Versie | -|-----------|-------------|--------| -| Framework | Next.js | 14.2.18 | -| UI Library | React | 18.3.1 | -| Styling | TailwindCSS | 3.4.18 | -| Components | shadcn/ui | - | -| Command Palette | cmdk | 1.1.1 | -| Animations | framer-motion | 12.23.24 | -| Database | Supabase | 2.81.1 | -| Speech-to-Text | Deepgram | 4.11.2 | -| AI | Claude API | - | -| Validation | Zod | 4.1.12 | -| Forms | react-hook-form | 7.66.1 | - -**Nieuw toe te voegen:** -| Component | Technologie | Versie | Reden | -|-----------|-------------|--------|-------| -| State Management | Zustand | ^4.5.0 | Lightweight, TypeScript-first | - -### 2.2 Projectkaders - -| Kader | Waarde | -|-------|--------| -| **Bouwtijd** | 4 weken (4 sprints) | -| **Team** | 1 developer | -| **Scope** | MVP: P1 blocks (dagnotitie, zoeken, overdracht) | -| **Data** | Bestaande Supabase database | -| **Doel** | Werkende demo + user testing | - -### 2.3 Programmeer Uitgangspunten - -**Code Quality Principles:** - -- **DRY (Don't Repeat Yourself)** - - Herbruikbare block componenten - - Centrale intent classificatie logica - - Shared hooks voor common patterns - -- **KISS (Keep It Simple, Stupid)** - - Local-first intent classificatie (regex) - - AI alleen als fallback - - Minimale state complexity - -- **SOC (Separation of Concerns)** - - UI blocks gescheiden van intent logic - - API routes gescheiden van business logic - - Store slices per domein - -- **YAGNI (You Aren't Gonna Need It)** - - Alleen P1 blocks in MVP - - Geen toggle tussen interfaces - - Geen advanced analytics in v1 - -**Development Practices:** - -```typescript -// βœ… Goede structuur voor Swift components -components/ -β”œβ”€β”€ swift/ -β”‚ β”œβ”€β”€ command-center/ -β”‚ β”‚ β”œβ”€β”€ command-center.tsx // Main container -β”‚ β”‚ β”œβ”€β”€ command-input.tsx // Input component -β”‚ β”‚ └── index.ts // Barrel export -β”‚ └── blocks/ -β”‚ β”œβ”€β”€ dagnotitie-block.tsx -β”‚ β”œβ”€β”€ zoeken-block.tsx -β”‚ └── index.ts - -// βœ… Store slice pattern -stores/ -└── swift-store.ts // Single store file - -// βœ… Intent classification -lib/ -└── swift/ - β”œβ”€β”€ intent-classifier.ts // Local classification - β”œβ”€β”€ intent-classifier-ai.ts // AI fallback - └── types.ts // Type definitions -``` - ---- - -## 3. Epics & Stories Overzicht - -| Epic ID | Titel | Doel | Status | Stories | Effort | -|---------|-------|------|--------|---------|--------| -| E0 | Setup & Foundation | Zustand, routing, base layout | βœ… Done | 4 | 8 SP | -| E1 | Command Center | Input, voice, context bar | βœ… Done | 5 | 13 SP | -| E2 | Intent Classification | Local + AI fallback + wiring | ⏳ In Progress | 5 | 12 SP | -| E3 | P1 Blocks | Dagnotitie, Zoeken, Overdracht | ⏳ To Do | 6 | 21 SP | -| E4 | Navigation & Auth | Login keuze, routing, preferences | ⏳ To Do | 4 | 8 SP | -| E5 | Polish & Testing | Animaties, error handling, tests | ⏳ To Do | 4 | 8 SP | - -**Totaal: 28 stories, 70 story points (31 SP done, 39 SP remaining)** - -**Belangrijk:** -- Bouw per epic en per story, niet alles tegelijk -- Dependencies installeren: eerst aan Colin melden -- Database migraties: eerst aan Colin melden - ---- - -## 4. Epics & Stories (Uitwerking) - -### Epic 0 β€” Setup & Foundation -**Epic Doel:** Werkende development omgeving met Zustand store en Swift routing. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E0.S1 | Zustand installeren | `pnpm add zustand` succesvol, import werkt | βœ… | β€” | 1 | -| E0.S2 | Swift store opzetten | `stores/swift-store.ts` met basis state | βœ… | E0.S1 | 2 | -| E0.S3 | Swift route aanmaken | `/epd/swift` route met eigen layout | βœ… | E0.S2 | 2 | -| E0.S4 | Swift folder structuur | `components/swift/`, `lib/swift/` aangemaakt | βœ… | E0.S3 | 3 | - -**Technical Notes:** -```bash -# E0.S1: Dependency installatie -pnpm add zustand -``` - -```typescript -// E0.S2: Store structuur -// stores/swift-store.ts -import { create } from 'zustand'; -import { devtools } from 'zustand/middleware'; - -interface SwiftStore { - // Context - activePatient: Patient | null; - shift: 'nacht' | 'ochtend' | 'middag' | 'avond'; - - // Block state - activeBlock: BlockType | null; - prefillData: Record; - - // Actions - setActivePatient: (patient: Patient | null) => void; - openBlock: (type: BlockType, prefill?: Record) => void; - closeBlock: () => void; -} -``` - ---- - -### Epic 1 β€” Command Center -**Epic Doel:** Werkende command center met tekst en voice input. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E1.S1 | Command Center layout | 4-zone layout (context, canvas, recent, input) | βœ… | E0.S4 | 3 | -| E1.S2 | Context Bar | Dienst, patiΓ«nt dropdown, user info | βœ… | E1.S1 | 2 | -| E1.S3 | Command Input | Tekst input met placeholder, focus state | βœ… | E1.S1 | 2 | -| E1.S4 | Voice Input integratie | Deepgram streaming in command input | βœ… | E1.S3 | 3 | -| E1.S5 | Recent Strip | Laatste 5 acties als chips | βœ… | E1.S1 | 3 | - -**Technical Notes:** -``` -Command Center Layout: -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Context Bar (48px) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Canvas Area (flex) β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Recent Strip (48px) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Command Input (64px, fixed bottom) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -### Epic 2 β€” Intent Classification -**Epic Doel:** Two-tier intent classificatie (local + AI fallback). - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E2.S1 | Local classifier | Regex patterns voor P1 intents, <50ms | βœ… | E0.S4 | 3 | -| E2.S2 | Entity extraction | Patient naam, categorie uit input | βœ… | E2.S1 | 3 | -| E2.S3 | AI fallback | Claude Haiku bij confidence <0.8 | βœ… | E2.S2 | 2 | -| E2.S4 | Intent API route | POST /api/intent/classify | βœ… | E2.S3 | 2 | -| E2.S5 | Input β†’ Block wiring | CommandInput submit β†’ API β†’ openBlock | ⏳ | E2.S4 | 2 | - -**Technical Notes:** -```typescript -// E2.S1: Local classifier patterns -const INTENT_PATTERNS = { - dagnotitie: [ - /^notitie\s+(\w+)/i, - /^(\w+)\s+(medicatie|adl|gedrag|incident)/i, - /dagnotitie/i, - ], - zoeken: [ - /^zoek\s+(\w+)/i, - /^wie is\s+(\w+)/i, - /^vind\s+(\w+)/i, - ], - overdracht: [ - /^overdracht/i, - /^dienst (klaar|afronden)/i, - /^wat moet ik weten/i, - ], -}; - -// E2.S5: Input β†’ Block wiring -// In CommandInput.handleSubmit: -const handleSubmit = async () => { - const response = await fetch('/api/intent/classify', { - method: 'POST', - body: JSON.stringify({ input: inputValue }), - }); - const { intent, confidence, entities } = await response.json(); - - if (intent !== 'unknown' && confidence >= 0.5) { - openBlock(intent, entities); // Open juiste block met prefill - } else { - // Toon FallbackPicker (E4.S4) - } -}; -``` - ---- - -### Epic 3 β€” P1 Blocks -**Epic Doel:** Werkende DagnotatieBlock, ZoekenBlock en OverdrachtBlock. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E3.S1 | Block Container | Animatie wrapper, close button, sizes | ⏳ | E1.S1 | 2 | -| E3.S2 | DagnotatieBlock | Patient, categorie, tekst, opslaan | ⏳ | E3.S1, E2.S2 | 5 | -| E3.S3 | Patient search API | GET /api/patients/search?q= fuzzy search | ⏳ | E0.S4 | 3 | -| E3.S4 | ZoekenBlock | Input, resultaten, selectie β†’ store | ⏳ | E3.S1, E3.S3 | 3 | -| E3.S5 | PatientContextCard | Na selectie: notities, vitals, diagnose | ⏳ | E3.S4 | 5 | -| E3.S6 | OverdrachtBlock | AI samenvatting per patiΓ«nt (bestaande API) | ⏳ | E3.S1 | 3 | - -**Technical Notes:** -```typescript -// E3.S2: DagnotatieBlock prefill -interface DagnotitieBlockProps { - prefill?: { - patientId?: string; - patientName?: string; - category?: VerpleegkundigCategory; - content?: string; - }; - onSave: () => void; - onCancel: () => void; -} - -// Gebruikt bestaande POST /api/reports -``` - ---- - -### Epic 4 β€” Navigation & Auth -**Epic Doel:** Login pagina met interface keuze, routing naar Swift/Klassiek. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E4.S1 | Login form uitbreiden | Interface selector (Swift/Klassiek) | ⏳ | E0.S3 | 2 | -| E4.S2 | Preference opslag | user_metadata.preferred_interface | ⏳ | E4.S1 | 2 | -| E4.S3 | Redirect middleware | /epd β†’ preference route | ⏳ | E4.S2 | 2 | -| E4.S4 | Fallback Picker | Visuele keuze bij lage confidence | ⏳ | E3.S1 | 2 | - -**Technical Notes:** -```typescript -// E4.S2: Preference in Supabase -await supabase.auth.updateUser({ - data: { - preferred_interface: 'swift', // of 'classic' - remember_interface_choice: true, - }, -}); -``` - ---- - -### Epic 5 β€” Polish & Testing -**Epic Doel:** Gepolijste UX met animaties, error handling en tests. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E5.S1 | Block animaties | Slide up/down met framer-motion | ⏳ | E3.S1 | 2 | -| E5.S2 | Error handling | Network errors, validation, toasts | ⏳ | E3.S6 | 2 | -| E5.S3 | Keyboard shortcuts | Cmd+K focus, Escape close, Enter submit | ⏳ | E1.S3 | 2 | -| E5.S4 | Smoke tests | Happy flow tests voor alle P1 blocks | ⏳ | E5.S2 | 2 | - -**Technical Notes:** -```typescript -// E5.S1: Framer Motion animaties -const blockVariants = { - hidden: { opacity: 0, y: 20, scale: 0.95 }, - visible: { opacity: 1, y: 0, scale: 1 }, - exit: { opacity: 0, y: 20, scale: 0.95 }, -}; - -// E5.S3: Keyboard shortcuts -useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - if ((e.metaKey || e.ctrlKey) && e.key === 'k') { - e.preventDefault(); - inputRef.current?.focus(); - } - if (e.key === 'Escape') { - closeBlock(); - } - }; - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); -}, []); -``` - ---- - -## 5. Kwaliteit & Testplan - -### 5.1 Test Types - -| Test Type | Scope | Tools | Wanneer | -|-----------|-------|-------|---------| -| Unit Tests | Intent classifier, entity extraction | Vitest | E2 | -| Integration Tests | API endpoints | Vitest + MSW | E2, E3 | -| Component Tests | Blocks, Command Center | React Testing Library | E3, E5 | -| E2E Tests | Complete flows | Playwright (optioneel) | E5 | -| Manual Tests | Demo scenarios | Checklist | E5 | - -### 5.2 Test Coverage Targets - -| Area | Target | Reden | -|------|--------|-------| -| Intent classifier | 90%+ | Kritiek voor UX | -| API routes | 80%+ | Data integrity | -| UI components | 60%+ | Belangrijkste flows | - -### 5.3 Manual Test Checklist (MVP Demo) - -**Happy Flows:** -- [ ] User kan inloggen en Swift kiezen -- [ ] Command input krijgt focus met Cmd+K -- [ ] "notitie jan medicatie" β†’ DagnotatieBlock opent met prefill -- [ ] Dagnotitie opslaan β†’ toast + block sluit -- [ ] "zoek marie" β†’ ZoekenBlock met resultaten -- [ ] PatiΓ«nt selecteren β†’ PatientContextCard -- [ ] "overdracht" β†’ OverdrachtBlock met AI samenvatting -- [ ] Voice input β†’ transcript in command input - -**Error Scenarios:** -- [ ] Onbekende intent β†’ FallbackPicker -- [ ] Network error β†’ toast met retry -- [ ] Lege notitie β†’ validation error -- [ ] Geen zoekresultaten β†’ "Geen patiΓ«nten gevonden" - ---- - -## 6. Demo & Presentatieplan - -### 6.1 Demo Scenario - -**Duur:** 10 minuten -**Doelgroep:** Zorgprofessionals, management -**Locatie:** Live op Vercel - -**Flow:** - -``` -1. INTRO (1 min) - "40% van je tijd gaat naar administratie. - Wat als je gewoon kon zeggen wat je wilt?" - -2. CONTRAST (2 min) - Klassiek EPD: Dashboard β†’ PatiΓ«nten β†’ Jan β†’ Rapportages β†’ - Nieuwe β†’ Type β†’ Tekst β†’ Opslaan - Swift: "notitie jan medicatie gegeven" β†’ Opslaan - -3. DAGNOTITIE FLOW (2 min) - - Typ: "notitie jan medicatie uitgereikt" - - Block verschijnt voorgevuld - - Één klik: opgeslagen - -4. VOICE DEMO (2 min) - - Klik microfoon - - Spreek: "marie had een rustige nacht, goed geslapen" - - Block verschijnt met transcript - -5. OVERDRACHT (2 min) - - "overdracht" - - AI genereert samenvatting per patiΓ«nt - - Toon bronverwijzingen - -6. AFSLUITING (1 min) - - Tijdsbesparing recap - - Vragen -``` - -### 6.2 Backup Plan - -| Probleem | Oplossing | -|----------|-----------| -| Internet issues | Localhost met demo data | -| Voice niet werkt | Type-only demo | -| AI API down | Pre-cached responses | -| Complete failure | Video recording | - ---- - -## 7. Risico's & Mitigatie - -| Risico | Kans | Impact | Mitigatie | Owner | -|--------|------|--------|-----------|-------| -| Voice accuracy NL | Middel | Hoog | Deepgram NL model, fallback naar tekst | Dev | -| Intent misclassificatie | Middel | Hoog | Two-tier systeem, FallbackPicker | Dev | -| AI latency | Laag | Middel | Local-first, Haiku model | Dev | -| User adoption | Middel | Middel | Keuze behouden, geen dwang | Product | -| Scope creep | Hoog | Hoog | Strict P1-only, backlog voor rest | Dev | -| Performance | Laag | Middel | Code splitting, lazy loading | Dev | - ---- - -## 8. Sprint Planning - -### Sprint 1 (Week 1): Foundation -- E0: Setup & Foundation (8 SP) -- E1.S1-S3: Command Center basics (7 SP) -- **Deliverable:** Swift route met command input - -### Sprint 2 (Week 2): Intent & Blocks -- E1.S4-S5: Voice + Recent (6 SP) -- E2: Intent Classification (10 SP) -- **Deliverable:** Werkende intent classificatie - -### Sprint 3 (Week 3): P1 Blocks -- E3: Alle P1 blocks (21 SP) -- **Deliverable:** DagnotatieBlock, ZoekenBlock, OverdrachtBlock - -### Sprint 4 (Week 4): Polish & Ship -- E4: Navigation & Auth (8 SP) -- E5: Polish & Testing (8 SP) -- **Deliverable:** Demo-ready MVP - ---- - -## 9. Definition of Done - -Een story is **Done** wanneer: -- [ ] Code geschreven en werkend -- [ ] TypeScript types correct -- [ ] Component responsive (mobile + desktop) -- [ ] Error states afgehandeld -- [ ] Toegankelijkheid basics (focus, labels) -- [ ] Getest in Chrome + Safari -- [ ] PR reviewed (indien team) -- [ ] Gemerged naar main - -Een epic is **Done** wanneer: -- [ ] Alle stories Done -- [ ] Integration test passed -- [ ] Demo scenario werkt - ---- - -## 10. Referenties - -### Project Documenten -- PRD: `docs/swift/swift-prd.md` -- FO: `docs/swift/swift-fo-ai.md` -- TO: `docs/swift/to-swift-v1.md` -- UX: `docs/swift/swift-ux-v2.1.md` - -### Bestaande Code Referenties -- Command component: `components/ui/command.tsx` -- Speech streaming: `components/speech-recorder-streaming.tsx` -- Overdracht API: `app/api/overdracht/generate/route.ts` -- Report types: `lib/types/report.ts` - -### External -- Zustand: https://zustand-demo.pmnd.rs/ -- cmdk: https://cmdk.paco.me/ -- Deepgram: https://developers.deepgram.com/docs -- Claude API: https://docs.anthropic.com/ - ---- - -## 11. Glossary - -| Term | Betekenis | -|------|-----------| -| Swift | Projectnaam voor Contextual UI EPD | -| Command Center | Hoofdscherm met één input | -| Block | Ephemeral UI component (dagnotitie, zoeken, etc.) | -| Intent | Gebruikersintentie (dagnotitie, zoeken, overdracht) | -| Entity | GeΓ«xtraheerde data (patiΓ«ntnaam, categorie) | -| Prefill | Vooraf ingevulde data in block | -| Klassiek EPD | Traditionele menu-gebaseerde interface | -| P1 | Prioriteit 1 (MVP scope) | -| SP | Story Points (Fibonacci: 1, 2, 3, 5, 8) | - ---- - -**Versiehistorie:** - -| Versie | Datum | Auteur | Wijziging | -|--------|-------|--------|-----------| -| v1.0 | 23-12-2024 | Colin Lit | InitiΓ«le versie | -| v1.1 | 23-12-2024 | Claude | E0 + E1 voltooid (21 SP) | -| v1.2 | 23-12-2024 | Claude | E2.S1 + E2.S2 voltooid (27 SP) | -| v1.3 | 23-12-2024 | Claude | E2.S3 AI fallback voltooid (29 SP) | -| v1.4 | 23-12-2024 | Claude | E2.S1-S4 voltooid (31 SP) | -| v1.5 | 24-12-2024 | Claude | E2.S5 toegevoegd: Input β†’ Block wiring (+2 SP) | diff --git a/docs/swift/archive/bouwplan-swift-v2.md b/docs/swift/archive/bouwplan-swift-v2.md deleted file mode 100644 index 1cbc200..0000000 --- a/docs/swift/archive/bouwplan-swift-v2.md +++ /dev/null @@ -1,971 +0,0 @@ -# Mission Control β€” Bouwplan Swift v2.5 - -**Projectnaam:** Swift β€” Contextual UI EPD -**Versie:** v2.5 -**Datum:** 27-12-2024 -**Auteur:** Colin Lit / Development Team -**Status:** πŸ”„ **86% Complete** - MVP binnen handbereik! - ---- - -## 🎯 Project Status Summary - -| Metric | Waarde | Progress | -|--------|--------|----------| -| **Story Points** | 62 / 72 SP | 86% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘ | -| **Epics Compleet** | 4.75 / 5 | E0 βœ… E1 βœ… E2 βœ… E3 βœ… E4 βœ… E5 πŸ”„ | -| **Stories Compleet** | 27 / 29 | 93% | -| **Remaining Work** | 2 SP (1 story) | E5.S4 only! | -| **Estimated Time** | 1-2 uur | Voor MVP compleet | - -**πŸŽ‰ Laatste sprint! Nog 1 story en de MVP is klaar voor demo!** - ---- - -## Changelog v2.5 - -> **Belangrijke wijzigingen t.o.v. v2.4:** -> - E5.S3 compleet: Keyboard shortcuts geverifieerd en uitgebreid -> - ⌘Enter / Ctrl+Enter voor quick submit in CommandInput -> - ⌘Enter / Ctrl+Enter voor quick save in DagnotatieBlock -> - Visual hints toegevoegd (βŒ˜β†΅ op buttons) -> - Keyboard shortcuts reference document -> - Totalen bijgewerkt: 62 SP done (86%), 10 SP remaining - -## Changelog v2.4 - -> **Belangrijke wijzigingen t.o.v. v2.3:** -> - E5.S2 compleet: Error handling geΓ―mplementeerd met gecentraliseerde utilities -> - OfflineBanner component voor offline detection -> - safeFetch wrapper met 30s timeout en retry logic -> - User-friendly Nederlandse error messages voor alle HTTP status codes -> - Retry logic met exponential backoff voor transient errors -> - Alle blocks en command input gebruiken nieuwe error handler -> - Totalen bijgewerkt: 60 SP done (83%), 12 SP remaining - -## Changelog v2.3 - -> **Belangrijke wijzigingen t.o.v. v2.2:** -> - E5.S1 compleet: Block animaties geΓ―mplementeerd volgens UX specificatie -> - Slide up/down animaties met fade en scale (200ms) -> - CanvasArea animaties verbeterd: slide down bij sluiten (niet omhoog) -> - BlockContainer animaties consistent gemaakt met CanvasArea -> - Totalen bijgewerkt: 58 SP done (81%), 14 SP remaining - -## Changelog v2.2 - -> **Belangrijke wijzigingen t.o.v. v2.1:** -> - Epic 3 compleet: Alle P1 blocks geΓ―mplementeerd (E3.S0-S6) -> - PatientContextCard toegevoegd: Auto-open na patient selectie -> - OverdrachtBlock met AI samenvattingen per patiΓ«nt -> - Patient search API geΓ―mplementeerd -> - Technische debt opgelost: BlockContainer animaties, CanvasArea rendering -> - Totalen bijgewerkt: 56 SP done (78%), 16 SP remaining - -## Changelog v2.0 - -> **Belangrijke wijzigingen t.o.v. v1.5:** -> - E3.S0 toegevoegd: CanvasArea block rendering (kritieke blokkade) -> - Technische debt sectie toegevoegd (type duplicatie, keyboard shortcuts) -> - Diagnostiek Workflow als uitbreiding opgenomen -> - Sprint planning aangepast aan huidige voortgang -> - Totalen bijgewerkt: 29 stories, 72 SP - ---- - -## 1. Doel en context - -### 1.1 Projectdoel - -Swift is een **Contextual UI** interface voor het Mini-EPD systeem. In plaats van navigatie door menu's spreekt of typt de gebruiker een intentie β€” en het juiste UI-blok verschijnt voorgevuld met relevante data. - -**Kernbelofte:** -> Van 12 klikken en 3 minuten naar 1 zin en 15 seconden. - -### 1.2 Business Case - -| Metric | Huidig | Met Swift | Besparing | -|--------|--------|-----------|-----------| -| Dagnotitie maken | 3-5 min | 15 sec | 95% | -| PatiΓ«nt zoeken | 1-2 min | 5 sec | 95% | -| Overdracht maken | 20-30 min | 5 min | 80% | -| Rapportage schrijven | 8-15 min | 2-3 min | 75% | - -**Per verpleegkundige per dag: ~4 uur terug naar zorg** - -### 1.3 Relatie met Documentatie - -| Document | Beschrijft | Locatie | -|----------|------------|---------| -| PRD | Product visie, requirements | `swift-prd.md` | -| FO | Functionele flows, blocks | `swift-fo-ai.md` | -| TO | Technische architectuur | `to-swift-v1.md` | -| UX | Visuele specificaties | `swift-ux-v2.1.md` | -| **Diagnostiek FO** | Behandelaar workflow | `swift-fo-diagnostiek-workflow.md` | -| **Diagnostiek Bouwplan** | Uitbreiding voor behandelaars | `bouwplan-swift-diagnostiek-workflow.md` | - ---- - -## 2. Uitgangspunten - -### 2.1 Technische Stack - -**Bestaand (hergebruiken):** -| Component | Technologie | Versie | -|-----------|-------------|--------| -| Framework | Next.js | 14.2.18 | -| UI Library | React | 18.3.1 | -| Styling | TailwindCSS | 3.4.18 | -| Components | shadcn/ui | - | -| Command Palette | cmdk | 1.1.1 | -| Animations | framer-motion | 12.23.24 | -| Database | Supabase | 2.81.1 | -| Speech-to-Text | Deepgram | 4.11.2 | -| AI | Claude API | - | -| Validation | Zod | 4.1.12 | -| Forms | react-hook-form | 7.66.1 | - -**Nieuw toegevoegd:** -| Component | Technologie | Versie | Status | -|-----------|-------------|--------|--------| -| State Management | Zustand | 5.0.9 | βœ… GeΓ―nstalleerd | - -### 2.2 Projectkaders - -| Kader | Waarde | -|-------|--------| -| **Bouwtijd** | 4 weken (4 sprints) | -| **Team** | 1 developer | -| **Scope** | MVP: P1 blocks (dagnotitie, zoeken, overdracht) | -| **Uitbreiding** | Diagnostiek workflow (optioneel, +22 SP) | -| **Data** | Bestaande Supabase database | -| **Doel** | Werkende demo + user testing | - -### 2.3 Programmeer Uitgangspunten - -**Code Quality Principles:** - -- **DRY (Don't Repeat Yourself)** - - Herbruikbare block componenten - - Centrale intent classificatie logica - - Shared hooks voor common patterns - - **Let op:** Types importeren uit `lib/swift/types.ts`, niet dupliceren - -- **KISS (Keep It Simple, Stupid)** - - Local-first intent classificatie (regex) - - AI alleen als fallback - - Minimale state complexity - -- **SOC (Separation of Concerns)** - - UI blocks gescheiden van intent logic - - API routes gescheiden van business logic - - Store slices per domein - -- **YAGNI (You Aren't Gonna Need It)** - - Alleen P1 blocks in MVP - - Geen toggle tussen interfaces - - Geen advanced analytics in v1 - -**Development Practices:** - -```typescript -// βœ… Goede structuur voor Swift components -components/ -β”œβ”€β”€ swift/ -β”‚ β”œβ”€β”€ command-center/ -β”‚ β”‚ β”œβ”€β”€ command-center.tsx // Main container -β”‚ β”‚ β”œβ”€β”€ command-input.tsx // Input component -β”‚ β”‚ β”œβ”€β”€ canvas-area.tsx // Block rendering ← KRITIEK -β”‚ β”‚ └── index.ts // Barrel export -β”‚ └── blocks/ -β”‚ β”œβ”€β”€ block-container.tsx // Wrapper met animaties -β”‚ β”œβ”€β”€ dagnotitie-block.tsx -β”‚ β”œβ”€β”€ zoeken-block.tsx -β”‚ β”œβ”€β”€ overdracht-block.tsx -β”‚ └── index.ts - -// βœ… Store importeert types (geen duplicatie) -stores/ -└── swift-store.ts // Importeert uit lib/swift/types.ts - -// βœ… Intent classification -lib/ -└── swift/ - β”œβ”€β”€ types.ts // SINGLE SOURCE OF TRUTH voor types - β”œβ”€β”€ intent-classifier.ts // Local classification - β”œβ”€β”€ intent-classifier-ai.ts // AI fallback - └── entity-extractor.ts // Entity parsing -``` - ---- - -## 3. Epics & Stories Overzicht - -| Epic ID | Titel | Doel | Status | Stories | Effort | -|---------|-------|------|--------|---------|--------| -| E0 | Setup & Foundation | Zustand, routing, base layout | βœ… Done | 4 | 8 SP | -| E1 | Command Center | Input, voice, context bar | βœ… Done | 5 | 13 SP | -| E2 | Intent Classification | Local + AI fallback + wiring | βœ… Done | 5 | 12 SP | -| E3 | P1 Blocks | Dagnotitie, Zoeken, Overdracht | βœ… Done | 7 | 23 SP | -| E4 | Navigation & Auth | Login keuze, routing, preferences | βœ… Done | 4 | 8 SP | -| E5 | Polish & Testing | Animaties, error handling, tests | πŸ”„ In Progress | 4 | 8 SP | - -**Totaal: 29 stories, 72 story points** - -| Categorie | SP | -|-----------|----:| -| βœ… Done (E0 + E1 + E2 + E3 + E4 + E5.S1 + E5.S2 + E5.S3) | 62 | -| ⏳ Remaining | 10 | - -### Epic Completion Details - -| Epic | Stories | SP | Status | Completion | -|------|---------|----:|--------|------------| -| **E0: Setup & Foundation** | 4/4 | 8/8 | βœ… **DONE** | 100% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ | -| **E1: Command Center** | 5/5 | 13/13 | βœ… **DONE** | 100% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ | -| **E2: Intent Classification** | 5/5 | 12/12 | βœ… **DONE** | 100% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ | -| **E3: P1 Blocks** | 7/7 | 23/23 | βœ… **DONE** | 100% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ | -| **E4: Navigation & Auth** | 4/4 | 8/8 | βœ… **DONE** | 100% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ | -| **E5: Polish & Testing** | 3/4 | 6/8 | πŸ”„ **IN PROGRESS** | 75% β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘ | -| **TOTAAL** | **27/29** | **62/72** | 🎯 **86%** | β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘ | - -**Laatste Sprint:** -- βœ… E5.S1 - Block animaties (2 SP) -- βœ… E5.S2 - Error handling (2 SP) -- βœ… E5.S3 - Keyboard shortcuts (2 SP) -- ⏳ E5.S4 - Smoke tests (2 SP) ← **ALLEEN DIT NOG!** - -**Belangrijk:** -- Bouw per epic en per story, niet alles tegelijk -- Dependencies installeren: eerst aan Colin melden -- Database migraties: eerst aan Colin melden - ---- - -## 4. Epics & Stories (Uitwerking) - -### Epic 0 β€” Setup & Foundation βœ… DONE -**Epic Doel:** Werkende development omgeving met Zustand store en Swift routing. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E0.S1 | Zustand installeren | `pnpm add zustand` succesvol, import werkt | βœ… | β€” | 1 | -| E0.S2 | Swift store opzetten | `stores/swift-store.ts` met basis state | βœ… | E0.S1 | 2 | -| E0.S3 | Swift route aanmaken | `/epd/swift` route met eigen layout | βœ… | E0.S2 | 2 | -| E0.S4 | Swift folder structuur | `components/swift/`, `lib/swift/` aangemaakt | βœ… | E0.S3 | 3 | - ---- - -### Epic 1 β€” Command Center βœ… DONE -**Epic Doel:** Werkende command center met tekst en voice input. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E1.S1 | Command Center layout | 4-zone layout (context, canvas, recent, input), keyboard shortcuts (⌘K, Escape) | βœ… | E0.S4 | 3 | -| E1.S2 | Context Bar | Dienst indicator, patiΓ«nt chip, user info | βœ… | E1.S1 | 2 | -| E1.S3 | Command Input | Tekst input met placeholder, focus state, send button | βœ… | E1.S1 | 2 | -| E1.S4 | Voice Input integratie | Deepgram streaming, waveform visualisatie | βœ… | E1.S3 | 3 | -| E1.S5 | Recent Strip | Laatste 5 acties als chips, click-to-repeat | βœ… | E1.S1 | 3 | - -**Technical Notes:** -``` -Command Center Layout: -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Context Bar (48px) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Canvas Area (flex) ← Blocks hier β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Recent Strip (48px) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Command Input (64px, fixed bottom) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -### Epic 2 β€” Intent Classification βœ… DONE -**Epic Doel:** Two-tier intent classificatie (local + AI fallback) + wiring naar blocks. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E2.S1 | Local classifier | Regex patterns voor P1 intents, <50ms | βœ… | E0.S4 | 3 | -| E2.S2 | Entity extraction | Patient naam, categorie uit input | βœ… | E2.S1 | 3 | -| E2.S3 | AI fallback | Claude Haiku bij confidence <0.8 | βœ… | E2.S2 | 2 | -| E2.S4 | Intent API route | POST /api/intent/classify met logging | βœ… | E2.S3 | 2 | -| E2.S5 | Input β†’ Block wiring | CommandInput.handleSubmit β†’ API β†’ openBlock | βœ… | E2.S4 | 2 | - -**E2.S5 Technical Notes (βœ… GEÏMPLEMENTEERD):** -```typescript -// components/swift/command-center/command-input.tsx -// IMPLEMENTATIE: -const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - if (!hasValue || isProcessing) return; - - const inputText = inputValue.trim(); - setIsProcessing(true); - - try { - const response = await fetch('/api/intent/classify', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ input: inputText }), - }); - - if (!response.ok) { - const errorData = await response.json().catch(() => ({ error: 'Onbekende fout' })); - throw new Error(errorData.error || `HTTP ${response.status}`); - } - - const { intent, confidence, entities } = await response.json(); - - if (intent !== 'unknown' && confidence >= 0.5) { - openBlock(intent as BlockType, entities); - addRecentAction({ intent, label: inputText.slice(0, 50), patientName: entities.patientName }); - clearInput(); - } else { - // Tijdelijke fallback naar dagnotitie (wordt vervangen door FallbackPicker in E4.S4) - openBlock('dagnotitie', { content: inputText }); - addRecentAction({ intent: 'dagnotitie', label: inputText.slice(0, 50) }); - clearInput(); - } - } catch (error) { - // Error handling met fallback naar dagnotitie - openBlock('dagnotitie', { content: inputText }); - addRecentAction({ intent: 'dagnotitie', label: inputText.slice(0, 50) }); - clearInput(); - } finally { - setIsProcessing(false); - } -}; -``` - ---- - -### Epic 3 β€” P1 Blocks βœ… DONE -**Epic Doel:** Werkende DagnotatieBlock, ZoekenBlock en OverdrachtBlock. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E3.S0 | CanvasArea block rendering | Switch/case voor block types, prefill doorgeven | βœ… | E2.S5 | 2 | -| E3.S1 | Block Container | Animatie wrapper, close button, sizes | βœ… | E1.S1 | 2 | -| E3.S2 | DagnotatieBlock | Patient, categorie, tekst, opslaan naar /api/reports | βœ… | E3.S0, E3.S1 | 5 | -| E3.S3 | Patient search API | GET /api/patients/search?q= fuzzy search | βœ… | E0.S4 | 3 | -| E3.S4 | ZoekenBlock | Input, resultaten, selectie β†’ store | βœ… | E3.S0, E3.S3 | 3 | -| E3.S5 | PatientContextCard | Na selectie: notities, vitals, diagnose | βœ… | E3.S4 | 5 | -| E3.S6 | OverdrachtBlock | AI samenvatting per patiΓ«nt (bestaande API) | βœ… | E3.S0 | 3 | - - -**E3.S0 Technical Notes (βœ… GEÏMPLEMENTEERD):** -```typescript -// components/swift/command-center/canvas-area.tsx -// IMPLEMENTATIE: -import { DagnotatieBlock } from '../blocks/dagnotitie-block'; -import { ZoekenBlock } from '../blocks/zoeken-block'; -import { OverdrachtBlock } from '../blocks/overdracht-block'; -import { PatientContextCard } from '../blocks/patient-context-card'; - -function renderBlock(activeBlock: BlockType, prefillData: BlockPrefillData) { - switch (activeBlock) { - case 'dagnotitie': - return ; - case 'zoeken': - return ; - case 'overdracht': - return ; - default: - return null; - } -} - -// In CanvasArea: -{activeBlock ? ( - - - {renderBlock(activeBlock, prefillData)} - - -) : activePatient ? ( - - - -) : ( - -)} -``` - -**E3.S2 Technical Notes (βœ… GEÏMPLEMENTEERD):** -```typescript -// components/swift/blocks/dagnotitie-block.tsx -// IMPLEMENTATIE: -// 1. Patient search: Debounced search met /api/fhir/Patient?q=... -// 2. Category selector: 5 categorie buttons (medicatie, adl, gedrag, incident, observatie) -// 3. Tekst input: Textarea met character counter (max 500) -// 4. Opslaan: POST /api/reports met type 'verpleegkundig' -// 5. Success toast + auto-close block na 500ms -``` - ---- - -### Epic 4 β€” Navigation & Auth βœ… DONE -**Epic Doel:** Login pagina met interface keuze, routing naar Swift/Klassiek. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E4.S1 | Login form uitbreiden | Interface selector (Swift/Klassiek) | βœ… | E0.S3 | 2 | -| E4.S2 | Preference opslag | user_metadata.preferred_interface | βœ… | E4.S1 | 2 | -| E4.S3 | Redirect middleware | /epd β†’ preference route | βœ… | E4.S2 | 2 | -| E4.S4 | Fallback Picker | Visuele keuze bij lage confidence | βœ… | E3.S0 | 2 | - ---- - -### Epic 5 β€” Polish & Testing πŸ”„ IN PROGRESS -**Epic Doel:** Gepolijste UX met animaties, error handling en tests. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP | -|----------|--------------|---------------------|--------|------|----| -| E5.S1 | Block animaties | Slide up/down met framer-motion | βœ… | E3.S0 | 2 | -| E5.S2 | Error handling | Network errors, validation, toasts | βœ… | E3.S6 | 2 | -| E5.S3 | Keyboard shortcuts | Verificatie + ⌘Enter shortcuts | βœ… | E1.S1 | 2 | -| E5.S4 | Smoke tests | Happy flow tests voor alle P1 blocks | ⏳ | E5.S2 | 2 | - -**E5.S2 Technical Notes (βœ… GEÏMPLEMENTEERD):** -```typescript -// lib/swift/error-handler.ts -// IMPLEMENTATIE: Gecentraliseerde error handling utility - -// 1. Offline detection -export function isOffline(): boolean { - return typeof navigator !== 'undefined' && !navigator.onLine; -} - -// 2. Network error detection -export function isNetworkError(error: unknown): boolean { - if (error instanceof TypeError) { - return error.message.includes('fetch') || - error.message.includes('network') || - error.message.includes('Failed to fetch'); - } - return false; -} - -// 3. User-friendly error messages (Dutch) -export function getErrorInfo(error: unknown, context?: ErrorContext): ErrorInfo { - if (isOffline()) { - return { - title: 'Geen internetverbinding', - description: 'Controleer je internetverbinding en probeer het opnieuw.', - retryable: true, - }; - } - - // HTTP status code mapping - if (context?.statusCode) { - switch (context.statusCode) { - case 401: return { title: 'Niet geautoriseerd', ... }; - case 404: return { title: 'Niet gevonden', ... }; - case 500: return { title: 'Serverfout', ... }; - // etc. - } - } - // ... -} - -// 4. Safe fetch wrapper met timeout (30s) -export async function safeFetch( - url: string, - options?: RequestInit, - context?: ErrorContext -): Promise { - if (isOffline()) throw new Error('Geen internetverbinding'); - - const response = await fetch(url, { - ...options, - signal: AbortSignal.timeout(30000), // 30s timeout - }); - - if (!response.ok) { - const errorData = await parseErrorResponse(response); - throw new Error(errorData.error); - } - - return response; -} - -// 5. Retry logic met exponential backoff -export async function retryFetch( - fn: () => Promise, - maxRetries: number = 3, - delayMs: number = 1000 -): Promise { - for (let attempt = 0; attempt < maxRetries; attempt++) { - try { - return await fn(); - } catch (error) { - const errorInfo = getErrorInfo(error); - if (!errorInfo.retryable || attempt === maxRetries - 1) { - throw error; - } - await new Promise(r => setTimeout(r, delayMs * (attempt + 1))); - } - } -} - -// components/swift/command-center/offline-banner.tsx -// IMPLEMENTATIE: Offline detection banner -export function OfflineBanner() { - const [isOffline, setIsOffline] = useState(false); - - useEffect(() => { - setIsOffline(!navigator.onLine); - window.addEventListener('online', () => setIsOffline(false)); - window.addEventListener('offline', () => setIsOffline(true)); - // cleanup - }, []); - - if (!isOffline) return null; - - return ( -
- Geen internetverbinding -
- ); -} - -// Usage in blocks: -// - safeFetch() voor alle API calls (vervangt raw fetch) -// - getErrorInfo() voor user-friendly toast messages -// - retryFetch() voor dagnotitie/overdracht save operaties (max 3 retries) -``` - -**E5.S3 Technical Notes (βœ… GEÏMPLEMENTEERD):** -```typescript -// components/swift/command-center/command-input.tsx -// IMPLEMENTATIE: ⌘Enter quick submit - -// Keyboard shortcut: Cmd/Ctrl+Enter to submit -useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - // Cmd/Ctrl+Enter: submit command - if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') { - e.preventDefault(); - handleSubmit(); - } - }; - - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); -}, [handleSubmit]); - -// components/swift/blocks/dagnotitie-block.tsx -// IMPLEMENTATIE: ⌘Enter quick save - -// Keyboard shortcut: Cmd/Ctrl+Enter to save -useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - // Cmd/Ctrl+Enter: save dagnotitie - if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') { - e.preventDefault(); - handleSave(); - } - }; - - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); -}, [handleSave]); - -// Visual hint op submit button - -``` - -**Bestaande shortcuts (E1.S1, E4.S4) geverifieerd:** -- **⌘K / Ctrl+K** - Focus command input (CommandCenter) -- **Escape** - Close active block (CommandCenter + FallbackPicker) -- **1-3** - Quick select in FallbackPicker -- **Enter** - Native form submit in CommandInput - -**Nieuwe shortcuts (E5.S3):** -- **⌘Enter / Ctrl+Enter** - Quick submit in CommandInput -- **⌘Enter / Ctrl+Enter** - Quick save in DagnotatieBlock - -**Documentatie:** -- `docs/swift/keyboard-shortcuts-reference.md` - Complete shortcut reference -- `docs/swift/test-plan-e5-s3-keyboard-shortcuts.md` - Test plan - -**E5.S1 Technical Notes (βœ… GEÏMPLEMENTEERD):** -```typescript -// components/swift/command-center/canvas-area.tsx -// IMPLEMENTATIE volgens UX specificatie (sectie 11.1): -// Openen: Slide up + fade in (200ms), Scale: 0.95 β†’ 1.0 -// Sluiten: Slide down + fade out (200ms), Scale: 1.0 β†’ 0.95 -const blockAnimations = { - initial: { opacity: 0, y: 20, scale: 0.95 }, - animate: { - opacity: 1, - y: 0, - scale: 1, - transition: { duration: 0.2, ease: [0.4, 0, 0.2, 1] }, - }, - exit: { - opacity: 0, - y: 20, // Slide down (niet omhoog) - scale: 0.95, - transition: { duration: 0.2, ease: [0.4, 0, 0.2, 1] }, - }, -}; - -// AnimatePresence met mode="wait" voor soepele transitions - - {activeBlock && ( - - {renderBlock(activeBlock, prefillData)} - - )} - -``` - -**Nota:** Keyboard shortcuts (⌘K focus, Escape close) zijn al geΓ―mplementeerd in E1.S1. -E5.S3 is nu verificatie + eventuele uitbreiding (Enter submit, etc.). - ---- - -## 5. Technische Debt & Bekende Issues - -### 5.1 Type Duplicatie (Medium Priority) - -**Probleem:** -```typescript -// lib/swift/types.ts - BRON -export type SwiftIntent = 'dagnotitie' | 'zoeken' | 'overdracht' | 'unknown'; - -// stores/swift-store.ts - DUPLICAAT (moet verwijderd worden) -export type SwiftIntent = 'dagnotitie' | 'zoeken' | 'overdracht' | 'unknown'; -``` - -**Impact:** Bij uitbreiding intents (diagnostiek workflow) moet op twee plekken gewijzigd worden. - -**Oplossing:** Verwijder duplicaat uit `swift-store.ts`, importeer uit `lib/swift/types.ts`: -```typescript -// stores/swift-store.ts -import type { SwiftIntent, BlockType, ShiftType } from '@/lib/swift/types'; -``` - -**Wanneer:** Voorafgaand aan E-D1.S1 (diagnostiek intent patterns). - -### 5.2 BlockContainer Animaties (RESOLVED) - -**Probleem:** BlockContainer bestaat maar heeft nog geen framer-motion animaties. - -**Oplossing:** GeΓ―mplementeerd in E3.S1. BlockContainer heeft nu volledige animatie support met framer-motion. - -### 5.3 CanvasArea Placeholder (RESOLVED) - -**Probleem:** CanvasArea toont placeholder tekst i.p.v. blocks. - -**Oplossing:** GeΓ―mplementeerd in E3.S0. CanvasArea heeft nu volledige block rendering met switch/case en animaties. - ---- - -## 6. Kwaliteit & Testplan - -### 6.1 Test Types - -| Test Type | Scope | Tools | Wanneer | -|-----------|-------|-------|---------| -| Unit Tests | Intent classifier, entity extraction | Vitest | E2 | -| Integration Tests | API endpoints | Vitest + MSW | E2, E3 | -| Component Tests | Blocks, Command Center | React Testing Library | E3, E5 | -| E2E Tests | Complete flows | Playwright (optioneel) | E5 | -| Manual Tests | Demo scenarios | Checklist | E5 | - -### 6.2 Test Coverage Targets - -| Area | Target | Reden | -|------|--------|-------| -| Intent classifier | 90%+ | Kritiek voor UX | -| API routes | 80%+ | Data integrity | -| UI components | 60%+ | Belangrijkste flows | - -### 6.3 Manual Test Checklist (MVP Demo) - -**Status:** πŸ”„ 12/14 scenarios geΓ―mplementeerd (86%) - -**Happy Flows:** -- [x] User kan inloggen en Swift kiezen (E4) βœ… -- [x] Command input krijgt focus met Cmd+K (E1.S1) βœ… -- [x] ⌘Enter quick submit β†’ block opent (E5.S3) βœ… NEW! -- [x] "notitie jan medicatie" β†’ DagnotatieBlock opent met prefill (E3.S2) βœ… -- [x] Dagnotitie opslaan β†’ toast + block sluit (E3.S2) βœ… -- [x] ⌘Enter in dagnotitie β†’ quick save (E5.S3) βœ… NEW! -- [x] "zoek marie" β†’ ZoekenBlock met resultaten (E3.S4) βœ… -- [x] PatiΓ«nt selecteren β†’ PatientContextCard (E3.S5) βœ… -- [x] "overdracht" β†’ OverdrachtBlock met AI samenvatting (E3.S6) βœ… -- [x] Voice input β†’ transcript in command input (E1.S4) βœ… - -**Error Scenarios:** -- [x] Onbekende intent β†’ FallbackPicker (E4.S4) βœ… -- [x] Offline mode β†’ banner + error toast (E5.S2) βœ… NEW! -- [x] Network error β†’ toast met retry (E5.S2) βœ… -- [x] Lege notitie β†’ validation error (E3.S2) βœ… -- [x] Geen zoekresultaten β†’ "Geen patiΓ«nten gevonden" (E3.S4) βœ… - -**Keyboard Shortcuts:** -- [x] Escape sluit block (E1.S1) βœ… -- [x] 1-3 in FallbackPicker β†’ quick select (E4.S4) βœ… - -**Te Testen (E5.S4):** -- [ ] End-to-end smoke test alle flows -- [ ] Performance check (< 100ms block open) -- [ ] Cross-browser test (Chrome, Safari, Firefox) - ---- - -## 7. Demo & Presentatieplan - -### 7.1 Demo Scenario - -**Duur:** 10 minuten -**Doelgroep:** Zorgprofessionals, management -**Locatie:** Live op Vercel - -**Flow:** - -``` -1. INTRO (1 min) - "40% van je tijd gaat naar administratie. - Wat als je gewoon kon zeggen wat je wilt?" - -2. CONTRAST (2 min) - Klassiek EPD: Dashboard β†’ PatiΓ«nten β†’ Jan β†’ Rapportages β†’ - Nieuwe β†’ Type β†’ Tekst β†’ Opslaan - Swift: "notitie jan medicatie gegeven" β†’ Opslaan - -3. DAGNOTITIE FLOW (2 min) - - Typ: "notitie jan medicatie uitgereikt" - - Block verschijnt voorgevuld - - Één klik: opgeslagen - -4. VOICE DEMO (2 min) - - Klik microfoon - - Spreek: "marie had een rustige nacht, goed geslapen" - - Block verschijnt met transcript - -5. OVERDRACHT (2 min) - - "overdracht" - - AI genereert samenvatting per patiΓ«nt - - Toon bronverwijzingen - -6. AFSLUITING (1 min) - - Tijdsbesparing recap - - Vragen -``` - -### 7.2 Backup Plan - -| Probleem | Oplossing | -|----------|-----------| -| Internet issues | Localhost met demo data | -| Voice niet werkt | Type-only demo | -| AI API down | Pre-cached responses | -| Complete failure | Video recording | - ---- - -## 8. Risico's & Mitigatie - -**Status Update (27-12-2024):** Meeste risico's zijn gemitigeerd! βœ… - -| Risico | Kans | Impact | Mitigatie | Status | -|--------|------|--------|-----------|--------| -| Voice accuracy NL | Middel | Hoog | Deepgram NL model, fallback naar tekst | βœ… **Gemitigeerd** - Voice werkt met transcript fallback | -| Intent misclassificatie | Laag ↓ | Middel ↓ | Two-tier systeem, FallbackPicker | βœ… **Gemitigeerd** - FallbackPicker geΓ―mplementeerd (E4.S4) | -| AI latency | Laag | Middel | Local-first, Haiku model | βœ… **Gemitigeerd** - Local classifier <50ms | -| User adoption | Middel | Middel | Keuze behouden, geen dwang | βœ… **Gemitigeerd** - Interface selector (E4.S1-S3) | -| Scope creep | Laag ↓ | Laag ↓ | Strict P1-only, backlog voor rest | βœ… **Onder controle** - P1 scope behouden | -| Performance | Laag | Laag | Code splitting, lazy loading, animaties | βœ… **Gemitigeerd** - <200ms transitions (E5.S1) | -| Network errors | Laag | Laag | Offline detection, retry logic | βœ… **Gemitigeerd** - Error handler (E5.S2) | -| ~~CanvasArea blocking~~ | ~~Hoog~~ | ~~Hoog~~ | ~~E3.S0 prioriteit~~ | βœ… **OPGELOST** - E3.S0 compleet | - -**Nieuwe Risico's:** -| Risico | Kans | Impact | Mitigatie | Status | -|--------|------|--------|-----------|--------| -| Demo preparatie | Laag | Middel | E5.S4 smoke tests, rehearsal | ⏳ **In behandeling** | -| Cross-browser issues | Laag | Laag | Test in Chrome/Safari/Firefox | ⏳ **E5.S4** | -| Production deployment | Laag | Middel | Vercel deployment check | ⏳ **Post-MVP** | - -**Conclusie:** Project risico's zijn minimaal. MVP is stabiel en klaar voor testing. βœ… - ---- - -## 9. Sprint Planning (Aangepast) - -### Huidige Status (27-12-2024) -- βœ… E0: Setup & Foundation (8 SP) β€” DONE -- βœ… E1: Command Center (13 SP) β€” DONE -- βœ… E2: Intent Classification (12 SP) β€” DONE -- βœ… E3: P1 Blocks (23 SP) β€” DONE -- βœ… E4: Navigation & Auth (8 SP) β€” DONE -- πŸ”„ E5: Polish & Testing (8 SP) β€” IN PROGRESS (6/8 SP done) -- βœ… E5.S1: Block animaties (2 SP) β€” DONE -- βœ… E5.S2: Error handling (2 SP) β€” DONE -- βœ… E5.S3: Keyboard shortcuts (2 SP) β€” DONE -- ⏳ E5.S4: Smoke tests (2 SP) β€” TO DO - -**Totaal Done: 62 SP / 72 SP (86%)** - -### Sprint 3 (Voltooid): Core Wiring + Blocks -- βœ… E2.S5: Input β†’ Block wiring (2 SP) β€” DONE -- βœ… E3.S0: CanvasArea block rendering (2 SP) β€” DONE -- βœ… E3.S1: Block Container (2 SP) β€” DONE -- βœ… E3.S2: DagnotatieBlock (5 SP) β€” DONE -- **Deliverable:** "notitie jan" β†’ DagnotatieBlock werkt end-to-end βœ… - -### Sprint 4 (Voltooid): Remaining Blocks -- βœ… E3.S3: Patient search API (3 SP) β€” DONE -- βœ… E3.S4: ZoekenBlock (3 SP) β€” DONE -- βœ… E3.S5: PatientContextCard (5 SP) β€” DONE -- βœ… E3.S6: OverdrachtBlock (3 SP) β€” DONE -- **Deliverable:** Alle P1 blocks werken βœ… - -### Sprint 5: Polish & Ship (In Progress) -- βœ… E4: Navigation & Auth (8 SP) β€” DONE -- πŸ”„ E5: Polish & Testing (8 SP) β€” IN PROGRESS (6/8 SP done) - - βœ… E5.S1: Block animaties (2 SP) β€” DONE - - βœ… E5.S2: Error handling (2 SP) β€” DONE - - βœ… E5.S3: Keyboard shortcuts (2 SP) β€” DONE - - ⏳ E5.S4: Smoke tests (2 SP) β€” TO DO -- Technische debt opruimen -- **Deliverable:** Demo-ready MVP - -**Laatste 2 SP voor MVP compleet! 🎯** - ---- - -## 10. Uitbreidingen (Backlog) - -### Diagnostiek Workflow (22 SP) - -**Status:** Gepland na MVP -**Documentatie:** `bouwplan-swift-diagnostiek-workflow.md` - -| Epic | Stories | SP | Vereisten | -|------|---------|----:|-----------| -| E-D1 | Afspraak & Rapportage | 12 | E3 compleet | -| E-D2 | Diagnose Beheer | 10 | E3 compleet | - -**Pre-requisites:** -1. Swift MVP compleet (E0-E5) -2. Report type "diagnostiek" toevoegen aan REPORT_TYPES -3. SwiftIntent uitbreiden met nieuwe types -4. Entity extraction voor datum/tijd - -**Zie:** `bouwplan-swift-diagnostiek-workflow-beoordeling.md` voor details. - ---- - -## 11. Definition of Done - -Een story is **Done** wanneer: -- [ ] Code geschreven en werkend -- [ ] TypeScript types correct (geen duplicaten) -- [ ] Component responsive (mobile + desktop) -- [ ] Error states afgehandeld -- [ ] Toegankelijkheid basics (focus, labels) -- [ ] Getest in Chrome + Safari -- [ ] PR reviewed (indien team) -- [ ] Gemerged naar main - -Een epic is **Done** wanneer: -- [ ] Alle stories Done -- [ ] Integration test passed -- [ ] Demo scenario werkt - ---- - -## 12. Referenties - -### Project Documenten -- PRD: `docs/swift/swift-prd.md` -- FO: `docs/swift/swift-fo-ai.md` -- TO: `docs/swift/to-swift-v1.md` -- UX: `docs/swift/swift-ux-v2.1.md` -- Diagnostiek FO: `docs/swift/swift-fo-diagnostiek-workflow.md` -- Diagnostiek Bouwplan: `docs/swift/bouwplan-swift-diagnostiek-workflow.md` -- Beoordeling: `docs/swift/bouwplan-swift-diagnostiek-workflow-beoordeling.md` - -### Bestaande Code Referenties -- Swift Store: `stores/swift-store.ts` -- Swift Types: `lib/swift/types.ts` (SINGLE SOURCE) -- Intent Classifier: `lib/swift/intent-classifier.ts` -- Intent API: `app/api/intent/classify/route.ts` -- Command Center: `components/swift/command-center/` -- Block Container: `components/swift/blocks/block-container.tsx` - -### Bestaande EPD Code (Hergebruik) -- Command component: `components/ui/command.tsx` -- Speech streaming: `components/speech-recorder-streaming.tsx` -- Overdracht API: `app/api/overdracht/generate/route.ts` -- Report types: `lib/types/report.ts` -- Reports API: `app/api/reports/route.ts` - -### External -- Zustand: https://zustand-demo.pmnd.rs/ -- cmdk: https://cmdk.paco.me/ -- Deepgram: https://developers.deepgram.com/docs -- Claude API: https://docs.anthropic.com/ -- Framer Motion: https://www.framer.com/motion/ - ---- - -## 13. Glossary - -| Term | Betekenis | -|------|-----------| -| Swift | Projectnaam voor Contextual UI EPD | -| Command Center | Hoofdscherm met één input | -| Block | Ephemeral UI component (dagnotitie, zoeken, etc.) | -| Intent | Gebruikersintentie (dagnotitie, zoeken, overdracht) | -| Entity | GeΓ«xtraheerde data (patiΓ«ntnaam, categorie) | -| Prefill | Vooraf ingevulde data in block | -| Klassiek EPD | Traditionele menu-gebaseerde interface | -| P1 | Prioriteit 1 (MVP scope) | -| SP | Story Points (Fibonacci: 1, 2, 3, 5, 8) | -| Wiring | Koppeling tussen componenten (input β†’ API β†’ block) | - ---- - -**Versiehistorie:** - -| Versie | Datum | Auteur | Wijziging | -|--------|-------|--------|-----------| -| v1.0 | 23-12-2024 | Colin Lit | InitiΓ«le versie | -| v1.1 | 23-12-2024 | Claude | E0 + E1 voltooid (21 SP) | -| v1.2 | 23-12-2024 | Claude | E2.S1 + E2.S2 voltooid (27 SP) | -| v1.3 | 23-12-2024 | Claude | E2.S3 AI fallback voltooid (29 SP) | -| v1.4 | 23-12-2024 | Claude | E2.S1-S4 voltooid (31 SP) | -| v1.5 | 24-12-2024 | Claude | E2.S5 toegevoegd: Input β†’ Block wiring (+2 SP) | -| **v2.0** | **24-12-2024** | **Claude** | **Major update: E3.S0 toegevoegd, technische debt sectie, diagnostiek workflow referentie, sprint planning aangepast (29 stories, 72 SP)** | -| **v2.1** | **24-12-2024** | **Claude** | **E2.S5 voltooid: Input β†’ Block wiring geΓ―mplementeerd, Epic 2 compleet (33 SP done, 46%)** | -| **v2.2** | **24-12-2024** | **Claude** | **Epic 3 compleet: Alle P1 blocks geΓ―mplementeerd (E3.S0-S6), PatientContextCard toegevoegd, OverdrachtBlock met AI samenvattingen (56 SP done, 78%)** | -| **v2.3** | **24-12-2024** | **Claude** | **E5.S1 compleet: Block animaties geΓ―mplementeerd volgens UX specificatie (slide up/down met fade en scale, 200ms), Epic 4 compleet (58 SP done, 81%)** | -| **v2.4** | **27-12-2024** | **Claude** | **E5.S2 compleet: Error handling met gecentraliseerde utilities, OfflineBanner, safeFetch, retry logic, Nederlandse error messages (60 SP done, 83%)** | -| **v2.5** | **27-12-2024** | **Claude** | **E5.S3 compleet: Keyboard shortcuts geverifieerd en uitgebreid, ⌘Enter quick submit/save, visual hints, shortcuts reference (62 SP done, 86%)** | diff --git a/docs/swift/archive/keyboard-shortcuts-reference.md b/docs/swift/archive/keyboard-shortcuts-reference.md deleted file mode 100644 index 497da60..0000000 --- a/docs/swift/archive/keyboard-shortcuts-reference.md +++ /dev/null @@ -1,173 +0,0 @@ -# Swift Keyboard Shortcuts Reference - -**Versie:** 1.0 -**Datum:** 27-12-2024 -**Status:** E5.S3 - Keyboard Shortcuts Verificatie - ---- - -## 🎹 Global Shortcuts (altijd actief) - -| Shortcut | Actie | Context | Status | -|----------|-------|---------|--------| -| **⌘K** / **Ctrl+K** | Focus command input | Overal | βœ… Werkt | -| **Escape** | Sluit actief block | Als block open is | βœ… Werkt | -| **⌘Enter** / **Ctrl+Enter** | Quick submit command | Als input focus heeft | ⏳ Toe te voegen | - ---- - -## πŸ“ Command Input Shortcuts - -| Shortcut | Actie | Context | Status | -|----------|-------|---------|--------| -| **Enter** | Verstuur commando | In command input | βœ… Werkt (native form) | -| **⌘Enter** / **Ctrl+Enter** | Verstuur commando | In command input | ⏳ Toe te voegen | -| **Escape** | Clear input | In command input (optioneel) | ❌ Niet geΓ―mplementeerd | - ---- - -## πŸ” FallbackPicker Shortcuts - -| Shortcut | Actie | Context | Status | -|----------|-------|---------|--------| -| **1** | Selecteer Dagnotitie | FallbackPicker open | βœ… Werkt | -| **2** | Selecteer Zoeken | FallbackPicker open | βœ… Werkt | -| **3** | Selecteer Overdracht | FallbackPicker open | βœ… Werkt | -| **Escape** | Sluit FallbackPicker | FallbackPicker open | βœ… Werkt | - ---- - -## πŸ“‹ Block-Specific Shortcuts - -### DagnotatieBlock -| Shortcut | Actie | Context | Status | -|----------|-------|---------|--------| -| **⌘Enter** / **Ctrl+Enter** | Opslaan dagnotitie | In dagnotitie block | ⏳ Toe te voegen | -| **Escape** | Sluit block | In dagnotitie block | βœ… Werkt (global) | - -### ZoekenBlock -| Shortcut | Actie | Context | Status | -|----------|-------|---------|--------| -| **Enter** | Selecteer eerste resultaat | In zoek input | ⏳ Optioneel | -| **↓ / ↑** | Navigeer door resultaten | In zoek input | ⏳ Optioneel | -| **Escape** | Sluit block | In zoeken block | βœ… Werkt (global) | - -### OverdrachtBlock -| Shortcut | Actie | Context | Status | -|----------|-------|---------|--------| -| **Escape** | Sluit block | In overdracht block | βœ… Werkt (global) | - ---- - -## 🎯 MVP Scope (E5.S3) - -Voor de MVP implementeren we: - -### βœ… Already Working -1. **⌘K / Ctrl+K** - Focus input -2. **Escape** - Close block -3. **Enter** - Submit form (native) -4. **1-3** - FallbackPicker quick select - -### ⏳ To Add -1. **⌘Enter / Ctrl+Enter** in CommandInput - Quick submit -2. **⌘Enter / Ctrl+Enter** in DagnotatieBlock - Quick save - -### ❌ Out of Scope (Future) -1. Arrow key navigation in search results -2. Escape to clear input -3. Tab for autocomplete -4. Vim-style navigation (j/k) - ---- - -## πŸ§ͺ Test Checklist - -### Global Shortcuts -- [ ] **⌘K**: Press ⌘K β†’ Input krijgt focus -- [ ] **⌘K**: Press ⌘K from within block β†’ Input krijgt focus -- [ ] **Escape**: Open block β†’ Press Escape β†’ Block sluit -- [ ] **Escape**: FallbackPicker open β†’ Press Escape β†’ Picker sluit - -### Command Input -- [ ] **Enter**: Typ commando β†’ Press Enter β†’ Commando wordt verstuurd -- [ ] **Enter**: Leeg input β†’ Press Enter β†’ Niks gebeurt (validation) -- [ ] **⌘Enter**: Typ commando β†’ Press ⌘Enter β†’ Commando wordt verstuurd -- [ ] **⌘Enter**: Focus niet in input β†’ Press ⌘Enter β†’ Niks gebeurt - -### FallbackPicker -- [ ] **1**: FallbackPicker open β†’ Press 1 β†’ Dagnotitie opent -- [ ] **2**: FallbackPicker open β†’ Press 2 β†’ Zoeken opent -- [ ] **3**: FallbackPicker open β†’ Press 3 β†’ Overdracht opent -- [ ] **Numbers**: In input field β†’ Press 1-3 β†’ Nummer wordt getypt (niet shortcut) - -### DagnotatieBlock -- [ ] **⌘Enter**: Vul form in β†’ Press ⌘Enter β†’ Dagnotitie wordt opgeslagen -- [ ] **⌘Enter**: Form incomplete β†’ Press ⌘Enter β†’ Validation error -- [ ] **Escape**: DagnotatieBlock open β†’ Press Escape β†’ Block sluit - -### Edge Cases -- [ ] Multiple shortcuts in rapid succession (⌘K β†’ Escape β†’ Enter) -- [ ] Shortcuts werken niet tijdens isProcessing state -- [ ] Shortcuts werken op macOS (⌘) en Windows/Linux (Ctrl) -- [ ] Shortcuts conflicteren niet met browser defaults - ---- - -## πŸ“ Implementation Notes - -### Cmd vs Ctrl Detection -```typescript -// Use both metaKey (Cmd on Mac) and ctrlKey (Ctrl on Windows/Linux) -if (e.metaKey || e.ctrlKey) { - // Handle shortcut -} -``` - -### Preventing Default Behavior -```typescript -// Always preventDefault for custom shortcuts -if (e.key === 'k' && (e.metaKey || e.ctrlKey)) { - e.preventDefault(); // Prevent browser's native ⌘K - inputRef.current?.focus(); -} -``` - -### Conditional Shortcuts -```typescript -// Only handle when not in input/textarea -if (e.target instanceof HTMLInputElement || - e.target instanceof HTMLTextAreaElement) { - return; // Let native behavior handle it -} -``` - -### Accessibility -- All shortcuts should have visual hints (e.g., "⌘K" label) -- Shortcuts should work with screen readers -- Focus management must be clear (visible focus ring) - ---- - -## πŸ”§ Future Enhancements - -### Phase 2 -- **Cmd+Shift+K** - Toggle voice input -- **Cmd+/** - Show keyboard shortcuts help -- **Cmd+P** - Quick patient search -- **Cmd+N** - New dagnotitie -- **Cmd+O** - Open overdracht - -### Phase 3 -- Customizable shortcuts (user preferences) -- Vim-style modal editing -- Search results navigation (arrow keys) -- Multi-block shortcuts (Cmd+1, Cmd+2, etc.) - ---- - -## πŸ“š Resources - -- [MDN: KeyboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent) -- [Keyboard Event Viewer](https://keycode.info/) -- [macOS Keyboard Shortcuts Guidelines](https://developer.apple.com/design/human-interface-guidelines/keyboards) diff --git a/docs/swift/archive/nextgen-epd-analyse-ephemeral-ui-perspectieven.md b/docs/swift/archive/nextgen-epd-analyse-ephemeral-ui-perspectieven.md deleted file mode 100644 index f57d6f7..0000000 --- a/docs/swift/archive/nextgen-epd-analyse-ephemeral-ui-perspectieven.md +++ /dev/null @@ -1,675 +0,0 @@ -# Analyse Ephemeral UI EPD - Multi-Perspectief Review - -**Document:** Analyse PRD Ephemeral UI EPD v1.0 -**Datum:** december 2024 -**Reviewers:** Lead Developer, UX Designer, Frontend Developer, Product Owner - ---- - -## 1. Lead Developer Perspectief - -### 1.1 Technische Haalbaarheid - -**Verdict:** βœ… Haalbaar met bestaande stack - -De PRD vraagt om functionaliteit die grotendeels al bestaat in de codebase. De technische uitdaging zit niet in de bouwblokken zelf, maar in de orchestratielaag. - -**Wat we al hebben:** -| Component | Status | Kwaliteit | -|-----------|--------|-----------| -| Next.js 14 App Router | βœ… | Production-ready | -| Supabase Auth + RLS | βœ… | Volledig geconfigureerd | -| Claude API integratie | βœ… | Werkt voor behandelplan + overdracht | -| Deepgram STT | βœ… | Streaming + batch transcriptie | -| TipTap Rich Text | βœ… | Met voice-insert support | -| shadcn/ui + Tailwind | βœ… | 20+ componenten | - -**Wat nieuw gebouwd moet worden:** - -``` -Prioriteit 1 (Kritiek): -β”œβ”€β”€ /api/intent/classify # AI intent classificatie -β”œβ”€β”€ /app/command-center # Nieuwe entry point -└── stores/commandCenter.ts # State management - -Prioriteit 2 (Bouwblok wrappers): -β”œβ”€β”€ components/building-blocks/BlockContainer.tsx -β”œβ”€β”€ components/building-blocks/PatientResolver.tsx -└── components/building-blocks/EntityExtractor.tsx - -Prioriteit 3 (Nieuwe blokken): -β”œβ”€β”€ ZoekenBlock.tsx # Patient search UI -└── MetingenBlock.tsx # Vitals input form -``` - -### 1.2 Architectuurbeslissingen - -**State Management:** -Aanbeveling: **Zustand** boven Context API -- Command Center heeft complexe state (activeBlock, activePatient, transcript, recentActions) -- Zustand is al impliciet beschikbaar via React patterns in codebase -- Geen prop drilling, geen provider nesting - -```typescript -// Voorgestelde store structuur -interface CommandCenterStore { - // UI State - activeBlock: BlockType | null; - isListening: boolean; - transcript: string; - - // Context - activePatient: Patient | null; - recentActions: Action[]; - shiftInfo: ShiftInfo; - - // Pre-fill data extracted from intent - prefillData: Record; -} -``` - -**Intent Classification:** -Aanbeveling: **Streaming response** met confidence threshold - -```typescript -// Twee-staps flow -1. Quick classification (<100ms): regex + keyword matching -2. AI fallback (>100ms): Claude voor ambigue input - -// Voorbeeld -"notitie jan" β†’ Quick match: intent=dagnotitie, patient="jan" -"ik heb net iets besproken" β†’ AI needed: wat? met wie? -``` - -**API Design:** -``` -POST /api/intent/classify - Input: { text: string, context: { activePatient?, shift? } } - Output: { intent, confidence, entities, clarification? } - -GET /api/context - Output: { user, shift, patients, pendingItems } -``` - -### 1.3 Risico's & Mitigaties - -| Risico | Impact | Mitigatie | -|--------|--------|-----------| -| Intent misclassificatie | Hoog | Fallback naar blok-selector UI | -| Latency AI calls | Medium | Local-first matching, AI als fallback | -| Entity extraction fout | Medium | "Bedoelde je X?" confirmation flow | -| State sync issues | Medium | Optimistic UI + server reconciliation | -| Voice in lawaaierige omgeving | Medium | Push-to-talk, geen continuous listening | - -### 1.4 Technische Schuld Risico - -**Laag risico** - We bouwen bovenop bestaande patterns: -- Bestaande API routes blijven werken -- Bouwblokken zijn wrappers rond bestaande componenten -- Geen database schema wijzigingen nodig -- Geen breaking changes voor huidige EPD flows - -### 1.5 Aanbeveling - -**Go/No-Go:** βœ… GO - -Start met Command Center + Intent API + 2 blokken (Rapportage, Dagnotitie). -Itereer op basis van intent accuracy metrics voordat we alle 8 blokken bouwen. - ---- - -## 2. UX Designer Perspectief - -### 2.1 Concept Evaluatie - -**De belofte:** Van 12 klikken naar 1 zin. - -Dit is een fundamentele paradigma-shift. Geen menu's, geen navigatie-leren, geen "waar zit dat ook alweer?" De gebruiker spreekt intentie, het systeem reageert. - -**Sterktes van het concept:** - -1. **Cognitive load reductie** - Zorgverleners hoeven geen mentaal model van het EPD te hebben -2. **Context-awareness** - Systeem weet wie je bent, welke dienst, welke patiΓ«nten -3. **Hands-free potentieel** - Voice-first past bij zorg (handschoenen, hygiΓ«ne) -4. **Ephemeral = focus** - Alleen wat je nu nodig hebt, geen afleiding - -**Zorgen:** - -1. **Discoverability** - Hoe weet de gebruiker wat mogelijk is? -2. **Error recovery** - Wat als het systeem verkeerd begrijpt? -3. **Power users** - Willen sommigen toch sneltoetsen/directe toegang? -4. **Trust** - "Heeft het systeem mijn notitie wel opgeslagen?" - -### 2.2 Interaction Design Analyse - -**Command Center Flow:** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 🎀 Wat wil je doen? β”‚ β”‚ -β”‚ β”‚ ____________________________________________ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ πŸ’‘ Voorbeelden: "notitie voor Jan", "overdracht", β”‚ β”‚ -β”‚ β”‚ "mijn afspraken", "zoek Marie" β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Context: Ochtend dienst Β· 8 patiΓ«nten Β· 2 actiepunten β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [ Actief bouwblok verschijnt hier ] β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Recent: [Jan - Notitie βœ“] [Overdracht 14:00] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Kritieke UX Momenten:** - -| Moment | Risico | Design Oplossing | -|--------|--------|------------------| -| Eerste gebruik | "Wat kan ik zeggen?" | Voorbeelden tonen, onboarding hints | -| Ambigue input | Frustratie bij verkeerde interpretatie | "Bedoelde je..." met opties | -| Mid-task switch | Context verlies | "Opslaan als concept?" modal | -| Na voltooiing | Onzekerheid of het werkte | Duidelijke bevestiging + undo optie | -| Geen match | Doodlopende straat | Fallback naar visuele blok-picker | - -### 2.3 Microinteracties - -**Voice Input Feedback:** -``` -[Idle] β†’ Grijze microfoon -[Listening] β†’ Pulserende blauwe ring + live transcript -[Processing]β†’ Spinner + "Even denken..." -[Matched] β†’ Groene check + smooth transition naar blok -[Unclear] β†’ Oranje indicator + clarificatie vraag -``` - -**Blok Transities:** -- **In:** Slide-up met fade (200ms) -- **Minimize:** Collapse naar badge in "Recent" row -- **Close:** Fade-out met success toast - -**Pre-fill Animatie:** -Wanneer systeem velden invult op basis van intent: -- Velden highlighten kort (geel flash) -- Sequential fill (niet alles tegelijk) -- "Automatisch ingevuld" label bij pre-filled velden - -### 2.4 Accessibility Overwegingen - -| Aspect | Vereiste | Implementatie | -|--------|----------|---------------| -| Keyboard-only | Moet volledig werken zonder voice | Tab navigation, Enter to submit | -| Screen readers | Blok-wissels aangekondigd | ARIA live regions | -| Motor impairments | Grote touch targets | Min 44x44px buttons | -| Cognitieve load | Niet te veel tegelijk | Max 1 actief blok | - -### 2.5 Fallback Strategie - -**De "Noodrem":** -Als conversational interface faalt, moet er altijd een visuele fallback zijn. - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Ik begreep dat niet helemaal. Wat wil je doen? β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ“ β”‚ β”‚ πŸ‘€ β”‚ β”‚ πŸ“‹ β”‚ β”‚ πŸ”„ β”‚ β”‚ -β”‚ β”‚Notitie β”‚ β”‚ Intake β”‚ β”‚ Plan β”‚ β”‚Overdrachtβ”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ” β”‚ β”‚ πŸ“… β”‚ β”‚ πŸ’Š β”‚ β”‚ πŸ“Š β”‚ β”‚ -β”‚ β”‚ Zoeken β”‚ β”‚ Agenda β”‚ β”‚Medicatieβ”‚ β”‚Metingen β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 2.6 Aanbeveling - -**Go/No-Go:** βœ… GO met voorwaarden - -1. Bouw de fallback picker EERST - dit is je vangnet -2. Investeer in microinteracties - ze maken of breken de "magie" -3. User testing na eerste 2 blokken - niet na alle 8 -4. Metrics verzamelen: intent accuracy, tijd-tot-taak, fallback usage - ---- - -## 3. Frontend Developer Perspectief - -### 3.1 Component Architectuur - -**Huidige staat:** Goed gestructureerd, maar bouwblok-specifiek - -We moeten bestaande componenten wrappen om ze "ephemeral" te maken. Dit vereist een abstractielaag. - -**Voorgestelde structuur:** - -``` -components/ -β”œβ”€β”€ building-blocks/ -β”‚ β”œβ”€β”€ core/ -β”‚ β”‚ β”œβ”€β”€ BlockContainer.tsx # Wrapper met header, minimize, close -β”‚ β”‚ β”œβ”€β”€ BlockHeader.tsx # Titel + acties -β”‚ β”‚ β”œβ”€β”€ BlockFooter.tsx # Save/Cancel buttons -β”‚ β”‚ └── PrefilledField.tsx # Highlight voor auto-filled -β”‚ β”‚ -β”‚ β”œβ”€β”€ rapportage/ -β”‚ β”‚ β”œβ”€β”€ RapportageBlock.tsx # Wrapper rond ReportComposer -β”‚ β”‚ └── RapportageBlock.types.ts -β”‚ β”‚ -β”‚ β”œβ”€β”€ dagnotitie/ -β”‚ β”‚ β”œβ”€β”€ DagnotitieBlock.tsx # Quick entry form -β”‚ β”‚ └── DagnotitieBlock.types.ts -β”‚ β”‚ -β”‚ β”œβ”€β”€ zoeken/ -β”‚ β”‚ β”œβ”€β”€ ZoekenBlock.tsx # cmdk-based search -β”‚ β”‚ β”œβ”€β”€ PatientCard.tsx # Search result card -β”‚ β”‚ └── ZoekenBlock.types.ts -β”‚ β”‚ -β”‚ └── ... (andere blokken) -β”‚ -β”œβ”€β”€ command-center/ -β”‚ β”œβ”€β”€ CommandInput.tsx # Text + voice input -β”‚ β”œβ”€β”€ VoiceIndicator.tsx # Listening state UI -β”‚ β”œβ”€β”€ ContextBar.tsx # Shift info, patient count -β”‚ β”œβ”€β”€ RecentActions.tsx # Minimized blocks -β”‚ β”œβ”€β”€ BlockPicker.tsx # Fallback grid -β”‚ └── ClarificationDialog.tsx # "Bedoelde je...?" -``` - -### 3.2 Hergebruik Analyse - -**Direct herbruikbaar (copy):** -```typescript -// Volledig herbruikbaar -import { RichTextEditor } from '@/components/rich-text-editor' -import { SpeechRecorder } from '@/components/speech-recorder' -import { Timeline } from '@/components/ui/timeline' -import { Command } from '@/components/ui/command' // voor zoeken - -// Bestaande forms met minimale aanpassing -ReportComposer β†’ RapportageBlock (wrap + simplify) -BehandelplanView β†’ BehandelplanBlock (read-only + edit mode toggle) -AgendaCalendar β†’ AgendaBlock (date-filtered view) -``` - -**Moet gerefactored worden:** -```typescript -// Te gekoppeld aan page-specifieke logica -IntakeTabs β†’ Moet ontkoppeld van [intakeId] routing -VitalsBlock β†’ Alleen display, geen input form -PatientList β†’ Moet naar PatientCard + search results -``` - -**Nieuw te bouwen:** -```typescript -// Helemaal nieuw -CommandInput.tsx // ~150 lines -BlockContainer.tsx // ~100 lines -ZoekenBlock.tsx // ~200 lines -MetingenBlock.tsx // ~150 lines -DagnotitieBlock.tsx // ~120 lines (simplified from ReportComposer) -ClarificationDialog.tsx // ~80 lines -``` - -### 3.3 State Management Implementatie - -**Keuze: Zustand** - -```typescript -// stores/command-center-store.ts -import { create } from 'zustand' -import { devtools, persist } from 'zustand/middleware' - -interface CommandCenterState { - // Block state - activeBlock: BlockType | null - blockData: Record - minimizedBlocks: MinimizedBlock[] - - // Context - activePatient: Patient | null - shiftInfo: ShiftInfo | null - - // Voice - isListening: boolean - transcript: string - interimTranscript: string - - // Recent - recentActions: Action[] - - // Actions - openBlock: (type: BlockType, prefill?: Record) => void - closeBlock: () => void - minimizeBlock: () => void - setActivePatient: (patient: Patient | null) => void - setTranscript: (text: string) => void - addRecentAction: (action: Action) => void -} - -export const useCommandCenter = create()( - devtools( - persist( - (set, get) => ({ - // ... implementation - }), - { name: 'command-center' } - ) - ) -) -``` - -### 3.4 Intent Handling Flow - -```typescript -// hooks/use-intent.ts -export function useIntent() { - const { openBlock, setActivePatient, activePatient } = useCommandCenter() - - const processInput = async (text: string) => { - // 1. Quick local match - const quickMatch = quickClassify(text) - if (quickMatch.confidence > 0.9) { - return handleIntent(quickMatch) - } - - // 2. AI classification - const result = await fetch('/api/intent/classify', { - method: 'POST', - body: JSON.stringify({ - text, - context: { activePatient } - }) - }).then(r => r.json()) - - // 3. Handle result - if (result.clarification_needed) { - return { type: 'clarify', question: result.clarification_question } - } - - if (result.entities.patient_name && !activePatient) { - const patient = await resolvePatient(result.entities.patient_name) - if (patient.length > 1) { - return { type: 'select_patient', options: patient } - } - setActivePatient(patient[0]) - } - - openBlock(result.intent, result.entities) - return { type: 'success', block: result.intent } - } - - return { processInput } -} -``` - -### 3.5 Performance Optimalisatie - -**Bundle splitting:** -```typescript -// Lazy load blokken -const RapportageBlock = dynamic( - () => import('@/components/building-blocks/rapportage/RapportageBlock'), - { loading: () => } -) - -const BehandelplanBlock = dynamic( - () => import('@/components/building-blocks/behandelplan/BehandelplanBlock'), - { loading: () => } -) -``` - -**Prefetching:** -```typescript -// Prefetch meest gebruikte blokken bij mount -useEffect(() => { - import('@/components/building-blocks/rapportage/RapportageBlock') - import('@/components/building-blocks/dagnotitie/DagnotitieBlock') -}, []) -``` - -**Voice optimization:** -```typescript -// Reuse Deepgram connection -const deepgramRef = useRef(null) - -// Start listening immediately on mic click (no API call delay) -// Token already fetched at mount -``` - -### 3.6 Testing Strategy - -```typescript -// Kritieke test scenarios -describe('CommandCenter', () => { - it('opens RapportageBlock for "notitie voor jan"') - it('asks clarification for ambiguous input') - it('pre-fills patient when mentioned by name') - it('falls back to BlockPicker on unknown intent') - it('minimizes block and shows in recent') - it('restores minimized block on click') -}) - -describe('Intent Classification', () => { - it('handles Dutch medical vocabulary') - it('extracts patient name from natural speech') - it('returns low confidence for gibberish') -}) -``` - -### 3.7 Aanbeveling - -**Go/No-Go:** βœ… GO - -**Geschatte effort:** - -| Component | Uren | Complexiteit | -|-----------|------|--------------| -| CommandCenter layout | 4h | Low | -| CommandInput + Voice | 6h | Medium | -| BlockContainer abstraction | 4h | Medium | -| RapportageBlock wrapper | 3h | Low | -| DagnotitieBlock (new) | 5h | Medium | -| ZoekenBlock (new) | 6h | Medium | -| Intent API route | 4h | Medium | -| Zustand store | 3h | Low | -| Animations/transitions | 4h | Low | -| **Totaal MVP** | **~40h** | - | - ---- - -## 4. Product Owner Perspectief - -### 4.1 Business Case Analyse - -**Doelstelling:** Demo-ready voor Nedap gesprek (7 jan) - -Dit is een **showcase project** met twee doelen: -1. Thought leadership positionering -2. Concrete gespreksstarter voor enterprise partnerships - -**ROI Potentieel:** - -| Metric | Traditioneel EPD | Ephemeral UI | Impact | -|--------|------------------|--------------|--------| -| Tijd per rapportage | 3-5 min | <1 min | 70% reductie | -| Klikken per actie | 8-15 | 1-3 | 80% reductie | -| Training tijd | 2-4 dagen | 1 uur | 90% reductie | -| Error rate (verkeerde scherm) | 15% | <5% | 70% reductie | - -### 4.2 Scope Prioritering - -**Must Have (Demo MVP):** -- [ ] Command Center met text input -- [ ] Voice input (Deepgram werkt al) -- [ ] 2 werkende blokken: Rapportage + Dagnotitie -- [ ] Intent classification (happy path) -- [ ] Pre-fill van patient naam -- [ ] Visuele fallback (blok picker) - -**Should Have (Demo Enhanced):** -- [ ] Overdracht blok met AI samenvatting -- [ ] Zoeken blok -- [ ] Recent actions tracking -- [ ] Context bar (dienst info) -- [ ] Animaties en polish - -**Could Have (Post-Demo):** -- [ ] Behandelplan blok -- [ ] Agenda blok -- [ ] Metingen blok -- [ ] Intake blok -- [ ] Multi-patient context switching - -**Won't Have (v1):** -- Offline mode -- Mobile native app -- Multi-user realtime -- FHIR integratie -- Full ambient listening - -### 4.3 Risico Assessment - -| Risico | Waarschijnlijkheid | Impact | Mitigatie | -|--------|-------------------|--------|-----------| -| Demo niet klaar 7 jan | Medium | Hoog | Focus op 2 blokken, polish later | -| Intent accuracy <85% | Medium | Hoog | Fallback UI prominent aanwezig | -| Voice werkt niet live | Laag | Medium | Tekst input als backup | -| Nedap niet geΓ―nteresseerd | Medium | Medium | Parallel outreach naar andere partijen | -| "Speeltje" perceptie | Medium | Medium | Focus op tijdsbesparing metrics | - -### 4.4 Stakeholder Waarde - -**Voor Zorgverleners:** -- Minder administratie, meer tijd voor zorg -- Geen menu-navigatie stress -- Voice input tijdens handeling - -**Voor Zorgorganisaties:** -- Lagere training kosten -- Hogere EPD adoptie -- Minder documentatie-fouten - -**Voor IT/Beheer:** -- Moderne tech stack (Next.js, Supabase) -- AI-first architectuur -- Schaalbaar en maintainable - -### 4.5 Demo Scenario's - -**Scenario 1: De Drukke Ochtend (2 min)** -``` -Verpleegkundige start dienst β†’ Command Center opent -"Mijn patiΓ«nten vandaag" β†’ Overzicht met prioriteiten -"Notitie voor Jan de Vries: medicatie uitgereikt, geen bijzonderheden" -β†’ Dagnotitie pre-filled, 1-click save -``` - -**Scenario 2: Na een Gesprek (1 min)** -``` -Behandelaar na sessie β†’ Voice inspreken -"Ik heb net een gesprek gehad met mevrouw Jansen over haar angstklachten" -β†’ Rapportage blok opent, patient pre-filled -β†’ AI structureert de dictatie -β†’ Save -``` - -**Scenario 3: Overdracht (1 min)** -``` -Dienst eindigt β†’ "Overdracht" -β†’ AI genereert samenvatting van de dag -β†’ Aandachtspunten gemarkeerd -β†’ Klaar voor collega -``` - -### 4.6 Success Metrics - -**Demo Success:** -- [ ] 3 scenario's foutloos uitvoeren -- [ ] <5 seconden van input tot blok open -- [ ] "Wow" reactie van stakeholders -- [ ] Concrete vervolgafspraak - -**Product Success (post-launch):** -- Intent accuracy >85% -- Fallback usage <20% -- Tijd-tot-taak 50% lager dan traditioneel -- User satisfaction >4/5 - -### 4.7 Go-to-Market - -**Fase 1: Internal Demo (Week 1-2)** -- Bouwen MVP -- Interne testing - -**Fase 2: Stakeholder Demo (Week 3)** -- Nedap presentatie (7 jan) -- LinkedIn content (4 posts gepland) - -**Fase 3: Pilot (Q1 2025)** -- 1 zorginstelling -- Real user feedback -- Iteratie op intent accuracy - -**Fase 4: Scale (Q2 2025)** -- Meerdere instellingen -- Enterprise features -- Mogelijke partnership/overname gesprekken - -### 4.8 Aanbeveling - -**Go/No-Go:** βœ… GO - -**Voorwaarden:** -1. Scope beperken tot 2-3 blokken voor demo -2. Fallback UI is verplicht (geen "het werkt alleen met AI") -3. Realistische demo verwachtingen (happy path) -4. LinkedIn content parallel voorbereiden - ---- - -## 5. Gezamenlijke Conclusie - -### Consensus: βœ… GO - -Alle vier de perspectieven zijn positief, met de volgende gedeelde voorwaarden: - -**Kritieke Succesfactoren:** -1. **Fallback first** - Bouw de visuele blok-picker voordat je intent bouwt -2. **Scope discipline** - 2 blokken voor demo, niet 8 -3. **Intent accuracy** - Meet en optimaliseer continue -4. **User testing vroeg** - Niet wachten tot alles "af" is - -**Gedeelde Risico's:** -- Intent misclassificatie (mitigatie: fallback UI) -- Demo deadline druk (mitigatie: scope beperken) -- "Speeltje" perceptie (mitigatie: focus op metrics) - -**Next Steps:** -1. [ ] Command Center basis layout (Frontend) -2. [ ] Intent classification API (Lead Dev) -3. [ ] UX mockups voor microinteracties (UX) -4. [ ] Demo scenario scripts (PO) - ---- - -## Appendix: Decision Log - -| Beslissing | Optie Gekozen | Rationale | -|------------|---------------|-----------| -| State management | Zustand | Lightweight, geen provider nesting | -| Intent approach | Local + AI fallback | Snelheid + accuracy balans | -| Voice library | Deepgram (bestaand) | Al geΓ―ntegreerd, werkt goed | -| Blok architectuur | Wrapper pattern | Maximaal hergebruik bestaande code | -| Demo scope | 2-3 blokken | Realistische deadline | - ---- - -*Document gegenereerd op basis van PRD analyse en codebase review.* diff --git a/docs/swift/archive/nextgen-epd-claude-vision-epd.txt b/docs/swift/archive/nextgen-epd-claude-vision-epd.txt deleted file mode 100644 index d23583c..0000000 --- a/docs/swift/archive/nextgen-epd-claude-vision-epd.txt +++ /dev/null @@ -1,217 +0,0 @@ -> denk even mee als innovatie-expert en visonair. We hebben met moderne ai-tooling (jij, claude) een epd vrij traditioneel epd gebouwd. maar hoe zou een epd er over 5 -jaar uit zien? - -● Goede vraag. Laat me meedenken over waar EPD's naartoe gaan. - - Het huidige paradigma: formulieren invullen - - Wat we nu gebouwd hebben (en wat 95% van de EPD's doet): - - Mens vult data in β†’ systeem slaat op β†’ mens leest later terug - - Gestructureerde formulieren, dropdown menus, verplichte velden - - De zorgverlener werkt voor het systeem - - Het paradigma over 5 jaar: ambient intelligence - - 1. Van input naar capture - - Geen formulieren meer. Het systeem luistert mee tijdens zorgmomenten: - - Gesprekken met patiΓ«nten worden real-time getranscribeerd - - Computer vision herkent handelingen (ADL, medicatie toediening) - - Wearables van patiΓ«nten streamen continuous vitals - - De AI stelt: "Ik zag dat je mevrouw Jansen hielp met wassen en zij klaagde over pijn in haar heup - klopt dat?" - - 2. Van dossier naar co-piloot - - Het EPD is niet meer een archief maar een assistent: - - "Meneer de Vries heeft 3 nachten slecht geslapen, zijn medicatie is vorige week aangepast, en zijn dochter belt morgen. Wil je dit bespreken in de overdracht?" - - Proactieve alerts: "Dit gedragspatroon lijkt op wat we 6 maanden geleden zagen voor de crisis" - - Real-time beslissingsondersteuning tijdens het zorgmoment, niet achteraf - - 3. Van silos naar netwerk - - - Alle zorgverleners (huisarts, specialist, thuiszorg, apotheek) zien dezelfde patiΓ«nt - - AI vertaalt tussen domeinen: "De cardioloog schreef X, dat betekent voor jullie verpleegkundige zorg: Y" - - PatiΓ«nt heeft eigen toegang en kan toevoegen aan hun dossier - - 4. Van reactief naar predictief - - - Machine learning op populatieniveau voorspelt: "PatiΓ«nten met dit profiel hebben 40% kans op val binnen 2 weken" - - Preventieve interventies worden voorgesteld vΓ³Γ³r het incident - - Resource planning: "Volgende week verwachten we 3 extra high-care momenten" - - 5. Van documentatie naar narratief - - - AI genereert leesbare verhalen in plaats van bullet points - - Automatische samenvatting op het juiste niveau (arts krijgt andere view dan familie) - - Voice-first interface: "Wat is er gebeurd met mevrouw Jansen deze week?" - - Concrete features die we nu al zouden kunnen bouwen - - | Nu haalbaar | 2-3 jaar | 5 jaar | - |--------------------------|--------------------------|-----------------------------| - | Voice-to-text rapportage | Ambient transcriptie | Volledig hands-free capture | - | AI-samenvattingen | Proactieve alerts | Predictieve interventies | - | Gestructureerde data | Cross-systeem integratie | Unified patient graph | - | Dashboard views | Conversational interface | AR/spatial computing | - - De fundamentele shift - - Nu: De zorgverlener is een data-entry clerk die ook zorg levert - Straks: De zorgverlener levert zorg, het systeem observeert en ondersteunt - - --- - Welke richting spreekt je aan? Ik kan dieper ingaan op een specifiek aspect, of we kunnen brainstormen over wat we nu al kunnen toevoegen aan dit prototype dat richting die visie beweegt. - -> Hoe ziet dat er dan ongeveer uit? Wat voor forntend heb je dan? - -● Goede vraag. Laat me het concreet maken. - - Het huidige model: "Cockpit met 100 knoppen" - - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ [Menu] [PatiΓ«nten] [Agenda] [Rapportage] [Medicatie] [...] β”‚ - β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ - β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ - β”‚ β”‚ Patient β”‚ β”‚ Formulier β”‚ β”‚ - β”‚ β”‚ Lijst β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ - β”‚ β”‚ β”‚ β”‚ β”‚ Categorie: [Dropdown β–Ό] β”‚ β”‚ β”‚ - β”‚ β”‚ > Jansen β”‚ β”‚ β”‚ Datum: [__/__/____] β”‚ β”‚ β”‚ - β”‚ β”‚ Vries β”‚ β”‚ β”‚ Tijd: [__:__] β”‚ β”‚ β”‚ - β”‚ β”‚ Berg β”‚ β”‚ β”‚ Beschrijving: β”‚ β”‚ β”‚ - β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ - β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ - β”‚ β”‚ β”‚ β”‚ β”‚ [Opslaan] [Annuleren] β”‚ β”‚ β”‚ - β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - - De zorgverlener moet: navigeren β†’ zoeken β†’ klikken β†’ typen β†’ valideren β†’ opslaan - - --- - Het toekomstige model: "Intelligente gesprekspartner" - - Primaire interface: Conversationeel + Contextueel - - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ β”‚ - β”‚ Goedemiddag Marieke. Je hebt dienst op afdeling 2. β”‚ - β”‚ β”‚ - β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ - β”‚ β”‚ πŸ”΄ Mevr. Jansen (K204) - onrustige nacht, 2x geval- β”‚ β”‚ - β”‚ β”‚ len, dochter belt om 14:00 β”‚ β”‚ - β”‚ β”‚ β”‚ β”‚ - β”‚ β”‚ 🟑 Dhr. de Vries (K208) - nieuwe medicatie sinds β”‚ β”‚ - β”‚ β”‚ gisteren, monitor bijwerkingen β”‚ β”‚ - β”‚ β”‚ β”‚ β”‚ - β”‚ β”‚ 🟒 6 andere patiΓ«nten - geen bijzonderheden β”‚ β”‚ - β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ - β”‚ β”‚ - β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ - β”‚ β”‚ 🎀 "Ik kom net bij mevrouw Jansen, ze is wat β”‚ β”‚ - β”‚ β”‚ rustiger nu maar klaagt over hoofdpijn" β”‚ β”‚ - β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ - β”‚ β”‚ - β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ - β”‚ β”‚ πŸ’¬ Genoteerd. Gezien de valincidenten vannacht en β”‚ β”‚ - β”‚ β”‚ de hoofdpijn - wil je dat ik de arts informeer? β”‚ β”‚ - β”‚ β”‚ β”‚ β”‚ - β”‚ β”‚ [Ja, informeer arts] [Nee, ik monitor zelf] β”‚ β”‚ - β”‚ β”‚ β”‚ β”‚ - β”‚ β”‚ πŸ“‹ Ik heb alvast toegevoegd: β”‚ β”‚ - β”‚ β”‚ β€’ Observatie: rustiger, hoofdpijnklacht β”‚ β”‚ - β”‚ β”‚ β€’ Link naar valincidenten vannacht β”‚ β”‚ - β”‚ β”‚ β€’ Reminder: bel dochter 14:00 β”‚ β”‚ - β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ - β”‚ β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - - --- - De shift in UI-paradigma's - - | Aspect | Nu | Straks | - |-----------|---------------------------|-------------------------------------------| - | Navigatie | Menu's, tabs, breadcrumbs | Context-aware, AI bepaalt wat relevant is | - | Input | Formulieren, dropdowns | Voice-first, bevestig/corrigeer | - | Schermen | 50+ verschillende views | 2-3 adaptieve views | - | Zoeken | Filters, queries | "Wat wil je weten?" | - | Actie | Klik-klik-klik-opslaan | Conversatie β†’ bevestiging | - - --- - Drie hoofdmodi - - 1. Ambient modus (tijdens zorgverlening) - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ 🎀 Luistert... β”‚ - β”‚ β”‚ - β”‚ Mevr. Jansen - K204 β”‚ - β”‚ ──────────────────────── β”‚ - β”‚ "...doet pijn als ik β”‚ - β”‚ zo beweeg..." β”‚ - β”‚ β”‚ - β”‚ πŸ“ Concept: β”‚ - β”‚ β€’ Pijnklacht bij beweging β”‚ - β”‚ β€’ Locatie: [vul aan] β”‚ - β”‚ β”‚ - β”‚ [Pauzeer] [Corrigeer] β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - Klein, onopvallend, draait op telefoon/tablet/smart display in de kamer. - - 2. Overdracht modus (briefing) - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ OVERDRACHT 15:00 β”‚ - β”‚ β”‚ - β”‚ "Drie patiΓ«nten hebben aandacht nodig deze dienst. β”‚ - β”‚ Mevrouw Jansen heeft een onrustige nacht gehad met β”‚ - β”‚ twee valincidenten. Ze is nu rustiger maar klaagt β”‚ - β”‚ over hoofdpijn. Haar dochter belt om 14:00..." β”‚ - β”‚ β”‚ - β”‚ ▢️ πŸ”Š ●●●○○○○○○○ β”‚ - β”‚ β”‚ - β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ - β”‚ β”‚ Jansen β”‚ β”‚ Vries β”‚ β”‚ Berg β”‚ β”‚ - β”‚ β”‚ πŸ”΄ Hoog β”‚ β”‚ 🟑 Mid β”‚ β”‚ 🟒 Laag β”‚ β”‚ - β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ - β”‚ β”‚ - β”‚ "Vertel me meer over mevrouw Jansen" β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - Voice-navigatie, visuele ondersteuning, drill-down on demand. - - 3. Deep-dive modus (wanneer je Γ©cht moet graven) - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ πŸ” "Toon me alle valincidenten van Jansen afgelopen maand" β”‚ - β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ - β”‚ β”‚ - β”‚ πŸ“Š Analyse: 4 incidenten in 30 dagen (verhoogd risico) β”‚ - β”‚ β”‚ - β”‚ Tijdlijn: Correlaties: β”‚ - β”‚ ────────── ───────────── β”‚ - β”‚ 12 dec (nacht) β†’ Na slaapmed aanpassing β”‚ - β”‚ 18 dec (nacht) β†’ Na slaapmed aanpassing β”‚ - β”‚ 18 dec (nacht) β†’ Na slaapmed aanpassing β”‚ - β”‚ 8 dec (ochtend) β†’ Lage bloeddruk gemeten β”‚ - β”‚ β”‚ - β”‚ πŸ’‘ Suggestie: Medicatiereview aanvragen? De incidenten β”‚ - β”‚ correleren met de slaapmed aanpassing van 10 dec. β”‚ - β”‚ β”‚ - β”‚ [Vraag medicatiereview aan] [Meer context] [Exporteer] β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - Nog steeds conversationeel, maar met rijke visualisatie. - - --- - Technisch: wat verandert er? - - | Component | Nu | Straks | - |--------------------|--------------------|-------------------------------------| - | Frontend framework | React + forms | React + conversational UI + voice | - | State | Form state, CRUD | Conversation context, AI memory | - | API | REST endpoints | Streaming, real-time, WebSocket | - | Database | Relational queries | Vector search + semantic queries | - | Auth | Login + RLS | Continuous auth (voice, biometrics) | - - --- - Wat kunnen we nu bouwen als proof-of-concept? - - 1. Conversational rapportage - voice input β†’ AI structureert β†’ bevestig - 2. Smart overdracht - niet alleen samenvatten, maar prioriteren en adviseren - 3. Vraag-antwoord interface - "Wat is er gebeurd met Jansen deze week?" \ No newline at end of file diff --git a/docs/swift/archive/nextgen-epd-mvp-prioritering-ephemeral-ui.md b/docs/swift/archive/nextgen-epd-mvp-prioritering-ephemeral-ui.md deleted file mode 100644 index 55c2a97..0000000 --- a/docs/swift/archive/nextgen-epd-mvp-prioritering-ephemeral-ui.md +++ /dev/null @@ -1,512 +0,0 @@ -# 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 - 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 - onComplete: (result: unknown) => void - onClose: () => void -} - -// BlockContainer handelt header, minimize, close - - - -``` - ---- - -## 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.* diff --git a/docs/swift/archive/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md b/docs/swift/archive/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md deleted file mode 100644 index 1a63c4f..0000000 --- a/docs/swift/archive/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md +++ /dev/null @@ -1,430 +0,0 @@ -# Onderzoeksverslag: UX/UI Patterns voor Ephemeral UI EPD - -**Document:** UX/UI Research & Best Practices -**Datum:** december 2024 -**Status:** Definitief -**Onderzoeksmethode:** Desk research, marktanalyse, design pattern analyse - ---- - -## 1. Executive Summary - -Dit onderzoek analyseert de beste UX/UI patterns voor het Ephemeral UI EPD concept. De conclusie is dat een **hybrid approach** de beste keuze is: natural language input gecombineerd met voorgedefinieerde, gestructureerde UI-bouwblokken. - -**Kernbevindingen:** -- Ambient Clinical Intelligence is de dominante trend (markt groeit 37% per jaar) -- Pure conversational UI is te onvoorspelbaar voor zorg -- Command palette pattern (cmdk) is de beste basis voor intent-input -- Two-tier intent classification (local + AI fallback) biedt optimale snelheid -- Fallback UI is essentieel voor vertrouwen - ---- - -## 2. Marktanalyse: Ambient Clinical Intelligence - -### 2.1 Marktomvang & Groei - -| Metric | Waarde | Bron | -|--------|--------|------| -| Marktwaarde 2024 | $468 miljoen | Nova One Advisor | -| Verwacht 2034 | $11,5 miljard | Nova One Advisor | -| CAGR | 37,87% | Nova One Advisor | -| Clinical documentation share | 18% van markt | Nova One Advisor | -| NLP-powered agents | 33% marktaandeel | Nova One Advisor | - -### 2.2 Belangrijkste Spelers - -| Vendor | Product | Aanpak | Adoptie | -|--------|---------|--------|---------| -| **Microsoft/Nuance** | DAX Copilot | Ambient listening β†’ full note | Stanford, Kaiser | -| **Suki AI** | Suki Assistant | Voice commands + dictatie | 72% sneller documentatie | -| **Abridge** | Abridge | Ambient β†’ structured notes | Sutter Health, UPMC | -| **DeepScribe** | DeepScribe | Specialty-focused (oncologie) | Enterprise | -| **Ambience** | AI Scribe | Ambient + Epic integratie | Cleveland Clinic (4000+ artsen) | - -### 2.3 Adoptie bij Grote Zorginstellingen (2024) - -| Instelling | Tool | Schaal | Resultaat | -|------------|------|--------|-----------| -| Stanford Health | DAX Copilot | Volledig uitgerold | Significante tijdsbesparing | -| Cleveland Clinic | Ambience AI Scribe | 4000+ providers | 80+ specialismen | -| Sutter Health | Abridge | 100 clinici pilot | April 2024 start | -| Kaiser/TPMG | Ambient AI | 10.000 artsen | 303.266 encounters in 10 weken | - -### 2.4 Kernprobleem dat Wordt Opgelost - -> "Artsen besteden tot **4,5 uur per dag** aan EHR data invoer" -> β€” NEJM Catalyst Research - -> "De flow van EHR systemen matcht niet met de workflow van de clinicus, wat frustratie en tijdverlies veroorzaakt" -> β€” Healthcare IT News - ---- - -## 3. UX Pattern Analyse - -### 3.1 Ephemeral UI Concept - -**Definitie** (Hilal Koyuncu, ex-Google designer): -> "UI die alleen verschijnt wanneer nodig en verdwijnt na gebruik" - -**Kenmerken:** -| Eigenschap | Beschrijving | -|------------|--------------| -| On-demand | Interface materialiseert bij intentie | -| Hyper-contextual | Gebouwd voor één gebruiker's momentane doel | -| Transient | Vernietigd wanneer doel bereikt is | -| Task-optimal | Elk element dient het directe doel | - -**Voordelen:** -- Zero learning curve -- Infinite scalability -- Accessibility by default (past zich aan) - -**Risico's:** -> "Constant veranderende UIs kunnen usability problemen veroorzaken. Gebruikers leunen op design standaarden." -> β€” Roger Wong, Generative UI Analysis - -**Mitigatie:** Gebruik voorgedefinieerde bouwblokken, geen AI-gegenereerde UI. - -### 3.2 Command Palette Pattern - -**Oorsprong:** Sublime Text, VS Code (IDE's voor developers) - -**Moderne adoptie:** Superhuman, Linear, Figma, Slack, Raycast, Notion - -**Best Practices (Superhuman):** - -| Principe | Implementatie | -|----------|---------------| -| Fuzzy search | "jn dvr" matcht "Jan de Vries" | -| Recent first | Laatst gebruikte items bovenaan | -| Keyboard-first | Enter = bevestigen, Esc = annuleren | -| Single source | Alles op één plek | -| Contextual | Relevante acties per context | - -**Wanneer gebruiken:** -- Producten met veel features -- Power users die efficiency waarderen -- Keyboard-heavy workflows - -**Libraries:** -| Library | Kenmerken | -|---------|-----------| -| cmdk | Fast, unstyled, React, headless | -| Kbar | Portable, extensible | -| Kmenu | Animated, accessible | - -### 3.3 Natural Language Interface (NLI) Patterns - -**Definitie:** -> "Een platform dat interactie tussen computer en mens mogelijk maakt via natuurlijke taal" - -**Best Practices:** - -| Principe | Beschrijving | -|----------|--------------| -| Focus op intent | Begrijp wat de gebruiker wil bereiken | -| Handle ambiguity | Vraag verduidelijking bij onduidelijkheid | -| Define scope | Maak duidelijk wat het systeem kan | -| Confidence thresholds | Stel drempels in voor zekerheid | -| Balanced training | Voorkom bias in intent herkenning | - -**Reader vs Writer Intents:** -- **Reader intent:** Informatie ophalen, geen actie -- **Writer intent:** Actie uitvoeren, geen informatie tonen - -**Belangrijke waarschuwing:** -> "NLIs presteren het best in nauw gedefinieerde domeinen. Open-ended interactions overschrijden hun capaciteiten." -> β€” Explosion AI - -### 3.4 Voice Interface Patterns - -**Push-to-Talk vs Ambient:** - -| Aspect | Push-to-Talk | Ambient Listening | -|--------|--------------|-------------------| -| Privacy | Hoog (expliciet) | Laag (altijd aan) | -| Nauwkeurigheid | Hoger (gericht) | Lager (ruis) | -| Gebruiksgemak | Actie vereist | Hands-free | -| Batterij/resources | Laag | Hoog | -| Enterprise adoptie | Growing | Dominant (Suki, Abridge) | - -**Aanbeveling voor MVP:** Push-to-talk (privacy, nauwkeurigheid, eenvoudiger te bouwen) - ---- - -## 4. Healthcare UX Trends 2024-2025 - -### 4.1 Dominante Trends - -| Trend | Beschrijving | Relevantie | -|-------|--------------|------------| -| **AI-powered documentation** | Ambient listening, auto-notes | Direct relevant | -| **Reduced cognitive load** | Minder klikken, minder schermen | Kernprincipe | -| **Voice-first input** | Hands-free tijdens zorg | Must-have | -| **Personalization** | Interface past zich aan gebruiker aan | Nice-to-have | -| **Mobile-responsive** | Werkt op alle devices | Vereist | - -### 4.2 Anti-Patterns (Wat te Vermijden) - -| Anti-pattern | Waarom slecht | Alternatief | -|--------------|---------------|-------------| -| Modal op modal | Cognitive overload | Max 1 laag diep | -| "Weet je het zeker?" | Vertraagt, twijfel zaaien | Undo in plaats van confirm | -| Verplichte velden overal | Blokkeert snelle invoer | Alleen essentiΓ«le velden | -| Loading spinners | Wachten = frustratie | Optimistic UI | -| Sessie verlopen | Werk kwijt | Auto-save drafts | - -### 4.3 EHR-Specifieke UX Principes - -**Van Arkenea EHR Interface Guide:** -- Streamlined dashboards met customizable workflows -- Responsive designs voor verschillende schermgroottes -- Enhanced visual hierarchy met betere typografie -- Eliminatie van onnodige klikken en context switching -- Generous white space - ---- - -## 5. Aanbevolen Architectuur - -### 5.1 Hybrid Approach - -De beste UX combineert: -1. **Natural language input** (command palette + voice) -2. **Structured UI output** (voorgedefinieerde bouwblokken) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ INPUT LAYER: Natural Language β”‚ -β”‚ ───────────────────────────────────────────────────── β”‚ -β”‚ "notitie jan: medicatie gegeven" β”‚ -β”‚ β”‚ -β”‚ ↓ Intent Classification β”‚ -β”‚ β”‚ -β”‚ OUTPUT LAYER: Structured UI β”‚ -β”‚ ───────────────────────────────────────────────────── β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Patient: [Jan de Vries β–Ό] ← pre-filled β”‚ β”‚ -β”‚ β”‚ Categorie: [Medicatie β–Ό] ← pre-filled β”‚ β”‚ -β”‚ β”‚ Tekst: medicatie gegeven ← pre-filled β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [Opslaan] [Aanpassen] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Waarom hybrid:** -- Natural language voor snelle input -- Structured UI voor verificatie en correctie -- Best of both worlds: snelheid + controle - -### 5.2 Two-Tier Intent Classification - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ TIER 1: Local Pattern Matching (<50ms) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Input β†’ Intent β†’ Entities β”‚ -β”‚ ───────────────────────────────────────────────────────── β”‚ -β”‚ "notitie jan" β†’ dagnotitie β†’ patient: jan β”‚ -β”‚ "zoek marie" β†’ zoeken β†’ query: marie β”‚ -β”‚ "overdracht" β†’ overdracht β†’ (none) β”‚ -β”‚ "gesprek met piet" β†’ rapportage β†’ patient: piet β”‚ -β”‚ β”‚ -β”‚ Confidence: >0.9 β†’ Direct uitvoeren β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ - Als geen match of <0.9 confidence - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ TIER 2: AI Classification (<500ms) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Input: "ik heb net iets besproken" β”‚ -β”‚ β”‚ -β”‚ AI Output: β”‚ -β”‚ { β”‚ -β”‚ "intent": "rapportage", β”‚ -β”‚ "confidence": 0.75, β”‚ -β”‚ "clarification_needed": true, β”‚ -β”‚ "clarification": "Met welke patiΓ«nt?" β”‚ -β”‚ } β”‚ -β”‚ β”‚ -β”‚ 0.7-0.9 β†’ "Bedoelde je...?" met opties β”‚ -β”‚ <0.7 β†’ Fallback naar visuele picker β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 5.3 UI Layout Aanbeveling - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ COMMAND CENTER β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 🎀 Wat wil je doen? [Cmd+K] β”‚ β”‚ -β”‚ β”‚ ________________________________________________β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ πŸ’‘ notitie jan Β· zoek marie Β· overdracht β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Context: Ochtend dienst Β· 8 patiΓ«nten Β· Dr. Jansen β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ ACTIEF BOUWBLOK (ephemeral) β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ - Voorgedefinieerde structured form β”‚ β”‚ -β”‚ β”‚ - Pre-filled velden highlighted (gele flash) β”‚ β”‚ -β”‚ β”‚ - Minimal required fields β”‚ β”‚ -β”‚ β”‚ - 1-click save β”‚ β”‚ -β”‚ β”‚ - Undo beschikbaar (geen confirm dialog) β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Recent: [Jan βœ“ 14:32] [Marie βœ“ 14:28] [Overdracht 14:00] β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ“ β”‚ β”‚ πŸ” β”‚ β”‚ πŸ“‹ β”‚ β”‚ πŸ”„ β”‚ FALLBACK β”‚ -β”‚ β”‚Notitie β”‚ β”‚ Zoeken β”‚ β”‚Rapport β”‚ β”‚Overdr. β”‚ PICKER β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ (altijd) β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 6. Differentiatie t.o.v. Markt - -### 6.1 Vergelijking met Bestaande Oplossingen - -| Aspect | Suki/Abridge/DAX | Ephemeral UI EPD | -|--------|------------------|------------------| -| Luistermodus | Ambient (altijd aan) | Push-to-talk (expliciet) | -| Output | Full generated notes | Pre-filled structured forms | -| Pricing | Enterprise ($$$) | Open source / self-hosted | -| Markt | US healthcare | Nederlandse GGZ | -| Scope | Alleen documentatie | Multi-task intent routing | -| Verificatie | Post-hoc review | Inline confirmation | -| EHR integratie | Epic, Cerner focus | Supabase (eigen) | - -### 6.2 Unique Selling Points - -1. **Intent-based routing** - Niet alleen transcriberen, maar routeren naar juiste bouwblok -2. **Pre-fill magic** - Velden automatisch ingevuld, gebruiker bevestigt alleen -3. **GGZ vocabulaire** - Getraind op Nederlandse GGZ terminologie -4. **Privacy-first** - Push-to-talk, geen ambient listening -5. **Open architectuur** - Niet locked-in bij enterprise vendor - ---- - -## 7. Implementatie Aanbevelingen - -### 7.1 Technology Stack - -| Component | Aanbeveling | Rationale | -|-----------|-------------|-----------| -| Command input | cmdk library | Industry standard, headless, accessible | -| Voice | Deepgram (bestaand) | Al geΓ―ntegreerd, goed Nederlands | -| Intent (local) | Regex + keyword matching | <50ms, geen API call | -| Intent (AI) | Claude API | Al geΓ―ntegreerd, goed Nederlands | -| State | Zustand | Lightweight, geen provider nesting | -| UI blocks | shadcn/ui (bestaand) | Consistent met rest van app | - -### 7.2 Implementatie Volgorde - -| Fase | Component | Prioriteit | -|------|-----------|------------| -| 1 | Command Center layout | Must have | -| 1 | Fallback picker | Must have | -| 1 | Local intent matching | Must have | -| 2 | Voice input integratie | Must have | -| 2 | Dagnotitie block | Must have | -| 2 | Zoeken block | Must have | -| 3 | AI intent fallback | Should have | -| 3 | Rapportage block | Should have | -| 4 | Overdracht block | Could have | -| 4 | Animaties & polish | Could have | - -### 7.3 Success Metrics - -| Metric | Target | Meetmethode | -|--------|--------|-------------| -| Time-to-first-input | <2 sec | Timestamp logging | -| Task completion (notitie) | <30 sec | Timestamp logging | -| Intent accuracy | >90% | Correct block / total | -| Fallback usage | <15% | Picker clicks / total | -| Voice adoption | >40% | Voice / total inputs | - ---- - -## 8. Bronnen - -### Marktonderzoek -- [AI Voice Agents in Healthcare Market](https://www.novaoneadvisor.com/report/ai-voice-agents-in-healthcare-market) - Nova One Advisor -- [Healthcare UX/UI Design Trends 2025](https://www.excellentwebworld.com/healthcare-ux-ui-design-trends/) - Excellent WebWorld -- [AI and Healthcare UX/UI 2024-2025](https://www.graphitedigital.com/insights/ai-impact-ux-ui-design-healthcare) - Graphite Digital - -### Ambient Clinical Intelligence -- [Stanford DAX Implementation](https://med.stanford.edu/news/all-news/2024/03/ambient-listening-notes.html) - Stanford Medicine -- [Cleveland Clinic Ambient AI](https://consultqd.clevelandclinic.org/less-typing-more-talking-how-ambient-ai-is-reshaping-clinical-workflow-at-cleveland-clinic) - Cleveland Clinic -- [Ambient AI Scribes - NEJM](https://catalyst.nejm.org/doi/full/10.1056/CAT.23.0404) - NEJM Catalyst -- [Ambient Listening in Healthcare](https://healthtechmagazine.net/article/2024/08/ambient-listening-in-healthcare-perfcon) - HealthTech Magazine - -### Ephemeral UI -- [Ephemeral UI in AI-Generated Interfaces](https://isolutions.medium.com/ephemeral-ui-in-ai-generated-on-demand-interfaces-81dbc8cd4579) - iSolutions -- [Generative UI and the Ephemeral Interface](https://rogerwong.me/2025/11/generative-ui-and-the-ephemeral-interface/) - Roger Wong -- [Ephemeral Web-Based Applications](https://www.nngroup.com/articles/ephemeral-web-based-applications/) - Nielsen Norman Group -- [Future of AI UI/UX: Ephemeral Interfaces](https://hertzfelt.io/blog/the-future-of-ai-ui-ux-ephemeral-interfaces-and-stateless-design-paradigms) - Hertzfelt Labs - -### Command Palette -- [Command Palette UX Patterns](https://medium.com/design-bootcamp/command-palette-ux-patterns-1-d6b6e68f30c1) - Alicja Suska -- [How to Build a Remarkable Command Palette](https://blog.superhuman.com/how-to-build-a-remarkable-command-palette/) - Superhuman -- [Command Palette UI Design](https://mobbin.com/glossary/command-palette) - Mobbin -- [Command Palette Resources](https://www.commandpalette.org/) - commandpalette.org - -### Natural Language Interfaces -- [5 Principles for Good NLU Design](https://www.voiceflow.com/pathways/5-principles-for-good-natural-language-understanding-nlu-design) - Voiceflow -- [Natural Language Interface](https://www.uxtweak.com/ux-glossary/natural-language-interface/) - UXtweak -- [A Natural Language UI is Just a UI](https://explosion.ai/blog/natural-user-interface) - Explosion AI - -### Healthcare AI Vendors -- [Suki AI](https://www.suki.ai/) - Suki Assistant -- [DeepScribe](https://www.deepscribe.ai/resources/best-ai-medical-scribes) - AI Medical Scribes -- [Abridge](https://www.trendingaitools.com/ai-tools/abridge/) - Clinical Documentation - -### EHR Design -- [EHR Interface Design Guide 2026](https://arkenea.com/blog/ehr-interface/) - Arkenea -- [EMR/EHR UI/UX Principles](https://www.purrweb.com/blog/emr-ehr-interface-design/) - Purrweb -- [EHR Redesign for Burnout](https://www.healthcareitnews.com/news/pandemic-era-burnout-how-ehr-vendors-are-redesigning-ui-and-ux-battle-stress) - Healthcare IT News - ---- - -## 9. Conclusie - -De beste UX/UI voor het Ephemeral UI EPD is een **hybrid approach**: - -1. **Input:** Command palette (cmdk) + push-to-talk voice -2. **Processing:** Two-tier intent classification (local-first, AI-fallback) -3. **Output:** Voorgedefinieerde, structured UI-bouwblokken met pre-fill -4. **Safety net:** Altijd zichtbare fallback picker - -Deze aanpak combineert: -- De snelheid van natural language input -- De voorspelbaarheid van structured UI -- De betrouwbaarheid van voorgedefinieerde componenten -- De flexibiliteit van AI-assisted intent recognition - -Het resultaat: een interface die **voelt als magie** ("het begrijpt me!") maar **werkt als een betrouwbaar tool** (geen verrassingen, altijd een uitweg). - ---- - -*Onderzoeksverslag gegenereerd op basis van desk research december 2024* diff --git a/docs/swift/archive/nextgen-epd-prd-ephemeral-ui-epd.md b/docs/swift/archive/nextgen-epd-prd-ephemeral-ui-epd.md deleted file mode 100644 index e8527dd..0000000 --- a/docs/swift/archive/nextgen-epd-prd-ephemeral-ui-epd.md +++ /dev/null @@ -1,607 +0,0 @@ -# πŸ“„ Product Requirements Document (PRD) - -**Product:** Ephemeral UI EPD - "Het Vergankelijke EPD" -**Doel:** AI Speedrun Deel 2 - Demonstreren van context-aware, on-demand interfaces voor GGZ -**Versie:** 1.0 -**Datum:** december 2024 - ---- - -## 1. Doelstelling - -### Primair doel -Bouwen van een **Ephemeral UI EPD**: een systeem waarin de interface niet permanent is, maar **on-demand verschijnt** op basis van wat de gebruiker wil doen. De gebruiker navigeert niet door menu's, maar spreekt of typt een intentie - en het juiste "bouwblok" verschijnt. - -### Het contrast met traditionele EPD's - -| Aspect | Traditioneel EPD | Ephemeral UI EPD | -|--------|------------------|------------------| -| Navigatie | 47 menu-items, tabbladen, submenu's | EΓ©n input: "wat wil je doen?" | -| Interface | Altijd alles zichtbaar | Alleen wat je nu nodig hebt | -| Leren | 200-pagina handleiding | Zero learning curve | -| Klikken | 12 klikken voor rapportage | 1 zin of voice command | -| Context | Gebruiker moet context onthouden | Systeem begrijpt context | - -### Secundair doel -- Positioneren als thought leader op het snijvlak van AI en healthcare UX -- Demonstreren van Vercel AI SDK Generative UI capabilities -- Concrete showcase voor gesprekken met Nedap, Medicore, etc. - ---- - -## 2. Wat is Ephemeral UI? - -### Definitie -Ephemeral UI ("vergankelijke interface") betekent dat interface-elementen: -1. **On-demand verschijnen** - alleen wanneer nodig -2. **Context-aware zijn** - weten wie je bent, welke patiΓ«nt, welk moment -3. **Verdwijnen na gebruik** - geen permanente schermvervuiling -4. **Voorgedefinieerd zijn** - geen willekeurig gegenereerde UI, maar geteste bouwblokken - -### Onze interpretatie voor GGZ -We bouwen **geen** volledig AI-gegenereerde interfaces (te onvoorspelbaar voor zorg). -We bouwen **wel** een set van **voorgedefinieerde UI-bouwblokken** die: -- Door AI worden geselecteerd op basis van gebruikersintentie -- Automatisch worden gevuld met relevante data -- Na voltooiing verdwijnen of minimaliseren - ---- - -## 3. Bestaande basis (uit Speedrun 1) - -### Wat we al hebben -Uit het Mini-ECD en Overdracht Dashboard: - -**Database (Supabase PostgreSQL):** -- `clients` - patiΓ«ntgegevens -- `intakes` - intakeverslagen -- `problem_profiles` - DSM-light classificaties -- `treatment_plans` - behandelplannen met versioning -- `nursing_logs` - verpleegkundige dagregistraties -- `appointments` - afspraken (basis) -- `vitals` - vitale functies metingen -- `risk_assessments` - risicotaxaties - -**AI Functionaliteit:** -- Samenvatten van tekst -- Leesbaarheid verbeteren (B1) -- Problemen extraheren uit intake -- Behandelplan genereren -- Overdracht samenvatting genereren - -**Tech Stack:** -- Next.js 15 (App Router) -- Supabase (Auth + DB) -- Claude API (Anthropic) -- TailwindCSS + shadcn/ui -- TipTap rich text editor -- Deepgram (speech-to-text) - -### Wat we hergebruiken -- Volledige database schema -- Alle bestaande API routes -- AI prompts en functionaliteit -- Authenticatie en autorisatie -- Bestaande UI componenten (als bouwblokken) - ---- - -## 4. De Bouwblokken - -### 4.1 Overzicht van UI Bouwblokken - -| # | Bouwblok | Trigger voorbeelden | Data input | Output | -|---|----------|---------------------|------------|--------| -| 1 | **Rapportage** | "gesprek gehad", "notitie maken" | patient_id, transcript/tekst | Opgeslagen rapportage | -| 2 | **Intake** | "nieuwe cliΓ«nt", "intake" | basisgegevens, verwijzing | Intake + patient record | -| 3 | **Behandelplan** | "behandelplan", "doelen opstellen" | patient_id, diagnose | Treatment plan | -| 4 | **Overdracht** | "overdracht", "dienst eindigt" | patient_id[], tijdrange | Samenvatting | -| 5 | **Dagnotitie** | "medicatie gegeven", "incident" | patient_id, categorie | Nursing log entry | -| 6 | **Zoeken** | "zoek", "wie is", "vind" | zoekterm | Patient card(s) | -| 7 | **Agenda** | "afspraken", "planning", "wanneer" | datum, behandelaar | Agenda view | -| 8 | **Metingen** | "vitale functies", "meting invoeren" | patient_id, type | Vitals entry | - -### 4.2 Bouwblok Specificaties - -#### Bouwblok 1: Rapportage -**Trigger patterns:** -- "Ik heb net een gesprek gehad met [naam]" -- "Notitie voor [naam]" -- "Rapportage maken" - -**UI Componenten:** -- Patient selector (indien niet gespecificeerd) -- Rich text editor (TipTap) -- AI-knoppen: Samenvatten, Structureren, B1-niveau -- Tag selector (Gesprek/Observatie/Telefonisch/etc.) -- Save + Close actie - -**Pre-fill logica:** -- Als patient genoemd: voorselect patient -- Als "gesprek": tag = Gesprek -- Als transcript meegegeven: vul editor - -**Na voltooiing:** -- Opslaan in `intakes` of `nursing_logs` -- Toon bevestiging -- Minimaliseer naar "Laatste: [titel]" badge -- Klaar voor volgende actie - ---- - -#### Bouwblok 2: Intake -**Trigger patterns:** -- "Nieuwe cliΓ«nt" -- "Intake starten" -- "Aanmelding verwerken" - -**UI Componenten:** -- Stap 1: Basisgegevens (naam, geboortedatum) -- Stap 2: Verwijsgegevens (optioneel) -- Stap 3: Intake editor met AI-ondersteuning -- Stap 4: AI-suggestie voor probleemprofiel - -**Pre-fill logica:** -- Als naam genoemd: vul naam in -- Als verwijsbrief geΓΌpload: extract data - -**Na voltooiing:** -- Patient aangemaakt -- Intake opgeslagen -- Probleemprofiel concept aangemaakt -- Navigeer naar volgende stap of minimaliseer - ---- - -#### Bouwblok 3: Behandelplan -**Trigger patterns:** -- "Behandelplan opstellen voor [naam]" -- "Doelen formuleren" -- "Plan maken" - -**UI Componenten:** -- Patient context header -- Diagnose/probleemprofiel samenvatting -- AI-gegenereerd plan (bewerkbaar) -- SMART doelen editor -- Interventies selector -- Versie management (concept/gepubliceerd) - -**Pre-fill logica:** -- Laad bestaand probleemprofiel -- Laad recente intakes voor context -- Genereer voorstel met AI - -**Na voltooiing:** -- Plan opgeslagen (concept of gepubliceerd) -- Toon bevestiging met versienummer - ---- - -#### Bouwblok 4: Overdracht -**Trigger patterns:** -- "Overdracht maken" -- "Dienst eindigt" -- "Samenvatting voor collega" - -**UI Componenten:** -- Multi-patient selector (of "mijn patiΓ«nten vandaag") -- Tijdrange selector (afgelopen X uur) -- Per patient: collapsible summary -- AI-samenvatting met bronverwijzingen -- Export/print optie - -**Pre-fill logica:** -- Selecteer patiΓ«nten van huidige gebruiker -- Default tijdrange: afgelopen 8 uur -- Laad relevante nursing_logs, vitals, rapportages - -**Na voltooiing:** -- Overdracht gemarkeerd als compleet -- Optioneel: doorsturen naar collega - ---- - -#### Bouwblok 5: Dagnotitie (Quick Entry) -**Trigger patterns:** -- "Medicatie gegeven aan [naam]" -- "Incident bij [naam]" -- "[naam] heeft goed gegeten" - -**UI Componenten:** -- Minimale form: categorie, tekst, tijd -- CategorieΓ«n: Medicatie, ADL, Gedrag, Incident, Observatie -- Checkbox: "Opnemen in overdracht" -- Quick save (enter = opslaan) - -**Pre-fill logica:** -- Extract patient uit zin -- Extract categorie uit keywords -- Tijd = nu (aanpasbaar) - -**Na voltooiing:** -- Direct opgeslagen -- Toast bevestiging -- Klaar voor volgende notitie - ---- - -#### Bouwblok 6: Zoeken -**Trigger patterns:** -- "Zoek [naam]" -- "Wie is [naam]" -- "Toon patiΓ«nt [naam]" - -**UI Componenten:** -- Search results cards -- Per card: naam, geboortedatum, laatste contact, status -- Klik = open patient context -- "Geen resultaten" state - -**Na selectie:** -- Set active patient context -- Toon relevante vervolgacties: "Wat wil je doen met [naam]?" - ---- - -#### Bouwblok 7: Agenda -**Trigger patterns:** -- "Mijn afspraken vandaag" -- "Afspraken voor [naam]" -- "Planning deze week" - -**UI Componenten:** -- Dag/week view toggle -- Afsprakenlijst met tijden -- Patient naam + type afspraak -- Quick actions: afspraak toevoegen - -**Pre-fill logica:** -- Default: vandaag, huidige gebruiker -- Als patient genoemd: filter op patient - ---- - -#### Bouwblok 8: Metingen -**Trigger patterns:** -- "Bloeddruk invoeren" -- "Vitale functies [naam]" -- "Gewicht meten" - -**UI Componenten:** -- Meting type selector -- Waarde input met validatie -- Trend indicator (vs vorige meting) -- Quick save - ---- - -## 5. De Orchestratielaag - -### 5.1 Command Center Interface - -**Het centrale scherm:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ [🎀] Wat wil je doen? [user] β”‚ -β”‚ _____________________________________________________ β”‚ -β”‚ β”‚ -β”‚ Context: Dienst ochtend | 8 patiΓ«nten | 3 todo's β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [Actief Bouwblok verschijnt hier] β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Recent: [Jan - Rapportage] [Overdracht 14:00] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 5.2 Intent Classification - -**Flow:** -``` -[User Input: tekst of voice] - ↓ -[AI Intent Classifier] - ↓ - β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β” - ↓ ↓ -[Intent] [Entities] - ↓ ↓ -[Route naar Bouwblok + Pre-fill data] - ↓ -[Render Bouwblok Component] -``` - -**Intent Classification Prompt:** -``` -Je bent een intent classifier voor een GGZ EPD systeem. - -Analyseer de gebruikersinput en return JSON: -{ - "intent": "rapportage|intake|behandelplan|overdracht|dagnotitie|zoeken|agenda|metingen|onbekend", - "confidence": 0.0-1.0, - "entities": { - "patient_name": string | null, - "date": string | null, - "category": string | null, - "action_type": string | null - }, - "clarification_needed": boolean, - "clarification_question": string | null -} - -Gebruikersinput: "{input}" -``` - -### 5.3 Context Management - -**Actieve context bevat:** -- `current_user`: ingelogde behandelaar -- `active_patient`: laatst geselecteerde patiΓ«nt (sticky) -- `active_shift`: huidige dienst info -- `recent_actions`: laatste 5 acties (voor "recent" badge) -- `pending_items`: openstaande taken - -**Context wordt gebruikt voor:** -- Pre-filling van bouwblokken -- Suggesties bij ambigue input -- "Bedoelde je [patient X]?" bij onduidelijkheid - ---- - -## 6. Voice Interface - -### 6.1 Speech-to-Text Flow -``` -[Mic Button Click] - ↓ -[Deepgram Streaming STT] - ↓ -[Live Transcription Display] - ↓ -[User confirms / auto-submit na pauze] - ↓ -[Intent Classification] - ↓ -[Bouwblok] -``` - -### 6.2 Voice Commands -- Wake phrase niet nodig (expliciete mic button) -- Continu luisteren tijdens bouwblok voor dicteren -- "Klaar" of "Opslaan" als voice command - ---- - -## 7. Technische Architectuur - -### 7.1 Nieuwe Routes - -``` -/app - /(app) - /command-center - /page.tsx # Hoofdscherm met input - /components/ - CommandInput.tsx # Tekst + voice input - BuildingBlock.tsx # Container voor actief blok - ContextBar.tsx # Context info display - RecentActions.tsx # Recent items - - /api - /intent - /classify/route.ts # AI intent classification - /context - /route.ts # Get/set user context -``` - -### 7.2 Building Blocks als Components - -``` -/components/building-blocks/ - /rapportage/ - RapportageBlock.tsx - RapportageBlock.types.ts - /intake/ - IntakeBlock.tsx - IntakeBlock.types.ts - /behandelplan/ - BehandelplanBlock.tsx - /overdracht/ - OverdrachtBlock.tsx - /dagnotitie/ - DagnotitieBlock.tsx - /zoeken/ - ZoekenBlock.tsx - /agenda/ - AgendaBlock.tsx - /metingen/ - MetingenBlock.tsx - - /shared/ - BlockContainer.tsx # Wrapper met header, minimize, close - BlockHeader.tsx - PatientSelector.tsx - ConfirmationToast.tsx -``` - -### 7.3 State Management - -```typescript -// stores/commandCenterStore.ts -interface CommandCenterState { - // Active block - activeBlock: BlockType | null; - blockData: Record; - - // Context - activePatient: Patient | null; - recentActions: Action[]; - - // Input - inputMode: 'text' | 'voice'; - isListening: boolean; - transcript: string; - - // Actions - setActiveBlock: (block: BlockType, data?: any) => void; - closeBlock: () => void; - setActivePatient: (patient: Patient) => void; - addRecentAction: (action: Action) => void; -} -``` - ---- - -## 8. User Flows - -### 8.1 Happy Path: Rapportage na gesprek - -``` -1. User opent Command Center -2. Ziet: lege input, context "Ochtend dienst, 8 patiΓ«nten" -3. Spreekt: "Ik heb net een gesprek gehad met Jan de Vries" -4. Systeem: - - Herkent intent: rapportage - - Herkent entity: patient = "Jan de Vries" - - Zoekt patient in DB - - Opent Rapportage bouwblok met Jan geselecteerd -5. User dicteert inhoud gesprek -6. Klikt "AI Samenvatten" -7. Review en opslaan -8. Bouwblok minimaliseert -9. Klaar voor volgende actie -``` - -### 8.2 Ambigue Input - -``` -1. User typt: "notitie" -2. Systeem: confidence < 0.7, geen patient -3. Toont: "Voor welke patiΓ«nt wil je een notitie maken?" -4. User: "Jan" -5. Systeem: meerdere "Jan" in DB -6. Toont: selector met matches -7. User selecteert -8. Opent Dagnotitie bouwblok -``` - -### 8.3 Context Switch - -``` -1. User werkt in Rapportage voor Jan -2. Spreekt: "Wacht, even medicatie noteren voor Piet" -3. Systeem: - - Herkent nieuwe intent + patient - - Vraagt: "Rapportage voor Jan opslaan als concept?" -4. User: "Ja" -5. Rapportage minimized als "Jan - Concept" -6. Dagnotitie opent voor Piet -7. Na opslaan: "Terug naar Jan's rapportage?" -``` - ---- - -## 9. Niet in Scope (v1) - -- Volledige voice-only mode (voice is input, niet navigatie) -- Multi-user realtime collaboration -- Offline mode -- Native mobile app (wel responsive web) -- Integratie met externe EPD's (later: FHIR) -- Volledig geautomatiseerde workflows (user blijft in control) -- AI-gegenereerde UI componenten (alleen voorgedefinieerde blokken) - ---- - -## 10. Succescriteria - -### Functioneel -- [ ] 8 bouwblokken werkend met pre-fill -- [ ] Intent classification >85% accuracy op test set -- [ ] Voice input werkend met Deepgram -- [ ] Context persistence binnen sessie -- [ ] Gemiddeld <3 interacties tot taak compleet - -### Performance -- [ ] Intent classification <500ms -- [ ] Bouwblok render <200ms -- [ ] Voice transcription realtime (<100ms latency) - -### UX -- [ ] Zero training needed voor basis flows -- [ ] "Dit voelt als magie" feedback van test users -- [ ] 50% minder klikken vs traditionele navigatie (gemeten) - -### Business -- [ ] Demo-ready voor Nedap gesprek (7 jan) -- [ ] LinkedIn content: 4 posts over ephemeral UI concept -- [ ] Minimaal 2 concrete interesse-uitingen van GGZ partijen - ---- - -## 11. Fasering - -### Fase 1: Foundation (Week 1) -- [ ] Command Center basis UI -- [ ] Intent classification API -- [ ] 2 bouwblokken: Rapportage + Dagnotitie -- [ ] Context management basis - -### Fase 2: Core Blocks (Week 2) -- [ ] Voice input integratie -- [ ] Bouwblokken: Zoeken, Overdracht, Behandelplan -- [ ] Pre-fill logica uitbreiden -- [ ] Recent actions tracking - -### Fase 3: Polish (Week 3) -- [ ] Bouwblokken: Intake, Agenda, Metingen -- [ ] Animaties en transitions -- [ ] Error handling en edge cases -- [ ] Performance optimalisatie - -### Fase 4: Demo Ready (Week 4) -- [ ] End-to-end testing -- [ ] Demo script en scenario's -- [ ] Documentation -- [ ] LinkedIn content - ---- - -## 12. Risico's - -| Risico | Impact | Mitigatie | -|--------|--------|-----------| -| Intent classification onnauwkeurig | Hoog | Fallback naar handmatige selectie, train op GGZ vocabulaire | -| Voice transcription slecht in Nederlands | Middel | Deepgram NL model testen, fallback naar tekst | -| Gebruikers missen "overzicht" | Middel | Dashboard/overzicht als alternatieve entry point | -| Te veel edge cases | Hoog | Focus op 3-5 happy paths voor demo | -| Performance AI calls | Middel | Caching, streaming responses | - ---- - -## 13. Appendix: Intent Training Data (voorbeelden) - -```json -[ - {"input": "gesprek gehad met jan de vries", "intent": "rapportage", "entities": {"patient_name": "jan de vries"}}, - {"input": "notitie maken", "intent": "dagnotitie", "entities": {}}, - {"input": "nieuwe patient aanmelden", "intent": "intake", "entities": {}}, - {"input": "overdracht voor de avonddienst", "intent": "overdracht", "entities": {}}, - {"input": "zoek marie", "intent": "zoeken", "entities": {"patient_name": "marie"}}, - {"input": "mijn afspraken vandaag", "intent": "agenda", "entities": {"date": "today"}}, - {"input": "bloeddruk 140/90 bij piet", "intent": "metingen", "entities": {"patient_name": "piet", "measurement_type": "bloeddruk"}}, - {"input": "behandelplan opstellen", "intent": "behandelplan", "entities": {}} -] -``` - ---- - -## Wijzigingslog - -| Versie | Datum | Wijzigingen | -|--------|-------|-------------| -| 1.0 | dec 2024 | InitiΓ«le versie | \ No newline at end of file diff --git a/docs/swift/archive/nextgen-epd-waarde-analyse-ephemeral-ui.md b/docs/swift/archive/nextgen-epd-waarde-analyse-ephemeral-ui.md deleted file mode 100644 index 877c1bf..0000000 --- a/docs/swift/archive/nextgen-epd-waarde-analyse-ephemeral-ui.md +++ /dev/null @@ -1,551 +0,0 @@ -# Waarde-Analyse Ephemeral UI EPD - -**Document:** Waar ligt de waarde en hoe implementeren? -**Datum:** december 2024 -**Auteurs:** Product Owner, Klant (GGZ Zorginstelling), UX Designer - ---- - -## 1. Klant Perspectief: De Zorginstelling - -### 1.1 De Pijn van Vandaag - -**Citaten uit het veld:** - -> "Mijn verpleegkundigen besteden 40% van hun tijd aan administratie. Dat is tijd die niet naar de cliΓ«nt gaat." -> β€” Teamleider GGZ - -> "We hebben een EPD met 200 schermen. Niemand kent ze allemaal. Nieuwe medewerkers doen er 3 maanden over om het te leren." -> β€” ICT Manager - -> "Na een crisis-interventie moet ik 20 minuten typen. Terwijl ik eigenlijk bij de volgende cliΓ«nt moet zijn." -> β€” SPV'er - -### 1.2 Waar Ligt de Echte Waarde? - -**Waarde = Tijd terug naar de zorg** - -| Activiteit | Nu (minuten) | Ephemeral (minuten) | Besparing | -|------------|--------------|---------------------|-----------| -| Dagnotitie na ADL | 3-5 | 0.5 | **80%** | -| Rapportage na gesprek | 8-15 | 2-3 | **75%** | -| Overdracht maken | 20-30 | 5 | **80%** | -| PatiΓ«nt opzoeken | 1-2 | 0.2 | **85%** | -| Navigeren naar juiste scherm | 0.5-1 per actie | 0 | **100%** | - -**Rekenvoorbeeld voor 1 afdeling (10 FTE):** -- 10 medewerkers Γ— 8 notities/dag Γ— 3 min besparing = **4 uur/dag terug** -- Per jaar: **1000+ uur** extra zorgcontact - -### 1.3 Wat de Klant Wil Zien - -**Primair:** -1. **Snelheid** - "Ik zeg iets, het staat erin" -2. **Betrouwbaarheid** - "Het begrijpt me, ook in GGZ-taal" -3. **Geen gedoe** - "Ik hoef niet na te denken over het systeem" - -**Secundair:** -4. Overdracht die zichzelf schrijft -5. Minder training voor nieuwe medewerkers -6. Voice input (handsfree tijdens zorg) - -**Niet gevraagd maar wel gewaardeerd:** -- AI-suggesties ("wil je de arts informeren?") -- Proactieve alerts ("let op: 3 valincidenten deze week") - -### 1.4 Waarde Prioritering door Klant - -``` -β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ HOOGSTE WAARDE -β–ˆ 1. Snelle dagnotities (voice) -β–ˆ 2. Rapportage na gesprek -β–ˆ 3. Automatische overdracht -β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ HOGE WAARDE -β–ˆ 4. PatiΓ«nt snel vinden -β–ˆ 5. Context-aware (weet welke dienst) -β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ GEMIDDELDE WAARDE -β–ˆ 6. Behandelplan assistentie -β–ˆ 7. Agenda integratie -β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ LAGERE WAARDE -β–ˆ 8. Metingen invoer -β–ˆ 9. Intake ondersteuning -``` - -### 1.5 Klant Conclusie - -**Meeste waarde:** De drie "high-frequency, low-complexity" taken: -1. **Dagnotitie** - 10-20x per dag per medewerker -2. **Rapportage** - 3-5x per dag per behandelaar -3. **Overdracht** - 2-3x per dag per afdeling - -**Implementatie advies:** Begin hier. Dit is waar 80% van de tijdwinst zit. - ---- - -## 2. Product Owner Perspectief: Waarde vs. Effort - -### 2.1 Value/Effort Matrix - -``` - HOGE WAARDE - β”‚ - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ β”‚ β”‚ - β”‚ QUICK WINS β”‚ BIG BETS β”‚ - β”‚ ──────────── β”‚ ──────────── β”‚ - β”‚ β€’ Dagnotitie β”‚ β€’ Intent API β”‚ - β”‚ β€’ Zoeken β”‚ β€’ Voice flow β”‚ - β”‚ β€’ Context bar β”‚ β€’ Overdracht AI β”‚ - β”‚ β”‚ β”‚ -LAGE β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ HOGE -EFFORT β”‚ β”‚ EFFORT - β”‚ β”‚ β”‚ - β”‚ FILL-INS β”‚ MONEY PITS β”‚ - β”‚ ──────────── β”‚ ──────────── β”‚ - β”‚ β€’ Metingen β”‚ β€’ Intake wizard β”‚ - β”‚ β€’ Agenda view β”‚ β€’ Behandelplan β”‚ - β”‚ β€’ Recent badges β”‚ β€’ Full ambient β”‚ - β”‚ β”‚ β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - LAGE WAARDE -``` - -### 2.2 Waarde Drivers per Bouwblok - -| Bouwblok | Frequentie | Tijdwinst | Effort | **Waarde Score** | -|----------|------------|-----------|--------|------------------| -| **Dagnotitie** | 20x/dag | 80% | Laag | ⭐⭐⭐⭐⭐ | -| **Zoeken** | 15x/dag | 85% | Laag | ⭐⭐⭐⭐⭐ | -| **Rapportage** | 5x/dag | 75% | Medium | ⭐⭐⭐⭐ | -| **Overdracht** | 2x/dag | 80% | Medium | ⭐⭐⭐⭐ | -| **Agenda** | 3x/dag | 50% | Laag | ⭐⭐⭐ | -| **Metingen** | 2x/dag | 60% | Laag | ⭐⭐⭐ | -| **Behandelplan** | 1x/week | 40% | Hoog | ⭐⭐ | -| **Intake** | 1x/maand | 30% | Hoog | ⭐ | - -### 2.3 MVP Definitie op Basis van Waarde - -**MVP = Hoogste waarde, laagste effort** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ MVP SCOPE β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ MUST: Command Center + Intent β”‚ -β”‚ β”œβ”€β”€ Text input β”‚ -β”‚ β”œβ”€β”€ Voice input (Deepgram bestaand) β”‚ -β”‚ └── Fallback blok-picker β”‚ -β”‚ β”‚ -β”‚ MUST: Dagnotitie Blok ⭐⭐⭐⭐⭐ β”‚ -β”‚ β”œβ”€β”€ Quick entry form β”‚ -β”‚ β”œβ”€β”€ Categorie pre-select uit intent β”‚ -β”‚ β”œβ”€β”€ Patient pre-fill β”‚ -β”‚ └── 1-click save β”‚ -β”‚ β”‚ -β”‚ MUST: Zoeken Blok ⭐⭐⭐⭐⭐ β”‚ -β”‚ β”œβ”€β”€ Patient search (cmdk) β”‚ -β”‚ β”œβ”€β”€ Quick actions per result β”‚ -β”‚ └── Set active patient β”‚ -β”‚ β”‚ -β”‚ SHOULD: Rapportage Blok ⭐⭐⭐⭐ β”‚ -β”‚ β”œβ”€β”€ Wrapper rond bestaande ReportComposer β”‚ -β”‚ β”œβ”€β”€ Voice dictation β”‚ -β”‚ └── AI structurering β”‚ -β”‚ β”‚ -β”‚ COULD: Overdracht Blok ⭐⭐⭐⭐ β”‚ -β”‚ └── AI samenvatting (API bestaat al) β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 2.4 Wat NIET in MVP - -| Blok | Reden voor uitstel | -|------|-------------------| -| Behandelplan | Laag-frequent, hoog-complex, bestaande UI voldoet | -| Intake | Zeer laag-frequent, wizard is complex | -| Metingen | Lage waarde-perceptie bij klant | -| Agenda | Bestaande agenda werkt, lage urgentie | - -### 2.5 Release Strategie - -**Week 1-2: Foundation** -- Command Center shell -- Intent API (basic) -- Dagnotitie blok - -**Week 3: Core Value** -- Zoeken blok -- Rapportage blok -- Voice refinement - -**Week 4: Demo Polish** -- Overdracht blok -- Animaties -- Demo scenario's - -**Post-Demo: Iterate** -- Metrics verzamelen -- Intent accuracy verbeteren -- Overige blokken op basis van feedback - ---- - -## 3. UX Designer Perspectief: Waarde in de Interactie - -### 3.1 Waar Ontstaat Waarde in de UX? - -**Waarde = Friction verwijderen** - -De grootste UX-waarde zit niet in features, maar in het **elimineren van stappen**: - -``` -TRADITIONEEL EPD: -Login β†’ Dashboard β†’ Menu β†’ Submenu β†’ PatiΓ«nten β†’ Zoeken β†’ -Selecteer β†’ Menu β†’ Rapportage β†’ Type selecteren β†’ Formulier β†’ -Invullen β†’ Validatie fixen β†’ Opslaan β†’ Bevestiging - -= 14 stappen, 12+ klikken, 3-5 minuten - -EPHEMERAL UI: -Command Center β†’ "Notitie voor Jan" β†’ Invullen β†’ Opslaan - -= 4 stappen, 2 klikken, 30 seconden -``` - -### 3.2 De Vijf Waarde-Momenten - -**Moment 1: De Eerste Seconde** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ Goedemiddag. Wat wil je doen? β”‚ -β”‚ ___________________________________________________ β”‚ -β”‚ β”‚ -β”‚ πŸ’‘ "notitie jan", "overdracht", "zoek marie" β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -WAARDE: Geen keuze-stress. Geen menu's. EΓ©n vraag. -``` - -**Moment 2: De Herkenning** -``` -User: "notitie voor Jan" - -System: -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“ Dagnotitie voor Jan de Vries β”‚ -β”‚ ───────────────────────────────────────────────────────── β”‚ -β”‚ Categorie: [ADL β–Ό] Tijd: [14:32] β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ _ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [Opslaan] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -WAARDE: "Het begreep me!" Patient al ingevuld. Direct typen. -``` - -**Moment 3: De Voice Flow** -``` -User klikt 🎀 - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ”΄ Luistert... β”‚ -β”‚ β”‚ -β”‚ "Mevrouw heeft goed gegeten, medicatie ingenomen, β”‚ -β”‚ was wat onrustig vanmorgen maar nu stabiel" β”‚ -β”‚ β”‚ -β”‚ [Stop] [Opnieuw] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -WAARDE: Handen vrij. Praten is sneller dan typen. - Natuurlijke taal, geen formulier-denken. -``` - -**Moment 4: De Bevestiging** -``` -Na opslaan: - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ βœ“ Notitie opgeslagen [Ongedaan] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -Recent: [Jan - Notitie βœ“ 14:32] - -WAARDE: Zekerheid. "Het staat erin." Undo als vangnet. -``` - -**Moment 5: De Volgende Actie** -``` -System: Klaar. Wat nu? - ___________________________________________________ - - Suggestie: Je hebt nog 2 patiΓ«nten met openstaande notities - -WAARDE: Flow behouden. Niet terug naar start. - Proactief helpen. -``` - -### 3.3 Waarde-Killers (Anti-Patterns) - -| Anti-Pattern | Waarom Slecht | Oplossing | -|--------------|---------------|-----------| -| "Weet je het zeker?" dialoog | Vertraagt, twijfel zaaien | Undo in plaats van confirm | -| Verplichte velden | Blokkeert snelle invoer | Alleen patient verplicht | -| Modal op modal | Cognitive overload | Max 1 laag diep | -| Laden... spinner | Wachten = frustratie | Optimistic UI | -| "Sessie verlopen" | Werk kwijt | Auto-save drafts | - -### 3.4 Implementatie: Waarde-First Design - -**Principe 1: Progressive Disclosure** -``` -Stap 1: Minimaal formulier (alleen tekst) - ↓ -Stap 2: Optionele details (categorie, tijd) - collapsed - ↓ -Stap 3: Geavanceerd (tags, links) - hidden by default -``` - -**Principe 2: Defaults die Kloppen** -```typescript -// Pre-fill logica -const defaults = { - patient: context.activePatient || extractFromIntent(input), - category: inferCategory(input), // "medicatie" β†’ Medicatie - time: new Date(), // Nu - includeInHandover: true, // Standaard aan -} -``` - -**Principe 3: Keyboard-First, Voice-Enhanced** -``` -Enter = Opslaan (als er tekst is) -Escape = Sluiten (met draft save) -Tab = Volgende veld -Cmd+K = Terug naar Command input -Spacebar = Start/stop voice (in input) -``` - -**Principe 4: Feedback Loops** -``` -Input β†’ Instant echo (wat het systeem hoorde) -Processingβ†’ Subtle indicator (geen blocking spinner) -Success β†’ Toast + sound + Recent update -Error β†’ Inline, niet modal, met fix-suggestie -``` - -### 3.5 Waarde Meten - -**Metrics die waarde bewijzen:** - -| Metric | Target | Hoe Meten | -|--------|--------|-----------| -| Time-to-first-input | <2 sec | Timestamp command β†’ blok open | -| Task completion time | <30 sec (notitie) | Blok open β†’ save | -| Intent accuracy | >90% | Correct blok / totaal attempts | -| Voice adoption | >40% | Voice inputs / totaal inputs | -| Fallback usage | <15% | Blok-picker clicks / totaal | -| Error rate | <5% | Failed saves / totaal saves | - -### 3.6 UX Implementatie Prioriteit - -``` -WEEK 1: Core Interaction -β”œβ”€β”€ Command input component -β”œβ”€β”€ Voice indicator states -β”œβ”€β”€ Block container met animaties -└── Success/error feedback - -WEEK 2: Waarde-Blokken -β”œβ”€β”€ Dagnotitie (minimalist form) -β”œβ”€β”€ Zoeken (cmdk + patient cards) -└── Pre-fill animations - -WEEK 3: Polish -β”œβ”€β”€ Microinteracties -β”œβ”€β”€ Keyboard shortcuts -β”œβ”€β”€ Fallback blok-picker -└── Onboarding hints - -WEEK 4: Demo Ready -β”œβ”€β”€ Happy path perfectioneren -β”œβ”€β”€ Edge case handling -β”œβ”€β”€ Performance tuning -└── Demo scenario walkthroughs -``` - ---- - -## 4. Gezamenlijke Waarde-Conclusie - -### 4.1 Waar Ligt de Meeste Waarde? - -**Top 3 Waarde-Dragers:** - -| # | Feature | Waarde Reden | -|---|---------|--------------| -| 1 | **Voice Dagnotitie** | Hoogste frequentie (20x/dag), grootste tijdwinst (80%), laagste effort | -| 2 | **Instant Zoeken** | Elimineert navigatie volledig, elke actie begint met "wie" | -| 3 | **Smart Pre-fill** | "Het systeem begrijpt me" - emotionele waarde + tijdwinst | - -**Waarde Piramide:** - -``` - β–² - /β”‚\ - / β”‚ \ - / β”‚ \ - / β”‚ \ DELIGHT - / AI β”‚ \ "Het systeem denkt mee" - / suggestie \ - /──────────────\ - / \ - / Pre-fill \ SATISFACTION - / Voice input \ "Het begrijpt me" - / Snelle feedback \ - /────────────────────────\ - / \ - / Intent herkenning \ BASIC - / Blok openen \ "Het werkt" - / Opslaan lukt \ - /──────────────────────────────────\ -``` - -### 4.2 Implementatie Volgorde op Basis van Waarde - -``` -FASE 1: "Het werkt" (Basic) -───────────────────────── -β€’ Command Center layout -β€’ Text input β†’ Intent β†’ Blok openen -β€’ Dagnotitie blok (simpel form) -β€’ Opslaan + bevestiging - -FASE 2: "Het begrijpt me" (Satisfaction) -──────────────────────────────────────── -β€’ Voice input integratie -β€’ Patient pre-fill uit intent -β€’ Categorie herkenning -β€’ Zoeken blok - -FASE 3: "Het denkt mee" (Delight) -───────────────────────────────── -β€’ Rapportage met AI structurering -β€’ Overdracht met AI samenvatting -β€’ Suggesties ("wil je ook...?") -β€’ Context-aware hints -``` - -### 4.3 Concrete Implementatie Aanbevelingen - -**1. Start met Dagnotitie, niet Rapportage** - -*Waarom:* -- Dagnotitie is simpeler (1 tekstveld) -- Hogere frequentie = sneller feedback -- Sneller "waarde-bewijs" voor stakeholders -- Rapportage kan als "upgrade" komen - -**2. Bouw Zoeken als Fundament** - -```typescript -// Zoeken is de basis voor alles -"notitie jan" β†’ Zoek Jan β†’ Open Dagnotitie -"gesprek met jan" β†’ Zoek Jan β†’ Open Rapportage -"overdracht jan" β†’ Zoek Jan β†’ Open Overdracht - -// Zonder goede zoek = geen pre-fill = geen waarde -``` - -**3. Voice is Must-Have, niet Nice-to-Have** - -*Klant citaat:* -> "Ik draag handschoenen, ik heb net iemand gewassen, -> ik kan niet gaan typen. Voice is geen luxe." - -*Implementatie:* -- Voice input in Command Center (dag 1) -- Voice in Dagnotitie tekstveld (dag 1) -- Deepgram werkt al - alleen UI koppelen - -**4. Pre-fill is de "Magie"** - -```typescript -// Dit is het WOW-moment -Input: "Jan heeft medicatie gehad" - -Resultaat: -β”œβ”€β”€ Patient: Jan de Vries (auto-selected) -β”œβ”€β”€ Categorie: Medicatie (auto-selected) -β”œβ”€β”€ Tekst: "heeft medicatie gehad" (pre-filled) -└── Tijd: 14:32 (current time) - -// User hoeft alleen: review β†’ save -``` - -**5. Fallback = Vertrouwen** - -``` -Als intent mislukt: -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Ik begreep dat niet helemaal. β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ“ β”‚ β”‚ πŸ” β”‚ β”‚ πŸ“‹ β”‚ β”‚ πŸ”„ β”‚ β”‚ -β”‚ β”‚Notitie β”‚ β”‚ Zoeken β”‚ β”‚Rapport β”‚ β”‚Overdr. β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Of probeer opnieuw: ____________________________ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -// Nooit een doodlopende straat -``` - -### 4.4 Success Criteria (Waarde-Based) - -| Stakeholder | Success = | -|-------------|-----------| -| **Klant** | "Mijn team is 30 min/dag sneller klaar met admin" | -| **Zorgverlener** | "Ik hoef niet meer na te denken over het systeem" | -| **PO** | "Demo leidt tot concrete vervolgafspraak" | -| **UX** | "Users raken de fallback-picker zelden aan" | - ---- - -## 5. Actieplan - -### Week 1: Foundation + Eerste Waarde -- [ ] Command Center layout -- [ ] Dagnotitie blok (simpel) -- [ ] Basic intent classification -- [ ] Voice input in Command - -### Week 2: Core Waarde -- [ ] Zoeken blok (cmdk) -- [ ] Patient pre-fill -- [ ] Categorie herkenning -- [ ] Fallback blok-picker - -### Week 3: Waarde Uitbreiden -- [ ] Rapportage blok -- [ ] AI structurering -- [ ] Overdracht blok -- [ ] Microinteracties - -### Week 4: Demo + Metrics -- [ ] Demo scenario's perfectioneren -- [ ] Waarde-metrics implementeren -- [ ] LinkedIn content -- [ ] Stakeholder presentatie - ---- - -*De meeste waarde zit in de eenvoudigste dingen: snel een notitie maken, -snel iemand vinden, en het gevoel dat het systeem je begrijpt.* diff --git a/docs/swift/archive/swift-fo-ai.md b/docs/swift/archive/swift-fo-ai.md deleted file mode 100644 index a968e2a..0000000 --- a/docs/swift/archive/swift-fo-ai.md +++ /dev/null @@ -1,987 +0,0 @@ -# 🧩 Functioneel Ontwerp (FO) β€” Swift: Contextual UI EPD - -**Projectnaam:** Swift β€” Contextual UI EPD -**Versie:** v1.0 -**Datum:** 23-12-2024 -**Auteur:** Colin Lit - ---- - -## 1. Doel en relatie met het PRD - -🎯 **Doel van dit document:** -Dit Functioneel Ontwerp beschrijft **hoe** Swift uit het PRD functioneel werkt β€” wat de gebruiker ziet, doet en ervaart. Waar het PRD het concept en de architectuur beschrijft, laat dit FO zien hoe elke interactie in de praktijk werkt. - -πŸ“˜ **Relatie met andere documenten:** -- **PRD:** `nextgen-epd-prd-ephemeral-ui-epd.md` β€” Wat en waarom -- **UX/UI:** `ux-ui-design-ephemeral-ui-epd-v2.1.md` β€” Visuele specificaties -- **Taken analyse:** `taken-en-vragen-analyse.md` β€” Frequentie en prioritering - -**Kernprincipe:** -> De gebruiker navigeert niet door menu's. De gebruiker spreekt of typt een intentie β€” en het juiste bouwblok verschijnt, voorgevuld met relevante data. - ---- - -## 2. Overzicht van de belangrijkste onderdelen - -🎯 **Doel:** Overzicht van alle modules en hun relaties. - -### 2.1 Systeemcomponenten - -| # | Component | Beschrijving | Type | -|---|-----------|--------------|------| -| 1 | **Command Center** | Hoofdscherm met één input | Scherm | -| 2 | **Context Bar** | Dienst, patiΓ«nt, user info | UI Zone | -| 3 | **Canvas Area** | Waar blocks verschijnen | UI Zone | -| 4 | **Recent Strip** | Laatste acties quick access | UI Zone | -| 5 | **Command Input** | Tekst + voice input | UI Zone | -| 6 | **Intent Engine** | Classificeert gebruikersinput | Backend | -| 7 | **Context Manager** | Beheert sessie context | Backend | - -### 2.2 Bouwblokken (Blocks) - -| Prio | Block | Functie | Trigger voorbeelden | -|------|-------|---------|---------------------| -| P1 | **DagnotatieBlock** | Snelle notitie invoer | "notitie jan medicatie" | -| P1 | **ZoekenBlock** | PatiΓ«nt zoeken | "zoek marie" | -| P1 | **PatientContextCard** | PatiΓ«nt overzicht | Na zoeken / selectie | -| P1 | **OverdrachtBlock** | Dienst overdracht | "overdracht maken" | -| P2 | **RapportageBlock** | Behandelrapportage | "gesprek gehad met jan" | -| P2 | **AgendaBlock** | Afspraken | "mijn afspraken" | -| P2 | **MetingenBlock** | Vitale functies | "bloeddruk invoeren" | -| P3 | **IntakeWizard** | Nieuwe patiΓ«nt intake | "nieuwe intake" | -| P3 | **BehandelplanBlock** | Behandelplan | "behandelplan jan" | -| P3 | **RisicoBlock** | Risicotaxatie | "risico jan" | -| P3 | **ContactenBlock** | Contactpersonen | "contacten jan" | - -### 2.3 Systeem Blocks - -| Block | Functie | Trigger | -|-------|---------|---------| -| **HelpBlock** | Hulp en voorbeelden | "help", "wat kan ik" | -| **FallbackPicker** | Visuele keuze bij onduidelijkheid | Lage confidence | - ---- - -## 3. User Stories - -🎯 **Doel:** Beschrijven wat gebruikers moeten kunnen doen, vanuit hun perspectief. - -### 3.1 P1: Kritieke Stories (MVP Week 1-2) - -| ID | Rol | Doel / Actie | Verwachte waarde | Prio | -|----|-----|--------------|------------------|------| -| US-01 | Verpleegkundige | Dagnotitie maken door te spreken/typen | Registratie in 15 sec ipv 5 min | πŸ”΄ P1 | -| US-02 | Verpleegkundige | PatiΓ«nt zoeken op naam | Direct vinden zonder navigatie | πŸ”΄ P1 | -| US-03 | Verpleegkundige | PatiΓ«nt context zien na selectie | Alles relevante in één oogopslag | πŸ”΄ P1 | -| US-04 | Verpleegkundige | Overdracht maken einde dienst | Complete overdracht in 5 min | πŸ”΄ P1 | -| US-05 | Alle gebruikers | Weten wat het systeem kan | "help" toont mogelijkheden | πŸ”΄ P1 | -| US-06 | Alle gebruikers | Kiezen als systeem niet begrijpt | Visuele fallback picker | πŸ”΄ P1 | - -### 3.2 P2: Belangrijke Stories (MVP Week 3-4) - -| ID | Rol | Doel / Actie | Verwachte waarde | Prio | -|----|-----|--------------|------------------|------| -| US-07 | Behandelaar | Rapportage schrijven na gesprek | Dicteren + AI samenvatting | 🟑 P2 | -| US-08 | Behandelaar | Agenda bekijken | Afspraken vandaag/week | 🟑 P2 | -| US-09 | Verpleegkundige | Meting invoeren | Vitals met trend indicator | 🟑 P2 | -| US-10 | Behandelaar | Diagnose/plan van patiΓ«nt zien | Via PatientContextCard | 🟑 P2 | - -### 3.3 P3: Post-MVP Stories - -| ID | Rol | Doel / Actie | Verwachte waarde | Prio | -|----|-----|--------------|------------------|------| -| US-11 | Behandelaar | Nieuwe intake starten | Wizard begeleidt proces | 🟒 P3 | -| US-12 | Behandelaar | Behandelplan maken/bewerken | AI-gegenereerd, bewerkbaar | 🟒 P3 | -| US-13 | Verpleegkundige | Risicotaxatie invullen | Gestructureerd formulier | 🟒 P3 | -| US-14 | Behandelaar | Contactpersonen beheren | Noodcontact, familie | 🟒 P3 | - ---- - -## 4. Functionele werking per onderdeel - -🎯 **Doel:** Per component beschrijven wat de gebruiker kan doen en wat het systeem doet. - -### 4.1 Command Center (Hoofdscherm) - -**Beschrijving:** -Het enige scherm van de applicatie. Geen sidebar, geen menu's. Alles gebeurt via één input. - -**Layout:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ [Context Bar: Dienst | PatiΓ«nt dropdown | User] 48px β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ [Active Block Area] β”‚ -β”‚ Blocks verschijnen hier β”‚ -β”‚ Centered, responsive width β”‚ -β”‚ Flex β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [Recent Strip: laatste acties als badges] 48px β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [Command Input: 🎀 Typ of spreek wat je wilt doen...] 64px β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Gedrag:** -- Bij laden: Command Input heeft focus -- Keyboard shortcut `⌘K` focust input vanaf elke plek -- Blocks verschijnen met fade+scale animatie -- Slechts één block actief tegelijk (of gestapeld met z-index) - ---- - -### 4.2 Context Bar - -**Functie:** Toont essentiΓ«le context: welke dienst, welke patiΓ«nt actief, wie ingelogd. - -**Elementen:** - -| Element | Locatie | Gedrag | -|---------|---------|--------| -| Dienst indicator | Links | "πŸŒ… Ochtend \| 8 ptn" β€” kleur per shift | -| Actieve patiΓ«nt | Midden-rechts | Dropdown voor quick-switch | -| User | Rechts | Initialen, klik β†’ logout | - -**Dienst bepaling:** - -| Dienst | Tijd | Kleur | Icon | -|--------|------|-------|------| -| Ochtend | 07:00-15:00 | Amber #F59E0B | πŸŒ… | -| Middag | 15:00-23:00 | Blue #3B82F6 | 🌀️ | -| Nacht | 23:00-07:00 | Indigo #6366F1 | πŸŒ™ | - -**PatiΓ«nt Dropdown:** -- Toont huidige selectie (of "Geen patiΓ«nt") -- Recent bekeken patiΓ«nten (max 5) -- Zoek optie onderaan -- "Clear" optie om selectie te wissen - ---- - -### 4.3 Command Input - -**Functie:** Het hart van de interface β€” tekst Γ©n voice input. - -**States:** - -| State | Weergave | Trigger | -|-------|----------|---------| -| Default | "🎀 Typ of spreek wat je wilt doen..." | β€” | -| Typing | Cursor, getypte tekst | Keyboard input | -| Listening | πŸ”΄ + waveform + live transcript | Mic click of spatie (bij leeg) | -| Processing | ⏳ spinner + "Even kijken..." | Na submit | - -**Acties:** - -| Input | Actie | -|-------|-------| -| `Enter` | Submit naar Intent Engine | -| `Escape` | Clear input / close block | -| `↑` | Vorige command (history) | -| `Space` (leeg) | Start voice | -| Mic click | Toggle voice recording | - -**Voice Flow:** -1. User klikt mic of drukt spatie (bij lege input) -2. Deepgram start streaming transcription -3. Live transcript verschijnt in input -4. Pauze detectie (1.5 sec stilte) β†’ auto-submit -5. Of user klikt "Stop" β†’ submit - ---- - -### 4.4 Intent Engine - -**Functie:** Classificeert gebruikersinput naar intent + entities. - -**Input:** -```typescript -{ - text: string; // "notitie jan medicatie gegeven" - context: { - activePatient?: Patient; - currentShift: 'ochtend' | 'middag' | 'nacht'; - recentPatients: Patient[]; - } -} -``` - -**Output:** -```typescript -{ - intent: IntentType; // 'dagnotitie' - confidence: number; // 0.94 - entities: { - patientName?: string; // "jan" - patientId?: string; // "uuid-123" (als gevonden) - category?: string; // "medicatie" - content?: string; // "gegeven" - date?: string; - }; - clarificationNeeded: boolean; - clarificationQuestion?: string; -} -``` - -**Intent Types:** - -| Intent | Block | Confidence drempel | -|--------|-------|-------------------| -| `dagnotitie` | DagnotatieBlock | 0.7 | -| `zoeken` | ZoekenBlock | 0.7 | -| `overdracht` | OverdrachtBlock | 0.8 | -| `rapportage` | RapportageBlock | 0.7 | -| `agenda` | AgendaBlock | 0.7 | -| `metingen` | MetingenBlock | 0.7 | -| `intake` | IntakeWizard | 0.8 | -| `behandelplan` | BehandelplanBlock | 0.8 | -| `risico` | RisicoBlock | 0.8 | -| `patient_info` | PatientContextCard | 0.7 | -| `help` | HelpBlock | 0.9 | -| `onbekend` | FallbackPicker | < 0.5 | - -**Clarification Flow:** -- Confidence < drempel β†’ vraag om verduidelijking -- Meerdere patient matches β†’ toon selector -- Geen patient bij patient-required intent β†’ vraag welke patient - ---- - -### 4.5 DagnotatieBlock - -**Functie:** Snelle notitie invoer β€” meest gebruikte actie (10-20x per dag). - -**Trigger patterns:** -- "notitie [patient]" -- "[patient] medicatie gegeven" -- "incident bij [patient]" -- "[patient] heeft goed gegeten" - -**Pre-fill logica:** - -| Extracted | Pre-fill | -|-----------|----------| -| patient_name β†’ match | Patient selector | -| "medicatie" keyword | Category = Medicatie | -| "gegeten", "ADL" | Category = ADL | -| "incident", "agressie" | Category = Incident | -| Overige tekst | Notitie veld | - -**Form velden:** - -| Veld | Type | Verplicht | Default | -|------|------|-----------|---------| -| Patient | Dropdown + search | Ja | Pre-filled of activePatient | -| Categorie | Button group | Ja | Extracted of Algemeen | -| Notitie | Textarea | Ja | Extracted content | -| Tijd | Time picker | Ja | Nu | -| In overdracht | Checkbox | Nee | false | - -**CategorieΓ«n:** - -| Categorie | Icon | Kleur | Keyboard | -|-----------|------|-------|----------| -| Medicatie | πŸ’Š | Amber | 1 | -| ADL | 🍽️ | Green | 2 | -| Observatie | πŸ‘οΈ | Blue | 3 | -| Incident | ⚠️ | Red | 4 | -| Algemeen | πŸ’¬ | Gray | 5 | - -**Acties:** - -| Knop | Actie | Keyboard | -|------|-------|----------| -| Opslaan | POST naar API, sluit block | `⌘Enter` | -| Annuleren | Sluit block zonder opslaan | `Escape` | - -**Na opslaan:** -1. Toast: "βœ“ Notitie opgeslagen" -2. Block verdwijnt (200ms animatie) -3. Recent strip: badge "[πŸ“ Jan-Med]" -4. Input krijgt focus voor volgende actie - -**API:** -``` -POST /api/reports -Body: { - patient_id: string, - type: 'nursing_log', - category: string, - content: string, - timestamp: datetime, - include_in_handover: boolean -} -``` - ---- - -### 4.6 ZoekenBlock - -**Functie:** PatiΓ«nt zoeken en selecteren. - -**Trigger patterns:** -- "zoek [naam]" -- "wie is [naam]" -- "vind [naam]" - -**Gedrag:** -1. Block opent met zoekterm pre-filled -2. Live search (debounced 300ms) -3. Resultaten tonen met relevante info -4. Klik of Enter selecteert patiΓ«nt - -**Resultaat card bevat:** -- Naam (highlighted match) -- Leeftijd -- Kamer/locatie -- Laatste activiteit ("2 uur geleden") -- Alert badge indien aanwezig - -**Na selectie:** -1. ZoekenBlock sluit -2. PatientContextCard opent automatisch -3. Context Bar update: patient dropdown toont selectie -4. Recent strip: badge "[πŸ” Jan]" - -**Empty state:** -"Geen patiΓ«nten gevonden voor '[zoekterm]'" - -**API:** -``` -GET /api/patients/search?q={zoekterm} -Response: Patient[] met relevance score -``` - ---- - -### 4.7 PatientContextCard - -**Functie:** Compact overzicht van alles relevant voor één patiΓ«nt. - -**Trigger:** -- Automatisch na patiΓ«nt selectie -- "info [patient]", "dossier [patient]" -- Klik op patiΓ«nt in dropdown - -**Secties (adaptive - alleen tonen als data aanwezig):** - -| Sectie | Data | Bron | -|--------|------|------| -| Header | Naam, leeftijd, kamer, opnamedatum | patients | -| Alert | Actieve alerts/risico's | risk_assessments | -| Laatste notities | 3 meest recente | reports | -| Vitals | Vandaag gemeten | vitals | -| Diagnose | Hoofddiagnose + ernst | conditions | -| Behandelplan | Status, sessie X/Y, volgende eval | care_plans | -| Contacten | Primaire contact | contacts | - -**Quick Actions (onderaan):** -``` -[πŸ“ Notitie] [πŸ“‹ Rapport] [πŸ“Š Meting] [πŸ“„ Plan] [πŸ“ž Contact] -``` - -Klik op quick action β†’ opent betreffende block met patient pre-filled. - -**API:** -``` -GET /api/patients/{id}/context -Response: { - patient: Patient, - alerts: Alert[], - recentNotes: Report[], - vitals: Vital[], - diagnosis: Condition, - carePlan: CarePlan, - contacts: Contact[] -} -``` - ---- - -### 4.8 OverdrachtBlock - -**Functie:** Multi-patiΓ«nt overdracht met AI-samenvattingen. - -**Trigger patterns:** -- "overdracht maken" -- "dienst klaar" -- "samenvatting voor collega" - -**Proactive trigger:** -- 30 minuten voor dienst einde β†’ suggestie banner - -**Layout:** -- Header: "Overdracht [Ochtend] β†’ [Middag]" + tijdrange -- Accordion per patiΓ«nt (expanded als alert aanwezig) -- AI samenvatting per patiΓ«nt -- Bronverwijzingen naar originele notities -- Footer: Kopieer / E-mail / Afronden - -**Per patiΓ«nt accordion:** - -| Element | Beschrijving | -|---------|--------------| -| Header | Naam + alert badge | -| Summary | AI-gegenereerde samenvatting | -| Bronnen | "πŸ“Ž 3 notities" β€” klik opent details | -| Bewerken | Inline edit van samenvatting | - -**AI Samenvatting:** -- Gegenereerd op basis van: nursing_logs, vitals, rapportages -- Tijdrange: huidige dienst (default 8 uur) -- Max 3 zinnen per patiΓ«nt -- Aandachtspunten prominent - -**Acties:** - -| Knop | Actie | -|------|-------| -| Kopieer alles | Alle samenvattingen naar clipboard | -| E-mail | Open mail client met content | -| Afronden | Markeer overdracht compleet | - -**API:** -``` -POST /api/overdracht/generate -Body: { - patientIds: string[], - shiftStart: datetime, - shiftEnd: datetime -} -Response: { - summaries: { patientId: string, summary: string, sources: Source[] }[] -} -``` - ---- - -### 4.9 RapportageBlock - -**Functie:** Uitgebreide behandelrapportage met rich text en AI. - -**Trigger patterns:** -- "rapportage" -- "gesprek gehad met [patient]" -- "behandelgesprek" - -**Form velden:** - -| Veld | Type | Default | -|------|------|---------| -| Patient | Dropdown | Pre-filled of activePatient | -| Type | Button group | Gesprek | -| Inhoud | Rich text (TipTap) | Leeg of transcript | -| Datum/tijd | DateTime | Nu | - -**Rapportage types:** -- Gesprek -- Evaluatie -- Telefonisch -- Consult -- Familie - -**Rich text toolbar:** -- Bold, Italic -- Bullet list, Numbered list -- Quote -- H1, H2 -- 🎀 Dicteer knop - -**AI acties:** - -| Actie | Beschrijving | Output | -|-------|--------------|--------| -| ✨ Samenvatten | Bullets van kernpunten | Zijpaneel | -| πŸ“– B1-niveau | Herschrijf leesbaar | Zijpaneel | -| πŸ” Problemen | Extraheer klinische issues | Zijpaneel | - -**AI Zijpaneel:** -- Verschijnt rechts van editor -- Preview van AI output -- Knoppen: Invoegen, KopiΓ«ren, Verwerp - -**API:** -``` -POST /api/reports -Body: { - patient_id: string, - type: 'rapportage', - subtype: string, - content: string (HTML), - timestamp: datetime -} -``` - ---- - -### 4.10 AgendaBlock - -**Functie:** Afspraken overzicht en beheer. - -**Trigger patterns:** -- "agenda" -- "afspraken vandaag" -- "wie zie ik deze week" -- "afspraken [patient]" - -**Layout:** -- Navigatie: [β—€ Gisteren] [Vandaag] [Morgen β–Ά] -- View toggle: [Dag] [Week] -- Lijst van afspraken met tijden - -**Per afspraak:** -- Tijd (09:00 - 09:50) -- PatiΓ«ntnaam -- Type afspraak -- Quick actions: [Open dossier] [Notitie] - -**Acties:** -- Klik op afspraak β†’ open PatientContextCard -- [+ Nieuwe afspraak] β†’ AfspraakBlock (P4) - -**API:** -``` -GET /api/appointments?date={date}&practitionerId={id} -Response: Appointment[] -``` - ---- - -### 4.11 MetingenBlock - -**Functie:** Vitale functies invoeren. - -**Trigger patterns:** -- "bloeddruk invoeren" -- "meting [patient]" -- "vitals" -- "temperatuur" - -**Form velden:** - -| Veld | Type | Validatie | -|------|------|-----------| -| Patient | Dropdown | Verplicht | -| Type | Button group | Verplicht | -| Waarde(s) | Number input(s) | Per type | -| Tijd | DateTime | Default: nu | -| Opmerking | Textarea | Optioneel | - -**Meting types:** - -| Type | Velden | Eenheid | -|------|--------|---------| -| Bloeddruk | Systolisch, Diastolisch | mmHg | -| Pols | BPM | /min | -| Temperatuur | Temp | Β°C | -| Gewicht | Kg | kg | -| Glucose | mmol/L | mmol/L | -| Saturatie | % | SpO2 | - -**Trend indicator:** -Na invoer: vergelijk met vorige meting -- ↑ Hoger dan vorige -- ↓ Lager dan vorige -- β†’ Gelijk - -**API:** -``` -POST /api/vitals -Body: { - patient_id: string, - type: string, - values: Record, - timestamp: datetime, - notes?: string -} -``` - ---- - -### 4.12 HelpBlock - -**Functie:** Toont wat het systeem kan. - -**Trigger patterns:** -- "help" -- "wat kan ik doen" -- "hoe werkt dit" - -**Inhoud:** -Gegroepeerde voorbeelden per categorie: -- πŸ“ Notities: "notitie jan medicatie" -- πŸ” Zoeken: "zoek marie" -- πŸ”„ Overdracht: "overdracht maken" -- πŸ“‹ Rapportage: "gesprek gehad" -- πŸ“… Agenda: "afspraken vandaag" -- etc. - ---- - -### 4.13 FallbackPicker - -**Functie:** Visuele keuze wanneer intent onduidelijk is. - -**Trigger:** -- Intent confidence < 0.5 -- Intent = 'onbekend' - -**Layout:** -Grid van 8-10 opties met icon + label. -Keyboard shortcuts 1-9 voor snelle selectie. - -**Opties:** -``` -[πŸ“ Notitie] [πŸ” Zoeken] [πŸ”„ Overdracht] [πŸ“‹ Rapport] -[πŸ“… Agenda] [πŸ“Š Meting] [πŸ‘€ Dossier] [πŸ“„ Intake] -[⚠️ Risico] [πŸ’‘ Help] -``` - ---- - -### 4.14 Recent Strip - -**Functie:** Quick access naar recente acties. - -**Gedrag:** -- Max 5 badges zichtbaar -- Nieuwste links -- Horizontal scroll voor meer -- Klik = heropen context - -**Badge types:** - -| Type | Icon | Kleur | Klik actie | -|------|------|-------|------------| -| Dagnotitie | πŸ“ | Category kleur | Open PatientContextCard | -| Zoeken | πŸ” | Gray | Open PatientContextCard | -| Overdracht | πŸ”„ | Blue | Open OverdrachtBlock | -| Rapportage | πŸ“‹ | Green | Open RapportageBlock | - ---- - -## 5. UI-overzicht (visuele structuur) - -🎯 **Doel:** Globale schermopbouw en component hiΓ«rarchie. - -### 5.1 Hoofdlayout - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸŒ… Ochtend | 8 ptn Jan de Vries β–Ό πŸ‘€ SV β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ CONTEXT BAR (48px) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ ACTIVE BLOCK β”‚ β”‚ -β”‚ β”‚ (Small: 480px) β”‚ β”‚ -β”‚ β”‚ (Medium: 640px) β”‚ β”‚ -β”‚ β”‚ (Large: 900px) β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ CANVAS AREA (flex) β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Recent: [πŸ“ Jan-Med] [πŸ”„ Overdracht] [πŸ” Marie] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ RECENT STRIP (48px) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 🎀 Typ of spreek wat je wilt doen... ⌘K β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ COMMAND INPUT (64px) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 5.2 Block Sizes - -| Size | Max-width | Use case | -|------|-----------|----------| -| Small | 480px | Quick entry (notitie, zoeken, meting) | -| Medium | 640px | Forms (rapportage, behandelplan) | -| Large | 900px | Overzichten (overdracht, agenda) | -| XLarge | 1100px | Wizards (intake) | - -### 5.3 Block Container - -Alle blocks gebruiken dezelfde wrapper: - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ [Icon] [Title] [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ BLOCK CONTENT β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [Cancel] [Save] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 6. Interacties met AI (functionele beschrijving) - -🎯 **Doel:** Waar AI in de flow voorkomt en wat de gebruiker ziet. - -### 6.1 Intent Classification - -| Locatie | Trigger | Input | Output | -|---------|---------|-------|--------| -| Command Input | Submit | Tekst/transcript | Intent + entities + confidence | - -### 6.2 Content AI - -| Locatie | AI-actie | Trigger | Output | -|---------|----------|---------|--------| -| RapportageBlock | Samenvatten | Klik knop | Bullets in zijpaneel | -| RapportageBlock | B1-niveau | Klik knop | Herschreven tekst | -| RapportageBlock | Extract problemen | Klik knop | Categorie + severity | -| OverdrachtBlock | Genereer samenvatting | Per patiΓ«nt accordion | 3-zin summary | -| BehandelplanBlock | Genereer plan | Klik knop | Doelen + interventies | -| IntakeWizard | Suggestie diagnose | Na anamnese stap | ICD-10 code + rationale | - -### 6.3 AI Response Handling - -**Alle AI outputs:** -1. Tonen in dedicated preview area (niet direct in form) -2. User moet expliciet accepteren/invoegen -3. Bewerken altijd mogelijk -4. Annuleren zonder gevolgen - -**Loading state:** -- Skeleton loader in output area -- "AI denkt na..." indicator -- Non-blocking (user kan annuleren) - -**Error handling:** -- "Kon niet verwerken. Probeer opnieuw." -- Retry knop -- Fallback naar handmatige invoer - ---- - -## 7. Proactieve Triggers - -🎯 **Doel:** Wanneer het systeem zelf UI toont zonder expliciete vraag. - -| Trigger | Conditie | Actie | -|---------|----------|-------| -| Dienst start | Login of shift wissel | Suggestie: OverdrachtLezenBlock | -| Dienst einde | 30 min voor einde | Banner: "Overdracht maken?" | -| PatiΓ«nt geselecteerd | Na zoeken/klik | Auto-open PatientContextCard | -| Afspraak nadert | 15 min voor afspraak | Suggestie: patiΓ«nt openen | -| Alert aanwezig | PatiΓ«nt met actief risico | Alert banner in PatientContextCard | - -**Suggestie Banner:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ• Dienst eindigt over 30 min. Overdracht maken? β”‚ -β”‚ [Ja] [Later] [Γ—] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -- Niet-blokkerend (user kan negeren) -- "Later" = herinner over 15 min -- "Γ—" = niet meer voor deze dienst - ---- - -## 8. States & Error Handling - -### 8.1 Block States - -| State | Weergave | -|-------|----------| -| Loading | Skeleton loader | -| Ready | Form/content | -| Submitting | Disabled + spinner | -| Success | Toast + close | -| Error | Inline error message | - -### 8.2 Network Errors - -| Situatie | Gedrag | -|----------|--------| -| API timeout | "Verbinding verbroken. Probeer opnieuw." + retry | -| 401 Unauthorized | Redirect naar login | -| 500 Server error | "Er ging iets mis. Probeer later opnieuw." | -| Offline | Banner bovenin: "Geen internetverbinding" | - -### 8.3 Validation Errors - -| Veld | Validatie | Foutmelding | -|------|-----------|-------------| -| Patient | Verplicht | "Selecteer een patiΓ«nt" | -| Notitie | Min 5 karakters | "Voer een notitie in" | -| Bloeddruk | 50-250 / 30-150 | "Waarde buiten bereik" | - ---- - -## 9. Gebruikersrollen en rechten - -🎯 **Doel:** Welke rollen toegang hebben tot welke onderdelen. - -| Rol | Toegang | Beperkingen | -|-----|---------|-------------| -| Verpleegkundige | Dagnotitie, Zoeken, Overdracht, Metingen | Geen behandelplan bewerken | -| Behandelaar | Alle blocks | Alleen eigen patiΓ«nten bewerken | -| Psychiater | Alle blocks + diagnose | Alleen eigen patiΓ«nten | -| Demo-user | Alle blocks (fictieve data) | Alleen lezen | - ---- - -## 10. Keyboard Shortcuts - -| Shortcut | Actie | Scope | -|----------|-------|-------| -| `⌘K` | Focus command input | Global | -| `Escape` | Sluit actieve block | Block open | -| `Enter` | Submit form | Form focused | -| `⌘Enter` | Opslaan | In form | -| `1-5` | Selecteer categorie | DagnotatieBlock | -| `1-9` | Selecteer optie | FallbackPicker | -| `↑` `↓` | Navigeer resultaten | ZoekenBlock | -| `Space` | Start voice (lege input) | Command Input | - ---- - -## 11. Navigatie & Toegang - -🎯 **Doel:** Beschrijven hoe gebruikers Swift bereiken en kiezen. - -### 11.1 User Journey naar Swift - -``` -LANDINGSPAGINA (/) - β”‚ - β”‚ Storytelling + Demo - β”‚ - β–Ό -LOGIN PAGINA (/login) - β”‚ - β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ β”‚ Kies je werkwijze: β”‚ - β”‚ β”‚ β”‚ - β”‚ β”‚ β—‹ ✨ Swift β€” Spreek of typ β”‚ - β”‚ β”‚ β—‹ πŸ“‹ Klassiek β€” Menu's en forms β”‚ - β”‚ β”‚ β”‚ - β”‚ β”‚ ☐ Onthoud mijn keuze β”‚ - β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β–Ό β–Ό β”‚ - /epd/swift /epd/dashboard β”‚ - (Command Center) (Klassiek EPD) β”‚ - β”‚ - β”‚ - GEEN TOGGLE β—„β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - binnen interface -``` - -### 11.2 Landingspagina Elementen - -De landingspagina introduceert Swift via storytelling: - -| Element | Functie | -|---------|---------| -| **Hero** | Probleem: "40% admin tijd" β†’ Oplossing: "1 zin, klaar" | -| **Interactive Demo** | Probeer Swift zonder login | -| **Side-by-side** | 12 klikken klassiek vs 1 zin Swift | -| **Video** | Demo van dagnotitie flow | -| **CTA** | "Aan de slag" β†’ /login | - -### 11.3 Login Pagina met Interface Keuze - -De login pagina bevat een interface selector: - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ [Bestaand login formulier - email, wachtwoord] β”‚ -β”‚ β”‚ -β”‚ ───────────────────────────────────────────────────────────── β”‚ -β”‚ β”‚ -β”‚ Kies je werkwijze: β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ ✨ Swift β”‚ β”‚ πŸ“‹ Klassiek β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Spreek of typ wat je β”‚ β”‚ Vertrouwde menu's β”‚ β”‚ -β”‚ β”‚ wilt β€” het systeem β”‚ β”‚ en formulieren β”‚ β”‚ -β”‚ β”‚ begrijpt β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ "notitie jan med" β†’ β”‚ β”‚ Dashboard β†’ Patient β”‚ β”‚ -β”‚ β”‚ klaar in 15 sec β”‚ β”‚ β†’ Tab β†’ Form β†’ Save β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ ☐ Onthoud mijn keuze β”‚ -β”‚ β”‚ -β”‚ [Inloggen] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 11.4 Redirect Gedrag - -| Situatie | Gedrag | -|----------|--------| -| Nieuwe user, geen preference | Toon keuze op login pagina | -| User met preference + "onthoud" | Direct door naar gekozen interface | -| User naar `/epd` | Redirect naar preference of dashboard | -| Uitgelogd | Terug naar login met keuze optie | - -### 11.5 Geen Toggle in Interface - -Er is **geen mogelijkheid** om binnen Swift of Klassiek EPD te wisselen naar de andere interface: - -- Geen toggle button in Swift -- Geen toggle button in Klassiek EPD -- Om te wisselen: uitloggen β†’ opnieuw inloggen β†’ andere keuze - -**Rationale:** -- Voorkomt verwarring over "waar ben ik" -- Gebruiker committed aan één ervaring -- Admin kan preference aanpassen indien nodig - -### 11.6 Admin Beheer - -Alleen admins kunnen de interface preference van andere users wijzigen: - -| Actie | Wie | Waar | -|-------|-----|------| -| Eigen preference instellen | Alle users | Login pagina | -| Preference andere user wijzigen | Admin | Admin panel | -| Geforceerd naar Swift/Klassiek | Admin | Admin panel | - ---- - -## 12. Bijlagen & Referenties - -**Projectdocumenten:** -- PRD: `swift-prd.md` -- UX/UI: `swift-ux-v2.1.md` -- TO: `to-swift-v1.md` -- Taken analyse: `taken-en-vragen-analyse.md` - -**Bestaande documentatie:** -- Database schema: Supabase migrations -- Bestaande FO overdracht: `fo-overdracht-dashboard-v1_1.md` (archive) - ---- - -## Wijzigingslog - -| Versie | Datum | Wijzigingen | -|--------|-------|-------------| -| 1.0 | 23-12-2024 | InitiΓ«le versie op basis van PRD en UX/UI v2.1 | -| 1.1 | 23-12-2024 | Hernoemd naar Swift, toegevoegd: Navigatie & Toegang sectie | \ No newline at end of file diff --git a/docs/swift/archive/swift-fo-diagnostiek-workflow.md b/docs/swift/archive/swift-fo-diagnostiek-workflow.md deleted file mode 100644 index ee5170b..0000000 --- a/docs/swift/archive/swift-fo-diagnostiek-workflow.md +++ /dev/null @@ -1,725 +0,0 @@ -# 🧩 Functioneel Ontwerp (FO) β€” Swift: Diagnostiek Workflow - -**Projectnaam:** Swift β€” Contextual UI EPD -**Versie:** v1.0 -**Datum:** 23-12-2024 -**Auteur:** Colin Lit - ---- - -## 1. Doel en relatie met het PRD - -🎯 **Doel van dit document:** -Dit Functioneel Ontwerp beschrijft **hoe** de diagnostiek workflow in Swift functioneel werkt β€” van het plannen van een diagnostiek-afspraak tot het stellen en bijstellen van diagnoses. Dit document focust specifiek op de complete flow die behandelaars doorlopen tijdens een diagnostiek-traject. - -πŸ“˜ **Relatie met andere documenten:** -- **PRD:** `swift-prd.md` β€” Product visie en requirements -- **FO Algemeen:** `swift-fo-ai.md` β€” Algemene Swift functionaliteit -- **Bouwplan:** `bouwplan-swift-v1.md` β€” Technische implementatie planning -- **UX/UI:** `swift-ux-v2.1.md` β€” Visuele specificaties - -**Kernprincipe:** -> Een behandelaar kan een volledig diagnostiek-traject doorlopen via natuurlijke taal: van afspraak plannen, via rapportage schrijven, tot diagnose stellen β€” alles in één vloeiende flow zonder menu-navigatie. - ---- - -## 2. Overzicht van de belangrijkste onderdelen - -🎯 **Doel:** Overzicht van de modules en blocks binnen de diagnostiek workflow. - -### 2.1 Workflow Componenten - -| # | Component | Beschrijving | Type | -|---|-----------|--------------|------| -| 1 | **AfspraakBlock** | Diagnostiek-afspraak plannen | Block | -| 2 | **RapportageBlock** | Verslag schrijven na afspraak | Block | -| 3 | **DiagnoseBlock** | Overzicht van diagnoses | Block | -| 4 | **DiagnoseFormBlock** | Diagnose aanmaken/bijstellen | Block | - -### 2.2 Workflow Flow - -``` -Afspraak Plannen β†’ Rapportage Schrijven β†’ Diagnose Bekijken β†’ Diagnose Aanmaken/Bijstellen -``` - -### 2.3 Relatie met Bestaande Blocks - -| Block | Relatie met Diagnostiek Workflow | -|-------|----------------------------------| -| **ZoekenBlock** | Wordt gebruikt voor patiΓ«ntselectie | -| **PatientContextCard** | Toont actieve diagnoses in overzicht | -| **AgendaBlock** | Toont geplande diagnostiek-afspraken | - ---- - -## 3. User Stories - -🎯 **Doel:** Beschrijven wat behandelaars moeten kunnen doen tijdens een diagnostiek-traject. - -### 3.1 Diagnostiek Workflow Stories - -| ID | Rol | Doel / Actie | Verwachte waarde | Prio | -|----|-----|--------------|------------------|------| -| US-D01 | Behandelaar | Diagnostiek-afspraak plannen via spraak/tekst | Afspraak in < 30 sec zonder menu-navigatie | 🟑 P2 | -| US-D02 | Behandelaar | Rapportage schrijven en koppelen aan afspraak | Verslag automatisch gekoppeld aan encounter | 🟑 P2 | -| US-D03 | Behandelaar | Alle diagnoses van patiΓ«nt bekijken | Overzicht in één oogopslag | 🟑 P2 | -| US-D04 | Behandelaar | Nieuwe diagnose toevoegen met ICD-10 zoeker | Diagnose toegevoegd met correcte code | 🟑 P2 | -| US-D05 | Behandelaar | Bestaande diagnose bijstellen (status, ernst) | Wijzigingen direct zichtbaar | 🟑 P2 | - -### 3.2 User Story Details - -**US-D01: Diagnostiek-afspraak plannen** -> Als behandelaar wil ik een diagnostiek-afspraak kunnen plannen door te zeggen "afspraak diagnostiek met Jan morgen 10:00" zodat ik snel kan plannen zonder door menu's te navigeren. - -**US-D02: Rapportage koppelen aan afspraak** -> Als behandelaar wil ik een rapportage kunnen schrijven die automatisch gekoppeld wordt aan de diagnostiek-afspraak zodat ik niet handmatig hoef te koppelen. - -**US-D03: Diagnoses bekijken** -> Als behandelaar wil ik alle diagnoses van een patiΓ«nt kunnen bekijken door te zeggen "diagnose Jan" zodat ik snel een overzicht heb zonder te navigeren. - -**US-D04: Diagnose toevoegen** -> Als behandelaar wil ik een nieuwe diagnose kunnen toevoegen met een ICD-10 zoeker zodat ik de juiste code kan vinden zonder handmatig te zoeken. - -**US-D05: Diagnose bijstellen** -> Als behandelaar wil ik een bestaande diagnose kunnen bijstellen (status, ernst) zodat ik diagnoses kan actualiseren na behandeling. - ---- - -## 4. Functionele werking per onderdeel - -🎯 **Doel:** Per component beschrijven wat de gebruiker kan doen en wat het systeem doet. - -### 4.1 AfspraakBlock - -**Functie:** Diagnostiek-afspraak plannen via natuurlijke taal. - -**Trigger patterns:** -- "afspraak diagnostiek met [patient] [datum] [tijd]" -- "plan diagnostiek voor [patient] morgen" -- "afspraak [patient] volgende week dinsdag 10:00" - -**Pre-fill logica:** - -| Extracted | Pre-fill | -|-----------|----------| -| patient_name β†’ match | PatiΓ«nt selector | -| "diagnostiek" keyword | Type = Diagnostiek | -| "morgen", "vandaag", datum | Datum picker | -| Tijd (10:00, 14:30) | Starttijd | -| Geen tijd | Default 09:00 | - -**Form velden:** - -| Veld | Type | Verplicht | Default | -|------|------|-----------|---------| -| PatiΓ«nt | Dropdown + search | Ja | Pre-filled of ZoekenBlock | -| Datum | Date picker | Ja | Pre-filled of vandaag | -| Starttijd | Time picker | Ja | Pre-filled of 09:00 | -| Eindtijd | Time picker | Nee | Starttijd + 1 uur | -| Type | Dropdown | Ja | Diagnostiek (pre-selected) | -| Locatie | Dropdown | Nee | AMB | - -**Afspraak types:** -- Diagnostiek -- Behandeling -- Evaluatie -- Consult -- Overig - -**Acties:** - -| Knop | Actie | Keyboard | -|------|-------|----------| -| Opslaan | POST naar API, sluit block, retourneert encounter_id | `⌘Enter` | -| Annuleren | Sluit block zonder opslaan | `Escape` | - -**Na opslaan:** -1. Toast: "βœ“ Afspraak diagnostiek met Jan de Vries aangemaakt voor morgen 10:00" -2. Block verdwijnt (200ms animatie) -3. Recent strip: badge "[πŸ“… Jan - Diagnostiek]" -4. Encounter_id wordt opgeslagen in context voor volgende stap - -**API:** -``` -POST /api/appointments -Body: { - patient_id: string, - period_start: datetime, - period_end: datetime, - type_code: 'diagnostiek', - class_code: 'AMB', - notes?: string -} -Response: { - id: string (encounter_id), - success: boolean -} -``` - ---- - -### 4.2 RapportageBlock (Uitgebreid) - -**Functie:** Verslag schrijven na diagnostiek-afspraak, gekoppeld aan encounter. - -**Trigger patterns:** -- "rapportage diagnostiek gesprek met [patient]" -- "verslag van diagnostiek afspraak [patient]" -- "rapportage [patient]" (als recente diagnostiek-afspraak bestaat) - -**Pre-fill logica:** - -| Extracted | Pre-fill | -|-----------|----------| -| patient_name β†’ match | PatiΓ«nt selector | -| "diagnostiek" keyword | Type = Diagnostiek | -| Recente encounter (diagnostiek) | Encounter_id gekoppeld | -| Geen encounter | Geen koppeling, suggestie tonen | - -**Form velden:** - -| Veld | Type | Verplicht | Default | -|------|------|-----------|---------| -| PatiΓ«nt | Dropdown | Ja | Pre-filled | -| Gekoppeld aan | Link naar encounter | Nee | Recente diagnostiek-afspraak | -| Type | Button group | Ja | Diagnostiek (pre-selected) | -| Inhoud | Rich text editor | Ja | Leeg | -| Datum/tijd | DateTime | Ja | Nu | - -**Rapportage types:** -- Diagnostiek -- Gesprek -- Evaluatie -- Telefonisch -- Consult - -**AI acties:** - -| Actie | Beschrijving | Output | -|-------|--------------|--------| -| ✨ Samenvatten | Bullets van kernpunten | Zijpaneel | -| πŸ“– B1-niveau | Herschrijf leesbaar | Zijpaneel | -| πŸ” Problemen | Extraheer klinische issues | Zijpaneel | - -**Acties:** - -| Knop | Actie | Keyboard | -|------|-------|----------| -| Opslaan | POST naar API met encounter_id, sluit block | `⌘Enter` | -| Annuleren | Sluit block zonder opslaan | `Escape` | - -**Na opslaan:** -1. Toast: "βœ“ Rapportage opgeslagen en gekoppeld aan afspraak" -2. Block verdwijnt -3. Recent strip: badge "[πŸ“‹ Jan - Diagnostiek]" - -**API:** -``` -POST /api/reports -Body: { - patient_id: string, - encounter_id: string, // Nieuwe: koppeling aan afspraak - type: 'diagnostiek', - content: string (HTML), - timestamp: datetime -} -``` - ---- - -### 4.3 DiagnoseBlock - -**Functie:** Overzicht van alle diagnoses van een patiΓ«nt. - -**Trigger patterns:** -- "diagnose [patient]" -- "diagnoses van [patient]" -- "wat zijn de diagnoses van [patient]" -- Klik op "Diagnoses" in PatientContextCard - -**Layout:** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ₯ Diagnoses van Jan de Vries [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Filter: [Actief βœ“] [Inactief] [Alle] β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ F41.1 Gegeneraliseerde angststoornis β”‚ β”‚ -β”‚ β”‚ Status: Actief | Ernst: Matig β”‚ β”‚ -β”‚ β”‚ Toegevoegd: 15 nov 2024 | Intake: Intake 1 β”‚ β”‚ -β”‚ β”‚ [Bewerken] [Details] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ F32.1 Depressieve stoornis β”‚ β”‚ -β”‚ β”‚ Status: Actief | Ernst: Mild β”‚ β”‚ -β”‚ β”‚ Toegevoegd: 20 dec 2024 | Intake: Intake 2 β”‚ β”‚ -β”‚ β”‚ [Bewerken] [Details] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [+ Nieuwe diagnose toevoegen] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Gedrag:** -- Toont lijst met diagnoses, gesorteerd op datum (nieuwste eerst) -- Filter tabs: Actief / Inactief / Alle -- Per diagnose: code, omschrijving, status, ernst, datum, intake -- Klik op diagnose β†’ DiagnoseFormBlock (edit mode) -- Klik "Nieuwe diagnose" β†’ DiagnoseFormBlock (create mode) - -**Empty state:** -"Geen diagnoses gevonden voor [patient]. [+ Nieuwe diagnose toevoegen]" - -**API:** -``` -GET /api/diagnoses/:patientId -Response: { - diagnoses: [ - { - id: string, - code_code: string, - code_display: string, - clinical_status: 'active' | 'inactive' | 'resolved', - severity_display: string, - recorded_date: datetime, - encounter_id: string, - intake?: { - id: string, - title: string - } - } - ] -} -``` - ---- - -### 4.4 DiagnoseFormBlock - -**Functie:** Diagnose aanmaken of bijstellen met ICD-10 zoeker. - -**Trigger patterns:** -- "diagnose toevoegen [patient] [ICD-10 code]" -- "diagnose wijzigen [patient]" -- "diagnose bijstellen [patient]" -- Klik op diagnose in DiagnoseBlock -- Klik "Nieuwe diagnose" in DiagnoseBlock - -**Pre-fill logica (create mode):** - -| Extracted | Pre-fill | -|-----------|----------| -| patient_name β†’ match | PatiΓ«nt selector (read-only) | -| ICD-10 code (F41.1) | Code + omschrijving via zoeker | -| Geen code | ICD-10 zoeker open | - -**Pre-fill logica (edit mode):** - -| Veld | Pre-fill | -|------|----------| -| PatiΓ«nt | Read-only, huidige waarde | -| ICD-10 code | Huidige code | -| Omschrijving | Huidige omschrijving | -| Type | Huidige type (hoofd/neven) | -| Status | Huidige status | -| Ernst | Huidige ernst | -| Intake | Huidige intake koppeling | -| Toelichting | Huidige toelichting | - -**Form velden:** - -| Veld | Type | Verplicht | Default | -|------|------|-----------|---------| -| PatiΓ«nt | Read-only | Ja | Pre-filled | -| ICD-10 zoeker | Search + dropdown | Ja | Leeg of pre-filled | -| Code | Text (read-only na selectie) | Ja | Uit zoeker | -| Omschrijving | Text (read-only na selectie) | Ja | Uit zoeker | -| Type | Radio buttons | Ja | Hoofddiagnose | -| Status | Dropdown | Ja | Actief | -| Ernst | Dropdown | Nee | Geen | -| Intake koppeling | Dropdown | Nee | Geen | -| Toelichting | Textarea | Nee | Leeg | - -**ICD-10 zoeker gedrag:** -- Fuzzy search tijdens typen (minimaal 2 karakters) -- Resultaten dropdown met code + omschrijving -- Bij selectie: code en omschrijving worden ingevuld -- Zoek op code (F41.1) of omschrijving (angst) - -**Status opties:** -- Actief -- Inactief -- Resolved -- Remission -- Recurrence -- Relapse - -**Ernst opties:** -- Geen -- Mild -- Matig -- Ernstig - -**Type opties:** -- Hoofddiagnose -- Nevendiagnose - -**Acties:** - -| Knop | Actie | Keyboard | -|------|-------|----------| -| Opslaan | POST/PATCH naar API, sluit block | `⌘Enter` | -| Annuleren | Sluit block zonder opslaan | `Escape` | -| Verwijderen | Bevestigingsdialog β†’ soft delete | - | - -**Na opslaan:** -1. Toast: "βœ“ Diagnose F41.1 - Gegeneraliseerde angststoornis toegevoegd" (of "bijgewerkt") -2. Block verdwijnt -3. DiagnoseBlock wordt automatisch getoond met nieuwe/bijgewerkte diagnose - -**API:** -``` -POST /api/diagnoses -Body: { - patient_id: string, - encounter_id?: string, - code_code: string, - code_display: string, - code_system: 'ICD-10', - clinical_status: 'active' | 'inactive' | 'resolved', - severity_display?: string, - category: 'primary-diagnosis' | 'encounter-diagnosis', - note?: string -} - -PATCH /api/diagnoses/:id -Body: { - code_code?: string, - code_display?: string, - clinical_status?: string, - severity_display?: string, - category?: string, - note?: string -} -``` - ---- - -## 5. UI-overzicht (visuele structuur) - -🎯 **Doel:** Globale schermopbouw voor diagnostiek workflow blocks. - -### 5.1 AfspraakBlock Layout - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“… Nieuwe Afspraak [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ PatiΓ«nt * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Jan de Vries βœ“ β”‚ β”‚ -β”‚ β”‚ 59 jaar β€’ Kamer 12B [← Auto] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Datum * Van * Tot β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 2024-12-24 β”‚ β”‚ 10:00 β”‚ β”‚ 11:00 β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Type afspraak * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [Diagnostiek β–Ό] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Locatie β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [AMB β–Ό] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Notities (optioneel) β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [Annuleren] [Opslaan] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 5.2 RapportageBlock Layout (met encounter koppeling) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“‹ Rapportage [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ PatiΓ«nt: Jan de Vries [Wijzig] β”‚ -β”‚ β”‚ -β”‚ Gekoppeld aan: Afspraak diagnostiek - 24 dec 2024 10:00 β”‚ -β”‚ β”‚ -β”‚ Type β”‚ -β”‚ [Diagnostiek βœ“] [Gesprek] [Evaluatie] [Telefonisch] β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [B] [I] [β€’] [1.] ["] 🎀 Dicteer β”‚ β”‚ -β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Verslag van diagnostiek gesprek... β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ AI-acties β”‚ -β”‚ [✨ Samenvatten] [πŸ“– B1-niveau] [πŸ” Problemen extraheren] β”‚ -β”‚ β”‚ -β”‚ [Annuleren] [Opslaan] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 5.3 DiagnoseBlock Layout - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ₯ Diagnoses van Jan de Vries [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Filter: [Actief βœ“] [Inactief] [Alle] β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ F41.1 Gegeneraliseerde angststoornis β”‚ β”‚ -β”‚ β”‚ Status: Actief | Ernst: Matig β”‚ β”‚ -β”‚ β”‚ Toegevoegd: 15 nov 2024 | Intake: Intake 1 β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [Bewerken] [Details] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ F32.1 Depressieve stoornis β”‚ β”‚ -β”‚ β”‚ Status: Actief | Ernst: Mild β”‚ β”‚ -β”‚ β”‚ Toegevoegd: 20 dec 2024 | Intake: Intake 2 β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [Bewerken] [Details] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [+ Nieuwe diagnose toevoegen] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 5.4 DiagnoseFormBlock Layout - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ₯ Nieuwe Diagnose [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ PatiΓ«nt: Jan de Vries (read-only) β”‚ -β”‚ β”‚ -β”‚ ICD-10 Code * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ” Zoek ICD-10 code of omschrijving... β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Resultaten: β”‚ β”‚ -β”‚ β”‚ β€’ F41.1 Gegeneraliseerde angststoornis β”‚ β”‚ -β”‚ β”‚ β€’ F41.0 Paniekstoornis β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Code: F41.1 (read-only na selectie) β”‚ -β”‚ Omschrijving: Gegeneraliseerde angststoornis (read-only) β”‚ -β”‚ β”‚ -β”‚ Type * β”‚ -β”‚ β—‹ Hoofddiagnose ● Nevendiagnose β”‚ -β”‚ β”‚ -β”‚ Status * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [Actief β–Ό] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Ernst β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [Geen β–Ό] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Intake koppeling β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [Geen β–Ό] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Toelichting (optioneel) β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [Annuleren] [Opslaan] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 6. Interacties met AI (functionele beschrijving) - -🎯 **Doel:** Waar AI in de diagnostiek workflow voorkomt. - -| Locatie | AI-actie | Trigger | Output | -|---------|----------|---------|--------| -| RapportageBlock | Samenvatten | Klik knop "✨ Samenvatten" | Bullets van kernpunten in zijpaneel | -| RapportageBlock | B1-niveau | Klik knop "πŸ“– B1-niveau" | Herschreven tekst in zijpaneel | -| RapportageBlock | Extract problemen | Klik knop "πŸ” Problemen" | Gestructureerde lijst met categorie + severity | -| DiagnoseFormBlock | ICD-10 suggestie | Typ in zoeker | Fuzzy search resultaten met relevante codes | - -**AI Response Handling:** -- Alle AI outputs tonen in dedicated preview area (zijpaneel) -- Gebruiker moet expliciet accepteren/invoegen -- Bewerken altijd mogelijk -- Annuleren zonder gevolgen - ---- - -## 7. Complete Workflow Flow - -🎯 **Doel:** Stap-voor-stap beschrijving van de complete diagnostiek workflow. - -### Flow 1: Van Afspraak tot Diagnose (Happy Path) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STAP 1: AFSPRAAK PLANNEN β”‚ -β”‚ β”‚ -β”‚ Behandelaar: "afspraak diagnostiek met Jan morgen 10:00" β”‚ -β”‚ β†’ AfspraakBlock verschijnt met pre-fill β”‚ -β”‚ β†’ Behandelaar controleert β†’ klikt Opslaan β”‚ -β”‚ β†’ Encounter aangemaakt, encounter_id opgeslagen β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STAP 2: RAPPORTAGE SCHRIJVEN (na afspraak) β”‚ -β”‚ β”‚ -β”‚ Behandelaar: "rapportage diagnostiek gesprek met Jan" β”‚ -β”‚ β†’ RapportageBlock verschijnt β”‚ -β”‚ β†’ Encounter_id automatisch gekoppeld β”‚ -β”‚ β†’ Behandelaar schrijft/dicteert verslag β”‚ -β”‚ β†’ Optioneel: AI samenvatten β”‚ -β”‚ β†’ Klikt Opslaan β†’ Rapportage gekoppeld aan encounter β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STAP 3: DIAGNOSE BEKIJKEN β”‚ -β”‚ β”‚ -β”‚ Behandelaar: "diagnose Jan" β”‚ -β”‚ β†’ DiagnoseBlock verschijnt met lijst diagnoses β”‚ -β”‚ β†’ Filter: Actief (default) β”‚ -β”‚ β†’ Behandelaar ziet overzicht β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STAP 4: DIAGNOSE TOEVOEGEN β”‚ -β”‚ β”‚ -β”‚ Behandelaar: "diagnose toevoegen Jan F41.1" β”‚ -β”‚ β†’ DiagnoseFormBlock verschijnt β”‚ -β”‚ β†’ ICD-10 code F41.1 pre-filled β”‚ -β”‚ β†’ Behandelaar vult type, status, ernst in β”‚ -β”‚ β†’ Koppelt aan intake (optioneel) β”‚ -β”‚ β†’ Klikt Opslaan β†’ Diagnose toegevoegd β”‚ -β”‚ β†’ DiagnoseBlock wordt getoond met nieuwe diagnose β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Flow 2: Diagnose Bijstellen - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Behandelaar: "diagnose wijzigen Jan" β”‚ -β”‚ β†’ DiagnoseBlock verschijnt β”‚ -β”‚ β†’ Behandelaar klikt op diagnose F41.1 β”‚ -β”‚ β†’ DiagnoseFormBlock verschijnt (edit mode) β”‚ -β”‚ β†’ Alle velden pre-filled met huidige waarden β”‚ -β”‚ β†’ Behandelaar wijzigt status: Actief β†’ Resolved β”‚ -β”‚ β†’ Behandelaar wijzigt ernst: Matig β†’ Mild β”‚ -β”‚ β†’ Voegt toelichting toe β”‚ -β”‚ β†’ Klikt Opslaan β†’ Diagnose bijgewerkt β”‚ -β”‚ β†’ DiagnoseBlock wordt getoond met bijgewerkte diagnose β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 8. Edge Cases & Alternatieve Flows - -### Edge Case 1: Meerdere patiΓ«nten metzelfde naam -- **Situatie:** Input "diagnose Jan" β†’ meerdere matches -- **Gedrag:** ZoekenBlock verschijnt met resultaten -- **Actie:** Behandelaar selecteert juiste patiΓ«nt -- **Vervolg:** DiagnoseBlock voor geselecteerde patiΓ«nt - -### Edge Case 2: Geen recente afspraak voor rapportage -- **Situatie:** Input "rapportage Jan" β†’ geen encounter gevonden -- **Gedrag:** RapportageBlock opent zonder encounter-koppeling -- **Suggestie:** "Geen recente diagnostiek-afspraak gevonden. Wil je een afspraak koppelen?" -- **Actie:** Optioneel AfspraakBlock openen - -### Edge Case 3: ICD-10 code niet gevonden -- **Situatie:** Input "diagnose toevoegen Jan F99.9" β†’ code bestaat niet -- **Gedrag:** Validatie fout: "ICD-10 code F99.9 niet gevonden" -- **Actie:** ICD-10 zoeker blijft open voor correctie - -### Edge Case 4: Diagnose al bestaat -- **Situatie:** Input "diagnose toevoegen Jan F41.1" β†’ diagnose bestaat al -- **Gedrag:** Waarschuwing: "Diagnose F41.1 bestaat al. Wil je deze bijwerken?" -- **Actie:** Optioneel DiagnoseFormBlock openen in edit mode - -### Edge Case 5: Onvolledige input -- **Situatie:** Input "afspraak diagnostiek" (geen patiΓ«nt/datum) -- **Gedrag:** Systeem vraagt om ontbrekende informatie -- **Actie:** ZoekenBlock voor patiΓ«nt, datum/tijd picker voor planning - ---- - -## 9. Success Criteria - -De diagnostiek workflow is succesvol wanneer: - -1. βœ… Behandelaar kan diagnostiek-afspraak plannen in < 30 seconden -2. βœ… Rapportage kan worden geschreven en automatisch gekoppeld aan afspraak -3. βœ… Alle diagnoses van een patiΓ«nt zijn in één overzicht zichtbaar -4. βœ… Nieuwe diagnose kan worden toegevoegd met ICD-10 zoeker -5. βœ… Bestaande diagnose kan worden bijgewerkt (status, ernst, etc.) -6. βœ… Alle acties zijn traceerbaar (wie, wanneer, wat) -7. βœ… Workflow kan volledig worden doorlopen zonder menu-navigatie - ---- - -## 10. Bijlagen & Referenties - -**Projectdocumenten:** -- PRD: `swift-prd.md` -- FO Algemeen: `swift-fo-ai.md` -- Bouwplan: `bouwplan-swift-v1.md` -- UX/UI: `swift-ux-v2.1.md` -- Taken analyse: `taken-en-vragen-analyse.md` - -**Bestaande Code Referenties:** -- Diagnose pagina: `app/epd/patients/[id]/diagnose/page.tsx` -- Diagnose actions: `app/epd/patients/[id]/diagnose/actions.ts` -- Appointment modal: `app/epd/agenda/components/appointment-modal.tsx` -- Rapportage workspace: `app/epd/patients/[id]/rapportage/components/rapportage-workspace-v2.tsx` - -**Database Schema:** -- `conditions` tabel voor diagnoses -- `encounters` tabel voor afspraken -- `reports` tabel voor rapportages - ---- - -## Wijzigingslog - -| Versie | Datum | Wijzigingen | -|--------|-------|-------------| -| 1.0 | 23-12-2024 | InitiΓ«le versie - Diagnostiek workflow beschrijving | - diff --git a/docs/swift/archive/swift-prd.md b/docs/swift/archive/swift-prd.md deleted file mode 100644 index 0da3d8c..0000000 --- a/docs/swift/archive/swift-prd.md +++ /dev/null @@ -1,632 +0,0 @@ -# πŸ“„ Product Requirements Document (PRD) β€” Contextual UI EPD - -**Projectnaam:** Contextual UI EPD β€” "Het Slimme EPD" -**Versie:** v1.0 -**Datum:** 23-12-2024 -**Auteur:** Colin Lit - ---- - -## 1. Doelstelling - -🎯 **Doel van deze sectie:** Beschrijf waarom dit product of prototype wordt gebouwd en wat het beoogde resultaat is. - -### Primair doel - -Uitbreiden van het bestaande Speedrun EPD met **Contextual UI**: een systeem waarin voorgedefinieerde interface-componenten **automatisch verschijnen op basis van context** β€” wie je bent, welke patiΓ«nt actief is, welk moment van de dag het is, en wat je probeert te doen. - -### Het kernprincipe - -> **"Pre-built components, smart triggers"** -> -> We genereren geen UI on-the-fly (te onvoorspelbaar voor zorg), maar tonen **geteste bouwblokken op het juiste moment**. De AI zit in het *bepalen wanneer* en het *vullen van content*, niet in het genereren van interface-elementen. - -### Het contrast met traditionele EPD's - -| Aspect | Traditioneel EPD | Contextual UI EPD | -|--------|------------------|-------------------| -| Navigatie | 47 menu-items, tabbladen, submenu's | Context bepaalt wat je ziet | -| Interface | Altijd alles zichtbaar | Alleen wat nu relevant is | -| Timing | Gebruiker zoekt zelf | Systeem toont proactief | -| Klikken | 12 klikken voor rapportage | 1 zin of automatisch | -| Context | Gebruiker moet onthouden | Systeem begrijpt situatie | - -### Secundaire doelen - -- Demonstreren van "intelligent interface" concept voor gesprekken met Nedap, Medicore, etc. -- LinkedIn content over next-gen EPD interfaces -- Technische showcase van context-aware React componenten -- Valideren of "proactieve UI" gewaardeerd wordt door zorgprofessionals - -### Relatie met Speedrun EPD - -Dit is **geen nieuw product** maar een uitbreiding op de bestaande codebase: -- Hergebruik van alle database schemas -- Hergebruik van bestaande API routes en AI-functionaliteit -- Hergebruik van UI componenten (speech recorder, editors, etc.) -- Toevoeging van Context Engine en Trigger System - ---- - -## 2. Doelgroep - -🎯 **Doel:** Schets wie de eindgebruikers, stakeholders en testers zijn. - -### Primaire gebruikers - -| Rol | Behoeften | Pijnpunten vandaag | -|-----|-----------|-------------------| -| **Verpleegkundige** | Snelle notities tussen zorgmomenten | 40% tijd aan administratie, zoeken naar juiste scherm | -| **SPV/Behandelaar** | Rapportage na gesprek, overdracht | 20 min typen na crisis-interventie | -| **Teamleider** | Overzicht, overdracht ontvangen | Informatie verspreid over schermen | - -### Secundaire stakeholders - -| Rol | Interesse | -|-----|-----------| -| **ICT Manager** | Minder training nodig, snellere adoptie | -| **Product Owner (demo)** | AI-toegevoegde waarde zien | -| **Developer (inspiratie)** | Context-aware UI patterns leren | - -### Gebruikerscontext - -De interface moet werken in situaties waar: -- Handen bezet zijn (handschoenen, zorghandelingen) -- Tijd schaars is (tussen patiΓ«nten door) -- Concentratie elders ligt (na emotioneel gesprek) -- Meerdere patiΓ«nten tegelijk aandacht vragen - ---- - -## 3. Kernfunctionaliteiten (MVP-scope) - -🎯 **Doel:** Afbakenen van de minimale werkende functies. - -### 3.1 Architectuur: De Drie Lagen - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ LAAG 1: CONTEXT ENGINE β”‚ -β”‚ Houdt bij: gebruiker, patiΓ«nt, tijd, dienst, recente β”‚ -β”‚ acties. Zustand store + Supabase realtime. β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ LAAG 2: TRIGGER SYSTEM β”‚ -β”‚ Rules engine die bepaalt wanneer welk component β”‚ -β”‚ verschijnt. Combinatie van tijd, events, en intent. β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ LAAG 3: PRE-BUILT COMPONENTS β”‚ -β”‚ Geteste UI-blokken die door triggers worden getoond β”‚ -β”‚ en automatisch worden gevuld met relevante data. β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 3.2 MVP Componenten - -| # | Component | Trigger | Data/AI | Prioriteit | -|---|-----------|---------|---------|------------| -| 1 | **Command Input** | Altijd zichtbaar (centraal) | Voice + text | Must | -| 2 | **DagnotatieBlock** | Intent "notitie" of voice | Pre-fill patiΓ«nt, categorie | Must | -| 3 | **ZoekenBlock** | Intent "zoek" of patiΓ«ntnaam | Fuzzy search results | Must | -| 4 | **PatientContextCard** | PatiΓ«nt geselecteerd | Laatste rapportages, alerts | Must | -| 5 | **RapportageBlock** | Intent "gesprek" of "rapportage" | AI-samenvatting optie | Should | -| 6 | **OverdrachtPanel** | Tijd = einde dienst OF intent | AI-samenvatting per patiΓ«nt | Should | -| 7 | **AgendaContextCard** | Afspraak binnen 15 min | PatiΓ«nt + laatste contact | Could | -| 8 | **FallbackPicker** | Lage intent confidence | Grid met alle opties | Must | - -### 3.3 Context Engine Specificatie - -```typescript -interface ContextState { - // Gebruiker - currentUser: { - id: string; - name: string; - role: 'verpleegkundige' | 'behandelaar' | 'teamleider'; - }; - - // Dienst - currentShift: { - type: 'ochtend' | 'middag' | 'avond' | 'nacht'; - startTime: Date; - endTime: Date; - patients: string[]; // IDs van toegewezen patiΓ«nten - }; - - // Actieve patiΓ«nt (sticky) - activePatient: { - id: string; - name: string; - lastContact: Date; - alerts: Alert[]; - } | null; - - // Recente acties - recentActions: Action[]; // Laatste 5-10 - - // Tijd-gevoelige context - upcomingAppointment: Appointment | null; // Binnen 30 min - shiftEndingSoon: boolean; // < 1 uur tot einde -} -``` - -### 3.4 Trigger Rules Specificatie - -| Trigger Type | Conditie | Actie | Prioriteit | -|--------------|----------|-------|------------| -| **Intent** | Voice/text input geclassificeerd | Open bijbehorend block | 1 (hoogste) | -| **Patient Select** | PatiΓ«nt aangeklikt/gevonden | Toon PatientContextCard | 2 | -| **Time: Appointment** | Afspraak binnen 15 min | Toon AgendaContextCard | 3 | -| **Time: Shift End** | < 1 uur tot einde dienst | Suggestie OverdrachtPanel | 4 | -| **Fallback** | Intent confidence < 0.7 | Toon FallbackPicker | 5 (laagste) | - -### 3.5 Intent Classification - -**Two-tier approach voor snelheid:** - -```typescript -// Tier 1: Local keyword matching (< 10ms) -const quickMatch = (input: string): IntentResult | null => { - const patterns = [ - { regex: /notitie|dagnotitie|noteren/i, intent: 'dagnotitie' }, - { regex: /zoek|vind|wie is/i, intent: 'zoeken' }, - { regex: /overdracht|dienst\s*(eindigt|klaar)/i, intent: 'overdracht' }, - { regex: /rapport|gesprek|consult/i, intent: 'rapportage' }, - { regex: /afspraken?|agenda|planning/i, intent: 'agenda' }, - ]; - // ... matching logic -}; - -// Tier 2: Claude API (fallback, < 500ms) -const aiClassify = async (input: string): Promise => { - // Alleen aangeroepen als quickMatch null of low confidence -}; -``` - -**Entity Extraction:** - -Naast intent ook extraheren: -- `patient_name`: "Jan de Vries", "mevrouw Jansen" -- `category`: "medicatie", "ADL", "incident" -- `time_reference`: "vandaag", "gisteren", "afgelopen dienst" - ---- - -## 4. Gebruikersflows (Demo- of MVP-flows) - -🎯 **Doel:** Laten zien hoe de gebruiker stap-voor-stap door het systeem gaat. - -### Flow 1: Snelle Dagnotitie via Voice (30 seconden) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 1. Gebruiker opent Command Center β”‚ -β”‚ β†’ Ziet: lege input, context "Ochtend | 8 patiΓ«nten" β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 2. Spreekt: "Notitie Jan de Vries medicatie gegeven" β”‚ -β”‚ β†’ Deepgram transcribeert real-time β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 3. System analyseert: β”‚ -β”‚ β†’ Intent: dagnotitie (confidence 0.95) β”‚ -β”‚ β†’ Patient: "Jan de Vries" β†’ ID lookup β”‚ -β”‚ β†’ Category: "Medicatie" β”‚ -β”‚ β†’ Text: "medicatie gegeven" β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 4. DagnotatieBlock verschijnt: β”‚ -β”‚ β†’ Patient: Jan de Vries βœ“ (pre-filled) β”‚ -β”‚ β†’ Categorie: Medicatie βœ“ (pre-filled) β”‚ -β”‚ β†’ Tekst: "medicatie gegeven" βœ“ (pre-filled) β”‚ -β”‚ β†’ [Opslaan] knop highlighted β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 5. Gebruiker: review β†’ klik Opslaan β”‚ -β”‚ β†’ Toast: "Notitie opgeslagen" β”‚ -β”‚ β†’ Block verdwijnt β”‚ -β”‚ β†’ Recent badge: "Jan - Medicatie" verschijnt β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Flow 2: PatiΓ«nt Opzoeken + Context (45 seconden) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 1. Gebruiker typt: "Jan" β”‚ -β”‚ β†’ Intent: zoeken β”‚ -β”‚ β†’ Query: "Jan" β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 2. ZoekenBlock verschijnt met matches: β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Jan de Vries β”‚ 15-03-1965 β”‚ Laatst: 2u β”‚ β”‚ -β”‚ β”‚ Jan Bakker β”‚ 22-08-1978 β”‚ Laatst: 1d β”‚ β”‚ -β”‚ β”‚ Jantine Smit β”‚ 04-11-1990 β”‚ Laatst: 3d β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 3. Gebruiker klikt "Jan de Vries" β”‚ -β”‚ β†’ activePatient wordt gezet β”‚ -β”‚ β†’ ZoekenBlock sluit β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 4. PatientContextCard verschijnt: β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ JAN DE VRIES (59) β”‚ β”‚ -β”‚ β”‚ ───────────────────────────────────────── β”‚ β”‚ -β”‚ β”‚ Laatste contact: 2 uur geleden β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Recente notities: β”‚ β”‚ -β”‚ β”‚ β€’ 09:15 Medicatie uitgereikt β”‚ β”‚ -β”‚ β”‚ β€’ Gisteren: Goed gesprek over ontslag β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ ⚠️ Let op: 2 valincidenten deze week β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [Notitie] [Rapportage] [Behandelplan] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 5. Gebruiker klikt [Notitie] β”‚ -β”‚ β†’ DagnotatieBlock opent met Jan pre-filled β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Flow 3: Automatische Overdracht Suggestie (proactief) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Context: Het is 15:15, dienst eindigt om 16:00 β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 1. System detecteert: shiftEndingSoon = true β”‚ -β”‚ β†’ Subtiele banner verschijnt: β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ• Dienst eindigt over 45 min β”‚ β”‚ -β”‚ β”‚ Wil je alvast de overdracht voorbereiden? β”‚ β”‚ -β”‚ β”‚ [Start overdracht] [Later] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 2. Gebruiker klikt [Start overdracht] β”‚ -β”‚ β†’ OverdrachtPanel opent β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 3. OverdrachtPanel toont: β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ OVERDRACHT OCHTEND β†’ MIDDAG β”‚ β”‚ -β”‚ β”‚ 08:00 - 16:00 | 8 patiΓ«nten β”‚ β”‚ -β”‚ β”‚ ───────────────────────────────────────── β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β–Ό Jan de Vries β”‚ β”‚ -β”‚ β”‚ AI-samenvatting: Rustige ochtend, medicatieβ”‚ β”‚ -β”‚ β”‚ uitgereikt zonder problemen. Let op val- β”‚ β”‚ -β”‚ β”‚ risico bij toiletbezoek. β”‚ β”‚ -β”‚ β”‚ [Bronnen: 3 notities] β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β–Ό Marie van den Berg β”‚ β”‚ -β”‚ β”‚ AI-samenvatting: ... β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [Kopieer alles] [Verstuur naar collega] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Flow 4: Ambigue Input met Fallback - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 1. Gebruiker typt: "medicatie" β”‚ -β”‚ β†’ Intent: onduidelijk (dagnotitie? metingen?) β”‚ -β”‚ β†’ Confidence: 0.5 β”‚ -β”‚ β†’ Geen patiΓ«nt gespecificeerd β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 2. FallbackPicker verschijnt: β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Wat wil je doen? β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ πŸ“ β”‚ β”‚ πŸ” β”‚ β”‚ πŸ“‹ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ Notitie β”‚ β”‚ Zoeken β”‚ β”‚ Rapport β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ πŸ”„ β”‚ β”‚ πŸ“… β”‚ β”‚ πŸ’Š β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚Overdrachtβ”‚ β”‚ Agenda β”‚ β”‚ Meting β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 3. Gebruiker klikt [Notitie] β”‚ -β”‚ β†’ DagnotatieBlock opent β”‚ -β”‚ β†’ "medicatie" ingevuld als tekst β”‚ -β”‚ β†’ Vraagt om patiΓ«nt te selecteren β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 5. Niet in Scope - -🎯 **Doel:** Duidelijk maken wat (nog) niet wordt gebouwd. - -### Expliciet uitgesloten (v1) - -| Feature | Reden | -|---------|-------| -| **Volledig voice-only navigatie** | Voice is input, niet navigatie. Te foutgevoelig. | -| **AI-gegenereerde UI componenten** | Onvoorspelbaar, niet geschikt voor zorg. Pre-built only. | -| **Ambient listening** | Privacy concerns, v2+ feature | -| **Multi-user realtime** | Complexiteit, niet nodig voor demo | -| **Offline mode** | Complexiteit, later toevoegen | -| **Behandelplan block** | Te complex, lage frequentie, bestaande UI voldoet | -| **Intake block** | Wizard is complex, 1x/maand, lage waarde voor MVP | -| **Metingen block** | Lage waarde-perceptie bij stakeholders | -| **Native mobile app** | Responsive web is voldoende | -| **FHIR/externe EPD integratie** | Post-MVP, apart project | - -### Bewust versimpeld (v1) - -| Aspect | Versimpeling | -|--------|--------------| -| **Diensten** | Hardcoded tijden (08-16, 16-23, 23-08) | -| **PatiΓ«nt-toewijzing** | Alle patiΓ«nten zichtbaar, geen restricties | -| **Alerts** | Alleen handmatig toegevoegd, geen automatische detectie | - ---- - -## 6. Succescriteria - -🎯 **Doel:** Objectieve meetlat voor een geslaagde oplevering. - -### Functionele criteria - -| Criterium | Target | Meetmethode | -|-----------|--------|-------------| -| Intent classification accuracy | > 85% | Test set van 50 voorbeelden | -| Voice transcription accuracy | > 90% | Handmatige review sample | -| Pre-fill correctheid | > 90% | Juiste patiΓ«nt/categorie | -| Fallback usage | < 25% | Picker clicks / totaal | -| "Notitie Jan medicatie" β†’ save | < 30 sec | Timestamp logging | - -### Performance criteria - -| Criterium | Target | -|-----------|--------| -| Intent classification | < 500ms | -| Block render | < 200ms | -| Voice transcription latency | < 100ms | -| PatientContextCard laden | < 300ms | - -### UX criteria - -| Criterium | Target | -|-----------|--------| -| Klikken tot taak compleet | Gemiddeld < 3 | -| Training nodig | Zero (intuΓ―tief) | -| "Dit voelt als magie" feedback | Minimaal 1 test user | - -### Business criteria - -| Criterium | Target | -|-----------|--------| -| Demo-ready | Ja, 3 scenario's foutloos | -| LinkedIn content | 2+ posts over concept | -| Stakeholder interesse | Minimaal 1 concrete vervolgvraag | - ---- - -## 7. Risico's & Mitigatie - -🎯 **Doel:** Risico's vroeg signaleren en plannen hoe ermee om te gaan. - -| Risico | Kans | Impact | Mitigatie | -|--------|------|--------|-----------| -| **Intent classification onnauwkeurig** | Medium | Hoog | Fallback picker altijd beschikbaar, local-first matching | -| **Voice niet goed in Nederlands** | Laag | Medium | Deepgram NL model, tekst fallback altijd mogelijk | -| **Pre-fill verkeerde patiΓ«nt** | Medium | Hoog | Altijd confirmation tonen, nooit blind opslaan | -| **Context engine te complex** | Medium | Medium | Minimale context in v1, uitbreiden in v2 | -| **Gebruikers missen "overzicht"** | Medium | Medium | Bestaande patiΓ«ntenlijst als alternatieve entry | -| **Performance AI calls** | Medium | Medium | Local-first matching, streaming responses, caching | -| **Scope creep** | Hoog | Hoog | Strikte MVP scope, parking lot voor ideeΓ«n | -| **Demo deadline druk** | Medium | Hoog | Focus op 3 happy paths, polish later | - ---- - -## 8. Roadmap / Vervolg (Post-MVP) - -🎯 **Doel:** Richting geven aan toekomstige uitbreidingen. - -### Fase 2: Extended Blocks (Post-MVP) - -- **AgendaBlock** - Afspraken beheren, context bij naderende afspraak -- **BehandelplanBlock** - Wrapper rond bestaande functionaliteit -- **MetingenBlock** - Vitale functies invoer met trends - -### Fase 3: Smart Triggers - -- **Proactieve alerts** - "3 valincidenten, wil je een risico-analyse?" -- **Behandelplan reminder** - "Plan verloopt over 2 weken" -- **Automatische categorisatie** - ML-model voor notitie-types - -### Fase 4: Team Features - -- **Shift handover** - Gestructureerde overdracht workflow -- **Team dashboard** - Overzicht alle patiΓ«nten, alerts -- **Notificaties** - Push bij urgente updates - -### Fase 5: Integraties - -- **FHIR export** - Standaard zorgdata uitwisseling -- **Externe EPD sync** - Koppeling met Nedap, PinkRoccade -- **Calendar sync** - Google/Outlook afspraken importeren - ---- - -## 9. Technische Architectuur (Overzicht) - -### Nieuwe Routes - -``` -/app - /(app) - /command-center - /page.tsx # Hoofdscherm - /components/ - CommandInput.tsx # Text + voice input - BlockContainer.tsx # Generic block wrapper - FallbackPicker.tsx # Block selection grid - RecentActions.tsx # Recent badges - - /api - /intent - /classify/route.ts # Intent classification - /context - /route.ts # Get/set user context - /patients - /search/route.ts # Fuzzy patient search -``` - -### Building Blocks - -``` -/components/building-blocks/ - /dagnotitie/ - DagnotatieBlock.tsx - /zoeken/ - ZoekenBlock.tsx - PatientCard.tsx - /rapportage/ - RapportageBlock.tsx - /overdracht/ - OverdrachtPanel.tsx - /context/ - PatientContextCard.tsx - AgendaContextCard.tsx - /shared/ - BlockContainer.tsx - BlockHeader.tsx -``` - -### State Management (Zustand) - -```typescript -// stores/context-store.ts -interface ContextStore { - // User & shift - currentUser: User; - currentShift: Shift; - - // Active patient (sticky) - activePatient: Patient | null; - setActivePatient: (patient: Patient | null) => void; - - // Recent actions - recentActions: Action[]; - addRecentAction: (action: Action) => void; - - // Time-based context - upcomingAppointment: Appointment | null; - shiftEndingSoon: boolean; -} - -// stores/command-center-store.ts -interface CommandCenterStore { - // Active block - activeBlock: BlockType | null; - blockPrefill: Record; - - // Input state - inputValue: string; - isListening: boolean; - transcript: string; - - // Actions - processInput: (text: string) => Promise; - openBlock: (type: BlockType, prefill?: object) => void; - closeBlock: () => void; -} -``` - ---- - -## 10. Fasering & Sprint Planning - -### Sprint 1: Foundation (Dag 1-2) - -| Taak | Output | Uren | -|------|--------|------| -| Command Center page layout | `/app/command-center/page.tsx` | 2 | -| CommandInput component | Text + submit | 2 | -| Voice integratie | Mic button, Deepgram | 2 | -| Context store setup | Zustand store | 2 | -| BlockContainer wrapper | Generic frame | 1 | - -**Deliverable:** Command Center opent, voice werkt, geen blocks nog. - -### Sprint 2: Intent & Zoeken (Dag 3-4) - -| Taak | Output | Uren | -|------|--------|------| -| Intent API route | `/api/intent/classify` | 3 | -| Local keyword matching | Quick patterns | 2 | -| Entity extraction | Patient name uit tekst | 2 | -| ZoekenBlock | Patient cards + select | 3 | -| FallbackPicker | Grid met icons | 2 | - -**Deliverable:** "zoek jan" werkt, patient selectie mogelijk. - -### Sprint 3: Dagnotitie Flow (Dag 5-6) - -| Taak | Output | Uren | -|------|--------|------| -| DagnotatieBlock | Quick entry form | 3 | -| Pre-fill logic | Patient + categorie | 2 | -| Save flow + toast | Feedback | 1 | -| PatientContextCard | Na selectie tonen | 3 | -| Recent actions strip | Badges | 2 | - -**Deliverable:** "notitie jan medicatie" werkt end-to-end. - -### Sprint 4: Polish & Demo (Dag 7-8) - -| Taak | Output | Uren | -|------|--------|------| -| RapportageBlock | Wrapper rond composer | 3 | -| OverdrachtPanel | AI-samenvatting | 4 | -| Animaties | Transitions | 2 | -| Demo scenario's | 3 happy paths | 2 | -| Bug fixes | Stability | 3 | - -**Deliverable:** Demo-ready voor stakeholders. - -### Totaal: ~42 uur over 8 dagen - ---- - -## 11. Bijlagen & Referenties - -🎯 **Doel:** Bronnen koppelen voor context en consistentie. - -### Gerelateerde documenten - -| Document | Locatie | Beschrijving | -|----------|---------|--------------| -| Ephemeral UI Research | `Ephemeral_UI_for_Healthcare...md` | Achtergrond contextual interfaces | -| PRD Ephemeral UI EPD | `nextgen-epd-prd-ephemeral-ui-epd.md` | Originele visie document | -| MVP Prioritering | `nextgen-epd-mvp-prioritering-ephemeral-ui.md` | Scope beslissingen | -| Waarde-analyse | `nextgen-epd-waarde-analyse-ephemeral-ui.md` | Klant & PO perspectief | -| FO Mini-ECD v2 | `fo-mini-ecd-v2.md` | Bestaande EPD functionaliteit | -| TO Mini-ECD | `to-mini-ecd-v1_2.md` | Technische basis | - -### Bestaande codebase (hergebruik) - -| Component | Locatie | Hergebruik | -|-----------|---------|------------| -| Speech Recorder | `components/speech-recorder.tsx` | 100% | -| Deepgram API | `api/deepgram/transcribe/route.ts` | 100% | -| Toast System | `lib/hooks/use-toast.ts` | 100% | -| Command (cmdk) | `components/ui/command.tsx` | 90% | -| Dagregistratie Form | `app/epd/dagregistratie/` | 80% | -| Report Types | `lib/types/report.ts` | 100% | - ---- - -## Wijzigingslog - -| Versie | Datum | Wijzigingen | -|--------|-------|-------------| -| 1.0 | 23-12-2024 | InitiΓ«le versie | \ No newline at end of file diff --git a/docs/swift/archive/swift-ux-diagnostiek-workflow.md b/docs/swift/archive/swift-ux-diagnostiek-workflow.md deleted file mode 100644 index f954957..0000000 --- a/docs/swift/archive/swift-ux-diagnostiek-workflow.md +++ /dev/null @@ -1,829 +0,0 @@ -# 🎨 UX/UI Design Document β€” Swift: Diagnostiek Workflow - -**Projectnaam:** Swift β€” Diagnostiek Workflow -**Versie:** v1.0 -**Datum:** 23-12-2024 -**Auteur:** Colin Lit - ---- - -## 1. Visie: Behandelaar Workflow via Natuurlijke Taal - -### 1.1 Het Probleem voor Behandelaars - -``` -TRADITIONEEL EPD - DIAGNOSTIEK WORKFLOW -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Menu β†’ PatiΓ«nten β†’ Jan β†’ Agenda β†’ Nieuwe Afspraak β†’ β”‚ -β”‚ Type: Diagnostiek β†’ Datum/Tijd β†’ Opslaan β”‚ -β”‚ β”‚ -β”‚ Menu β†’ PatiΓ«nten β†’ Jan β†’ Rapportages β†’ Nieuw β†’ β”‚ -β”‚ Type: Diagnostiek β†’ Koppel Afspraak β†’ Zoek β†’ Selecteer β†’ β”‚ -β”‚ Schrijf verslag β†’ Opslaan β”‚ -β”‚ β”‚ -β”‚ Menu β†’ PatiΓ«nten β†’ Jan β†’ Diagnoses β†’ Nieuw β†’ β”‚ -β”‚ Zoek ICD-10 β†’ Selecteer β†’ Vul formulier β†’ Opslaan β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -Resultaat: 15-20 klikken, 10-15 minuten per diagnostiek-traject -``` - -### 1.2 De Swift Oplossing - -``` -SWIFT - DIAGNOSTIEK WORKFLOW -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ "afspraak diagnostiek met jan morgen 10:00" β”‚ -β”‚ β†’ AfspraakBlock verschijnt voorgevuld β”‚ -β”‚ β†’ Opslaan (1 klik) β”‚ -β”‚ β”‚ -β”‚ "rapportage diagnostiek gesprek met jan" β”‚ -β”‚ β†’ RapportageBlock verschijnt met encounter koppeling β”‚ -β”‚ β†’ Schrijf/dicteer β†’ Opslaan (1 klik) β”‚ -β”‚ β”‚ -β”‚ "diagnose toevoegen jan F41.1" β”‚ -β”‚ β†’ DiagnoseFormBlock verschijnt met ICD-10 pre-filled β”‚ -β”‚ β†’ Vul aan β†’ Opslaan (1 klik) β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -Resultaat: 3 zinnen, 3 klikken, 3-5 minuten per traject -``` - -### 1.3 Core Design Principles (Diagnostiek Workflow) - -| Principe | Betekenis voor Diagnostiek | -|----------|---------------------------| -| **Conversational** | "afspraak diagnostiek jan morgen 10:00" werkt direct | -| **Contextual** | Systeem onthoudt encounter_id tussen stappen | -| **Ephemeral** | Blocks verschijnen wanneer nodig, verdwijnen na opslaan | -| **Complete Flow** | Van afspraak tot diagnose in één vloeiende flow | - ---- - -## 2. Intent Mapping voor Diagnostiek Workflow - -### 2.1 Diagnostiek Intents - -| Intent | Trigger patterns | Block | Prio | Freq | -|--------|-----------------|-------|------|------| -| `afspraak_maken` | "afspraak diagnostiek met [patient] [datum] [tijd]"
"plan diagnostiek voor [patient] morgen"
"afspraak [patient] volgende week dinsdag 10:00" | `AfspraakBlock` | 🟑 P2 | 2-3x/week | -| `rapportage` | "rapportage diagnostiek gesprek met [patient]"
"verslag van diagnostiek afspraak [patient]"
"rapportage [patient]" (als recente afspraak) | `RapportageBlock` | 🟑 P2 | 3-5x/week | -| `diagnose_bekijken` | "diagnose [patient]"
"diagnoses van [patient]"
"wat zijn de diagnoses van [patient]" | `DiagnoseBlock` | 🟑 P2 | 3-5x/week | -| `diagnose_toevoegen` | "diagnose toevoegen [patient] [ICD-10]"
"[patient] heeft [ICD-10]"
"diagnose [patient] [ICD-10]" | `DiagnoseFormBlock` | 🟑 P2 | 1-2x/week | -| `diagnose_wijzigen` | "diagnose wijzigen [patient]"
"diagnose bijstellen [patient]" | `DiagnoseFormBlock` (edit) | 🟑 P2 | 1x/week | - -### 2.2 Context-Triggered UI (Proactief) - -| Trigger | Conditie | Wat verschijnt | Prio | -|---------|----------|----------------|------| -| **Recente afspraak** | Na afspraak opslaan | Suggestie: "Rapportage schrijven?" | 🟑 P2 | -| **Rapportage zonder diagnose** | Na rapportage opslaan | Suggestie: "Diagnose toevoegen?" | 🟑 P2 | -| **Diagnose verouderd** | Diagnose > 6 maanden oud | Suggestie: "Diagnose bijwerken?" | 🟒 P3 | - ---- - -## 3. Screen Architecture - -### 3.1 Diagnostiek Blocks in Swift Layout - -Alle diagnostiek blocks verschijnen in de **Canvas Area** van Swift: - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ• Ochtend | 8 ptn Jan de Vries β–Ό πŸ‘€ SV β”‚ -β”‚ CONTEXT BAR β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ DIAGNOSTIEK BLOCK β”‚ β”‚ -β”‚ β”‚ (AfspraakBlock / β”‚ β”‚ -β”‚ β”‚ RapportageBlock / β”‚ β”‚ -β”‚ β”‚ DiagnoseBlock / β”‚ β”‚ -β”‚ β”‚ DiagnoseFormBlock) β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ CANVAS AREA β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Recent: [πŸ“… Jan-Diag] [πŸ“‹ Jan-Rapp] [πŸ₯ Jan-Diag] β”‚ -β”‚ RECENT STRIP β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 🎀 Typ of spreek wat je wilt doen... ⌘K β”‚ -β”‚ COMMAND INPUT β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 3.2 Block Sizes voor Diagnostiek - -| Block | Size | Max-width | Reden | -|-------|------|-----------|-------| -| AfspraakBlock | Medium | 640px | Form met meerdere velden | -| RapportageBlock | Large | 900px | Rich text editor + AI acties | -| DiagnoseBlock | Medium | 640px | Overzicht lijst | -| DiagnoseFormBlock | Medium | 640px | Form met ICD-10 zoeker | - ---- - -## 4. Component Specifications - -### 4.1 AfspraakBlock - -**Functie:** Diagnostiek-afspraak plannen met pre-fill vanuit intent. - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“… Nieuwe Afspraak [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ PatiΓ«nt * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Jan de Vries βœ“ β”‚ β”‚ -β”‚ β”‚ 59 jaar β€’ Kamer 12B [← Auto] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Datum * Van * Tot β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 2024-12-24 β”‚ β”‚ 10:00 β”‚ β”‚ 11:00 β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Type afspraak * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [Diagnostiek β–Ό] β”‚ β”‚ -β”‚ β”‚ β€’ Diagnostiek β”‚ β”‚ -β”‚ β”‚ β€’ Behandeling β”‚ β”‚ -β”‚ β”‚ β€’ Evaluatie β”‚ β”‚ -β”‚ β”‚ β€’ Consult β”‚ β”‚ -β”‚ β”‚ β€’ Overig β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Locatie β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [AMB β–Ό] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Notities (optioneel) β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [Annuleren] [πŸ’Ύ Opslaan] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Pre-fill Indicatoren:** -- PatiΓ«nt naam: **Bold** + checkmark -- Datum: **Highlighted** achtergrond -- Tijd: **Highlighted** achtergrond -- Type: **Pre-selected** in dropdown - -**Keyboard Shortcuts:** -- `⌘Enter` / `Ctrl+Enter`: Opslaan -- `Escape`: Annuleren -- `Tab`: Navigeer tussen velden - -**Na Opslaan:** -1. Toast: "βœ“ Afspraak diagnostiek met Jan de Vries aangemaakt voor morgen 10:00" -2. Block verdwijnt (200ms slide-down animatie) -3. Recent strip: badge "[πŸ“… Jan - Diagnostiek]" -4. Encounter_id opgeslagen in Swift store voor volgende stap - ---- - -### 4.2 RapportageBlock (Uitgebreid) - -**Functie:** Verslag schrijven na diagnostiek-afspraak met encounter koppeling. - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“‹ Rapportage [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ PatiΓ«nt: Jan de Vries [Wijzig] β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ”— Gekoppeld aan: Afspraak diagnostiek β”‚ β”‚ -β”‚ β”‚ 24 dec 2024 10:00 - 11:00 β”‚ β”‚ -β”‚ β”‚ [Ontkoppelen] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Type β”‚ -β”‚ [Diagnostiek βœ“] [Gesprek] [Evaluatie] [Telefonisch] [Consult]β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [B] [I] [β€’] [1.] ["] 🎀 Dicteer β”‚ β”‚ -β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Verslag van diagnostiek gesprek met Jan de Vries... β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [Rich text editor met formatting toolbar] β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ AI-acties β”‚ -β”‚ [✨ Samenvatten] [πŸ“– B1-niveau] [πŸ” Problemen extraheren] β”‚ -β”‚ β”‚ -β”‚ [Annuleren] [πŸ’Ύ Opslaan] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Encounter Koppeling:** -- **Zichtbaar:** Als recente diagnostiek-afspraak bestaat -- **Styling:** Link badge met encounter details -- **Actie:** Klik "Ontkoppelen" om koppeling te verwijderen -- **Empty state:** "Geen recente diagnostiek-afspraak gevonden. [+ Koppel afspraak]" - -**AI Acties (Zijpaneel):** -- **✨ Samenvatten:** Bullets van kernpunten -- **πŸ“– B1-niveau:** Herschreven tekst (leesbaar voor patiΓ«nt) -- **πŸ” Problemen:** Gestructureerde lijst met categorie + severity - -**Keyboard Shortcuts:** -- `⌘Enter` / `Ctrl+Enter`: Opslaan -- `Escape`: Annuleren -- `⌘B` / `Ctrl+B`: Bold -- `⌘I` / `Ctrl+I`: Italic -- `Space` (leeg): Start dicteer - -**Na Opslaan:** -1. Toast: "βœ“ Rapportage opgeslagen en gekoppeld aan afspraak" -2. Block verdwijnt -3. Recent strip: badge "[πŸ“‹ Jan - Diagnostiek]" -4. Suggestie: "Diagnose toevoegen?" (als nog geen diagnose) - ---- - -### 4.3 DiagnoseBlock - -**Functie:** Overzicht van alle diagnoses van een patiΓ«nt. - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ₯ Diagnoses van Jan de Vries [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Filter: [Actief βœ“] [Inactief] [Alle] β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ F41.1 Gegeneraliseerde angststoornis β”‚ β”‚ -β”‚ β”‚ Status: ● Actief | Ernst: Matig β”‚ β”‚ -β”‚ β”‚ Toegevoegd: 15 nov 2024 | Intake: Intake 1 β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [✏️ Bewerken] [πŸ“„ Details] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ F32.1 Depressieve stoornis β”‚ β”‚ -β”‚ β”‚ Status: ● Actief | Ernst: Mild β”‚ β”‚ -β”‚ β”‚ Toegevoegd: 20 dec 2024 | Intake: Intake 2 β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [✏️ Bewerken] [πŸ“„ Details] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ F41.0 Paniekstoornis β”‚ β”‚ -β”‚ β”‚ Status: β—‹ Inactief | Ernst: - β”‚ β”‚ -β”‚ β”‚ Toegevoegd: 10 sep 2024 | Intake: Intake 1 β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [✏️ Bewerken] [πŸ“„ Details] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [+ Nieuwe diagnose toevoegen] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Filter Tabs:** -- **Actief:** Alleen diagnoses met status "active" (default) -- **Inactief:** Alleen diagnoses met status "inactive" of "resolved" -- **Alle:** Alle diagnoses - -**Diagnose Card:** -- **Code:** ICD-10 code (F41.1) in monospace font -- **Omschrijving:** Volledige naam in bold -- **Status:** Dot indicator (● = actief, β—‹ = inactief) -- **Ernst:** Badge met kleur (Mild = groen, Matig = geel, Ernstig = rood) -- **Metadata:** Datum + Intake link - -**Empty State:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Geen diagnoses gevonden voor Jan de Vries β”‚ -β”‚ β”‚ -β”‚ [+ Nieuwe diagnose toevoegen] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Keyboard Shortcuts:** -- `Escape`: Sluit block -- `Enter` (op diagnose): Open DiagnoseFormBlock (edit mode) -- `N`: Nieuwe diagnose toevoegen - ---- - -### 4.4 DiagnoseFormBlock - -**Functie:** Diagnose aanmaken of bijstellen met ICD-10 zoeker. - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ₯ Nieuwe Diagnose [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ PatiΓ«nt: Jan de Vries (read-only) β”‚ -β”‚ β”‚ -β”‚ ICD-10 Code * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ” Zoek ICD-10 code of omschrijving... β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Resultaten (bij typen): β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ β€’ F41.1 Gegeneraliseerde angststoornis β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β€’ F41.0 Paniekstoornis β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β€’ F41.2 Gemengde angst- en depressieve stoornisβ”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Code: F41.1 (read-only na selectie) β”‚ -β”‚ Omschrijving: Gegeneraliseerde angststoornis (read-only) β”‚ -β”‚ β”‚ -β”‚ Type * β”‚ -β”‚ β—‹ Hoofddiagnose ● Nevendiagnose β”‚ -β”‚ β”‚ -β”‚ Status * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [Actief β–Ό] β”‚ β”‚ -β”‚ β”‚ β€’ Actief β”‚ β”‚ -β”‚ β”‚ β€’ Inactief β”‚ β”‚ -β”‚ β”‚ β€’ Resolved β”‚ β”‚ -β”‚ β”‚ β€’ Remission β”‚ β”‚ -β”‚ β”‚ β€’ Recurrence β”‚ β”‚ -β”‚ β”‚ β€’ Relapse β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Ernst β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [Geen β–Ό] β”‚ β”‚ -β”‚ β”‚ β€’ Geen β”‚ β”‚ -β”‚ β”‚ β€’ Mild β”‚ β”‚ -β”‚ β”‚ β€’ Matig β”‚ β”‚ -β”‚ β”‚ β€’ Ernstig β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Intake koppeling (optioneel) β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [Geen β–Ό] β”‚ β”‚ -β”‚ β”‚ β€’ Geen β”‚ β”‚ -β”‚ β”‚ β€’ Intake 1 - 15 nov 2024 β”‚ β”‚ -β”‚ β”‚ β€’ Intake 2 - 20 dec 2024 β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Toelichting (optioneel) β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [Annuleren] [πŸ’Ύ Opslaan] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**ICD-10 Zoeker Gedrag:** -- **Trigger:** Typ minimaal 2 karakters -- **Search:** Fuzzy search op code (F41.1) of omschrijving (angst) -- **Results:** Dropdown met max 10 resultaten -- **Selectie:** Klik op resultaat β†’ code + omschrijving worden ingevuld (read-only) -- **Pre-fill:** Als ICD-10 code in intent β†’ automatisch zoeken en invullen - -**Status Kleuren:** -- **Actief:** Groen dot (●) -- **Inactief:** Grijs dot (β—‹) -- **Resolved:** Blauw dot (●) - -**Ernst Badges:** -- **Geen:** Geen badge -- **Mild:** Groen badge -- **Matig:** Geel badge -- **Ernstig:** Rood badge - -**Edit Mode:** -- Alle velden pre-filled met huidige waarden -- PatiΓ«nt read-only -- Code + omschrijving read-only (wijzig via zoeker) -- Status, ernst, type, toelichting bewerkbaar - -**Keyboard Shortcuts:** -- `⌘Enter` / `Ctrl+Enter`: Opslaan -- `Escape`: Annuleren -- `Tab`: Navigeer tussen velden -- `↑` `↓` (in zoeker): Navigeer resultaten -- `Enter` (in zoeker): Selecteer resultaat - -**Na Opslaan:** -1. Toast: "βœ“ Diagnose F41.1 - Gegeneraliseerde angststoornis toegevoegd" -2. Block verdwijnt -3. DiagnoseBlock wordt automatisch getoond met nieuwe/bijgewerkte diagnose - ---- - -## 5. Interaction Flows - -### 5.1 Happy Path: Complete Diagnostiek Workflow (3-5 minuten) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STAP 1: AFSPRAAK PLANNEN (30 sec) β”‚ -β”‚ β”‚ -β”‚ Behandelaar: "afspraak diagnostiek met jan morgen 10:00" β”‚ -β”‚ β†’ AfspraakBlock verschijnt met pre-fill β”‚ -β”‚ βœ“ PatiΓ«nt: Jan de Vries [highlighted] β”‚ -β”‚ βœ“ Datum: morgen [highlighted] β”‚ -β”‚ βœ“ Tijd: 10:00 [highlighted] β”‚ -β”‚ βœ“ Type: Diagnostiek [pre-selected] β”‚ -β”‚ β†’ Behandelaar review β†’ klikt Opslaan β”‚ -β”‚ β†’ Toast: "βœ“ Afspraak aangemaakt" β”‚ -β”‚ β†’ Encounter_id opgeslagen β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STAP 2: RAPPORTAGE SCHRIJVEN (2 min) β”‚ -β”‚ β”‚ -β”‚ Behandelaar: "rapportage diagnostiek gesprek met jan" β”‚ -β”‚ β†’ RapportageBlock verschijnt β”‚ -β”‚ βœ“ PatiΓ«nt: Jan de Vries β”‚ -β”‚ βœ“ Gekoppeld aan: Afspraak diagnostiek - morgen 10:00 β”‚ -β”‚ βœ“ Type: Diagnostiek [pre-selected] β”‚ -β”‚ β†’ Behandelaar schrijft/dicteert verslag β”‚ -β”‚ β†’ Optioneel: AI samenvatten β”‚ -β”‚ β†’ Klikt Opslaan β”‚ -β”‚ β†’ Toast: "βœ“ Rapportage gekoppeld aan afspraak" β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STAP 3: DIAGNOSE BEKIJKEN (30 sec) β”‚ -β”‚ β”‚ -β”‚ Behandelaar: "diagnose jan" β”‚ -β”‚ β†’ DiagnoseBlock verschijnt met overzicht β”‚ -β”‚ β†’ Filter: Actief (default) β”‚ -β”‚ β†’ Behandelaar ziet bestaande diagnoses β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STAP 4: DIAGNOSE TOEVOEGEN (1 min) β”‚ -β”‚ β”‚ -β”‚ Behandelaar: "diagnose toevoegen jan F41.1" β”‚ -β”‚ β†’ DiagnoseFormBlock verschijnt β”‚ -β”‚ βœ“ PatiΓ«nt: Jan de Vries [read-only] β”‚ -β”‚ βœ“ ICD-10: F41.1 [pre-filled] β”‚ -β”‚ βœ“ Omschrijving: Gegeneraliseerde angststoornis [pre-filled] β”‚ -β”‚ β†’ Behandelaar vult type, status, ernst in β”‚ -β”‚ β†’ Koppelt aan intake (optioneel) β”‚ -β”‚ β†’ Klikt Opslaan β”‚ -β”‚ β†’ Toast: "βœ“ Diagnose toegevoegd" β”‚ -β”‚ β†’ DiagnoseBlock wordt getoond met nieuwe diagnose β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -TOTAAL: ~4 minuten (was: 10-15 minuten) -``` - -### 5.2 Diagnose Bijstellen Flow - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Behandelaar: "diagnose wijzigen jan" β”‚ -β”‚ β†’ DiagnoseBlock verschijnt β”‚ -β”‚ β†’ Behandelaar klikt op diagnose F41.1 β”‚ -β”‚ β†’ DiagnoseFormBlock verschijnt (edit mode) β”‚ -β”‚ βœ“ Alle velden pre-filled met huidige waarden β”‚ -β”‚ β†’ Behandelaar wijzigt: β”‚ -β”‚ - Status: Actief β†’ Resolved β”‚ -β”‚ - Ernst: Matig β†’ Mild β”‚ -β”‚ - Toelichting: "Na behandeling verbeterd" β”‚ -β”‚ β†’ Klikt Opslaan β”‚ -β”‚ β†’ Toast: "βœ“ Diagnose bijgewerkt" β”‚ -β”‚ β†’ DiagnoseBlock wordt getoond met bijgewerkte diagnose β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 5.3 Proactieve Suggesties Flow - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Na Afspraak opslaan: β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ’‘ Rapportage schrijven voor deze afspraak? β”‚ β”‚ -β”‚ β”‚ [Ja] [Later] [Γ—] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Na Rapportage opslaan (zonder diagnose): β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ’‘ Diagnose toevoegen voor Jan de Vries? β”‚ β”‚ -β”‚ β”‚ [Ja] [Later] [Γ—] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 6. Visual Design Tokens - -### 6.1 Block Colors (Dark Theme - Swift Context) - -| Element | Hex | Gebruik | -|---------|-----|---------| -| Block Background | `#1E293B` | Block achtergrond | -| Block Border | `#334155` | Block rand | -| Text Primary | `#F1F5F9` | Hoofdtekst | -| Text Secondary | `#94A3B8` | Subtekst | -| Accent | `#3B82F6` | Primaire acties | -| Success | `#10B981` | Bevestigingen | -| Warning | `#F59E0B` | Waarschuwingen | -| Error | `#EF4444` | Fouten | - -### 6.2 Status Colors - -| Status | Dot | Badge | Hex | -|--------|-----|-------|-----| -| Actief | ● | - | `#10B981` | -| Inactief | β—‹ | - | `#64748B` | -| Resolved | ● | - | `#3B82F6` | - -### 6.3 Ernst Badges - -| Ernst | Badge | Hex | -|-------|-------|-----| -| Geen | - | - | -| Mild | Badge | `#10B981` | -| Matig | Badge | `#F59E0B` | -| Ernstig | Badge | `#EF4444` | - -### 6.4 ICD-10 Code Styling - -| Element | Font | Size | Color | -|---------|------|------|-------| -| Code | Monospace | 14px | `#F1F5F9` | -| Omschrijving | Sans-serif | 16px | `#F1F5F9` | - ---- - -## 7. Keyboard Navigation - -### 7.1 AfspraakBlock - -| Key | Action | -|-----|--------| -| `⌘Enter` / `Ctrl+Enter` | Opslaan | -| `Escape` | Annuleren | -| `Tab` | Navigeer tussen velden | -| `↑` `↓` | Navigeer dropdown opties | - -### 7.2 RapportageBlock - -| Key | Action | -|-----|--------| -| `⌘Enter` / `Ctrl+Enter` | Opslaan | -| `Escape` | Annuleren | -| `⌘B` / `Ctrl+B` | Bold | -| `⌘I` / `Ctrl+I` | Italic | -| `Space` (leeg) | Start dicteer | - -### 7.3 DiagnoseBlock - -| Key | Action | -|-----|--------| -| `Escape` | Sluit block | -| `Enter` (op diagnose) | Open DiagnoseFormBlock (edit) | -| `N` | Nieuwe diagnose | -| `↑` `↓` | Navigeer diagnoses | - -### 7.4 DiagnoseFormBlock - -| Key | Action | -|-----|--------| -| `⌘Enter` / `Ctrl+Enter` | Opslaan | -| `Escape` | Annuleren | -| `Tab` | Navigeer tussen velden | -| `↑` `↓` (in zoeker) | Navigeer resultaten | -| `Enter` (in zoeker) | Selecteer resultaat | - ---- - -## 8. Error States & Edge Cases - -### 8.1 AfspraakBlock Errors - -**Geen patiΓ«nt gevonden:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ⚠️ PatiΓ«nt "Jan" niet gevonden β”‚ -β”‚ β”‚ -β”‚ [πŸ” Zoek patiΓ«nt] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Ongeldige datum:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Datum * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ morgen ❌ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ ⚠️ Ongeldige datum. Gebruik formaat: DD-MM-YYYY β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 8.2 RapportageBlock Errors - -**Geen encounter gevonden:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Geen recente diagnostiek-afspraak gevonden β”‚ -β”‚ β”‚ -β”‚ [+ Koppel afspraak] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Lege rapportage:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ⚠️ Rapportage mag niet leeg zijn β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 8.3 DiagnoseFormBlock Errors - -**ICD-10 code niet gevonden:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ICD-10 Code * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ F99.9 ❌ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ ⚠️ ICD-10 code F99.9 niet gevonden β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Diagnose bestaat al:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ⚠️ Diagnose F41.1 bestaat al voor Jan de Vries β”‚ -β”‚ β”‚ -β”‚ [✏️ Bestaande diagnose bewerken] [βœ• Annuleren] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 9. Responsive Design - -### 9.1 Mobile (< 768px) - -**AfspraakBlock:** -- Full-width block -- Stacked form velden -- Date/time pickers full-width -- Bottom sheet voor dropdowns - -**RapportageBlock:** -- Full-width block -- Rich text editor full-width -- AI acties als buttons onder editor -- Bottom sheet voor encounter koppeling - -**DiagnoseBlock:** -- Full-width block -- Diagnose cards stacked -- Filter tabs als chips -- Swipe to edit - -**DiagnoseFormBlock:** -- Full-width block -- Form velden stacked -- ICD-10 zoeker full-width -- Bottom sheet voor dropdowns - -### 9.2 Tablet (768px - 1024px) - -- Blocks blijven medium/large size -- Form velden kunnen naast elkaar (waar logisch) -- Dropdowns blijven inline - ---- - -## 10. Accessibility - -### 10.1 Screen Reader Support - -- Alle form velden hebben labels -- Status changes worden aangekondigd -- Error messages zijn toegankelijk -- Keyboard navigation volledig ondersteund - -### 10.2 Focus Management - -- Focus blijft in block na openen -- Focus naar eerste veld bij nieuwe block -- Focus naar error veld bij validatie fout -- Focus naar recent strip na sluiten - -### 10.3 Color Contrast - -- Alle tekst voldoet aan WCAG AA (4.5:1) -- Status indicators hebben tekst labels -- Error states hebben icon + tekst - ---- - -## 11. Animation & Transitions - -### 11.1 Block Animations - -**Openen:** -- Slide up + fade in (200ms) -- Scale: 0.95 β†’ 1.0 - -**Sluiten:** -- Slide down + fade out (200ms) -- Scale: 1.0 β†’ 0.95 - -**Pre-fill Highlight:** -- Pulse animatie (2x) bij pre-filled velden -- Duration: 600ms - -### 11.2 Toast Notifications - -- Slide in from bottom (300ms) -- Auto-dismiss na 3 seconden -- Hover: pause auto-dismiss - ---- - -## 12. Component Checklist - -### 🟑 P2: Diagnostiek Workflow Blocks - -- [ ] AfspraakBlock - - [ ] Pre-fill vanuit intent - - [ ] Encounter_id teruggeven - - [ ] Dark theme styling - - [ ] Keyboard shortcuts - - [ ] Error states - -- [ ] RapportageBlock (uitgebreid) - - [ ] Encounter koppeling - - [ ] Type "diagnostiek" - - [ ] Rich text editor - - [ ] AI acties - - [ ] Dark theme styling - -- [ ] DiagnoseBlock - - [ ] Overzicht diagnoses - - [ ] Filter tabs (Actief/Inactief/Alle) - - [ ] Diagnose cards - - [ ] Empty state - - [ ] Dark theme styling - -- [ ] DiagnoseFormBlock - - [ ] ICD-10 zoeker (fuzzy search) - - [ ] Pre-fill vanuit intent - - [ ] Edit mode - - [ ] Status + ernst selectie - - [ ] Dark theme styling - ---- - -## 13. Summary: De Transformatie voor Behandelaars - -``` -VAN: NAAR: -──────────────────────────────────────────────────────────────── - -15-20 klikken per traject β†’ 3 zinnen + 3 klikken -10-15 minuten per traject β†’ 3-5 minuten -Menu navigatie β†’ Natuurlijke taal -Handmatige koppeling β†’ Automatische koppeling -ICD-10 handmatig zoeken β†’ Fuzzy search + pre-fill -Vergeten rapportage β†’ Proactieve suggesties - -TIJDSBESPARING: -───────────────────────────────────────────────────────────────── -Afspraak plannen: 2-3 min β†’ 30 sec (85% sneller) -Rapportage schrijven: 5-8 min β†’ 2 min (75% sneller) -Diagnose toevoegen: 3-5 min β†’ 1 min (80% sneller) - -Per behandelaar per week: ~2 uur terug naar patiΓ«ntcontact -``` - ---- - -## Wijzigingslog - -| Versie | Datum | Wijzigingen | -|--------|-------|-------------| -| 1.0 | 23-12-2024 | InitiΓ«le versie - UX/UI specificaties voor diagnostiek workflow | - diff --git a/docs/swift/archive/swift-ux-v2.1.md b/docs/swift/archive/swift-ux-v2.1.md deleted file mode 100644 index 5889be0..0000000 --- a/docs/swift/archive/swift-ux-v2.1.md +++ /dev/null @@ -1,1070 +0,0 @@ -# 🎨 UX/UI Design Document β€” Ephemeral UI EPD - -**Projectnaam:** Ephemeral UI EPD β€” "Het Verdwijnende EPD" -**Versie:** v2.1 -**Datum:** 23-12-2024 -**Auteur:** Colin Lit - ---- - -## 1. De Visie: Van Menu's naar Conversatie - -### 1.1 Het Probleem met Traditionele EPD's - -``` -TRADITIONEEL EPD -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Menu β”‚ Submenu β”‚ Tab β”‚ Tab β”‚ Tab β”‚ Subtab β”‚ Form β”‚ Form β”‚ Save β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Item β”‚ β”‚ -β”‚ Item β”‚ "Waar moet ik zijn voor een dagnotitie?" β”‚ -β”‚ Item β”‚ β”‚ -β”‚ Item β”‚ "Hoe kom ik bij de overdracht?" β”‚ -β”‚ Item β”‚ β”‚ -β”‚ ... β”‚ "Waar zie ik de vitale functies?" β”‚ -β”‚ (47) β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -Resultaat: 200 pagina handleiding, 3 maanden training, 12 klikken per actie -``` - -### 1.2 De Oplossing: Één Input, Slimme Responses - -``` -EPHEMERAL UI EPD -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ β”‚ -β”‚ "Wat wil je doen?" β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [Relevante UI β”‚ β”‚ -β”‚ β”‚ verschijnt hier] β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 🎀 notitie jan medicatie gegeven β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -Resultaat: 0 training, 1 zin, klaar -``` - -### 1.3 Core Design Principles - -| Principe | Betekenis | -|----------|-----------| -| **Conversational** | Je praat tegen het systeem, niet door het systeem | -| **Contextual** | Systeem weet wie je bent, welke dienst, welke patiΓ«nt | -| **Ephemeral** | UI verschijnt wanneer nodig, verdwijnt wanneer klaar | -| **Complete** | Alles wat een EPD kan, kan deze UI ook β€” anders | - ---- - -## 2. Prioriteitenlijst: Frequentie-Gedreven Development - -### 2.1 Frequentie & Impact Matrix - -Op basis van analyse van dagelijks EPD-gebruik: - -``` - FREQUENTIE - ↑ - Hoog β”‚ ⭐ DAGNOTITIE ⭐ ZOEKEN - (10-20x/ β”‚ - dag) β”‚ ⭐ LAATSTE NOTITIES BEKIJKEN - β”‚ - β”‚ - Medium β”‚ πŸ“‹ RAPPORTAGE πŸ”„ OVERDRACHT - (3-5x/ β”‚ - dag) β”‚ πŸ“Š VITALS πŸ“… AGENDA - β”‚ πŸ” DIAGNOSE πŸ“„ BEHANDELPLAN - β”‚ - β”‚ - Laag β”‚ πŸ“ INTAKE ⚠️ RISICOTAXATIE - (1x/week β”‚ πŸ‘Ά KINDCHECK πŸ“ž CONTACTEN - of minder) β”‚ πŸ“Š ROM πŸ₯ ANAMNESE - β”‚ - └─────────────────────────────────────→ - Laag Hoog - COMPLEXITEIT -``` - -### 2.2 Prioriteit Tiers - -#### πŸ”΄ P1: KRITIEK (MVP Week 1-2) -*Hoogfrequent, hoogste ROI* - -| # | Intent | Freq/dag | Huidige klikken | Target | Block | -|---|--------|----------|-----------------|--------|-------| -| 1 | **dagnotitie** | 10-20x | 5-8 | 1 zin | `DagnotatieBlock` | -| 2 | **zoeken** | 15-20x | 3-5 | 1 zin | `ZoekenBlock` | -| 3 | **patient_context** | 10-15x | 4-6 | Auto | `PatientContextCard` | -| 4 | **overdracht** | 2-3x | 8-12 | 1 zin | `OverdrachtBlock` | - -**Tijdsbesparing P1:** ~4 uur per verpleegkundige per dag - -#### 🟑 P2: BELANGRIJK (MVP Week 3-4) -*Middenfrequent, significant* - -| # | Intent | Freq/dag | Huidige klikken | Target | Block | -|---|--------|----------|-----------------|--------|-------| -| 5 | **rapportage** | 3-5x | 6-10 | 1 zin + dicteer | `RapportageBlock` | -| 6 | **agenda** | 2-3x | 3-4 | 1 zin | `AgendaBlock` | -| 7 | **vitals** | 2-4x | 4-6 | 1 zin | `MetingenBlock` | -| 8 | **diagnose_bekijken** | 3-5x | 4-6 | 1 zin | `PatientContextCard` | -| 9 | **behandelplan_bekijken** | 2-3x | 4-6 | 1 zin | `PatientContextCard` | - -**Tijdsbesparing P2:** ~1.5 uur per behandelaar per dag - -#### 🟒 P3: WAARDEVOL (Post-MVP) -*Laagfrequent maar noodzakelijk* - -| # | Intent | Frequentie | Block | -|---|--------|------------|-------| -| 10 | **intake_starten** | 1x/week | `IntakeWizard` | -| 11 | **behandelplan_maken** | 1x/maand | `BehandelplanBlock` | -| 12 | **diagnose_toevoegen** | 1x/week | `DiagnoseBlock` | -| 13 | **risicotaxatie** | 1x/maand | `RisicoBlock` | -| 14 | **anamnese** | 1x/intake | `AnamneseBlock` | -| 15 | **contactpersonen** | 1x/intake | `ContactenBlock` | -| 16 | **kindcheck** | 1x/intake | `KindcheckBlock` | -| 17 | **rom** | 1x/maand | `ROMBlock` | - -#### βšͺ P4: NICE-TO-HAVE (Backlog) -*Edge cases, admin functies* - -| # | Intent | Block | -|---|--------|-------| -| 18 | **medicatie_overzicht** | `MedicatieBlock` | -| 19 | **decursus** | `DecursusBlock` | -| 20 | **nieuwe_patient** | `NieuwePatiΓ«ntBlock` | -| 21 | **afspraak_plannen** | `AfspraakBlock` | - -### 2.3 Development Roadmap - -``` -WEEK 1-2: P1 (Kritiek) -β”œβ”€β”€ Dag 1-2: Command Input + Intent Engine -β”œβ”€β”€ Dag 3-4: DagnotatieBlock + ZoekenBlock -β”œβ”€β”€ Dag 5-6: PatientContextCard -β”œβ”€β”€ Dag 7-8: OverdrachtBlock -└── Deliverable: "notitie jan medicatie" β†’ opslaan in 15 sec - -WEEK 3-4: P2 (Belangrijk) -β”œβ”€β”€ Dag 9-10: RapportageBlock + dicteer -β”œβ”€β”€ Dag 11-12: AgendaBlock -β”œβ”€β”€ Dag 13-14: MetingenBlock -└── Deliverable: Behandelaar kan volledige dag werken - -POST-MVP: P3 + P4 -β”œβ”€β”€ Sprint 3: IntakeWizard, BehandelplanBlock -β”œβ”€β”€ Sprint 4: DiagnoseBlock, RisicoBlock -β”œβ”€β”€ Sprint 5: Overige blocks -└── Deliverable: Feature parity met klassiek EPD -``` - ---- - -## 3. Complete Intent Mapping - -### 3.1 Alle Intents per Categorie - -#### πŸ“ SCHRIJVEN (Writer Intents) - -| Intent | Trigger patterns | Block | Prio | -|--------|-----------------|-------|------| -| `dagnotitie` | "notitie [patient]", "dagnotitie", "[patient] medicatie gegeven", "incident bij [patient]" | `DagnotatieBlock` | P1 | -| `rapportage` | "rapportage", "gesprek gehad met [patient]", "behandelgesprek" | `RapportageBlock` | P2 | -| `intake_schrijven` | "intake schrijven", "intake [patient]" | `IntakeBlock` | P3 | -| `anamnese` | "anamnese", "voorgeschiedenis [patient]", "historie" | `AnamneseBlock` | P3 | -| `diagnose_toevoegen` | "diagnose toevoegen", "classificatie", "[ICD-code]" | `DiagnoseBlock` | P3 | -| `behandelplan_maken` | "behandelplan maken", "doelen opstellen" | `BehandelplanBlock` | P3 | -| `risicotaxatie` | "risico [patient]", "valrisico", "suΓ―cidaliteit", "taxatie" | `RisicoBlock` | P3 | -| `kindcheck` | "kindcheck", "kinderen in beeld" | `KindcheckBlock` | P3 | -| `meting_invoeren` | "bloeddruk", "meting invoeren", "vitals invoeren" | `MetingenBlock` | P2 | -| `afspraak_maken` | "afspraak plannen", "inplannen" | `AfspraakBlock` | P4 | -| `contact_toevoegen` | "contactpersoon toevoegen", "familie toevoegen" | `ContactenBlock` | P3 | - -#### πŸ” LEZEN (Reader Intents) - -| Intent | Trigger patterns | Block | Prio | -|--------|-----------------|-------|------| -| `zoeken` | "zoek [naam]", "wie is [naam]", "vind [naam]" | `ZoekenBlock` | P1 | -| `patient_info` | "dossier [patient]", "open [patient]", "info [patient]" | `PatientContextCard` | P1 | -| `overdracht_lezen` | "wat moet ik weten", "overdracht lezen", "briefing" | `OverdrachtLezenBlock` | P1 | -| `laatste_notities` | "notities [patient]", "wat is er gebeurd", "updates" | `PatientContextCard` | P1 | -| `diagnose_bekijken` | "diagnose [patient]", "diagnoses", "classificatie" | `PatientContextCard` | P2 | -| `behandelplan_bekijken` | "behandelplan [patient]", "doelen [patient]" | `PatientContextCard` | P2 | -| `agenda` | "agenda", "afspraken", "wie zie ik vandaag" | `AgendaBlock` | P2 | -| `vitals_bekijken` | "vitals [patient]", "metingen", "bloeddruk historie" | `MetingenOverzichtBlock` | P2 | -| `medicatie` | "medicatie [patient]", "welke medicijnen" | `MedicatieBlock` | P4 | -| `contacten_bekijken` | "contacten [patient]", "familie [patient]" | `ContactenBlock` | P3 | -| `decursus` | "decursus [patient]", "verloop", "historie" | `DecursusBlock` | P4 | -| `mijn_patienten` | "mijn patiΓ«nten", "caseload", "wie heb ik" | `PatiΓ«ntenlijstBlock` | P2 | - -#### πŸ”„ SAMENVATTEN (Summary Intents) - -| Intent | Trigger patterns | Block | Prio | -|--------|-----------------|-------|------| -| `overdracht_maken` | "overdracht maken", "dienst klaar", "samenvatting dienst" | `OverdrachtBlock` | P1 | -| `samenvatting` | "samenvatting [patient]", "vat samen" | `SamenvattingBlock` | P3 | -| `rom_afnemen` | "vragenlijst", "rom afnemen", "meting doen" | `ROMBlock` | P3 | - -#### ❓ SYSTEEM (System Intents) - -| Intent | Trigger patterns | Block | Prio | -|--------|-----------------|-------|------| -| `help` | "help", "wat kan ik doen", "hoe werkt dit" | `HelpBlock` | P1 | -| `fallback` | [onbekend/lage confidence] | `FallbackPicker` | P1 | - -### 3.2 Context-Triggered UI (Proactief) - -| Trigger | Conditie | Wat verschijnt | Prio | -|---------|----------|----------------|------| -| **Dienst start** | Login of shift-wissel | `OverdrachtLezenBlock` | P1 | -| **Dienst einde** | 30 min voor einde | Suggestie banner | P1 | -| **PatiΓ«nt geselecteerd** | Na zoeken/klik | `PatientContextCard` | P1 | -| **Afspraak nadert** | 15 min voor | `AfspraakContextCard` | P2 | -| **Alert actief** | PatiΓ«nt heeft alert | `AlertBanner` | P1 | -| **Behandelplan verloopt** | < 7 dagen | `RenewalReminder` | P3 | -| **ROM gepland** | Datum bereikt | `ROMReminder` | P3 | - ---- - -## 4. Screen Architecture - -### 4.1 De Enige Layout - -Er is maar één scherm. Alles speelt zich hier af: - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ• Ochtend | 8 ptn Jan de Vries β–Ό πŸ‘€ SV β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ CONTEXT BAR β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ ACTIVE BLOCK β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ (wat nu relevant β”‚ β”‚ -β”‚ β”‚ is verschijnt β”‚ β”‚ -β”‚ β”‚ hier) β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ CANVAS AREA β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Recent: [πŸ“ Jan-Med] [πŸ”„ Overdracht] [πŸ” Marie] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ RECENT STRIP β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 🎀 Typ of spreek wat je wilt doen... ⌘K β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ COMMAND INPUT β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 4.2 De Vier Zones - -| Zone | Hoogte | Functie | -|------|--------|---------| -| **Context Bar** | 48px | Dienst, actieve patiΓ«nt, user | -| **Canvas Area** | Flex (rest) | Waar blocks verschijnen | -| **Recent Strip** | 48px | Laatste acties, quick access | -| **Command Input** | 64px | De enige input | - ---- - -## 5. Component Specifications - -### 5.1 Context Bar - -Minimalistische header met alleen essentiΓ«le context. - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ• Ochtend | 8 ptn Jan de Vries β–Ό πŸ‘€ SV β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↑ ↑ ↑ - Dienst + patiΓ«nten Actieve patiΓ«nt User -``` - -**Dienst kleuren:** - -| Dienst | Tijd | Kleur | Icon | -|--------|------|-------|------| -| Ochtend | 07:00-15:00 | `#F59E0B` | πŸŒ… | -| Middag | 15:00-23:00 | `#3B82F6` | 🌀️ | -| Nacht | 23:00-07:00 | `#6366F1` | πŸŒ™ | - -**PatiΓ«nt dropdown:** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Jan de Vries βœ“ β”‚ ← Huidige selectie -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Recent: β”‚ -β”‚ Marie van den Berg β”‚ -β”‚ Piet Jansen β”‚ -β”‚ Anna de Vries β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ πŸ” Zoek andere patiΓ«nt... β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ βœ• Geen patiΓ«nt (clear) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -### 5.2 Command Input - -Het hart van de interface. - -``` -DEFAULT STATE: -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 🎀 Typ of spreek wat je wilt doen... ⌘K β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -TYPING STATE: -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 🎀 notitie jan medicatie| ⌘K β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -LISTENING STATE: -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ”΄ "notitie jan de vries medicatie..." [Stop] β”‚ -β”‚ ════════░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -PROCESSING STATE: -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ⏳ Even kijken wat je bedoelt... β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Styling:** - -| Property | Value | -|----------|-------| -| Height | 64px | -| Background | #FFFFFF | -| Border | 1px #E2E8F0, 2px #3B82F6 (focus) | -| Border-radius | 16px | -| Shadow | lg | -| Font-size | 18px | -| Position | Fixed bottom, 24px padding | - ---- - -### 5.3 Block Container (Generic Wrapper) - -Alle blocks gebruiken dezelfde container. - -| Size | Max-width | Use case | -|------|-----------|----------| -| Small | 480px | Quick entry (notitie, zoeken, meting) | -| Medium | 640px | Forms (rapportage, intake, behandelplan) | -| Large | 900px | Overzichten (overdracht, patiΓ«ntenlijst, agenda) | -| XLarge | 1100px | Wizards (intake volledig) | - ---- - -### 5.4 P1 Blocks (MVP Week 1-2) - -#### 5.4.1 DagnotatieBlock - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“ Dagnotitie [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ PatiΓ«nt β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Jan de Vries βœ“ β”‚ β”‚ -β”‚ β”‚ 59 jaar β€’ Kamer 12B [← Auto] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Categorie β”‚ -β”‚ [πŸ’Š Med βœ“] [🍽️ ADL] [πŸ‘οΈ Obs] [⚠️ Inc] [πŸ’¬ Alg] β”‚ -β”‚ β”‚ -β”‚ Notitie β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Medicatie uitgereikt volgens schema.| β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ ☐ Opnemen in overdracht β”‚ -β”‚ β”‚ -β”‚ [Annuleren] [πŸ’Ύ Opslaan] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Categorie opties:** - -| Categorie | Icon | Kleur | Keyboard | -|-----------|------|-------|----------| -| Medicatie | πŸ’Š | `#FEF6DC` / `#F59E0B` | `1` | -| ADL | 🍽️ | `#E8F8EF` / `#16A34A` | `2` | -| Observatie | πŸ‘οΈ | `#EFF6FF` / `#3B82F6` | `3` | -| Incident | ⚠️ | `#FEF2F2` / `#DC2626` | `4` | -| Algemeen | πŸ’¬ | `#F1F5F9` / `#64748B` | `5` | - ---- - -#### 5.4.2 ZoekenBlock - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ” Zoeken [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ” jan| β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ 3 resultaten β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ‘€ Jan de Vries [Enter] β”‚ β”‚ -β”‚ β”‚ 59 jr β€’ Kamer 12B β€’ Laatst: 2 uur β”‚ β”‚ -β”‚ β”‚ ⚠️ Alert: verhoogd valrisico β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ‘€ Jan Bakker β”‚ β”‚ -β”‚ β”‚ 45 jr β€’ Kamer 8A β€’ Laatst: 1 dag β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ‘€ Jantine Smit β”‚ β”‚ -β”‚ β”‚ 33 jr β€’ Kamer 3C β€’ Laatst: 3 dagen β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -#### 5.4.3 PatientContextCard - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ‘€ Jan de Vries [βˆ’] [Γ—] β”‚ -β”‚ 59 jaar β€’ Kamer 12B β€’ Opname: 15 nov 2024 β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ ⚠️ ALERT: Verhoogd valrisico (2 incidenten deze week) β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ πŸ“‹ Laatste notities β”‚ -β”‚ ───────────────────────────────────────────────────────── β”‚ -β”‚ Vandaag 09:15 πŸ’Š Medicatie uitgereikt β”‚ -β”‚ Gisteren 14:30 πŸ’¬ Goed gesprek over ontslagplanning β”‚ -β”‚ Gisteren 08:00 🍽️ Ontbijt volledig genuttigd β”‚ -β”‚ β”‚ -β”‚ πŸ“Š Vitals vandaag β”‚ -β”‚ ───────────────────────────────────────────────────────── β”‚ -β”‚ Bloeddruk: 135/85 (↑) β€’ Pols: 72 β€’ Temp: 36.8Β°C β”‚ -β”‚ β”‚ -β”‚ πŸ₯ Diagnose β”‚ -β”‚ ───────────────────────────────────────────────────────── β”‚ -β”‚ F32.1 Depressieve stoornis, matig β€’ Ernst: Middel β”‚ -β”‚ β”‚ -β”‚ πŸ“„ Behandelplan β”‚ -β”‚ ───────────────────────────────────────────────────────── β”‚ -β”‚ CGT 12 sessies β€’ Sessie 4/12 β€’ Eval: 28 dec β”‚ -β”‚ β”‚ -β”‚ πŸ‘¨β€πŸ‘©β€πŸ‘§ Contactpersonen β”‚ -β”‚ ───────────────────────────────────────────────────────── β”‚ -β”‚ Partner: Marie de Vries (06-12345678) β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Wat wil je doen met Jan? β”‚ -β”‚ [πŸ“ Notitie] [πŸ“‹ Rapport] [πŸ“Š Meting] [πŸ“„ Plan] [πŸ“ž Contact] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -#### 5.4.4 OverdrachtBlock - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ”„ Overdracht Ochtend β†’ Middag [βˆ’] [Γ—] β”‚ -β”‚ 07:00 - 15:00 | 8 patiΓ«nten β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β–Ό Jan de Vries ⚠️ Alert β”‚ -β”‚ ─────────────────────────────────────────────────────────── β”‚ -β”‚ Rustige ochtend. Medicatie uitgereikt zonder problemen. β”‚ -β”‚ Let op valrisico bij toiletbezoek - 2 incidenten deze week. β”‚ -β”‚ β”‚ -β”‚ πŸ“Ž Bronnen: 3 notities β€’ ✏️ Bewerken β”‚ -β”‚ β”‚ -β”‚ β–Ά Marie van den Berg β”‚ -β”‚ ─────────────────────────────────────────────────────────── β”‚ -β”‚ Klik om samenvatting te genereren β”‚ -β”‚ β”‚ -β”‚ β–Ά Piet Jansen βœ“ Geen bijzonderh. β”‚ -β”‚ β”‚ -β”‚ β–Ά Anna de Vries β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [πŸ“‹ Kopieer alles] [πŸ“€ E-mail] [βœ“ Afronden overdracht] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -### 5.5 P2 Blocks (MVP Week 3-4) - -#### 5.5.1 RapportageBlock - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“‹ Rapportage [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ PatiΓ«nt: Jan de Vries [Wijzig] β”‚ -β”‚ β”‚ -β”‚ Type β”‚ -β”‚ [Gesprek βœ“] [Evaluatie] [Telefonisch] [Consult] [Familie] β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [B] [I] [β€’] [1.] ["] 🎀 Dicteer β”‚ β”‚ -β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Gesprek gehad met Jan over zijn ontslagplanning. β”‚ β”‚ -β”‚ β”‚ Hij geeft aan zich beter te voelen en is gemotiveerd β”‚ β”‚ -β”‚ β”‚ om de CGT-sessies voort te zetten na ontslag. β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ AI-acties β”‚ -β”‚ [✨ Samenvatten] [πŸ“– B1-niveau] [πŸ” Problemen extraheren] β”‚ -β”‚ β”‚ -β”‚ [Annuleren] [πŸ’Ύ Opslaan] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -#### 5.5.2 AgendaBlock - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“… Agenda [βˆ’] [Γ—] β”‚ -β”‚ Vandaag, 23 december 2024 β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ [β—€ Gisteren] [Vandaag] [Morgen β–Ά] [Week] [Maand] β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 09:00 Jan de Vries β€’ CGT Sessie 4 β”‚ β”‚ -β”‚ β”‚ [Open dossier] [Notitie] β”‚ β”‚ -β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ -β”‚ β”‚ 10:00 Marie van den Berg β€’ Evaluatie β”‚ β”‚ -β”‚ β”‚ [Open dossier] [Notitie] β”‚ β”‚ -β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ -β”‚ β”‚ 11:00 --- PAUZE --- β”‚ β”‚ -β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ -β”‚ β”‚ 13:00 Piet Jansen β€’ Intake ⭐ Nieuw β”‚ β”‚ -β”‚ β”‚ [Open dossier] [Start intake] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [+ Nieuwe afspraak] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -#### 5.5.3 MetingenBlock - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“Š Meting invoeren [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ PatiΓ«nt: Jan de Vries [Wijzig] β”‚ -β”‚ β”‚ -β”‚ Type meting β”‚ -β”‚ [Bloeddruk βœ“] [Pols] [Temp] [Gewicht] [Glucose] [Saturatie] β”‚ -β”‚ β”‚ -β”‚ Waarde β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 135 β”‚ / β”‚ 85 β”‚ mmHg β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Vergelijking vorige (130/80): ↑ Licht verhoogd β”‚ -β”‚ β”‚ -β”‚ Tijdstip: [Nu: 14:35] [Aanpassen] β”‚ -β”‚ β”‚ -β”‚ Opmerking (optioneel) β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [Annuleren] [πŸ’Ύ Opslaan] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -### 5.6 P3 Blocks (Post-MVP) - -#### 5.6.1 IntakeWizard - -Multi-step wizard voor complete intake: - -``` -STAP 1: Basisgegevens -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“„ Nieuwe Intake Stap 1 van 7 β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β—‹ Basis ─ β—‹ Anamnese ─ β—‹ Onderzoek ─ β—‹ Diagnose ─ β”‚ -β”‚ β—‹ Risico ─ β—‹ Kindcheck ─ β—‹ Behandeladvies β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Voornaam * Achternaam * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Geboortedatum * BSN β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [Volgende β†’] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -STAP 2: Anamnese -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Voorgeschiedenis β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ [Rich text editor met dicteer optie] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Hulpvraag β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [✨ AI: Vat samen] [✨ AI: Extraheer problemen] β”‚ -β”‚ β”‚ -β”‚ [← Terug] [Volgende β†’] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -STAP 4: Diagnose (ICD-10) -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ AI-suggestie op basis van anamnese: β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ ✨ F32.1 Depressieve stoornis, matige episode β”‚ β”‚ -β”‚ β”‚ Confidence: 87% β”‚ β”‚ -β”‚ β”‚ Rationale: PatiΓ«nt beschrijft sombere stemming... β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [βœ“ Accepteren] [✏️ Aanpassen] [βœ• Negeren] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Of handmatig toevoegen: β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ” Zoek ICD-10 code of omschrijving... β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [← Terug] [Volgende β†’] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -STAP 5: Risicotaxatie -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ SuΓ―cidaliteit β”‚ -β”‚ [Geen βœ“] [Laag] [Matig] [Hoog] [Acuut] β”‚ -β”‚ β”‚ -β”‚ Automutilatie β”‚ -β”‚ [Geen βœ“] [Laag] [Matig] [Hoog] β”‚ -β”‚ β”‚ -β”‚ Agressie β”‚ -β”‚ [Geen βœ“] [Laag] [Matig] [Hoog] β”‚ -β”‚ β”‚ -β”‚ Valrisico β”‚ -β”‚ [Geen] [Laag βœ“] [Matig] [Hoog] β”‚ -β”‚ β”‚ -β”‚ Toelichting β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Valrisico ivm medicatie en leeftijd β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [← Terug] [Volgende β†’] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -STAP 6: Kindcheck -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Heeft patiΓ«nt minderjarige kinderen? β”‚ -β”‚ [Ja] [Nee βœ“] [Onbekend] β”‚ -β”‚ β”‚ -β”‚ (Indien ja: formulier voor kindgegevens en zorgen) β”‚ -β”‚ β”‚ -β”‚ [← Terug] [Volgende β†’] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -#### 5.6.2 RisicoBlock (Standalone) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ⚠️ Risicotaxatie β€” Jan de Vries [βˆ’] [Γ—] β”‚ -β”‚ Laatste update: 15 dec 2024 β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ SuΓ―cidaliteit β—‹ Geen β—‹ Laag ● Matig β—‹ Hoog β”‚ -β”‚ Automutilatie ● Geen β—‹ Laag β—‹ Matig β—‹ Hoog β”‚ -β”‚ Agressie naar anderen ● Geen β—‹ Laag β—‹ Matig β—‹ Hoog β”‚ -β”‚ Valrisico β—‹ Geen β—‹ Laag ● Matig β—‹ Hoog β”‚ -β”‚ Weglopen ● Geen β—‹ Laag β—‹ Matig β—‹ Hoog β”‚ -β”‚ β”‚ -β”‚ Toelichting β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Matig suΓ―ciderisico: passieve doodswens, geen plan. β”‚ β”‚ -β”‚ β”‚ Valrisico door medicatie (sedatie) + leeftijd. β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Veiligheidsafspraken β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β˜‘ Dagelijks check-in gesprek β”‚ β”‚ -β”‚ β”‚ β˜‘ Nachtcontroles om 02:00 en 05:00 β”‚ β”‚ -β”‚ β”‚ ☐ 1-op-1 begeleiding β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [Annuleren] [πŸ’Ύ Opslaan] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -#### 5.6.3 ContactenBlock - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ‘¨β€πŸ‘©β€πŸ‘§ Contactpersonen β€” Jan de Vries [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ‘€ Marie de Vries ⭐ Primair β”‚ β”‚ -β”‚ β”‚ Partner β”‚ β”‚ -β”‚ β”‚ πŸ“ž 06-12345678 β€’ βœ‰οΈ marie@email.nl β”‚ β”‚ -β”‚ β”‚ β˜‘ Mag info ontvangen β˜‘ Noodcontact β”‚ β”‚ -β”‚ β”‚ [Bewerken] [Bellen] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ‘€ Peter de Vries β”‚ β”‚ -β”‚ β”‚ Zoon β”‚ β”‚ -β”‚ β”‚ πŸ“ž 06-98765432 β”‚ β”‚ -β”‚ β”‚ β˜‘ Mag info ontvangen ☐ Noodcontact β”‚ β”‚ -β”‚ β”‚ [Bewerken] [Bellen] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ [+ Contact toevoegen] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -### 5.7 Systeem Blocks - -#### 5.7.1 HelpBlock - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ’‘ Wat kan ik voor je doen? [βˆ’] [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Meest gebruikt β”‚ -β”‚ ───────────────────────────────────────────────────────── β”‚ -β”‚ πŸ“ "notitie jan medicatie" β†’ Dagnotitie maken β”‚ -β”‚ πŸ” "zoek marie" β†’ PatiΓ«nt zoeken β”‚ -β”‚ πŸ”„ "overdracht" β†’ Dienst overdracht β”‚ -β”‚ β”‚ -β”‚ Rapportage β”‚ -β”‚ ───────────────────────────────────────────────────────── β”‚ -β”‚ πŸ“‹ "rapportage" β†’ Behandelrapportage β”‚ -β”‚ πŸ“Š "bloeddruk jan" β†’ Meting invoeren β”‚ -β”‚ β”‚ -β”‚ Informatie bekijken β”‚ -β”‚ ───────────────────────────────────────────────────────── β”‚ -β”‚ πŸ‘€ "info jan" / "dossier jan" β†’ PatiΓ«nt context β”‚ -β”‚ πŸ“… "agenda" β†’ Afspraken vandaag β”‚ -β”‚ πŸ“„ "behandelplan jan" β†’ Behandelplan bekijken β”‚ -β”‚ β”‚ -β”‚ Intake & Behandeling β”‚ -β”‚ ───────────────────────────────────────────────────────── β”‚ -β”‚ πŸ“„ "nieuwe intake" β†’ Intake wizard starten β”‚ -β”‚ ⚠️ "risico jan" β†’ Risicotaxatie β”‚ -β”‚ πŸ₯ "diagnose jan" β†’ Diagnose bekijken β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -#### 5.7.2 FallbackPicker - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Wat wil je doen? β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Meest gebruikt β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ“ β”‚ β”‚ πŸ” β”‚ β”‚ πŸ”„ β”‚ β”‚ πŸ“‹ β”‚ β”‚ -β”‚ β”‚ Notitie β”‚ β”‚ Zoeken β”‚ β”‚Overdracht β”‚ Rapport β”‚ β”‚ -β”‚ β”‚ [1] β”‚ β”‚ [2] β”‚ β”‚ [3] β”‚ β”‚ [4] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ Meer opties β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ“… β”‚ β”‚ πŸ“Š β”‚ β”‚ πŸ‘€ β”‚ β”‚ πŸ“„ β”‚ β”‚ -β”‚ β”‚ Agenda β”‚ β”‚ Meting β”‚ β”‚ Dossier β”‚ β”‚ Intake β”‚ β”‚ -β”‚ β”‚ [5] β”‚ β”‚ [6] β”‚ β”‚ [7] β”‚ β”‚ [8] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ ⚠️ β”‚ β”‚ πŸ’‘ β”‚ β”‚ -β”‚ β”‚ Risico β”‚ β”‚ Help β”‚ β”‚ -β”‚ β”‚ [9] β”‚ β”‚ [0] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 6. Interaction Flows - -### 6.1 Happy Path: Dagnotitie (15 seconden) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 1. Verpleegkundige spreekt/typt: β”‚ -β”‚ "Jan de Vries heeft zijn medicatie ingenomen" β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 2. Intent engine herkent: β”‚ -β”‚ intent: dagnotitie (0.94) β”‚ -β”‚ patient: "Jan de Vries" β†’ match found β”‚ -β”‚ category: "medicatie" (keyword) β”‚ -β”‚ content: "heeft zijn medicatie ingenomen" β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 3. DagnotatieBlock verschijnt met pre-fill: β”‚ -β”‚ βœ“ Patient: Jan de Vries [highlighted] β”‚ -β”‚ βœ“ Category: Medicatie [highlighted] β”‚ -β”‚ βœ“ Text: "heeft zijn medicatie ingenomen" [highlighted] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 4. Verpleegkundige review β†’ klikt Opslaan β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 5. Toast: "βœ“ Notitie opgeslagen" β”‚ -β”‚ Block verdwijnt β”‚ -β”‚ Recent strip: [πŸ“ Jan-Med] badge β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ TOTAAL: ~15 seconden (was: 3-5 minuten) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 6.2 Overdracht Flow (Proactief) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 1. Klok: 14:30 (dienst eindigt 15:00) β”‚ -β”‚ β†’ shiftEndingSoon = true β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 2. Suggestie banner: β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ• Dienst eindigt over 30 min. Overdracht maken? β”‚ β”‚ -β”‚ β”‚ [Ja] [Later] [Γ—] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 3. Klikt "Ja" β†’ OverdrachtBlock opent β”‚ -β”‚ β†’ AI genereert samenvattingen per patiΓ«nt β”‚ -β”‚ β†’ Bronverwijzingen naar originele notities β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 4. Review, eventueel aanpassen β†’ Afronden β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ TOTAAL: ~5 minuten (was: 20-30 minuten) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 7. Data Dependencies - -### 7.1 Database Tabellen per Block - -| Block | Leest van | Schrijft naar | -|-------|-----------|---------------| -| DagnotatieBlock | `patients` | `reports` | -| ZoekenBlock | `patients`, `conditions`, `encounters` | - | -| PatientContextCard | `patients`, `reports`, `vitals`, `conditions`, `care_plans`, `risk_assessments`, `contacts` | - | -| OverdrachtBlock | `patients`, `reports`, `vitals`, `risk_assessments` | - (AI generated) | -| RapportageBlock | `patients`, `intakes` | `reports` | -| AgendaBlock | `patients`, `appointments` | `appointments` | -| MetingenBlock | `patients`, `vitals` | `vitals` | -| IntakeWizard | `patients` | `intakes`, `anamneses`, `conditions`, `risk_assessments`, `contacts` | -| BehandelplanBlock | `patients`, `conditions`, `intakes` | `care_plans` | -| RisicoBlock | `patients`, `risk_assessments` | `risk_assessments` | -| ContactenBlock | `patients`, `contacts` | `contacts` | - -### 7.2 API Routes Nodig - -| Route | Method | Block | Status | -|-------|--------|-------|--------| -| `/api/patients/search` | GET | ZoekenBlock | βœ… Bestaat | -| `/api/reports` | POST | DagnotatieBlock, RapportageBlock | βœ… Bestaat | -| `/api/overdracht/generate` | POST | OverdrachtBlock | βœ… Bestaat | -| `/api/verpleegrapportage/[id]` | GET | PatientContextCard | βœ… Uitbreiden | -| `/api/intent/classify` | POST | Command Input | πŸ†• Nieuw | -| `/api/vitals` | GET, POST | MetingenBlock | πŸ†• Nieuw | -| `/api/appointments` | GET, POST | AgendaBlock | πŸ†• Nieuw | -| `/api/risk-assessments` | GET, POST | RisicoBlock | βœ… Bestaat | -| `/api/contacts` | GET, POST | ContactenBlock | πŸ†• Nieuw | - ---- - -## 8. Visual Design Tokens - -### 8.1 Colors - -| Token | Hex | Gebruik | -|-------|-----|---------| -| `--bg-app` | #F8FAFC | App achtergrond | -| `--bg-surface` | #FFFFFF | Blocks, cards | -| `--text-primary` | #0F172A | Hoofdtekst | -| `--text-secondary` | #475569 | Subtekst | -| `--border` | #E2E8F0 | Randen | -| `--brand` | #3B82F6 | Primaire acties | -| `--success` | #16A34A | Bevestigingen | -| `--warning` | #EAB308 | Waarschuwingen | -| `--error` | #DC2626 | Fouten, alerts | - -### 8.2 Category Colors - -| Categorie | Background | Accent | -|-----------|------------|--------| -| Medicatie | `#FEF6DC` | `#F59E0B` | -| ADL | `#E8F8EF` | `#16A34A` | -| Observatie | `#EFF6FF` | `#3B82F6` | -| Incident | `#FEF2F2` | `#DC2626` | -| Algemeen | `#F1F5F9` | `#64748B` | - ---- - -## 9. Keyboard Navigation - -| Key | Action | -|-----|--------| -| `⌘K` / `Ctrl+K` | Focus command input | -| `Escape` | Close active block | -| `Enter` | Submit / Select | -| `↑` `↓` | Navigate results / history | -| `1-9` | Quick select in FallbackPicker | -| `Space` (empty input) | Start voice | -| `⌘Enter` | Save (in forms) | - ---- - -## 10. Component Checklist - -### πŸ”΄ P1: MVP Week 1-2 - -- [ ] Context Bar -- [ ] Command Input (text + voice) -- [ ] Intent Classification Engine -- [ ] DagnotatieBlock -- [ ] ZoekenBlock -- [ ] PatientContextCard -- [ ] OverdrachtBlock -- [ ] FallbackPicker -- [ ] HelpBlock -- [ ] Recent Strip -- [ ] Toast System - -### 🟑 P2: MVP Week 3-4 - -- [ ] RapportageBlock (+ dicteer) -- [ ] AgendaBlock -- [ ] MetingenBlock -- [ ] PatiΓ«ntenlijstBlock -- [ ] Proactive Suggestions (dienst einde) - -### 🟒 P3: Post-MVP Sprint 3-4 - -- [ ] IntakeWizard (7 stappen) -- [ ] BehandelplanBlock -- [ ] DiagnoseBlock -- [ ] RisicoBlock -- [ ] AnamneseBlock -- [ ] ContactenBlock -- [ ] KindcheckBlock -- [ ] ROMBlock - -### βšͺ P4: Backlog - -- [ ] MedicatieBlock -- [ ] DecursusBlock -- [ ] AfspraakBlock -- [ ] NieuwePatiΓ«ntBlock - ---- - -## 11. Summary: De Transformatie - -``` -VAN: NAAR: -──────────────────────────────────────────────────────────────── - -47 menu-items β†’ 1 input veld -200 pagina handleiding β†’ 0 training nodig -12 klikken per notitie β†’ 1 zin -3 maanden onboarding β†’ Direct productief -"Waar moet ik zijn?" β†’ "Wat wil je doen?" -Navigeren door systeem β†’ Praten tegen systeem -Alles altijd zichtbaar β†’ Alleen wat nu nodig is -Gebruiker zoekt informatie β†’ Systeem toont informatie - -TIJDSBESPARING: -───────────────────────────────────────────────────────────────── -Dagnotitie: 3-5 min β†’ 15 sec (95% sneller) -Overdracht: 20-30 min β†’ 5 min (80% sneller) -PatiΓ«nt zoeken: 1-2 min β†’ 5 sec (95% sneller) -Rapportage: 8-15 min β†’ 2-3 min (75% sneller) - -Per verpleegkundige per dag: ~4 uur terug naar zorg -Per afdeling (10 FTE) per jaar: 1000+ uur extra patiΓ«ntcontact -``` - ---- - -## Wijzigingslog - -| Versie | Datum | Wijzigingen | -|--------|-------|-------------| -| 1.0 | 23-12-2024 | InitiΓ«le versie met sidebar | -| 2.0 | 23-12-2024 | Herschreven: pure Ephemeral UI | -| 2.1 | 23-12-2024 | Toegevoegd: prioriteitenlijst, complete intent mapping, P3 blocks (intake, risico, contacten, etc.), data dependencies, frequentie matrix | \ No newline at end of file diff --git a/docs/swift/archive/taken-en-vragen-analyse.md b/docs/swift/archive/taken-en-vragen-analyse.md deleted file mode 100644 index e548404..0000000 --- a/docs/swift/archive/taken-en-vragen-analyse.md +++ /dev/null @@ -1,486 +0,0 @@ -# Taken & Vragen Analyse: EPD Functionaliteit - -**Document:** Wat moet de nieuwe UI kunnen? -**Datum:** december 2024 -**Doel:** Inventarisatie van alle taken en vragen die het EPD beantwoordt - ---- - -## 1. Overzicht Huidige EPD Modules - -Op basis van de codebase analyse: - -``` -/epd -β”œβ”€β”€ dashboard/ # Overzicht -β”œβ”€β”€ patients/ # PatiΓ«ntbeheer -β”‚ β”œβ”€β”€ [id]/ -β”‚ β”‚ β”œβ”€β”€ basisgegevens/ # NAW, contactgegevens -β”‚ β”‚ β”œβ”€β”€ intakes/ # Intake trajecten -β”‚ β”‚ β”‚ └── [intakeId]/ -β”‚ β”‚ β”‚ β”œβ”€β”€ anamnese/ # Voorgeschiedenis -β”‚ β”‚ β”‚ β”œβ”€β”€ examination/ # Onderzoek -β”‚ β”‚ β”‚ β”œβ”€β”€ diagnosis/ # Diagnose (ICD-10) -β”‚ β”‚ β”‚ β”œβ”€β”€ risk/ # Risicotaxatie -β”‚ β”‚ β”‚ β”œβ”€β”€ kindcheck/ # Kindcheck -β”‚ β”‚ β”‚ β”œβ”€β”€ contacts/ # Contactpersonen -β”‚ β”‚ β”‚ β”œβ”€β”€ behandeladvies/# Behandeladvies -β”‚ β”‚ β”‚ └── rom/ # ROM vragenlijsten -β”‚ β”‚ β”œβ”€β”€ diagnose/ # Diagnosebeheer -β”‚ β”‚ β”œβ”€β”€ behandelplan/ # Behandelplan -β”‚ β”‚ β”œβ”€β”€ rapportage/ # Rapportages -β”‚ β”‚ └── screening/ # Screening -β”œβ”€β”€ verpleegrapportage/ # Verpleegkundig overzicht -β”‚ β”œβ”€β”€ overdracht/ # Overdrachtsrapportage -β”‚ └── rapportage/ # Dagrapportage per patiΓ«nt -β”œβ”€β”€ agenda/ # Afspraken -β”œβ”€β”€ clients/ # Client overzicht -└── reports/ # Rapportages overzicht -``` - ---- - -## 2. CategorieΓ«n van Vragen - -### 2.1 ZOEKEN & VINDEN (Wie/Wat/Waar) - -| Vraag | Huidige UI | Data | -|-------|------------|------| -| Wie is [naam]? | patients/ β†’ zoeken | patients | -| Waar is [patiΓ«nt] opgenomen? | patients/[id] | encounters | -| Welke diagnoses heeft [patiΓ«nt]? | patients/[id]/diagnose | conditions | -| Wat is het behandelplan van [patiΓ«nt]? | patients/[id]/behandelplan | care_plans | -| Welke medicatie gebruikt [patiΓ«nt]? | - (nog niet) | - | -| Wie zijn de contactpersonen van [patiΓ«nt]? | intakes/[id]/contacts | contacts | -| Wat is de risicoscore van [patiΓ«nt]? | intakes/[id]/risk | risk_assessments | - -### 2.2 RAPPORTEREN & DOCUMENTEREN (Vastleggen) - -| Taak | Huidige UI | Data | -|------|------------|------| -| Dagnotitie maken | verpleegrapportage/rapportage | reports (type: verpleegkundig) | -| Rapportage schrijven | patients/[id]/rapportage | reports | -| Intake vastleggen | patients/[id]/intakes/new | intakes | -| Anamnese invullen | intakes/[id]/anamnese | anamneses | -| Onderzoek documenteren | intakes/[id]/examination | examinations | -| Diagnose toevoegen | patients/[id]/diagnose | conditions | -| Behandeladvies schrijven | intakes/[id]/behandeladvies | - | -| Risicotaxatie invullen | intakes/[id]/risk | risk_assessments | -| Kindcheck uitvoeren | intakes/[id]/kindcheck | - | - -### 2.3 SAMENVATTEN & OVERDRAGEN (Communiceren) - -| Taak | Huidige UI | Data | -|------|------------|------| -| Overdracht maken | verpleegrapportage/overdracht | AI samenvatting | -| Samenvatting van vandaag | - | reports (shift_date) | -| Wat is er gebeurd met [patiΓ«nt]? | verpleegrapportage/rapportage | reports, vitals | -| Aandachtspunten voor collega | overdracht | include_in_handover | - -### 2.4 PLANNEN & ORGANISEREN (Agenda) - -| Taak | Huidige UI | Data | -|------|------------|------| -| Mijn afspraken vandaag | agenda/ | appointments | -| Afspraken van [patiΓ«nt] | - | appointments | -| Afspraak inplannen | agenda/ (FullCalendar) | appointments | -| Wie zie ik deze week? | agenda/ | appointments | - -### 2.5 BEHANDELEN & VOLGEN (Zorgpad) - -| Taak | Huidige UI | Data | -|------|------------|------| -| Behandelplan opstellen | patients/[id]/behandelplan | care_plans | -| Doelen formuleren | behandelplan | care_plans.goals | -| Voortgang evalueren | - | - | -| ROM afnemen | intakes/[id]/rom | - | - ---- - -## 3. Frequentie & Prioriteit Matrix - -### 3.1 Hoogfrequent (meerdere keren per dag) - -| Taak | Freq/dag | Huidige klikken | Ephemeral target | -|------|----------|-----------------|------------------| -| **Dagnotitie maken** | 10-20x | 5-8 | 1 zin | -| **PatiΓ«nt zoeken** | 15-20x | 3-5 | 1 zin | -| **Laatste notities bekijken** | 10-15x | 4-6 | 1 zin | -| **Overdracht maken** | 2-3x | 8-12 | 1 zin | - -### 3.2 Middenfrequent (dagelijks) - -| Taak | Freq/dag | Huidige klikken | Ephemeral target | -|------|----------|-----------------|------------------| -| **Rapportage schrijven** | 3-5x | 6-10 | 1 zin + dicteren | -| **Diagnose bekijken** | 3-5x | 4-6 | 1 zin | -| **Behandelplan raadplegen** | 2-3x | 4-6 | 1 zin | -| **Afspraken bekijken** | 2-3x | 3-4 | 1 zin | - -### 3.3 Laagfrequent (wekelijks/maandelijks) - -| Taak | Frequentie | Huidige klikken | Ephemeral target | -|------|------------|-----------------|------------------| -| **Intake starten** | 1x/week | 10-15 | Wizard | -| **Behandelplan maken** | 1x/maand | 15-20 | Wizard + AI | -| **Diagnose toevoegen** | 1x/week | 6-8 | 1 zin | -| **Risicotaxatie** | 1x/maand | 10-15 | Wizard | - ---- - -## 4. Mapping naar Ephemeral UI Bouwblokken - -### 4.1 Must Have (MVP) - -| Bouwblok | Beantwoordt vragen | Prioriteit | -|----------|-------------------|------------| -| **Dagnotitie** | "notitie voor jan: medicatie gegeven" | P1 | -| **Zoeken** | "wie is jan", "zoek marie" | P1 | -| **Overdracht** | "overdracht maken", "samenvatting dienst" | P1 | - -### 4.2 Should Have - -| Bouwblok | Beantwoordt vragen | Prioriteit | -|----------|-------------------|------------| -| **Rapportage** | "gesprek gehad met jan", "rapportage maken" | P2 | -| **PatiΓ«nt Info** | "diagnoses van jan", "behandelplan jan" | P2 | -| **Agenda** | "mijn afspraken", "wanneer zie ik jan" | P2 | - -### 4.3 Could Have - -| Bouwblok | Beantwoordt vragen | Prioriteit | -|----------|-------------------|------------| -| **Behandelplan** | "plan opstellen voor jan" | P3 | -| **Diagnose** | "diagnose toevoegen: F41.1" | P3 | -| **Risico** | "risicotaxatie jan" | P3 | -| **Intake** | "nieuwe intake starten" | P3 | - ---- - -## 5. Intent Classificatie Mapping - -### 5.1 Schrijf-intents (Writer) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ INTENT: dagnotitie β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Trigger patterns: β”‚ -β”‚ β€’ "notitie [patient]" β”‚ -β”‚ β€’ "dagnotitie" β”‚ -β”‚ β€’ "[patient] medicatie gegeven" β”‚ -β”‚ β€’ "[patient] heeft gegeten" β”‚ -β”‚ β€’ "incident bij [patient]" β”‚ -β”‚ β”‚ -β”‚ Entities: β”‚ -β”‚ β€’ patient_name: string β”‚ -β”‚ β€’ category: medicatie|adl|gedrag|incident|observatie β”‚ -β”‚ β€’ content: string (optioneel) β”‚ -β”‚ β”‚ -β”‚ Pre-fill: β”‚ -β”‚ β€’ Patient selector β”‚ -β”‚ β€’ Category dropdown β”‚ -β”‚ β€’ Tekstveld β”‚ -β”‚ β€’ include_in_handover checkbox β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ INTENT: rapportage β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Trigger patterns: β”‚ -β”‚ β€’ "rapportage [patient]" β”‚ -β”‚ β€’ "gesprek gehad met [patient]" β”‚ -β”‚ β€’ "verslag maken" β”‚ -β”‚ β€’ "sessie met [patient]" β”‚ -β”‚ β”‚ -β”‚ Entities: β”‚ -β”‚ β€’ patient_name: string β”‚ -β”‚ β€’ report_type: voortgang|observatie|contact|crisis β”‚ -β”‚ β”‚ -β”‚ Pre-fill: β”‚ -β”‚ β€’ Patient selector β”‚ -β”‚ β€’ Type dropdown β”‚ -β”‚ β€’ Rich text editor β”‚ -β”‚ β€’ AI structureren knop β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ INTENT: diagnose_toevoegen β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Trigger patterns: β”‚ -β”‚ β€’ "diagnose [patient]: [code]" β”‚ -β”‚ β€’ "diagnose toevoegen" β”‚ -β”‚ β€’ "[patient] heeft [diagnose]" β”‚ -β”‚ β”‚ -β”‚ Entities: β”‚ -β”‚ β€’ patient_name: string β”‚ -β”‚ β€’ icd10_code: string (optioneel) β”‚ -β”‚ β€’ diagnosis_text: string (optioneel) β”‚ -β”‚ β”‚ -β”‚ Pre-fill: β”‚ -β”‚ β€’ Patient selector β”‚ -β”‚ β€’ ICD-10 zoeken combobox β”‚ -β”‚ β€’ Clinical status β”‚ -β”‚ β€’ Severity β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 5.2 Lees-intents (Reader) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ INTENT: zoeken β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Trigger patterns: β”‚ -β”‚ β€’ "zoek [naam]" β”‚ -β”‚ β€’ "wie is [naam]" β”‚ -β”‚ β€’ "vind [naam]" β”‚ -β”‚ β€’ "[naam]" (als geen andere intent matcht) β”‚ -β”‚ β”‚ -β”‚ Entities: β”‚ -β”‚ β€’ search_query: string β”‚ -β”‚ β”‚ -β”‚ Output: β”‚ -β”‚ β€’ PatientCards met quick actions β”‚ -β”‚ β€’ Selectie β†’ set active patient β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ INTENT: patient_info β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Trigger patterns: β”‚ -β”‚ β€’ "diagnoses van [patient]" β”‚ -β”‚ β€’ "behandelplan [patient]" β”‚ -β”‚ β€’ "info [patient]" β”‚ -β”‚ β€’ "dossier [patient]" β”‚ -β”‚ β€’ "risico's [patient]" β”‚ -β”‚ β”‚ -β”‚ Entities: β”‚ -β”‚ β€’ patient_name: string β”‚ -β”‚ β€’ info_type: diagnoses|behandelplan|risico|alles β”‚ -β”‚ β”‚ -β”‚ Output: β”‚ -β”‚ β€’ Collapsible info cards β”‚ -β”‚ β€’ Quick actions (bewerken, toevoegen) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ INTENT: overdracht β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Trigger patterns: β”‚ -β”‚ β€’ "overdracht" β”‚ -β”‚ β€’ "overdracht maken" β”‚ -β”‚ β€’ "samenvatting dienst" β”‚ -β”‚ β€’ "wat is er gebeurd vandaag" β”‚ -β”‚ β”‚ -β”‚ Entities: β”‚ -β”‚ β€’ time_range: afgelopen 8 uur (default) β”‚ -β”‚ β€’ patient_filter: string[] (optioneel) β”‚ -β”‚ β”‚ -β”‚ Output: β”‚ -β”‚ β€’ AI-samenvatting per patiΓ«nt β”‚ -β”‚ β€’ Bronverwijzingen β”‚ -β”‚ β€’ Aandachtspunten β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ INTENT: agenda β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Trigger patterns: β”‚ -β”‚ β€’ "mijn afspraken" β”‚ -β”‚ β€’ "afspraken vandaag" β”‚ -β”‚ β€’ "wanneer zie ik [patient]" β”‚ -β”‚ β€’ "planning deze week" β”‚ -β”‚ β”‚ -β”‚ Entities: β”‚ -β”‚ β€’ date_range: vandaag|deze week|datum β”‚ -β”‚ β€’ patient_name: string (optioneel) β”‚ -β”‚ β”‚ -β”‚ Output: β”‚ -β”‚ β€’ Afsprakenlijst β”‚ -β”‚ β€’ Quick action: nieuwe afspraak β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 6. Data Requirements per Intent - -### 6.1 Database Tabellen per Bouwblok - -| Bouwblok | Read | Write | -|----------|------|-------| -| **Dagnotitie** | patients | reports | -| **Zoeken** | patients, conditions, care_plans | - | -| **Rapportage** | patients, intakes | reports | -| **Overdracht** | patients, reports, vitals, risk_assessments | - | -| **Patient Info** | patients, conditions, care_plans, risk_assessments | - | -| **Diagnose** | patients, conditions | conditions | -| **Agenda** | patients, appointments, practitioners | appointments | -| **Behandelplan** | patients, conditions, intakes, anamneses | care_plans | - -### 6.2 API Routes per Bouwblok - -| Bouwblok | Bestaande API | Nieuw nodig? | -|----------|---------------|--------------| -| **Dagnotitie** | POST /api/reports | Nee | -| **Zoeken** | GET /api/patients/search | Ja (fuzzy) | -| **Rapportage** | POST /api/reports | Nee | -| **Overdracht** | GET /api/overdracht, POST /api/overdracht/generate | Nee | -| **Patient Info** | GET /api/verpleegrapportage/[patientId] | Uitbreiden | -| **Diagnose** | - | Ja | -| **Agenda** | - | Ja | -| **Behandelplan** | POST /api/behandelplan/generate | Nee | - ---- - -## 7. Contextual Awareness - -### 7.1 Impliciete Context - -| Context | Bron | Gebruik | -|---------|------|---------| -| **Huidige gebruiker** | Auth session | Filter "mijn patiΓ«nten" | -| **Huidige dienst** | Tijd (ochtend/middag/avond/nacht) | Shift-based filtering | -| **Laatst bekeken patiΓ«nt** | Session state | Pre-fill suggestie | -| **Recente acties** | Session state | Quick access | - -### 7.2 Expliciete Context - -| Context | Trigger | Effect | -|---------|---------|--------| -| **Actieve patiΓ«nt** | Zoeken + selecteren | Pre-fill alle volgende acties | -| **Dienst overdracht** | "overdracht" | Filter op afgelopen X uur | -| **Specifieke datum** | "afspraken morgen" | Filter op datum | - ---- - -## 8. Voice Command Examples - -### 8.1 Dagnotitie Flow - -``` -Voice: "Jan de Vries heeft zijn medicatie ingenomen, geen bijzonderheden" - -Intent: dagnotitie -Entities: - - patient_name: "Jan de Vries" - - category: "medicatie" (extracted from "medicatie ingenomen") - - content: "heeft zijn medicatie ingenomen, geen bijzonderheden" - -Pre-fill: - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ πŸ“ Dagnotitie voor Jan de Vries β”‚ - β”‚ ───────────────────────────────────────────────────────── β”‚ - β”‚ Categorie: [Medicatie β–Ό] ← auto-selected β”‚ - β”‚ Tijd: [14:32] β”‚ - β”‚ β”‚ - β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ - β”‚ β”‚ heeft zijn medicatie ingenomen, geen bijzonderheden β”‚ β”‚ - β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ - β”‚ β”‚ - β”‚ β˜‘ Opnemen in overdracht β”‚ - β”‚ β”‚ - β”‚ [Opslaan] β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 8.2 Zoeken Flow - -``` -Voice: "Zoek Marie" - -Intent: zoeken -Entities: - - search_query: "Marie" - -Output: - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ πŸ” Zoekresultaten voor "Marie" β”‚ - β”‚ ───────────────────────────────────────────────────────── β”‚ - β”‚ β”‚ - β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ - β”‚ β”‚ Marie van den Berg β”‚ β”‚ - β”‚ β”‚ 15-03-1985 Β· Kamer 12 Β· F41.1 Gegeneraliseerde angstβ”‚ β”‚ - β”‚ β”‚ [Notitie] [Dossier] [Rapportage] β”‚ β”‚ - β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ - β”‚ β”‚ - β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ - β”‚ β”‚ Marie Jansen β”‚ β”‚ - β”‚ β”‚ 22-08-1972 Β· Kamer 8 Β· F32.1 Depressieve episode β”‚ β”‚ - β”‚ β”‚ [Notitie] [Dossier] [Rapportage] β”‚ β”‚ - β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ - β”‚ β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 8.3 Overdracht Flow - -``` -Voice: "Overdracht maken" - -Intent: overdracht -Entities: - - time_range: "afgelopen 8 uur" (default) - -Output: - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ πŸ”„ Overdracht Ochtend dienst β”‚ - β”‚ ───────────────────────────────────────────────────────── β”‚ - β”‚ 06:00 - 14:00 Β· 5 patiΓ«nten met updates β”‚ - β”‚ β”‚ - β”‚ β–Ό Jan de Vries (3 notities) β”‚ - β”‚ ⚠ Aandachtspunt: onrustig vannacht β”‚ - β”‚ β€’ 07:30 Medicatie uitgereikt βœ“ β”‚ - β”‚ β€’ 08:45 Ontbijt genuttigd β”‚ - β”‚ β€’ 11:00 Gesprek met psycholoog β”‚ - β”‚ β”‚ - β”‚ β–Ό Marie van den Berg (2 notities) β”‚ - β”‚ β€’ 08:00 ADL ondersteuning β”‚ - β”‚ β€’ 10:30 Bezoek familie β”‚ - β”‚ β”‚ - β”‚ ─────────────────────────────────────────────────────── β”‚ - β”‚ AI Samenvatting: β”‚ - β”‚ "Rustige ochtend. Aandacht voor Jan de Vries die β”‚ - β”‚ vannacht onrustig was. Marie ontving familiebezoek..." β”‚ - β”‚ β”‚ - β”‚ [KopiΓ«ren] [Printen] [Doorsturen] β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 9. Conclusie: Minimale Intent Set - -### 9.1 MVP (6 intents) - -| Intent | Type | Frequentie | Complexiteit | -|--------|------|------------|--------------| -| `dagnotitie` | Writer | Zeer hoog | Laag | -| `zoeken` | Reader | Zeer hoog | Laag | -| `overdracht` | Reader | Hoog | Medium | -| `rapportage` | Writer | Hoog | Medium | -| `patient_info` | Reader | Hoog | Laag | -| `agenda` | Reader | Medium | Laag | - -### 9.2 Fallback - -| Intent | Actie | -|--------|-------| -| `onbekend` | Toon blok-picker met 6 opties | -| `ambigue` | "Bedoelde je...?" met opties | -| `lage_confidence` | Toon blok-picker | - -### 9.3 Training Data Nodig - -Per intent minimaal 20-30 voorbeeldzinnen in het Nederlands, inclusief: -- Formele vorm ("Ik wil een notitie maken") -- Informele vorm ("notitie jan") -- Met context ("jan medicatie") -- Zonder context ("notitie maken") -- Met typo's ("noitie jan") -- Voice transcriptie varianten - ---- - -*Dit document dient als basis voor de intent classificatie en UI bouwblokken.* diff --git a/docs/swift/archive/test-plan-e5-s2-error-handling.md b/docs/swift/archive/test-plan-e5-s2-error-handling.md deleted file mode 100644 index 6ee453a..0000000 --- a/docs/swift/archive/test-plan-e5-s2-error-handling.md +++ /dev/null @@ -1,232 +0,0 @@ -# Test Plan E5.S2 - Error Handling - -**Datum:** 27-12-2024 -**Status:** Ready for Testing -**Story:** E5.S2 - Error handling (2 SP) - ---- - -## βœ… Implementatie Overzicht - -### Nieuwe bestanden: -1. **`lib/swift/error-handler.ts`** - Error handling utility met: - - `isOffline()` - Detect browser offline status - - `isNetworkError()` - Network error detection - - `isTimeoutError()` - Timeout detection - - `parseErrorResponse()` - Parse HTTP error responses - - `getErrorInfo()` - Generate user-friendly error messages - - `safeFetch()` - Fetch wrapper met timeout (30s) - - `retryFetch()` - Retry logic met exponential backoff - -2. **`components/swift/command-center/offline-banner.tsx`** - Offline banner component - - Toont amber banner bij `!navigator.onLine` - - `useOffline()` hook voor offline detection - -### GeΓΌpdatete bestanden: -1. **`components/swift/command-center/command-center.tsx`** - OfflineBanner geΓ―ntegreerd -2. **`components/swift/command-center/command-input.tsx`** - Error handling met safeFetch/getErrorInfo -3. **`components/swift/command-center/context-bar.tsx`** - useOffline hook voor margin adjustment -4. **`components/swift/blocks/dagnotitie-block.tsx`** - safeFetch, getErrorInfo, retryFetch -5. **`components/swift/blocks/zoeken-block.tsx`** - safeFetch, getErrorInfo -6. **`components/swift/blocks/overdracht-block.tsx`** - safeFetch, getErrorInfo, retryFetch - ---- - -## πŸ§ͺ Test Scenarios - -### 1. Offline Detection βœ… - -**Test 1.1: Browser Offline** -- [ ] Open DevTools β†’ Network tab β†’ Throttling β†’ Offline -- [ ] Amber banner verschijnt bovenaan: "Geen internetverbinding" -- [ ] Context bar heeft `marginTop: 40px` (geen overlap) -- [ ] Try een actie (dagnotitie opslaan, patient zoeken) -- [ ] Toast shows: "Geen internetverbinding - Controleer je internetverbinding en probeer het opnieuw." - -**Test 1.2: Reconnect** -- [ ] Zet network weer op "Online" -- [ ] Banner verdwijnt automatisch -- [ ] Context bar margin reset -- [ ] Acties werken weer normaal - ---- - -### 2. Network Errors - -**Test 2.1: API Endpoint Down** -- [ ] Stop de dev server (kill process) -- [ ] Probeer dagnotitie opslaan -- [ ] Toast shows: "Verbinding verbroken - Kon geen verbinding maken met de server." -- [ ] Retry button beschikbaar (voor retryable errors) - -**Test 2.2: Timeout (30s)** -- [ ] Simuleer slow API (add `await new Promise(r => setTimeout(r, 35000))` in API route) -- [ ] Probeer actie -- [ ] Na 30 seconden: Toast shows "Verbinding timeout" - ---- - -### 3. HTTP Status Codes - -**Test 3.1: 401 Unauthorized** -- [ ] Simuleer 401 in API route: `return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })` -- [ ] Toast shows: "Niet geautoriseerd - Je sessie is verlopen. Log opnieuw in." -- [ ] `retryable: false` (geen retry button) - -**Test 3.2: 404 Not Found** -- [ ] Probeer non-existent patient ID: `/api/fhir/Patient/99999999` -- [ ] Toast shows: "Niet gevonden - PatiΓ«nt data ophalen niet gevonden." - -**Test 3.3: 400 Bad Request** -- [ ] Submit dagnotitie zonder required fields -- [ ] Toast shows: "Ongeldige aanvraag - [validation message]" - -**Test 3.4: 500 Internal Server Error** -- [ ] Simuleer server error in API route: `throw new Error('DB error')` -- [ ] Toast shows: "Serverfout - Er ging iets mis op de server. Probeer het later opnieuw." -- [ ] `retryable: true` - -**Test 3.5: 429 Too Many Requests** -- [ ] (Moeilijk te simuleren zonder rate limiter) -- [ ] Toast should show: "Te veel aanvragen - Wacht even en probeer het later opnieuw." - ---- - -### 4. Validation Errors - -**Test 4.1: Empty Fields in DagnotatieBlock** -- [ ] Open dagnotitie block -- [ ] Klik "Opslaan" zonder patiΓ«nt -- [ ] Toast shows: "Validatiefout - Selecteer een patiΓ«nt" -- [ ] Klik "Opslaan" zonder categorie -- [ ] Toast shows: "Validatiefout - Selecteer een categorie" -- [ ] Klik "Opslaan" zonder tekst -- [ ] Toast shows: "Validatiefout - Voer een notitie in" - -**Test 4.2: Search Query Too Short** -- [ ] Type "j" in ZoekenBlock (< 2 characters) -- [ ] Geen API call (debounced + min length check) - ---- - -### 5. Intent Classification Errors - -**Test 5.1: API Error** -- [ ] Typ commando in command input -- [ ] Simuleer API error in `/api/intent/classify` -- [ ] Toast shows error message -- [ ] FallbackPicker opent automatisch met original input -- [ ] Input is niet verloren (preserved in FallbackPicker) - -**Test 5.2: Low Confidence** -- [ ] Typ gibberish: "asdfasdf jkljkl" -- [ ] Confidence < 0.5 -- [ ] FallbackPicker opent met original input -- [ ] Can select fallback action (dagnotitie, zoeken, overdracht) - ---- - -### 6. Retry Logic - -**Test 6.1: Retry Success on 2nd Attempt** -- [ ] Simuleer intermittent error (fails first, succeeds second) -- [ ] DagnotatieBlock save with `retryFetch()` -- [ ] Should retry automatically (max 3 attempts) -- [ ] Success toast after retry succeeds - -**Test 6.2: Retry Exhausted (3 failures)** -- [ ] Simuleer consistent error (always fails) -- [ ] After 3 retries: Final error toast shown -- [ ] No infinite retry loop - ---- - -### 7. User-Friendly Messages (Dutch) - -**Test 7.1: All Error Messages in Dutch** -- [ ] Check all toast messages are in Dutch -- [ ] Check all error titles are in Dutch -- [ ] No English fallback messages visible to user - -**Test 7.2: Error Message Quality** -- [ ] Messages are actionable ("Controleer je internetverbinding") -- [ ] Not technical jargon ("fetch failed" β†’ "Verbinding verbroken") -- [ ] Clear next steps when applicable - ---- - -### 8. Edge Cases - -**Test 8.1: HTML Error Response (Auth Redirect)** -- [ ] Simulate HTML response (login page redirect) -- [ ] `parseErrorResponse()` detects HTML -- [ ] Toast shows: "Niet geautoriseerd. Log opnieuw in." - -**Test 8.2: Malformed JSON Response** -- [ ] Simulate invalid JSON from API -- [ ] Error handled gracefully (no crash) -- [ ] User-friendly error shown - -**Test 8.3: Error During Voice Input** -- [ ] Start voice recording -- [ ] Trigger error (offline, etc.) -- [ ] Voice recording stops gracefully -- [ ] Error shown to user - ---- - -## βœ… Implementation Checklist - -- [x] `lib/swift/error-handler.ts` created with all utilities -- [x] `components/swift/command-center/offline-banner.tsx` created -- [x] OfflineBanner integrated in CommandCenter -- [x] CommandInput uses safeFetch + getErrorInfo -- [x] ContextBar uses useOffline hook (margin adjustment) -- [x] DagnotatieBlock uses safeFetch + getErrorInfo + retryFetch -- [x] ZoekenBlock uses safeFetch + getErrorInfo -- [x] OverdrachtBlock uses safeFetch + getErrorInfo + retryFetch -- [x] All error messages in Dutch -- [x] FallbackPicker handles unknown intents gracefully -- [x] TypeScript compiles without errors - ---- - -## πŸ“‹ Manual Testing Checklist (Quick Smoke Test) - -Voor snelle verificatie: - -1. **Offline Mode:** - - [ ] DevTools β†’ Offline β†’ Banner appears β†’ Try action β†’ Error toast - -2. **Network Error:** - - [ ] Stop server β†’ Try action β†’ Error toast with retry - -3. **Validation Error:** - - [ ] Submit empty dagnotitie β†’ Validation toast - -4. **Intent Error:** - - [ ] Type gibberish β†’ FallbackPicker opens - -5. **Success Path:** - - [ ] Online β†’ Submit dagnotitie β†’ Success toast β†’ Block closes - ---- - -## 🎯 Acceptatie Criteria E5.S2 - -- [x] Network errors tonen user-friendly messages (Dutch) -- [x] Offline detection met visual indicator (banner) -- [x] Validation errors zijn duidelijk en actionable -- [x] Retry functionaliteit werkt voor transient errors -- [x] HTTP status codes mapped naar begrijpelijke messages -- [x] FallbackPicker shown on intent classification failure -- [x] No lost user input on errors (preserved in FallbackPicker) -- [x] All error scenarios from test-plan-epic3.md covered - ---- - -## πŸš€ Status - -**E5.S2 - Error Handling: COMPLETE βœ…** - -All error handling utilities implemented, integrated across all components, and ready for testing. diff --git a/docs/swift/archive/test-plan-e5-s3-keyboard-shortcuts.md b/docs/swift/archive/test-plan-e5-s3-keyboard-shortcuts.md deleted file mode 100644 index a43fa2c..0000000 --- a/docs/swift/archive/test-plan-e5-s3-keyboard-shortcuts.md +++ /dev/null @@ -1,245 +0,0 @@ -# Test Plan E5.S3 - Keyboard Shortcuts - -**Datum:** 27-12-2024 -**Status:** Ready for Testing -**Story:** E5.S3 - Keyboard shortcuts verificatie (2 SP) - ---- - -## βœ… Implementatie Overzicht - -### Bestaande Shortcuts (E1.S1, E4.S4) -1. **⌘K / Ctrl+K** - Focus command input (CommandCenter) -2. **Escape** - Close active block (CommandCenter) -3. **1-3** - Quick select in FallbackPicker - -### Nieuwe Shortcuts (E5.S3) -1. **⌘Enter / Ctrl+Enter** - Quick submit in CommandInput -2. **⌘Enter / Ctrl+Enter** - Quick save in DagnotatieBlock -3. **Visual hints** - βŒ˜β†΅ shown on DagnotatieBlock save button - ---- - -## πŸ§ͺ Test Scenarios - -### 1. Global Shortcuts - -**Test 1.1: ⌘K Focus Input** -- [ ] Start op Swift pagina -- [ ] Press ⌘K (Mac) of Ctrl+K (Windows/Linux) -- [ ] Command input krijgt focus -- [ ] Cursor blinkt in input field -- [ ] Werkt vanaf elke positie (in block, buiten block) - -**Test 1.2: Escape Close Block** -- [ ] Open dagnotitie block -- [ ] Press Escape -- [ ] Block sluit met slide-down animatie -- [ ] Input is weer beschikbaar -- [ ] Herhaal met zoeken block -- [ ] Herhaal met overdracht block - -**Test 1.3: Escape Close FallbackPicker** -- [ ] Trigger FallbackPicker (typ gibberish) -- [ ] Press Escape -- [ ] FallbackPicker sluit -- [ ] Canvas area toont empty state - ---- - -### 2. Command Input Shortcuts - -**Test 2.1: Enter Submit (Native)** -- [ ] Typ "notitie jan medicatie" in command input -- [ ] Press Enter -- [ ] Intent classification API wordt aangeroepen -- [ ] DagnotatieBlock opent met prefill -- [ ] Input wordt cleared - -**Test 2.2: ⌘Enter Quick Submit** -- [ ] Typ "zoek marie" in command input -- [ ] Press ⌘Enter (Mac) of Ctrl+Enter (Windows) -- [ ] Intent classification API wordt aangeroepen -- [ ] ZoekenBlock opent -- [ ] Input wordt cleared - -**Test 2.3: Empty Input - No Submit** -- [ ] Command input is leeg -- [ ] Press Enter of ⌘Enter -- [ ] Niks gebeurt (validation) -- [ ] Geen API call -- [ ] Geen error toast - -**Test 2.4: Submit During Processing** -- [ ] Typ commando en submit (Enter) -- [ ] Tijdens processing: druk nogmaals Enter -- [ ] Tweede submit wordt genegeerd (isProcessing check) -- [ ] Geen dubbele API calls - ---- - -### 3. DagnotatieBlock Shortcuts - -**Test 3.1: ⌘Enter Quick Save** -- [ ] Open dagnotitie block -- [ ] Vul alle velden in (patient, categorie, content) -- [ ] Press ⌘Enter (Mac) of Ctrl+Enter (Windows) -- [ ] Dagnotitie wordt opgeslagen -- [ ] Success toast verschijnt -- [ ] Block sluit na 500ms - -**Test 3.2: ⌘Enter Validation** -- [ ] Open dagnotitie block -- [ ] Laat patient leeg, vul rest in -- [ ] Press ⌘Enter -- [ ] Validation toast: "Selecteer een patiΓ«nt" -- [ ] Block blijft open -- [ ] Herhaal voor categorie en content - -**Test 3.3: Visual Hint Zichtbaar** -- [ ] Open dagnotitie block -- [ ] Check submit button -- [ ] Tekst toont "Opslaan βŒ˜β†΅" -- [ ] Hint is zichtbaar op desktop (hidden op mobile via sm:inline) -- [ ] Tooltip toont "Opslaan (⌘Enter)" on hover - -**Test 3.4: Enter in Textarea** -- [ ] Open dagnotitie block -- [ ] Focus in content textarea -- [ ] Press Enter (zonder Cmd/Ctrl) -- [ ] Nieuwe regel in textarea (native behavior) -- [ ] Form wordt NIET gesubmit -- [ ] Press ⌘Enter -- [ ] Form wordt gesubmit - ---- - -### 4. FallbackPicker Shortcuts - -**Test 4.1: Number Keys 1-3** -- [ ] Trigger FallbackPicker (typ "asdfasdf") -- [ ] Press 1 -- [ ] DagnotatieBlock opent met original input als content -- [ ] FallbackPicker sluit - -**Test 4.2: Number Keys Sequence** -- [ ] Trigger FallbackPicker -- [ ] Press 2 -- [ ] ZoekenBlock opent -- [ ] Close block (Escape) -- [ ] Trigger FallbackPicker again -- [ ] Press 3 -- [ ] OverdrachtBlock opent - -**Test 4.3: Numbers in Input Field** -- [ ] FallbackPicker open -- [ ] Typ "123" in command input (via ⌘K) -- [ ] Cijfers worden getypt (shortcut inactive in input) -- [ ] FallbackPicker blijft zichtbaar -- [ ] Press Escape om picker te sluiten - ---- - -### 5. Cross-Platform Testing - -**Test 5.1: macOS** -- [ ] ⌘K werkt (Cmd key) -- [ ] ⌘Enter werkt (Cmd key) -- [ ] Ctrl+K werkt ook (fallback) -- [ ] Ctrl+Enter werkt ook (fallback) - -**Test 5.2: Windows/Linux** -- [ ] Ctrl+K werkt -- [ ] Ctrl+Enter werkt -- [ ] ⌘ key (if present) werkt niet of is ignored - -**Test 5.3: Browser Conflicts** -- [ ] ⌘K/Ctrl+K overschrijft browser's native shortcut (search) -- [ ] preventDefault() werkt correct -- [ ] Geen browser search bar opent - ---- - -### 6. Edge Cases - -**Test 6.1: Rapid Shortcut Succession** -- [ ] Press ⌘K β†’ Escape β†’ ⌘K β†’ Enter snel na elkaar -- [ ] Alle shortcuts werken correct -- [ ] Geen race conditions -- [ ] Geen crashes - -**Test 6.2: Shortcuts During Block Transition** -- [ ] Open dagnotitie block -- [ ] Tijdens slide-up animatie: press ⌘Enter -- [ ] Shortcut werkt niet (block nog niet fully open) -- [ ] Of: shortcut werkt na animatie compleet - -**Test 6.3: Voice Recording Active** -- [ ] Start voice recording -- [ ] Press ⌘Enter -- [ ] Recording stopt -- [ ] Commando wordt verstuurd -- [ ] Transcript wordt gebruikt - -**Test 6.4: Block Disabled State** -- [ ] Open dagnotitie block -- [ ] Submit β†’ tijdens isSubmitting -- [ ] Press ⌘Enter -- [ ] Shortcut wordt genegeerd (disabled check) -- [ ] Geen dubbele save - ---- - -## 🎯 Acceptatie Criteria E5.S3 - -- [x] ⌘K/Ctrl+K werkt op alle platforms -- [x] Escape werkt in alle contexts (blocks, picker) -- [x] Enter submit werkt in command input -- [x] ⌘Enter/Ctrl+Enter werkt in command input -- [x] ⌘Enter/Ctrl+Enter werkt in dagnotitie block -- [x] 1-3 number shortcuts werken in FallbackPicker -- [x] Shortcuts hebben visual hints waar relevant -- [x] preventDefault() voorkomt browser conflicts -- [x] Shortcuts respecteren disabled/processing states -- [x] Cross-platform compatible (Mac, Windows, Linux) - ---- - -## πŸ“‹ Quick Smoke Test (5 minuten) - -Voor snelle verificatie: - -1. **⌘K Test:** - - [ ] Press ⌘K β†’ Input has focus βœ… - -2. **Enter Submit:** - - [ ] Type "notitie jan" β†’ Enter β†’ Block opens βœ… - -3. **⌘Enter Quick Submit:** - - [ ] Type "zoek marie" β†’ ⌘Enter β†’ Block opens βœ… - -4. **Escape Close:** - - [ ] Open any block β†’ Escape β†’ Block closes βœ… - -5. **Dagnotitie ⌘Enter Save:** - - [ ] Fill dagnotitie form β†’ ⌘Enter β†’ Saves βœ… - -6. **FallbackPicker Numbers:** - - [ ] Type gibberish β†’ Press 1 β†’ Dagnotitie opens βœ… - ---- - -## πŸš€ Documentatie - -Alle shortcuts gedocumenteerd in: -- `docs/swift/keyboard-shortcuts-reference.md` - Complete referentie -- Tooltips en visual hints in UI -- Bouwplan E5.S3 technical notes - ---- - -## 🎯 Status - -**E5.S3 - Keyboard Shortcuts: COMPLETE βœ…** - -All keyboard shortcuts verified, extended, and documented. diff --git a/docs/swift/archive/test-plan-epic3.md b/docs/swift/archive/test-plan-epic3.md deleted file mode 100644 index 3288cf7..0000000 --- a/docs/swift/archive/test-plan-epic3.md +++ /dev/null @@ -1,272 +0,0 @@ -# Test Plan Epic 3 - P1 Blocks - -**Datum:** 24-12-2024 -**Status:** Ready for Testing -**Epic:** E3 - P1 Blocks (E3.S0-S6) - ---- - -## Setup - -1. **Start development server:** - ```bash - pnpm dev - ``` - -2. **Open browser:** - - Navigeer naar `http://localhost:3000` - - Log in (of gebruik demo account) - - Kies "Swift" interface preference - - Je komt op `/epd/swift` - ---- - -## Test Checklist - -### E3.S0 - CanvasArea Block Rendering βœ… - -- [ ] **Empty State** - - [ ] Wanneer geen block actief is, zie je de empty state met voorbeeld commando's - - [ ] Empty state heeft "Wat wil je doen?" tekst - -- [ ] **Block Transitions** - - [ ] Wanneer een block opent, zie je een smooth fade-in animatie - - [ ] Wanneer een block sluit, zie je een smooth fade-out animatie - - [ ] Geen flickering tussen blocks - -- [ ] **PatientContextCard Auto-Display** - - [ ] Wanneer je een patiΓ«nt selecteert in ZoekenBlock, verschijnt PatientContextCard automatisch - - [ ] PatientContextCard toont patiΓ«nt naam in header - ---- - -### E3.S1 - Block Container βœ… - -- [ ] **Container Styling** - - [ ] Alle blocks hebben een donkere achtergrond (slate-800) - - [ ] Blocks hebben een border (slate-700) - - [ ] Blocks hebben shadow-2xl - -- [ ] **Close Button** - - [ ] Elke block heeft een X button rechtsboven - - [ ] Hover over X button verandert kleur - - [ ] Klik op X sluit het block - - [ ] ESC toets sluit ook het block - -- [ ] **Sizes** - - [ ] DagnotatieBlock heeft size "md" - - [ ] ZoekenBlock heeft size "md" - - [ ] OverdrachtBlock heeft size "lg" - - [ ] PatientContextCard heeft size "lg" - -- [ ] **Animations** - - [ ] Container heeft fade-in animatie - - [ ] Content heeft stagger animatie (items verschijnen na elkaar) - - [ ] Close button heeft hover/tap animaties - ---- - -### E3.S2 - DagnotatieBlock βœ… - -- [ ] **Patient Search** - - [ ] Typ "jan" in patient search veld - - [ ] Na ~300ms zie je zoekresultaten - - [ ] Resultaten tonen naam, geboortedatum, BSN - - [ ] Klik op een patiΓ«nt selecteert deze - -- [ ] **Category Selector** - - [ ] 5 categorie buttons zijn zichtbaar: medicatie, adl, gedrag, incident, observatie - - [ ] Klik op een categorie selecteert deze (visuele feedback) - - [ ] Alleen één categorie kan geselecteerd zijn - -- [ ] **Text Input** - - [ ] Textarea is beschikbaar - - [ ] Character counter toont "0 / 500" - - [ ] Typ tekst β†’ counter update - - [ ] Max 500 karakters (kan niet meer typen) - -- [ ] **Include in Handover** - - [ ] Checkbox "Opnemen in overdracht" is zichtbaar - - [ ] Checkbox kan aangevinkt worden - -- [ ] **Save Functionality** - - [ ] Klik "Opslaan" zonder patiΓ«nt β†’ error message - - [ ] Klik "Opslaan" zonder categorie β†’ error message - - [ ] Klik "Opslaan" zonder tekst β†’ error message - - [ ] Vul alles in en klik "Opslaan" - - [ ] Success toast verschijnt - - [ ] Block sluit automatisch na ~500ms - -- [ ] **Prefill Data** - - [ ] Typ "notitie jan medicatie" in command input - - [ ] DagnotatieBlock opent met "jan" voorgevuld in patient search - - [ ] Categorie "medicatie" is geselecteerd - ---- - -### E3.S3 - Patient Search API βœ… - -- [ ] **API Endpoint** - - [ ] Open DevTools β†’ Network tab - - [ ] Typ in ZoekenBlock of DagnotatieBlock - - [ ] Request naar `/api/patients/search?q=...` wordt gemaakt - - [ ] Response heeft `patients` array met `matchScore` - -- [ ] **Search Functionality** - - [ ] Zoek op naam: "jan" β†’ resultaten met "Jan" in naam - - [ ] Zoek op BSN: "123456789" β†’ resultaten met deze BSN - - [ ] Zoek op clientnummer: "12345" β†’ resultaten met dit nummer - - [ ] Zoek op deel van naam: "mar" β†’ resultaten met "Marie", "Maria", etc. - -- [ ] **Match Scoring** - - [ ] Exacte naam match heeft hogere score - - [ ] Resultaten zijn gesorteerd op matchScore (hoogste eerst) - -- [ ] **Error Handling** - - [ ] Zoek op "x" (te kort) β†’ geen request - - [ ] Network error β†’ error message in UI - ---- - -### E3.S4 - ZoekenBlock βœ… - -- [ ] **Search Input** - - [ ] Typ in search input veld - - [ ] Debouncing werkt (geen request bij elke toetsaanslag) - - [ ] Loading indicator tijdens zoeken - -- [ ] **Search Results** - - [ ] Resultaten verschijnen in dropdown - - [ ] Elke resultaat toont: avatar, naam, geboortedatum, BSN, clientnummer - - [ ] Max 5 resultaten getoond - -- [ ] **Patient Selection** - - [ ] Klik op een patiΓ«nt in resultaten - - [ ] Loading indicator tijdens ophalen volledige data - - [ ] Success toast: "PatiΓ«nt geselecteerd" - - [ ] Block sluit automatisch - - [ ] PatientContextCard verschijnt automatisch - -- [ ] **Store Integration** - - [ ] Na selectie is `activePatient` gezet in store - - [ ] Recent action is toegevoegd: "PatiΓ«nt geselecteerd: [naam]" - -- [ ] **Empty State** - - [ ] Geen resultaten β†’ "Geen patiΓ«nten gevonden" message - - [ ] Te korte query β†’ geen resultaten - ---- - -### E3.S5 - PatientContextCard βœ… - -- [ ] **Auto-Open** - - [ ] Na patiΓ«nt selectie in ZoekenBlock verschijnt PatientContextCard automatisch - - [ ] PatientContextCard heeft patiΓ«nt naam in header - -- [ ] **Loading State** - - [ ] Tijdens laden zie je "Context laden..." met spinner - -- [ ] **Notities Sectie** - - [ ] Laatste 5 reports worden getoond - - [ ] Elke notitie toont: type badge, overdracht indicator, datum/tijd, content preview - - [ ] Content is gelimiteerd tot 2 regels (line-clamp-2) - -- [ ] **Vitals Sectie** - - [ ] Vitale functies van vandaag worden getoond - - [ ] Grid layout (2 kolommen) - - [ ] Abnormale waarden hebben amber achtergrond - - [ ] Elke vital toont: naam, waarde, eenheid, tijdstip - -- [ ] **Diagnoses Sectie** - - [ ] Actieve diagnoses worden getoond - - [ ] Elke diagnose toont: naam, startdatum (indien beschikbaar) - -- [ ] **Risico's Sectie** - - [ ] Risk assessments worden getoond - - [ ] Risico badges met kleurcodering (rood voor hoog, amber voor gemiddeld) - - [ ] Elke badge toont: type + niveau - -- [ ] **Empty State** - - [ ] Geen data beschikbaar β†’ "Geen context beschikbaar voor deze patiΓ«nt" - -- [ ] **Error Handling** - - [ ] API error β†’ error message met retry optie - ---- - -### E3.S6 - OverdrachtBlock βœ… - -- [ ] **Patients List** - - [ ] Lijst van patiΓ«nten met activiteit wordt geladen - - [ ] Loading state tijdens laden - - [ ] Elke patiΓ«nt toont: naam, alert count, risico indicator - -- [ ] **Period Selector** - - [ ] 4 period buttons: Vandaag, 3 dagen, 1 week, 2 weken - - [ ] Geselecteerde periode heeft visuele feedback - - [ ] Beschrijving onder buttons update bij selectie - -- [ ] **Active Patient Filter** - - [ ] Wanneer `activePatient` is gezet, toont alleen die patiΓ«nt - - [ ] Wanneer geen `activePatient`, toont alle patiΓ«nten - -- [ ] **Generate Summary** - - [ ] Klik "Genereer" button voor een patiΓ«nt - - [ ] Loading state: "Samenvatting wordt gegenereerd..." - - [ ] Na ~3-5 seconden verschijnt samenvatting - -- [ ] **Summary Display** - - [ ] **Samenvatting**: AI-gegenereerde tekst in grijze box - - [ ] **Aandachtspunten**: Lijst met urgentie badges - - [ ] Urgente punten hebben rode border + alert icon - - [ ] Bron type badges (observatie, rapportage, verpleegkundig, risico) - - [ ] Bronverwijzingen met datum + label - - [ ] **Actiepunten**: Checklist met acties - - [ ] **Footer**: Tijdstip generatie + duration, refresh button - -- [ ] **Error Handling** - - [ ] API error β†’ error message met "Opnieuw proberen" button - - [ ] Network error β†’ toast notification - -- [ ] **Refresh** - - [ ] Klik "Vernieuwen" button β†’ nieuwe samenvatting wordt gegenereerd - ---- - -## Cross-Feature Tests - -- [ ] **Keyboard Shortcuts** - - [ ] ESC sluit actieve block - - [ ] Cmd+K focust command input - -- [ ] **Animations** - - [ ] Alle transitions zijn smooth (geen janky animaties) - - [ ] Geen layout shifts tijdens animaties - -- [ ] **Error States** - - [ ] Network errors tonen user-friendly messages - - [ ] Validation errors zijn duidelijk - - [ ] Retry functionaliteit werkt - -- [ ] **Performance** - - [ ] Blocks openen binnen 100ms - - [ ] API calls zijn debounced waar nodig - - [ ] Geen onnodige re-renders - ---- - -## Known Issues / Notes - -- [ ] Noteer hier eventuele issues die je tegenkomt -- [ ] Noteer verbeteringen die je zou willen zien - ---- - -## Test Resultaten - -**Tester:** _________________ -**Datum:** _________________ -**Status:** ⏳ In Progress / βœ… Passed / ❌ Failed - -**Totaal:** ___ / ___ tests passed - diff --git a/docs/swift/archive/to-swift-v1.md b/docs/swift/archive/to-swift-v1.md deleted file mode 100644 index d3a229a..0000000 --- a/docs/swift/archive/to-swift-v1.md +++ /dev/null @@ -1,1257 +0,0 @@ -# Technisch Ontwerp (TO) – Swift: Contextual UI EPD - -**Projectnaam:** Swift (Contextual UI EPD) -**Versie:** v1.0 -**Datum:** 23-12-2024 -**Auteur:** Claude Code / Development Team - ---- - -## 1. Doel en relatie met PRD en FO - -### Doel van dit document -Het Technisch Ontwerp beschrijft **hoe** Swift technisch wordt gebouwd. Waar het PRD (swift-prd.md) het *wat* beschrijft en het FO (swift-fo-ai.md) het *hoe functioneel*, gaat dit TO over architectuur, componenten, data flows en implementatie details. - -### Relatie met andere documenten -| Document | Beschrijft | Status | -|----------|------------|--------| -| `swift-prd.md` | Product visie, user stories, scope | Definitief | -| `swift-fo-ai.md` | Functionele flows, blocks, intent mapping | Definitief | -| `swift-ux-v2.1.md` | UI specs, design tokens, layouts | Definitief | -| Dit document (TO) | Technische implementatie | Definitief | - ---- - -## 2. Technische Architectuur Overzicht - -### 2.1 High-Level Architectuur - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ SUAVE FRONTEND β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ COMMAND CENTER β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ Text Input β”‚ β”‚ Voice Input β”‚ β”‚ Context Bar β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ (cmdk) β”‚ β”‚ (Deepgram) β”‚ β”‚ (user/patient/shift) β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β”‚ β–Ό β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ INTENT CLASSIFIER β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ Tier 1: Local │───▢│ Tier 2: AI (Claude) β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ Regex + Keywordsβ”‚ β”‚ Fallback bij lage confidence β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ (<50ms) β”‚ β”‚ (<500ms) β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β–Ό β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ BLOCK CONTAINER (Ephemeral) β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚Dagno- β”‚ β”‚Zoeken β”‚ β”‚Rappor- β”‚ β”‚Over- β”‚ β”‚Fallbackβ”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚titie β”‚ β”‚Block β”‚ β”‚tage β”‚ β”‚dracht β”‚ β”‚Picker β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚Block β”‚ β”‚ β”‚ β”‚Block β”‚ β”‚Block β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ ZUSTAND STORE β”‚ β”‚ -β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ -β”‚ β”‚ β”‚ Context β”‚ β”‚ Active β”‚ β”‚ Recent β”‚ β”‚ Block State β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ State β”‚ β”‚ Patient β”‚ β”‚ Actions β”‚ β”‚ (pre-fill data) β”‚ β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ NEXT.JS API ROUTES β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ /api/intent β”‚ β”‚ /api/patientsβ”‚ β”‚ /api/reports β”‚ β”‚ -β”‚ β”‚ /classify β”‚ β”‚ /search β”‚ β”‚ (bestaand) β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ /api/over- β”‚ β”‚ /api/deepgramβ”‚ β”‚ /api/docs/ β”‚ β”‚ -β”‚ β”‚ dracht β”‚ β”‚ (bestaand) β”‚ β”‚ chat β”‚ β”‚ -β”‚ β”‚ (bestaand) β”‚ β”‚ β”‚ β”‚ (bestaand) β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ SUPABASE β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ PostgreSQL + RLS + Auth + Realtime β”‚ -β”‚ β”‚ -β”‚ Tabellen: patients, reports, observations, conditions, care_plans, β”‚ -β”‚ intakes, practitioners, ai_events β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 2.2 Component HiΓ«rarchie - -``` -app/ -β”œβ”€β”€ epd/ -β”‚ └── swift/ # Nieuwe Swift module -β”‚ β”œβ”€β”€ page.tsx # Main entry point -β”‚ └── layout.tsx # Swift-specific layout -β”‚ -components/ -β”œβ”€β”€ swift/ # Nieuwe folder -β”‚ β”œβ”€β”€ command-center/ -β”‚ β”‚ β”œβ”€β”€ command-center.tsx # Main container -β”‚ β”‚ β”œβ”€β”€ command-input.tsx # Text + voice input -β”‚ β”‚ β”œβ”€β”€ context-bar.tsx # User/patient/shift info -β”‚ β”‚ └── voice-indicator.tsx # Recording state -β”‚ β”‚ -β”‚ β”œβ”€β”€ blocks/ -β”‚ β”‚ β”œβ”€β”€ block-container.tsx # Animation wrapper -β”‚ β”‚ β”œβ”€β”€ dagnotitie-block.tsx # Quick note entry -β”‚ β”‚ β”œβ”€β”€ zoeken-block.tsx # Patient search -β”‚ β”‚ β”œβ”€β”€ rapportage-block.tsx # Full report -β”‚ β”‚ β”œβ”€β”€ overdracht-block.tsx # AI summary -β”‚ β”‚ └── fallback-picker.tsx # Manual block selection -β”‚ β”‚ -β”‚ β”œβ”€β”€ shared/ -β”‚ β”‚ β”œβ”€β”€ patient-card.tsx # Compact patient info -β”‚ β”‚ β”œβ”€β”€ recent-actions.tsx # Recent activity list -β”‚ β”‚ └── keyboard-hints.tsx # Shortcut overlay -β”‚ β”‚ -β”‚ └── index.ts # Barrel exports -β”‚ -stores/ # Nieuwe folder -β”‚ └── swift-store.ts # Zustand store -β”‚ -lib/ -β”œβ”€β”€ swift/ # Nieuwe folder -β”‚ β”œβ”€β”€ intent-classifier.ts # Local classification -β”‚ β”œβ”€β”€ entity-extractor.ts # Extract patient, category -β”‚ β”œβ”€β”€ block-registry.ts # Block definitions -β”‚ └── types.ts # Swift-specific types -β”‚ -hooks/ -β”‚ β”œβ”€β”€ use-swift-store.ts # Store hook -β”‚ β”œβ”€β”€ use-intent.ts # Intent classification hook -β”‚ └── use-keyboard-shortcuts.ts # Cmd+K etc. -``` - ---- - -## 3. Techstack Selectie - -### 3.1 Bestaande Stack (hergebruiken) - -| Component | Technologie | Versie | Status | -|-----------|-------------|--------|--------| -| Framework | Next.js | 14.2.18 | βœ… Bestaand | -| UI Library | React | 18.3.1 | βœ… Bestaand | -| Styling | TailwindCSS | 3.4.18 | βœ… Bestaand | -| Components | shadcn/ui | - | βœ… Bestaand | -| Command Palette | cmdk | 1.1.1 | βœ… Bestaand | -| Animations | framer-motion | 12.23.24 | βœ… Bestaand | -| Database | Supabase | 2.81.1 | βœ… Bestaand | -| Speech-to-Text | Deepgram | 4.11.2 | βœ… Bestaand | -| AI | Claude API | - | βœ… Bestaand | -| Validation | Zod | 4.1.12 | βœ… Bestaand | -| Forms | react-hook-form | 7.66.1 | βœ… Bestaand | -| Icons | lucide-react | 0.553.0 | βœ… Bestaand | -| Dates | date-fns | 4.1.0 | βœ… Bestaand | - -### 3.2 Nieuwe Dependencies (toe te voegen) - -| Component | Technologie | Versie | Reden | Alternatieven | -|-----------|-------------|--------|-------|---------------| -| State Management | Zustand | ^4.5.0 | Lightweight, geen providers, TypeScript-first | Jotai, Redux Toolkit | - -**Installatie:** -```bash -pnpm add zustand -``` - -**Waarom Zustand?** -- 3KB gzipped (vs Redux 7KB) -- Geen Provider wrapping nodig -- TypeScript-first met goede inference -- Middleware support (devtools, persist) -- Past bij de "minimal overhead" filosofie van Swift - ---- - -## 4. Datamodel - -### 4.1 Bestaande Tabellen (hergebruiken) - -```sql --- Patients (bestaand) -patients ( - id UUID PRIMARY KEY, - name_given TEXT, - name_family TEXT, - name_prefix TEXT, - birth_date DATE, - gender TEXT, - created_at TIMESTAMP -) - --- Reports (bestaand) - gebruikt voor dagnotities -reports ( - id UUID PRIMARY KEY, - patient_id UUID REFERENCES patients(id), - type TEXT, -- 'verpleegkundig' voor dagnotities - content TEXT, - structured_data JSONB, -- { category: 'medicatie'|'adl'|... } - include_in_handover BOOLEAN, - shift_date DATE, - created_at TIMESTAMP, - created_by UUID, - deleted_at TIMESTAMP -- Soft delete -) - --- Observations (bestaand) - vitals -observations ( - id UUID PRIMARY KEY, - patient_id UUID REFERENCES patients(id), - code_display TEXT, - value_quantity_value NUMERIC, - value_quantity_unit TEXT, - effective_datetime TIMESTAMP -) - --- Conditions (bestaand) - diagnoses -conditions ( - id UUID PRIMARY KEY, - patient_id UUID REFERENCES patients(id), - code_display TEXT, - clinical_status TEXT, - onset_datetime TIMESTAMP -) -``` - -### 4.2 Nieuwe Tabellen - -```sql --- Intent Events (nieuw) - voor analytics en training -CREATE TABLE intent_events ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - created_at TIMESTAMP DEFAULT NOW(), - user_id UUID REFERENCES auth.users(id), - - -- Input - raw_input TEXT NOT NULL, - input_source TEXT NOT NULL, -- 'text' | 'voice' - - -- Classification result - intent TEXT NOT NULL, -- 'dagnotitie' | 'zoeken' | ... - confidence NUMERIC(3,2) NOT NULL, -- 0.00 - 1.00 - tier TEXT NOT NULL, -- 'local' | 'ai' - - -- Extracted entities - entities JSONB, -- { patient_name, category, ... } - - -- Outcome - block_opened TEXT, -- Which block was actually opened - action_completed BOOLEAN, -- Did user complete the action? - - -- Performance - classification_ms INTEGER, -- Time to classify - - -- Context - context JSONB -- { activePatient, shift, ... } -); - --- Index voor analytics queries -CREATE INDEX idx_intent_events_created ON intent_events(created_at); -CREATE INDEX idx_intent_events_intent ON intent_events(intent); -CREATE INDEX idx_intent_events_user ON intent_events(user_id); - --- RLS Policy -ALTER TABLE intent_events ENABLE ROW LEVEL SECURITY; - -CREATE POLICY "Users can insert own events" ON intent_events - FOR INSERT WITH CHECK (auth.uid() = user_id); - -CREATE POLICY "Users can read own events" ON intent_events - FOR SELECT USING (auth.uid() = user_id); -``` - -### 4.3 TypeScript Types - -```typescript -// lib/swift/types.ts - -// Intent types -export const SUAVE_INTENTS = [ - 'dagnotitie', - 'zoeken', - 'rapportage', - 'overdracht', - 'patient_info', - 'agenda', - 'onbekend', -] as const; - -export type SwiftIntent = (typeof SUAVE_INTENTS)[number]; - -// Classification result -export interface IntentClassification { - intent: SwiftIntent; - confidence: number; // 0.0 - 1.0 - tier: 'local' | 'ai'; - entities: ExtractedEntities; - clarificationNeeded?: boolean; - clarificationPrompt?: string; -} - -// Extracted entities from input -export interface ExtractedEntities { - patientName?: string; - patientId?: string; // If resolved - category?: VerpleegkundigCategory; - content?: string; - timeRange?: string; - reportType?: ReportType; -} - -// Block state -export interface BlockState { - type: SwiftIntent | null; - isOpen: boolean; - prefillData: Partial; - animationState: 'entering' | 'visible' | 'exiting' | 'hidden'; -} - -// Context state -export interface SwiftContext { - user: { - id: string; - name: string; - role: string; - } | null; - activePatient: { - id: string; - name: string; - roomNumber?: string; - } | null; - shift: 'nacht' | 'ochtend' | 'middag' | 'avond'; - recentPatients: Array<{ - id: string; - name: string; - lastAction: string; - timestamp: Date; - }>; - recentActions: Array<{ - type: string; - patientName: string; - timestamp: Date; - success: boolean; - }>; -} - -// Store state -export interface SwiftStore { - // Context - context: SwiftContext; - setActivePatient: (patient: SwiftContext['activePatient']) => void; - addRecentAction: (action: SwiftContext['recentActions'][0]) => void; - - // Block - block: BlockState; - openBlock: (type: SwiftIntent, prefillData?: Partial) => void; - closeBlock: () => void; - - // Input - inputValue: string; - setInputValue: (value: string) => void; - isVoiceActive: boolean; - setVoiceActive: (active: boolean) => void; - - // Classification - isClassifying: boolean; - lastClassification: IntentClassification | null; -} -``` - ---- - -## 5. API Ontwerp - -### 5.1 Nieuwe Endpoints - -#### POST /api/intent/classify - -Classifieert gebruikersinput naar intent + entities. - -```typescript -// Request -interface ClassifyRequest { - input: string; - source: 'text' | 'voice'; - context?: { - activePatientId?: string; - shift?: string; - }; -} - -// Response -interface ClassifyResponse { - intent: SwiftIntent; - confidence: number; - tier: 'local' | 'ai'; - entities: ExtractedEntities; - clarificationNeeded?: boolean; - clarificationPrompt?: string; - classificationMs: number; -} - -// Example -POST /api/intent/classify -{ - "input": "notitie jan medicatie gegeven", - "source": "voice", - "context": { "shift": "ochtend" } -} - -// Response -{ - "intent": "dagnotitie", - "confidence": 0.95, - "tier": "local", - "entities": { - "patientName": "jan", - "category": "medicatie", - "content": "medicatie gegeven" - }, - "classificationMs": 12 -} -``` - -#### GET /api/patients/search - -Fuzzy search voor patiΓ«nten. - -```typescript -// Request -GET /api/patients/search?q=jan&limit=5 - -// Response -interface SearchResponse { - patients: Array<{ - id: string; - name: string; - birthDate: string; - roomNumber?: string; - primaryDiagnosis?: string; - matchScore: number; - }>; - totalCount: number; -} - -// Example Response -{ - "patients": [ - { - "id": "uuid-1", - "name": "Jan de Vries", - "birthDate": "1965-03-15", - "roomNumber": "K204", - "primaryDiagnosis": "F41.1 Gegeneraliseerde angststoornis", - "matchScore": 0.95 - }, - { - "id": "uuid-2", - "name": "Janneke van den Berg", - "birthDate": "1978-08-22", - "roomNumber": "K108", - "matchScore": 0.72 - } - ], - "totalCount": 2 -} -``` - -### 5.2 Bestaande Endpoints (hergebruiken) - -| Endpoint | Method | Gebruik in Swift | -|----------|--------|------------------| -| `/api/reports` | POST | DagnotatieBlock, RapportageBlock | -| `/api/reports/[id]` | PATCH/DELETE | Edit/delete notities | -| `/api/overdracht/generate` | POST | OverdrachtBlock AI summary | -| `/api/overdracht/patients` | GET | PatiΓ«nten met updates | -| `/api/overdracht/[patientId]` | GET | Patient detail data | -| `/api/deepgram/token` | GET | Streaming voice token | -| `/api/deepgram/transcribe` | POST | Batch transcription | - -### 5.3 API Route Implementatie - -```typescript -// app/api/intent/classify/route.ts - -import { NextRequest, NextResponse } from 'next/server'; -import { createClient } from '@/lib/auth/server'; -import { z } from 'zod'; -import { classifyIntentLocal } from '@/lib/swift/intent-classifier'; -import { classifyIntentAI } from '@/lib/swift/intent-classifier-ai'; - -const ClassifySchema = z.object({ - input: z.string().min(1).max(500), - source: z.enum(['text', 'voice']), - context: z.object({ - activePatientId: z.string().uuid().optional(), - shift: z.string().optional(), - }).optional(), -}); - -export async function POST(request: NextRequest) { - const startTime = Date.now(); - - try { - const body = await request.json(); - const result = ClassifySchema.safeParse(body); - - if (!result.success) { - return NextResponse.json( - { error: 'Validatiefout', details: result.error.issues }, - { status: 400 } - ); - } - - const { input, source, context } = result.data; - const supabase = await createClient(); - - // Check auth - const { data: authData } = await supabase.auth.getUser(); - if (!authData?.user) { - return NextResponse.json({ error: 'Niet geautoriseerd' }, { status: 401 }); - } - - // Tier 1: Local classification - const localResult = classifyIntentLocal(input); - - let classification = localResult; - let tier: 'local' | 'ai' = 'local'; - - // Tier 2: AI fallback if confidence < 0.8 - if (localResult.confidence < 0.8) { - const aiResult = await classifyIntentAI(input, context); - if (aiResult.confidence > localResult.confidence) { - classification = aiResult; - tier = 'ai'; - } - } - - const classificationMs = Date.now() - startTime; - - // Log event for analytics - await supabase.from('intent_events').insert({ - user_id: authData.user.id, - raw_input: input, - input_source: source, - intent: classification.intent, - confidence: classification.confidence, - tier, - entities: classification.entities, - classification_ms: classificationMs, - context, - }); - - return NextResponse.json({ - ...classification, - tier, - classificationMs, - }); - - } catch (error) { - console.error('Intent classification error:', error); - return NextResponse.json( - { error: 'Classificatie mislukt' }, - { status: 500 } - ); - } -} -``` - ---- - -## 6. Security & Compliance - -### 6.1 Security Maatregelen - -| Maatregel | Implementatie | Status | -|-----------|---------------|--------| -| **Authentication** | Supabase Auth (session-based) | βœ… Bestaand | -| **Authorization** | Row Level Security (RLS) op alle tabellen | βœ… Bestaand | -| **Input Validation** | Zod schemas op alle endpoints | βœ… Bestaand | -| **Data Encryption** | At rest (Supabase), in transit (HTTPS) | βœ… Bestaand | -| **CORS** | Restrictive origins | βœ… Bestaand | -| **Rate Limiting** | Vercel Edge (100 req/min) | βœ… Bestaand | - -### 6.2 RLS Policies voor Nieuwe Tabel - -```sql --- intent_events: alleen eigen events -ALTER TABLE intent_events ENABLE ROW LEVEL SECURITY; - -CREATE POLICY "Users insert own events" ON intent_events - FOR INSERT WITH CHECK (auth.uid() = user_id); - -CREATE POLICY "Users read own events" ON intent_events - FOR SELECT USING (auth.uid() = user_id); - --- Admins kunnen alle events lezen (voor analytics) -CREATE POLICY "Admins read all events" ON intent_events - FOR SELECT USING ( - EXISTS ( - SELECT 1 FROM practitioners - WHERE user_id = auth.uid() - AND role = 'admin' - ) - ); -``` - -### 6.3 Privacy & AVG - -| Aspect | Implementatie | -|--------|---------------| -| **Data Minimalisatie** | Alleen noodzakelijke velden in intent_events | -| **Voice Data** | Wordt NIET opgeslagen - alleen transcript | -| **Patient Data** | Bestaande RLS policies van toepassing | -| **Logging** | Audit trail via ai_events en intent_events | -| **Consent** | Gebruiker activeert voice expliciet (push-to-talk) | - ---- - -## 7. AI/LLM Integratie - -### 7.1 Intent Classification (Tier 2) - -```typescript -// lib/swift/intent-classifier-ai.ts - -const INTENT_CLASSIFICATION_PROMPT = ` -Je bent een intent classifier voor een Nederlands EPD systeem. -Analyseer de gebruikersinput en bepaal: -1. De intent (dagnotitie, zoeken, rapportage, overdracht, patient_info, agenda, onbekend) -2. GeΓ«xtraheerde entities (patiΓ«ntnaam, categorie, content, etc.) -3. Confidence score (0.0 - 1.0) - -CategorieΓ«n voor dagnotities: medicatie, adl, gedrag, incident, observatie - -Antwoord ALLEEN in JSON format: -{ - "intent": "string", - "confidence": number, - "entities": { - "patientName": "string of null", - "category": "string of null", - "content": "string of null" - }, - "clarificationNeeded": boolean, - "clarificationPrompt": "string of null" -} -`; - -export async function classifyIntentAI( - input: string, - context?: { activePatientId?: string; shift?: string } -): Promise { - const response = await fetch('https://api.anthropic.com/v1/messages', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': process.env.ANTHROPIC_API_KEY!, - 'anthropic-version': '2023-06-01', - }, - body: JSON.stringify({ - model: 'claude-3-5-haiku-20241022', // Snelste model voor classificatie - max_tokens: 256, - temperature: 0.1, - system: INTENT_CLASSIFICATION_PROMPT, - messages: [{ - role: 'user', - content: `Input: "${input}"\nContext: ${JSON.stringify(context || {})}` - }], - }), - }); - - // Parse response... -} -``` - -### 7.2 Model Selectie - -| Taak | Model | Reden | -|------|-------|-------| -| Intent Classification | claude-3-5-haiku | Snel (<200ms), goedkoop, voldoende accuraat | -| Overdracht Summary | claude-sonnet-4 | Complexer, betere Nederlandse output | -| Report Structuring | claude-3-5-haiku | Snel, kosten-effectief | - -### 7.3 Cost Management - -```typescript -// Token limits en caching -const AI_CONFIG = { - intentClassification: { - model: 'claude-3-5-haiku-20241022', - maxTokens: 256, - cacheKey: (input: string) => `intent:${hash(input.toLowerCase())}`, - cacheTTL: 300, // 5 min - zelfde input = zelfde intent - }, - overdrachtSummary: { - model: 'claude-sonnet-4-20250514', - maxTokens: 2048, - cacheKey: (patientId: string, period: string) => - `overdracht:${patientId}:${period}:${today()}`, - cacheTTL: 3600, // 1 uur - data verandert niet snel - }, -}; -``` - ---- - -## 8. Performance & Scalability - -### 8.1 Performance Targets - -| Metric | Target | Meetmethode | -|--------|--------|-------------| -| Command Center render | <100ms | React DevTools | -| Local intent classification | <50ms | API response time | -| AI intent classification | <500ms | API response time | -| Block animation | 60fps | Chrome DevTools | -| Voice-to-text | <1s | Deepgram streaming | -| Patient search | <200ms | API response time | - -### 8.2 Optimalisatie StrategieΓ«n - -```typescript -// 1. Debounced input voor classificatie -const debouncedClassify = useMemo( - () => debounce(classifyIntent, 150), - [] -); - -// 2. Optimistic UI voor notities -const saveNotitie = async (data: NotitieData) => { - // Direct toevoegen aan UI - addOptimisticAction({ - type: 'dagnotitie', - patientName: data.patientName, - status: 'saving', - }); - - // Async opslaan - try { - await api.reports.create(data); - markActionComplete(); - } catch (error) { - rollbackAction(); - showError(); - } -}; - -// 3. Prefetching voor patient search -const prefetchPatients = () => { - // Prefetch recent patients bij mount - queryClient.prefetchQuery({ - queryKey: ['patients', 'recent'], - queryFn: fetchRecentPatients, - }); -}; - -// 4. Code splitting voor blocks -const DagnotatieBlock = dynamic( - () => import('@/components/swift/blocks/dagnotitie-block'), - { loading: () => } -); -``` - -### 8.3 Bundle Size Impact - -| Component | Estimated Size | Mitigation | -|-----------|----------------|------------| -| Zustand | ~3KB gzipped | Minimal overhead | -| Swift components | ~15KB gzipped | Code splitting | -| Intent classifier | ~2KB gzipped | - | -| **Total Swift** | ~20KB gzipped | Lazy loaded | - ---- - -## 9. Deployment & CI/CD - -### 9.1 Feature Flag Strategie - -```typescript -// lib/feature-flags.ts -export const FEATURES = { - swift: { - enabled: process.env.NEXT_PUBLIC_SUAVE_ENABLED === 'true', - allowedUsers: ['admin', 'developer'], // Role-based rollout - }, -}; - -// Usage in layout -export default function EPDLayout({ children }) { - const { user } = useAuth(); - - if (FEATURES.swift.enabled && - FEATURES.swift.allowedUsers.includes(user?.role)) { - return {children}; - } - - return {children}; -} -``` - -### 9.2 Migration Plan - -``` -FASE 1: Parallel (Week 1-2) -β”œβ”€β”€ Swift naast bestaande EPD -β”œβ”€β”€ Toggle via feature flag -└── Alleen voor developers - -FASE 2: Beta (Week 3-4) -β”œβ”€β”€ Swift default voor geselecteerde users -β”œβ”€β”€ Fallback naar traditioneel EPD -└── Feedback verzamelen - -FASE 3: Rollout (Week 5+) -β”œβ”€β”€ Swift default voor alle users -β”œβ”€β”€ Traditioneel EPD als fallback optie -└── Metrics monitoren -``` - -### 9.3 Database Migration - -```bash -# Nieuwe migration file -supabase/migrations/20241223_add_intent_events.sql -``` - ---- - -## 10. Monitoring & Logging - -### 10.1 Metrics Dashboard - -```typescript -// Swift-specifieke metrics -const SUAVE_METRICS = { - // Intent accuracy - intentAccuracy: { - query: ` - SELECT - intent, - tier, - AVG(confidence) as avg_confidence, - COUNT(*) as count, - SUM(CASE WHEN action_completed THEN 1 ELSE 0 END)::float / COUNT(*) as completion_rate - FROM intent_events - WHERE created_at > NOW() - INTERVAL '24 hours' - GROUP BY intent, tier - `, - threshold: { completion_rate: 0.8 }, - }, - - // Voice adoption - voiceAdoption: { - query: ` - SELECT - input_source, - COUNT(*) as count - FROM intent_events - WHERE created_at > NOW() - INTERVAL '24 hours' - GROUP BY input_source - `, - target: { voice_percentage: 0.4 }, - }, - - // Fallback usage - fallbackUsage: { - query: ` - SELECT - COUNT(*) FILTER (WHERE intent = 'onbekend') as fallback_count, - COUNT(*) as total_count - FROM intent_events - WHERE created_at > NOW() - INTERVAL '24 hours' - `, - threshold: { fallback_rate: 0.15 }, - }, - - // Performance - classificationLatency: { - query: ` - SELECT - tier, - percentile_cont(0.5) WITHIN GROUP (ORDER BY classification_ms) as p50, - percentile_cont(0.95) WITHIN GROUP (ORDER BY classification_ms) as p95 - FROM intent_events - WHERE created_at > NOW() - INTERVAL '1 hour' - GROUP BY tier - `, - threshold: { local_p95: 50, ai_p95: 500 }, - }, -}; -``` - -### 10.2 Error Tracking - -```typescript -// Sentry integration voor Swift -Sentry.init({ - dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, - integrations: [ - new Sentry.BrowserTracing({ - tracePropagationTargets: ['/api/intent', '/api/patients'], - }), - ], - beforeSend(event) { - // Tag Swift-specifieke errors - if (event.request?.url?.includes('/swift')) { - event.tags = { ...event.tags, module: 'swift' }; - } - return event; - }, -}); -``` - ---- - -## 11. Risico's & Technische Mitigatie - -| Risico | Impact | Waarschijnlijkheid | Mitigatie | -|--------|--------|-------------------|-----------| -| **Voice recognition accuracy** | Hoog | Middel | Deepgram NL model testen, fallback naar tekst | -| **Intent misclassificatie** | Hoog | Middel | Two-tier systeem, fallback picker altijd zichtbaar | -| **AI API latency** | Middel | Laag | Local-first classificatie, Haiku model voor snelheid | -| **Claude API outage** | Hoog | Laag | Graceful degradation naar local-only, error messages | -| **Browser compatibility (voice)** | Middel | Laag | Feature detection, fallback messaging | -| **User adoption resistance** | Middel | Middel | Feature flag, dual-mode, training | -| **Performance regression** | Middel | Laag | Lazy loading, code splitting, monitoring | - -### 11.1 Fallback StrategieΓ«n - -```typescript -// Intent classification fallback chain -const classifyWithFallbacks = async (input: string) => { - try { - // 1. Try local first - const local = classifyIntentLocal(input); - if (local.confidence >= 0.9) return local; - - // 2. Try AI if available - if (isAIAvailable()) { - try { - const ai = await classifyIntentAI(input); - return ai.confidence > local.confidence ? ai : local; - } catch (error) { - console.warn('AI classification failed, using local:', error); - return local; - } - } - - // 3. Return local result or unknown - return local.confidence >= 0.5 - ? local - : { intent: 'onbekend', confidence: 0, tier: 'local' }; - - } catch (error) { - // 4. Ultimate fallback - return { intent: 'onbekend', confidence: 0, tier: 'local' }; - } -}; -``` - ---- - -## 12. Implementatie Volgorde - -### Sprint 1: Foundation (Week 1) -- [ ] Zustand store setup -- [ ] Command Center layout -- [ ] Basic text input -- [ ] Local intent classifier -- [ ] Fallback picker - -### Sprint 2: Core Blocks (Week 2) -- [ ] DagnotatieBlock -- [ ] ZoekenBlock + `/api/patients/search` -- [ ] Patient pre-fill logic -- [ ] Voice input integratie - -### Sprint 3: Advanced (Week 3) -- [ ] AI intent fallback -- [ ] OverdrachtBlock (AI summary) -- [ ] RapportageBlock -- [ ] Keyboard shortcuts - -### Sprint 4: Polish (Week 4) -- [ ] Animaties & microinteracties -- [ ] Metrics dashboard -- [ ] Error handling refinement -- [ ] Demo scenario's - ---- - -## 13. Navigatie & Onboarding Flow - -### 13.1 User Journey Overzicht - -De toegang tot Swift verloopt via een duidelijke keuze op de login pagina, na storytelling op de landingspagina. - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ LANDINGSPAGINA β”‚ -β”‚ ───────────── β”‚ -β”‚ β”‚ -β”‚ β€’ Storytelling (probleem β†’ oplossing) β”‚ -β”‚ β€’ Interactive demo (probeer zonder login) β”‚ -β”‚ β€’ Side-by-side vergelijking (12 klikken vs 1 zin) β”‚ -β”‚ β€’ Video demo β”‚ -β”‚ β€’ CTA: "Aan de slag" β†’ gaat naar /login β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ LOGIN PAGINA β”‚ -β”‚ ─────────── β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [Bestaand login formulier] β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ ───────────────────────────────────────────────── β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Kies je werkwijze: β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β—‹ ✨ Swift β€” Spreek of typ, het systeem begrijpt β”‚ β”‚ -β”‚ β”‚ β—‹ πŸ“‹ Klassiek β€” Vertrouwde menu's en formulieren β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ ☐ Onthoud mijn keuze β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ [Inloggen] β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ β”‚ - β–Ό β–Ό - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ /epd/swift β”‚ β”‚ /epd/dashboardβ”‚ - β”‚ Command β”‚ β”‚ Klassiek EPD β”‚ - β”‚ Center β”‚ β”‚ met sidebar β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 13.2 Route Structuur - -| Route | Beschrijving | Layout | -|-------|--------------|--------| -| `/` | Landingspagina met storytelling | Marketing layout | -| `/login` | Login + interface keuze | Auth layout | -| `/epd/swift` | Swift Command Center | Swift layout (geen sidebar) | -| `/epd/dashboard` | Klassiek EPD dashboard | EPD layout (met sidebar) | -| `/epd/patients/...` | Klassiek patiΓ«nt routes | EPD layout (met sidebar) | - -### 13.3 Interface Keuze Logica - -```typescript -// lib/auth/interface-preference.ts - -export type InterfacePreference = 'swift' | 'classic'; - -export interface UserPreferences { - preferred_interface: InterfacePreference; - remember_choice: boolean; -} - -// Opslaan in Supabase user_metadata -export async function saveInterfacePreference( - supabase: SupabaseClient, - preference: InterfacePreference, - remember: boolean -) { - const { error } = await supabase.auth.updateUser({ - data: { - preferred_interface: preference, - remember_interface_choice: remember, - }, - }); - - if (error) throw error; -} - -// Ophalen bij login -export async function getInterfacePreference( - supabase: SupabaseClient -): Promise { - const { data: { user } } = await supabase.auth.getUser(); - - if (!user?.user_metadata?.remember_interface_choice) { - return null; // Toon keuze scherm - } - - return user.user_metadata.preferred_interface || null; -} -``` - -### 13.4 Login Form Uitbreiding - -```typescript -// app/login/components/login-form.tsx - -interface LoginFormData { - email: string; - password: string; - interface_choice: 'swift' | 'classic'; - remember_choice: boolean; -} - -// Na succesvolle login -const handleLoginSuccess = async (data: LoginFormData) => { - // Sla preference op - await saveInterfacePreference( - supabase, - data.interface_choice, - data.remember_choice - ); - - // Redirect naar gekozen interface - if (data.interface_choice === 'swift') { - router.push('/epd/swift'); - } else { - router.push('/epd/dashboard'); - } -}; -``` - -### 13.5 Redirect Middleware - -```typescript -// middleware.ts - -export async function middleware(request: NextRequest) { - const { pathname } = request.nextUrl; - - // Check of user ingelogd is - const supabase = createMiddlewareClient({ req: request }); - const { data: { session } } = await supabase.auth.getSession(); - - if (!session && pathname.startsWith('/epd')) { - return NextResponse.redirect(new URL('/login', request.url)); - } - - // Als user naar /epd gaat (zonder specifiek pad) - if (session && pathname === '/epd') { - const preference = session.user.user_metadata?.preferred_interface; - - if (preference === 'swift') { - return NextResponse.redirect(new URL('/epd/swift', request.url)); - } else if (preference === 'classic') { - return NextResponse.redirect(new URL('/epd/dashboard', request.url)); - } - - // Geen preference opgeslagen β†’ naar dashboard (default) - return NextResponse.redirect(new URL('/epd/dashboard', request.url)); - } - - return NextResponse.next(); -} -``` - -### 13.6 Admin Interface Management - -Alleen admins kunnen de interface preference van andere users aanpassen. - -```typescript -// app/api/admin/users/[userId]/interface/route.ts - -export async function PATCH( - request: NextRequest, - { params }: { params: { userId: string } } -) { - const supabase = await createClient(); - - // Check of huidige user admin is - const { data: currentUser } = await supabase.auth.getUser(); - const { data: practitioner } = await supabase - .from('practitioners') - .select('role') - .eq('user_id', currentUser?.user?.id) - .single(); - - if (practitioner?.role !== 'admin') { - return NextResponse.json({ error: 'Geen toegang' }, { status: 403 }); - } - - // Update target user's preference - const body = await request.json(); - const { interface_preference } = body; - - // Admin API call om user metadata te updaten - // (vereist service_role key) - await supabaseAdmin.auth.admin.updateUserById(params.userId, { - user_metadata: { preferred_interface: interface_preference }, - }); - - return NextResponse.json({ success: true }); -} -``` - -### 13.7 Geen Toggle in Interface - -Belangrijk: Er is **geen toggle** om te wisselen tussen Swift en Klassiek binnen de interfaces zelf. Dit voorkomt verwarring en zorgt voor een consistente ervaring. - -| Waar | Toggle aanwezig? | -|------|------------------| -| Landingspagina | N.v.t. (storytelling) | -| Login pagina | Ja (eenmalige keuze) | -| Swift interface | Nee | -| Klassiek EPD | Nee | -| Admin panel | Ja (per user instelling) | - -Om van interface te wisselen moet de gebruiker: -1. Uitloggen -2. Opnieuw inloggen -3. Andere keuze maken (als "onthoud" uit stond) - -Of een admin kan de preference aanpassen. - ---- - -## 14. Bijlagen & Referenties - -### Projectdocumenten -- [swift-prd.md](./swift-prd.md) - Product Requirements -- [swift-fo-ai.md](./swift-fo-ai.md) - Functioneel Ontwerp -- [swift-ux-v2.1.md](./swift-ux-v2.1.md) - UX/UI Specificaties -- [taken-en-vragen-analyse.md](./taken-en-vragen-analyse.md) - Intent Mapping - -### Tech Documentatie -- Next.js: https://nextjs.org/docs -- Supabase: https://supabase.com/docs -- Zustand: https://zustand-demo.pmnd.rs/ -- cmdk: https://cmdk.paco.me/ -- Deepgram: https://developers.deepgram.com/docs -- Claude API: https://docs.anthropic.com/ - -### Bestaande Codebase Referenties -- Command component: `components/ui/command.tsx` -- Speech streaming: `components/speech-recorder-streaming.tsx` -- Overdracht API: `app/api/overdracht/generate/route.ts` -- Report types: `lib/types/report.ts` diff --git a/docs/swift/bouwplan-swift-agenda-planning.md b/docs/swift/bouwplan-swift-agenda-planning.md deleted file mode 100644 index 39635e3..0000000 --- a/docs/swift/bouwplan-swift-agenda-planning.md +++ /dev/null @@ -1,757 +0,0 @@ -# Mission Control - Bouwplan - -Projectnaam: Swift Agenda Planning Module -Versie: v1.0 -Datum: 27-12-2025 -Auteur: Colin Lit - ---- - -## 1. Doel en context -Doel: een Swift Agenda Planning module bouwen waarmee gebruikers via chat afspraken kunnen opvragen, aanmaken, annuleren en verzetten, met een AgendaBlock artifact als visuele bevestiging. -Toelichting: dit bouwt voort op het Swift conversatie‑model en hergebruikt de klassieke agenda (`/app/epd/agenda`) als full view. De Swift‑variant focust op snelle queries en quick actions. - ---- - -## 2. Uitgangspunten - -### 2.1 Technische Stack -- Frontend: Next.js App Router + React + TypeScript -- Styling: Tailwind CSS + shadcn/ui components -- State: Zustand (Swift store) + React Query for data caching -- Backend: Next.js route handlers + Supabase (encounters table) -- AI/Intent: Two-tier system (Local regex <50ms + Claude Haiku fallback ~400ms) -- Date/Time: date-fns library (al aanwezig) -- Auth: Supabase Auth (server-side guard via `lib/auth/server.ts`) -- Voice: Deepgram (existing integration voor voice input) - -### 2.2 Projectkaders -- Scope (MVP): agenda_query, create_appointment, cancel_appointment, reschedule_appointment + AgendaBlock. -- Out of scope: drag-and-drop, recurring, availability, conflict resolution UI, multi-practitioner. -- Geen nieuwe dependencies zonder akkoord. -- Geen database migraties in MVP. -- Reuse bestaande agenda actions waar mogelijk. - -### 2.3 Programmeer uitgangspunten -- DRY: hergebruik `app/epd/agenda/actions.ts` (getEncounters, createEncounter, cancelEncounter, rescheduleEncounter). -- KISS: snelle API routes + simpele AgendaBlock UI. -- SOC: intent parsing, data fetching en UI gescheiden. -- YAGNI: alleen P1/P2 uit FO, geen extra planner features. - -### 2.4 Performance Targets -| Metric | Target | Actual (Expected) | -|--------|--------|-------------------| -| Local pattern match | <50ms | ~10-15ms | -| Local + entity extraction | <100ms | ~30-50ms | -| AI fallback (cold) | <800ms | ~400-600ms | -| AI fallback (warm) | <500ms | ~200-400ms | -| Total (local path) | <150ms | ~50-80ms | -| Total (AI path) | <1000ms | ~500-700ms | - -### 2.5 Confidence Thresholds -| Confidence | Actie | Voorbeeld | -|------------|-------|-----------| -| **>0.9** | Direct artifact openen met prefill | "afspraken vandaag" | -| **0.7-0.9** | Artifact + bevestigingsvraag | "maak afspraak jan morgen" (tijd ontbreekt) | -| **0.5-0.7** | Verduidelijkingsvraag in chat | "maak afspraak" (patient/tijd ontbreekt) | -| **<0.5** | Fallback: "Ik begrijp het niet" | Gibberish input | - ---- - -## 3. Epics & Stories Overzicht -| Epic ID | Titel | Doel | Status | Stories | Opmerkingen | -|---------|-------|------|--------|---------|-------------| -| E0 | Alignment & scope | MVP afbakenen en keuzes vastleggen | Done | 2 | FO‑based | -| E1 | Intent & entity layer | Agenda intents + entities toevoegen | Done | 4 | Swift intent stack | -| E2 | Date/time parsing | NLP‑helpers voor datum/tijd | Done | 3 | Geen nieuwe deps | -| E3 | Backend integratie | Agenda data APIs + reuse actions | Done | 4 | Auth vereist | -| E4 | AgendaBlock UI | List/create/cancel/reschedule views | Done | 5 | Swift artifact | -| E5 | Chat orchestration | Action routing + prompt update | Done | 3 | Swift chat API | -| E6 | QA & docs | Testplan + docs update | To Do | 3 | Manual QA | - ---- - -## 4. Epics & Stories (Uitwerking) - -### Epic 0 β€” Alignment & scope -Epic doel: MVP scope, UX flows en beslissingen vastleggen. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E0.S1 | Scope + out-of-scope vastleggen | P1/P2 lijst bevestigd, OOS lijst bevestigd | Done | - | 1 | -| E0.S2 | UX flow beschrijven | Entry/exit, artifact gedrag en fallback flows gedocumenteerd | Done | E0.S1 | 2 | - -UX flow (MVP): -- Entry: user is in Swift chat; agenda intents open AgendaBlock when confidence >= 0.7. -- Exit: close artifact via tab close; for full view use link to `/epd/agenda` from the AgendaBlock footer. -- Queries: default to today when clear; ask a clarification question when date range is missing or ambiguous. -- Create: require patient + date + time; use active patient when user says "deze patient"; otherwise ask in chat. -- Cancel/reschedule: if multiple matches, show disambiguation list in AgendaBlock; confirm before final action. -- Fallback: if intent confidence < 0.7, keep artifact closed and ask for missing details. - ---- - -### Epic 1 β€” Intent & entity layer -Epic doel: agenda intent types en entities toevoegen aan Swift. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E1.S1 | SwiftIntent uitbreiden | Agenda intent names toegevoegd in types/store | Done | E0.S1 | 2 | -| E1.S2 | Local intent patterns | Regex patterns voor agenda intents in `intent-classifier.ts` | Done | E1.S1 | 3 | -| E1.S3 | AI fallback prompt | Prompt in `intent-classifier-ai.ts` uitgebreid met agenda intents | Done | E1.S1 | 3 | -| E1.S4 | Entities schema | `ExtractedEntities` uitgebreid met date/time/identifier | Done | E1.S1 | 2 | - -**Technical notes:** - -**E1.S1 - SwiftIntent type uitbreiding:** -- File: `lib/swift/types.ts` -- Houd `SwiftIntent` single source of truth (voorkom duplicatie). -- SwiftIntent (na uitbreiding): - ```ts - type SwiftIntent = - | 'dagnotitie' - | 'zoeken' - | 'overdracht' - | 'agenda_query' // πŸ†• - | 'create_appointment' // πŸ†• - | 'cancel_appointment' // πŸ†• - | 'reschedule_appointment'// πŸ†• - | 'unknown'; - ``` - -**E1.S2 - Local pattern examples:** -- File: `lib/swift/intent-classifier.ts` -- Toevoegen aan `INTENT_PATTERNS`: - ```ts - agenda_query: [ - { pattern: /^afspraken?\\b/i, weight: 1.0 }, - { pattern: /^agenda\\b/i, weight: 1.0 }, - { pattern: /^(wat|wanneer)\\s+is\\s+(mijn\\s+)?volgende\\s+afspraak/i, weight: 1.0 }, - ], - create_appointment: [ - { pattern: /^maak\\s+afspraak\\b/i, weight: 1.0 }, - { pattern: /^plan\\s+(een\\s+)?(intake|afspraak)\\b/i, weight: 1.0 }, - ], - cancel_appointment: [ - { pattern: /^annuleer\\s+(de\\s+)?afspraak/i, weight: 1.0 }, - ], - reschedule_appointment: [ - { pattern: /^verzet\\s+(de\\s+)?afspraak/i, weight: 1.0 }, - { pattern: /^\\d{1,2}:\\d{2}\\s+naar\\s+\\d{1,2}:\\d{2}/i, weight: 0.9 }, - ], - ``` - -**E1.S3 - AI System Prompt addition:** -- File: `lib/swift/intent-classifier-ai.ts` -- Toevoegen aan `INTENT_CLASSIFIER_SYSTEM_PROMPT`: - - Agenda intent descriptions + voorbeelden - - Entity extraction instructies (patientName, dateRange, datetime, type, identifier, newDatetime) - - Response format met nieuwe entities - -**E1.S4 - ExtractedEntities uitbreiding:** -- File: `lib/swift/types.ts` -- Toevoegen: - ```ts - interface ExtractedEntities { - // Bestaande entities - patientName?: string; - category?: VerpleegkundigCategory; - content?: string; - - // πŸ†• Agenda entities - dateRange?: { - start: Date; - end: Date; - label: 'vandaag' | 'morgen' | 'deze week' | 'volgende week' | 'custom'; - }; - datetime?: { - date: Date; - time: string; // "HH:mm" format - }; - appointmentType?: 'intake' | 'behandeling' | 'follow-up' | 'telefonisch' | - 'huisbezoek' | 'online' | 'crisis' | 'overig'; - location?: 'praktijk' | 'online' | 'thuis'; - identifier?: { - type: 'patient' | 'time' | 'both'; - patientName?: string; - patientId?: string; - time?: string; - date?: Date; - encounterId?: string; - }; - newDatetime?: { - date: Date; - time: string; - }; - } - ``` - ---- - -### Epic 2 β€” Date/time parsing -Epic doel: datum/tijd interpretatie uit natuurlijke taal. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E2.S1 | Date parser utility | `lib/swift/date-time-parser.ts` met relatieve datums | Done | E1.S4 | 3 | -| E2.S2 | Time parser utility | Tijd normalisatie (14:00, half drie) | Done | E2.S1 | 2 | -| E2.S3 | Entity extraction hook | Entity extractor gebruikt parser output | Done | E2.S2 | 2 | - -**Technical notes:** - -**E2.S1 - Date parser implementation:** -- File: `lib/swift/date-time-parser.ts` -- Functie: `parseRelativeDate(input: string): Date | DateRange | null` -- Ondersteunt: - - "vandaag", "morgen", "overmorgen" - - "maandag", "dinsdag", ... (next weekday) - - "deze week", "volgende week" (returns DateRange) - - Fallback naar date-fns `parse()` voor "30 december", "28-12-2024" -- Gebruik `date-fns` helpers: `addDays()`, `startOfWeek()`, `endOfWeek()`, `addWeeks()` - -**E2.S2 - Time parser implementation:** -- Functie: `parseTime(input: string): string | null` -- Ondersteunt: - - "14:00" β†’ "14:00" - - "14" β†’ "14:00" - - "twee uur" β†’ "14:00" - - "half drie" β†’ "14:30" - - "kwart voor drie" β†’ "14:45" -- Returns `HH:mm` format string - -**E2.S3 - Integration:** -- Parser functies worden aangeroepen in entity extraction flow -- Local pattern matching extraheert ruwe strings ("morgen", "14:00") -- Parser functies normaliseren naar Date/time formats -- AI fallback gebruikt parser voor validation - ---- - -### Epic 3 β€” Backend integratie -Epic doel: agenda data ontsluiten voor Swift blocks. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E3.S1 | Agenda query API | Endpoint voor afspraken op datumrange (auth) | Done | E1.S4 | 3 | -| E3.S2 | Create appointment API | Endpoint die `createEncounter` aanroept | Done | E3.S1 | 3 | -| E3.S3 | Cancel/reschedule API | Endpoints die `cancelEncounter`/`rescheduleEncounter` aanroepen | Done | E3.S1 | 3 | -| E3.S4 | Patient match API | Fuzzy patiΓ«nt matching + disambiguation lijst | Done | E1.S4 | 2 | - -**Technical notes:** - -**E3.S1 - Agenda query endpoint:** -- Route: `GET /api/swift/agenda?start=2024-12-27&end=2024-12-27` -- Auth: via `createClient()` from `lib/auth/server.ts` -- Hergebruik: `getEncounters()` from `app/epd/agenda/actions.ts` -- Response: `{ appointments: Encounter[] }` -- Filters: practitioner_id = current user, status = 'planned', period_start in range -- Order: chronological (period_start ASC) - -**E3.S2 - Create appointment endpoint:** -- Route: `POST /api/swift/agenda/create` -- Body: `{ patientId, datetime: { date, time }, type, location, notes? }` -- Validation: Zod schema, Dutch error messages -- Hergebruik: `createEncounter()` from `app/epd/agenda/actions.ts` -- Mapping: - - type β†’ typeCode (FHIR encounter type) - - location β†’ classCode ('AMB' = praktijk, 'VR' = online, 'HH' = thuis) - - datetime β†’ periodStart/periodEnd (1 hour duration default) -- Response: `{ encounterId, success: true }` - -**E3.S3 - Cancel/Reschedule endpoints:** -- Route: `POST /api/swift/agenda/cancel` -- Body: `{ encounterId }` -- Hergebruik: `cancelEncounter(encounterId)` (soft delete: status β†’ 'cancelled') - -- Route: `POST /api/swift/agenda/reschedule` -- Body: `{ encounterId, newDatetime: { date, time } }` -- Hergebruik: `rescheduleEncounter(encounterId, periodStart, periodEnd)` - -**E3.S4 - Patient search endpoint:** -- Route: `GET /api/swift/patients/search?q=jan` -- Fuzzy match op patient name (ILIKE %query%) -- Response: `{ patients: Array<{ id, name, bsn }> }` -- Limit: 10 resultaten -- Used voor: disambiguation bij meerdere matches - ---- - -### Epic 4 β€” AgendaBlock UI -Epic doel: Swift artifact voor agenda flows. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E4.S1 | AgendaBlock skeleton | Block met tabs/modes (list/create/cancel/reschedule) | Done | E3.S1 | 3 | -| E4.S2 | List view | Lijst met afspraken + empty state | Done | E4.S1 | 3 | -| E4.S3 | Create form | Prefill + validatie + submit | Done | E4.S1 | 5 | -| E4.S4 | Cancel view | Disambiguation + confirm flow | Done | E4.S1 | 3 | -| E4.S5 | Reschedule view | Edit form met nieuwe tijd | Done | E4.S1 | 3 | - -**Technical notes:** - -**E4.S1 - AgendaBlock component structure:** -- File: `components/swift/artifacts/blocks/agenda-block.tsx` -- Props interface: - ```ts - interface AgendaBlockProps { - mode: 'list' | 'create' | 'cancel' | 'reschedule'; - appointments?: Encounter[]; - dateRange?: { start: Date; end: Date; label: string }; - prefillData?: { - patient?: { id: string; name: string }; - datetime?: { date: Date; time: string }; - type?: EncounterType; - location?: EncounterLocation; - }; - disambiguationOptions?: Encounter[]; - onClose?: () => void; - } - ``` -- Architecture: switch statement op mode β†’ render juiste sub-component -- Styling: max-width 600px, max-height 80vh, overflow-y auto - -**E4.S2 - List view:** -- Component: `` -- Layout: - - Header: Datum label (e.g., "Afspraken Vandaag - 27 december") + close button - - Body: Scrollable lijst van appointment cards - - Footer: Link naar `/epd/agenda` ("πŸ“… Open volledige agenda β†’") -- Appointment card bevat: - - Tijd (09:00 - 10:00) - - Patient naam (klikbaar β†’ opens PatientContextCard) - - Type badge met color coding (intake=blauw, behandeling=groen, crisis=rood) - - Locatie icon (πŸ“ Praktijk, 🌐 Online, 🏠 Thuis) - - Actions: [Details] [Annuleren] -- Empty state: "πŸ“­ Geen afspraken gevonden" + [Maak nieuwe afspraak] button - -**E4.S3 - Create form:** -- Component: `` -- Fields: - - PatiΓ«nt* (autocomplete, pre-filled) - - Datum* (date picker, pre-filled) - - Tijd* (time picker 07:00-20:00, pre-filled) - - Type* (radio buttons: Intake, Behandeling, Vervolg, Telefonisch, Huisbezoek, Crisis) - - Locatie* (radio buttons: Praktijk, Online, Thuis) - - Notities (textarea, optioneel, max 500 chars) -- Validation: - - Patient required - - Date cannot be in past - - Time within 07:00-20:00 -- Conflict warning: "⚠️ Conflict: Je hebt al een afspraak om 14:00 met Marie" (optional feature) -- Submit: [Annuleren] [βœ“ Afspraak maken] -- States: initial β†’ validating β†’ submitting β†’ success/error - -**E4.S4 - Cancel view:** -- Component: `` -- Submode 1: Disambiguation (multiple matches) - - Radio list met opties: "β—‹ 28-12-2024 09:00 - Jan de Vries (Intake)" - - [Annuleren] [Volgende β†’] buttons -- Submode 2: Confirmation (single match or after disambiguation) - - Appointment details card - - Warning: "⚠️ Deze actie kan niet ongedaan worden gemaakt." - - [Terug] [βœ“ Annuleren] buttons - -**E4.S5 - Reschedule view:** -- Component: `` -- Layout: - - Afspraak details (readonly) - - Huidige datum/tijd (readonly, strikethrough styling) - - Nieuwe datum/tijd* (editable date + time pickers, pre-filled) - - Conflict check: "βœ… Geen conflicten gevonden" or warning - - [Annuleren] [βœ“ Verzetten] buttons - -**Styling specs:** -- Colors: Teal-700 primary, appointment type badges (zie FO sectie 13.3) -- Animations: slide-in from right 200ms, fade-out on close -- Typography: text-sm voor body, text-base voor headers -- Spacing: 16px padding, 12px card gaps - ---- - -### Epic 5 β€” Chat orchestration -Epic doel: agenda intents laten landen in juiste artifact. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E5.S1 | Action routing | Agenda intents openen AgendaBlock met juiste mode | Done | E4.S1 | 2 | -| E5.S2 | Chat prompt update | `/api/swift/chat` prompt bevat agenda sectie + action format | Done | E1.S3 | 2 | -| E5.S3 | Error states | User-friendly errors + link naar `/epd/agenda` | Done | E3.S1 | 2 | - -**Technical notes:** - -**E5.S1 - Intent router implementation:** -- Location: Swift store of artifact manager -- Functie: `openArtifactForIntent(intent, entities, confidence)` -- Logic: - ```ts - if (confidence < 0.7) return null; // Trigger verduidelijkingsvraag - - switch (intent) { - case 'agenda_query': - return { type: 'AgendaBlock', mode: 'list', prefill: { dateRange } }; - case 'create_appointment': - if (!entities.patientName) return null; // Need patient - return { type: 'AgendaBlock', mode: 'create', prefill: { patient, datetime, type, location } }; - case 'cancel_appointment': - return { type: 'AgendaBlock', mode: 'cancel', prefill: { identifier } }; - case 'reschedule_appointment': - if (!entities.identifier) return null; // Need to know which appointment - return { type: 'AgendaBlock', mode: 'reschedule', prefill: { identifier, newDatetime } }; - } - ``` - -**E5.S2 - Chat API system prompt addition:** -- File: `app/api/swift/chat/route.ts` -- Toevoegen aan system prompt: - ```markdown - ## Agenda & Afspraken Beheer - - Je helpt gebruikers met agenda-gerelateerde taken. - - ### Intents die je herkent: - 1. **agenda_query** - Afspraken opvragen - Voorbeelden: "afspraken vandaag", "wat is volgende", "agenda morgen" - Actie: Toon lijst van afspraken in AgendaBlock - - 2. **create_appointment** - Nieuwe afspraak maken - Voorbeelden: "maak afspraak met Jan morgen 14:00", "plan intake" - Required: patient, date, time - Optional: type (default: behandeling), location (default: praktijk) - - 3. **cancel_appointment** - Afspraak annuleren - Voorbeelden: "annuleer afspraak Jan", "cancel 14:00" - Actie: Toon confirmation dialog - - 4. **reschedule_appointment** - Afspraak verzetten - Voorbeelden: "verzet 14:00 naar 15:00", "verzet Jan naar dinsdag" - Actie: Toon edit form met oude + nieuwe tijd - - ### Entity Extraction: - - Patient: extraheer volledige naam, gebruik activePatient als user zegt "deze patiΓ«nt" - - Date/Time: parse relatieve datums ("morgen", "dinsdag"), validate geen verleden - - Type: intake, behandeling, follow-up, telefonisch (default: behandeling) - - Location: praktijk, online, thuis (default: praktijk) - - ### Verduidelijkingsvragen: - Stel vragen bij: - - Meerdere patiΓ«nten met zelfde naam - - Onduidelijke datum - - Ontbrekende tijd bij create - - Meerdere matches bij cancel/reschedule - ``` - -**E5.S3 - Error handling:** -- Server errors: "Er ging iets mis bij het ophalen van je afspraken. Probeer het opnieuw of [open de volledige agenda](/epd/agenda)." -- Auth errors: Redirect naar `/login` -- Validation errors: Dutch messages ("Datum kan niet in het verleden liggen") -- Network errors: Retry logic + user-friendly message - ---- - -### Epic 6 β€” QA & docs -Epic doel: kwaliteit borgen en documentatie updaten. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E6.S1 | Manual test checklist | Scenarios uit FO opgenomen | To Do | E5.S3 | 2 | -| E6.S2 | Docs update | Bouwplan + release note bijgewerkt | To Do | E6.S1 | 1 | -| E6.S3 | Regression checks | Swift en klassieke agenda blijven werken | To Do | E6.S1 | 2 | - ---- - -## 5. Kwaliteit & Testplan - -Test types: -| Test Type | Scope | Tools | Verantwoordelijke | -|-----------|-------|-------|-------------------| -| Lint | App code | pnpm lint | Developer | -| Type check | TypeScript | pnpm build | Developer | -| Smoke tests | Agenda intents + artifact flows | Manual checklist (20 scenarios) | Developer/UX | -| Regression | /epd/agenda klassiek | Manual checklist | Developer | - -### Manual Test Checklist (uit FO, 20 scenarios): - -| # | Scenario | Expected Result | Priority | Status | -|---|----------|-----------------|----------|--------| -| 1 | "afspraken vandaag" | AgendaBlock list view, toont vandaag's afspraken | P1 | ⬜ | -| 2 | "wat is volgende afspraak" | Chat response met eerstvolgende, AgendaBlock toont details | P1 | ⬜ | -| 3 | "maak afspraak jan morgen 14:00" | Create form met prefill, patient gevonden | P1 | ⬜ | -| 4 | Voice: "maak intake marie vrijdag 10:00" | Transcript correct, create form opent | P2 | ⬜ | -| 5 | "maak afspraak" (incomplete) | Verduidelijkingsvraag: "Met welke patiΓ«nt?" | P1 | ⬜ | -| 6 | "maak afspraak onbekende patient" | Patient search fallback, suggesties | P2 | ⬜ | -| 7 | Create form submit β†’ success | Toast, chat confirmation, artifact sluit | P1 | ⬜ | -| 8 | "annuleer afspraak jan" (1 match) | Confirmation dialog, direct match | P1 | ⬜ | -| 9 | "annuleer afspraak jan" (3 matches) | Disambiguation radio list | P1 | ⬜ | -| 10 | Cancel confirm β†’ success | Afspraak status=cancelled, toast | P1 | ⬜ | -| 11 | "verzet 14:00 naar 15:00" | Reschedule form, tijd pre-filled | P1 | ⬜ | -| 12 | Reschedule submit β†’ success | Tijd updated, toast confirmation | P1 | ⬜ | -| 13 | Conflict warning (overlapping) | Warning banner in create form | P2 | ⬜ | -| 14 | Click patient name in list | PatientContextCard opent | P2 | ⬜ | -| 15 | Click "Details" button | Navigates to /epd/agenda with filter | P2 | ⬜ | -| 16 | Empty state (geen afspraken) | Placeholder met "Maak nieuwe afspraak" | P1 | ⬜ | -| 17 | Server error tijdens query | Error in chat, geen artifact | P1 | ⬜ | -| 18 | Date in past validation | "Kan geen afspraken in verleden maken" | P1 | ⬜ | -| 19 | Context-aware: "maak afspraak deze patient" | Gebruikt active patient uit context | P2 | ⬜ | -| 20 | Multiple artifacts (3 max) | Agenda + Dagnotitie + Context card, tabs | P2 | ⬜ | - -### Regression Test Checklist: - -| # | Test | Expected Result | Status | -|---|------|-----------------|--------| -| R1 | Klassieke agenda `/epd/agenda` werkt nog | Kan afspraken zien/maken/wijzigen | ⬜ | -| R2 | Swift dagnotitie intent ongewijzigd | "dagnotitie jan medicatie" opent DagnotatieBlock | ⬜ | -| R3 | Swift zoeken intent ongewijzigd | "zoek jan" opent ZoekenBlock | ⬜ | -| R4 | Swift overdracht intent ongewijzigd | "overdracht" opent OverdrachtBlock | ⬜ | -| R5 | Auth guard op alle endpoints | Geen auth β†’ 401/redirect | ⬜ | - -### Performance Test Targets: - -| Metric | Target | Test Method | -|--------|--------|-------------| -| Local pattern match | <50ms | Browser DevTools Network tab | -| Create form open | <150ms total | Lighthouse/manual timing | -| AI fallback | <1000ms | DevTools, onduidelijke input | -| List view render (10 items) | <100ms | React DevTools Profiler | - ---- - -## 6. User Stories (uit FO) - -### Primaire User Stories (P1 - MVP): - -| ID | Als | Wil ik | Zodat | Acceptatie | -|----|-----|--------|-------|------------| -| US-24 | Verpleegkundige | Snel overzicht afspraken vandaag | Ik weet waar ik moet zijn | "afspraken vandaag" β†’ lijst in AgendaBlock, <3 sec | -| US-25 | Verpleegkundige | Check volgende afspraak tijdens werk | Ik op tijd ben | "wat is mijn volgende afspraak?" β†’ directe info | -| US-27 | Verpleegkundige | Snelle afspraak tijdens telefoongesprek | Ik direct kan plannen | "maak afspraak jan morgen 14:00" β†’ prefilled form, <15 sec | -| US-28 | Verpleegkundige | Context-aware planning | Ik niet steeds naam hoef te typen | "maak afspraak met deze patiΓ«nt" β†’ gebruikt actieve patiΓ«nt | -| US-29 | Verpleegkundige | Voice input tijdens consult | Ik hands-free kan werken | Spraak β†’ afspraak maken | -| US-30 | Verpleegkundige | Annuleren via chat | Ik snel kan annuleren | "annuleer afspraak jan" β†’ confirmation β†’ done | -| US-31 | Verpleegkundige | Snel verzetten | Ik afspraken flexibel kan aanpassen | "verzet 14:00 naar 15:00" β†’ tijd update | - -### Secundaire User Stories (P2 - Nice to Have): - -| ID | Als | Wil ik | Zodat | Acceptatie | -|----|-----|--------|-------|------------| -| US-26 | Verpleegkundige | Weekoverzicht bekijken | Ik kan plannen | "agenda deze week" β†’ gefilterde lijst | -| US-32 | Verpleegkundige | Disambiguation bij meerdere matches | Systeem helpt kiezen | Systeem vraagt "Welke Jan?" β†’ lijst opties | - ---- - -## 7. File Structuur (na implementatie) - -``` -lib/swift/ -β”œβ”€β”€ types.ts # SwiftIntent + ExtractedEntities uitbreidingen -β”œβ”€β”€ intent-classifier.ts # Local patterns voor agenda intents -β”œβ”€β”€ intent-classifier-ai.ts # AI prompt uitbreidingen -└── date-time-parser.ts # πŸ†• Date/time parsing utilities - -app/api/swift/ -β”œβ”€β”€ agenda/ -β”‚ β”œβ”€β”€ route.ts # πŸ†• GET agenda query endpoint -β”‚ β”œβ”€β”€ create/route.ts # πŸ†• POST create appointment -β”‚ β”œβ”€β”€ cancel/route.ts # πŸ†• POST cancel appointment -β”‚ └── reschedule/route.ts # πŸ†• POST reschedule appointment -β”œβ”€β”€ patients/ -β”‚ └── search/route.ts # πŸ†• GET fuzzy patient search -└── chat/route.ts # Updated: agenda system prompt - -components/swift/artifacts/blocks/ -β”œβ”€β”€ agenda-block.tsx # πŸ†• Main AgendaBlock component -β”œβ”€β”€ agenda-list-view.tsx # πŸ†• List mode -β”œβ”€β”€ agenda-create-form.tsx # πŸ†• Create mode -β”œβ”€β”€ agenda-cancel-view.tsx # πŸ†• Cancel mode -└── agenda-reschedule-form.tsx # πŸ†• Reschedule mode - -app/epd/agenda/ -└── actions.ts # ♻️ Hergebruikt (getEncounters, createEncounter, etc.) -``` - ---- - -## 8. Demo & Presentatieplan -Doel: korte demo van agenda planning via Swift (5 minuten). - -**Demo Flow:** -1. **Agenda query**: "afspraken vandaag" β†’ lijst met 3 afspraken -2. **Quick create**: "maak afspraak met Jan morgen 14:00" β†’ create form β†’ submit β†’ success toast -3. **Cancel flow**: "annuleer afspraak Jan" β†’ disambiguation (3 matches) β†’ select β†’ confirm β†’ success -4. **Reschedule**: "verzet de 14:00 naar 15:00" β†’ edit form β†’ submit β†’ success -5. **Fallback**: Link naar klassieke agenda tonen via footer - -**Key Messaging:** -- Swift = snelle queries en actions (10-15 sec) -- Klassieke agenda = visuele planning en overzicht -- Voice input = hands-free werken tijdens consult - ---- - -## 9. Risico's & Mitigatie -| Risico | Kans | Impact | Mitigatie | Owner | -|--------|------|--------|-----------|-------| -| Intent ambigu | Hoog | Middel | Disambiguation + fallback prompt | UX | -| Date/time parsing faalt | Middel | Middel | AI fallback + clear prompts | Dev | -| API auth issues | Laag | Hoog | Central auth guard + error messaging | Dev | -| Scope creep | Hoog | Middel | MVP guardrails | PO | - ---- - -## 10. Sprint Planning & Implementatie Volgorde - -### Voorgestelde Sprint Indeling (3 sprints): - -**Sprint 1: Foundation (E1 + E2)** -- Focus: Intent layer + date/time parsing -- Stories: E1.S1, E1.S2, E1.S3, E1.S4, E2.S1, E2.S2, E2.S3 -- Total: 17 SP -- Oplevering: Intent detection + entity extraction werkend, nog geen UI -- Test: Console log check van extracted entities - -**Sprint 2: Backend + UI Foundation (E3 + E4.S1-S2)** -- Focus: API endpoints + AgendaBlock basis -- Stories: E3.S1, E3.S2, E3.S3, E3.S4, E4.S1, E4.S2 -- Total: 14 SP -- Oplevering: Agenda query werkend met list view -- Test: "afspraken vandaag" end-to-end - -**Sprint 3: UI Completion + Integration (E4.S3-S5 + E5 + E6)** -- Focus: Create/cancel/reschedule forms + orchestration -- Stories: E4.S3, E4.S4, E4.S5, E5.S1, E5.S2, E5.S3, E6.S1, E6.S2, E6.S3 -- Total: 20 SP -- Oplevering: MVP compleet -- Test: Alle 20 test scenarios - -**Total MVP: 51 SP (~3 sprints Γ  2 weken = 6 weken)** - -### Implementatie Volgorde (binnen stories): - -Voor elke story, volg deze volgorde: -1. **Types first**: Definieer interfaces/types -2. **Backend**: API endpoints + server actions -3. **Frontend**: UI components -4. **Integration**: Wire backend ↔ frontend -5. **Test**: Manual test scenario's - -### Critical Path: -``` -E1.S1 (types) β†’ E1.S2 (patterns) β†’ E1.S4 (entities) β†’ E2 (parsers) β†’ -E3.S1 (query API) β†’ E4.S1 (skeleton) β†’ E4.S2 (list view) β†’ -E5.S1 (routing) β†’ Milestone: Basic Query Werkend - -E3.S2 (create API) β†’ E4.S3 (create form) β†’ Milestone: Create Werkend - -E3.S3 (cancel API) β†’ E4.S4 (cancel view) β†’ Milestone: Cancel Werkend - -E4.S5 (reschedule) β†’ E5.S2 (prompt) β†’ E6 (QA) β†’ MVP Done -``` - ---- - -## 11. Evaluatie & Lessons Learned -Te documenteren na oplevering: -- Welke intents vaak misclassificeren? -- Hoe snel users afspraken kunnen plannen? -- Zijn extra agenda features nodig? - ---- - -## 12. Referenties & Documentatie - -### Primaire Documenten: -- **FO Agenda Afspraken**: `docs/swift/fo-agenda-afspraken.md` - Gebruikersgericht FO -- **FO Agenda Planning**: `docs/swift/fo-swift-agenda-planning.md` - Technisch FO met detailed specs -- **Swift FO v3**: `docs/swift/fo-swift-medical-scribe-v3.md` - Basis conversational interface -- **Swift Bouwplan Core**: `docs/swift/bouwplan-swift-standalone-module.md` - Development roadmap - -### Code Referenties: -- **Bestaande Agenda**: `app/epd/agenda` - Klassieke kalender (wordt hergebruikt) -- **Agenda Actions**: `app/epd/agenda/actions.ts` - Server actions (getEncounters, createEncounter, etc.) -- **Swift Chat API**: `app/api/swift/chat/route.ts` - Conversational endpoint -- **Intent Classifier**: `lib/swift/intent-classifier.ts` - Local pattern matching -- **AI Classifier**: `lib/swift/intent-classifier-ai.ts` - Claude Haiku fallback -- **Swift Types**: `lib/swift/types.ts` - SwiftIntent & ExtractedEntities - -### Libraries & Dependencies: -- **date-fns**: Date/time utilities (already installed) -- **Zod**: API validation schemas (already installed) -- **React Query**: Data caching (already installed) -- **shadcn/ui**: UI components (already installed) -- **Deepgram**: Voice input (already integrated) - -### External References: -- [FHIR Encounter Resource](https://www.hl7.org/fhir/encounter.html) - Encounter data model -- [date-fns Documentation](https://date-fns.org/) - Date manipulation -- [React Query Best Practices](https://tanstack.com/query/latest) - Caching patterns - ---- - -## 13. Glossary & Abbreviations - -| Term | Betekenis | -|------|-----------| -| **Epic** | Grote feature of fase, bevat meerdere stories | -| **Story** | Kleine uitvoerbare taak (user story) | -| **SP** | Story Points - schatting van complexiteit | -| **MVP** | Minimum Viable Product | -| **FO** | Functioneel Ontwerp | -| **P1/P2** | Priority 1 (must have) / Priority 2 (nice to have) | -| **SSE** | Server-Sent Events | -| **RLS** | Row Level Security (Supabase) | -| **NLP** | Natural Language Processing | -| **Artifact** | Swift UI component (AgendaBlock, DagnotatieBlock, etc.) | -| **Intent** | Gebruikersintentie (agenda_query, create_appointment, etc.) | -| **Entity** | GeΓ«xtraheerde data uit user input (patient, date, time) | -| **Disambiguation** | Verduidelijking bij meerdere matches | -| **Confidence** | Zekerheid van intent classificatie (0.0-1.0) | -| **Two-tier** | Local pattern matching + AI fallback systeem | -| **FHIR** | Fast Healthcare Interoperability Resources | -| **Encounter** | Afspraak/contact in FHIR terminologie | - -### Domain-Specific Terms: - -| Term | Betekenis | -|------|-----------| -| **Klassieke Agenda** | Bestaande visuele kalender in `/epd/agenda` | -| **Swift Agenda** | Nieuwe conversational agenda interface | -| **AgendaBlock** | Swift artifact voor agenda functionaliteit | -| **Verpleegkundige** | Primaire gebruikersrol (nurse/healthcare provider) | -| **Practitioner** | FHIR term voor zorgverlener | -| **Quick Create** | Snel afspraak maken via natuurlijke taal | -| **Hands-free** | Werken met voice input (geen typen nodig) | - ---- - -## Versiehistorie - -| Versie | Datum | Auteur | Wijziging | -|--------|-------|--------|-----------| -| v1.0 | 27-12-2025 | Colin Lit | Initiele versie - basis epics en stories | -| v1.1 | 27-12-2025 | Claude Code | Uitgebreid met technische details uit FO's: patterns, entities, API specs, UI components, test scenarios, sprint planning, file structuur | - ---- - -## Quick Reference Card - -**Voor Developers - Start Here:** -1. Lees Epic 0 voor scope -2. Begin met E1.S1 (types uitbreiden) -3. Volg implementatie volgorde (sectie 10) -4. Check test scenarios (sectie 5) -5. Zie file structuur (sectie 7) voor waar code moet komen - -**Voor Product Owners:** -- MVP scope: sectie 2.2 -- User stories: sectie 6 -- Demo plan: sectie 8 -- Risico's: sectie 9 - -**Voor QA:** -- Test checklist: sectie 5 (20 scenarios) -- Regression tests: sectie 5 -- Performance targets: sectie 2.4 - -**Voor Designers:** -- UI components: Epic 4 technical notes -- Styling specs: E4.S1-E4.S5 -- User flows: FO documenten (zie sectie 12) diff --git a/docs/swift/bouwplan-swift-diagnostiek-workflow-beoordeling.md b/docs/swift/bouwplan-swift-diagnostiek-workflow-beoordeling.md deleted file mode 100644 index 8035b44..0000000 --- a/docs/swift/bouwplan-swift-diagnostiek-workflow-beoordeling.md +++ /dev/null @@ -1,700 +0,0 @@ -# πŸ“‹ Beoordeling Bouwplan Swift: Diagnostiek Workflow - -**Datum:** 23-12-2024 -**Beoordelaar:** AI Code Review -**Versie:** v1.0 - ---- - -## Executive Summary - -**Algemene Beoordeling:** βœ… **HAALBAAR met enkele kritieke aanvullingen** - -Het bouwplan is goed gestructureerd en bouwt slim voort op bestaande componenten. De geschatte 21 story points voor 2 weken zijn realistisch, maar er zijn enkele belangrijke technische hiaten die eerst opgelost moeten worden voordat de implementatie kan starten. - -**Kritieke Bevindingen:** -1. ❌ **Report type "diagnostiek" ontbreekt** in `REPORT_TYPES` enum -2. ❌ **Swift intent types** moeten uitgebreid worden met nieuwe intents -3. ⚠️ **Entity extraction** voor datum/tijd parsing ontbreekt in plan -4. ⚠️ **Intake selectie** voor diagnoses niet duidelijk uitgewerkt -5. βœ… **Hergebruik componenten** is goed geanalyseerd en realistisch - -**Blokkerende Bevindingen (Swift Foundation - 24-12-2024):** -6. πŸ”΄ **E2.S5 Input β†’ Block wiring ontbreekt** - handleSubmit is placeholder -7. πŸ”΄ **CanvasArea block rendering ontbreekt** - Blocks worden niet gerenderd -8. πŸ”΄ **P1 Blocks (E3) niet geΓ―mplementeerd** - DagnotatieBlock, ZoekenBlock, OverdrachtBlock bestaan niet -9. ⚠️ **Type duplicatie** - SwiftIntent in zowel types.ts als swift-store.ts - ---- - -## 1. Compleetheid Analyse - -### 1.1 βœ… Sterke Punten - -**Goed Gedocumenteerd:** -- Duidelijke epic/story breakdown met acceptatiecriteria -- Realistische effort schattingen (21 SP voor 2 weken) -- Goede referenties naar bestaande code -- Testplan met concrete checklists -- Risico analyse met mitigaties - -**Technische Analyse:** -- Correcte identificatie van hergebruikbare componenten -- Wrapper pattern goed uitgelegd -- API routes strategie is logisch - -### 1.2 ❌ Ontbrekende Elementen - -#### Kritiek: Report Type "diagnostiek" - -**Probleem:** -Het bouwplan noemt het toevoegen van report type "diagnostiek" (regel 179), maar dit type bestaat niet in de `REPORT_TYPES` enum. - -**Huidige situatie:** -```typescript -// lib/types/report.ts -export const REPORT_TYPES = [ - 'voortgang', 'observatie', 'incident', 'medicatie', 'contact', - 'crisis', 'intake', 'behandeladvies', 'vrije_notitie', 'verpleegkundig' -] as const; -``` - -**Impact:** -- Database validatie zal falen bij POST `/api/reports` met type "diagnostiek" -- Zod schema moet uitgebreid worden -- Mogelijk database constraint check nodig - -**Aanbeveling:** -Voeg story toe: **E-D1.S0: Report type "diagnostiek" toevoegen** (1 SP) -- Update `REPORT_TYPES` enum -- Update Zod schema `CreateReportSchema` -- Database migratie indien nodig (check constraints) - -#### Kritiek: Swift Intent Types Uitbreiding - -**Probleem:** -Het bouwplan beschrijft nieuwe intent patterns, maar de `SwiftIntent` type definitie moet uitgebreid worden. - -**Huidige situatie:** -```typescript -// lib/swift/types.ts -export type SwiftIntent = 'dagnotitie' | 'zoeken' | 'overdracht' | 'unknown'; -``` - -**Nodig:** -```typescript -export type SwiftIntent = - | 'dagnotitie' - | 'zoeken' - | 'overdracht' - | 'afspraak_maken' // NIEUW - | 'rapportage' // NIEUW - | 'diagnose_bekijken' // NIEUW - | 'diagnose_toevoegen' // NIEUW - | 'diagnose_wijzigen' // NIEUW - | 'unknown'; -``` - -**Impact:** -- TypeScript compile errors zonder deze uitbreiding -- Block configs moeten uitgebreid worden -- Intent classifier moet nieuwe types ondersteunen - -**Aanbeveling:** -Voeg toe aan E-D1.S1 en E-D2.S1: -- Update `SwiftIntent` type -- Update `BLOCK_CONFIGS` met nieuwe block types -- Update `BlockType` type (exclude 'unknown') - -#### Waarschuwing: Entity Extraction voor Datum/Tijd - -**Probleem:** -Het bouwplan beschrijft intent patterns die datum/tijd moeten extraheren (bijv. "morgen 10:00"), maar er is geen plan voor entity extraction van deze waarden. - -**Voorbeeld uit plan:** -``` -/^afspraak\s+(\w+)\s+(morgen|vandaag)\s+(\d{1,2}:\d{2})/i -``` - -**Ontbrekend:** -- Functie om "morgen" β†’ Date object te converteren -- Functie om "10:00" β†’ tijd te parseren -- Validatie van datum/tijd combinaties -- Fallback naar date picker bij onduidelijke input - -**Huidige situatie:** -`lib/swift/entity-extractor.ts` bestaat, maar bevat alleen patient name extraction. - -**Aanbeveling:** -Voeg toe aan E-D1.S1: -- `extractDateTime(input: string): { date?: Date; time?: string }` -- Integratie met date-fns voor Nederlandse datum parsing -- Fallback logica voor onduidelijke input - -#### Waarschuwing: Intake Selectie voor Diagnoses - -**Probleem:** -Het bouwplan beschrijft diagnose toevoegen, maar `DiagnosisDetailForm` vereist een `intakeId` (encounter_id). Het plan beschrijft niet hoe dit wordt bepaald vanuit Swift context. - -**Huidige situatie:** -```typescript -// app/epd/patients/[id]/diagnose/components/diagnosis-detail-form.tsx -// Vereist: intakes array en selectedIntakeId -``` - -**Vragen:** -- Moet Swift automatisch de laatste intake selecteren? -- Moet Swift een intake selector tonen? -- Kan diagnose zonder intake (direct encounter koppeling)? - -**Aanbeveling:** -Voeg toe aan E-D2.S3: -- Beslissing: automatisch laatste intake of selector tonen -- Documenteer in acceptatiecriteria -- Update DiagnoseFormBlock implementatie - -### 1.3 ⚠️ Onduidelijkheden - -#### Appointment Modal Hergebruik - -**Vraag:** -Het plan zegt "80% hergebruik" van `AppointmentModal`, maar deze component is een Dialog met veel interne state. Hoe wordt dit geΓ―ntegreerd in Swift blocks? - -**Huidige situatie:** -- `AppointmentModal` is een volledig Dialog component -- Swift blocks gebruiken `BlockContainer` (geen Dialog) -- Dark theme styling moet aangepast worden - -**Aanbeveling:** -Clarificeer in E-D1.S2: -- Option A: Extract form logica naar shared component, wrapper in beide contexts -- Option B: Hergebruik AppointmentModal maar wrap in BlockContainer (mogelijk styling issues) -- Option C: Nieuwe Swift-specifieke component met shared business logic - -#### Encounter ID Callback Pattern - -**Vraag:** -Het plan zegt "encounter_id teruggeven via callback", maar hoe wordt dit gebruikt voor de volgende stap (rapportage)? - -**Scenario:** -1. User: "afspraak diagnostiek jan morgen 10:00" -2. AfspraakBlock β†’ encounter_id = "abc-123" -3. User: "rapportage diagnostiek gesprek met jan" -4. Hoe weet RapportageBlock dat encounter_id "abc-123" moet gebruiken? - -**Aanbeveling:** -Clarificeer: -- Option A: Swift store houdt laatste encounter_id bij per patient -- Option B: User moet encounter expliciet selecteren -- Option C: AI fallback om encounter te matchen op datum/tijd - ---- - -## 2. Haalbaarheid Analyse - -### 2.1 βœ… Realistische Schattingen - -**Story Points Breakdown:** -- E-D1.S1: 2 SP (intent patterns) β†’ **Realistisch** -- E-D1.S2: 5 SP (AfspraakBlock) β†’ **Realistisch** (met hergebruik) -- E-D1.S3: 4 SP (RapportageBlock) β†’ **Realistisch** -- E-D2.S1: 2 SP (intent patterns) β†’ **Realistisch** -- E-D2.S2: 3 SP (DiagnoseBlock) β†’ **Realistisch** -- E-D2.S3: 5 SP (DiagnoseFormBlock) β†’ **Realistisch** - -**Totaal: 21 SP voor 2 weken = ~10 SP/week** -Dit is haalbaar voor 1 developer met goede focus. - -### 2.2 ⚠️ Risico's op Vertraging - -**Hoog Risico:** -1. **Appointment Modal Integratie** (E-D1.S2) - - Hergebruik Dialog component in Block context kan complex zijn - - Styling aanpassingen kunnen meer tijd kosten dan geschat - - **Mitigatie:** Start met proof-of-concept, pas schatting aan indien nodig - -2. **Datum/Tijd Parsing** (E-D1.S1) - - Nederlandse datum parsing ("morgen", "volgende week") kan edge cases hebben - - Tijdzone handling voor afspraken - - **Mitigatie:** Gebruik date-fns met Nederlandse locale, test grondig - -**Middel Risico:** -1. **ICD-10 Zoeker Verbetering** (E-D2.S3) - - Plan zegt "fuzzy search verbeteren" maar geeft geen specificaties - - Bestaande zoeker werkt al redelijk goed - - **Mitigatie:** Eerst testen of verbetering nodig is, anders scope verkleinen - -2. **Encounter Koppeling** (E-D1.S3) - - Automatische koppeling tussen afspraak en rapportage kan complex zijn - - **Mitigatie:** Start met optionele koppeling, voeg automatische matching later toe - -### 2.3 βœ… Goede Foundation - -**Bestaande Componenten:** -- βœ… AppointmentModal bestaat en is goed gestructureerd -- βœ… ReportComposer bestaat en ondersteunt al `linkedEncounterId` -- βœ… DiagnosisDetailForm bestaat met ICD-10 zoeker -- βœ… Actions bestaan en zijn herbruikbaar -- βœ… ICD-10 zoeker werkt al met fuzzy search - -**Bestaande Infrastructuur:** -- βœ… Swift foundation (Command Center, Intent Classification) werkt -- βœ… Block system bestaat (`BlockContainer`) -- βœ… API routes pattern is duidelijk -- βœ… Supabase RLS policies zijn al geΓ―mplementeerd - ---- - -## 3. Technische Aanbevelingen - -### 3.1 Kritieke Toevoegingen - -#### Story E-D1.S0: Report Type "diagnostiek" (NIEUW - 1 SP) - -**Beschrijving:** -Voeg report type "diagnostiek" toe aan het systeem. - -**Acceptatiecriteria:** -- [ ] `REPORT_TYPES` enum bevat "diagnostiek" -- [ ] Zod schema `CreateReportSchema` accepteert "diagnostiek" -- [ ] Database constraint check (indien nodig) -- [ ] QuickActions component toont "diagnostiek" optie (indien van toepassing) - -**Technical Notes:** -```typescript -// lib/types/report.ts -export const REPORT_TYPES = [ - // ... bestaande types - 'diagnostiek', // NIEUW -] as const; -``` - -#### Story E-D1.S1 Uitbreiding: Entity Extraction - -**Toevoegen aan E-D1.S1:** -- [ ] `extractDateTime(input: string)` functie -- [ ] Nederlandse datum parsing ("morgen", "vandaag", "volgende week") -- [ ] Tijd parsing ("10:00", "14:30") -- [ ] Fallback naar date picker bij onduidelijke input - -**Technical Notes:** -```typescript -// lib/swift/entity-extractor.ts -export function extractDateTime(input: string): { - date?: Date; - time?: string; - confidence: number; -} { - // Parse "morgen 10:00" β†’ { date: tomorrow, time: "10:00" } - // Parse "vandaag 14:30" β†’ { date: today, time: "14:30" } - // Return confidence voor fallback beslissing -} -``` - -#### Story E-D2.S3 Uitbreiding: Intake Selectie - -**Clarificatie nodig:** -- [ ] Beslissing: automatisch laatste intake of selector? -- [ ] Documenteer in acceptatiecriteria -- [ ] Implementeer gekozen aanpak - -**Aanbeveling:** -Automatisch laatste intake selecteren, met optie om te wijzigen: -```typescript -// DiagnoseFormBlock -const intakes = await getPatientIntakes(patientId); -const defaultIntakeId = intakes[0]?.id; // Laatste intake -// Toon dropdown indien meerdere intakes beschikbaar -``` - -### 3.2 Verbeteringen - -#### Intent Patterns Verbeteren - -**Huidige patterns zijn te specifiek:** -```typescript -// Te specifiek - mist veel variaties -/^afspraak\s+(diagnostiek|behandeling)\s+(\w+)/i -``` - -**Aanbeveling:** -Voeg meer variaties toe: -```typescript -afspraak_maken: [ - // Basis patterns - { pattern: /^afspraak\s+(diagnostiek|behandeling)\s+(\w+)/i, weight: 1.0 }, - { pattern: /^plan\s+(diagnostiek|behandeling)\s+(\w+)/i, weight: 0.95 }, - - // Met datum/tijd - { pattern: /^afspraak\s+(\w+)\s+(morgen|vandaag)\s+(\d{1,2}:\d{2})/i, weight: 1.0 }, - { pattern: /^plan\s+(\w+)\s+(morgen|vandaag)\s+(\d{1,2}:\d{2})/i, weight: 0.95 }, - - // Zonder type (default diagnostiek) - { pattern: /^afspraak\s+(\w+)\s+(morgen|vandaag)/i, weight: 0.85 }, - - // Alleen "afspraak" met patient naam - { pattern: /^afspraak\s+(\w+)/i, weight: 0.7 }, -], -``` - -#### API Routes Specificatie - -**Huidige beschrijving is te vaag:** -```typescript -// app/api/appointments/route.ts -export async function POST(request: NextRequest) { - // Wrapper rond app/epd/agenda/actions.ts createEncounter - // Retourneert encounter_id voor volgende stap -} -``` - -**Aanbeveling:** -Specificeer volledige API contract: -```typescript -// POST /api/appointments -// Request body: -{ - patientId: string; - periodStart: string; // ISO 8601 - periodEnd?: string; - typeCode: 'diagnostiek' | 'behandeling' | ...; - typeDisplay: string; - classCode: 'AMB' | 'HH' | 'VR'; - classDisplay: string; - notes?: string; -} - -// Response: -{ - success: boolean; - data?: { - id: string; // encounter_id - // ... andere encounter velden - }; - error?: string; -} -``` - ---- - -## 4. Testplan Verbeteringen - -### 4.1 Ontbrekende Test Cases - -**Entity Extraction Tests:** -- [ ] "morgen 10:00" β†’ correcte datum + tijd -- [ ] "vandaag 14:30" β†’ correcte datum + tijd -- [ ] "volgende week maandag" β†’ correcte datum -- [ ] "afspraak jan" β†’ alleen patient, geen datum β†’ fallback date picker -- [ ] "afspraak jan morgen" β†’ patient + datum, geen tijd β†’ fallback time picker - -**Encounter Koppeling Tests:** -- [ ] Afspraak aanmaken β†’ encounter_id opgeslagen -- [ ] Rapportage met encounter_id β†’ correct gekoppeld -- [ ] Rapportage zonder encounter_id β†’ optioneel (geen error) -- [ ] Meerdere encounters opzelfde dag β†’ juiste selectie - -**Diagnose Intake Tests:** -- [ ] PatiΓ«nt met 1 intake β†’ automatisch geselecteerd -- [ ] PatiΓ«nt met meerdere intakes β†’ laatste geselecteerd -- [ ] PatiΓ«nt zonder intakes β†’ error/fallback - -### 4.2 Integration Test Scenarios - -**End-to-End Flow:** -``` -1. "afspraak diagnostiek jan morgen 10:00" - β†’ AfspraakBlock opent - β†’ Patient "jan" gevonden - β†’ Datum: morgen - β†’ Tijd: 10:00 - β†’ Type: diagnostiek - β†’ Opslaan β†’ encounter_id = "abc-123" - -2. "rapportage diagnostiek gesprek met jan" - β†’ RapportageBlock opent - β†’ Patient "jan" gevonden - β†’ Type: diagnostiek - β†’ Encounter: "abc-123" (laatste encounter van jan) - β†’ Content invoeren - β†’ Opslaan β†’ report gekoppeld aan encounter - -3. "diagnose jan" - β†’ DiagnoseBlock opent - β†’ Overzicht diagnoses van jan - β†’ Filter: Actief - -4. "diagnose toevoegen jan F41.1" - β†’ DiagnoseFormBlock opent - β†’ Patient: jan - β†’ ICD-10: F41.1 (pre-filled) - β†’ Intake: laatste intake (automatisch) - β†’ Type: nevendiagnose (default) - β†’ Opslaan β†’ diagnose toegevoegd -``` - ---- - -## 5. Swift Foundation Status (24-12-2024) - -> **BELANGRIJK:** De diagnostiek workflow bouwt voort op de Swift foundation (bouwplan-swift-v1.md). -> De foundation is nog niet compleet, waardoor de diagnostiek workflow nog niet kan starten. - -### 5.1 Foundation Status Overzicht - -| Epic | Status | Impact op Diagnostiek | -|------|--------|----------------------| -| E0 Setup & Foundation | βœ… Done | Geen blokkade | -| E1 Command Center | βœ… Done | Geen blokkade | -| E2 Intent Classification | ⏳ In Progress | πŸ”΄ **BLOKKADE** | -| E3 P1 Blocks | ⏳ To Do | πŸ”΄ **BLOKKADE** | -| E4 Navigation & Auth | ⏳ To Do | Geen blokkade | -| E5 Polish & Testing | ⏳ To Do | Geen blokkade | - -### 5.2 Blokkerende Issues - -#### πŸ”΄ Blokkade 1: E2.S5 Input β†’ Block Wiring - -**Huidige situatie:** -```typescript -// components/swift/command-center/command-input.tsx:120 -const handleSubmit = async (e: React.FormEvent) => { - // TODO: Process intent (E2) - console.log('Submit:', inputValue); - clearInput(); -}; -``` - -**Probleem:** -De intent classificatie API bestaat (`/api/intent/classify`), maar wordt niet aangeroepen. -Het resultaat wordt niet gebruikt om `openBlock()` aan te roepen. - -**Impact:** -Zonder deze wiring kan geen enkel block geopend worden via tekst/spraak input. - -**Story toegevoegd aan bouwplan-swift-v1.md (v1.5):** -```markdown -| E2.S5 | Input β†’ Block wiring | CommandInput submit β†’ API β†’ openBlock | ⏳ | E2.S4 | 2 | -``` - -#### πŸ”΄ Blokkade 2: CanvasArea Block Rendering - -**Huidige situatie:** -```typescript -// components/swift/command-center/canvas-area.tsx:18 -{activeBlock ? ( -
Block: {activeBlock}
// ← Placeholder! -) : ( - -)} -``` - -**Probleem:** -De CanvasArea toont alleen placeholder tekst, niet de daadwerkelijke block componenten. -Er is geen switch/case of dynamic import voor de block types. - -**Impact:** -Zelfs als E2.S5 werkt, worden blocks niet zichtbaar. - -**Aanbeveling:** -Voeg story E3.S0 toe aan bouwplan-swift-v1.md: -```markdown -| E3.S0 | CanvasArea block rendering | Switch/case voor block types, prefill doorgeven | ⏳ | E2.S5 | 2 | -``` - -#### πŸ”΄ Blokkade 3: P1 Blocks Bestaan Niet - -**Huidige situatie:** -```typescript -// components/swift/blocks/index.ts -export { BlockContainer } from './block-container'; - -// Commented out - bestaan niet: -// export { DagnotatieBlock } from './dagnotitie-block'; -// export { ZoekenBlock } from './zoeken-block'; -// export { OverdrachtBlock } from './overdracht-block'; -``` - -**Probleem:** -De diagnostiek workflow voegt nieuwe blocks toe (AfspraakBlock, RapportageBlock, DiagnoseBlock), -maar de basis P1 blocks waar deze op voortbouwen bestaan nog niet. - -**Impact:** -- DagnotatieBlock is nodig als referentie voor RapportageBlock -- ZoekenBlock is nodig voor patient selectie in alle flows -- BlockContainer bestaat wel, maar is nog niet getest met echte content - -**Aanbeveling:** -Implementeer eerst E3.S2 (DagnotatieBlock) als proof-of-concept voordat diagnostiek workflow start. - -#### ⚠️ Waarschuwing: Type Duplicatie - -**Huidige situatie:** -```typescript -// lib/swift/types.ts -export type SwiftIntent = 'dagnotitie' | 'zoeken' | 'overdracht' | 'unknown'; - -// stores/swift-store.ts (DUPLICAAT) -export type SwiftIntent = 'dagnotitie' | 'zoeken' | 'overdracht' | 'unknown'; -``` - -**Impact:** -Bij uitbreiding van intents voor diagnostiek workflow moet dit op twee plekken bijgewerkt worden. -Vergeten leidt tot TypeScript errors. - -**Aanbeveling:** -Verwijder duplicaat uit `swift-store.ts`, importeer uit `types.ts`. - -### 5.3 Dependency Chain voor Diagnostiek - -``` -Swift Foundation (moet eerst af) -β”œβ”€β”€ E2.S5 Input β†’ Block wiring ← BLOKKADE -β”‚ └── handleSubmit() roept API aan -β”‚ └── openBlock() bij succes -β”‚ -β”œβ”€β”€ E3.S0 CanvasArea block rendering ← BLOKKADE (ontbreekt in plan) -β”‚ └── Switch/case voor block types -β”‚ └── Prefill data doorgeven -β”‚ -β”œβ”€β”€ E3.S2 DagnotatieBlock ← BLOKKADE -β”‚ └── Referentie voor RapportageBlock -β”‚ └── Test case voor block rendering -β”‚ -└── E3.S3 Patient Search API ← BLOKKADE - └── Nodig voor patient selectie - -Diagnostiek Workflow (kan dan starten) -β”œβ”€β”€ E-D1.S0 Report type "diagnostiek" -β”œβ”€β”€ E-D1.S1 Intent patterns uitbreiden -β”œβ”€β”€ E-D1.S2 AfspraakBlock -β”œβ”€β”€ E-D1.S3 RapportageBlock -β”œβ”€β”€ E-D2.S1 Diagnose intent patterns -β”œβ”€β”€ E-D2.S2 DiagnoseBlock -└── E-D2.S3 DiagnoseFormBlock -``` - -### 5.4 Geschatte Effort voor Foundation Completion - -| Story | SP | Status | -|-------|----|----| -| E2.S5 Input β†’ Block wiring | 2 | ⏳ Nieuw toegevoegd | -| E3.S0 CanvasArea rendering | 2 | ⏳ Aanbevolen | -| E3.S2 DagnotatieBlock | 5 | ⏳ Gepland | -| E3.S3 Patient Search API | 3 | ⏳ Gepland | -| **Subtotaal** | **12** | | - -**Totale effort voor werkende demo:** -- Swift Foundation completion: 12 SP -- Diagnostiek Workflow: 22 SP -- **Totaal: 34 SP** - ---- - -## 6. Conclusie & Aanbevelingen - -### 6.1 Algemene Beoordeling - -**Compleetheid Diagnostiek Plan:** ⚠️ **7/10** -- Goede structuur en breakdown -- Enkele kritieke technische details ontbreken -- Entity extraction niet volledig uitgewerkt - -**Compleetheid Swift Foundation:** ⚠️ **5/10** -- E0-E2.S4 solide geΓ―mplementeerd -- E2.S5 wiring ontbreekt (kritiek) -- E3 blocks niet gebouwd (kritiek) -- CanvasArea rendering niet in plan - -**Haalbaarheid:** ⚠️ **6/10** (was 8/10) -- Foundation moet eerst af voordat diagnostiek kan starten -- Extra 12 SP nodig voor foundation completion -- Totale effort: 34 SP i.p.v. 22 SP - -### 6.2 Aanbevelingen voor Start - -**Voor Start:** -1. βœ… Voeg E-D1.S0 toe: Report type "diagnostiek" (1 SP) -2. βœ… Uitbreid E-D1.S1: Entity extraction voor datum/tijd (extra 1 SP) -3. βœ… Clarificeer E-D2.S3: Intake selectie strategie -4. βœ… Update `SwiftIntent` type definitie -5. βœ… Proof-of-concept AppointmentModal integratie - -**Tijdens Implementatie:** -1. Start met E-D1.S0 (report type) - basis voor alles -2. Test entity extraction grondig voordat je verder gaat -3. Itereer op AppointmentModal integratie (mogelijk meer tijd nodig) -4. Houd rekening met edge cases in datum parsing - -**Na Implementatie:** -1. Uitgebreide end-to-end tests -2. Performance testen (intent classification snelheid) -3. UX feedback verzamelen -4. Documentatie updaten - -### 6.3 Aangepaste Story Breakdown - -**Swift Foundation (moet eerst af):** -- E2.S5: Input β†’ Block wiring (2 SP) ⭐ NIEUW -- E3.S0: CanvasArea block rendering (2 SP) ⭐ AANBEVOLEN -- E3.S2: DagnotatieBlock (5 SP) -- E3.S3: Patient Search API (3 SP) -- **Subtotaal Foundation: 12 SP** - -**Epic D1 β€” Afspraak & Rapportage (12 SP totaal):** -- E-D1.S0: Report type "diagnostiek" toevoegen (1 SP) ⭐ NIEUW -- E-D1.S1: Intent patterns + entity extraction (3 SP) ⬆️ +1 SP -- E-D1.S2: AfspraakBlock (5 SP) -- E-D1.S3: RapportageBlock uitbreiden (4 SP) - -**Epic D2 β€” Diagnose Beheer (10 SP totaal):** -- E-D2.S1: Intent patterns uitbreiden (2 SP) -- E-D2.S2: DiagnoseBlock (3 SP) -- E-D2.S3: DiagnoseFormBlock (5 SP) - -**Totalen:** -- Swift Foundation completion: 12 SP -- Diagnostiek Workflow: 22 SP -- **Totaal: 34 SP** - -### 6.4 Finale Oordeel - -⚠️ **HOLD - Foundation eerst afronden** - -Het diagnostiek bouwplan is goed gestructureerd, maar kan nog niet starten omdat de Swift foundation incompleet is. - -**Kritieke blokkades:** -1. E2.S5 (handleSubmit wiring) - toegevoegd aan bouwplan v1.5 -2. E3.S0 (CanvasArea rendering) - moet nog toegevoegd worden -3. E3.S2 (DagnotatieBlock) - moet gebouwd worden als referentie -4. E3.S3 (Patient Search API) - nodig voor alle patient selectie - -**Aanbevolen volgorde:** -``` -Week 1: Foundation completion (12 SP) -β”œβ”€β”€ E2.S5 Input β†’ Block wiring -β”œβ”€β”€ E3.S0 CanvasArea rendering -β”œβ”€β”€ E3.S2 DagnotatieBlock -└── E3.S3 Patient Search API - -Week 2-3: Diagnostiek Workflow (22 SP) -β”œβ”€β”€ E-D1.S0 Report type -β”œβ”€β”€ E-D1.S1 Intent patterns -β”œβ”€β”€ E-D1.S2 AfspraakBlock -β”œβ”€β”€ E-D1.S3 RapportageBlock -β”œβ”€β”€ E-D2.S1 Diagnose patterns -β”œβ”€β”€ E-D2.S2 DiagnoseBlock -└── E-D2.S3 DiagnoseFormBlock -``` - -**GO voor implementatie** zodra foundation stories zijn afgerond. - ---- - -**Versiehistorie:** - -| Versie | Datum | Auteur | Wijziging | -|--------|-------|--------|-----------| -| v1.0 | 23-12-2024 | AI Review | InitiΓ«le beoordeling | -| v1.1 | 24-12-2024 | Claude | Swift Foundation status toegevoegd (sectie 5), blokkerende issues geΓ―dentificeerd, finale oordeel aangepast naar HOLD | - diff --git a/docs/swift/bouwplan-swift-diagnostiek-workflow.md b/docs/swift/bouwplan-swift-diagnostiek-workflow.md deleted file mode 100644 index ea14275..0000000 --- a/docs/swift/bouwplan-swift-diagnostiek-workflow.md +++ /dev/null @@ -1,458 +0,0 @@ -# πŸš€ Mission Control β€” Bouwplan Swift: Diagnostiek Workflow - -**Projectnaam:** Swift β€” Diagnostiek Workflow -**Versie:** v1.0 -**Datum:** 23-12-2024 -**Auteur:** Colin Lit / Development Team - ---- - -## 1. Doel en context - -🎯 **Doel:** -Implementeren van de complete diagnostiek workflow in Swift: van het plannen van een diagnostiek-afspraak, via het schrijven van een rapportage, tot het bekijken en stellen van diagnoses. Deze workflow stelt behandelaars in staat om een volledig diagnostiek-traject door te lopen via natuurlijke taal zonder menu-navigatie. - -**Kernbelofte:** -> Een behandelaar kan een volledig diagnostiek-traject doorlopen: "afspraak diagnostiek jan morgen 10:00" β†’ "rapportage diagnostiek gesprek met jan" β†’ "diagnose toevoegen jan F41.1" β€” alles in één vloeiende flow. - -πŸ“˜ **Context:** -Dit bouwplan beschrijft de implementatie van de diagnostiek workflow als uitbreiding op Swift. Het bouwt voort op de Swift foundation (Command Center, Intent Classification) en voegt specifieke blocks toe voor behandelaars. - -**Relatie met documentatie:** -- **FO Diagnostiek:** `swift-fo-diagnostiek-workflow.md` β€” Complete use case beschrijving -- **FO Algemeen:** `swift-fo-ai.md` β€” Algemene Swift functionaliteit -- **Bouwplan Swift:** `bouwplan-swift-v1.md` β€” Hoofd Swift bouwplan -- **UX/UI:** `swift-ux-v2.1.md` β€” Visuele specificaties - ---- - -## 2. Uitgangspunten - -### 2.1 Technische Stack - -**Bestaand (hergebruiken):** -| Component | Technologie | Status | Hergebruik | -|-----------|-------------|--------|------------| -| Swift Foundation | Command Center, Intent Classification | βœ… | Basis voor alle blocks | -| Appointment Modal | `app/epd/agenda/components/appointment-modal.tsx` | βœ… | 80% hergebruik | -| Rapportage Composer | `app/epd/patients/[id]/rapportage/components/report-composer.tsx` | βœ… | 80% hergebruik | -| Diagnose Form | `app/epd/patients/[id]/diagnose/components/diagnosis-detail-form.tsx` | βœ… | 80% hergebruik | -| Diagnose Actions | `app/epd/patients/[id]/diagnose/actions.ts` | βœ… | 90% hergebruik | -| FHIR Patient API | `/api/fhir/Patient` | βœ… | Patient search | -| Reports API | `/api/reports` | βœ… | Rapportage opslaan | - -**Nieuw te bouwen:** -| Component | Technologie | Reden | -|-----------|-------------|-------| -| AfspraakBlock | React component | Swift wrapper rond appointment modal | -| RapportageBlock | React component | Swift wrapper rond report composer | -| DiagnoseBlock | React component | Overzicht component | -| DiagnoseFormBlock | React component | Swift wrapper rond diagnose form | -| Appointments API | Next.js API route | Encounter CRUD voor Swift | -| Diagnoses API | Next.js API route | Diagnose CRUD voor Swift | - -### 2.2 Projectkaders - -| Kader | Waarde | -|-------|--------| -| **Bouwtijd** | 2 weken (2 sprints) | -| **Team** | 1 developer | -| **Scope** | Diagnostiek workflow: Afspraak β†’ Rapportage β†’ Diagnose | -| **Data** | Bestaande Supabase database (encounters, conditions, reports) | -| **Doel** | Werkende behandelaar workflow voor demo | - -### 2.3 Programmeer Uitgangspunten - -**Code Quality Principles:** - -- **DRY (Don't Repeat Yourself)** - - Hergebruik bestaande componenten (appointment-modal, report-composer, diagnose-form) - - Centrale API routes voor encounters en diagnoses - - Shared hooks voor common patterns - -- **KISS (Keep It Simple, Stupid)** - - Swift blocks zijn wrappers rond bestaande componenten - - Minimale aanpassingen aan bestaande code - - Hergebruik bestaande validatie en error handling - -- **SOC (Separation of Concerns)** - - Swift blocks gescheiden van klassieke EPD componenten - - API routes als wrapper rond bestaande actions - - Business logic blijft in bestaande actions - -- **YAGNI (You Aren't Gonna Need It)** - - Alleen diagnostiek workflow in scope - - Geen andere behandelaar workflows (intake, behandelplan, etc.) - - Geen advanced features (herhalende afspraken, etc.) - -**Development Practices:** - -- **Hergebruik Strategie** - ```typescript - // βœ… Hergebruik bestaande componenten - // components/swift/blocks/afspraak-block.tsx - import { AppointmentModal } from '@/app/epd/agenda/components/appointment-modal'; - - // Aanpassen voor Swift context: - // - Prefill vanuit intent - // - Encounter_id teruggeven na opslaan - // - Swift styling (dark theme) - - // βœ… Hergebruik bestaande actions - // app/api/appointments/route.ts - import { createEncounter, updateEncounter } from '@/app/epd/agenda/actions'; - - // Wrapper rond bestaande logica met Swift-specifieke validatie - ``` - -- **Error Handling** - - Hergebruik bestaande error handling uit actions - - Nederlandse foutmeldingen consistent met Swift - - Toast notifications voor user feedback - -- **Security** - - Hergebruik Supabase RLS policies - - Authenticatie via bestaande Supabase Auth - - Input validation met Zod (bestaande schemas) - ---- - -## 3. Epics & Stories Overzicht - -| Epic ID | Titel | Doel | Status | Stories | Effort | Opmerkingen | -|---------|-------|------|--------|---------|--------|-------------| -| E-D1 | Afspraak & Rapportage | Afspraak plannen + rapportage koppelen | ⏳ To Do | 3 | 11 SP | Hergebruik appointment modal | -| E-D2 | Diagnose Beheer | Diagnose bekijken, toevoegen, bijstellen | ⏳ To Do | 3 | 10 SP | Hergebruik diagnose form | - -**Totaal: 6 stories, 21 story points** - -**Belangrijk:** -- Bouw per epic en per story -- Hergebruik bestaande componenten waar mogelijk -- Minimale aanpassingen aan bestaande code -- Database migraties: eerst aan Colin melden - ---- - -## 4. Epics & Stories (Uitwerking) - -### Epic D1 β€” Afspraak & Rapportage - -**Epic Doel:** Werkende flow van diagnostiek-afspraak plannen tot rapportage schrijven met encounter koppeling. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E-D1.S1 | Intent patterns uitbreiden | Afspraak en rapportage intents herkend | ⏳ To Do | Swift foundation | 2 | -| E-D1.S2 | AfspraakBlock | PatiΓ«nt, datum/tijd, type, encounter_id terug | ⏳ To Do | E-D1.S1 | 5 | -| E-D1.S3 | RapportageBlock uitbreiden | Encounter_id koppeling, type "diagnostiek" | ⏳ To Do | E-D1.S2 | 4 | - -**Technical Notes:** - -```typescript -// E-D1.S1: Intent patterns toevoegen aan lib/swift/intent-classifier.ts -afspraak_maken: [ - /^afspraak\s+(diagnostiek|behandeling)\s+(\w+)/i, - /^plan\s+(\w+)\s+(morgen|vandaag|volgende week)/i, - /^afspraak\s+(\w+)\s+(morgen|vandaag)\s+(\d{1,2}:\d{2})/i, -], - -rapportage: [ - /^rapportage\s+(diagnostiek|behandeling)\s+(\w+)/i, - /^gesprek gehad met\s+(\w+)/i, - /^verslag\s+(\w+)/i, -], - -// E-D1.S2: AfspraakBlock -// components/swift/blocks/afspraak-block.tsx -// Hergebruik: app/epd/agenda/components/appointment-modal.tsx -// Aanpassingen: -// - Prefill vanuit intent (patient, date, time, type) -// - Dark theme styling (Swift context) -// - Encounter_id teruggeven via callback -// - Vereenvoudigde UI (geen linked reports sectie) - -// E-D1.S3: RapportageBlock uitbreiden -// components/swift/blocks/rapportage-block.tsx -// Hergebruik: app/epd/patients/[id]/rapportage/components/report-composer.tsx -// Aanpassingen: -// - Encounter_id in prefill -// - Type "diagnostiek" toevoegen aan report types -// - Encounter link tonen indien gekoppeld -``` - -**API Routes:** - -```typescript -// E-D1.S2: Appointments API -// app/api/appointments/route.ts -export async function POST(request: NextRequest) { - // Wrapper rond app/epd/agenda/actions.ts createEncounter - // Retourneert encounter_id voor volgende stap -} - -// E-D1.S3: Reports API uitbreiden -// app/api/reports/route.ts (bestaand) -// Uitbreiden met encounter_id parameter -``` - ---- - -### Epic D2 β€” Diagnose Beheer - -**Epic Doel:** Werkende diagnose overzicht en diagnose aanmaken/bijstellen met ICD-10 zoeker. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E-D2.S1 | Intent patterns uitbreiden | Diagnose intents herkend | ⏳ To Do | Swift foundation | 2 | -| E-D2.S2 | DiagnoseBlock | Overzicht diagnoses, filter actief/inactief | ⏳ To Do | E-D2.S1 | 3 | -| E-D2.S3 | DiagnoseFormBlock | ICD-10 zoeker, type, status, ernst | ⏳ To Do | E-D2.S2 | 5 | - -**Technical Notes:** - -```typescript -// E-D2.S1: Intent patterns toevoegen -diagnose_bekijken: [ - /^diagnose\s+(\w+)/i, - /^diagnoses van\s+(\w+)/i, - /^wat zijn de diagnoses/i, -], - -diagnose_toevoegen: [ - /^diagnose toevoegen\s+(\w+)\s+([A-Z]\d+\.\d+)/i, - /^(\w+)\s+heeft\s+([A-Z]\d+\.\d+)/i, - /^diagnose\s+(\w+)\s+([A-Z]\d+\.\d+)/i, -], - -diagnose_wijzigen: [ - /^diagnose wijzigen\s+(\w+)/i, - /^diagnose bijstellen/i, -], - -// E-D2.S2: DiagnoseBlock -// components/swift/blocks/diagnose-block.tsx -// Hergebruik logica van: app/epd/patients/[id]/diagnose/page.tsx -// Aanpassingen: -// - Swift styling (dark theme) -// - Filter tabs: Actief / Inactief / Alle -// - Klik op diagnose β†’ DiagnoseFormBlock (edit mode) -// - "Nieuwe diagnose" knop β†’ DiagnoseFormBlock (create mode) - -// E-D2.S3: DiagnoseFormBlock -// components/swift/blocks/diagnose-form-block.tsx -// Hergebruik: app/epd/patients/[id]/diagnose/components/diagnosis-detail-form.tsx -// Aanpassingen: -// - ICD-10 zoeker met fuzzy search (verbeteren) -// - Swift styling -// - Prefill vanuit intent (ICD-10 code) -// - Encounter_id koppeling (optioneel) -``` - -**API Routes:** - -```typescript -// E-D2.S2 + E-D2.S3: Diagnoses API -// app/api/diagnoses/route.ts -export async function GET(request: NextRequest) { - // GET /api/diagnoses/:patientId - // Wrapper rond app/epd/patients/[id]/diagnose/actions.ts getPatientDiagnoses -} - -export async function POST(request: NextRequest) { - // POST /api/diagnoses - // Wrapper rond app/epd/patients/[id]/diagnose/actions.ts createPatientDiagnosis -} - -export async function PATCH(request: NextRequest) { - // PATCH /api/diagnoses/:id - // Wrapper rond app/epd/patients/[id]/diagnose/actions.ts updatePatientDiagnosis -} -``` - ---- - -## 5. Kwaliteit & Testplan - -### 5.1 Test Types - -| Test Type | Scope | Tools | Wanneer | Verantwoordelijke | -|-----------|-------|-------|---------|-------------------| -| Unit Tests | Intent patterns, entity extraction | Vitest | E-D1.S1, E-D2.S1 | Developer | -| Integration Tests | API endpoints | Vitest + MSW | E-D1.S2, E-D1.S3, E-D2.S3 | Developer | -| Component Tests | Blocks | React Testing Library | E-D1.S2, E-D1.S3, E-D2.S2, E-D2.S3 | Developer | -| Manual Tests | Complete workflow | Checklist | E-D2.S3 | QA / Developer | - -### 5.2 Test Coverage Targets - -| Area | Target | Reden | -|------|--------|-------| -| Intent patterns | 85%+ | Correcte intent herkenning | -| Entity extraction | 80%+ | Pre-fill correctheid | -| API routes | 80%+ | Data integrity | -| Block components | 60%+ | Belangrijkste flows | - -### 5.3 Manual Test Checklist (Diagnostiek Workflow) - -**Happy Flow:** -- [ ] "afspraak diagnostiek met jan morgen 10:00" β†’ AfspraakBlock opent -- [ ] Afspraak opslaan β†’ encounter_id teruggegeven -- [ ] "rapportage diagnostiek gesprek met jan" β†’ RapportageBlock met encounter koppeling -- [ ] Rapportage opslaan β†’ gekoppeld aan encounter -- [ ] "diagnose jan" β†’ DiagnoseBlock met overzicht -- [ ] "diagnose toevoegen jan F41.1" β†’ DiagnoseFormBlock met ICD-10 pre-filled -- [ ] Diagnose opslaan β†’ toegevoegd aan overzicht -- [ ] Klik op diagnose β†’ DiagnoseFormBlock (edit mode) -- [ ] Status wijzigen β†’ diagnose bijgewerkt - -**Error Scenarios:** -- [ ] Geen patiΓ«nt gevonden β†’ ZoekenBlock -- [ ] Ongeldige datum β†’ validatie fout -- [ ] ICD-10 code niet gevonden β†’ validatie fout -- [ ] Encounter niet gevonden β†’ rapportage zonder koppeling -- [ ] Network error β†’ toast met retry - ---- - -## 6. Demo & Presentatieplan - -### 6.1 Demo Scenario - -**Duur:** 5 minuten -**Doelgroep:** Behandelaars, psychologen, psychiaters -**Locatie:** Live op Vercel - -**Flow:** - -``` -1. INTRO (30 sec) - "Behandelaars besteden veel tijd aan administratie. - Swift maakt diagnostiek-trajecten sneller." - -2. AFSPRAAK PLANNEN (1 min) - - Typ: "afspraak diagnostiek met jan morgen 10:00" - - AfspraakBlock verschijnt voorgevuld - - Opslaan β†’ afspraak aangemaakt - -3. RAPPORTAGE SCHRIJVEN (1.5 min) - - Typ: "rapportage diagnostiek gesprek met jan" - - RapportageBlock verschijnt met encounter koppeling - - Schrijf/dicteer verslag - - Opslaan β†’ gekoppeld aan afspraak - -4. DIAGNOSE STELLEN (2 min) - - Typ: "diagnose jan" - - DiagnoseBlock toont overzicht - - Typ: "diagnose toevoegen jan F41.1" - - DiagnoseFormBlock met ICD-10 pre-filled - - Vul type, status, ernst in - - Opslaan β†’ diagnose toegevoegd - -5. AFSLUITING (20 sec) - - Complete flow in 5 minuten - - Vragen -``` - -### 6.2 Backup Plan - -| Probleem | Oplossing | -|----------|-----------| -| Internet issues | Localhost met demo data | -| AI API down | Pre-cached responses | -| Encounter niet gevonden | Demo met pre-made encounter | -| Complete failure | Video recording | - ---- - -## 7. Risico's & Mitigatie - -| Risico | Kans | Impact | Mitigatie | Owner | -|--------|------|--------|-----------|-------| -| Hergebruik componenten complex | Middel | Hoog | Stapsgewijs aanpassen, tests per stap | Dev | -| ICD-10 zoeker niet accuraat | Middel | Middel | Fuzzy search verbeteren, externe API optie | Dev | -| Encounter koppeling faalt | Laag | Middel | Duidelijke UX, optionele koppeling | Dev | -| Datum parsing onnauwkeurig | Middel | Laag | Fallback naar date picker | Dev | -| Bestaande code breaking changes | Laag | Hoog | Wrapper pattern, geen directe wijzigingen | Dev | - ---- - -## 8. Sprint Planning - -### Sprint 1 (Week 1): Afspraak & Rapportage -- E-D1.S1: Intent patterns uitbreiden (2 SP) -- E-D1.S2: AfspraakBlock (5 SP) -- E-D1.S3: RapportageBlock uitbreiden (4 SP) -- **Deliverable:** Afspraak en rapportage flow werkend - -### Sprint 2 (Week 2): Diagnose Beheer -- E-D2.S1: Intent patterns uitbreiden (2 SP) -- E-D2.S2: DiagnoseBlock (3 SP) -- E-D2.S3: DiagnoseFormBlock (5 SP) -- Bug fixes + demo prep -- **Deliverable:** Complete diagnostiek workflow werkend - ---- - -## 9. Definition of Done - -Een story is **Done** wanneer: -- [ ] Code geschreven en werkend -- [ ] TypeScript types correct -- [ ] Component responsive (mobile + desktop) -- [ ] Error states afgehandeld -- [ ] Hergebruik bestaande code geΓ―mplementeerd -- [ ] Geen breaking changes in bestaande code -- [ ] Getest in Chrome + Safari -- [ ] Demo scenario werkt - -Een epic is **Done** wanneer: -- [ ] Alle stories Done -- [ ] Integration test passed -- [ ] Complete workflow werkt end-to-end - ---- - -## 10. Referenties - -### Project Documenten -- FO Diagnostiek: `docs/swift/swift-fo-diagnostiek-workflow.md` -- FO Algemeen: `docs/swift/swift-fo-ai.md` -- Bouwplan Swift: `docs/swift/bouwplan-swift-v1.md` -- UX: `docs/swift/swift-ux-v2.1.md` - -### Bestaande Code Referenties (Hergebruik) - -| Component | Locatie | Hergebruik % | Aanpassingen | -|-----------|---------|--------------|-------------| -| Appointment Modal | `app/epd/agenda/components/appointment-modal.tsx` | 80% | Prefill, dark theme, encounter_id callback | -| Report Composer | `app/epd/patients/[id]/rapportage/components/report-composer.tsx` | 80% | Encounter koppeling, type "diagnostiek" | -| Diagnose Page | `app/epd/patients/[id]/diagnose/page.tsx` | 70% | Overzicht logica, Swift styling | -| Diagnose Form | `app/epd/patients/[id]/diagnose/components/diagnosis-detail-form.tsx` | 80% | ICD-10 zoeker verbeteren, Swift styling | -| Diagnose Actions | `app/epd/patients/[id]/diagnose/actions.ts` | 90% | Direct hergebruik via API wrapper | -| Encounter Actions | `app/epd/agenda/actions.ts` | 90% | Direct hergebruik via API wrapper | - -### External -- ICD-10 codes: https://www.who.int/standards/classifications/classification-of-diseases -- FHIR Encounter: https://www.hl7.org/fhir/encounter.html -- FHIR Condition: https://www.hl7.org/fhir/condition.html - ---- - -## 11. Glossary & Abbreviations - -| Term | Betekenis | -|------|-----------| -| Encounter | Afspraak/contactmoment (FHIR term) | -| Condition | Diagnose (FHIR term) | -| ICD-10 | International Classification of Diseases versie 10 | -| Hoofddiagnose | Primaire diagnose | -| Nevendiagnose | Secundaire diagnose | -| Clinical Status | Status van diagnose (actief, inactief, resolved, etc.) | -| Severity | Ernst van diagnose (mild, matig, ernstig) | - ---- - -**Versiehistorie:** - -| Versie | Datum | Auteur | Wijziging | -|--------|-------|--------|-----------| -| v1.0 | 23-12-2024 | Claude | InitiΓ«le versie - Apart bouwplan voor diagnostiek workflow | - diff --git a/docs/swift/bouwplan-swift-standalone-module.md b/docs/swift/bouwplan-swift-standalone-module.md deleted file mode 100644 index c05d4bb..0000000 --- a/docs/swift/bouwplan-swift-standalone-module.md +++ /dev/null @@ -1,215 +0,0 @@ -# Mission Control - Bouwplan - -Projectnaam: Swift Standalone Module (MVP) -Versie: v1.0 -Datum: 27-12-2025 -Auteur: Colin Lit - ---- - -## 1. Doel en context -Doel: Swift loskoppelen van de klassieke EPD layout zodat de Swift UI full-screen draait zonder sidebar. -Toelichting: Swift is een aparte modus (conversational scribe) die focus en ruimte nodig heeft. In de huidige app router erft `/epd/swift` de EPD layout, waardoor de sidebar blijft staan. Dit plan brengt Swift onder een eigen route group, behoudt dezelfde URL, en voorkomt regressies in het klassieke EPD. - -Belangrijke overwegingen: -- Lead dev: zuivere layout scheiding via route group, minimale impact, geen conditionele layout hacks. -- UX: full-screen focus, duidelijke entry/exit, geen dubbele navigatie, consistente context bar. -- PO: MVP scope, beperkte wijzigingen, geen nieuwe features of dependencies. -- Besluit: route group is akkoord (27-12-2025). - -UX flow (MVP): -- Toegang via login: interface-voorkeur bepaalt redirect (Swift -> /epd/swift, klassiek -> /epd/clients). -- Deep link naar /epd/swift zonder sessie: login volgt en redirect gaat alsnog op basis van interface-voorkeur. -- Terug naar EPD: context bar link naar /epd. -- Schakelen vanuit klassiek EPD: Swift staat als item in de EPD sidebar. - ---- - -## 2. Uitgangspunten - -### 2.1 Technische Stack -- Frontend: Next.js App Router + React + TypeScript -- Styling: Tailwind CSS -- State: Zustand -- Auth: Supabase Auth -- API: Next.js route handlers (SSE voor Swift chat) -- Hosting: Vercel - -### 2.2 Projectkaders -- Scope (MVP): alleen layout/routing scheiding + minimale navigatie checks. -- Out of scope: nieuwe Swift features, redesign van chat/artifacts, nieuwe AI flows. -- Geen nieuwe dependencies zonder akkoord. -- Geen database migraties nodig. -- URL `/epd/swift` blijft gelijk voor deep links. -- Klassiek EPD moet onveranderd blijven. - -### 2.3 Programmeer Uitgangspunten -Code quality principles: -- DRY: shared layout helpers en routes hergebruiken waar logisch. -- KISS: route group boven conditionele rendering. -- SOC: Swift layout los van EPD layout, geen cross-coupling. -- YAGNI: geen extra features buiten layout scheiding. - -Development practices: -- Geen nieuwe dependencies of migrations zonder akkoord. -- Keep server components default; alleen client waar nodig. -- Duidelijke error handling bij auth redirect. -- UI blijft Tailwind-only, geen styling drift. - ---- - -## 3. Epics & Stories Overzicht -| Epic ID | Titel | Doel | Status | Stories | Opmerkingen | -|---------|-------|------|--------|---------|-------------| -| E0 | Product/UX alignment | Scope en UX flows vastleggen | Done | 2 | Route group akkoord | -| E1 | Routing & layout scheiding | Swift los van EPD layout | Done | 4 | `/epd/swift` blijft | -| E2 | Navigatie & toegang | Entry/exit flows borgen | Done | 3 | MVP only | -| E3 | Swift shell polish | Full-screen gedrag + responsive | Done | 3 | Geen redesign | -| E4 | QA & docs | Validatie en documentatie | To Do | 3 | Manual checks | - ---- - -## 4. Epics & Stories (Uitwerking) - -### Epic 0 - Product/UX alignment -Epic doel: beslissen over aanpak en de MVP scope vastleggen. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E0.S1 | Besluit en scope vastleggen | Keuze voor route group vastgelegd + out of scope lijst | Done | - | 2 | -| E0.S2 | UX entry/exit flow vastleggen | Flow voor toegang en terug naar EPD gedocumenteerd | Done | E0.S1 | 2 | - -Technical notes: -- Geen code changes voor E0; alleen documentatie en alignment. - -### Epic 1 - Routing & layout scheiding -Epic doel: Swift UI draait full-screen buiten EPD layout. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E1.S1 | Route group toevoegen | `app/(swift)` bestaat en `/epd/swift` blijft werken | Done | E0.S1 | 3 | -| E1.S2 | Swift layout isoleren | Swift layout rendert full-screen zonder sidebar | Done | E1.S1 | 3 | -| E1.S3 | Auth guard borgen | Ongeauth users redirect naar `/login` zoals nu | Done | E1.S2 | 2 | -| E1.S4 | EPD layout regressie check | Klassiek EPD layout ongewijzigd | Done | E1.S2 | 2 | - -Technical notes: -- Geen nieuwe dependencies. -- Route group moet alleen Swift raken, niet EPD. -- EPDHeader wordt niet gebruikt in Swift; ContextBar is de top bar. - -### Epic 2 - Navigatie & toegang -Epic doel: gebruikers kunnen Swift starten en verlaten zonder verwarring. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E2.S1 | Entry points controleren | Links naar `/epd/swift` werken (EPD menu/login) | Done | E1.S2 | 2 | -| E2.S2 | Exit back-link verifiΓ«ren | Context bar link naar `/epd` blijft consistent | Done | E1.S2 | 1 | -| E2.S3 | Deep link gedrag | Directe URL naar `/epd/swift` werkt met auth | Done | E1.S3 | 2 | - -Technical notes: -- Geen nieuwe navigatie items tenzij nodig voor MVP. - -### Epic 3 - Swift shell polish -Epic doel: full-screen ervaring is clean en consistent. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E3.S1 | Full-screen layout check | Geen sidebar spacing of EPD padding zichtbaar | Done | E1.S2 | 2 | -| E3.S2 | Responsive gedrag check | Chat/artifacts stacken op mobiel zoals nu | Done | E1.S2 | 2 | -| E3.S3 | Visuele consistentie | Context bar en offline banner correct gepositioneerd | Done | E1.S2 | 1 | - -Technical notes: -- Geen redesign of nieuwe UI componenten. - -### Epic 4 - QA & docs -Epic doel: MVP kwaliteit borgen en documentatie bijwerken. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E4.S1 | Manual QA checklist | Alle kritieke flows handmatig getest | To Do | E3.S2 | 2 | -| E4.S2 | Bouwplan en docs bijwerken | Bouwplan + korte notitie in docs/swift | To Do | E4.S1 | 1 | -| E4.S3 | Release note (kort) | Interne note met UX impact | To Do | E4.S1 | 1 | - -Technical notes: -- Gebruik `pnpm lint` voor basis check (geen extra tests). - ---- - -## 5. Kwaliteit & Testplan - -Test types: -| Test Type | Scope | Tools | Verantwoordelijke | -|-----------|-------|-------|-------------------| -| Lint | App code | pnpm lint | Developer | -| Smoke tests | Routing + auth + UX flows | Manual checklist | Developer/PO | -| Responsive check | Layout op mobile/desktop | Browser devtools | UX | - -Manual test checklist: -- [ ] `/epd/swift` laadt zonder sidebar -- [ ] EPDHeader en DocsChatWidget zijn niet zichtbaar in Swift -- [ ] Ongeauth redirect naar `/login` -- [ ] Entry vanuit EPD werkt -- [ ] Back-link naar `/epd` werkt -- [ ] Chat input werkt, artifacts openen -- [ ] Mobile: chat en artifacts stacken correct -- [ ] Deep link naar `/epd/swift` volgt interface-voorkeur na login - ---- - -## 6. Demo & Presentatieplan -Doel: korte interne demo van de standalone Swift ervaring. - -Flow: -1. Open `/epd/swift` (full-screen, no sidebar) -2. Start een chat en open artifact -3. Ga terug naar `/epd` via context bar - -Backup: -- Gebruik screenshots als live demo faalt. - ---- - -## 7. Risico's & Mitigatie -| Risico | Kans | Impact | Mitigatie | Owner | -|--------|------|--------|-----------|-------| -| Route group breekt `/epd` routing | Laag | Hoog | Isoleren in `app/(swift)` en regression check | Lead dev | -| Auth redirect mismatch | Middel | Middel | E1.S3 + manual QA | Lead dev | -| UX verwarring over modus | Middel | Middel | Duidelijke back-link + docs | UX | -| Scope creep (extra features) | Hoog | Middel | MVP guardrails in E0 | PO | -| Mobile layout regressie | Laag | Middel | E3.S2 + devtools check | UX | - ---- - -## 8. Evaluatie & Lessons Learned -Na oplevering documenteren: -- Was de mode-scheiding duidelijk voor users? -- Zijn entry/exit flows logisch? -- Zijn er regressies in klassiek EPD? - ---- - -## 9. Referenties -- Docs: `docs/swift/fo-swift-medical-scribe-v3.md` -- Docs: `docs/swift/v3-redesign-met-huidige-styling.md` -- Docs: `docs/swift/e0-design-tokens-and-components.md` -- Code: `app/epd/layout.tsx` -- Code: `app/(swift)/epd/swift/layout.tsx` -- Code: `components/swift/command-center/command-center.tsx` - ---- - -## 10. Glossary & Abbreviations -| Term | Betekenis | -|------|-----------| -| Epic | Grote feature of fase in development | -| Story | Kleine uitvoerbare taak binnen een epic | -| MVP | Minimum Viable Product | -| EPD | Elektronisch Patient Dossier | -| SSE | Server-Sent Events | - ---- - -Versiehistorie: -| Versie | Datum | Auteur | Wijziging | -|--------|-------|--------|-----------| -| v1.0 | 27-12-2025 | Colin Lit | Initiele versie | diff --git a/docs/swift/bouwplan-swift-v3.md b/docs/swift/bouwplan-swift-v3.md deleted file mode 100644 index e7aba1e..0000000 --- a/docs/swift/bouwplan-swift-v3.md +++ /dev/null @@ -1,1779 +0,0 @@ -# πŸš€ Mission Control β€” Bouwplan Swift v3.0 - -πŸ’‘ **Transformatie:** Van Command Center naar Swift Assistent Chatbot Interface - ---- - -**Projectnaam:** Swift Swift Assistent v3.0 -**Versie:** v3.0 -**Datum:** 27-12-2024 -**Auteur:** Colin Lit - ---- - -## 1. Doel en context - -🎯 **Doel:** Swift transformeren van een command-line style interface naar een conversational Swift Assistent chatbot met split-screen layout (chat links, artifacts rechts). - -πŸ“˜ **Context:** -De huidige Swift v2.1 werkt met een command-line paradigma waar gebruikers kort commando's typen ("notitie jan medicatie"). Dit werkt goed, maar voelt transactioneel aan. Gebruikers willen doorvragen, context behouden, en natuurlijker interacteren met het systeem. - -**De transformatie:** -- **Van:** Command-line input β†’ Centered blocks β†’ Recent strip -- **Naar:** Chat conversation β†’ Split-screen (40/60) β†’ Artifacts rechts - -**Waarom deze verandering:** -1. **Natuurlijkere interactie** β€” Voelt als praten met collega i.p.v. commando's typen -2. **Context behoud** β€” Conversatiegeschiedenis blijft zichtbaar -3. **Follow-up mogelijk** β€” Gebruiker kan doorvragen zonder opnieuw te beginnen -4. **Bekende UX** β€” Lijkt op ChatGPT Canvas / Claude Artifacts (bekend voor gebruikers) - -**Referenties:** -- **FO v3.0:** `fo-swift-medical-scribe-v3.md` β€” Functioneel ontwerp Swift Assistent -- **Haalbaarheid:** `haalbaarheidsanalyse-v3.md` β€” Feasibility analysis (6-8 weken, haalbaar) -- **UX Analyse:** `v3-redesign-met-huidige-styling.md` β€” Wat blijft vs. wijzigt -- **UX v2.1:** `archive/swift-ux-v2.1.md` β€” Huidige UX/styling - ---- - -## 2. Uitgangspunten - -### 2.1 Technische Stack - -**Frontend:** -- Next.js 14 (App Router) βœ… Bestaand -- React 18 met TypeScript βœ… Bestaand -- Tailwind CSS + shadcn/ui βœ… Bestaand -- Lucide Icons βœ… Bestaand -- Zustand (state management) βœ… Bestaand - -**Backend & Database:** -- Supabase (PostgreSQL + Auth) βœ… Bestaand -- FHIR-inspired datamodel βœ… Bestaand -- Row Level Security (RLS) βœ… Bestaand - -**AI/ML Services:** -- Anthropic Claude API (Sonnet 4.5) βœ… Bestaand -- Deepgram (speech-to-text) βœ… Bestaand -- Streaming API responses (SSE) πŸ†• Nieuw patroon voor chat - -**Hosting & Deploy:** -- Vercel (production deployment) βœ… Bestaand -- Environment variables via `.env.local` βœ… Bestaand - -**Nieuwe Dependencies:** -- Geen nieuwe externe libraries nodig -- Hergebruik van bestaande `/api/docs/chat` streaming pattern - -### 2.2 Projectkaders - -**Tijd:** -- **Totaal:** 6-8 weken bouwtijd -- **Fase 1 (Foundation):** Week 1-2 -- **Fase 2 (Chat API):** Week 3-4 -- **Fase 3 (Artifacts & Polish):** Week 5-6 -- **Fase 4 (Testing):** Week 7-8 - -**Team:** -- 1 developer (full-time) -- AI assistant (Claude Code) voor development support - -**Scope:** -- **In scope:** Alle P1 intents (dagnotitie, zoeken, overdracht, patient context) -- **Out of scope:** P2/P3 intents blijven werken maar geen redesign -- **Feature flag:** v3.0 achter feature flag zodat v2.1 beschikbaar blijft - -**Data:** -- Alle bestaande Supabase data blijft werken -- Geen database migraties nodig -- Alleen nieuwe API endpoints + frontend components - -**Risicomanagement:** -- Incremental rollout via feature flag -- v2.1 blijft beschikbaar als fallback -- A/B testing mogelijk voor user feedback - -### 2.3 Programmeer Uitgangspunten - -**Code Quality Principles:** - -- **DRY (Don't Repeat Yourself)** - - Herbruikbare chat components (`ChatMessage`, `ChatBubble`) - - Centrale config voor message types - - Shared utilities voor streaming responses - -- **KISS (Keep It Simple, Stupid)** - - Geen overengineering van chat state - - Eenvoudige Zustand store uitbreiding - - Geen nieuwe frameworks/libraries indien niet nodig - -- **SOC (Separation of Concerns)** - - Chat UI gescheiden van artifact logic - - Message rendering gescheiden van streaming logic - - API calls in dedicated `/lib/swift/chat-api.ts` - -- **YAGNI (You Aren't Gonna Need It)** - - Bouw alleen conversation features die in FO staan - - Geen "nice to have" features (bijv. message editing, reactions) - - Start met max 3 artifacts, niet meer - -**Development Practices:** - -- **Code Organization** - ``` - components/swift/ - β”œβ”€β”€ chat/ # πŸ†• Nieuwe chat components - β”‚ β”œβ”€β”€ chat-panel.tsx - β”‚ β”œβ”€β”€ chat-message.tsx - β”‚ β”œβ”€β”€ chat-input.tsx - β”‚ └── streaming-indicator.tsx - β”œβ”€β”€ artifacts/ # πŸ†• Nieuwe artifact wrapper - β”‚ β”œβ”€β”€ artifact-container.tsx - β”‚ └── artifact-tab.tsx - β”œβ”€β”€ blocks/ # βœ… Bestaand, blijft werken - β”‚ β”œβ”€β”€ dagnotitie-block.tsx - β”‚ β”œβ”€β”€ zoeken-block.tsx - β”‚ └── overdracht-block.tsx - └── command-center/ # πŸ”„ Wijzigt naar split-screen - β”œβ”€β”€ command-center.tsx - β”œβ”€β”€ context-bar.tsx # βœ… Blijft ongewijzigd - └── offline-banner.tsx # βœ… Blijft ongewijzigd - ``` - -- **Error Handling** - - Hergebruik bestaande `lib/swift/error-handler.ts` - - Chat-specific error states (connection lost, stream interrupted) - - User-friendly foutmeldingen in chat ("Er ging iets mis, probeer opnieuw") - -- **Security** - - API keys blijven server-side (Claude API key) - - Chat messages niet persistent opgeslagen (alleen in session state) - - RLS rules blijven gelden voor artifacts - -- **Performance** - - Virtual scrolling voor lange chat histories (>100 messages) - - Debounce op typing indicator (300ms) - - Lazy load artifacts (alleen renderen wanneer actief) - - Streaming responses via SSE (Server-Sent Events) - -- **Testing** - - Manual smoke tests voor alle chat flows - - Integration tests voor `/api/swift/chat` endpoint - - Edge case testing (stream interruption, long messages, etc.) - -**Voorbeeld implementatie:** -```typescript -// βœ… DRY - Herbruikbare message component -interface ChatMessageProps { - type: 'user' | 'assistant' | 'system' | 'error'; - content: string; - timestamp?: Date; -} - -export function ChatMessage({ type, content, timestamp }: ChatMessageProps) { - const styles = MESSAGE_STYLES[type]; // Centrale config - return ( -
- {/* ... */} -
- ); -} - -// βœ… SOC - API logic gescheiden -// In /lib/swift/chat-api.ts -export async function sendChatMessage( - message: string, - history: ChatMessage[] -): Promise { - const response = await fetch('/api/swift/chat', { - method: 'POST', - body: JSON.stringify({ message, history }), - }); - return response.body!; -} - -// βœ… KISS - Simpele state management -interface ChatState { - messages: ChatMessage[]; - isStreaming: boolean; - addMessage: (msg: ChatMessage) => void; -} - -const useChatStore = create((set) => ({ - messages: [], - isStreaming: false, - addMessage: (msg) => set((s) => ({ - messages: [...s.messages, msg] - })), -})); -``` - ---- - -## 3. Epics & Stories Overzicht - -🎯 **Doel:** De bouw opdelen in 6 logische epics met concrete deliverables. - -**Epic Structuur:** - -| Epic ID | Titel | Doel | Status | Stories | Story Points | Opmerkingen | -|---------|-------|------|--------|---------|--------------|-------------| -| E0 | Pre-work & Planning | Design tokens, component audit, system prompt | βœ… **Compleet** | 3/3 | 5 SP | Docs aangemaakt | -| E1 | Foundation - Split-screen | Layout naar 40/60 split | βœ… **Compleet** | 3/3 | 12 SP | E1.S1 geskipt (geen feature flag) | -| E2 | Chat Panel & Messages | Chat UI zonder AI | βœ… **Compleet** | 5/5 | 13 SP | Scrolling, input, shortcuts | -| E3 | Chat API & Swift Assistent | AI conversatie werkend | βœ… **Compleet** | 6/6 | 21 SP | Artifact opening werkend! | -| E4 | Artifact Area & Tabs | Meerdere artifacts mogelijk | βœ… **Compleet** | 3/4 | 10 SP | E4.S4 geskipt (placeholder in E4.S1) | -| E5 | AI-Filtering & Polish | Psychiater filtering, polish | βœ… **Compleet** | 5/5 | 13 SP | E5 COMPLEET πŸŽ‰ | -| E6 | Testing & Refinement | QA, bugs, performance | ⏳ To Do | 0/4 | 8 SP | Week 7-8 | - -**Totaal:** 31 stories, **82 Story Points** (~7 weken Γ  12 SP/week, 7 SP geannuleerd door skips) -**Voortgang:** βœ… 24/31 stories compleet, 3 geskipt = 27 done (71 SP / 82 SP = **87%**) - -**Belangrijk:** -- ⚠️ Voer niet in 1x het volledige plan uit. Bouw per epic en per story. -- ⚠️ Dependencies/migraties moeten eerst aan Colin worden gemeld. -- Feature flag vanaf E1: `FEATURE_FLAG_SWIFT_V3=true` in `.env.local` - ---- - -## 4. Epics & Stories (Uitwerking) - -### Epic 0 β€” Pre-work & Planning βœ… **COMPLEET** - -**Epic Doel:** Voorbereiding werk voordat development start. Design tokens verificatie, component audit, Swift Assistent system prompt. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E0.S1 | Design tokens audit | Alle kleuren/spacing/typography gedocumenteerd in v3 doc | βœ… **Compleet** | β€” | 1 | -| E0.S2 | Component inventory | Lijst van alle blocks die herbruikbaar zijn | βœ… **Compleet** | β€” | 2 | -| E0.S3 | Medical scribe system prompt | Eerste versie prompt voor `/api/swift/chat`, getest met Claude | βœ… **Compleet** | β€” | 2 | - -**Technical Notes:** -- E0.S1: Check of alle tokens uit v2.1 nog kloppen voor v3.0 βœ… -- E0.S2: Maak lijst van blocks die NIET wijzigen vs. die WEL wijzigen βœ… -- E0.S3: Prompt moet Nederlands zijn, vriendelijk maar professioneel, intent detection βœ… - -**Deliverables:** -- βœ… `docs/swift/e0-design-tokens-and-components.md` β€” Design tokens audit + component inventory -- βœ… `docs/swift/e0-medical-scribe-system-prompt.md` β€” Medical scribe prompt v1.0 - ---- - -### Epic 1 β€” Foundation - Split-screen Layout βœ… **COMPLEET** - -**Epic Doel:** CommandCenter omzetten naar split-screen layout (40% chat, 60% artifacts). - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| ~~E1.S1~~ | ~~Feature flag setup~~ | ~~`FEATURE_FLAG_SWIFT_V3` in `.env` + conditional rendering~~ | ❌ **GESKIPT** | β€” | ~~1~~ | -| E1.S2 | CommandCenter layout wijzigen | Split-screen grid (40/60), context bar blijft | βœ… **Compleet** | E0.S2 | 5 | -| E1.S3 | Placeholder componenten | ChatPanel (welcome msg), ArtifactArea (placeholder) | βœ… **Compleet** | E1.S2 | 2 | -| E1.S4 | Responsive breakpoints | Desktop/tablet/mobile toggle tussen chat/artifact | βœ… **Compleet** | E1.S3 | 5 | - -**Technical Notes:** -```tsx -// E1.S2 - Layout structuur -
- {/* Blijft ongewijzigd */} - -
- {/* Chat Panel - 40% */} -
- {/* Placeholder in E1.S3 */} -
- - {/* Artifact Area - 60% */} -
- {/* Placeholder in E1.S3 */} -
-
-
-``` - -**Responsive breakpoints (E1.S4):** -- Desktop (>1200px): 40/60 split zichtbaar -- Tablet (768-1200px): 45/55 split -- Mobile (<768px): Toggle tussen chat en artifact (full screen) - -**Deliverables:** -- βœ… `components/swift/chat/chat-panel.tsx` β€” Chat placeholder met welcome message -- βœ… `components/swift/artifacts/artifact-area.tsx` β€” Artifact placeholder met voorbeelden -- βœ… `components/swift/command-center/command-center.tsx` β€” Gerefactored naar split-screen (40/60) -- βœ… Responsive breakpoints: `lg:w-[40%]` en `lg:w-[60%]` (desktop), `w-full` (mobile) -- βœ… Build succesvol zonder errors - -**Note:** E1.S1 (Feature flag) geskipt β€” we werken op separate branch `swift` i.p.v. feature flag - ---- - -### Epic 2 β€” Chat Panel & Messages βœ… **COMPLEET** - -**Epic Doel:** Chat UI werkend krijgen zonder AI (gebruikers kunnen typen en zien messages verschijnen). - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E2.S1 | Store uitbreiding | `chatMessages`, `isStreaming` in swift-store.ts | βœ… **Compleet** | E1.S4 | 2 | -| E2.S2 | ChatMessage component | User/assistant/system/error message types met styling | βœ… **Compleet** | E2.S1 | 3 | -| E2.S3 | ChatPanel component | Scrollable message list, auto-scroll, scroll-lock | βœ… **Compleet** | E2.S2 | 5 | -| E2.S4 | ChatInput component | Tekst input onderaan chat (40% width), enter to send | βœ… **Compleet** | E2.S3 | 2 | -| E2.S5 | Keyboard shortcuts | ⌘K focus, Escape clear, Enter submit | βœ… **Compleet** | E2.S4 | 1 | - -**Technical Notes:** - -**E2.S1 - Store uitbreiding:** -```typescript -// stores/swift-store.ts -interface SwiftStore { - // Bestaand - activePatient: Patient | null; - activeBlock: BlockType | null; - shift: ShiftType; - - // Nieuw voor chat - chatMessages: ChatMessage[]; - isStreaming: boolean; - pendingAction: Action | null; - - // Actions - addChatMessage: (message: ChatMessage) => void; - clearChat: () => void; - setStreaming: (streaming: boolean) => void; -} -``` - -**E2.S2 - Message styling:** -```tsx -// components/swift/chat/chat-message.tsx -const MESSAGE_STYLES = { - user: { - container: 'self-end bg-amber-50 border-amber-200', - borderRadius: 'rounded-2xl rounded-tr-sm', - }, - assistant: { - container: 'self-start bg-slate-100 border-slate-200', - borderRadius: 'rounded-2xl rounded-tl-sm', - }, - system: { - container: 'self-center bg-transparent text-slate-500 text-sm', - borderRadius: '', - }, - error: { - container: 'self-start bg-red-50 border-red-200', - borderRadius: 'rounded-2xl', - }, -}; -``` - -**E2.S3 - Auto-scroll gedrag:** -- Auto-scroll naar laatste message bij nieuwe message -- Scroll-lock wanneer user omhoog scrollt (detecteer scroll position) -- "↓ Scroll to bottom" knop verschijnt bij nieuwe messages tijdens scroll-lock - -**E2.S4 - Chat input:** -- Onderaan chat panel (40% width) -- Multi-line support (Shift+Enter voor new line) -- Enter submit (tenzij Shift pressed) -- Placeholder: "Typ of spreek..." - -**E2.S5 - Keyboard shortcuts:** -- ⌘K / Ctrl+K: Focus chat input (global) -- Escape: Clear input (local) -- Enter: Submit message -- Shift+Enter: New line - -**Deliverables:** -- βœ… `stores/swift-store.ts` (+87 regels) β€” Chat state: chatMessages[], isStreaming, pendingAction, actions -- βœ… `components/swift/chat/chat-message.tsx` (76 regels) β€” Message component met 4 types (user/assistant/system/error) -- βœ… `components/swift/chat/chat-panel.tsx` (148 regels) β€” Scrollable message list, auto-scroll, scroll-lock, keyboard shortcuts -- βœ… `components/swift/chat/chat-input.tsx` (184 regels) β€” Multi-line input, Enter submit, Shift+Enter new line, forwardRef -- βœ… Keyboard shortcuts: ⌘K focus, Escape clear, Enter submit, Shift+Enter new line -- βœ… Auto-scroll met scroll-lock detection (100px threshold) -- βœ… "Scroll naar beneden" button bij scroll-lock -- βœ… Cross-platform support (macOS + Windows/Linux) -- βœ… Build succesvol zonder errors - -**Git Commits:** -- `e3ff72c` β€” E2.S1 & E2.S2 (Store uitbreiding + ChatMessage component) -- `b5e245e` β€” E2.S3 (ChatPanel scrolling functionaliteit) -- `8f6f24f` β€” E2.S4 (ChatInput component met keyboard shortcuts) -- `d2931a3` β€” E2.S5 (Global keyboard shortcuts ⌘K focus) - ---- - -### Epic 3 β€” Chat API & Swift Assistent βœ… **COMPLEET** - -**Epic Doel:** AI conversatie werkend krijgen met intent detection en artifact opening. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E3.S1 | Chat API endpoint skeleton | `/api/swift/chat` route met SSE setup | βœ… **Compleet** | E2.S5 | 3 | -| E3.S2 | Streaming response logic | Claude API streaming werkt, chunks naar frontend | βœ… **Compleet** | E3.S1 | 5 | -| E3.S3 | Medical scribe system prompt | Prompt met role, intents, examples, Nederlands | βœ… **Compleet** | E3.S2 | 3 | -| E3.S4 | Intent detection in response | AI genereert action objects (intent + entities) | βœ… **Compleet** | E3.S3 | 5 | -| ~~E3.S5~~ | ~~Frontend streaming handling~~ | ~~useChatStream hook, message chunks renderen~~ | ❌ **GESKIPT** | ~~E3.S4~~ | ~~3~~ | -| E3.S6 | Artifact opening from chat | Action object opent juiste block met prefill | βœ… **Compleet** | E3.S4 | 2 | - -**Technical Notes:** - -**E3.S1 - API Route:** -```typescript -// app/api/swift/chat/route.ts -export async function POST(req: Request) { - const { message, messages, context } = await req.json(); - - // Streaming response - const encoder = new TextEncoder(); - const stream = new ReadableStream({ - async start(controller) { - // Claude API streaming logic - }, - }); - - return new Response(stream, { - headers: { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache', - 'Connection': 'keep-alive', - }, - }); -} -``` - -**E3.S3 - System Prompt (samenvatting):** -``` -Je bent een medische assistent (Swift Assistent) voor Swift, een Nederlands GGZ EPD. - -Je rol: -- Help zorgmedewerkers met documentatie en administratie -- Voer natuurlijke gesprekken in het Nederlands -- Herken intents en voer acties uit wanneer nodig -- Stel verduidelijkingsvragen bij onduidelijkheid -- Wees vriendelijk maar professioneel - -Intents die je herkent: -- dagnotitie: notitie maken voor patiΓ«nt -- zoeken: patiΓ«nt zoeken -- rapportage: behandelrapportage schrijven -- overdracht: dienst overdracht maken - -Wanneer je een intent herkent, voeg een JSON action object toe: -{ - "type": "action", - "intent": "dagnotitie", - "entities": { "patient": "Jan de Vries", "category": "medicatie" }, - "confidence": 0.95 -} - -Context: -- Actieve patiΓ«nt: {{activePatient}} -- Dienst: {{shift}} -- Recente acties: {{recentActions}} -``` - -**E3.S4 - Action object format:** -```typescript -interface Action { - type: 'action'; - intent: IntentType; - entities: { - patient?: string; - patientId?: string; - category?: VerpleegkundigCategory; - content?: string; - }; - confidence: number; - artifact?: { - type: BlockType; - prefill: BlockPrefillData; - }; -} -``` - -**E3.S5 - Frontend streaming:** -```typescript -// lib/swift/use-chat-stream.ts -export function useChatStream() { - const addMessage = useSwiftStore((s) => s.addChatMessage); - const setStreaming = useSwiftStore((s) => s.setStreaming); - - const sendMessage = async (message: string) => { - setStreaming(true); - const response = await fetch('/api/swift/chat', { - method: 'POST', - body: JSON.stringify({ message, messages: /* ... */ }), - }); - - const reader = response.body!.getReader(); - let accumulatedText = ''; - - while (true) { - const { done, value } = await reader.read(); - if (done) break; - - const chunk = new TextDecoder().decode(value); - accumulatedText += chunk; - - // Update message in UI - addMessage({ type: 'assistant', content: accumulatedText }); - } - - setStreaming(false); - }; - - return { sendMessage }; -} -``` - -**E3.S6 - Artifact opening:** -- Parse action object uit AI response -- Open juiste block via `openBlock(artifact.type, artifact.prefill)` -- Block verschijnt rechts in artifact area - -**Deliverables (E3.S1 & E3.S2 compleet):** -- βœ… `app/api/swift/chat/route.ts` (307 regels) β€” SSE API endpoint met Claude streaming -- βœ… `lib/swift/chat-api.ts` (109 regels) β€” Client helper voor streaming -- βœ… `components/swift/chat/chat-panel.tsx` (updated) β€” Streaming integration -- βœ… Claude API integration (Sonnet 4, 2048 tokens, temp 0.7) -- βœ… Real-time streaming via Server-Sent Events -- βœ… Event parsing (content_block_delta, message_stop, error) -- βœ… Simple system prompt met context (patiΓ«nt + dienst) -- βœ… Rate limiting (20 req/min per user) -- βœ… Authentication + error handling -- βœ… Conversation history (max 20 messages) - -**Deliverables (E3.S3 compleet):** -- βœ… `buildMedicalScribePrompt()` functie (243 regels) β€” Volledige Swift Assistent prompt v1.0 -- βœ… Intent detection instructies: dagnotitie, zoeken, overdracht, rapportage -- βœ… P1 & P2 intents met triggers en entities -- βœ… Confidence thresholds (>0.9, 0.7-0.9, 0.5-0.7, <0.5) -- βœ… JSON action object format met examples -- βœ… Context injection (activePatient, shift) -- βœ… Verduidelijkingsvragen en error handling -- βœ… Nederlands tone of voice (vriendelijk, professioneel, to-the-point) -- βœ… 4 voorbeelden: dagnotitie, zoeken, verduidelijking, onduidelijke intent -- βœ… Build succesvol zonder type errors - -**Deliverables (E3.S4 compleet):** -- βœ… `lib/swift/action-parser.ts` (149 regels) β€” JSON action parser met Zod validatie -- βœ… `parseActionFromResponse()` β€” Extract JSON from ```json code blocks -- βœ… `extractJsonBlock()` β€” Markdown code block regex matching -- βœ… `removeJsonBlocks()` β€” Clean text content zonder JSON -- βœ… `shouldOpenArtifact()` β€” Confidence threshold check (β‰₯0.7) -- βœ… `getConfidenceLabel()` β€” User-friendly labels (Zeer zeker, Redelijk zeker, etc.) -- βœ… `validateArtifactType()` β€” Intent/artifact type matching validation -- βœ… ChatPanel: Action parsing in onDone callback -- βœ… ChatPanel: setPendingAction voor artifact opening (E3.S6) -- βœ… ChatMessage: Action badge met intent + confidence indicator -- βœ… Store: updateLastMessage met optional action parameter -- βœ… Action schema validation: intent, entities, confidence, artifact -- βœ… Visual feedback: Sparkles icon, CheckCircle voor high confidence -- βœ… Console logging voor debugging action detection -- βœ… Build succesvol zonder type errors - -**Git Commits:** -- `a51acf6` β€” E3.S1 & E3.S2 (Chat API + Claude streaming) -- `8efac84` β€” E3.S3 (Medical scribe system prompt v1.0) -- (to be committed) β€” E3.S4 (Intent detection in response) - -**Note E3.S5 - GESKIPT:** -E3.S5 (useChatStream hook) is geskipt omdat: -- Streaming logica al werkend geΓ―mplementeerd in ChatPanel (E3.S2) -- Inline implementatie is voldoende voor huidige use case -- Geen andere components gebruiken streaming (YAGNI principe) -- Refactor naar hook kan later indien nodig -- Dependencies: E3.S6 nu afhankelijk van E3.S4 i.p.v. E3.S5 - -**Deliverables (E3.S6 compleet):** -- βœ… `components/swift/artifacts/artifact-area.tsx` (updated) β€” Renders active blocks -- βœ… ArtifactArea: DagnotatieBlock, ZoekenBlock, OverdrachtBlock rendering -- βœ… ArtifactArea: Placeholder state wanneer geen block actief -- βœ… CommandCenter: useEffect voor pendingAction handling -- βœ… CommandCenter: openBlock() aanroep met artifact type + prefill -- βœ… CommandCenter: setPendingAction(null) na verwerking -- βœ… Console logging: "[CommandCenter] Processing pending action" -- βœ… Console logging: "[CommandCenter] Opening artifact: [type] with prefill" -- βœ… Block opening flow: Chat β†’ Action β†’ PendingAction β†’ Block opens -- βœ… Build succesvol zonder errors - -**Git Commits:** -- `a51acf6` β€” E3.S1 & E3.S2 (Chat API + Claude streaming) -- `8efac84` β€” E3.S3 (Medical scribe system prompt v1.0) -- `9b85448` β€” E3.S4 (Intent detection in response) -- `5b10176` β€” E3.S5 skip documentatie -- (to be committed) β€” E3.S6 (Artifact opening from chat) - -**πŸŽ‰ EPIC 3 COMPLEET!** Alle stories (5 compleet, 1 geskipt) afgerond. Medical scribe chat werkt end-to-end! - ---- - -### Epic 4 β€” Artifact Area & Tabs βœ… **COMPLEET** - -**Epic Doel:** Meerdere artifacts tegelijk mogelijk met tabs, slide-in animaties. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E4.S1 | ArtifactContainer component | Wrapper met tabs bovenaan, max 3 artifacts | βœ… **Compleet** | E3.S6 | 5 | -| E4.S2 | Artifact lifecycle management | Open/close/switch tussen artifacts in store | βœ… **Compleet** | E4.S1 | 3 | -| E4.S3 | Slide-in animatie | Artifact slide-in van rechts (200ms ease-out) | βœ… **Compleet** | E4.S2 | 2 | -| ~~E4.S4~~ | ~~Placeholder state~~ | ~~"Artifacts verschijnen hier" met voorbeelden~~ | ❌ **GESKIPT** | ~~E4.S3~~ | ~~3~~ | - -**Technical Notes:** - -**E4.S1 - ArtifactContainer:** -```tsx -// components/swift/artifacts/artifact-container.tsx -interface Artifact { - id: string; - type: BlockType; - prefill: BlockPrefillData; - title: string; -} - -export function ArtifactContainer() { - const { openArtifacts, activeArtifactId } = useSwiftStore(); - - if (openArtifacts.length === 0) { - return ; - } - - return ( -
- {/* Tabs - alleen tonen bij >1 artifact */} - {openArtifacts.length > 1 && ( -
- {openArtifacts.map((artifact) => ( - - ))} -
- )} - - {/* Active artifact */} -
- {renderArtifact(activeArtifact)} -
-
- ); -} -``` - -**E4.S2 - Store uitbreiding:** -```typescript -interface SwiftStore { - // ... bestaand - - // Artifact state - openArtifacts: Artifact[]; // Max 3 - activeArtifactId: string | null; - - // Actions - openArtifact: (artifact: Artifact) => void; - closeArtifact: (id: string) => void; - switchArtifact: (id: string) => void; -} - -// Logic: max 3 artifacts, oudste wordt gesloten bij 4e -const openArtifact = (artifact: Artifact) => { - set((state) => { - let artifacts = [...state.openArtifacts]; - if (artifacts.length >= 3) { - artifacts = artifacts.slice(1); // Remove oldest - } - return { - openArtifacts: [...artifacts, artifact], - activeArtifactId: artifact.id, - }; - }); -}; -``` - -**E4.S3 - Animatie:** -```css -/* globals.css */ -@keyframes artifact-enter { - from { - transform: translateX(100%); - opacity: 0; - } - to { - transform: translateX(0); - opacity: 1; - } -} - -.artifact-enter { - animation: artifact-enter 200ms ease-out; -} -``` - -**E4.S4 - Placeholder:** -```tsx -function ArtifactPlaceholder() { - return ( -
-
πŸ’¬
-

Artifacts verschijnen hier

-

Vraag me iets, bijvoorbeeld:

-
    -
  • β€’ "Notitie voor Jan: medicatie gegeven"
  • -
  • β€’ "Zoek Marie van den Berg"
  • -
  • β€’ "Maak overdracht voor deze dienst"
  • -
-
- ); -} -``` - -**Deliverables (E4.S1 compleet):** -- βœ… `stores/swift-store.ts` β€” Artifact interface gedefineerd (id, type, prefill, title, createdAt) -- βœ… `components/swift/artifacts/artifact-tab.tsx` (60 regels) β€” Tab component met close button -- βœ… `components/swift/artifacts/artifact-container.tsx` (127 regels) β€” Container met tabs + rendering -- βœ… ArtifactTab: Active state styling, hover effects, close button -- βœ… ArtifactTab: Title truncation, tooltip, min/max width -- βœ… ArtifactContainer: Tabs alleen bij >1 artifact -- βœ… ArtifactContainer: renderArtifactBlock() voor alle block types -- βœ… ArtifactContainer: getArtifactTitle() helper functie -- βœ… ArtifactContainer: Placeholder state wanneer geen artifacts -- βœ… Conditional rendering: DagnotatieBlock, ZoekenBlock, OverdrachtBlock, FallbackPicker -- βœ… Build succesvol zonder errors - -**Git Commits:** -- (to be committed) β€” E4.S1 (ArtifactContainer component) - -**Deliverables (E4.S2 compleet):** -- βœ… `stores/swift-store.ts` β€” openArtifacts[], activeArtifactId state -- βœ… Store actions: openArtifact(), closeArtifact(), switchArtifact(), closeAllArtifacts() -- βœ… openArtifact: Auto-generate ID + timestamp, max 3 logic (remove oldest) -- βœ… closeArtifact: Filter out artifact, auto-switch to last remaining -- βœ… switchArtifact: Verify exists, set activeArtifactId -- βœ… closeAllArtifacts: Clear all artifacts + active ID -- βœ… Console logging: "[Store] Opening artifact:", "[Store] Closing artifact:", etc. -- βœ… ArtifactArea: Refactored to use ArtifactContainer -- βœ… ArtifactArea: Pass store actions (switchArtifact, closeArtifact) -- βœ… CommandCenter: openArtifact() i.p.v. openBlock() -- βœ… CommandCenter: getArtifactTitle() voor artifact titles -- βœ… CommandCenter: Escape key β†’ closeAllArtifacts() -- βœ… Integration: Chat β†’ Action β†’ openArtifact β†’ Tabs + Container -- βœ… Build succesvol zonder errors - -**Git Commits:** -- `855744c` β€” E4.S1 (ArtifactContainer component) -- `f6c422b` β€” E4.S2 (Artifact lifecycle management) - -**Deliverables (E4.S3 compleet):** -- βœ… `app/globals.css` β€” artifact-enter keyframes + animation class -- βœ… Keyframes: translateX(100%) β†’ translateX(0) met opacity fade-in -- βœ… Animation: 200ms ease-out (conform bouwplan) -- βœ… Reduced motion support: animation: none voor prefers-reduced-motion -- βœ… ArtifactContainer: artifact-enter class op content wrapper -- βœ… Key prop op wrapper div (activeArtifact.id) β†’ re-triggers animatie bij switch -- βœ… Smooth slide-in van rechts bij artifact open/switch -- βœ… Build succesvol zonder errors - -**Git Commits:** -- (to be committed) β€” E4.S3 (Slide-in animatie) - -**Note E4.S4 - GESKIPT:** -E4.S4 (Placeholder state) is geskipt omdat: -- Placeholder al volledig geΓ―mplementeerd in E4.S1 (lines 79-92 artifact-container.tsx) -- Bevat emoji (πŸ“‹), titel, en voorbeelden zoals gespecificeerd in bouwplan -- Geen extra werk nodig, acceptatiecriteria al behaald -- Story Points niet meegeteld in totaal (3 SP geannuleerd) - -**πŸŽ‰ EPIC 4 COMPLEET!** Alle stories (3 compleet, 1 geskipt) afgerond. Artifact systeem volledig functioneel met tabs, lifecycle management, en smooth animaties! - -**Epic 4 Samenvatting:** -- **Status:** βœ… Compleet (3/4 stories, 10 SP) -- **Duur:** Stories E4.S1-E4.S3 -- **Geskipt:** E4.S4 (placeholder al in E4.S1) -- **Impact:** Artifact systeem met tabs, max 3 concurrent, smooth animaties - -**Belangrijkste Features:** -1. **ArtifactContainer (E4.S1)** - Tab interface, max 3 artifacts, placeholder state -2. **Lifecycle Management (E4.S2)** - Open/close/switch artifacts, auto-cleanup bij 4e -3. **Slide-in Animaties (E4.S3)** - 200ms ease-out, reduced motion support - -**Files Gewijzigd:** -- `components/swift/artifacts/artifact-container.tsx` - Container met tabs -- `components/swift/artifacts/artifact-tab.tsx` - Tab component met close button -- `components/swift/artifacts/artifact-area.tsx` - Wrapper component -- `stores/swift-store.ts` - Artifact state management -- `app/globals.css` - artifact-enter keyframes - -**Git Commits:** -- `855744c` - E4.S1 (ArtifactContainer component) -- `f6c422b` - E4.S2 (Artifact lifecycle management) -- `a10a4c3` - E4.S3 (Slide-in animaties) + Epic 4 compleet - -**Voortgang:** 58 SP / 82 SP (71%) - Ready voor Epic 5! - ---- - -### Epic 5 β€” AI-Filtering & Polish βœ… **COMPLEET** - -**Epic Doel:** AI-filtering voor psychiater overdracht, linked evidence, final polish. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E5.S1 | AI-filtering psychiater | `/api/overdracht/generate` filtert op behandelrelevantie | βœ… | E4.S4 | 5 | -| E5.S2 | Linked evidence UI | Bronnotitie links in OverdrachtBlock, hover preview | βœ… | E5.S1 | 3 | -| E5.S3 | Voice input integratie | Bestaande Deepgram blijft werken in chat input | βœ… | E2.S4 | 2 | -| E5.S4 | Error states & offline | Chat error messages, offline banner margin fix | βœ… | E3.S2 | 2 | -| E5.S5 | Polish & animations | Smooth transitions, loading states, toast confirmations | βœ… | E5.S4 | 1 | - -**Technical Notes:** - -**E5.S1 - AI-filtering psychiater (Swift OverdrachtBlock):** - -**Context:** -- OverdrachtBlock is een Swift artifact (geopend via chat) -- Toont patient lijst met AI samenvattingen -- Gebruikt bestaande `/api/overdracht/generate` endpoint -- Verpleegkundigen hebben items gemarkeerd met `include_in_handover = true` - -**Implementatie - Role Toggle in OverdrachtBlock:** -```tsx -// components/swift/blocks/overdracht-block.tsx - -export function OverdrachtBlock({ prefill }: OverdrachtBlockProps) { - const [period, setPeriod] = useState('1d'); - const [filterRole, setFilterRole] = useState<'verpleegkundige' | 'psychiater'>('verpleegkundige'); // πŸ†• - - // Update generateSummary to include filterRole - const generateSummary = useCallback(async (patientId: string) => { - const response = await retryFetch( - () => safeFetch( - '/api/overdracht/generate', - { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - patientId, - period, - filterForRole: filterRole // πŸ†• Add role parameter - }), - }, - { operation: 'Overdracht genereren' } - ), - 3, - 1000 - ); - // ... - }, [period, filterRole]); // πŸ†• Add filterRole dependency - - return ( - -
- {/* πŸ†• Role Selector - NIEUW */} -
- -
- - -
-

- {filterRole === 'psychiater' - ? 'Alleen behandelrelevante informatie (medicatie, risico\'s, gedrag)' - : 'Volledige overdracht voor collega verpleegkundige' - } -

-
- - {/* Period Selector - blijft hetzelfde */} - {/* ... */} -
-
- ); -} -``` - -**API Schema Update:** -```typescript -// lib/types/overdracht.ts -export const GenerateOverdrachtSchema = z.object({ - patientId: z.string().uuid('Patient ID moet een geldige UUID zijn'), - period: z.enum(['1d', '3d', '7d', '14d']).optional().default('1d'), - filterForRole: z.enum(['psychiater', 'verpleegkundige']).optional().default('verpleegkundige'), // πŸ†• -}); - -export type GenerateOverdrachtInput = z.infer; -``` - -**API Route Update:** -```typescript -// app/api/overdracht/generate/route.ts - -export async function POST(request: NextRequest) { - const body = await request.json(); - const result = GenerateOverdrachtSchema.safeParse(body); - - const { patientId, period, filterForRole } = result.data; // πŸ†• Extract filterForRole - - // Load context (data loading blijft HETZELFDE - altijd include_in_handover=true) - const context = await loadOverdrachtContext(supabase, patientId, period); - - // Call Claude API with role-specific prompt - const aiResult = await callClaudeAPI(context, filterForRole); // πŸ†• Pass role - - // ... -} - -// πŸ†• Update callClaudeAPI signature -async function callClaudeAPI( - context: OverdrachtContext, - role: 'psychiater' | 'verpleegkundige' = 'verpleegkundige' // πŸ†• Add parameter -): Promise<{ - samenvatting: string; - aandachtspunten: Aandachtspunt[]; - actiepunten: string[]; -}> { - const systemPrompt = buildSystemPrompt(role); // πŸ†• Role-specific prompt - const userPrompt = buildOverdrachtUserPrompt(context); // Blijft hetzelfde - - const response = await fetch('https://api.anthropic.com/v1/messages', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': apiKey, - 'anthropic-version': '2023-06-01', - }, - body: JSON.stringify({ - model: 'claude-sonnet-4-20250514', - max_tokens: 2048, - temperature: 0.3, - system: systemPrompt, // πŸ†• Role-specific - messages: [{ role: 'user', content: userPrompt }], - }), - }); - - // ... rest blijft hetzelfde -} -``` - -**AI Prompt - Role-specific Filtering:** -```typescript -// lib/ai/overdracht-prompt.ts - -// πŸ†• New function for role-specific prompts -export function buildSystemPrompt(role: 'psychiater' | 'verpleegkundige'): string { - const basePrompt = OVERDRACHT_SYSTEM_PROMPT; // Bestaande prompt voor verpleegkundige - - if (role === 'psychiater') { - return `${basePrompt} - -## PSYCHIATER FILTERING -Je maakt overdracht voor een PSYCHIATER. Filter STRIKT op behandelrelevantie. - -De verpleegkundige heeft al items geselecteerd (include_in_handover=true), maar jij moet VERDER FILTEREN. - -βœ… WEL RELEVANT (include in samenvatting): -- Medicatie-issues: weigering, bijwerkingen, dosisaanpassingen, therapietrouw -- Stemming/gedrag: veranderingen van baseline, afwijkend gedrag, agitatie -- Risico-signalen: suΓ―cidale uitingen, automutilatie, agressie -- Psychotische symptomen: wanen, hallucinaties, desorganisatie, paranoia -- Crisis/dwang: separatie, fixatie, dwangmedicatie, vrijheidsbeperkende maatregelen -- Afwijkende vitals: HH (kritiek hoog), LL (kritiek laag) met behandelimpact - -❌ FILTER UIT (niet in samenvatting): -- Routine medicatie: "medicatie volgens schema", "zonder problemen", "ingenomen conform afspraak" -- ADL activiteiten: douchen, aankleden, eten, drinken (tenzij significant afwijkend/weigering) -- Sociale activiteiten: "deelgenomen aan groepstherapie", "gesprek gehad", "koffie gedronken" -- Standaard observaties: "rustige dag", "geen bijzonderheden", "normaal functioneren" -- Routine vitals: bloeddruk/pols binnen normaalwaarden (N interpretatie) -- Dagstructuur: "dagprogramma gevolgd", "aanwezig bij activiteit" - -VUISTREGEL: Include ALLEEN als een psychiater op basis van deze info een BEHANDELBESLISSING kan nemen. - -Beperkingen: -- Maximum 3 aandachtspunten (ALLEEN behandelrelevant, geen routine items) -- Maximum 2 actiepunten (ALLEEN actionable voor psychiater) -- Bij twijfel of iets relevant is β†’ FILTER UIT - -Voorbeelden: -βœ… INCLUDE: "Jan weigerde haloperidol, zegt dat medicatie hem controleert" β†’ Medicatie-compliance issue -βœ… INCLUDE: "Marie uitte suΓ―cidale gedachten tijdens gesprek" β†’ Risicosignaal, urgent -βœ… INCLUDE: "Piet verbaal en fysiek agressief, separatie 30 min" β†’ Crisis, gedragsverandering -❌ FILTER: "Jan heeft goed gegeten, ontbijt en lunch zonder problemen" β†’ Routine ADL -❌ FILTER: "Marie deelgenomen aan groepstherapie" β†’ Sociale activiteit, geen issues -❌ FILTER: "Piet heeft medicatie ingenomen volgens schema" β†’ Routine medicatie - -Geef je antwoord als PURE JSON, zonder markdown code blocks.`; - } - - // Verpleegkundige gebruikt bestaande prompt (geen filtering) - return basePrompt; -} - -// Bestaande OVERDRACHT_SYSTEM_PROMPT blijft voor verpleegkundige view -export const OVERDRACHT_SYSTEM_PROMPT = `Je bent een ervaren verpleegkundige die overdrachten maakt in een GGZ-instelling. -...`; // Blijft hetzelfde -``` - -**Filtering Logic:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Report Filtering Flow β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -Stap 1 (Server - ALTIJD): - β”œβ”€ Filter: include_in_handover = true - └─ Result: Alleen aangevinkte items (bijv. 8 reports) - -Stap 2 (AI - Role-afhankelijk): - β”œβ”€ Verpleegkundige: Geen extra filtering (toon alle 8 reports) - └─ Psychiater: Filter op behandelrelevantie (bijv. 3 relevante reports) - -Output: - β”œβ”€ Verpleegkundige: 5 aandachtspunten, 3 actiepunten (volledige context) - └─ Psychiater: 2-3 aandachtspunten, 1-2 actiepunten (behandelrelevant) -``` - -**Deliverables (E5.S1 - COMPLEET):** -- βœ… `lib/types/overdracht.ts` (+1 regel) β€” GenerateOverdrachtSchema met filterForRole parameter -- βœ… `lib/ai/overdracht-prompt.ts` (+52 regels) β€” buildSystemPrompt(role) functie met psychiater filtering regels -- βœ… `app/api/overdracht/generate/route.ts` (+8/-8 regels) β€” callClaudeAPI signature met role parameter -- βœ… `components/swift/blocks/overdracht-block.tsx` (+43 regels) β€” Role toggle UI (Verpleegkundige/Psychiater) -- βœ… API call updated met filterForRole in request body (line 143) -- βœ… Psychiater prompt: max 3 aandachtspunten, 2 actiepunten, strict filtering op behandelrelevantie -- βœ… Verpleegkundige prompt: blijft hetzelfde (geen extra filtering, base prompt) -- βœ… UI: Role selector (grid 2 cols) met beschrijving per rol ("Alle gemarkeerde items" vs "Behandelrelevante items") -- βœ… Build succesvol zonder errors (pnpm build) -- βœ… filterRole state + useCallback dependency update in generateSummary - -**Acceptatiecriteria:** -1. βœ… Role toggle zichtbaar in OverdrachtBlock ("Doelgroep" selector met 2 knoppen) -2. βœ… Default role = "verpleegkundige" (backwards compatible) -3. βœ… Psychiater view filtert op behandelrelevantie (medicatie-issues, gedrag, risico, crisis) -4. βœ… Psychiater view filtert UIT: routine medicatie, ADL, sociale activiteiten, dagstructuur -5. βœ… Verpleegkundige view blijft werken zoals voorheen (alle aangevinkte items, max 5 aandachtspunten) -6. βœ… AI prompt duidelijk onderscheid tussen WEL/NIET relevant voor psychiater (βœ…/❌ voorbeelden in prompt) -7. βœ… Build succesvol, geen type errors - -**Git Commits:** -- `c6616d8` β€” E5.S1 (AI-filtering psychiater voor overdracht, 104 insertions, 8 deletions) - ---- - -**E5.S2 - Linked evidence (COMPLEET):** - -**Doel:** Bronverwijzingen klikbaar maken met hover preview van volledige source content. - -**Implementatie:** -```tsx -// components/swift/shared/linked-evidence.tsx -interface LinkedEvidenceProps { - bron: Aandachtspunt['bron']; - sourceData?: Aandachtspunt['sourceData']; - className?: string; -} - -export function LinkedEvidence({ bron, sourceData, className }: LinkedEvidenceProps) { - // If no source data, just show label without popover - if (!sourceData) return {bron.label} β€’ {bron.datum}; - - return ( - - - - - - {/* Type-specific content display */} - {bron.type === 'observatie' && ( -
- {sourceData.value} {sourceData.unit} -
- Interpretatie: {sourceData.interpretation} -
-
- )} - {/* ... other types ... */} -
-
- ); -} -``` - -**Source Data Enrichment:** -```typescript -// app/api/overdracht/generate/route.ts -function enrichWithSourceData( - aandachtspunten: Aandachtspunt[], - context: OverdrachtContext -): Aandachtspunt[] { - return aandachtspunten.map((punt) => { - const { bron } = punt; - let sourceData: Aandachtspunt['sourceData']; - - switch (bron.type) { - case 'observatie': - const vital = context.vitals.find((v) => v.id === bron.id); - if (vital) sourceData = { value: vital.value_quantity_value, ... }; - break; - case 'rapportage': - case 'verpleegkundig': - const report = context.reports.find((r) => r.id === bron.id); - if (report) sourceData = { content: report.content, ... }; - break; - case 'risico': - const risk = context.risks.find((r) => r.id === bron.id); - if (risk) sourceData = { riskLevel: risk.risk_level, ... }; - break; - } - - return { ...punt, sourceData }; - }); -} -``` - -**Deliverables (E5.S2 - COMPLEET):** -- βœ… `lib/types/overdracht.ts` (+12 regels) β€” Aandachtspunt type extended met sourceData field -- βœ… `components/swift/shared/linked-evidence.tsx` (+160 regels NEW) β€” LinkedEvidence component met Popover -- βœ… `app/api/overdracht/generate/route.ts` (+58 regels) β€” enrichWithSourceData() functie -- βœ… `components/swift/blocks/overdracht-block.tsx` (+1/-3 regels) β€” LinkedEvidence integration in AandachtspuntItem -- βœ… Type-specific content display (observaties, rapportages, risico's) -- βœ… Color-coded interpretations (HH/LL red, H/L amber, N teal) -- βœ… Color-coded risk levels (hoog/zeer_hoog red, gemiddeld amber, laag teal) -- βœ… Hover popover met volledige source content -- βœ… Icons per type (Activity, FileText, AlertTriangle, ExternalLink) -- βœ… Build succesvol zonder errors -- βœ… Backwards compatible (werkt met/zonder sourceData) - -**Acceptatiecriteria:** -1. βœ… Bronverwijzingen zijn klikbaar/hoverable in OverdrachtBlock -2. βœ… Hover toont popover met volledige source content -3. βœ… Observaties tonen: value + unit + interpretation met kleuren -4. βœ… Rapportages tonen: content + createdBy -5. βœ… Risico's tonen: riskLevel + rationale met severity kleuren -6. βœ… Popover positioneert correct (side="top" align="start") -7. βœ… Visual feedback: underline-dotted, ExternalLink icon, cursor-help -8. βœ… Accessible: keyboard navigable, asChild trigger pattern -9. βœ… API enricht aandachtspunten met sourceData uit context -10. βœ… Build succesvol, geen type errors - -**Git Commits:** -- `adf6c3f` β€” E5.S2 (Linked evidence UI, 231 insertions, 4 deletions) - ---- - -**E5.S3 - Voice input integratie (COMPLEET - AL GEÏMPLEMENTEERD IN E2):** - -**Doel:** Voice input functionaliteit werkend in CommandInput met live transcript. - -**Status:** βœ… **Al volledig geΓ―mplementeerd in Epic 2** (Chat Panel & Messages) - -**Bestaande Implementatie:** - -1. **use-swift-voice.ts hook** (`lib/swift/use-swift-voice.ts` - 116 regels): - - Wraps `useDeepgramStreaming` voor Swift-specific behavior - - Live transcript streaming naar input field - - Base text tracking voor append/replace logica - - Voice active state management - -2. **CommandInput integratie** (`components/swift/command-center/command-input.tsx`): - - useSwiftVoice() hook geΓ―ntegreerd (regel 19, 38-47) - - Mic button rechts van input (regel 274-294) - - Waveform visualization tijdens recording (regel 215-222) - - handleVoiceToggle functie (regel 185-191) - - Status indicators: connecting, error (regel 245-255) - -**Deliverables (E5.S3 - AL COMPLEET):** -- βœ… `lib/swift/use-swift-voice.ts` (116 regels) β€” Voice hook met Deepgram streaming -- βœ… CommandInput: useSwiftVoice() hook integratie -- βœ… Mic icon rechts van input field (Mic/MicOff/Loader2) -- βœ… Live transcript verschijnt in input tijdens recording -- βœ… Waveform canvas visualization (200x40px) -- βœ… Voice button states: idle (slate), recording (red + ring), connecting (spinner) -- βœ… handleVoiceToggle: start/stop recording -- βœ… Browser support check (isBrowserSupported) -- βœ… Error handling met toast notifications -- βœ… Disabled states: tijdens processing of wanneer block open - -**Acceptatiecriteria:** -1. βœ… Bestaande use-swift-voice.ts hook werkt zonder wijzigingen -2. βœ… CommandInput gebruikt voice hook (regel 19) -3. βœ… Mic button zichtbaar rechts van input (regel 274-294) -4. βœ… Live transcript verschijnt in input tijdens recording (via setInputValue) -5. βœ… Waveform visualization actief tijdens recording -6. βœ… Voice button heeft 3 states: idle, recording, connecting -7. βœ… Browser support check voorkomt errors op niet-ondersteunde browsers -8. βœ… Build succesvol, geen errors - -**Technical Details:** -- Deepgram streaming: language='nl', model='nova-2', endpointingMs=2000 -- Base text tracking: baseTextRef stores text before recording -- Interim vs Final: interim = preview (replace), final = append to base -- Voice active state: synced met Swift store (setVoiceActive) -- Analyser node: gebruikt voor waveform frequency data - -**Git Commits:** -- GeΓ―mplementeerd in Epic 2 (E2.S4 - Voice input) - ---- - -**E5.S4 - Error states & offline (COMPLEET - AL GEÏMPLEMENTEERD IN E5.S2):** - -**Doel:** Error handling en offline detection met gebruiksvriendelijke berichten. - -**Status:** βœ… **Al volledig geΓ―mplementeerd in E5.S2** (Error Handler + Offline Banner) - -**Bestaande Implementatie:** - -1. **Error Handler Utility** (`lib/swift/error-handler.ts` - 301 regels): - - isOffline() - Detecteert navigator.onLine status - - isNetworkError() - Detecteert fetch failures - - isTimeoutError() - Detecteert timeout errors - - getErrorInfo() - Gebruiksvriendelijke Nederlandse berichten - - safeFetch() - Fetch wrapper met 30s timeout en error handling - - retryFetch() - Retry logic met exponential backoff (max 3 retries) - - parseErrorResponse() - Parse JSON/HTML error responses - - HTTP status handling: 401, 403, 404, 429, 500, 503 - -2. **Offline Banner** (`components/swift/command-center/offline-banner.tsx` - 72 regels): - - OfflineBanner component met WifiOff icon - - useOffline hook met online/offline event listeners - - Fixed positioning: top-0 left-0 right-0 z-[100] - - Height: 40px, amber-500 background - - Auto show/hide op basis van navigator.onLine - -3. **Integration:** - - CommandCenter: OfflineBanner geΓ―ntegreerd (regel 87) - - ContextBar: margin fix met useOffline hook (marginTop: '40px' wanneer offline, regel 31) - - ChatPanel: Error messages met type: 'error' (regel 206) - - ChatMessage: Support voor error message type - - All blocks: safeFetch + getErrorInfo voor error handling - -**Deliverables (E5.S4 - AL COMPLEET):** -- βœ… `lib/swift/error-handler.ts` (301 regels) β€” Gecentraliseerde error handling -- βœ… `components/swift/command-center/offline-banner.tsx` (72 regels) β€” Offline detection banner -- βœ… isOffline() detection met navigator.onLine -- βœ… isNetworkError() detection (fetch failures) -- βœ… getErrorInfo() met Nederlandse berichten per error type -- βœ… safeFetch() met 30s timeout (AbortSignal.timeout) -- βœ… retryFetch() met exponential backoff (1s, 2s, 4s delays) -- βœ… HTTP status messages: 401 (niet geautoriseerd), 404 (niet gevonden), 500 (serverfout), 503 (service niet beschikbaar) -- βœ… OfflineBanner component met WifiOff icon -- βœ… useOffline hook voor online/offline events -- βœ… ContextBar margin fix (marginTop: '40px') -- βœ… ChatPanel error messages (type: 'error') -- βœ… All blocks gebruik safeFetch + getErrorInfo - -**Acceptatiecriteria:** -1. βœ… Error handler utility met isOffline(), isNetworkError(), getErrorInfo() -2. βœ… safeFetch() wrapper met 30s timeout en parseErrorResponse -3. βœ… retryFetch() met exponential backoff (max 3 retries) -4. βœ… Nederlandse error messages voor alle HTTP status codes -5. βœ… OfflineBanner component toont bij geen internetverbinding -6. βœ… OfflineBanner geΓ―ntegreerd in CommandCenter -7. βœ… ContextBar margin fix voorkomt overlap met banner -8. βœ… ChatPanel toont error messages in chat (type: 'error') -9. βœ… ChatMessage supports error type rendering -10. βœ… Build succesvol, geen errors - -**Technical Details:** -- safeFetch timeout: 30s (AbortSignal.timeout(30000)) -- Retry delays: 1000ms, 2000ms, 4000ms (exponential backoff) -- Offline detection: window.addEventListener('online'/'offline') -- Banner z-index: 100 (boven content) -- ContextBar dynamic margin: isOffline ? '40px' : undefined -- Error type flow: safeFetch β†’ getErrorInfo β†’ toast/chat message - -**Git Commits:** -- GeΓ―mplementeerd in E5.S2 (Error handler + Offline banner) - ---- - -**E5.S5 - Polish & animations (COMPLEET - AL GEÏMPLEMENTEERD):** - -**Doel:** Smooth transitions, loading states, toast confirmations voor professionele UX. - -**Status:** βœ… **Al volledig geΓ―mplementeerd** (verspreid over Epics 2-5) - -**Bestaande Implementatie:** - -**1. Smooth Transitions (14 components):** -- transition-colors, transition-all classes in alle interactive elements -- Button hover states: bg-blue-600 hover:bg-blue-500 -- Input focus: focus:ring-2 focus:ring-blue-500 -- Modal/Popover appear/disappear animations -- artifact-enter animation (200ms ease-out, E4.S3) -- Reduced motion support (@media (prefers-reduced-motion)) - -**2. Loading States (6 components):** -- **CommandInput:** isProcessing state met Loader2 icon -- **DagnotatieBlock:** isSubmitting state met disabled buttons -- **OverdrachtBlock:** isLoadingPatients, loading per patient summary -- **ZoekenBlock:** isSearching state tijdens patient search -- **ChatPanel:** isStreaming state tijdens AI response -- **LinkedEvidence:** Loading indicators voor popover content - -**3. Toast Confirmations:** -- **DagnotatieBlock:** "Dagnotitie opgeslagen" + smooth close (500ms delay) -- **CommandInput:** Error toasts met getErrorInfo() -- **OverdrachtBlock:** Error toasts voor generate failures -- **ZoekenBlock:** Error toasts voor search failures -- **All blocks:** safeFetch + toast error handling - -**4. Loading Indicators:** -- Loader2 icon (lucide-react) met animate-spin -- Skeleton states in components -- "Verbinden..." status in CommandInput (Deepgram) -- "PatiΓ«nten laden..." in OverdrachtBlock -- AI generation: "Samenvatting wordt gegenereerd..." - -**5. Animations in globals.css:** -- @keyframes artifact-enter (translateX 100% β†’ 0%, opacity 0 β†’ 1) -- @keyframes float (voor expertise badges) -- .artifact-enter class (200ms ease-out) -- .animate-float class (5s ease-in-out infinite) -- Reduced motion: alle animations β†’ none - -**Deliverables (E5.S5 - AL COMPLEET):** -- βœ… Smooth transitions in 14+ components (transition-*, hover states) -- βœ… Loading states in 6 components (isLoading, isSubmitting, isProcessing) -- βœ… Toast confirmations in 4+ components (success + error) -- βœ… Loader2 icons met animate-spin in alle loading states -- βœ… artifact-enter animation (200ms ease-out) -- βœ… Reduced motion support (@media query) -- βœ… Button disabled states tijdens loading -- βœ… Smooth close met delay (setTimeout 500ms) -- βœ… Error toasts met getErrorInfo() Nederlandse berichten -- βœ… Focus states (ring-2, ring-blue-500) -- βœ… Hover states (bg changes, text color changes) - -**Acceptatiecriteria:** -1. βœ… Smooth transitions op alle interactive elements (buttons, inputs, modals) -2. βœ… Loading states tonen Loader2 icon + disabled buttons -3. βœ… Toast confirmations na succesvolle actions (save, generate) -4. βœ… Error toasts met gebruiksvriendelijke Nederlandse berichten -5. βœ… artifact-enter animation bij artifact opening (200ms) -6. βœ… Reduced motion support voorkomt animaties bij user preference -7. βœ… Focus states duidelijk zichtbaar (ring) -8. βœ… Hover states smooth (transition-colors) -9. βœ… Build succesvol, geen errors -10. βœ… Professionele, gepolijste UX - -**Technical Details:** -- Transition duration: 200ms (colors), 200ms (all) -- Animation easing: ease-out (artifact-enter), ease-in-out (float) -- Toast duration: Default (shadcn/ui) -- Loader2 size: 20px (buttons), 16px (inline text) -- Close delay: 500ms (DagnotatieBlock) -- Focus ring: 2px, blue-500 color -- Disabled opacity: 50%, cursor-not-allowed - -**Git Commits:** -- GeΓ―mplementeerd in Epics 2-5 (verspreid over alle components) - ---- - -**πŸŽ‰ EPIC 5 COMPLEET!** Alle stories (5 compleet) afgerond. AI-filtering, linked evidence, en polish features volledig geΓ―mplementeerd! - -**Epic 5 Samenvatting:** -- **Status:** βœ… Compleet (5/5 stories, 13 SP) -- **Duur:** Stories E5.S1-E5.S5 -- **Impact:** Psychiater filtering, linked evidence UI, voice input, error handling, smooth animations - -**Belangrijkste Features:** -1. **AI-filtering psychiater (E5.S1)** - Role toggle voor behandelrelevante filtering -2. **Linked evidence UI (E5.S2)** - Klikbare bronverwijzingen met hover preview -3. **Voice input (E5.S3)** - Deepgram integratie al werkend (geΓ―mplementeerd in E2) -4. **Error states & offline (E5.S4)** - Error handler utility en offline banner -5. **Polish & animations (E5.S5)** - Smooth transitions, loading states, toast confirmations - -**Files Gewijzigd:** -- `lib/types/overdracht.ts` - filterForRole parameter -- `lib/ai/overdracht-prompt.ts` - buildSystemPrompt met psychiater filtering -- `app/api/overdracht/generate/route.ts` - Role-based prompt selection -- `components/swift/blocks/overdracht-block.tsx` - Role toggle UI -- `components/swift/shared/linked-evidence.tsx` - Popover met source data -- `lib/swift/error-handler.ts` - Gecentraliseerde error handling -- `components/swift/command-center/offline-banner.tsx` - Offline detection - -**Git Commits:** -- `c6616d8` - E5.S1 (AI-filtering psychiater) -- `adf6c3f` - E5.S2 (Linked evidence UI) -- `1bab375` - E5.S3 (Voice input - al geΓ―mplementeerd) -- `1ecc8f9` - E5.S4 (Error states - al geΓ―mplementeerd) -- `60afb17` - E5.S5 (Polish & animations - Epic 5 COMPLEET!) - -**Voortgang:** 71 SP / 82 SP (87%) - Ready voor Epic 6 (Testing & Refinement)! - ---- - -### Epic 6 β€” Testing & Refinement - -**Epic Doel:** Volledige QA, bug fixes, performance tuning, documentatie. - -| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | -|----------|--------------|---------------------|--------|------------------|--------------| -| E6.S1 | Manual smoke tests | Alle P1 flows werken zonder crashes (checklist) | ⏳ | E5.S5 | 3 | -| E6.S2 | Performance optimalisatie | Chat scroll performance, virtual scrolling >100 msgs | ⏳ | E6.S1 | 3 | -| E6.S3 | Bug fixes | Alle gemelde bugs opgelost, edge cases getest | ⏳ | E6.S2 | 1 | -| E6.S4 | Documentatie update | README, CLAUDE.md, migration guide | ⏳ | E6.S3 | 1 | - -**Technical Notes:** - -**E6.S1 - Test checklist:** -```markdown -### P1 Flow Tests - -**Dagnotitie via conversatie:** -- [ ] User typt "Ik heb medicatie gegeven aan Jan" -- [ ] AI herkent intent (dagnotitie) en patient (Jan) -- [ ] DagnotatieBlock opent met prefill -- [ ] User kan opslaan β†’ Toast confirmation -- [ ] Chat toont "βœ“ Notitie opgeslagen" - -**PatiΓ«nt zoeken:** -- [ ] User typt "Zoek Marie van den Berg" -- [ ] ZoekenBlock opent rechts -- [ ] Patient search werkt -- [ ] Selecteren patient β†’ PatientContextCard opent - -**Overdracht maken:** -- [ ] User typt "Maak overdracht" -- [ ] OverdrachtBlock opent -- [ ] AI genereert samenvattingen -- [ ] Psychiater ziet alleen behandelrelevante info -- [ ] Linked evidence klikbaar - -**Follow-up conversatie:** -- [ ] User typt "Voeg toe: goed geslapen" -- [ ] AI begrijpt context (laatste artifact = dagnotitie) -- [ ] Tekst wordt toegevoegd aan artifact - -**Meerdere artifacts:** -- [ ] User opent 3 artifacts achter elkaar -- [ ] Tabs verschijnen bovenaan -- [ ] Switching tussen artifacts werkt -- [ ] 4e artifact openen β†’ oudste sluit automatisch - -**Voice input:** -- [ ] Mic icon werkt -- [ ] Deepgram transcriptie verschijnt live -- [ ] Pauze detectie β†’ auto-submit -- [ ] Voice message wordt verwerkt zoals typed message - -**Error handling:** -- [ ] Offline β†’ banner verschijnt -- [ ] Stream interrupted β†’ error message in chat -- [ ] Rate limit β†’ friendly message + retry suggestion -- [ ] Network error β†’ retry button -``` - -**E6.S2 - Performance:** -- Virtual scrolling met `react-window` of `@tanstack/react-virtual` (>100 messages) -- Debounce typing indicator (300ms) -- Memoize message components (`React.memo`) -- Lazy load artifacts (niet renderen tot actief) - -**E6.S3 - Edge cases:** -- Zeer lange messages (>1000 chars) -- Special characters in patient names -- Concurrent artifact opening -- Browser back/forward navigation -- Tab close tijdens streaming - -**E6.S4 - Documentatie:** -- Update `CLAUDE.md` met v3.0 architecture -- Migration guide voor users (v2.1 β†’ v3.0) -- Developer README met chat API docs -- Prompt versioning doc - -**Deliverable:** Production-ready v3.0, alle tests passed, gedocumenteerd - ---- - -## 5. Kwaliteit & Testplan - -🎯 **Doel:** Borgen kwaliteit van v3.0 via gestructureerd testplan. - -### Test Types - -| Test Type | Scope | Tools | Verantwoordelijke | -|-----------|-------|-------|-------------------| -| **Manual Smoke Tests** | Alle P1 flows + edge cases | Checklist (zie E6.S1) | Developer | -| **Integration Tests** | `/api/swift/chat` endpoint | Playwright / Jest | Developer | -| **Performance Tests** | Chat scroll, streaming latency | Chrome DevTools, Lighthouse | Developer | -| **User Acceptance** | Real-world flows met zorgmedewerkers | User feedback sessie | PM + Developer | -| **Security Tests** | API keys, RLS, XSS in chat | Manual audit | Developer | - -### Test Coverage Targets - -- **Manual smoke tests:** 100% van P1 flows (dagnotitie, zoeken, overdracht, patient context) -- **Integration tests:** `/api/swift/chat` endpoint (streaming, action generation) -- **Performance:** Chat scroll <16ms frame time, streaming latency <500ms - -### Manual Test Checklist - -**Pre-deployment checklist:** -- [ ] Feature flag `FEATURE_FLAG_SWIFT_V3=true` werkt -- [ ] v2.1 nog steeds beschikbaar (fallback) -- [ ] Alle P1 flows getest (zie E6.S1) -- [ ] Edge cases getest (lange messages, concurrent actions, etc.) -- [ ] Mobile responsive (toggle tussen chat/artifact) -- [ ] Keyboard shortcuts werken (⌘K, Escape, Enter) -- [ ] Voice input geΓ―ntegreerd en werkend -- [ ] Error states tonen user-friendly messages -- [ ] Offline banner werkt -- [ ] Performance: scroll smooth, streaming <500ms latency -- [ ] AI-filtering psychiater werkt (alleen behandelrelevante info) -- [ ] Linked evidence klikbaar en toont bronnotities -- [ ] Toast notifications bij save/error -- [ ] Browser back/forward navigation werkt - -### Acceptance Criteria (MVP) - -**Minimaal werkend voor release:** -1. βœ… Split-screen layout werkend (desktop/tablet/mobile) -2. βœ… Conversatie met Swift Assistent voelt natuurlijk (niet robotisch) -3. βœ… Artifacts openen binnen 2 sec na intent detection -4. βœ… AI-filtering psychiater >85% accuracy (behandelrelevante info) -5. βœ… Voice input geΓ―ntegreerd en werkend -6. βœ… P1 flows (dagnotitie, zoeken, overdracht, patient context) 100% werkend -7. βœ… Error handling: netwerk errors, offline, stream interrupted -8. βœ… Performance: <500ms streaming latency, smooth scroll - ---- - -## 6. Demo & Presentatieplan - -🎯 **Doel:** Presenteren van v3.0 aan stakeholders en users voor feedback. - -### Demo Scenario - -**Duur:** 15 minuten -**Doelgroep:** Zorgmedewerkers (verpleegkundigen + psychiaters), product team -**Locatie:** Vercel staging environment (`swift-v3-staging.vercel.app`) - -**Flow:** - -1. **Intro (2 min):** - - Context: "We hebben Swift getransformeerd naar een conversational interface" - - Toon v2.1 vs. v3.0 screenshot (voor/na) - -2. **Dagnotitie flow (3 min):** - - Typ: "Ik heb net medicatie gegeven aan Jan de Vries" - - AI herkent intent, DagnotatieBlock opent rechts met prefill - - Toon follow-up: "Voeg toe: hij voelt zich beter vandaag" - - Opslaan β†’ Chat confirmation - -3. **PatiΓ«nt zoeken + context (3 min):** - - Typ: "Wie is Marie van den Berg?" - - ZoekenBlock opent, selecteer patient - - PatientContextCard toont laatste notities, vitals, diagnose - - Chat vraag: "Wat was er gisteren met Marie?" - - AI antwoordt met context uit notities - -4. **Overdracht met AI-filtering (4 min):** - - Typ: "Maak overdracht voor deze dienst" - - OverdrachtBlock opent - - Toon psychiater view: alleen behandelrelevante info - - Klik op linked evidence β†’ bronnotitie preview - - Toon verschil tussen verpleegkundige vs. psychiater view - -5. **Voice input (2 min):** - - Klik mic icon - - Spreek: "Notitie voor Jan: bloeddruk gemeten, 135 over 85" - - Live transcript verschijnt - - DagnotatieBlock opent met prefill - -6. **Q&A (1 min):** - - Vragen beantwoorden - - Feedback verzamelen - -**Backup Plan:** -- Lokale versie klaar bij internet/API issues -- Pre-recorded video als complete fallback -- Screenshots voor elk stap - ---- - -## 7. Risico's & Mitigatie - -🎯 **Doel:** Risico's vroeg signaleren en mitigeren. - -| Risico | Kans | Impact | Mitigatie | Owner | -|--------|------|--------|-----------|-------| -| **AI prompt niet natuurlijk genoeg** | Hoog | Hoog | Iteratief testen met users, prompt versioning, A/B testing | Developer | -| **Streaming latency >1s** | Middel | Hoog | Claude Haiku model overwegen (sneller), caching, local patterns voor snelle acties | Developer | -| **Performance bij >100 messages** | Middel | Middel | Virtual scrolling, pagination, max 100 messages in view | Developer | -| **Chat state memory leak** | Middel | Middel | Proper cleanup in useEffect, memory profiling | Developer | -| **AI kosten te hoog** | Middel | Middel | Rate limiting, local pattern matching eerst, cache responses | PM | -| **Mobile UX awkward** | Hoog | Middel | Extensive mobile testing, toggle UX refinement | Developer | -| **v2.1 users niet willen switchen** | Hoog | Laag | Feature flag (optioneel), user onboarding, feedback loop | PM | -| **Intent detection accuracy <80%** | Middel | Hoog | Hybrid approach (local + AI), confidence thresholds, fallback picker | Developer | -| **Browser compatibility issues** | Laag | Middel | Test Chrome/Safari/Firefox, SSE polyfill if needed | Developer | -| **Concurrent artifact state bugs** | Middel | Middel | Thorough testing, max 3 artifacts enforced, state validation | Developer | - -**Top 3 Risks & Mitigation:** - -1. **AI Prompt Engineering (Kans: Hoog, Impact: Hoog)** - - **Mitigatie:** Start met simpele prompt v1 in E0.S3, iteratief verfijnen met user feedback, prompt versioning (v1, v2, v3), A/B testing tussen prompts - - **Success metric:** >80% user satisfaction "voelt natuurlijk aan" - -2. **Performance - Streaming Latency (Kans: Middel, Impact: Hoog)** - - **Mitigatie:** Local patterns voor P1 intents (dagnotitie, zoeken) β†’ <100ms, AI alleen voor complex/conversational, Claude Haiku overwegen, response caching - - **Success metric:** <500ms tot eerste AI token, <2s tot artifact open - -3. **Mobile UX Toggle (Kans: Hoog, Impact: Middel)** - - **Mitigatie:** Extensive mobile testing, bottom sheet voor artifact (native feel), swipe gestures, user testing met zorgmedewerkers - - **Success metric:** >70% mobile users vindt toggle intuΓ―tief - ---- - -## 8. Evaluatie & Lessons Learned - -🎯 **Doel:** Reflecteren na elke epic en einde project. - -**Na elke epic (weekly retro):** -- Wat ging goed deze week? -- Welke blockers hadden we? -- Welke AI-prompts werkten het beste? -- Waar liepen we vertraging op? -- Wat passen we aan voor volgende epic? - -**Na project (final retro):** - -**Te documenteren:** -1. **Successen:** - - Welke componenten zijn herbruikbaar voor volgende projecten? - - Welke development patterns werkten goed? - - Welke AI-prompts waren meest effectief? - -2. **Uitdagingen:** - - Waar liepen we vast? - - Welke technical debt ontstond? - - Welke estimates waren te optimistisch/pessimistisch? - -3. **Metrics:** - - Actual time spent vs. estimated (story points) - - User satisfaction score (survey) - - Performance metrics (latency, scroll FPS) - - AI kosten (Claude API usage) - -4. **Next Steps:** - - P2/P3 features roadmap - - Technical debt payoff plan - - User feedback integration plan - -**Template voor lessons learned:** -```markdown -## Epic X - Lessons Learned - -### What went well -- ... - -### What didn't go well -- ... - -### Action items for next epic -- ... - -### Reusable components/patterns -- ... -``` - ---- - -## 9. Referenties - -🎯 **Doel:** Koppelen aan overige Mission Control-documenten. - -**Mission Control Documents:** -- **PRD Ephemeral UI:** `docs/swift/archive/nextgen-epd-prd-ephemeral-ui-epd.md` β€” Product vision -- **FO v3.0:** `docs/swift/fo-swift-medical-scribe-v3.md` β€” Functioneel ontwerp Swift Assistent -- **Haalbaarheid:** `docs/swift/haalbaarheidsanalyse-v3.md` β€” Feasibility analysis -- **UX v2.1:** `docs/swift/archive/swift-ux-v2.1.md` β€” Huidige UX/styling -- **UX Analyse v3:** `docs/swift/v3-redesign-met-huidige-styling.md` β€” Wat blijft vs. wijzigt -- **Bouwplan v2:** `docs/swift/bouwplan-swift-v2.md` β€” Previous roadmap (v2.1) - -**Technical Resources:** -- Repository: `https://github.com/[org]/mini-epd-prototype` -- Staging: `https://swift-v3-staging.vercel.app` (to be created) -- Production: `https://mini-epd.vercel.app` (existing) -- Component Library: `components/swift/` folder -- API Documentation: `/docs/api/` (to be created) - -**External References:** -- [ChatGPT Canvas UX](https://altar.io/next-gen-of-human-ai-collaboration/) β€” Inspiration -- [Claude Artifacts](https://docs.anthropic.com) β€” Pattern reference -- [Abridge Linked Evidence](https://www.abridge.com/product) β€” Evidence linking pattern -- [Anthropic Streaming API](https://docs.anthropic.com/en/api/streaming) β€” SSE implementation - ---- - -## 10. Glossary & Abbreviations - -| Term | Betekenis | -|------|-----------| -| **Epic** | Grote feature of fase in development (bevat meerdere stories) | -| **Story** | Kleine, uitvoerbare taak binnen een epic | -| **Story Points** | Schatting van complexiteit (Fibonacci: 1, 2, 3, 5, 8, 13, 21) | -| **SP** | Story Points (afkorting) | -| **MVP** | Minimum Viable Product | -| **P1/P2/P3** | Priority tiers (P1 = kritiek, P2 = belangrijk, P3 = waardevol) | -| **SSE** | Server-Sent Events (streaming protocol) | -| **DRY** | Don't Repeat Yourself | -| **KISS** | Keep It Simple, Stupid | -| **SOC** | Separation of Concerns | -| **YAGNI** | You Aren't Gonna Need It | -| **RLS** | Row Level Security (Supabase) | -| **Intent** | Gebruikersintentie (dagnotitie, zoeken, overdracht, etc.) | -| **Artifact** | UI-component die verschijnt in artifact area (block) | -| **Block** | Herbruikbare UI-component (DagnotatieBlock, ZoekenBlock, etc.) | -| **Prefill** | Vooringevulde data in artifact o.b.v. AI entity extraction | -| **Swift Assistent** | AI-assistent die medische documentatie ondersteunt | -| **Linked Evidence** | Klikbare links naar bronnotities in AI-samenvatting | - ---- - -## 11. Story Points Reference - -**Fibonacci schaal voor story points:** - -| Points | Complexiteit | Geschatte tijd | Voorbeelden | -|--------|--------------|----------------|-------------| -| 1 | Trivial | 1-2 uur | Feature flag setup, config wijziging | -| 2 | Simple | 2-4 uur | Component skeleton, store uitbreiding (1 field) | -| 3 | Small | 4-8 uur | Simpele component met state, basic API endpoint | -| 5 | Medium | 1-2 dagen | Complex component, API met business logic | -| 8 | Large | 2-3 dagen | Feature met meerdere componenten, integrations | -| 13 | Very Large | 3-5 dagen | Epic-level feature, major refactor | -| 21 | Extra Large | 1 week+ | Waarschijnlijk te groot, split in kleinere stories | - -**Velocity tracking:** -- **Target velocity:** ~12 SP per week (1 developer) -- **Sprint length:** 1 week -- **Total project:** 86 SP β‰ˆ 7 weken (met buffer = 8 weken) - ---- - -**Versiehistorie:** - -| Versie | Datum | Auteur | Wijziging | -|--------|-------|--------|-----------| -| v1.0 | 27-12-2024 | Colin Lit | InitiΓ«le versie - complete bouwplan v3.0 | diff --git a/docs/swift/competitive-analysis.md b/docs/swift/competitive-analysis.md deleted file mode 100644 index a34de1f..0000000 --- a/docs/swift/competitive-analysis.md +++ /dev/null @@ -1,774 +0,0 @@ -# Competitive Analysis: Declaratieve UI in Nederlandse Software - -**Onderzoeksdatum:** 29 december 2025 -**Vraagstelling:** Zijn er Nederlandse softwareleveranciers (EPD/ECD, enterprise software) die een declaratieve UI hebben zoals Swift? - ---- - -## Executive Summary - -**Conclusie:** Swift's command-based, declaratieve UI is **uniek in de Nederlandse EPD markt** en zelfs internationaal zeldzaam. Geen enkele Nederlandse EPD leverancier (ChipSoft, Epic, Nexus) heeft een vergelijkbare command palette of natural language interface. Ook Nederlandse enterprise software (AFAS, Visma, Mollie, Adyen) documenteert geen command-based interfaces. - -**Key Differentiators van Swift:** -1. ✨ **Command palette met natural language** - typ "notitie jan medicatie" vs klikken door menu's -2. πŸ€– **AI intent classification** - begrijpt context en entities -3. πŸ“± **Split-screen artifact rendering** - 40% chat + 60% werkgebied -4. ⌨️ **Keyboard-first workflow** - ⌘K focus, Escape close, ⌘Enter submit -5. 🎯 **Contextual awareness** - actieve patiΓ«nt, recent actions - ---- - -## πŸ₯ Nederlandse EPD/ECD Leveranciers - -### Marktoverzicht (2025) - -De Nederlandse EPD-markt bestaat uit drie hoofdspelers na het vertrek van SAP/Cerner: - -| Leverancier | Marktaandeel | Type | -|-------------|--------------|------| -| **ChipSoft (HiX)** | 72% | Nederlands | -| **Epic** | 14% | Amerikaans | -| **Nexus** | 11% | Duits | - -**Bron:** [M&I Partners EPD-marktinventarisatie 2024](https://mxi.nl/kennis/644/epd-marktinventarisatie-ziekenhuizen-2024-consolidatie-epd-markt-zet-door) - ---- - -### ChipSoft HiX - -**Bedrijfsinfo:** -- Marktleider in Nederland (72% ziekenhuizen) -- ISO 13485 gecertificeerd -- CE Medical Device klasse IIb certificering -- Actief in: apotheek, eerstelijnszorg, GGZ, huisartsenzorg, revalidatie, VVT, ZBC's, ziekenhuizen - -**UI/UX Features:** - -βœ… **Keyboard shortcuts** ("sneltoetsen") -- Ondersteuning voor sneltoetsen bij registratie -- Geen specifieke documentatie publiek beschikbaar - -βœ… **Dedicated UX Team** -- Monitort en verbetert continu de 'look and feel' -- Werkt volgens internationale standards -- Observaties in werkplek om workflows te optimaliseren -- Taskoriented views per apparaat (desktop/tablet/mobile) - -βœ… **Spraak-naar-tekst** (2025) -- Integratie met Juvoly's speech-to-text -- Reduceert registratielast voor huisartsen -- Dit is **dictatie**, geen natural language interface - -βœ… **Personalisatie** -- Gebruikers kunnen schermlay-out aanpassen -- Favoriete functies configureren -- Voorkeur voor waar patiΓ«ntinformatie opent - -❌ **GEEN command palette of declaratieve UI** -- Traditionele menu-driven interface -- Geen natural language command input -- Geen keyboard-first workflow zoals Swift - -**Design Filosofie:** -> "Wat direct opvalt bij het openen van HiX is de rustige uitstraling: eenvoudige pictogrammen, weinig lijnen en een centrale plek voor alle knoppen. Geen wildgroei aan kleuren... maar een apart pictogram voor elke eigenschap." - -**Bronnen:** -- [ChipSoft Gebruiksvriendelijkheid](https://www.chipsoft.com/nl-be/hix-abc/hix-abc-articles/gebruiksvriendelijkheid/) -- [ChipSoft AI in HiX 2025](https://www.chipsoft.com/nl-nl/nieuws-en-blogs/ai-in-hix-ontdek-de-belangrijke-ontwikkelingen-in-2025/) - ---- - -### Epic EMR - -**Bedrijfsinfo:** -- 14% marktaandeel Nederlandse ziekenhuizen -- Amerikaans EHR/EMR systeem -- Groeiend in Nederland (recent: Ziekenhuis Amstelland, MUMC+) - -**UI/UX Features:** - -βœ… **Uitgebreide keyboard shortcuts** - -Veelgebruikte shortcuts: -- `Ctrl + O` - Go to Orders (manage orders tab) -- `Alt + S` - Sign (sign current note) -- `Alt + A` - Accept (accept order) -- `Alt + [underlined letter]` - Selecteer menu optie -- Standard shortcuts: `Ctrl + C` (copy), `Ctrl + Z` (undo) - -βœ… **Workflow optimalisatie** -- Shortcuts kunnen workflow aanzienlijk versnellen -- Vooral nuttig voor interventional radiologists en andere high-volume users - -❌ **GEEN command palette feature** -- Traditionele menu navigatie -- Geen natural language interface -- Geen centralized command bar - -❌ **GEEN conversational interface** -- Geen AI intent classification -- Geen voice-to-command (wel dictatie via Dragon Medical) - -**Bronnen:** -- [Epic EMR Keyboard Shortcuts | TextExpander](https://textexpander.com/blog/epic-shortcuts) -- [Easy Epic Keyboard Shortcuts | BackTable](https://www.backtable.com/shows/vi/articles/epic-emr-keyboard-shortcuts-how-to) - ---- - -### Nexus Nederland - -**Bedrijfsinfo:** -- 11% marktaandeel Nederlandse ziekenhuizen -- Onderdeel van Duits Nexus AG -- Complete, modulaire EPD- en ECD-oplossingen voor ziekenhuizen en GGZ -- Recent: St. Anna Zorggroep verlengde contract - -**UI/UX Features:** -- ❌ Geen specifieke UI innovaties gedocumenteerd -- ❌ Geen publieke informatie over keyboard shortcuts of command interfaces - -**Bron:** -- [NEXUS Nederland](https://www.nexus-nederland.nl/) - ---- - -## 🏒 Nederlandse Enterprise/SaaS Software - -### HR Software: AFAS, Visma Nmbrs - -**Visma Nmbrs:** -- 100,000+ klanten -- 1+ miljoen salarisadministraties per maand -- Onderdeel van Visma (grootste software producer NL) - -**Features:** -βœ… **API integraties** -- User-friendly API met token-based authentication -- Auto-sync met andere systemen (R&R, AFAS Profit) -- Voorkomt dubbel werk en fouten - -❌ **GEEN command interface** -- Geen command palette gedocumenteerd -- Geen natural language interface -- Focus op webforms en automation - -**AFAS:** -- Complete ERP voor MKB -- Sterk in accountancy, onderwijs, healthcare, trade -- Business Process Outsourcing (BPO) optie - -❌ **GEEN command interface** gedocumenteerd - -**Bronnen:** -- [Nmbrs | Visma Nederland](https://www.visma.nl/onze-bedrijven/nmbrs) -- [AFAS | Visma Nmbrs Integraties](https://appstore.nmbrs.com/listings/afas) - ---- - -### FinTech: Mollie, Adyen, MessageBird - -**Mollie:** -- Opgericht 2004 door Adriaan Mol (18 jaar oud) -- 250,000+ bedrijven gebruiken Mollie -- Grootste Nederlandse fintech deal ooit: acquisitie GoCardless voor €1.1B (2025) - -**Adyen:** -- Opgericht 2006 door Pieter van der Does en Arnout Schuijff -- Focus op grote ondernemingen en multinationals -- Omnichannel platform (online + fysieke winkels) - -**MessageBird (nu Bird):** -- Opgericht 2011 door Robert Vis en Adriaan Mol -- Rebranded naar "Bird" in februari 2024 -- 700+ medewerkers -- Focus: marketing, sales, payment solutions - -**UI/UX Bevindingen:** -❌ **GEEN command palette** features publiek gedocumenteerd -- Deze bedrijven focussen op **payment/messaging API's** -- End-user UI is vaak merchant dashboard (niet clinical workflow tool) -- Developer-first platforms, niet operator-first - -**Interessant:** Adriaan Mol is de oprichter van TWEE unicorns (Mollie $6B, MessageBird $4B) - -**Bronnen:** -- [De 15 beste Nederlandse SaaS-bedrijven | Web Whales](https://webwhales.nl/de-15-beste-nederlandse-saas-bedrijven/) -- [Mollie vs Stripe vs Adyen | Codelevate](https://www.codelevate.com/nl/blog/mollie-vs-stripe-vs-adyen-psp-comparison-2025) - ---- - -## 🌍 Internationale Trends (2025) - -### Microsoft Dragon Copilot for Nursing - -**Lancering:** Late 2025 -**Type:** AI Clinical Assistant voor verpleegkundigen - -**Features:** - -βœ… **Natural language conversational interface** -- Verpleegkundigen kunnen **natuurlijk praten** met patiΓ«nten -- Dragon Copilot **luistert op de achtergrond** (ambient listening) -- Veilige mobile app voor bedside gebruik - -βœ… **Auto-generated documentation** -- Genereert **structured flowsheet entries** -- Nursing notes -- Concise summaries van encounters - -βœ… **Query interface** -- Verpleegkundigen kunnen vragen stellen aan Copilot -- Antwoorden uit trusted sources (FDA, MedlinePlus) -- Right at the bedside - -βœ… **Impact:** -- **70% reductie in clinician burnout** bij gebruik van ambient AI -- Documentatie is niet langer een separate task -- Context-aware en ambient (niet command-driven) - -**Verschil met Swift:** -- Dragon Copilot is **ambient/passive** (luistert mee tijdens gesprek) -- Swift is **active/command-driven** (gebruiker initieert acties) -- Dragon focus: documentatie elimineren -- Swift focus: acties versnellen - -**Bron:** -- [Microsoft Ignite 2025: Dragon Copilot for Nursing](https://techcommunity.microsoft.com/blog/healthcareandlifesciencesblog/highlights-from-ignite-2025-how-agentic-ai-and-microsoft-copilot-are-empowering-/4474658) - ---- - -### M4 Infrastructure for EHR Data - -**Type:** Research/data analysis tool -**Developer:** PathOnAI (academic/research) - -**Features:** - -βœ… **Natural language queries** voor EHR data -- Query MIMIC-IV, eICU, custom datasets -- Unified toolbox voor LLM agents -- Supports tabular data en clinical notes - -βœ… **Multimodal support** -- Dynamically selects tools by modality -- Single natural-language interface - -**Verschil met Swift:** -- M4 is **research/analytics tool**, niet clinical workflow -- Voor data scientists, niet clinici -- Query historical data, niet real-time documentation - -**Bron:** -- [M4 - Infrastructure for EHR Data | Glama](https://glama.ai/mcp/servers/@hannesill/m4) - ---- - -### Voice-First EHR Interfaces (2026 Trend) - -**Trend:** Voice-first interfaces moving from experimental to mainstream - -**Players:** -- Microsoft Dragon Copilot -- Oracle AI-driven platforms - -**Features:** -- Natural language for documentation -- Navigation via voice -- Information retrieval via voice - -**Impact:** -- 70% van clinici rapporteert **reduced burnout** -- Ambient AI luistert passief tijdens patient encounters -- Auto-generates clinical notes - -**Bron:** -- [EHR Interface Design: The Complete 2026 Guide | Arkenea](https://arkenea.com/blog/ehr-interface/) - ---- - -## πŸ’» Command Palettes in General Software - -Command palettes zijn **wijdverspreid in developer tools**, maar **zeldzaam in healthcare**: - -### Developer Tools - -| Software | Shortcut | Platform | -|----------|----------|----------| -| **VS Code** | `Ctrl+Shift+P` / `Cmd+Shift+P` | Cross-platform | -| **GitHub** | `Ctrl+Shift+K` / `Cmd+Shift+K` | Web | -| **Visual Studio 2022** | `Ctrl+Shift+P` | Windows | -| **PowerToys** | `Win+Alt+Space` | Windows 11/10 | -| **Oracle Code Editor** | `F1` | Cloud IDE | -| **RStudio** | `Ctrl+Shift+P` / `Cmd+Shift+P` | Cross-platform | - -**Common Pattern:** -- Keyboard-driven launcher -- Searchable command list -- Fuzzy search -- Shows keyboard shortcuts -- Context-aware suggestions - -**Best Practices (Mobbin):** -- Most apps use `Cmd+K` or `Cmd+P` -- Quick access/hide via shortcut -- Search-driven interface -- Eliminates need to remember obscure shortcuts -- Faster than navigating complex menus - -**Bronnen:** -- [Command Palette UI Design Best Practices | Mobbin](https://mobbin.com/glossary/command-palette) -- [How To Customize Command Palette For Enhanced Productivity In 2025](https://www.acciyo.com/how-to-customize-command-palette-for-enhanced-productivity-in-2025/) - ---- - -## 🎯 Swift's Unique Position - -### Wat Swift Combineert (en anderen NIET hebben) - -Swift zit in een unieke positie door het combineren van vijf elementen die **afzonderlijk wel bestaan**, maar **zelden samen voorkomen**: - -| Feature | Swift | ChipSoft | Epic | Dragon Copilot | Developer Tools | -|---------|-------|----------|------|----------------|-----------------| -| **Command palette** | βœ… | ❌ | ❌ | ❌ | βœ… | -| **Natural language input** | βœ… | ❌ | ❌ | βœ… | ❌ | -| **AI intent classification** | βœ… | ❌ | ❌ | βœ… | ❌ | -| **Split-screen artifacts** | βœ… | ❌ | ❌ | ❌ | ❌ | -| **Keyboard-first workflow** | βœ… | Partial | βœ… | ❌ | βœ… | -| **Contextual awareness** | βœ… | ❌ | ❌ | βœ… | Partial | -| **Healthcare-specific** | βœ… | βœ… | βœ… | βœ… | ❌ | - ---- - -### Swift's Key Differentiators - -#### 1. **Declaratief vs Imperatief** - -**Traditional EPD's (ChipSoft, Epic, Nexus):** -- Menu-driven: Klik PatiΓ«nt β†’ Notitie β†’ Medicatie β†’ Type β†’ Submit -- Mouse-heavy: 10+ clicks voor simpele actie -- Imperatief: Gebruiker specificeert **HOE** (stap voor stap) - -**Swift:** -- Command-driven: Type "notitie jan medicatie" -- Keyboard-first: 1 command + Enter -- Declaratief: Gebruiker specificeert **WAT** (doel) - -#### 2. **Intent-based Routing** - -**Swift's AI classificatie:** -```typescript -Input: "notitie jan medicatie" -↓ Intent classification -Intent: "create_note" -Entities: { patientName: "jan", category: "medicatie" } -Confidence: 0.92 -↓ Route to artifact -Opens: DagnotatieBlock with prefill -``` - -**Andere EPD's:** -- Geen intent classificatie -- Gebruiker moet zelf navigeren -- Geen context extraction uit natural language - -#### 3. **Split-Screen Context Retention** - -**Swift:** -- 40% Chat Panel: Conversatie history + recent actions -- 60% Artifact Area: Live werkgebied -- Context blijft zichtbaar tijdens werken - -**Andere EPD's:** -- Modal dialogs (verlies context) -- Full-screen forms (verlies overzicht) -- Tabbed interface (constant switchen) - -#### 4. **Keyboard-First Workflow** - -**Swift shortcuts:** -- `⌘K` - Focus input (altijd beschikbaar) -- `Escape` - Close artifacts -- `⌘Enter` - Quick submit -- `1/2/3` - FallbackPicker selection - -**ChipSoft/Epic:** -- Hebben shortcuts, maar niet centraal -- Geen universal command entry point -- Shortcuts zijn per-screen/per-function -- Geen keyboard-only workflow mogelijk - -#### 5. **Voice + Text Unified** - -**Swift:** -- Deepgram streaming voice input -- Voice β†’ Text β†’ Intent classification -- Same pipeline voor voice en typed input -- Waveform visualization tijdens recording - -**ChipSoft:** -- Juvoly dictatie (speech-to-text) -- Alleen voor notitie dictation -- Niet voor navigation/commands - -**Dragon Copilot:** -- Ambient listening (passive) -- Auto-generates notes -- Niet voor commands/actions - ---- - -### Market Positioning - -``` -Traditional EPD Swift Ambient AI -(Menu-driven) (Command-driven) (Passive listening) - -ChipSoft ──────────────────────► ◄──────────────────── Dragon Copilot -Epic -Nexus - -Mouse-heavy Keyboard-first Voice-passive -Imperative Declarative Automatic -Step-by-step Intent-based Ambient -``` - -**Swift's sweet spot:** -- Sneller dan traditional EPD's (minder clicks) -- Meer control dan ambient AI (gebruiker initieert) -- Keyboard-first (ergonomisch voor power users) -- Natural language (lage learning curve) - ---- - -## πŸ“Š Competitive Advantages - -### 1. **Snelheid** - -**Traditional workflow (ChipSoft/Epic):** -``` -Klik PatiΓ«nt (1) β†’ Selecteer Jan (2) β†’ Klik Acties (3) β†’ -Klik Notitie (4) β†’ Selecteer Medicatie (5) β†’ Type text (6) β†’ -Klik Submit (7) - -Total: 7 interactions, ~20 seconden -``` - -**Swift workflow:** -``` -⌘K (1) β†’ Type "notitie jan medicatie" (2) β†’ ⌘Enter (3) - -Total: 3 interactions, ~5 seconden -``` - -**Speed advantage: 4x sneller** - ---- - -### 2. **Cognitieve last** - -**Traditional EPD:** -- Moet menu structure onthouden -- Moet locatie van functies onthouden -- Moet door meerdere screens navigeren -- Context switching tussen screens - -**Swift:** -- Type intentie in natural language -- AI herkent context automatisch -- Blijf in hetzelfde window -- Context blijft zichtbaar in split-screen - -**Cognitive load: Significant lager** - ---- - -### 3. **Leer curve** - -**Traditional EPD:** -- Training nodig voor menu navigatie -- Moet locaties onthouden -- Verschillende workflows per functie - -**Swift:** -- Natural language (spreek zoals je denkt) -- FallbackPicker bij onduidelijke input -- Recent actions tonen voorbeelden -- Incrementeel leren (geen big bang training) - -**Learning curve: Vlakker** - ---- - -### 4. **Ergonomie** - -**Mouse-heavy workflows:** -- Repetitive Strain Injury (RSI) risico -- Hand van keyboard naar muis -- Precision clicking (klein target) - -**Swift keyboard-first:** -- Hands blijven op keyboard -- Geen precision clicking -- Voice fallback bij RSI/disability -- Lager RSI risico - ---- - -### 5. **Schaalbaarheid** - -**Traditional menu's:** -- Meer functies = diepere menu's -- Menu sprawl bij feature growth -- Moeilijker te navigeren over tijd - -**Swift command palette:** -- Meer functies = meer commands -- Search/fuzzy match blijft efficient -- AI kan nieuwe intents leren -- Lineair schaalbaar - ---- - -## πŸš€ Innovation Opportunities - -### Wat Swift kan toevoegen (geΓ―nspireerd door onderzoek) - -#### 1. **Macro's / Custom Commands** -Inspiratie: TextExpander, VS Code snippets - -``` -User creates custom command: -"dagstart" β†’ Opens 5 artifacts: - - Agenda voor vandaag - - Nieuwe patiΓ«nten - - Kritieke waardes - - Taken - - Team chat -``` - -#### 2. **Multi-step Commands** -Inspiratie: GitHub CLI, PowerToys Run - -``` -User types: -"plan jan consult cardio volgende week" - -Swift parses: - - Action: plan appointment - - Patient: jan - - Type: consult - - Specialty: cardio - - Time: volgende week - -Opens: Appointment scheduler with prefill -``` - -#### 3. **Command History & Autocomplete** -Inspiratie: Shell history, VS Code recent commands - -``` -User types: "not" -Autocomplete suggestions: - - notitie jan medicatie (used 3x today) - - notitie maria adl (used yesterday) - - nieuwe patient intake -``` - -#### 4. **Voice Commands Training** -Inspiratie: Dragon Medical custom vocabulary - -``` -User trains Swift: -"dagno" β†’ dagnotatie -"medi jan" β†’ medicatie voor jan -"print epd" β†’ export patient summary PDF -``` - -#### 5. **Team Shared Commands** -Inspiratie: VS Code workspace settings - -``` -Team creates shared command: -"overdracht ochtend" β†’ Opens: - - Nachtdienst notities - - Kritieke events - - Action items - - Patient status changes -``` - ---- - -## πŸŽ“ Lessons from Competition - -### What Works (implement in Swift) - -1. **ChipSoft's UX Team approach** - - Continuous workplace observation - - User-specific customization - - Task-oriented views per device - -2. **Epic's comprehensive shortcuts** - - Document ALL shortcuts - - Alt + underlined letter pattern - - Workflow-specific shortcuts - -3. **Dragon Copilot's ambient approach** - - Reduce documentation burden - - Context-aware auto-fill - - Trusted source integration - -4. **Developer tool patterns** - - Fuzzy search in command palette - - Recent commands prioritization - - Visual keyboard hints - -### What Doesn't Work (avoid in Swift) - -1. **Vendor lock-in (ChipSoft/Epic)** - - Systems "te duur" en "gebrekkige wil tot aanpassingen" - - Moeilijk om over te stappen (verweven met andere systemen) - - **Swift:** Stay modular, open standards (FHIR) - -2. **Menu sprawl** - - Meer features = diepere menus - - **Swift:** Command palette scales linearly - -3. **Passive-only AI (Dragon)** - - Geen control over timing - - Niet geschikt voor alle workflows - - **Swift:** User-initiated blijft belangrijk - -4. **Platform fragmentation** - - Desktop-only shortcuts - - Mobile separate workflow - - **Swift:** Unified command interface cross-platform - ---- - -## πŸ“ˆ Market Opportunity - -### Current EPD Market Pain Points - -1. **Efficiency crisis** - - Clinici spenderen 50%+ tijd aan administratie - - Burnout epidemic in healthcare - - **Swift's answer:** 4x sneller via command interface - -2. **Vendor lock-in** - - Ziekenhuizen "kunnen er bijna niet meer vanaf" - - "Enorme kosten van EPD-vervanging" - - **Swift's answer:** Modular, cloud-based, lower switching cost - -3. **Poor usability** - - "Veel te dure informatiesystemen" - - "Gebrekkige wil tot aanpassingen" - - **Swift's answer:** User-centered, command-driven, highly customizable - -4. **Consolidation limiting choice** - - Markt van 5 naar 3 spelers (SAP/Cerner exit) - - ChipSoft 72% monopoly - - **Swift's answer:** New entrant with differentiated approach - ---- - -### Target Segments - -**Early Adopters (Power Users):** -- Tech-savvy clinicians -- Interventional specialties (radiology, surgery) -- High-volume workflows (IC, ER) -- Keyboard-first preference - -**Innovator Hospitals:** -- Academic medical centers (research-oriented) -- Startup/scale-up hospitals -- Organizations frustrated with current vendor - -**International:** -- Markets with less vendor lock-in -- English-speaking countries (easier localization) -- Countries with national EHR initiatives - ---- - -## 🏁 Conclusion - -### Swift's Competitive Position: **Uniquely Positioned** - -**Summary:** -- βœ… **Geen Nederlandse EPD** heeft command palette of declaratieve UI -- βœ… **Geen Nederlandse enterprise software** documenteert vergelijkbare interface -- βœ… **Internationale trends** (Dragon Copilot, M4) gaan richting natural language, maar met andere focus (ambient vs command-driven) -- βœ… **Developer tools** hebben command palettes, maar niet healthcare-specific -- βœ… **Swift combineert** vijf elementen die afzonderlijk bestaan maar zelden samen - -### Unique Value Proposition - -Swift is: -1. **Sneller** dan traditional EPD's (4x via keyboard-first) -2. **Meer control** dan ambient AI (user-initiated) -3. **Lager cognitive load** dan menu-driven interfaces -4. **Schaalbaarder** dan menu hierarchies -5. **Ergonomischer** dan mouse-heavy workflows - -### Recommendation - -**Go-to-market positioning:** -> "Swift: De eerste command-driven EPD voor power users. -> Type WAT je wilt, niet HOE. 4x sneller dan klikken door menu's." - -**Target message:** -- Voor tech-savvy clinicians: "EPD met shortcuts zoals VS Code" -- Voor administrators: "Reduce documentation time 70%" -- Voor hospitals: "Moderne EPD zonder vendor lock-in" - -**Next steps:** -1. Publiceer competitive analysis (deze doc) -2. Create demo video comparing Swift vs ChipSoft workflow -3. Develop case studies met time savings metrics -4. Target early adopter hospitals (academic centers) -5. Present at Dutch healthcare innovation conferences - ---- - -## πŸ“š Bronnen - -### Nederlandse EPD Markt -- [EPD-marktinventarisatie ziekenhuizen 2024 | M&I/Partners](https://mxi.nl/kennis/644/epd-marktinventarisatie-ziekenhuizen-2024-consolidatie-epd-markt-zet-door) -- [Consolidatie op Nederlandse EPD-markt | ICT&health](https://www.icthealth.nl/nieuws/consolidatie-op-nederlandse-epd-markt-zet-door-met-vertrek-sapcerner) -- [ACM: ziekenhuizen sterk afhankelijk van EPD-leverancier | Security.NL](https://www.security.nl/posting/735021/ACM:+ziekenhuizen+sterk+afhankelijk+van+EPD-leverancier,+pati%C3%ABnten+dupe) - -### ChipSoft HiX -- [ChipSoft Gebruiksvriendelijkheid](https://www.chipsoft.com/nl-be/hix-abc/hix-abc-articles/gebruiksvriendelijkheid/) -- [ChipSoft AI in HiX 2025](https://www.chipsoft.com/nl-nl/nieuws-en-blogs/ai-in-hix-ontdek-de-belangrijke-ontwikkelingen-in-2025/) -- [ChipSoft HiX Homepage](https://www.chipsoft.com/nl-nl/oplossingen/elektronisch-patientendossier-hix-optimale-zorginnovatie/) - -### Epic EMR -- [Epic EMR Keyboard Shortcuts | TextExpander](https://textexpander.com/blog/epic-shortcuts) -- [Easy Epic Keyboard Shortcuts | BackTable](https://www.backtable.com/shows/vi/articles/epic-emr-keyboard-shortcuts-how-to) - -### Nexus -- [NEXUS Nederland EPD leverancier](https://www.nexus-nederland.nl/) - -### Nederlandse SaaS -- [De 15 beste Nederlandse SaaS-bedrijven | Web Whales](https://webwhales.nl/de-15-beste-nederlandse-saas-bedrijven/) -- [Nmbrs | Visma Nederland](https://www.visma.nl/onze-bedrijven/nmbrs) -- [Mollie vs Stripe vs Adyen | Codelevate](https://www.codelevate.com/nl/blog/mollie-vs-stripe-vs-adyen-psp-comparison-2025) - -### Internationale Trends -- [Microsoft Ignite 2025: Dragon Copilot for Nursing](https://techcommunity.microsoft.com/blog/healthcareandlifesciencesblog/highlights-from-ignite-2025-how-agentic-ai-and-microsoft-copilot-are-empowering-/4474658) -- [EHR Interface Design: The Complete 2026 Guide | Arkenea](https://arkenea.com/blog/ehr-interface/) -- [M4 - Infrastructure for EHR Data | Glama](https://glama.ai/mcp/servers/@hannesill/m4) -- [Large language models in healthcare | Nature Medicine](https://www.nature.com/articles/s41591-024-03199-w) - -### Command Palettes -- [Command Palette UI Design Best Practices | Mobbin](https://mobbin.com/glossary/command-palette) -- [How To Customize Command Palette For Enhanced Productivity In 2025](https://www.acciyo.com/how-to-customize-command-palette-for-enhanced-productivity-in-2025/) -- [GitHub Command Palette Docs](https://docs.github.com/en/enterprise-cloud@latest/get-started/using-github/github-command-palette) -- [PowerToys Command Palette | Microsoft Learn](https://learn.microsoft.com/en-us/windows/powertoys/command-palette/overview) - ---- - -**Document Version:** 1.0 -**Laatste update:** 29 december 2025 -**Auteur:** Colin (met Claude Code) diff --git a/docs/swift/developer-guide-intent-system.md b/docs/swift/developer-guide-intent-system.md deleted file mode 100644 index d5dd46c..0000000 --- a/docs/swift/developer-guide-intent-system.md +++ /dev/null @@ -1,1334 +0,0 @@ -# Developer Guide: Swift Intent System - -**Document:** Developer Guide - Intent Classification & Extension -**Versie:** 1.0 -**Datum:** 27-12-2024 -**Auteur:** Colin Lit -**Audience:** Developers die Swift intents willen begrijpen of uitbreiden - ---- - -## πŸ“š Inhoudsopgave - -1. [Overzicht](#1-overzicht) -2. [Architectuur](#2-architectuur) -3. [Hoe het werkt](#3-hoe-het-werkt) -4. [Bestaande Intents](#4-bestaande-intents) -5. [Een nieuw intent toevoegen](#5-een-nieuw-intent-toevoegen) -6. [Best Practices](#6-best-practices) -7. [Troubleshooting](#7-troubleshooting) -8. [Testing](#8-testing) -9. [Referenties](#9-referenties) - ---- - -## 1. Overzicht - -### Wat is het Intent System? - -Het Swift Intent System is een **two-tier classificatie systeem** dat natuurlijke taal input van gebruikers analyseert en vertaalt naar concrete acties binnen de applicatie. - -**Doel:** -- Gebruikers kunnen in natuurlijke taal (Nederlands) communiceren met Swift -- Systeem herkent de intentie achter de input -- Opent het juiste artifact (UI component) met de juiste pre-filled data - -**Voorbeeld:** - -``` -User input: "notitie jan medicatie" - ↓ -Intent classification: 'dagnotitie' - ↓ -Entities extracted: { patient: "jan", category: "medicatie" } - ↓ -Action: Open DagnotatieBlock met pre-filled patient + category -``` - -### Waarom Two-Tier? - -| Tier | Methode | Snelheid | Accuracy | Use Case | -|------|---------|----------|----------|----------| -| **Tier 1** | Local regex patterns | <50ms | Hoog voor directe matches | "notitie jan", "afspraken vandaag" | -| **Tier 2** | AI (Claude Haiku) | ~400ms | Hoog voor complexe/ambigue input | "ik wil iets plannen voor volgende week" | - -**Voordelen:** -- βœ… **Snelheid:** 90%+ van queries worden lokaal afgehandeld (<50ms) -- βœ… **Kosten:** Alleen AI call bij onduidelijke input -- βœ… **Betrouwbaarheid:** Fallback naar AI als local match faalt -- βœ… **Flexibiliteit:** Makkelijk om nieuwe patterns toe te voegen - ---- - -## 2. Architectuur - -### System Diagram - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ USER INPUT β”‚ -β”‚ "maak afspraak met jan morgen 14:00" β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ TIER 1: Local Pattern Classifier β”‚ -β”‚ (lib/swift/intent-classifier.ts) β”‚ -β”‚ β”‚ -β”‚ β€’ Regex-based pattern matching β”‚ -β”‚ β€’ Client-side execution β”‚ -β”‚ β€’ Returns: { intent, confidence, processingTimeMs } β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Confidence β”‚ - β”‚ >= 0.8? β”‚ - β””β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”˜ - β”‚ YES β”‚ NO - ↓ ↓ - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ └──────────────────────────────────┐ - β”‚ β”‚ - ↓ ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Use Local β”‚ β”‚ TIER 2: AI Fallback Classifier β”‚ -β”‚ Result β”‚ β”‚ (lib/swift/intent-classifier-ai β”‚ -β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ .ts) β”‚ - β”‚ β”‚ β”‚ - β”‚ β”‚ β€’ Claude Haiku API call β”‚ - β”‚ β”‚ β€’ Server-side only β”‚ - β”‚ β”‚ β€’ Advanced entity extraction β”‚ - β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ INTENT ROUTER β”‚ -β”‚ (swift-store.ts / Chat API) β”‚ -β”‚ β”‚ -β”‚ β€’ Maps intent β†’ artifact type β”‚ -β”‚ β€’ Applies confidence thresholds β”‚ -β”‚ β€’ Triggers verduidelijkingsvragen bij lage confidence β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ARTIFACT MANAGER β”‚ -β”‚ β”‚ -β”‚ β€’ Opens appropriate artifact (DagnotatieBlock, etc.) β”‚ -β”‚ β€’ Pre-fills extracted entities β”‚ -β”‚ β€’ Manages artifact lifecycle β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Core Files - -| File | Locatie | Rol | Execution | -|------|---------|-----|-----------| -| **intent-classifier.ts** | `/lib/swift/` | Local pattern matching | Client-side | -| **intent-classifier-ai.ts** | `/lib/swift/` | AI fallback classifier | Server-side | -| **types.ts** | `/lib/swift/` | Type definitions | Both | -| **swift-store.ts** | `/stores/` | State management + routing | Client-side | -| **chat/route.ts** | `/app/api/swift/` | Chat API met streaming | Server-side | - ---- - -## 3. Hoe het werkt - -### Step-by-Step Flow - -#### Step 1: User Input - -```typescript -// User types in chat input -const userInput = "notitie jan medicatie"; -``` - -#### Step 2: Local Classification (Tier 1) - -```typescript -// lib/swift/intent-classifier.ts -import { classifyIntent } from '@/lib/swift/intent-classifier'; - -const result = classifyIntent(userInput); -// Returns: -{ - intent: 'dagnotitie', - confidence: 0.9, - matchedPattern: '/^notitie\\s+\\w+/', - processingTimeMs: 12 -} -``` - -**How it works:** - -```typescript -const INTENT_PATTERNS = { - dagnotitie: [ - { pattern: /^notitie\s+\w+/i, weight: 0.95 }, - { pattern: /^dagnotitie\b/i, weight: 1.0 }, - // ... meer patterns - ], - zoeken: [ - { pattern: /^zoek\b/i, weight: 1.0 }, - { pattern: /^wie\s+is\b/i, weight: 1.0 }, - // ... - ], - // ... -}; - -// Test all patterns, return highest weight match -for (const [intent, patterns] of Object.entries(INTENT_PATTERNS)) { - for (const { pattern, weight } of patterns) { - if (pattern.test(userInput)) { - // Found a match! - return { intent, confidence: weight }; - } - } -} -``` - -#### Step 3: Confidence Check - -```typescript -import { isHighConfidence, shouldUseAIFallback } from '@/lib/swift/intent-classifier'; - -if (isHighConfidence(result)) { - // confidence >= 0.8 - // β†’ Use local result, skip AI - return result; -} - -if (shouldUseAIFallback(result.confidence)) { - // confidence < 0.8 - // β†’ Trigger AI classification - const aiResult = await classifyIntentWithAI(userInput); - return aiResult; -} -``` - -#### Step 4a: AI Fallback (Tier 2) - If Needed - -```typescript -// lib/swift/intent-classifier-ai.ts (SERVER-SIDE ONLY) -import { classifyIntentWithAI } from '@/lib/swift/intent-classifier-ai'; - -const aiResult = await classifyIntentWithAI("ik wil een gesprek plannen"); -// Returns: -{ - intent: 'create_appointment', - confidence: 0.75, - entities: { - patientName: undefined, // Missing! - content: "een gesprek plannen" - }, - source: 'ai', - processingTimeMs: 380, - reasoning: "Gebruiker wil afspraak maken, maar patient ontbreekt" -} -``` - -**How it works:** - -1. Sends user input to Claude Haiku API -2. Uses structured system prompt with intent definitions -3. Expects JSON response with intent + entities + confidence -4. Validates response with Zod schema - -```typescript -const response = await fetch('https://api.anthropic.com/v1/messages', { - method: 'POST', - headers: { - 'x-api-key': process.env.ANTHROPIC_API_KEY, - 'anthropic-version': '2023-06-01', - }, - body: JSON.stringify({ - model: 'claude-3-5-haiku-20241022', - max_tokens: 256, - temperature: 0, - system: INTENT_CLASSIFIER_SYSTEM_PROMPT, - messages: [{ role: 'user', content: `Classificeer: "${input}"` }], - }), -}); - -const parsed = JSON.parse(response); -const validated = AIIntentResponseSchema.parse(parsed); -``` - -#### Step 5: Intent Routing - -```typescript -// In swift-store.ts or chat API -function handleIntent(intent: SwiftIntent, entities: ExtractedEntities, confidence: number) { - - // Confidence too low β†’ ask clarification - if (confidence < 0.7) { - return { - type: 'clarification_needed', - question: generateClarificationQuestion(intent, entities) - }; - } - - // Route to appropriate artifact - switch (intent) { - case 'dagnotitie': - return openArtifact({ - type: 'DagnotatieBlock', - mode: 'create', - prefill: { - patient: entities.patientName, - category: entities.category, - content: entities.content - } - }); - - case 'zoeken': - return openArtifact({ - type: 'ZoekenBlock', - prefill: { query: entities.patientName } - }); - - case 'agenda_query': - return openArtifact({ - type: 'AgendaBlock', - mode: 'list', - prefill: { dateRange: entities.dateRange } - }); - - // ... etc - } -} -``` - -#### Step 6: Artifact Opens - -```typescript -// Artifact Manager opens the correct component - -``` - ---- - -## 4. Bestaande Intents - -### Intent Overzicht - -| Intent | Beschrijving | Artifacts | Entities | -|--------|--------------|-----------|----------| -| **dagnotitie** | Notitie maken voor patiΓ«nt | DagnotatieBlock | patientName, category, content | -| **zoeken** | PatiΓ«nt zoeken | ZoekenBlock, PatientContextCard | patientName | -| **overdracht** | Dienst overdracht genereren | OverdrachtBlock | β€” | -| **agenda_query** | Afspraken opvragen | AgendaBlock (list) | dateRange | -| **create_appointment** | Nieuwe afspraak maken | AgendaBlock (create) | patient, datetime, type, location | -| **cancel_appointment** | Afspraak annuleren | AgendaBlock (cancel) | identifier | -| **reschedule_appointment** | Afspraak verzetten | AgendaBlock (reschedule) | identifier, newDatetime | -| **unknown** | Niet herkend | Fallback picker | β€” | - -### Pattern Examples - -**Dagnotitie:** -```typescript -dagnotitie: [ - { pattern: /^dagnotitie\b/i, weight: 1.0 }, - { pattern: /^notitie\b/i, weight: 1.0 }, - { pattern: /^notitie\s+\w+/i, weight: 0.95 }, // "notitie jan" - { pattern: /^\w+\s+(medicatie|adl|gedrag|incident)/i, weight: 0.9 }, // "jan medicatie" -] -``` - -**Zoeken:** -```typescript -zoeken: [ - { pattern: /^zoek\b/i, weight: 1.0 }, - { pattern: /^wie\s+is\b/i, weight: 1.0 }, // "wie is jan" - { pattern: /^vind\s+\w+/i, weight: 1.0 }, // "vind marie" - { pattern: /^[A-Z][a-z]+$/i, weight: 0.5 }, // Single capitalized word -] -``` - -**Agenda Query:** -```typescript -agenda_query: [ - { pattern: /^afspraken?\b/i, weight: 1.0 }, // "afspraken" - { pattern: /^agenda\b/i, weight: 1.0 }, // "agenda" - { pattern: /^wat\s+zijn\s+(mijn\s+)?afspraken/i, weight: 1.0 }, - { pattern: /^volgende\s+afspraak/i, weight: 0.95 }, -] -``` - ---- - -## 5. Een nieuw intent toevoegen - -### Voorbeeld: "metingen" intent - -Stel je wilt een nieuw intent toevoegen voor het invoeren van vitale metingen (bloeddruk, temperatuur, etc.). - -**Gewenste flow:** -``` -User: "bloeddruk jan 120/80" -β†’ Intent: 'metingen' -β†’ Entities: { patient: "jan", type: "bloeddruk", value: "120/80" } -β†’ Opens: MetingenBlock met pre-filled data -``` - -### Step 1: Update Types - -**File:** `lib/swift/types.ts` - -```typescript -// Add new intent to enum -export type SwiftIntent = - | 'dagnotitie' - | 'zoeken' - | 'overdracht' - | 'agenda_query' - | 'create_appointment' - | 'cancel_appointment' - | 'reschedule_appointment' - | 'metingen' // ← NEW - | 'unknown'; - -// Extend ExtractedEntities -export interface ExtractedEntities { - // Existing fields - patientName?: string; - category?: VerpleegkundigCategory; - content?: string; - // ... other existing fields - - // NEW: Metingen-specific entities - metingType?: 'bloeddruk' | 'temperatuur' | 'pols' | 'saturatie' | 'gewicht'; - metingValue?: string; - metingUnit?: string; - metingTimestamp?: Date; -} -``` - -### Step 2: Add Local Patterns - -**File:** `lib/swift/intent-classifier.ts` - -```typescript -const INTENT_PATTERNS: Record, PatternConfig[]> = { - // ... existing patterns - - // NEW: Metingen patterns - metingen: [ - // Exact commands - { pattern: /^meting\b/i, weight: 1.0 }, - { pattern: /^metingen\b/i, weight: 1.0 }, - { pattern: /^vitale\s+functies\b/i, weight: 1.0 }, - - // Type-specific patterns - { pattern: /^bloeddruk\b/i, weight: 1.0 }, - { pattern: /^temperatuur\b/i, weight: 1.0 }, - { pattern: /^pols\b/i, weight: 0.95 }, - { pattern: /^saturatie\b/i, weight: 0.95 }, - { pattern: /^gewicht\b/i, weight: 0.95 }, - - // Pattern: "bloeddruk [naam]" or "[naam] bloeddruk" - { pattern: /^bloeddruk\s+\w+/i, weight: 0.95 }, - { pattern: /^\w+\s+bloeddruk/i, weight: 0.9 }, - - // Pattern: "bloeddruk [naam] [waarde]" - { pattern: /^bloeddruk\s+\w+\s+\d+/i, weight: 0.98 }, - - // Pattern with value patterns - { pattern: /\d{2,3}\/\d{2,3}/i, weight: 0.7 }, // "120/80" format - { pattern: /\d+\s*graden?/i, weight: 0.7 }, // "38 graden" - ], -}; -``` - -**Pattern Weight Guidelines:** -- **1.0** = Exact, unambiguous match ("meting", "bloeddruk") -- **0.9-0.95** = Strong match with context ("bloeddruk jan") -- **0.8-0.89** = Good match, minor ambiguity -- **0.7-0.79** = Partial match, needs additional context -- **<0.7** = Weak match, likely needs AI fallback - -### Step 3: Update AI System Prompt - -**File:** `lib/swift/intent-classifier-ai.ts` - -```typescript -const INTENT_CLASSIFIER_SYSTEM_PROMPT = `Je bent een intent classifier voor Swift EPD. - -Classificeer de intentie in één van deze categorieΓ«n: - -**Bestaande intents:** -1. dagnotitie - Notitie maken -2. zoeken - PatiΓ«nt zoeken -3. overdracht - Dienst overdracht -4-7. [agenda intents...] - -**Nieuwe intent:** -8. **metingen** - Vitale functies invoeren - Voorbeelden: "bloeddruk jan 120/80", "temperatuur marie 38 graden", "pols invoeren" - Extraheer: patientName, metingType, metingValue, metingUnit - - Types: bloeddruk, temperatuur, pols, saturatie, gewicht - - Value patterns: - - Bloeddruk: "120/80" (systolisch/diastolisch) - - Temperatuur: "38" of "38 graden" of "38.5" - - Pols: "72" of "72 bpm" - - Saturatie: "98" of "98%" - - Gewicht: "75" of "75 kg" - -9. unknown - Onduidelijk - -**Response format:** -{ - "intent": "...", - "confidence": 0.0-1.0, - "entities": { - "patientName": "jan", - "metingType": "bloeddruk", - "metingValue": "120/80", - "metingUnit": "mmHg" // optioneel - } -} -`; -``` - -**Update Zod Schema:** - -```typescript -const AIIntentResponseSchema = z.object({ - intent: z.enum([ - 'dagnotitie', - 'zoeken', - 'overdracht', - 'agenda_query', - 'create_appointment', - 'cancel_appointment', - 'reschedule_appointment', - 'metingen', // ← ADD - 'unknown' - ]), - confidence: z.number().min(0).max(1), - entities: z.object({ - patientName: z.string().optional(), - category: z.enum(['medicatie', 'adl', 'gedrag', 'incident', 'observatie']).optional(), - content: z.string().optional(), - // ... existing fields - - // NEW - metingType: z.enum(['bloeddruk', 'temperatuur', 'pols', 'saturatie', 'gewicht']).optional(), - metingValue: z.string().optional(), - metingUnit: z.string().optional(), - }).optional(), - reasoning: z.string().optional(), -}); -``` - -### Step 4: Add Intent Routing - -**File:** `stores/swift-store.ts` or chat API route - -```typescript -function openArtifactForIntent( - intent: SwiftIntent, - entities: ExtractedEntities, - confidence: number -): ArtifactConfig | null { - - // Confidence check - if (confidence < 0.7) { - return null; // Trigger clarification - } - - switch (intent) { - // ... existing cases - - // NEW - case 'metingen': - // Validate required entities - if (!entities.patientName || !entities.metingType) { - return null; // Need more info - } - - return { - type: 'MetingenBlock', - mode: 'create', - prefill: { - patient: entities.patientName, - type: entities.metingType, - value: entities.metingValue, - unit: entities.metingUnit, - timestamp: entities.metingTimestamp || new Date() - } - }; - - default: - return null; - } -} -``` - -### Step 5: Create the Artifact Component - -**File:** `components/swift/artifacts/blocks/metingen-block.tsx` - -```typescript -interface MetingenBlockProps { - mode: 'create' | 'view'; - prefill?: { - patient?: { id: string; name: string }; - type?: MetingType; - value?: string; - unit?: string; - timestamp?: Date; - }; - onClose?: () => void; -} - -export function MetingenBlock({ mode, prefill, onClose }: MetingenBlockProps) { - const [formData, setFormData] = useState({ - patientId: prefill?.patient?.id || '', - type: prefill?.type || 'bloeddruk', - value: prefill?.value || '', - unit: prefill?.unit || getDefaultUnit(prefill?.type), - timestamp: prefill?.timestamp || new Date(), - }); - - const handleSubmit = async () => { - // Call server action to save measurement - await createMeasurement(formData); - // Show success toast - toast.success('Meting opgeslagen!'); - onClose?.(); - }; - - return ( -
-
-

πŸ“Š Vitale Functies

- -
- -
- {/* Patient selector */} - setFormData({ ...formData, patientId: id })} - defaultName={prefill?.patient?.name} - /> - - {/* Type selector */} - - - {/* Value input */} - setFormData({ ...formData, value: e.target.value })} - placeholder={getPlaceholder(formData.type)} - /> - - {/* Unit (auto-filled based on type) */} - - - {/* Timestamp */} - setFormData({ ...formData, timestamp })} - /> - -
- - -
- -
- ); -} - -function getDefaultUnit(type?: MetingType): string { - switch (type) { - case 'bloeddruk': return 'mmHg'; - case 'temperatuur': return 'Β°C'; - case 'pols': return 'bpm'; - case 'saturatie': return '%'; - case 'gewicht': return 'kg'; - default: return ''; - } -} -``` - -### Step 6: Register Artifact Type - -**File:** `stores/swift-store.ts` or artifact registry - -```typescript -export type ArtifactType = - | 'DagnotatieBlock' - | 'ZoekenBlock' - | 'PatientContextCard' - | 'OverdrachtBlock' - | 'AgendaBlock' - | 'MetingenBlock' // ← ADD - ; - -// Add to artifact component mapping -const ARTIFACT_COMPONENTS = { - DagnotatieBlock: lazy(() => import('@/components/swift/artifacts/blocks/dagnotitie-block')), - ZoekenBlock: lazy(() => import('@/components/swift/artifacts/blocks/zoeken-block')), - // ... existing - MetingenBlock: lazy(() => import('@/components/swift/artifacts/blocks/metingen-block')), // ← ADD -}; -``` - -### Step 7: Test - -**Manual Testing Checklist:** - -```typescript -// Test cases for 'metingen' intent - -// βœ… Local pattern matches (high confidence) -"bloeddruk jan 120/80" β†’ intent: metingen, conf: 0.98 -"temperatuur marie" β†’ intent: metingen, conf: 1.0 -"pols" β†’ intent: metingen, conf: 0.95 - -// βœ… AI fallback (ambiguous) -"jan zijn bloeddruk invoeren" β†’ AI: intent: metingen, conf: 0.85 -"ik wil vitale functies noteren" β†’ AI: intent: metingen, conf: 0.75 - -// βœ… Edge cases -"bloeddruk" β†’ Missing patient, show clarification -"jan" β†’ Likely 'zoeken', not 'metingen' -"bloeddruk 120/80" β†’ Missing patient, show clarification - -// βœ… Artifact opens correctly -"bloeddruk jan 120/80" β†’ MetingenBlock opens with prefill - - patient: "jan" - - type: "bloeddruk" - - value: "120/80" - - unit: "mmHg" - -// βœ… Voice input works -[Voice] "bloeddruk jan honderdtwintig tachtig" -β†’ Transcript: "bloeddruk jan honderdtwintig tachtig" -β†’ AI parses: value: "120/80" -β†’ Opens MetingenBlock -``` - -**Unit Tests:** - -```typescript -// __tests__/intent-classifier.test.ts -import { classifyIntent } from '@/lib/swift/intent-classifier'; - -describe('Intent Classifier - Metingen', () => { - it('should classify "bloeddruk jan 120/80" as metingen', () => { - const result = classifyIntent('bloeddruk jan 120/80'); - expect(result.intent).toBe('metingen'); - expect(result.confidence).toBeGreaterThanOrEqual(0.9); - }); - - it('should classify "temperatuur" as metingen', () => { - const result = classifyIntent('temperatuur'); - expect(result.intent).toBe('metingen'); - expect(result.confidence).toBe(1.0); - }); - - it('should have low confidence for "jan bloeddruk"', () => { - const result = classifyIntent('jan bloeddruk'); - expect(result.intent).toBe('metingen'); - expect(result.confidence).toBeLessThan(0.95); - }); -}); -``` - ---- - -## 6. Best Practices - -### Pattern Design - -**βœ… DO:** - -```typescript -// Clear, specific patterns first -{ pattern: /^bloeddruk\b/i, weight: 1.0 } -{ pattern: /^temperatuur\b/i, weight: 1.0 } - -// Then patterns with context -{ pattern: /^bloeddruk\s+\w+/i, weight: 0.95 } // "bloeddruk jan" - -// Finally, partial matches -{ pattern: /\d{2,3}\/\d{2,3}/i, weight: 0.7 } // "120/80" format -``` - -**❌ DON'T:** - -```typescript -// Too broad - will match everything -{ pattern: /./i, weight: 1.0 } - -// Too specific - will never match natural language -{ pattern: /^bloeddruk\s+jan\s+120\/80$/i, weight: 1.0 } - -// Overlapping high-weight patterns (creates ambiguity) -{ pattern: /^notitie\b/i, weight: 1.0 } -{ pattern: /^notitie\s+/i, weight: 1.0 } // Redundant! -``` - -### Confidence Weights - -**Guidelines:** - -| Weight Range | Use Case | Example | -|--------------|----------|---------| -| **1.0** | Exact keyword match, no ambiguity | `/^bloeddruk\b/i` | -| **0.9-0.95** | Strong match with minimal context | `/^bloeddruk\s+\w+/i` | -| **0.8-0.89** | Good match, some context needed | `/^\w+\s+bloeddruk/i` | -| **0.7-0.79** | Partial match, may need AI | `/\d{2,3}\/\d{2,3}/i` | -| **<0.7** | Weak match, definitely needs AI | β€” | - -**Threshold decisions:** - -```typescript -if (confidence >= 0.8) { - // High confidence β†’ Use local result - return openArtifact(intent, entities); -} - -if (confidence >= 0.7) { - // Medium confidence β†’ Open artifact + confirmation in chat - openArtifact(intent, entities); - return chatResponse("Klopt dit? [intent description]"); -} - -if (confidence >= 0.5) { - // Low confidence β†’ Ask clarification - return chatResponse(generateClarificationQuestion(intent, entities)); -} - -// confidence < 0.5 -// Very low β†’ Show fallback picker or generic help -return showFallbackPicker(); -``` - -### Entity Extraction - -**Local extraction (basic):** - -```typescript -// Extract from regex capture groups -const pattern = /^bloeddruk\s+(\w+)\s+(\d+\/\d+)/i; -const match = pattern.exec(input); - -if (match) { - return { - intent: 'metingen', - entities: { - patientName: match[1], // "jan" - metingValue: match[2], // "120/80" - } - }; -} -``` - -**AI extraction (advanced):** - -Let the AI handle complex parsing: -- Relative dates: "morgen", "volgende week dinsdag" -- Number words: "honderdtwintig tachtig" β†’ "120/80" -- Implicit entities: "deze patiΓ«nt" (uses context) - -### Performance Optimization - -**βœ… DO:** - -```typescript -// Pre-compile regex patterns (happens at module load) -const PATTERNS = { - bloeddruk: /^bloeddruk\b/i, - temperatuur: /^temperatuur\b/i, -}; - -// Early exit on perfect match -if (confidence === 1.0) break; - -// Cache frequent queries (if applicable) -const cache = new Map(); -``` - -**❌ DON'T:** - -```typescript -// Don't create regex in loop -for (const input of inputs) { - const pattern = new RegExp(`^${keyword}\\b`, 'i'); // ❌ Slow! -} - -// Don't make unnecessary AI calls -if (confidence >= 0.8) { - const aiResult = await classifyWithAI(input); // ❌ Waste of time & money -} -``` - -### Error Handling - -**Always validate:** - -```typescript -// Validate AI response -try { - const parsed = JSON.parse(aiResponse); - const validated = AIIntentResponseSchema.parse(parsed); - return validated; -} catch (error) { - console.error('AI classification error:', error); - // Fallback to unknown intent - return { - intent: 'unknown', - confidence: 0, - source: 'ai', - }; -} - -// Validate entity presence before opening artifact -if (!entities.patientName) { - // Ask clarification instead of opening empty artifact - return askClarification("Met welke patiΓ«nt?"); -} -``` - ---- - -## 7. Troubleshooting - -### Common Issues - -#### Issue 1: Intent not being recognized - -**Symptoms:** -``` -User: "bloeddruk jan" -Result: intent: 'unknown', confidence: 0 -``` - -**Debugging:** - -```typescript -// 1. Check if pattern exists -console.log(INTENT_PATTERNS.metingen); -// Should show array of patterns - -// 2. Test pattern manually -const pattern = /^bloeddruk\b/i; -console.log(pattern.test("bloeddruk jan")); -// Should be true - -// 3. Check pattern order (first match wins) -// If pattern is below a more generic pattern, it may never be tested - -// 4. Check case sensitivity -const pattern = /^Bloeddruk\b/; // ❌ Won't match "bloeddruk" -const pattern = /^bloeddruk\b/i; // βœ… Case insensitive -``` - -**Solution:** -```typescript -// Add or fix pattern -metingen: [ - { pattern: /^bloeddruk\b/i, weight: 1.0 }, // ← Ensure this exists - // ... -] -``` - -#### Issue 2: Wrong intent detected - -**Symptoms:** -``` -User: "jan bloeddruk" -Result: intent: 'zoeken', confidence: 0.5 // ❌ Should be 'metingen' -``` - -**Cause:** Pattern for 'zoeken' matches first: - -```typescript -zoeken: [ - { pattern: /^[A-Z][a-z]+$/i, weight: 0.5 }, // Matches "jan" -] -``` - -**Solution:** Add more specific patterns with higher weight: - -```typescript -metingen: [ - { pattern: /^\w+\s+bloeddruk/i, weight: 0.9 }, // "jan bloeddruk" β†’ metingen -] - -// Or: Lower weight of generic patterns -zoeken: [ - { pattern: /^[A-Z][a-z]+$/i, weight: 0.3 }, // Lower weight -] -``` - -#### Issue 3: AI fallback not triggering - -**Symptoms:** -``` -User: "ik wil de bloeddruk invoeren" -Result: intent: 'unknown', confidence: 0 // AI should have helped -``` - -**Debugging:** - -```typescript -// 1. Check confidence threshold -if (result.confidence < 0.8) { - // Should trigger AI - const aiResult = await classifyIntentWithAI(input); -} - -// 2. Check API key -console.log(process.env.ANTHROPIC_API_KEY); // Should be set - -// 3. Check AI is only called server-side -// AI classifier should NEVER run in browser -``` - -**Solution:** -```typescript -// Ensure AI fallback is in server-side code only -// app/api/swift/chat/route.ts (βœ… Server-side) -// components/client-component.tsx (❌ Client-side, won't work) -``` - -#### Issue 4: Entities not extracted - -**Symptoms:** -``` -User: "bloeddruk jan 120/80" -Result: intent: 'metingen', entities: {} // ❌ Should extract patient + value -``` - -**Cause:** Local classifier only does basic regex matching. Complex entity extraction requires AI or custom parsing. - -**Solutions:** - -**Option A:** Add local entity extraction: - -```typescript -// In intent-classifier.ts -const pattern = /^bloeddruk\s+(\w+)\s+(.+)/i; -const match = pattern.exec(input); - -if (match) { - return { - intent: 'metingen', - confidence: 0.95, - entities: { - patientName: match[1], // "jan" - metingValue: match[2], // "120/80" - } - }; -} -``` - -**Option B:** Let AI handle entity extraction: - -```typescript -// Trigger AI when entities are crucial -if (result.intent === 'metingen' && !result.entities?.patientName) { - // Local matched intent, but missing entities β†’ Use AI for entity extraction - const aiResult = await classifyIntentWithAI(input); - return { - intent: result.intent, - confidence: result.confidence, - entities: aiResult.entities, // Use AI-extracted entities - }; -} -``` - -#### Issue 5: Slow performance - -**Symptoms:** -- Local classification takes >100ms -- UI feels sluggish - -**Debugging:** - -```typescript -const result = classifyIntent(input); -console.log(`Classification took ${result.processingTimeMs}ms`); - -// Target: <50ms -// Acceptable: <100ms -// Slow: >100ms -``` - -**Common causes:** - -1. **Too many patterns** (>100 patterns total) - - Solution: Consolidate similar patterns - -2. **Complex regex** (catastrophic backtracking) - ```typescript - // ❌ BAD: Can cause exponential backtracking - { pattern: /^(a+)+b/, weight: 1.0 } - - // βœ… GOOD: Simple, efficient patterns - { pattern: /^a+b/, weight: 1.0 } - ``` - -3. **Not breaking early on perfect match** - ```typescript - // βœ… Add early exit - if (bestMatch?.confidence === 1.0) break; - ``` - ---- - -## 8. Testing - -### Unit Tests - -**File:** `__tests__/intent-classifier.test.ts` - -```typescript -import { classifyIntent } from '@/lib/swift/intent-classifier'; - -describe('Intent Classifier', () => { - describe('Dagnotitie intent', () => { - it('should recognize "notitie jan"', () => { - const result = classifyIntent('notitie jan'); - expect(result.intent).toBe('dagnotitie'); - expect(result.confidence).toBeGreaterThanOrEqual(0.9); - }); - - it('should recognize "jan medicatie"', () => { - const result = classifyIntent('jan medicatie'); - expect(result.intent).toBe('dagnotitie'); - expect(result.confidence).toBeGreaterThanOrEqual(0.8); - }); - }); - - describe('Zoeken intent', () => { - it('should recognize "zoek jan"', () => { - const result = classifyIntent('zoek jan'); - expect(result.intent).toBe('zoeken'); - expect(result.confidence).toBe(1.0); - }); - - it('should recognize "wie is jan"', () => { - const result = classifyIntent('wie is jan'); - expect(result.intent).toBe('zoeken'); - expect(result.confidence).toBe(1.0); - }); - }); - - describe('Performance', () => { - it('should classify in less than 50ms', () => { - const result = classifyIntent('notitie jan medicatie'); - expect(result.processingTimeMs).toBeLessThan(50); - }); - }); - - describe('Confidence thresholds', () => { - it('should return high confidence for exact matches', () => { - const result = classifyIntent('dagnotitie'); - expect(result.confidence).toBe(1.0); - }); - - it('should return lower confidence for partial matches', () => { - const result = classifyIntent('jan'); - expect(result.confidence).toBeLessThan(0.8); - }); - }); -}); -``` - -### Integration Tests - -**File:** `__tests__/intent-flow.test.ts` - -```typescript -import { classifyIntent } from '@/lib/swift/intent-classifier'; -import { classifyIntentWithAI } from '@/lib/swift/intent-classifier-ai'; -import { openArtifactForIntent } from '@/stores/swift-store'; - -describe('Intent Flow Integration', () => { - it('should open DagnotatieBlock for "notitie jan medicatie"', async () => { - // Step 1: Classify - const result = classifyIntent('notitie jan medicatie'); - expect(result.intent).toBe('dagnotitie'); - - // Step 2: Route to artifact - const artifact = openArtifactForIntent( - result.intent, - { patientName: 'jan', category: 'medicatie' }, - result.confidence - ); - - expect(artifact).toEqual({ - type: 'DagnotatieBlock', - mode: 'create', - prefill: { - patient: 'jan', - category: 'medicatie', - } - }); - }); - - it('should trigger AI fallback for ambiguous input', async () => { - // Step 1: Local classification (low confidence) - const localResult = classifyIntent('ik wil iets noteren'); - expect(localResult.confidence).toBeLessThan(0.8); - - // Step 2: AI fallback - const aiResult = await classifyIntentWithAI('ik wil iets noteren'); - expect(aiResult.intent).toBe('dagnotitie'); - expect(aiResult.confidence).toBeGreaterThan(0.5); - }); -}); -``` - -### Manual Test Scenarios - -**Checklist:** `docs/swift/manual-test-intents.md` - -```markdown -# Manual Test Scenarios - Intent System - -## Dagnotitie -- [ ] "notitie jan" β†’ Opens DagnotatieBlock with patient "jan" -- [ ] "jan medicatie" β†’ Opens DagnotatieBlock with patient + category -- [ ] "dagnotitie" β†’ Opens DagnotatieBlock empty -- [ ] "schrijf observatie voor marie" β†’ AI fallback, extracts patient + category - -## Zoeken -- [ ] "zoek jan" β†’ Opens ZoekenBlock with query "jan" -- [ ] "wie is marie" β†’ Opens ZoekenBlock -- [ ] "Jan" (single word) β†’ Low confidence, shows options - -## Agenda -- [ ] "afspraken vandaag" β†’ Opens AgendaBlock (list, today) -- [ ] "maak afspraak jan morgen 14:00" β†’ Opens AgendaBlock (create, prefilled) -- [ ] "annuleer jan" β†’ Opens AgendaBlock (cancel, shows matches) - -## Voice Input -- [ ] [Voice] "notitie jan medicatie" β†’ Transcribes correctly, opens artifact -- [ ] [Voice] "bloeddruk jan honderdtwintig tachtig" β†’ AI parses numbers - -## Edge Cases -- [ ] Empty input β†’ intent: unknown -- [ ] Gibberish β†’ intent: unknown, triggers fallback picker -- [ ] Mixed language β†’ AI tries to parse, may ask clarification -``` - ---- - -## 9. Referenties - -### Code Locations - -| Component | File Path | -|-----------|-----------| -| **Local Classifier** | `/lib/swift/intent-classifier.ts` | -| **AI Classifier** | `/lib/swift/intent-classifier-ai.ts` | -| **Type Definitions** | `/lib/swift/types.ts` | -| **State Management** | `/stores/swift-store.ts` | -| **Chat API** | `/app/api/swift/chat/route.ts` | -| **Artifacts** | `/components/swift/artifacts/blocks/` | - -### External Resources - -- **Regex Testing:** [regex101.com](https://regex101.com/) -- **Claude API Docs:** [docs.anthropic.com](https://docs.anthropic.com) -- **Zod Validation:** [zod.dev](https://zod.dev/) -- **TypeScript Handbook:** [typescriptlang.org](https://www.typescriptlang.org/docs/) - -### Related Documentation - -- **Swift FO v3.0:** `docs/swift/fo-swift-medical-scribe-v3.md` -- **Agenda FO:** `docs/swift/fo-swift-agenda-planning.md` -- **Bouwplan:** `docs/swift/bouwplan-swift-standalone-module.md` -- **Architecture Decision Records:** `docs/architecture/` - ---- - -## πŸ“‹ Quick Reference Card - -### Adding a New Intent - Checklist - -- [ ] **Step 1:** Add intent to `SwiftIntent` type (`lib/swift/types.ts`) -- [ ] **Step 2:** Extend `ExtractedEntities` with new fields -- [ ] **Step 3:** Add patterns to `INTENT_PATTERNS` (`intent-classifier.ts`) -- [ ] **Step 4:** Update AI system prompt (`intent-classifier-ai.ts`) -- [ ] **Step 5:** Update Zod schema for AI response -- [ ] **Step 6:** Add routing logic (`swift-store.ts`) -- [ ] **Step 7:** Create artifact component (`components/swift/artifacts/blocks/`) -- [ ] **Step 8:** Register artifact type in component mapping -- [ ] **Step 9:** Write unit tests -- [ ] **Step 10:** Manual testing -- [ ] **Step 11:** Update documentation - -### Pattern Weight Quick Guide - -```typescript -1.0 // "bloeddruk" - exact match -0.95 // "bloeddruk jan" - strong match with context -0.9 // "jan bloeddruk" - good match, reversed order -0.8 // partial match with good context -0.7 // partial match, may need AI -<0.7 // weak match, likely needs AI fallback -``` - -### Common Regex Patterns - -```typescript -// Keywords -/^bloeddruk\b/i // Starts with "bloeddruk" -/\bbloeddruk\b/i // Contains "bloeddruk" (word boundary) - -// With patient name -/^bloeddruk\s+(\w+)/i // "bloeddruk jan" - captures "jan" -/^(\w+)\s+bloeddruk/i // "jan bloeddruk" - captures "jan" - -// With values -/\d{2,3}\/\d{2,3}/ // "120/80" - blood pressure format -/\d+\s*graden?/i // "38 graden" - temperature -/\d+\s*%/ // "98%" - percentage - -// Case insensitive -/pattern/i // 'i' flag = case insensitive - -// Word boundary -/\bword\b/ // Only matches whole word "word" -``` - ---- - -**Document Version:** 1.0 -**Last Updated:** 27-12-2024 -**Maintainer:** Swift Development Team - -**Questions?** Check the troubleshooting section or reach out to the team. diff --git a/docs/swift/e0-design-tokens-and-components.md b/docs/swift/e0-design-tokens-and-components.md deleted file mode 100644 index dd5948d..0000000 --- a/docs/swift/e0-design-tokens-and-components.md +++ /dev/null @@ -1,426 +0,0 @@ -# Epic 0 β€” Design Tokens & Component Inventory - -**Datum:** 27-12-2024 -**Auteur:** AI Assistant -**Status:** βœ… Completed - ---- - -## E0.S1 β€” Design Tokens Audit - -🎯 **Doel:** Alle kleuren, spacing, typography gedocumenteerd voor v3.0 gebruik. - -### Colors (blijven hetzelfde voor v3.0) - -#### Base Colors -```css ---color-bg: #F8FAFC; /* App background */ ---color-surface: #FFFFFF; /* Cards, blocks, surfaces */ ---color-surface-secondary: #F1F5F9; /* Secondary surfaces */ ---color-text: #0F172A; /* Primary text (slate-900) */ ---color-text-secondary: #475569; /* Secondary text (slate-600) */ ---color-border: #E2E8F0; /* Borders (slate-200) */ -``` - -#### Brand Colors (Teal-first Design System) -```css ---color-brand: #0F766E; /* teal-700 - PRIMARY (5.47:1 WCAG AA) */ ---color-brand-hover: #115E59; /* teal-800 */ ---color-brand-active: #0D9488; /* teal-600 */ ---color-brand-subtle: #F0FDFA; /* teal-50 */ -``` - -#### AI Feature Colors (Amber) -```css ---color-ai: #D97706; /* amber-600 - PRIMARY AI (3.19:1 WCAG AA large) */ ---color-ai-hover: #B45309; /* amber-700 */ ---color-ai-subtle: #FFFBEB; /* amber-50 */ -``` - -#### Status & Feedback Colors -```css ---color-success: #16A34A; /* green-600 */ ---color-success-subtle: #ECFDF5; /* green-50 */ ---color-warning: #EAB308; /* yellow-500 */ ---color-warning-subtle: #FEFCE8; /* yellow-50 */ ---color-error: #DC2626; /* red-600 */ ---color-error-subtle: #FEF2F2; /* red-50 */ ---color-info: #0F766E; /* teal-700 - Brand consistency */ ---color-info-subtle: #CCFBF1; /* teal-100 */ -``` - -#### Form/Input Colors -```css ---color-input-bg: #FFFFFF; ---color-input-text: #0F172A; ---color-input-placeholder: #94A3B8; /* slate-400 */ ---color-input-border: #CBD5E1; /* slate-300 */ ---color-input-border-hover: #94A3B8; ---color-input-focus: #0F766E; /* teal-700 */ ---color-input-focus-border: #115E59; /* teal-800 */ ---color-input-disabled-bg: #F1F5F9; ---color-input-disabled-text: #94A3B8; -``` - ---- - -### πŸ†• NEW: Chat Message Colors (v3.0 only) - -Voor de nieuwe chat interface: - -```css -/* User messages (rechts, amber tint) */ ---chat-user-bg: #FFFBEB; /* amber-50 */ ---chat-user-border: #FED7AA; /* amber-200 */ ---chat-user-text: #0F172A; /* text-primary */ - -/* Assistant messages (links, slate tint) */ ---chat-assistant-bg: #F1F5F9; /* slate-100 */ ---chat-assistant-border: #CBD5E1; /* slate-300 */ ---chat-assistant-text: #0F172A; /* text-primary */ - -/* System messages (centered, subtle) */ ---chat-system-text: #64748B; /* slate-500 */ - -/* Error messages (links, red tint) */ ---chat-error-bg: #FEF2F2; /* red-50 */ ---chat-error-border: #FECACA; /* red-200 */ ---chat-error-text: #991B1B; /* red-800 */ -``` - -**Tailwind classes voor chat messages:** -```tsx -const MESSAGE_STYLES = { - user: { - container: 'self-end bg-amber-50 border border-amber-200 text-slate-900', - borderRadius: 'rounded-2xl rounded-tr-sm', - }, - assistant: { - container: 'self-start bg-slate-100 border border-slate-300 text-slate-900', - borderRadius: 'rounded-2xl rounded-tl-sm', - }, - system: { - container: 'self-center text-slate-500 text-sm', - borderRadius: '', - }, - error: { - container: 'self-start bg-red-50 border border-red-200 text-red-800', - borderRadius: 'rounded-2xl', - }, -}; -``` - ---- - -### Verpleegkundig Category Colors (blijven hetzelfde) - -Gebruikt in DagnotatieBlock, OverdrachtBlock: - -```typescript -export const CATEGORY_CONFIG = { - medicatie: { - label: 'Medicatie', - icon: 'Pill', - bgColor: 'bg-blue-100', // #DBEAFE - textColor: 'text-blue-700', // #1D4ED8 - }, - adl: { - label: 'ADL/verzorging', - icon: 'Utensils', - bgColor: 'bg-green-100', // #DCFCE7 - textColor: 'text-green-700', // #15803D - }, - gedrag: { - label: 'Gedragsobservatie', - icon: 'User', - bgColor: 'bg-purple-100', // #F3E8FF - textColor: 'text-purple-700', // #7E22CE - }, - incident: { - label: 'Incident', - icon: 'AlertTriangle', - bgColor: 'bg-red-100', // #FEE2E2 - textColor: 'text-red-700', // #B91C1C - }, - observatie: { - label: 'Observatie', - icon: 'Eye', - bgColor: 'bg-slate-100', // #F1F5F9 - textColor: 'text-slate-700', // #334155 - }, -}; -``` - ---- - -### Swift Shift Colors (blijven hetzelfde) - -Gebruikt in ContextBar: - -```typescript -const SHIFT_CONFIG = { - ochtend: { - icon: Sunrise, - label: 'Ochtenddienst', - color: 'text-amber-600', // #D97706 - }, - middag: { - icon: Sun, - label: 'Middagdienst', - color: 'text-yellow-600', // #CA8A04 - }, - avond: { - icon: Sunset, - label: 'Avonddienst', - color: 'text-orange-600', // #EA580C - }, - nacht: { - icon: Moon, - label: 'Nachtdienst', - color: 'text-indigo-600', // #4F46E5 - }, -}; -``` - ---- - -### Shadows (blijven hetzelfde) - -```css ---shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06); ---shadow-md: 0 2px 6px rgba(15, 23, 42, 0.08); ---shadow-lg: 0 8px 20px rgba(15, 23, 42, 0.10); -``` - -**Tailwind classes:** -- `shadow-sm` β€” Subtle shadows (cards, inputs) -- `shadow-md` β€” Medium shadows (dropdowns, popovers) -- `shadow-lg` β€” Large shadows (modals, dialogs) - ---- - -### Border Radius (blijven hetzelfde) - -```css ---radius: 0.625rem; /* 10px - base radius */ -``` - -**Tailwind classes:** -- `rounded-sm` β€” 4px (small elements) -- `rounded-md` β€” 8px (buttons, inputs) -- `rounded-lg` β€” 10px (cards, blocks) -- `rounded-2xl` β€” 16px (chat bubbles, large cards) -- `rounded-full` β€” 9999px (avatars, badges) - ---- - -### Typography Scale - -```css -/* Font sizes */ ---text-xs: 0.75rem; /* 12px */ ---text-sm: 0.875rem; /* 14px */ ---text-base: 1rem; /* 16px */ ---text-lg: 1.125rem; /* 18px */ ---text-xl: 1.25rem; /* 20px */ - -/* Line heights */ ---line-height-tight: 1.2; /* Headings */ ---line-height-relaxed: 1.8; /* Body text */ -``` - -**Tailwind classes:** -- `text-xs` β€” Metadata, labels -- `text-sm` β€” Secondary text, descriptions -- `text-base` β€” Body text (default) -- `text-lg` β€” Input fields, chat messages -- `text-xl` β€” Headings, titles - ---- - -### Spacing Scale (blijven hetzelfde) - -```css ---space-1: 0.25rem; /* 4px */ ---space-2: 0.5rem; /* 8px */ ---space-3: 0.75rem; /* 12px */ ---space-4: 1rem; /* 16px */ ---space-6: 1.5rem; /* 24px */ ---space-8: 2rem; /* 32px */ ---space-12: 3rem; /* 48px */ ---space-16: 4rem; /* 64px */ -``` - -**Tailwind classes:** -- `p-2` / `m-2` β€” 8px padding/margin -- `p-4` / `m-4` β€” 16px (most common) -- `p-6` / `m-6` β€” 24px (cards, blocks) -- `gap-4` β€” 16px gap in flex/grid - ---- - -### 🎨 Design Token Usage in v3.0 - -#### Chat Panel -- Background: `bg-white` (`--color-surface`) -- Border right: `border-r border-slate-200` (`--color-border`) -- Width: `w-[40%]` (desktop), `w-full` (mobile) - -#### Chat Messages -- User: `bg-amber-50 border-amber-200` (NEW) -- Assistant: `bg-slate-100 border-slate-300` (NEW) -- Padding: `p-3` (12px) of `p-4` (16px) -- Border radius: `rounded-2xl` met accent `rounded-tr-sm` (user) of `rounded-tl-sm` (assistant) - -#### Artifact Area -- Background: `bg-slate-50` (`--color-surface-secondary`) -- Width: `w-[60%]` (desktop), `w-full` (mobile) - -#### Artifact Container (bestaande blocks blijven ongewijzigd) -- Background: `bg-white` -- Border: `border border-slate-200` -- Border radius: `rounded-lg` -- Shadow: `shadow-lg` -- Padding: `p-6` - ---- - -## E0.S2 β€” Component Inventory - -🎯 **Doel:** Lijst van alle blocks die herbruikbaar zijn vs. nieuwe componenten voor v3.0. - -### βœ… Bestaande Components (blijven ongewijzigd) - -Deze components werken in v3.0 zonder wijzigingen (alleen de wrapper wijzigt): - -| Component | Locatie | Functie | Wijzigingen v3.0 | -|-----------|---------|---------|------------------| -| **ContextBar** | `components/swift/command-center/context-bar.tsx` | Dienst, patient selector, user info | βœ… Geen wijzigingen | -| **OfflineBanner** | `components/swift/command-center/offline-banner.tsx` | Offline detectie en banner | βœ… Geen wijzigingen | -| **DagnotatieBlock** | `components/swift/blocks/dagnotitie-block.tsx` | Dagnotitie maken | βœ… Geen wijzigingen | -| **ZoekenBlock** | `components/swift/blocks/zoeken-block.tsx` | Patient zoeken | βœ… Geen wijzigingen | -| **OverdrachtBlock** | `components/swift/blocks/overdracht-block.tsx` | Dienst overdracht | ⚠️ Uitbreiding: AI-filtering (E5.S1) | -| **PatientContextCard** | `components/swift/blocks/patient-context-card.tsx` | Patient overzicht | βœ… Geen wijzigingen | -| **FallbackPicker** | `components/swift/blocks/fallback-picker.tsx` | Intent fallback | βœ… Geen wijzigingen | -| **BlockContainer** | `components/swift/blocks/block-container.tsx` | Generic wrapper voor blocks | βœ… Geen wijzigingen | - -**Total:** 8 components blijven werken zoals ze zijn (behalve OverdrachtBlock met uitbreiding in E5). - ---- - -### πŸ”„ Components die WIJZIGEN - -| Component | Locatie | v2.1 Functie | v3.0 Wijziging | -|-----------|---------|--------------|----------------| -| **CommandCenter** | `components/swift/command-center/command-center.tsx` | 4-zone layout (context, canvas, recent, input) | β†’ Split-screen layout (40/60) | -| **CommandInput** | `components/swift/command-center/command-input.tsx` | Single-line command input | β†’ Multi-line chat input (onderaan chat panel) | -| **CanvasArea** | `components/swift/command-center/canvas-area.tsx` | Centered block display | β†’ Vervangen door ArtifactArea (rechts, 60%) | -| **RecentStrip** | `components/swift/command-center/recent-strip.tsx` | Recent actions strip | β†’ Verwijderen of integreren in chat history | - -**Total:** 4 components wijzigen. - ---- - -### πŸ†• Nieuwe Components voor v3.0 - -Deze components moeten worden gebouwd: - -| Component | Locatie | Functie | Epic | Story Points | -|-----------|---------|---------|------|--------------| -| **ChatPanel** | `components/swift/chat/chat-panel.tsx` | Scrollable message list, auto-scroll | E2 | 5 SP | -| **ChatMessage** | `components/swift/chat/chat-message.tsx` | Message bubble (user/assistant/system/error) | E2 | 3 SP | -| **ChatInput** | `components/swift/chat/chat-input.tsx` | Multi-line input onderaan chat | E2 | 2 SP | -| **StreamingIndicator** | `components/swift/chat/streaming-indicator.tsx` | Pulsating dots tijdens AI response | E2 | 1 SP | -| **ChatActionLink** | `components/swift/chat/chat-action-link.tsx` | Klikbare action links in chat | E3 | 1 SP | -| **ArtifactArea** | `components/swift/artifacts/artifact-area.tsx` | Right-side area (60%) voor blocks | E1 | 2 SP | -| **ArtifactContainer** | `components/swift/artifacts/artifact-container.tsx` | Wrapper met tabs (max 3 artifacts) | E4 | 5 SP | -| **ArtifactTab** | `components/swift/artifacts/artifact-tab.tsx` | Tab component voor artifact switching | E4 | 2 SP | -| **ArtifactPlaceholder** | `components/swift/artifacts/artifact-placeholder.tsx` | Placeholder: "Artifacts verschijnen hier" | E4 | 1 SP | -| **LinkedEvidence** | `components/swift/shared/linked-evidence.tsx` | Bronnotitie links met hover preview | E5 | 3 SP | - -**Total:** 10 nieuwe components, **25 Story Points** - ---- - -### πŸ“Š Component Architecture (v3.0) - -``` -components/swift/ -β”œβ”€β”€ command-center/ -β”‚ β”œβ”€β”€ command-center.tsx πŸ”„ WIJZIGT - Split-screen layout -β”‚ β”œβ”€β”€ context-bar.tsx βœ… BLIJFT -β”‚ └── offline-banner.tsx βœ… BLIJFT -β”‚ -β”œβ”€β”€ chat/ πŸ†• NIEUW -β”‚ β”œβ”€β”€ chat-panel.tsx -β”‚ β”œβ”€β”€ chat-message.tsx -β”‚ β”œβ”€β”€ chat-input.tsx -β”‚ β”œβ”€β”€ streaming-indicator.tsx -β”‚ └── chat-action-link.tsx -β”‚ -β”œβ”€β”€ artifacts/ πŸ†• NIEUW -β”‚ β”œβ”€β”€ artifact-area.tsx -β”‚ β”œβ”€β”€ artifact-container.tsx -β”‚ β”œβ”€β”€ artifact-tab.tsx -β”‚ └── artifact-placeholder.tsx -β”‚ -β”œβ”€β”€ blocks/ βœ… BLIJVEN -β”‚ β”œβ”€β”€ dagnotitie-block.tsx -β”‚ β”œβ”€β”€ zoeken-block.tsx -β”‚ β”œβ”€β”€ overdracht-block.tsx ⚠️ + AI-filtering (E5) -β”‚ β”œβ”€β”€ patient-context-card.tsx -β”‚ β”œβ”€β”€ fallback-picker.tsx -β”‚ └── block-container.tsx -β”‚ -└── shared/ πŸ†• NIEUW (partial) - └── linked-evidence.tsx -``` - ---- - -### 🎯 Component Reuse Strategy - -**Maximize reuse:** -1. βœ… **Alle blocks blijven werken** β€” Geen refactor nodig -2. βœ… **Context Bar blijft** β€” Shift colors, patient selector unchanged -3. βœ… **Offline Banner blijft** β€” Error handling unchanged -4. βœ… **Block styling blijft** β€” Category colors, sizes, shadows unchanged - -**Minimize new code:** -1. πŸ†• **Chat components** β€” 10 nieuwe components, maar simpel (message bubbles, input) -2. πŸ†• **Artifact wrapper** β€” 4 components voor tab management -3. πŸ”„ **Layout refactor** β€” Alleen CommandCenter wijzigt naar split-screen - -**Total new code estimate:** -- **New components:** ~600 LOC (10 components Γ— ~60 LOC average) -- **Modified components:** ~200 LOC (4 components Γ— ~50 LOC changes) -- **Total:** ~800 LOC (reasonable scope) - ---- - -### βœ… E0.S1 & E0.S2 Complete - -**E0.S1 - Design Tokens Audit:** βœ… Compleet -- Alle kleuren gedocumenteerd -- Chat message colors toegevoegd (NEW) -- Spacing, shadows, typography verified -- Verpleegkundig category colors verified -- Shift colors verified - -**E0.S2 - Component Inventory:** βœ… Compleet -- 8 bestaande components blijven werken -- 4 components wijzigen (layout refactor) -- 10 nieuwe components nodig (~25 SP) -- Architecture diagram gemaakt - -**Next:** E0.S3 - Medical scribe system prompt - ---- - -## Referenties - -- `app/globals.css` β€” Design tokens definitie -- `tailwind.config.ts` β€” Tailwind color palette -- `lib/types/report.ts` β€” Category config -- `components/swift/command-center/context-bar.tsx` β€” Shift config -- `components/swift/blocks/` β€” Bestaande blocks diff --git a/docs/swift/e0-medical-scribe-system-prompt.md b/docs/swift/e0-medical-scribe-system-prompt.md deleted file mode 100644 index 64c742d..0000000 --- a/docs/swift/e0-medical-scribe-system-prompt.md +++ /dev/null @@ -1,518 +0,0 @@ -# E0.S3 β€” Swift Assistent System Prompt - -**Datum:** 27-12-2024 -**Versie:** v1.0 -**Auteur:** AI Assistant -**Status:** βœ… Ready for testing - ---- - -## System Prompt v1.0 - -Dit is de eerste versie van de Swift Assistent system prompt voor `/api/swift/chat`. - -### Volledige Prompt - -```markdown -Je bent Swift Assistent, een medische assistent voor Swift EPD, een Nederlands EPD-systeem voor GGZ-instellingen. - -## Je rol - -Je helpt zorgmedewerkers (verpleegkundigen, psychiaters, behandelaren) met documentatie en administratie tijdens hun dagelijkse werk. - -### Kernkwaliteiten: -- **Natuurlijk Nederlands**: Je spreekt vloeiend, informeel maar professioneel Nederlands -- **Begrijpend**: Je begrijpt context en kan doorvragen -- **EfficiΓ«nt**: Je helpt snel zonder onnodige uitleg -- **Betrouwbaar**: Je maakt geen aannames, maar vraagt bij twijfel - -### Tone of voice: -- Vriendelijk en behulpzaam (zoals een collega) -- Professioneel en respectvol -- Kort en to-the-point (geen lange uitleg) -- Empatisch voor werkdruk zorgmedewerkers - -## Wat je DOET - -### 1. Intents herkennen - -Je herkent de volgende gebruikersintenties en voert acties uit: - -**P1 Intents (kritiek, hoogfrequent):** - -- **dagnotitie** β€” Verpleegkundige wil snelle notitie maken - - Triggers: "notitie [patient]", "medicatie gegeven", "[patient] heeft...", "incident bij [patient]" - - Entities: patient (naam), category (medicatie/adl/gedrag/incident/observatie), content (tekst) - -- **zoeken** β€” Gebruiker zoekt patiΓ«nt - - Triggers: "zoek [naam]", "wie is [naam]", "vind [naam]", "patient [naam]" - - Entities: query (zoekterm) - -- **patient_info** β€” Gebruiker wil patiΓ«nt overzicht - - Triggers: "dossier [patient]", "info [patient]", "open [patient]", "toon [patient]" - - Entities: patient (naam of ID) - -- **overdracht** β€” Dienst overdracht maken - - Triggers: "overdracht", "dienst overdracht", "maak overdracht", "wat moet ik weten" - - Entities: shift (optioneel: ochtend/middag/avond/nacht) - -**P2 Intents (belangrijk, middenfrequent):** - -- **rapportage** β€” Behandelrapportage schrijven - - Triggers: "rapportage", "gesprek gehad", "behandelgesprek", "evaluatie" - - Entities: patient (naam), type (optioneel: gesprek/evaluatie/consult) - -- **agenda** β€” Afspraken bekijken - - Triggers: "agenda", "afspraken", "wie zie ik vandaag" - - Entities: date (optioneel: vandaag/morgen/datum) - -### 2. Verduidelijkingsvragen stellen - -Als je twijfelt over de intent of belangrijke informatie mist: - -**Vraag om verduidelijking:** -- "Met welke patiΓ«nt had je het gesprek?" (patient ontbreekt) -- "Wil je een notitie maken of de overdracht bekijken?" (intent onduidelijk) -- "Bedoel je Jan de Vries of Jan Bakker?" (meerdere matches) - -**Bevestig interpretatie:** -- "Ik maak een dagnotitie voor Jan de Vries. Categorie: Medicatie. Klopt dat?" -- "Je wilt de overdracht voor de ochtend. Correct?" - -### 3. Action objects genereren - -Wanneer je een intent herkent EN voldoende informatie hebt, genereer je een JSON action object: - -**Format:** -```json -{ - "type": "action", - "intent": "dagnotitie", - "entities": { - "patient": "Jan de Vries", - "patientId": "uuid-here", - "category": "medicatie", - "content": "Medicatie uitgereikt volgens schema" - }, - "confidence": 0.95, - "artifact": { - "type": "DagnotatieBlock", - "prefill": { - "patientName": "Jan de Vries", - "patientId": "uuid-here", - "category": "medicatie", - "content": "Medicatie uitgereikt volgens schema" - } - } -} -``` - -**Confidence thresholds:** -- `>0.9` β†’ Open artifact direct met prefill -- `0.7-0.9` β†’ Open artifact + bevestigingsvraag -- `0.5-0.7` β†’ Verduidelijkingsvraag, geen artifact -- `<0.5` β†’ "Ik begrijp het niet helemaal. Kun je het anders zeggen?" - -### 4. Follow-up conversatie - -Gebruikers kunnen doorvragen of aanvullen: - -**Voorbeelden:** -``` -User: "Ik heb medicatie gegeven aan Jan" -AI: "Ik maak een dagnotitie voor Jan de Vries. Categorie: Medicatie. Wil je nog iets toevoegen?" -[Artifact opent: DagnotatieBlock] - -User: "Voeg toe: hij voelt zich beter vandaag" -AI: "Toegevoegd aan de notitie." -[Artifact update: content += " Hij voelt zich beter vandaag"] - -User: "Opslaan" -AI: "Notitie opgeslagen voor Jan de Vries." -[Artifact sluit, toast notification] -``` - -## Wat je NIET doet - -❌ **Geen medisch advies geven** -- Je bent assistent voor documentatie, geen diagnostische tool -- Bij medische vragen: "Daarvoor moet je de behandelaar raadplegen." - -❌ **Geen aannames over patiΓ«nten** -- Als patient naam onduidelijk is β†’ vraag om verduidelijking -- Als meerdere patiΓ«nten matchen β†’ vraag welke bedoeld wordt - -❌ **Geen lange uitleg** -- Houd antwoorden kort en to-the-point -- Geen "Ik ga nu..." of "Laat me even kijken..." (doe gewoon) - -❌ **Geen ongevraagde acties** -- Maak geen notities zonder expliciete opdracht -- Geen notities automatisch opslaan (gebruiker beslist) - -## Context die beschikbaar is - -Je hebt toegang tot de volgende context: - -```json -{ - "activePatient": { - "id": "uuid", - "name": "Jan de Vries", - "age": 59, - "room": "12B" - }, - "shift": "ochtend", - "user": { - "role": "verpleegkundige", - "name": "Sarah Verhoeven" - }, - "recentActions": [ - { - "type": "dagnotitie", - "patient": "Jan de Vries", - "timestamp": "2024-12-27T09:15:00Z" - } - ] -} -``` - -**Gebruik context slim:** -- Als `activePatient` bekend is, gebruik die als default -- Bij "maak notitie" zonder patient naam β†’ gebruik activePatient -- Bij "wat heb ik net gedaan" β†’ verwijs naar recentActions - -## Voorbeelden (Request β†’ Response) - -### Voorbeeld 1: Dagnotitie (Happy Path) - -**User:** -``` -Medicatie gegeven aan Jan -``` - -**AI Response:** -``` -Ik maak een dagnotitie voor Jan de Vries. Categorie: Medicatie. Wil je nog iets toevoegen? - -{ - "type": "action", - "intent": "dagnotitie", - "entities": { - "patient": "Jan de Vries", - "patientId": "abc-123", - "category": "medicatie", - "content": "Medicatie gegeven" - }, - "confidence": 0.95, - "artifact": { - "type": "DagnotatieBlock", - "prefill": { - "patientName": "Jan de Vries", - "patientId": "abc-123", - "category": "medicatie", - "content": "Medicatie gegeven" - } - } -} -``` - ---- - -### Voorbeeld 2: Verduidelijkingsvraag - -**User:** -``` -Ik heb een gesprek gehad -``` - -**AI Response:** -``` -Met welke patiΓ«nt had je het gesprek? -``` - -**User:** -``` -Jan de Vries -``` - -**AI Response:** -``` -Ik maak een rapportage voor Jan de Vries. Wat wil je vastleggen? - -{ - "type": "action", - "intent": "rapportage", - "entities": { - "patient": "Jan de Vries", - "patientId": "abc-123" - }, - "confidence": 0.85, - "artifact": { - "type": "RapportageBlock", - "prefill": { - "patientName": "Jan de Vries", - "patientId": "abc-123" - } - } -} -``` - ---- - -### Voorbeeld 3: PatiΓ«nt zoeken - -**User:** -``` -Wie is Marie van den Berg? -``` - -**AI Response:** -``` -Ik zoek Marie van den Berg voor je. - -{ - "type": "action", - "intent": "zoeken", - "entities": { - "query": "Marie van den Berg" - }, - "confidence": 0.98, - "artifact": { - "type": "ZoekenBlock", - "prefill": { - "query": "Marie van den Berg" - } - } -} -``` - ---- - -### Voorbeeld 4: Overdracht - -**User:** -``` -Maak overdracht voor deze dienst -``` - -**AI Response:** -``` -Ik maak de overdracht voor de ochtenddienst (07:00-15:00). - -{ - "type": "action", - "intent": "overdracht", - "entities": { - "shift": "ochtend" - }, - "confidence": 0.92, - "artifact": { - "type": "OverdrachtBlock", - "prefill": { - "shift": "ochtend" - } - } -} -``` - ---- - -### Voorbeeld 5: Follow-up (context behouden) - -**User:** -``` -Notitie voor Jan: bloeddruk gemeten -``` - -**AI Response:** -``` -Ik maak een dagnotitie voor Jan de Vries. Categorie: Observatie. - -{ - "type": "action", - "intent": "dagnotitie", - "entities": { - "patient": "Jan de Vries", - "patientId": "abc-123", - "category": "observatie", - "content": "Bloeddruk gemeten" - }, - "confidence": 0.9, - "artifact": { - "type": "DagnotatieBlock", - "prefill": { - "patientName": "Jan de Vries", - "patientId": "abc-123", - "category": "observatie", - "content": "Bloeddruk gemeten" - } - } -} -``` - -**User:** -``` -Voeg toe: 135 over 85 -``` - -**AI Response:** -``` -Toegevoegd aan de notitie. - -{ - "type": "update", - "target": "activeArtifact", - "update": { - "content": "Bloeddruk gemeten: 135 over 85" - } -} -``` - ---- - -### Voorbeeld 6: Onduidelijke intent (laag confidence) - -**User:** -``` -Jan -``` - -**AI Response:** -``` -Wat wil je doen met Jan de Vries? Je kunt bijvoorbeeld: -- Een notitie maken -- Het dossier openen -- Een rapportage schrijven -``` - ---- - -### Voorbeeld 7: Meerdere patiΓ«nten match - -**User:** -``` -Zoek Jan -``` - -**AI Response (als er meerdere Jannen zijn):** -``` -Ik vind meerdere patiΓ«nten met de naam Jan: -- Jan de Vries (59 jr, kamer 12B) -- Jan Bakker (45 jr, kamer 8A) -- Jantine Smit (33 jr, kamer 3C) - -Wie bedoel je? -``` - ---- - -## Intent Mapping Table - -| User Input (NL) | Intent | Confidence | Artifact | -|-----------------|--------|------------|----------| -| "Medicatie gegeven aan Jan" | dagnotitie | 0.95 | DagnotatieBlock | -| "Notitie jan medicatie" | dagnotitie | 0.92 | DagnotatieBlock | -| "Incident bij Marie" | dagnotitie | 0.90 | DagnotatieBlock (category: incident) | -| "Zoek Jan de Vries" | zoeken | 0.98 | ZoekenBlock | -| "Wie is Marie" | zoeken | 0.95 | ZoekenBlock | -| "Info Jan" | patient_info | 0.90 | PatientContextCard | -| "Dossier Jan" | patient_info | 0.92 | PatientContextCard | -| "Overdracht maken" | overdracht | 0.95 | OverdrachtBlock | -| "Dienst overdracht" | overdracht | 0.93 | OverdrachtBlock | -| "Rapportage Jan" | rapportage | 0.88 | RapportageBlock | -| "Gesprek gehad met Jan" | rapportage | 0.85 | RapportageBlock | -| "Agenda vandaag" | agenda | 0.95 | AgendaBlock | -| "Wie zie ik vandaag" | agenda | 0.90 | AgendaBlock | - ---- - -## Error Handling - -### Onbekende intent - -**User:** -``` -Blablabla random tekst -``` - -**AI Response:** -``` -Ik begrijp niet helemaal wat je wilt doen. Typ "help" voor voorbeelden, of probeer: -- "Notitie maken voor [patient]" -- "Zoek [patient]" -- "Maak overdracht" -``` - -### Geen patient gevonden - -**User:** -``` -Notitie voor Henk -``` - -**AI Response (als Henk niet bestaat):** -``` -Ik kan geen patiΓ«nt vinden met de naam Henk. Wil je: -- De naam anders spellen -- Een andere patiΓ«nt zoeken -``` - -### API error tijdens artifact opening - -**AI Response:** -``` -Er ging iets mis bij het openen van de notitie. Probeer het opnieuw, of neem contact op met de helpdesk als het probleem blijft. -``` - ---- - -## Prompt Engineering Notes - -### Strengths v1.0: -βœ… Duidelijke role definition -βœ… Concrete intent examples -βœ… JSON action format gedefinieerd -βœ… Confidence thresholds -βœ… Error handling voorbeelden -βœ… Nederlandse tone of voice - -### Areas for improvement (v2.0): -⚠️ Category inference (medicatie, adl, gedrag, incident, observatie) kan beter -⚠️ Multi-turn conversation tracking (context window management) -⚠️ Edge cases: typos, dialect, afkortingen -⚠️ Ambiguity resolution (bijv. "Jan" als er 3 Jannen zijn) - -### Testing checklist: -- [ ] Happy path: dagnotitie maken -- [ ] Happy path: patient zoeken -- [ ] Happy path: overdracht maken -- [ ] Verduidelijkingsvraag bij onduidelijke intent -- [ ] Meerdere patiΓ«nten met zelfde naam -- [ ] Follow-up conversatie (context behouden) -- [ ] Error handling (unknown intent, patient not found) -- [ ] Confidence thresholds (>0.9, 0.7-0.9, <0.5) - ---- - -## Next Steps (E3.S3) - -1. Implementeer prompt in `/app/api/swift/chat/route.ts` -2. Test met Claude API (Sonnet 4.5) -3. Iterate op basis van test results -4. Document prompt versioning (v1.0, v1.1, v2.0, etc.) - ---- - -## Versiehistorie - -| Versie | Datum | Wijzigingen | -|--------|-------|-------------| -| v1.0 | 27-12-2024 | Initial prompt - Dutch Swift Assistent, intents, examples | - ---- - -## βœ… E0.S3 Complete - -**Status:** βœ… System prompt v1.0 klaar voor implementatie en testing -**Next Epic:** E1 - Foundation (Split-screen layout) diff --git a/docs/swift/fo-agenda-afspraken.md b/docs/swift/fo-agenda-afspraken.md deleted file mode 100644 index 8c301e0..0000000 --- a/docs/swift/fo-agenda-afspraken.md +++ /dev/null @@ -1,581 +0,0 @@ -# 🧩 Functioneel Ontwerp (FO) – Swift Agenda & Afspraken - -**Projectnaam:** Swift - Agenda & Afspraken Module -**Versie:** v1.0 -**Datum:** 27-12-2024 -**Auteur:** Colin Lit - ---- - -## 1. Doel en relatie met het PRD - -🎯 **Doel van dit document:** -Dit Functioneel Ontwerp beschrijft **hoe** de agenda- en afsprakenfunctionaliteit binnen Swift werkt. Swift is een conversational medical scribe interface waarin gebruikers via natuurlijke taal (Nederlands) afspraken kunnen opvragen, aanmaken, wijzigen en annuleren. Dit FO beschrijft de gebruikerservaring, UI-interacties en AI-functionaliteit. - -πŸ“˜ **Relatie met andere documenten:** -- **PRD:** Ephemeral UI visie (`nextgen-epd-prd-ephemeral-ui-epd.md`) - Conversational interface voor EPD -- **Swift FO v3.0:** `fo-swift-medical-scribe-v3.md` - Basis conversational interface architectuur -- **Klassieke Agenda:** `/app/epd/agenda` - Bestaande visuele kalender (blijft bestaan voor complexe planning) -- **Bouwplan:** `bouwplan-swift-standalone-module.md` - Development roadmap - -**Kernprincipe:** -> Gebruikers kunnen via natuurlijke taal (chat of spraak) snel afspraken beheren zonder door menu's te klikken. Voor visueel overzicht en complexe planning blijft de klassieke kalender beschikbaar. Swift is de **snelle, hands-free** interface; klassieke agenda is de **visuele planner**. - -**Toegevoegde waarde:** - -| Aspect | Klassieke Agenda | Swift Agenda | -|--------|------------------|--------------| -| **Gebruik** | Visuele weekplanning | Quick actions, queries | -| **Input** | Klikken, formulieren | Natuurlijke taal, spraak | -| **Snelheid** | ~30-60 sec voor nieuwe afspraak | ~10-15 sec via chat/voice | -| **Ideaal voor** | Weekplanning, drag-drop | Tijdens telefoongesprek, hands-free | - ---- - -## 2. Overzicht van de belangrijkste onderdelen - -🎯 **Doel:** Overzicht van de functionaliteit binnen de Swift Agenda module. - -### Hoofdonderdelen - -1. **Agenda Queries** - Afspraken opvragen ("afspraken vandaag", "wat is volgende afspraak") -2. **Quick Create** - Snel afspraak maken ("maak afspraak jan morgen 14:00") -3. **Cancel Flow** - Afspraak annuleren ("annuleer afspraak jan") -4. **Reschedule Flow** - Afspraak verzetten ("verzet 14:00 naar 15:00") -5. **AgendaBlock** - UI component toont afspraken lijst en formulieren -6. **Intent Detection** - AI herkent wat gebruiker wil doen - -### Artifact: AgendaBlock - -Het **AgendaBlock** is het centrale UI-component met 4 modes: - -| Mode | Functie | Trigger | -|------|---------|---------| -| **List View** | Toont chronologische lijst afspraken | "afspraken vandaag" | -| **Create Form** | Formulier voor nieuwe afspraak | "maak afspraak jan" | -| **Cancel View** | Confirmation dialog | "annuleer afspraak" | -| **Reschedule Form** | Datum/tijd aanpassing | "verzet afspraak" | - ---- - -## 3. User Stories - -🎯 **Doel:** Beschrijven wat gebruikers moeten kunnen doen vanuit hun perspectief. - -### Primaire User Stories (P1) - -| ID | Rol | Doel / Actie | Verwachte waarde | Prio | -|----|-----|--------------|------------------|------| -| **US-24** | Verpleegkundige | Snel overzicht afspraken vandaag | "afspraken vandaag" β†’ lijst in AgendaBlock, <3 sec | πŸ”΄ P1 | -| **US-25** | Verpleegkundige | Check volgende afspraak tijdens werk | "wat is mijn volgende afspraak?" β†’ directe info | πŸ”΄ P1 | -| **US-27** | Verpleegkundige | Snelle afspraak tijdens telefoongesprek | "maak afspraak jan morgen 14:00" β†’ prefilled form, <15 sec | πŸ”΄ P1 | -| **US-28** | Verpleegkundige | Context-aware planning | "maak afspraak met deze patiΓ«nt" β†’ gebruikt actieve patiΓ«nt | πŸ”΄ P1 | -| **US-29** | Verpleegkundige | Voice input tijdens consult | Hands-free afspraak maken via spraak | πŸ”΄ P1 | -| **US-30** | Verpleegkundige | Annuleren via chat | "annuleer afspraak jan" β†’ confirmation β†’ done | πŸ”΄ P1 | -| **US-31** | Verpleegkundige | Snel verzetten | "verzet 14:00 naar 15:00" β†’ tijd update | πŸ”΄ P1 | - -### Secundaire User Stories (P2) - -| ID | Rol | Doel / Actie | Verwachte waarde | Prio | -|----|-----|--------------|------------------|------| -| **US-26** | Verpleegkundige | Weekoverzicht bekijken | "agenda deze week" β†’ gefilterde lijst | 🟑 P2 | -| **US-32** | Verpleegkundige | Disambiguation bij meerdere matches | Systeem vraagt "Welke Jan?" β†’ lijst opties | 🟑 P2 | - ---- - -## 4. Functionele werking per onderdeel - -🎯 **Doel:** Per hoofdonderdeel beschrijven wat de gebruiker kan doen en wat het systeem doet. - -### 4.1 Agenda Query (Afspraken opvragen) - -**Wat doet de gebruiker:** -- Typt of spreekt: "afspraken vandaag", "wat is mijn volgende afspraak", "agenda morgen" - -**Wat doet het systeem:** -1. **Intent detection:** Herkent dat gebruiker afspraken wil opvragen -2. **Datum parsing:** Vertaalt "vandaag", "morgen", "deze week" naar datumbereik -3. **Data ophalen:** Haalt afspraken op uit database -4. **AI response:** Chat toont samenvatting: "Je hebt vandaag 3 afspraken..." -5. **AgendaBlock opent:** Rechts verschijnt lijst met afspraken - -**AgendaBlock List View bevat:** -- Header met datumbereik ("Afspraken Vandaag - 27 december") -- Per afspraak: tijd, patiΓ«nt (klikbaar), type badge, locatie -- Actions per afspraak: [Details] [Annuleren] -- Footer: Link naar volledige klassieke agenda - -**States:** -- **Loading:** Spinner tijdens data fetch -- **Lijst met afspraken:** Chronologisch geordend -- **Empty state:** "Geen afspraken gevonden voor [datum]" + knop "Maak nieuwe afspraak" -- **Error:** "Fout bij ophalen afspraken" + link naar klassieke agenda - -**Voorbeeld interactie:** -``` -User: "afspraken vandaag" - ↓ -AI: "Je hebt vandaag 3 afspraken: - - 09:00 Intake Jan de Vries - - 11:30 Behandeling Marie Jansen - - 14:00 Vervolggesprek Piet Bakker" - ↓ -[AgendaBlock opens rechts met lijst van 3 afspraken] -``` - ---- - -### 4.2 Quick Create (Afspraak maken) - -**Wat doet de gebruiker:** -- Typt: "maak afspraak jan morgen 14:00" -- Of spreekt via voice input (spatie-knop) - -**Wat doet het systeem:** -1. **Intent detection:** Herkent 'create_appointment' intent -2. **Entity extraction:** - - Patient: "jan" (fuzzy search in database) - - Datum: "morgen" β†’ parses naar 28-12-2024 - - Tijd: "14:00" - - Type: default "behandeling" (kan gespecificeerd worden: "maak intake...") -3. **AI response:** "Ik maak een afspraak voor Jan de Vries op 28 december om 14:00." -4. **AgendaBlock opent:** Create form met pre-filled velden -5. **Gebruiker bevestigt of past aan** -6. **Opslaan:** Server action β†’ database β†’ toast "Afspraak aangemaakt!" - -**AgendaBlock Create Form bevat:** -- **PatiΓ«nt:** Autocomplete dropdown (pre-filled "Jan de Vries") -- **Datum:** Date picker (pre-filled: 28-12-2024) -- **Tijd:** Time picker (pre-filled: 14:00) -- **Type:** Radio buttons (Intake, Behandeling, Vervolg, Telefonisch, Crisis, etc.) -- **Locatie:** Radio buttons (Praktijk, Online, Thuis) -- **Notities:** Optionele textarea -- **Conflict warning:** "⚠️ Je hebt al een afspraak om 14:00 met Marie" (indien van toepassing) -- **Actions:** [Annuleren] [βœ“ Afspraak maken] - -**Form validatie:** -- PatiΓ«nt is verplicht -- Datum kan niet in het verleden -- Tijd moet binnen 07:00-20:00 - -**Voorbeeld interactie (voice):** -``` -User: [Drukt spatie] "maak intake met Jan de Vries morgen 14:00" - ↓ -[Deepgram transcribeert live] - ↓ -AI: "Ik maak een intake-afspraak voor Jan de Vries op 28 december om 14:00." - ↓ -[AgendaBlock create form opent met prefill] - ↓ -User: [Klikt "Afspraak maken"] - ↓ -Toast: "βœ“ Afspraak aangemaakt!" -Chat: "Afspraak ingepland voor Jan de Vries op 28 december om 14:00." -``` - -**Edge cases:** -- **PatiΓ«nt niet gevonden:** "Ik vond geen patiΓ«nt met de naam 'jan'. Bedoel je Jan de Vries of Jan Bakker?" (disambiguation) -- **Meerdere Jan's:** Toont lijst met opties in AgendaBlock -- **Tijd onduidelijk:** "Hoe laat wil je de afspraak plannen?" -- **Incomplete info:** "maak afspraak" β†’ vraagt eerst om patiΓ«nt, dan datum/tijd - ---- - -### 4.3 Cancel Flow (Afspraak annuleren) - -**Wat doet de gebruiker:** -- Typt: "annuleer afspraak jan" of "annuleer de 14:00 afspraak" - -**Wat doet het systeem:** -1. **Intent detection:** Herkent 'cancel_appointment' -2. **Search matching appointments:** - - Op patiΓ«ntnaam: zoekt "jan" - - Op tijd: zoekt afspraak om 14:00 vandaag -3. **Disambiguation (indien meerdere):** - - Toont lijst van matching afspraken in AgendaBlock - - Gebruiker selecteert welke -4. **Confirmation dialog:** - - Toont details van geselecteerde afspraak - - Waarschuwing: "Deze actie kan niet ongedaan worden gemaakt" -5. **Bevestigen:** Status β†’ 'cancelled', toast + chat confirmation - -**AgendaBlock Cancel View:** - -**Single Match:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ❌ Afspraak Annuleren [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Wil je deze afspraak annuleren? β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 28-12-2024 14:00 - 15:00 β”‚ β”‚ -β”‚ β”‚ Jan de Vries - Intake β”‚ β”‚ -β”‚ β”‚ Praktijk β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ ⚠️ Actie kan niet ongedaan gemaakt β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [Terug] [βœ“ Annuleren] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Multiple Matches (Disambiguation):** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ❌ Afspraak Annuleren [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Welke afspraak wil je annuleren? β”‚ -β”‚ β”‚ -β”‚ β—‹ 28-12 09:00 - Jan de Vries (Intake) β”‚ -β”‚ β—‹ 28-12 14:00 - Jan de Vries (Vervolg) β”‚ -β”‚ β—‹ 03-01 11:00 - Jan de Vries (Behndl) β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [Annuleren] [Volgende β†’] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Voorbeeld interactie:** -``` -User: "annuleer afspraak jan" - ↓ -[Systeem vindt 3 afspraken met "jan"] - ↓ -AI: "Je hebt 3 afspraken met Jan. Welke wil je annuleren?" - ↓ -[AgendaBlock toont disambiguation list] - ↓ -User: [Selecteert 14:00 afspraak] - ↓ -[Confirmation dialog] - ↓ -User: [Klikt "Annuleren"] - ↓ -Toast: "Afspraak geannuleerd" -Chat: "Afspraak met Jan de Vries op 28 december om 14:00 is geannuleerd." -``` - ---- - -### 4.4 Reschedule Flow (Afspraak verzetten) - -**Wat doet de gebruiker:** -- Typt: "verzet 14:00 naar 15:00" of "verzet jan naar dinsdag" - -**Wat doet het systeem:** -1. **Intent detection:** Herkent 'reschedule_appointment' -2. **Parse old & new time:** - - Oude afspraak: "14:00" vandaag - - Nieuwe tijd: "15:00" -3. **Find appointment:** Zoekt matching afspraak -4. **AgendaBlock opent:** Edit form -5. **Conflict check:** Controleert of nieuwe tijd vrij is -6. **Bevestigen:** Update afspraak β†’ toast + chat - -**AgendaBlock Reschedule Form:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ”„ Afspraak Verzetten [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Afspraak β”‚ -β”‚ Jan de Vries - Intake β”‚ -β”‚ β”‚ -β”‚ Huidige tijd β”‚ -β”‚ 28-12-2024 14:00 - 15:00 β”‚ -β”‚ (strikethrough) β”‚ -β”‚ β”‚ -β”‚ Nieuwe datum/tijd * β”‚ -β”‚ [28-12-2024 β–Ό] [15:00 β–Ό] β”‚ -β”‚ β”‚ -β”‚ βœ… Geen conflicten gevonden β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [Annuleren] [βœ“ Verzetten] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Voorbeeld interactie:** -``` -User: "verzet de 14:00 naar 15:00" - ↓ -AI: "Ik verzet je afspraak van 14:00 met Jan naar 15:00." - ↓ -[AgendaBlock reschedule form opent] - ↓ -User: [Bevestigt of past aan] - ↓ -User: [Klikt "Verzetten"] - ↓ -Toast: "Afspraak verzet naar 15:00" -Chat: "Afspraak verzet naar 15:00." -``` - ---- - -### 4.5 AgendaBlock States & Lifecycle - -**Artifact Lifecycle:** -1. **Closed (default):** Geen artifact zichtbaar -2. **Opening:** Slide-in animation (200ms from right) -3. **Active:** Gebruiker kan interacteren -4. **Submitting:** Form disabled, spinner op submit button -5. **Success:** Toast + chat confirmation β†’ artifact sluit (of blijft voor volgende) -6. **Error:** Error message in artifact, re-enable form - -**Max artifacts:** 3 tegelijk (tabs bovenaan bij meerdere) -- Bij 4e artifact: oudste sluit automatisch - -**Keyboard shortcuts:** -- `⌘K` / `Ctrl+K` - Focus chat input -- `Escape` - Sluit artifact -- `Enter` - Submit form (in form fields) - ---- - -## 5. UI-overzicht (visuele structuur) - -🎯 **Doel:** Inzicht geven in de globale schermopbouw. - -### Split-Screen Layout (Command Center) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Context Bar: πŸ• Ochtend | 8 ptn Jan de Vries β–Ό πŸ‘€ SV β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ β”‚ -β”‚ CHAT PANEL (40%) β”‚ ARTIFACT AREA (60%) β”‚ -β”‚ β”‚ β”‚ -β”‚ πŸ‘€ "afspraken vandaag" β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ πŸ“… Afspraken Vandaag β”‚ β”‚ -β”‚ πŸ€– Je hebt vandaag 3 β”‚ β”‚ β”‚ β”‚ -β”‚ afspraken: β”‚ β”‚ 09:00 - Intake β”‚ β”‚ -β”‚ - 09:00 Intake Jan β”‚ β”‚ Jan de Vries β”‚ β”‚ -β”‚ - 11:30 Behandeling β”‚ β”‚ πŸ“ Praktijk β”‚ β”‚ -β”‚ - 14:00 Vervolg β”‚ β”‚ [Details] [Annuleren] β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ πŸ‘€ "maak afspraak jan β”‚ β”‚ 11:30 - Behandeling β”‚ β”‚ -β”‚ morgen 14:00" β”‚ β”‚ Marie Jansen β”‚ β”‚ -β”‚ β”‚ β”‚ 🌐 Online β”‚ β”‚ -β”‚ πŸ€– Ik maak een afspraak β”‚ β”‚ [Details] [Annuleren] β”‚ β”‚ -β”‚ voor Jan de Vries... β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ 14:00 - Vervolg β”‚ β”‚ -β”‚ [AgendaBlock opent β†’] β”‚ β”‚ Piet Bakker β”‚ β”‚ -β”‚ β”‚ β”‚ πŸ“ Praktijk β”‚ β”‚ -β”‚ β”‚ β”‚ [Details] [Annuleren] β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ [πŸ“… Open volledige β”‚ β”‚ -β”‚ β”‚ β”‚ agenda β†’] β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ -β”‚ πŸ’¬ Typ of spreek... 🎀 β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### AgendaBlock Modes (UI varianten) - -**Mode 1: List View** -- Header: Datum range + close button -- Body: Scrollable lijst van appointment cards -- Footer: Link naar klassieke agenda - -**Mode 2: Create Form** -- Header: "Nieuwe Afspraak" + close button -- Body: Form velden (patient, datum, tijd, type, locatie, notities) -- Footer: [Annuleren] [βœ“ Afspraak maken] - -**Mode 3: Cancel View** -- Header: "Afspraak Annuleren" + close button -- Body: Appointment details + warning message -- Footer: [Terug] [βœ“ Annuleren] - -**Mode 4: Reschedule Form** -- Header: "Afspraak Verzetten" + close button -- Body: Huidige tijd (readonly) + nieuwe tijd (editable) -- Footer: [Annuleren] [βœ“ Verzetten] - -### Design Tokens - -**Colors:** -- Primary: Teal-700 (#0F766E) -- User message: Amber-50 bg, amber-200 border -- AI message: Slate-100 bg, slate-300 border -- Appointment types: Blauw (intake), groen (behandeling), rood (crisis) - -**Spacing:** -- Context bar: h-12 (48px) -- Chat/artifact gap: 16px -- Card spacing: space-y-4 - -**Typography:** -- Chat messages: text-sm -- Headers: text-base font-medium - ---- - -## 6. Interacties met AI (functionele beschrijving) - -🎯 **Doel:** Uitleggen waar AI in de flow voorkomt en wat de gebruiker ziet. - -### AI-functies - -| Locatie | AI-actie | Trigger | Input | Output | -|---------|----------|---------|-------|--------| -| **Chat Input** | Intent detection | User message | "afspraken vandaag" | Intent: 'agenda_query', confidence: 1.0 | -| **Chat Input** | Entity extraction | User message | "maak afspraak jan morgen 14:00" | Patient: "jan", date: tomorrow, time: "14:00" | -| **Chat Input** | Verduidelijkingsvraag | Incomplete info | "maak afspraak" | "Met welke patiΓ«nt wil je afspreken?" | -| **Chat Panel** | Streaming response | Intent detected | β€” | "Je hebt vandaag 3 afspraken..." (typed effect) | -| **Patient Search** | Fuzzy matching | "jan" input | Database query | Matches: "Jan de Vries", "Jan Bakker" | -| **Date Parser** | Natural language parsing | "morgen", "volgende week dinsdag" | Date string | ISO date: 2024-12-28 | - -### AI Intent Detection (Two-Tier) - -**Tier 1: Local Pattern Matching (<50ms)** -- Fast regex-based matching -- Client-side execution -- Confidence >= 0.8 β†’ direct gebruiken - -Voorbeelden: -- "afspraken vandaag" β†’ Pattern: `/^afspraken?\b/i` β†’ Match! (confidence: 1.0) -- "maak afspraak" β†’ Pattern: `/^maak\s+afspraak/i` β†’ Match! (confidence: 1.0) - -**Tier 2: AI Fallback (Claude Haiku) (~400ms)** -- Voor onduidelijke/complexe input -- Server-side execution -- Triggered als local confidence <0.8 - -Voorbeelden: -- "ik wil graag een gesprek plannen" β†’ AI: intent: 'create_appointment', confidence: 0.75 -- "verzet hem naar volgende week" β†’ AI: intent: 'reschedule', confidence: 0.7 (patient onduidelijk) - -**Confidence Thresholds:** - -| Confidence | Actie | Voorbeeld | -|------------|-------|-----------| -| **>0.9** | Direct artifact openen | "afspraken vandaag" | -| **0.7-0.9** | Artifact + bevestigingsvraag | "maak afspraak jan" (tijd ontbreekt) | -| **0.5-0.7** | Verduidelijkingsvraag in chat | "maak afspraak" | -| **<0.5** | Fallback: "Ik begrijp het niet" | Gibberish input | - -### Voice Input (Deepgram) - -**Functionaliteit:** -- Live transcription tijdens spreken -- Pause detection (1.5s stilte) β†’ auto-submit -- Nederlands language model - -**User experience:** -1. User drukt spatie (of klikt mic icon) -2. Mic wordt rood πŸ”΄, waveform animatie -3. Live transcript verschijnt in input field -4. Na 1.5s stilte: auto-submit -5. Intent detection + artifact opening - -**Voorbeeld:** -``` -User: [Drukt spatie] -β†’ Mic: πŸ”΄ LIVE -β†’ User spreekt: "maak afspraak met jan morgen om twee uur" -β†’ Transcript: "maak afspraak met jan morgen om twee uur" -β†’ [1.5s pause] -β†’ Auto-submit -β†’ AI parses: "twee uur" β†’ "14:00" -β†’ AgendaBlock opent -``` - ---- - -## 7. Gebruikersrollen en rechten - -🎯 **Doel:** Beschrijven welke rollen toegang hebben tot agenda functionaliteit. - -| Rol | Toegang | Beperkingen | -|-----|---------|-------------| -| **Verpleegkundige** | Eigen afspraken maken/wijzigen/annuleren | Alleen eigen practitioner_id | -| **Behandelaar** | Eigen afspraken + caseload patiΓ«nten | Alleen eigen + team afspraken | -| **Manager** | Lezen alle afspraken | Geen create/update/delete | -| **Demo-user** | Volledige functionaliteit met fictieve data | Alleen lezen | - -**Permissies:** - -| Actie | Verpleegkundige | Behandelaar | Manager | -|-------|-----------------|-------------|---------| -| **Agenda query** (eigen) | βœ… | βœ… | βœ… | -| **Agenda query** (team) | ❌ | βœ… | βœ… | -| **Create appointment** | βœ… | βœ… | ❌ | -| **Cancel appointment** (eigen) | βœ… | βœ… | ❌ | -| **Reschedule** (eigen) | βœ… | βœ… | ❌ | - -**Database-level (RLS):** -- Filter op `practitioner_id = current_user_id` -- Voor managers: read-only view - ---- - -## 8. Bijlagen & Referenties - -🎯 **Doel:** Linken naar overige documenten. - -### Gerelateerde Documenten - -**Swift Documentatie:** -- **Swift FO v3.0:** `docs/swift/fo-swift-medical-scribe-v3.md` - Basis conversational interface -- **Swift Bouwplan:** `docs/swift/bouwplan-swift-standalone-module.md` - Development roadmap -- **Developer Guide Intent System:** `docs/swift/developer-guide-intent-system.md` - Technische details intent detection -- **Scalability Architecture:** `docs/swift/architecture-intent-scalability.md` - Schaalbaarheid optimalisaties - -**Agenda Implementatie:** -- **Klassieke Agenda:** `/app/epd/agenda` - Bestaande visuele kalender -- **Agenda Actions:** `/app/epd/agenda/actions.ts` - Server actions (wordt hergebruikt) -- **Encounters Schema:** Database schema voor afspraken - -**Design & UX:** -- **PRD Ephemeral UI:** Conversational interface visie -- **UX Research:** Chat + artifacts pattern analyse - -### Technische Specs (voor developers) - -- **Gedetailleerd FO Agenda Planning:** `docs/swift/fo-swift-agenda-planning.md` - Uitgebreide technische specificatie -- **Intent Classifier:** `lib/swift/intent-classifier.ts` - Local pattern matching -- **AI Classifier:** `lib/swift/intent-classifier-ai.ts` - Claude Haiku fallback -- **Types:** `lib/swift/types.ts` - TypeScript type definitions - -### Out of Scope (Toekomstige Versies) - -❌ **Niet in MVP:** -- Full calendar grid view (blijft in klassieke agenda) -- Drag-and-drop rescheduling -- Recurring appointments ("elke dinsdag om 10:00") -- Beschikbaarheidscheck ("wanneer ben ik vrij") -- Conflict detection & resolution -- Multi-practitioner scheduling -- SMS/email notificaties - ---- - -## Wijzigingslog - -| Versie | Datum | Wijzigingen | Auteur | -|--------|-------|-------------|--------| -| v1.0 | 27-12-2024 | Initial version - Agenda & afspraken functionaliteit in Swift volgens FO template | Colin Lit | - ---- - -**Goedkeuring:** - -- [ ] Product Owner: _________________________ -- [ ] Lead Developer: _________________________ -- [ ] UX Designer: _________________________ - -**Status:** Draft - Ter review - -**Volgende stappen:** -1. Review met stakeholders -2. UX wireframes maken op basis van dit FO -3. Technical implementation planning -4. User testing scenario's opstellen diff --git a/docs/swift/fo-swift-agenda-planning.md b/docs/swift/fo-swift-agenda-planning.md deleted file mode 100644 index a44fc85..0000000 --- a/docs/swift/fo-swift-agenda-planning.md +++ /dev/null @@ -1,1816 +0,0 @@ -# 🧩 Functioneel Ontwerp (FO) β€” Swift Agenda Planning - -**Projectnaam:** Swift β€” Agenda Planning Module -**Versie:** v1.0 -**Datum:** 27-12-2024 -**Auteur:** Colin Lit - ---- - -## 1. Doel en Context - -🎯 **Doel van dit document:** -Dit Functioneel Ontwerp beschrijft de **agenda/afspraken planning functionaliteit** binnen Swift. De gebruiker kan via natuurlijke conversatie afspraken bekijken, aanmaken, wijzigen en annuleren. Het systeem biedt een snelle, hands-free interface die de bestaande visuele kalender (`/epd/agenda`) aanvult. - -πŸ“˜ **Relatie met andere documenten:** -- **Swift FO v3.0:** `fo-swift-medical-scribe-v3.md` β€” Basis conversational interface -- **Bouwplan Swift:** `bouwplan-swift-standalone-module.md` β€” Development roadmap -- **Klassieke Agenda:** `/app/epd/agenda` β€” Bestaande visuele kalender implementatie - -**Kernprincipe:** -> De gebruiker vraagt via chat om agenda-informatie of spreekt een planningsintentie uit. Swift herkent het intent, toont relevante afspraken in een AgendaBlock artifact, en faciliteert quick actions via natuurlijke taal. Voor complexe visuele planning blijft de gebruiker de klassieke kalender gebruiken. - -**Toegevoegde Waarde:** - -| Aspect | Klassieke Agenda | Swift Agenda | -|--------|------------------|--------------| -| Gebruik | Visuele planning, overzicht | Quick actions, queries | -| Input | Klikken, formulieren | Natuurlijke taal, spraak | -| Snelheid | ~30-60 sec voor nieuwe afspraak | ~10-15 sec via conversatie | -| Context | Vereist manuele navigatie | Context-aware (actieve patiΓ«nt) | -| Ideaal voor | Weekplanning, drag-drop | Telefoon intake, snelle check | - ---- - -## 2. Scope & Prioritering - -### 2.1 In Scope (MVP) - -βœ… **P1 - Must Have:** -- Agenda queries: "afspraken vandaag", "wat is volgende afspraak" -- AgendaBlock artifact met lijst-weergave -- Quick create: "maak afspraak met Jan morgen 14:00" -- Annuleren via chat: "annuleer afspraak van Jan" -- Reschedule: "verzet 14:00 naar 15:00" - -βœ… **P2 - Should Have:** -- Disambiguation bij meerdere matches -- Voice input support voor alle commando's -- Link naar klassieke agenda voor full view -- Context-aware suggestions (recent patients) - -### 2.2 Out of Scope (Toekomstige Versies) - -❌ **Niet in MVP:** -- Full calendar grid weergave (blijft in `/epd/agenda`) -- Drag-and-drop rescheduling -- Recurring appointments ("elke dinsdag om 10:00") -- Beschikbaarheidscheck ("wanneer ben ik vrij") -- Conflict detection & resolution -- Multi-practitioner scheduling -- SMS/email notificaties - ---- - -## 3. Systeemcomponenten - -| # | Component | Beschrijving | Type | -|---|-----------|--------------|------| -| 1 | **Chat Panel** | Natuurlijke taal input voor agenda commando's | UI Zone | -| 2 | **AgendaBlock** | Artifact toont afspraken lijst en forms | Artifact | -| 3 | **Intent Engine** | Herkent agenda intents (query/create/cancel/reschedule) | Backend | -| 4 | **Encounter Actions** | Reuse bestaande server actions uit `/epd/agenda/actions.ts` | Backend | -| 5 | **Patient Search** | Fuzzy matching voor patiΓ«ntnamen | Backend | -| 6 | **Date/Time Parser** | NLP voor datum/tijd extractie uit natuurlijke taal | Backend | - ---- - -## 4. User Stories - -### 4.1 Agenda Queries - -| ID | Rol | Doel / Actie | Verwachte waarde | Prio | -|----|-----|--------------|------------------|------| -| US-24 | Verpleegkundige | Snel overzicht van afspraken vandaag | "Afspraken vandaag" β†’ lijst in AgendaBlock | πŸ”΄ P1 | -| US-25 | Verpleegkundige | Check volgende afspraak tijdens werk | "Wat is mijn volgende afspraak?" β†’ directe info | πŸ”΄ P1 | -| US-26 | Verpleegkundige | Weekoverzicht bekijken | "Agenda deze week" β†’ gefilterde lijst | 🟑 P2 | - -### 4.2 Afspraak Aanmaken - -| ID | Rol | Doel / Actie | Verwachte waarde | Prio | -|----|-----|--------------|------------------|------| -| US-27 | Verpleegkundige | Snelle afspraak tijdens telefoongesprek | "Maak intake Jan morgen 14:00" β†’ prefilled form | πŸ”΄ P1 | -| US-28 | Verpleegkundige | Context-aware planning | "Maak afspraak met deze patiΓ«nt" β†’ gebruikt active patient | πŸ”΄ P1 | -| US-29 | Verpleegkundige | Voice input tijdens consult | Hands-free afspraak maken | 🟑 P2 | - -### 4.3 Afspraak Wijzigen - -| ID | Rol | Doel / Actie | Verwachte waarde | Prio | -|----|-----|--------------|------------------|------| -| US-30 | Verpleegkundige | Annuleren via chat | "Annuleer afspraak Jan" β†’ confirmation β†’ done | πŸ”΄ P1 | -| US-31 | Verpleegkundige | Snel verzetten | "Verzet 14:00 naar 15:00" β†’ tijd update | πŸ”΄ P1 | -| US-32 | Verpleegkundige | Disambiguation bij meerdere matches | Systeem vraagt "Welke Jan?" β†’ lijst opties | 🟑 P2 | - ---- - -## 5. Intent System Integratie - -🎯 **Doel:** Beschrijven hoe de agenda intents integreren met het bestaande Swift two-tier intent systeem. - -### 5.1 Bestaande Intent Architectuur - -Swift gebruikt een **hybride two-tier classificatie systeem** voor intent detection: - -**Tier 1: Local Pattern Matching** (`lib/swift/intent-classifier.ts`) -- Fast regex-based matching -- Client-side execution -- Target: <50ms response time -- Confidence threshold: β‰₯0.8 β†’ direct gebruiken, geen AI nodig - -**Tier 2: AI Fallback** (`lib/swift/intent-classifier-ai.ts`) -- Claude Haiku API voor onduidelijke input -- Server-side execution (~200-500ms) -- Triggered wanneer local confidence <0.8 -- Entity extraction + reasoning - -**Huidige Intents (voor agenda toevoeging):** - -```typescript -type SwiftIntent = - | 'dagnotitie' // Notitie maken voor patiΓ«nt - | 'zoeken' // PatiΓ«nt zoeken - | 'overdracht' // Dienst overdracht - | 'unknown'; // Niet herkend -``` - -### 5.2 Nieuwe Intent Types - -**Na integratie:** - -```typescript -type SwiftIntent = - | 'dagnotitie' - | 'zoeken' - | 'overdracht' - | 'agenda_query' // πŸ†• Afspraken opvragen - | 'create_appointment' // πŸ†• Nieuwe afspraak - | 'cancel_appointment' // πŸ†• Afspraak annuleren - | 'reschedule_appointment'// πŸ†• Afspraak verzetten - | 'unknown'; -``` - -### 5.3 Tier 1: Local Pattern Extensions - -**Toevoegen aan `INTENT_PATTERNS` in `intent-classifier.ts`:** - -```typescript -const INTENT_PATTERNS: Record, PatternConfig[]> = { - // ... bestaande patterns (dagnotitie, zoeken, overdracht) - - // πŸ†• Agenda query patterns - agenda_query: [ - { pattern: /^afspraken?\b/i, weight: 1.0 }, - { pattern: /^agenda\b/i, weight: 1.0 }, - { pattern: /^wat\s+zijn\s+(mijn\s+)?afspraken/i, weight: 1.0 }, - { pattern: /^(wat|wanneer)\s+is\s+(mijn\s+)?volgende\s+afspraak/i, weight: 1.0 }, - { pattern: /^afspraken\s+(vandaag|morgen|deze\s+week|volgende\s+week)/i, weight: 0.95 }, - { pattern: /^(vandaag|morgen|deze\s+week)\s+afspraken/i, weight: 0.9 }, - { pattern: /^toon\s+agenda/i, weight: 0.9 }, - { pattern: /^planning\s+(vandaag|morgen|week)/i, weight: 0.85 }, - ], - - // πŸ†• Create appointment patterns - create_appointment: [ - { pattern: /^maak\s+afspraak\b/i, weight: 1.0 }, - { pattern: /^plan\s+(een\s+)?(intake|afspraak)\b/i, weight: 1.0 }, - { pattern: /^afspraak\s+(maken|plannen|inplannen)\b/i, weight: 0.95 }, - { pattern: /^nieuwe?\s+afspraak\b/i, weight: 0.95 }, - { pattern: /^(intake|behandeling|gesprek)\s+\w+\s+(morgen|vandaag|volgende)/i, weight: 0.85 }, - { pattern: /^(intake|behandeling)\s+(met\s+)?\w+/i, weight: 0.8 }, - ], - - // πŸ†• Cancel appointment patterns - cancel_appointment: [ - { pattern: /^annuleer\s+(de\s+)?afspraak/i, weight: 1.0 }, - { pattern: /^cancel\s+(de\s+)?afspraak/i, weight: 1.0 }, - { pattern: /^verwijder\s+afspraak/i, weight: 0.95 }, - { pattern: /^afspraak\s+annuleren/i, weight: 0.95 }, - { pattern: /^annuleer\s+\w+/i, weight: 0.7 }, // "annuleer jan" - ], - - // πŸ†• Reschedule appointment patterns - reschedule_appointment: [ - { pattern: /^verzet\s+(de\s+)?afspraak/i, weight: 1.0 }, - { pattern: /^verplaats\s+(de\s+)?afspraak/i, weight: 1.0 }, - { pattern: /^verschuif\s+afspraak/i, weight: 0.95 }, - { pattern: /^afspraak\s+verzetten/i, weight: 0.95 }, - { pattern: /^\d{1,2}:\d{2}\s+naar\s+\d{1,2}:\d{2}/i, weight: 0.9 }, // "14:00 naar 15:00" - { pattern: /^verzet\s+\w+\s+naar/i, weight: 0.85 }, // "verzet jan naar dinsdag" - ], -}; -``` - -**Voorbeelden van local matches:** - -| User Input | Matched Pattern | Confidence | Time | -|------------|----------------|------------|------| -| "afspraken vandaag" | `/^afspraken?\b/i` | 1.0 | ~8ms | -| "maak afspraak jan morgen 14:00" | `/^maak\s+afspraak\b/i` | 1.0 | ~10ms | -| "verzet 14:00 naar 15:00" | `/^\d{1,2}:\d{2}\s+naar/i` | 0.9 | ~12ms | -| "annuleer afspraak" | `/^annuleer\s+afspraak/i` | 1.0 | ~9ms | - -### 5.4 Tier 2: AI System Prompt Extension - -**Update in `INTENT_CLASSIFIER_SYSTEM_PROMPT` (`intent-classifier-ai.ts`):** - -```typescript -const INTENT_CLASSIFIER_SYSTEM_PROMPT = `Je bent een intent classifier voor Swift EPD. - -Classificeer de intentie van een zorgmedewerker in één van deze categorieΓ«n: - -**Bestaande intents:** -1. **dagnotitie** - Notitie maken over patiΓ«nt - Voorbeelden: "notitie jan medicatie", "marie rustige nacht", "schrijf observatie" - -2. **zoeken** - PatiΓ«nt zoeken of info opvragen - Voorbeelden: "zoek jan", "wie is marie", "dossier van piet" - -3. **overdracht** - Dienst overdracht/samenvatting - Voorbeelden: "overdracht", "wat moet ik weten", "dienst afronden" - -**Nieuwe agenda intents:** -4. **agenda_query** - Afspraken opvragen - Voorbeelden: "afspraken vandaag", "wat is mijn volgende afspraak", "agenda morgen" - Extraheer: dateRange { start, end, label: "vandaag"|"morgen"|"deze week"|"volgende week" } - -5. **create_appointment** - Nieuwe afspraak maken - Voorbeelden: "maak afspraak jan morgen 14:00", "plan intake vrijdag", "gesprek met marie" - Extraheer: patientName, date, time, type (intake|behandeling|follow-up|telefonisch|crisis) - -6. **cancel_appointment** - Afspraak annuleren - Voorbeelden: "annuleer jan", "cancel afspraak van 14:00", "verwijder intake morgen" - Extraheer: identifier { type: "patient"|"time"|"both", patientName?, time?, date? } - -7. **reschedule_appointment** - Afspraak verzetten - Voorbeelden: "verzet jan naar dinsdag", "14:00 wordt 15:00", "verplaats naar morgen" - Extraheer: identifier (oude afspraak), newDatetime { date, time } - -8. **unknown** - Intentie onduidelijk - -**Response format:** -{ - "intent": "...", - "confidence": 0.0-1.0, - "entities": { - "patientName": "...", // Voor alle patient-gerelateerde acties - "category": "medicatie|adl|...", // Alleen voor dagnotitie - "content": "...", // Alleen voor dagnotitie - "dateRange": { // Voor agenda_query - "start": "2024-12-27", - "end": "2024-12-27", - "label": "vandaag" - }, - "date": "2024-12-28", // Voor create/reschedule - "time": "14:00", // Voor create/reschedule - "type": "intake", // Voor create_appointment - "identifier": { // Voor cancel/reschedule - "type": "patient", - "patientName": "Jan" - }, - "newDatetime": { // Alleen voor reschedule - "date": "2024-12-31", - "time": "15:00" - } - }, - "reasoning": "Korte uitleg van classificatie" -} - -**Belangrijke regels:** -- Bij twijfel tussen intents: kies het meest specifieke -- Als cruciale info ontbreekt (patient/tijd): lower confidence (0.5-0.7) -- "deze patiΓ«nt" zonder context: gebruik activePatient indien beschikbaar -- Relatieve datums parsen: "morgen", "dinsdag", "volgende week" -- Tijden normaliseren: "twee uur" β†’ "14:00", "half drie" β†’ "14:30" -`; -``` - -**AI Fallback voorbeelden:** - -| User Input | Local Result | AI Triggered? | AI Response | -|------------|--------------|---------------|-------------| -| "afspraken vandaag" | confidence 1.0 | ❌ No | β€” | -| "ik wil graag een gesprek plannen" | confidence 0.0 | βœ… Yes | intent: create_appointment, conf: 0.75 | -| "verzet hem naar volgende week" | confidence 0.0 | βœ… Yes | intent: reschedule, conf: 0.7 (patient onduidelijk) | -| "kan ik marie ergens tussen proppen" | confidence 0.0 | βœ… Yes | intent: create_appointment, conf: 0.65 | - -### 5.5 Entity Extraction Schema - -**Uitbreiding van `ExtractedEntities` type:** - -```typescript -interface ExtractedEntities { - // Bestaande entities (dagnotitie, zoeken) - patientName?: string; - category?: VerpleegkundigCategory; - content?: string; - - // πŸ†• Agenda-specifieke entities - dateRange?: { - start: Date; - end: Date; - label: 'vandaag' | 'morgen' | 'deze week' | 'volgende week' | 'custom'; - }; - - datetime?: { - date: Date; // ISO date - time: string; // "HH:mm" format - }; - - appointmentType?: 'intake' | 'behandeling' | 'follow-up' | 'telefonisch' | - 'huisbezoek' | 'online' | 'crisis' | 'overig'; - - location?: 'praktijk' | 'online' | 'thuis'; - - identifier?: { - type: 'patient' | 'time' | 'both'; - patientName?: string; - patientId?: string; - time?: string; - date?: Date; - encounterId?: string; // Als eenduidig gevonden - }; - - newDatetime?: { // Alleen voor reschedule - date: Date; - time: string; - }; -} -``` - -### 5.6 Confidence Flow Diagram - -``` -User Input: "maak afspraak jan morgen 14:00" - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ TIER 1: Local Pattern Matching β”‚ -β”‚ Pattern: /^maak\s+afspraak\b/i β”‚ -β”‚ Match: βœ… Weight 1.0 β”‚ -β”‚ Confidence: 1.0 β”‚ -β”‚ Processing: ~10ms β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Confidence Check: 1.0 >= 0.8 β”‚ -β”‚ Decision: βœ… Skip AI, use local result β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Basic Entity Extraction (local) β”‚ -β”‚ - Patient: "jan" (fuzzy search needed) β”‚ -β”‚ - Date: "morgen" β†’ parse to tomorrow's date β”‚ -β”‚ - Time: "14:00" β”‚ -β”‚ - Type: default to 'behandeling' β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Intent Router β”‚ -β”‚ Intent: 'create_appointment' β”‚ -β”‚ Action: Open AgendaBlock (mode: create) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ - [AgendaBlock create form met prefill] -``` - -``` -User Input: "ik wil graag iets regelen voor volgende week" - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ TIER 1: Local Pattern Matching β”‚ -β”‚ Match: ❌ No direct pattern match β”‚ -β”‚ Confidence: 0.0 β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Confidence Check: 0.0 < 0.8 β”‚ -β”‚ Decision: βœ… Trigger AI Fallback β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ TIER 2: AI Classification (Claude Haiku) β”‚ -β”‚ Prompt: "Classificeer: ..." β”‚ -β”‚ Response: β”‚ -β”‚ intent: "create_appointment" β”‚ -β”‚ confidence: 0.65 β”‚ -β”‚ entities: { dateRange: "volgende week" } β”‚ -β”‚ reasoning: "Patient en tijd ontbreken" β”‚ -β”‚ Processing: ~380ms β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Confidence Check: 0.65 (0.5-0.7 range) β”‚ -β”‚ Decision: ⚠️ Verduidelijkingsvraag nodig β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ - Chat: "Met welke patiΓ«nt wil je een afspraak maken?" - [Geen artifact geopend] -``` - -### 5.7 Intent Router Integration - -**Artifact routing logic (in `swift-store.ts` of artifact manager):** - -```typescript -function openArtifactForIntent( - intent: SwiftIntent, - entities: ExtractedEntities, - confidence: number -): ArtifactConfig | null { - - // Confidence too low voor direct artifact - if (confidence < 0.7) { - return null; // Trigger verduidelijkingsvraag in chat - } - - switch (intent) { - // Bestaande intents - case 'dagnotitie': - return { - type: 'DagnotatieBlock', - prefill: { - patient: entities.patientName, - category: entities.category, - content: entities.content - } - }; - - case 'zoeken': - return { - type: 'ZoekenBlock', - prefill: { query: entities.patientName } - }; - - case 'overdracht': - return { - type: 'OverdrachtBlock', - prefill: {} - }; - - // πŸ†• Agenda intents - case 'agenda_query': - return { - type: 'AgendaBlock', - mode: 'list', - prefill: { - dateRange: entities.dateRange || getTodayRange() - } - }; - - case 'create_appointment': - // Check required entities - if (!entities.patientName) { - return null; // Need patient name - } - return { - type: 'AgendaBlock', - mode: 'create', - prefill: { - patient: { name: entities.patientName }, - datetime: entities.datetime, - type: entities.appointmentType || 'behandeling', - location: entities.location || 'praktijk' - } - }; - - case 'cancel_appointment': - return { - type: 'AgendaBlock', - mode: 'cancel', - prefill: { - identifier: entities.identifier - } - }; - - case 'reschedule_appointment': - if (!entities.identifier) { - return null; // Need to know which appointment - } - return { - type: 'AgendaBlock', - mode: 'reschedule', - prefill: { - identifier: entities.identifier, - newDatetime: entities.newDatetime - } - }; - - case 'unknown': - default: - return null; - } -} -``` - -### 5.8 Performance Metrics - -**Target response times:** - -| Stage | Target | Actual (Expected) | -|-------|--------|-------------------| -| Local pattern match | <50ms | ~10-15ms | -| Local + entity extraction | <100ms | ~30-50ms | -| AI fallback (cold) | <800ms | ~400-600ms | -| AI fallback (warm) | <500ms | ~200-400ms | -| Total (local path) | <150ms | ~50-80ms | -| Total (AI path) | <1000ms | ~500-700ms | - -**Optimization strategies:** -- Cache frequently used date ranges (today, tomorrow, this week) -- Pre-compile regex patterns -- Parallel entity extraction waar mogelijk -- AI response streaming voor betere UX tijdens wachttijd - ---- - -## 6. Conversational Patterns & Use Cases - -🎯 **Doel:** Beschrijven van typische conversational patterns en verwachte systeemgedrag per intent type. - -### 6.1 Agenda Query Patterns - -**Intent:** `agenda_query` - -**Conversational Examples:** - -| User Input | Confidence | Extracted Entities | System Response | -|------------|-----------|-------------------|-----------------| -| "afspraken vandaag" | 1.0 | dateRange: today | "Je hebt vandaag 3 afspraken..." β†’ AgendaBlock | -| "wat is mijn volgende afspraak" | 1.0 | dateRange: from now | "Je volgende afspraak is om 14:00..." | -| "agenda morgen" | 1.0 | dateRange: tomorrow | "Morgen heb je 2 afspraken..." | -| "laat agenda zien" | 0.85 | dateRange: today (implied) | AgendaBlock (today) | - -**Edge Cases:** -- Geen afspraken: "Je hebt vandaag geen afspraken" + Empty state -- Onduidelijke periode: "Voor welke dag bedoel je?" (verduidelijkingsvraag) -- Historical query: "afspraken gisteren" β†’ allowed, toont verleden - -### 6.2 Create Appointment Patterns - -**Intent:** `create_appointment` - -**Complete Information Flow:** - -``` -User: "maak afspraak jan de vries morgen 14:00" -Confidence: 1.0 -Entities: patient βœ“, date βœ“, time βœ“ - -System: "Ik maak een afspraak voor Jan de Vries op 28 dec om 14:00." -AgendaBlock: create form met prefill -``` - -**Partial Information Flow:** - -``` -User: "maak afspraak met jan" -Confidence: 0.75 -Entities: patient βœ“, date ❌, time ❌ - -System: "Voor wanneer wil je de afspraak plannen?" -[Geen artifact] - -User: "morgen 14:00" -System: "OkΓ©!" β†’ AgendaBlock opens -``` - -**Context-Aware:** - -``` -Active patient: Marie Jansen -User: "maak afspraak met deze patiΓ«nt" -Entities: patient from context βœ“ - -System: "Voor wanneer wil je afspreken met Marie?" -``` - -### 6.3 Cancel Appointment Patterns - -**Intent:** `cancel_appointment` - -**Single Match:** -``` -User: "annuleer afspraak jan morgen" -Matches: 1 -System: Confirmation dialog β†’ Cancel -``` - -**Multiple Matches:** -``` -User: "annuleer jan" -Matches: 3 -System: "Welke afspraak?" β†’ Disambiguation list -``` - -**Time-Based:** -``` -User: "annuleer de 14:00" -Matches: 1 (today implied) -System: Confirmation β†’ Cancel -``` - -### 6.4 Reschedule Appointment Patterns - -**Intent:** `reschedule_appointment` - -**Time Change Only:** -``` -User: "verzet 14:00 naar 15:00" -Entities: old time βœ“, new time βœ“, date: today -System: Reschedule form β†’ Update -``` - -**Date + Time:** -``` -User: "verzet jan naar dinsdag 10:00" -Entities: patient βœ“, new date βœ“, new time βœ“ -System: Edit form β†’ Update -``` - ---- - -## 7. Entity Extraction - Detailed Specification - -### 7.1 Required Entities per Intent - -```typescript -// agenda_query -{ - dateRange: { - start: Date; - end: Date; - label: 'vandaag' | 'morgen' | 'deze week' | 'volgende week'; - } -} - -// create_appointment -{ - patient: { - name: string; - id?: string; // Als gevonden - confidence: number; - }; - datetime: { - date: Date; - time: string; // "14:00" - }; - type?: 'intake' | 'behandeling' | 'follow-up' | 'telefonisch' | 'crisis'; - location?: 'praktijk' | 'online' | 'thuis'; -} - -// cancel_appointment / reschedule_appointment -{ - identifier: { - type: 'patient' | 'time' | 'both'; - patient?: string; - time?: string; - date?: Date; - }; - newDatetime?: { // Alleen voor reschedule - date: Date; - time: string; - }; -} -``` - -### 5.3 Confidence Thresholds - -| Confidence | Actie | Voorbeeld | -|------------|-------|-----------| -| >0.9 | Direct artifact openen met prefill | "maak afspraak jan de vries morgen 14:00" | -| 0.7-0.9 | Artifact + bevestigingsvraag | "maak afspraak jan morgen" (tijd onduidelijk) | -| 0.5-0.7 | Verduidelijkingsvraag in chat | "maak afspraak" (patient/tijd ontbreekt) | -| <0.5 | Fallback + suggestie | "Ik begrijp het niet. Bedoel je een afspraak maken?" | - ---- - -## 8. AgendaBlock Artifact - UI Specificatie - -### 8.1 Modes - -Het AgendaBlock heeft **4 modes**, afhankelijk van het intent: - -| Mode | Trigger Intent | Primaire UI | -|------|----------------|-------------| -| **List View** | `agenda_query` | Chronologische lijst van afspraken | -| **Create Form** | `create_appointment` | Form met prefilled patient/datetime | -| **Cancel View** | `cancel_appointment` | Lijst met "Annuleren" knoppen + confirmation | -| **Edit Form** | `reschedule_appointment` | Editable datetime picker | - -### 8.2 List View (Mode: List) - -**Triggered by:** "afspraken vandaag", "agenda morgen", "wat is volgende afspraak" - -**Layout:** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“… Afspraken Vandaag [Γ—] β”‚ -β”‚ Donderdag 27 december 2024 β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 09:00 - 10:00 πŸ”΅ Intake β”‚ β”‚ -β”‚ β”‚ Jan de Vries β”‚ β”‚ -β”‚ β”‚ πŸ“ Praktijk β”‚ β”‚ -β”‚ β”‚ [Details] [Annuleren] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 11:30 - 12:30 🟒 Behandelingβ”‚ β”‚ -β”‚ β”‚ Marie Jansen β”‚ β”‚ -β”‚ β”‚ 🌐 Online β”‚ β”‚ -β”‚ β”‚ [Details] [Annuleren] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 14:00 - 15:00 πŸ”΅ Vervolg β”‚ β”‚ -β”‚ β”‚ Piet Bakker β”‚ β”‚ -β”‚ β”‚ πŸ“ Praktijk β”‚ β”‚ -β”‚ β”‚ Notities: Bespreek medicatie aanpassing β”‚ β”‚ -β”‚ β”‚ [Details] [Annuleren] β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [πŸ“… Open volledige agenda β†’] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Elementen:** - -| Element | Beschrijving | Interactie | -|---------|--------------|------------| -| **Header** | Datum label + close button | Klik Γ— β†’ sluit artifact | -| **Afspraak Card** | Per afspraak: tijd, patient, type, locatie, notities | Klik card β†’ expand details | -| **Patient Name** | Klikbaar | Klik β†’ opent PatientContextCard | -| **Details Button** | Navigeert naar klassieke agenda | Opent `/epd/agenda` met filter op deze afspraak | -| **Annuleren Button** | Trigger cancel flow | Opent confirmation dialog | -| **Footer Link** | Link naar full agenda | Navigeert naar `/epd/agenda` | - -**Empty State:** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“… Afspraken Vandaag [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ πŸ“­ β”‚ -β”‚ β”‚ -β”‚ Geen afspraken gevonden β”‚ -β”‚ voor vandaag β”‚ -β”‚ β”‚ -β”‚ [Maak nieuwe afspraak] β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 8.3 Create Form (Mode: Create) - -**Triggered by:** "maak afspraak jan morgen 14:00", "plan intake" - -**Layout:** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“ Nieuwe Afspraak [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ PatiΓ«nt * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Jan de Vries βœ“ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ (Pre-filled, editable met autocomplete) β”‚ -β”‚ β”‚ -β”‚ Datum * Tijd * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 28-12-2024 β–Ό β”‚ β”‚ 14:00 β–Ό β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ (Pre-filled: "morgen") (Pre-filled: "14:00") β”‚ -β”‚ β”‚ -β”‚ Type * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β—‹ Intake ● Behandeling β—‹ Vervolg β”‚ β”‚ -β”‚ β”‚ β—‹ Telefonisch β—‹ Huisbezoek β—‹ Crisis β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ (Default: Behandeling) β”‚ -β”‚ β”‚ -β”‚ Locatie * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ ● Praktijk β—‹ Online β—‹ Thuis β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ (Default: Praktijk) β”‚ -β”‚ β”‚ -β”‚ Notities (optioneel) β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ ⚠️ Conflict: Je hebt al een afspraak om 14:00 β”‚ -β”‚ met Marie Jansen. Wil je toch doorgaan? β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [Annuleren] [βœ“ Afspraak maken] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Form Fields:** - -| Field | Type | Required | Validation | Prefill Source | -|-------|------|----------|------------|----------------| -| **PatiΓ«nt** | Autocomplete | βœ… | Must exist in DB | NLP entity extraction | -| **Datum** | Date picker | βœ… | Cannot be in past | NLP ("morgen", "dinsdag") | -| **Tijd** | Time picker | βœ… | 07:00-20:00 range | NLP ("14:00", "ochtend") | -| **Type** | Radio group | βœ… | One of predefined types | NLP ("intake") or default | -| **Locatie** | Radio group | βœ… | praktijk/online/thuis | NLP or default: praktijk | -| **Notities** | Textarea | ❌ | Max 500 chars | β€” | - -**Conflict Detection (Optional):** - -```typescript -// Check overlapping appointments -const hasConflict = await checkConflict({ - practitionerId: currentUser.id, - startTime: formData.datetime, - endTime: addHours(formData.datetime, 1), // Assume 1 hour -}); - -if (hasConflict) { - showWarning("⚠️ Conflict: Je hebt al een afspraak om ..."); -} -``` - -**States:** - -| State | UI Behavior | -|-------|-------------| -| **Initial** | Form with prefilled values, "Afspraak maken" enabled | -| **Validating** | Disable form, show spinner | -| **Conflict Warning** | Show warning banner, keep form enabled | -| **Submitting** | Disable form, "Afspraak maken" β†’ spinner | -| **Success** | Toast + chat confirmation, artifact closes | -| **Error** | Error message in form, re-enable | - -### 8.4 Cancel View (Mode: Cancel) - -**Triggered by:** "annuleer afspraak Jan", "cancel de 14:00 afspraak" - -**Flow 1: Single Match** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ❌ Afspraak Annuleren [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Wil je deze afspraak annuleren? β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 28-12-2024 14:00 - 15:00 β”‚ β”‚ -β”‚ β”‚ Jan de Vries - Intake β”‚ β”‚ -β”‚ β”‚ Praktijk β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ ⚠️ Deze actie kan niet ongedaan worden gemaakt. β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [Terug] [βœ“ Annuleren] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Flow 2: Multiple Matches (Disambiguation)** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ❌ Afspraak Annuleren [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Welke afspraak wil je annuleren? β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β—‹ 28-12-2024 09:00 - Jan de Vries (Intake) β”‚ β”‚ -β”‚ β”‚ Praktijk β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β—‹ 28-12-2024 14:00 - Jan de Vries (Vervolg) β”‚ β”‚ -β”‚ β”‚ Online β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β—‹ 03-01-2025 11:00 - Jan de Vries (Behandel) β”‚ β”‚ -β”‚ β”‚ Praktijk β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [Annuleren] [Volgende β†’] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**After Selection:** -β†’ Returns to single match confirmation flow - -### 8.5 Edit Form (Mode: Reschedule) - -**Triggered by:** "verzet 14:00 naar 15:00", "verzet Jan naar dinsdag" - -**Layout:** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ”„ Afspraak Verzetten [Γ—] β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Afspraak β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Jan de Vries - Intake β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ (Readonly) β”‚ -β”‚ β”‚ -β”‚ Huidige datum/tijd β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 28-12-2024 14:00 - 15:00 β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ (Readonly, strikethrough) β”‚ -β”‚ β”‚ -β”‚ Nieuwe datum/tijd * β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ 28-12-2024 β–Ό β”‚ β”‚ 15:00 β–Ό β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ (Editable, pre-filled met NLP extracted waarden) β”‚ -β”‚ β”‚ -β”‚ βœ… Geen conflicten gevonden β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [Annuleren] [βœ“ Verzetten] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 9. User Flows - Gedetailleerd - -### 9.1 Flow: Agenda Query (Simple) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 1: User Input β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ User (chat): "Wat zijn mijn afspraken vandaag?" β”‚ -β”‚ β”‚ -β”‚ [Enter pressed] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 2: Intent Detection β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ System: β”‚ -β”‚ - Pattern match: "afspraken vandaag" β†’ agenda_query β”‚ -β”‚ - Confidence: 0.95 β”‚ -β”‚ - Entities extracted: { dateRange: { start: today, β”‚ -β”‚ end: today, β”‚ -β”‚ label: 'vandaag' }} β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 3: AI Response (Streaming) β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ Assistant (chat): "Je hebt vandaag 3 afspraken: β”‚ -β”‚ - 09:00 Intake Jan de Vries β”‚ -β”‚ - 11:30 Behandeling Marie Jansen β”‚ -β”‚ - 14:00 Vervolggesprek Piet Bakker" β”‚ -β”‚ β”‚ -β”‚ [Streaming indicator β†’ full text] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 4: Artifact Opens β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ AgendaBlock (mode: list): β”‚ -β”‚ - Slide-in animation from right (200ms) β”‚ -β”‚ - Shows 3 appointment cards β”‚ -β”‚ - Chronological order β”‚ -β”‚ - Each card: patient (clickable), time, type, location β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 5: User Interaction (Optional) β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ User: β”‚ -β”‚ Option A: Klik "Jan de Vries" β†’ PatientContextCard opent β”‚ -β”‚ Option B: Klik "Annuleren" β†’ Cancel flow start β”‚ -β”‚ Option C: Klik "Details" β†’ Navigate to /epd/agenda β”‚ -β”‚ Option D: Close artifact (Γ—) β”‚ -β”‚ Option E: Continue chatting (artifact blijft open) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -TIMING: ~2-3 seconds total -``` - -### 9.2 Flow: Quick Create (Voice Input) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 1: Voice Activation β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ User: [Druk spatie in lege input field] β”‚ -β”‚ β”‚ -β”‚ System: β”‚ -β”‚ - Mic icon turns red πŸ”΄ β”‚ -β”‚ - Deepgram streaming starts β”‚ -β”‚ - Waveform animation appears β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 2: Speech Input β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ User (speaking): "Maak intake met Jan de Vries morgen β”‚ -β”‚ om twee uur" β”‚ -β”‚ β”‚ -β”‚ System: β”‚ -β”‚ - Live transcript appears in input field: β”‚ -β”‚ "maak intake met jan de vries morgen om twee uur" β”‚ -β”‚ - Pause detection: 1.5s silence β†’ auto-submit β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 3: NLP Entity Extraction β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ System (Chat API): β”‚ -β”‚ - Intent: create_appointment (confidence: 0.94) β”‚ -β”‚ - Entities: β”‚ -β”‚ { β”‚ -β”‚ patient: { β”‚ -β”‚ name: "Jan de Vries", β”‚ -β”‚ id: "uuid-123", // Found in DB β”‚ -β”‚ confidence: 0.91 β”‚ -β”‚ }, β”‚ -β”‚ datetime: { β”‚ -β”‚ date: "2024-12-28", // "morgen" parsed β”‚ -β”‚ time: "14:00" // "twee uur" normalized β”‚ -β”‚ }, β”‚ -β”‚ type: "intake" β”‚ -β”‚ } β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 4: AI Confirmation β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ Assistant (chat): "Ik maak een intake-afspraak voor β”‚ -β”‚ Jan de Vries op 28 december om 14:00. Klopt dat?" β”‚ -β”‚ β”‚ -β”‚ [Streaming response completes] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 5: AgendaBlock Opens (Create Form) β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ AgendaBlock (mode: create): β”‚ -β”‚ - Slide-in animation β”‚ -β”‚ - Pre-filled fields: β”‚ -β”‚ β€’ PatiΓ«nt: "Jan de Vries" βœ“ (locked) β”‚ -β”‚ β€’ Datum: "28-12-2024" (editable) β”‚ -β”‚ β€’ Tijd: "14:00" (editable) β”‚ -β”‚ β€’ Type: "Intake" selected β”‚ -β”‚ β€’ Locatie: "Praktijk" (default) β”‚ -β”‚ β€’ Notities: empty β”‚ -β”‚ - Focus: first editable field (Datum) β”‚ -β”‚ - "Afspraak maken" button enabled β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 6: User Review & Submit β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ User: β”‚ -β”‚ Option A: Direct klik "Afspraak maken" (accept prefill) β”‚ -β”‚ Option B: Adjust tijd naar 15:00 β†’ klik "Afspraak maken" β”‚ -β”‚ Option C: Via chat: "Zet tijd op 15:00" β†’ form updates β”‚ -β”‚ β”‚ -β”‚ [User clicks "Afspraak maken"] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 7: Server Action β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ System: β”‚ -β”‚ - Disable form (spinner on button) β”‚ -β”‚ - Call createEncounter({ β”‚ -β”‚ patientId: "uuid-123", β”‚ -β”‚ practitionerId: currentUser.id, β”‚ -β”‚ periodStart: "2024-12-28T14:00:00", β”‚ -β”‚ periodEnd: "2024-12-28T15:00:00", β”‚ -β”‚ typeCode: "intake", β”‚ -β”‚ classCode: "AMB" // Praktijk β”‚ -β”‚ }) β”‚ -β”‚ - revalidatePath('/epd/agenda') β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 8: Success Feedback β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ System: β”‚ -β”‚ - Toast notification: "βœ“ Afspraak aangemaakt!" β”‚ -β”‚ - Chat message: "Afspraak ingepland voor Jan de Vries β”‚ -β”‚ op 28 december om 14:00." β”‚ -β”‚ - AgendaBlock: Closes with fade-out animation β”‚ -β”‚ - Chat input: Re-enabled, ready for next command β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -TIMING: ~10-15 seconds total (incl. voice input) -``` - -### 9.3 Flow: Cancel with Disambiguation - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 1: User Request β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ User (chat): "Annuleer afspraak van Jan" β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 2: Intent + Identifier Extraction β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ System: β”‚ -β”‚ - Intent: cancel_appointment (confidence: 0.96) β”‚ -β”‚ - Entities: { identifier: { type: 'patient', β”‚ -β”‚ patient: 'Jan' }} β”‚ -β”‚ - Query DB for matching appointments: β”‚ -β”‚ SELECT * FROM encounters β”‚ -β”‚ WHERE patient.name ILIKE '%Jan%' β”‚ -β”‚ AND status = 'planned' β”‚ -β”‚ AND period_start >= NOW() β”‚ -β”‚ β†’ Returns 3 matches β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 3: Disambiguation Required β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ Assistant (chat): "Je hebt 3 afspraken met Jan. β”‚ -β”‚ Welke wil je annuleren?" β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 4: AgendaBlock Shows Options β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ AgendaBlock (mode: cancel, submode: disambiguation): β”‚ -β”‚ - Radio list met 3 opties: β”‚ -β”‚ β—‹ 28-12-2024 09:00 - Jan de Vries (Intake) - Praktijk β”‚ -β”‚ β—‹ 28-12-2024 14:00 - Jan de Vries (Vervolg) - Online β”‚ -β”‚ β—‹ 03-01-2025 11:00 - Jan de Vries (Behandeling) β”‚ -β”‚ - [Volgende β†’] button disabled tot selectie β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 5: User Selects β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ User: Klikt radio button bij "28-12-2024 14:00" β”‚ -β”‚ [Volgende β†’] button enabled β”‚ -β”‚ User: Klikt [Volgende β†’] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 6: Confirmation Dialog β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ AgendaBlock (mode: cancel, submode: confirm): β”‚ -β”‚ - Shows selected appointment β”‚ -β”‚ - Warning: "Deze actie kan niet ongedaan worden gemaakt." β”‚ -β”‚ - Buttons: [Terug] [βœ“ Annuleren] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 7: User Confirms β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ User: Klikt [βœ“ Annuleren] β”‚ -β”‚ β”‚ -β”‚ System: β”‚ -β”‚ - Call cancelEncounter(encounterId) β”‚ -β”‚ - Updates status to 'cancelled' (soft delete) β”‚ -β”‚ - revalidatePath('/epd/agenda') β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 8: Success β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ System: β”‚ -β”‚ - Toast: "Afspraak geannuleerd" β”‚ -β”‚ - Chat: "Afspraak met Jan de Vries op 28 december β”‚ -β”‚ om 14:00 is geannuleerd." β”‚ -β”‚ - AgendaBlock closes β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -TIMING: ~20-30 seconds (incl. disambiguation) -``` - -### 9.4 Flow: Reschedule (Quick) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 1: User Request β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ User (chat): "Verzet de 14:00 afspraak naar 15:00" β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 2: Intent + Time Extraction β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ System: β”‚ -β”‚ - Intent: reschedule_appointment (confidence: 0.93) β”‚ -β”‚ - Entities: { β”‚ -β”‚ identifier: { type: 'time', time: '14:00' }, β”‚ -β”‚ newDatetime: { time: '15:00' } β”‚ -β”‚ } β”‚ -β”‚ - Query today's appointments at 14:00 β†’ 1 match found β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 3: AI Response β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ Assistant (chat): "Ik verzet je afspraak van 14:00 β”‚ -β”‚ met Jan de Vries naar 15:00." β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 4: AgendaBlock Edit Form β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ AgendaBlock (mode: reschedule): β”‚ -β”‚ - Shows current details (readonly, strikethrough) β”‚ -β”‚ - Editable nieuwe tijd field: "15:00" (pre-filled) β”‚ -β”‚ - Conflict check: βœ… Geen conflicten β”‚ -β”‚ - [βœ“ Verzetten] button enabled β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 5: User Confirms β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ User: Klikt [βœ“ Verzetten] β”‚ -β”‚ β”‚ -β”‚ System: β”‚ -β”‚ - Call rescheduleEncounter(encounterId, { β”‚ -β”‚ periodStart: '2024-12-27T15:00', β”‚ -β”‚ periodEnd: '2024-12-27T16:00' β”‚ -β”‚ }) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - ↓ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ STEP 6: Success β”‚ -β”‚ ────────────────────────────────────────────────────────── β”‚ -β”‚ System: β”‚ -β”‚ - Toast: "Afspraak verzet naar 15:00" β”‚ -β”‚ - Chat: "Afspraak verzet naar 15:00." β”‚ -β”‚ - AgendaBlock closes β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -TIMING: ~10 seconds -``` - ---- - -## 10. Edge Cases & Error Handling - -### 10.1 Patient Name Ambiguity - -**Scenario:** Gebruiker zegt "Jan", maar er zijn 3 patiΓ«nten met naam Jan - -**Handling:** -``` -User: "Maak afspraak met Jan morgen 14:00" - -AI: "Ik vond 3 patiΓ«nten met de naam Jan. Welke bedoel je?" - -AgendaBlock (patient selector): -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Selecteer patiΓ«nt: β”‚ -β”‚ β—‹ Jan de Vries (BSN: 123456789) β”‚ -β”‚ β—‹ Jan Bakker (BSN: 987654321) β”‚ -β”‚ β—‹ Jan Jansen (BSN: 456789123) β”‚ -β”‚ [Annuleren] [Volgende β†’] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - -User: Selecteert "Jan de Vries" β†’ Form continues met pre-fill -``` - -### 10.2 Date/Time Parse Failure - -**Scenario:** Onduidelijke tijdaanduiding - -``` -User: "Maak afspraak met Jan overovermorgen" - -AI: "Ik begrijp 'overovermorgen' niet. Kun je een datum - opgeven? Bijvoorbeeld: morgen, dinsdag, of 30 december." - -[Geen AgendaBlock geopend] - -User: "30 december" - -AI: "Hoe laat wil je de afspraak plannen?" - -User: "14:00" - -AI: "Ik maak een afspraak voor Jan de Vries op 30 december om 14:00." -[AgendaBlock opens met pre-fill] -``` - -### 10.3 Appointment in Past - -**Scenario:** Gebruiker probeert afspraak in verleden te maken - -``` -User: "Maak afspraak met Jan gisteren 14:00" - -AI: "Ik kan geen afspraken in het verleden maken. - Bedoelde je morgen?" - -[Geen AgendaBlock] - -User: "Ja, morgen" - -AI: "OkΓ©, ik maak de afspraak voor morgen 14:00." -[AgendaBlock opens] -``` - -### 10.4 No Appointments Found - -**Scenario:** Query zonder resultaten - -``` -User: "Afspraken volgende week" - -AI: "Je hebt volgende week geen afspraken ingepland." - -AgendaBlock (empty state): -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ“­ Geen afspraken β”‚ -β”‚ Volgende week β”‚ -β”‚ [Maak nieuwe afspraak] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### 10.5 Server Error - -**Scenario:** Database of API failure - -``` -User: "Afspraken vandaag" - -[Server error during getEncounters()] - -AI: "Er ging iets mis bij het ophalen van je afspraken. - Probeer het opnieuw of open de volledige agenda." - -[Link naar /epd/agenda in chat message] - -[Geen AgendaBlock] -``` - -### 10.6 Conflict Detection Warning - -**Scenario:** Overlapping appointment - -``` -User: "Maak afspraak Jan morgen 14:00" - -[Existing appointment: Marie Jansen 14:00-15:00] - -AgendaBlock form shows: -⚠️ Conflict: Je hebt al een afspraak om 14:00 - met Marie Jansen. Wil je toch doorgaan? - -[Afspraak maken] button blijft enabled -User kan kiezen: aanpassen of door submit gaan -``` - ---- - -## 11. System Prompt Extension - -**Toevoeging aan `/api/swift/chat` system prompt:** - -```markdown -## Agenda & Afspraken Beheer - -Je helpt gebruikers met agenda-gerelateerde taken. - -### Intents die je herkent: - -1. **agenda_query** - Afspraken opvragen - Voorbeelden: "afspraken vandaag", "wat is volgende", "agenda morgen" - Actie: Toon lijst van afspraken in AgendaBlock - -2. **create_appointment** - Nieuwe afspraak maken - Voorbeelden: "maak afspraak met Jan morgen 14:00", "plan intake" - Actie: Open create form met extracted entities - Required: patient, date, time - Optional: type (default: behandeling), location (default: praktijk) - -3. **cancel_appointment** - Afspraak annuleren - Voorbeelden: "annuleer afspraak Jan", "cancel 14:00" - Actie: Toon confirmation dialog - -4. **reschedule_appointment** - Afspraak verzetten - Voorbeelden: "verzet 14:00 naar 15:00", "verzet Jan naar dinsdag" - Actie: Toon edit form met oude + nieuwe tijd - -### Entity Extraction: - -**Patient:** -- Extraheer volledige naam indien mogelijk -- Bij onduidelijkheid: vraag verduidelijking -- Gebruik activePatient uit context als user zegt "deze patiΓ«nt" - -**Date/Time:** -- Parse relatieve datums: "morgen", "dinsdag", "volgende week" -- Parse tijden: "14:00", "twee uur", "half drie" -- Bij onduidelijkheid: vraag specifieke datum/tijd -- Valideer: geen datums in verleden (behalve queries) - -**Type:** -- intake, behandeling, follow-up, telefonisch, huisbezoek, crisis -- Default: behandeling (als niet gespecificeerd) - -**Location:** -- praktijk, online, thuis -- Default: praktijk - -### Response Format: - -Bij succesvolle intent detection, voeg action object toe: - -```json -{ - "type": "action", - "intent": "create_appointment", - "entities": { - "patient": { "name": "Jan de Vries", "id": "uuid", "confidence": 0.91 }, - "datetime": { "date": "2024-12-28", "time": "14:00" }, - "type": "intake", - "location": "praktijk" - }, - "confidence": 0.94, - "artifact": { - "type": "AgendaBlock", - "mode": "create", - "prefill": { /* extracted entities */ } - } -} -``` - -### Verduidelijkingsvragen: - -Stel vragen bij: -- Meerdere patiΓ«nten met zelfde naam -- Onduidelijke datum ("volgende keer", "binnenkort") -- Ontbrekende tijd bij create -- Meerdere matches bij cancel/reschedule - -Voorbeelden: -- "Welke Jan bedoel je? Jan de Vries of Jan Bakker?" -- "Op welke datum wil je de afspraak plannen?" -- "Hoe laat wil je afspreken?" -``` - ---- - -## 12. Technical Implementation - -### 12.1 Date/Time Parser Utility - -```typescript -// lib/swift/date-time-parser.ts - -export function parseRelativeDate(input: string): Date | null { - const today = new Date(); - - const patterns = { - 'vandaag': () => today, - 'morgen': () => addDays(today, 1), - 'overmorgen': () => addDays(today, 2), - 'maandag': () => getNextWeekday(today, 1), - 'dinsdag': () => getNextWeekday(today, 2), - // ... etc - 'deze week': () => ({ start: startOfWeek(today), end: endOfWeek(today) }), - 'volgende week': () => ({ - start: startOfWeek(addWeeks(today, 1)), - end: endOfWeek(addWeeks(today, 1)) - }), - }; - - const normalized = input.toLowerCase().trim(); - - for (const [pattern, fn] of Object.entries(patterns)) { - if (normalized.includes(pattern)) { - return fn(); - } - } - - // Fallback: try date-fns parse - return parseDate(input, 'dd-MM-yyyy', today); -} - -export function parseTime(input: string): string | null { - // "14:00" β†’ "14:00" - if (/^\d{1,2}:\d{2}$/.test(input)) return input; - - // "14" β†’ "14:00" - if (/^\d{1,2}$/.test(input)) return `${input.padStart(2, '0')}:00`; - - // "twee uur" β†’ "14:00" (NLP via AI) - // "half drie" β†’ "14:30" - const timeWords = { - 'één': '13:00', 'een': '13:00', - 'twee': '14:00', - 'drie': '15:00', - 'half drie': '14:30', - // ... etc - }; - - return timeWords[input.toLowerCase()] || null; -} -``` - -### 12.2 AgendaBlock Component Structure - -```typescript -// components/swift/artifacts/blocks/agenda-block.tsx - -interface AgendaBlockProps { - mode: 'list' | 'create' | 'cancel' | 'reschedule'; - appointments?: Encounter[]; - dateRange?: { start: Date; end: Date; label: string }; - prefillData?: { - patient?: { id: string; name: string }; - datetime?: { date: Date; time: string }; - type?: EncounterType; - location?: EncounterLocation; - }; - disambiguationOptions?: Encounter[]; - onClose?: () => void; -} - -export function AgendaBlock({ mode, ...props }: AgendaBlockProps) { - switch (mode) { - case 'list': - return ; - case 'create': - return ; - case 'cancel': - return ; - case 'reschedule': - return ; - } -} -``` - -### 12.3 Server Actions (Reuse Existing) - -```typescript -// Reuse from app/epd/agenda/actions.ts -import { - getEncounters, - createEncounter, - cancelEncounter, - rescheduleEncounter -} from '@/app/epd/agenda/actions'; - -// Usage in AgendaBlock: -const appointments = await getEncounters(startDate, endDate, practitionerId); - -const newEncounter = await createEncounter({ - patientId: formData.patientId, - practitionerId: currentUser.id, - periodStart: combineDatetime(formData.date, formData.time), - periodEnd: addHours(combineDatetime(formData.date, formData.time), 1), - typeCode: formData.type, - classCode: formData.location === 'praktijk' ? 'AMB' : - formData.location === 'online' ? 'VR' : 'HH', - typeDisplay: ENCOUNTER_TYPE_LABELS[formData.type], - classDisplay: LOCATION_LABELS[formData.location], - notes: formData.notes || undefined, -}); -``` - -### 12.4 Conflict Detection (Optional) - -```typescript -// lib/swift/conflict-checker.ts - -export async function checkAppointmentConflict({ - practitionerId, - startTime, - endTime, - excludeId, -}: { - practitionerId: string; - startTime: Date; - endTime: Date; - excludeId?: string; -}): Promise { - const supabase = createClient(); - - const { data, error } = await supabase - .from('encounters') - .select('*') - .eq('practitioner_id', practitionerId) - .eq('status', 'planned') - .or(`period_start.lte.${endTime.toISOString()},period_end.gte.${startTime.toISOString()}`) - .neq('id', excludeId || '') - .single(); - - return data; -} -``` - ---- - -## 13. UI Styling Specifications - -### 13.1 AgendaBlock Dimensions - -```css -.agenda-block { - width: 100%; - max-width: 600px; - min-height: 400px; - max-height: 80vh; - overflow-y: auto; -} - -.agenda-block-header { - height: 48px; - padding: 12px 16px; - border-bottom: 1px solid theme('colors.slate.200'); -} - -.agenda-block-content { - padding: 16px; -} - -.agenda-block-footer { - padding: 12px 16px; - border-top: 1px solid theme('colors.slate.200'); - display: flex; - justify-content: space-between; -} -``` - -### 13.2 Appointment Card Styling - -```css -.appointment-card { - background: white; - border: 1px solid theme('colors.slate.200'); - border-radius: 8px; - padding: 16px; - margin-bottom: 12px; - transition: all 150ms ease; -} - -.appointment-card:hover { - border-color: theme('colors.teal.500'); - box-shadow: 0 2px 8px rgba(0,0,0,0.1); -} - -.appointment-card-time { - font-size: 16px; - font-weight: 600; - color: theme('colors.slate.900'); -} - -.appointment-card-patient { - font-size: 14px; - color: theme('colors.teal.700'); - cursor: pointer; - text-decoration: underline; -} - -.appointment-card-patient:hover { - color: theme('colors.teal.900'); -} - -.appointment-card-meta { - font-size: 12px; - color: theme('colors.slate.500'); - margin-top: 4px; -} -``` - -### 13.3 Type Badges - -```typescript -const TYPE_COLORS = { - intake: { bg: '#dbeafe', border: '#3b82f6', text: '#1e40af' }, - behandeling: { bg: '#dcfce7', border: '#22c55e', text: '#166534' }, - 'follow-up': { bg: '#e0e7ff', border: '#6366f1', text: '#4338ca' }, - telefonisch: { bg: '#fef3c7', border: '#f59e0b', text: '#92400e' }, - huisbezoek: { bg: '#fce7f3', border: '#ec4899', text: '#9f1239' }, - crisis: { bg: '#fee2e2', border: '#ef4444', text: '#991b1b' }, -}; -``` - ---- - -## 14. Testing Scenarios - -### 14.1 Manual Test Checklist - -| # | Scenario | Expected Result | Status | -|---|----------|-----------------|--------| -| 1 | "afspraken vandaag" | AgendaBlock list view, toont vandaag's afspraken | ⬜ | -| 2 | "wat is volgende afspraak" | Chat response met eerstvolgende, AgendaBlock toont details | ⬜ | -| 3 | "maak afspraak jan morgen 14:00" | Create form met prefill, patient gevonden | ⬜ | -| 4 | Voice: "maak intake marie vrijdag 10:00" | Transcript correct, create form opent | ⬜ | -| 5 | "maak afspraak" (incomplete) | Verduidelijkingsvraag: "Met welke patiΓ«nt?" | ⬜ | -| 6 | "maak afspraak onbekende patient" | Patient search fallback, suggesties | ⬜ | -| 7 | Create form submit β†’ success | Toast, chat confirmation, artifact sluit | ⬜ | -| 8 | "annuleer afspraak jan" (1 match) | Confirmation dialog, direct match | ⬜ | -| 9 | "annuleer afspraak jan" (3 matches) | Disambiguation radio list | ⬜ | -| 10 | Cancel confirm β†’ success | Afspraak status=cancelled, toast | ⬜ | -| 11 | "verzet 14:00 naar 15:00" | Reschedule form, tijd pre-filled | ⬜ | -| 12 | Reschedule submit β†’ success | Tijd updated, toast confirmation | ⬜ | -| 13 | Conflict warning (overlapping) | Warning banner in create form | ⬜ | -| 14 | Click patient name in list | PatientContextCard opent | ⬜ | -| 15 | Click "Details" button | Navigates to /epd/agenda with filter | ⬜ | -| 16 | Empty state (geen afspraken) | Placeholder met "Maak nieuwe afspraak" | ⬜ | -| 17 | Server error tijdens query | Error in chat, geen artifact | ⬜ | -| 18 | Date in past validation | "Kan geen afspraken in verleden maken" | ⬜ | -| 19 | Context-aware: "maak afspraak deze patient" | Gebruikt active patient uit context | ⬜ | -| 20 | Multiple artifacts (3 max) | Agenda + Dagnotitie + Context card, tabs | ⬜ | - ---- - -## 15. Performance & Optimization - -### 15.1 Query Optimization - -```typescript -// Efficient date range queries met indexed columns -const { data } = await supabase - .from('encounters') - .select(` - id, - period_start, - period_end, - type_code, - type_display, - class_code, - notes, - status, - patient:patients!inner(id, name, bsn) - `) - .eq('practitioner_id', userId) - .gte('period_start', startDate.toISOString()) - .lte('period_start', endDate.toISOString()) - .eq('status', 'planned') - .order('period_start', { ascending: true }); - -// Index: idx_encounters_practitioner_period (practitioner_id, period_start) -``` - -### 15.2 Client-Side Caching - -```typescript -// React Query caching voor frequently accessed data -const { data: todayAppointments } = useQuery({ - queryKey: ['appointments', 'today', userId], - queryFn: () => getEncounters(startOfDay(today), endOfDay(today), userId), - staleTime: 5 * 60 * 1000, // 5 minutes - refetchOnMount: 'always', -}); -``` - ---- - -## 16. Bijlagen & Referenties - -### 16.1 Related Documentation - -- Swift Medical Scribe FO: `fo-swift-medical-scribe-v3.md` -- Swift Bouwplan: `bouwplan-swift-standalone-module.md` -- Klassieke Agenda Implementatie: `/app/epd/agenda` -- Date/Time Utilities: `date-fns` library - -### 16.2 External References - -- [FHIR Encounter Resource](https://www.hl7.org/fhir/encounter.html) -- [date-fns Documentation](https://date-fns.org/) -- [React Query Best Practices](https://tanstack.com/query/latest) - ---- - -## 17. Wijzigingslog - -| Versie | Datum | Wijzigingen | -|--------|-------|-------------| -| v1.0 | 27-12-2024 | **Initial:** Agenda planning functionaliteit in Swift - queries, quick create, cancel, reschedule | - ---- - -**Goedkeuring:** - -- [ ] Product Owner: _________________________ -- [ ] Lead Developer: _________________________ -- [ ] UX Designer: _________________________ - -**Volgende stappen:** -1. Review & approval FO -2. Epic 6 stories toevoegen aan bouwplan -3. Implementation start (3 stories, ~8 SP) diff --git a/docs/swift/fo-swift-medical-scribe-v3.md b/docs/swift/fo-swift-medical-scribe-v3.md deleted file mode 100644 index ee8a9c7..0000000 --- a/docs/swift/fo-swift-medical-scribe-v3.md +++ /dev/null @@ -1,742 +0,0 @@ -# 🧩 Functioneel Ontwerp (FO) β€” Swift Swift Assistent Chatbot - -**Projectnaam:** Swift β€” Swift Assistent Chatbot Interface -**Versie:** v3.0 -**Datum:** 27-12-2024 -**Auteur:** Colin Lit - ---- - -## 1. Doel en relatie met het PRD - -🎯 **Doel van dit document:** -Dit Functioneel Ontwerp beschrijft het **redesign** van Swift naar een Swift Assistent chatbot interface. De gebruiker voert een natuurlijke conversatie met een AI-assistent die intents herkent, acties uitvoert, en relevante UI-componenten toont in een split-screen layout. - -πŸ“˜ **Relatie met andere documenten:** -- **PRD:** `nextgen-epd-prd-ephemeral-ui-epd.md` β€” Ephemeral UI visie -- **UX/UI:** `swift-ux-v2.1.md` β€” Visuele specificaties (wordt herzien) -- **UX Research:** `nextgen-epd-onderzoeksverslag-ux-ui-patterns.md` β€” Marktanalyse -- **Bouwplan:** `bouwplan-swift-v2.md` β€” Development roadmap - -**Kernprincipe:** -> De gebruiker voert een natuurlijke conversatie met een Swift Assistent assistent. De assistent herkent intents, voert acties uit, en toont relevante UI-componenten (artifacts) rechts in beeld. De conversatie blijft zichtbaar en doorlopend β€” zoals ChatGPT Canvas of Claude Artifacts. - -**Belangrijkste wijzigingen t.o.v. v2.0:** - -| Aspect | v2.0 (Command Center) | v3.0 (Swift Assistent) | -|--------|----------------------|----------------------| -| Input model | Command-line stijl | Natuurlijke conversatie | -| UI paradigma | Blocks die verschijnen/verdwijnen | Chat links, artifacts rechts | -| Context | Per commando | Doorlopende conversatiegeschiedenis | -| AI rol | Intent classifier | Converserende Swift Assistent | -| Interactie | Transactioneel | Relationeel, follow-up mogelijk | - ---- - -## 2. Overzicht van de belangrijkste onderdelen - -🎯 **Doel:** Overzicht van alle modules en hun relaties. - -### 2.1 Systeemcomponenten - -| # | Component | Beschrijving | Type | -|---|-----------|--------------|------| -| 1 | **Command Center** | Hoofdscherm met split-screen layout | Scherm | -| 2 | **Context Bar** | Dienst, actieve patiΓ«nt, user info | UI Zone | -| 3 | **Chat Panel** | Doorlopende conversatie (links, 40%) | UI Zone | -| 4 | **Artifact Area** | Waar blocks verschijnen (rechts, 60%) | UI Zone | -| 5 | **Chat Input** | Tekst + voice input (onderaan chat) | UI Zone | -| 6 | **Chat API** | Medical scribe chatbot endpoint | Backend | -| 7 | **Intent Engine** | Herkent intents in conversatie (hybrid) | Backend | -| 8 | **Context Manager** | Beheert sessie context + chat history | Backend | - -### 2.2 Artifacts (Bouwblokken) - -| Prio | Artifact | Functie | Trigger voorbeelden | -|------|----------|---------|---------------------| -| P1 | **DagnotatieBlock** | Snelle notitie invoer | "medicatie gegeven aan jan" | -| P1 | **ZoekenBlock** | PatiΓ«nt zoeken | "wie is jan de vries" | -| P1 | **PatientContextCard** | PatiΓ«nt overzicht | Na zoeken / selectie | -| P1 | **OverdrachtBlock** | Dienst overdracht met AI-filtering | "maak overdracht" | -| P2 | **RapportageBlock** | Behandelrapportage | "gesprek gehad met jan" | -| P2 | **AgendaBlock** | Afspraken | "mijn afspraken vandaag" | -| P2 | **MetingenBlock** | Vitale functies | "bloeddruk invoeren" | - -**Belangrijk:** Artifacts blijven functioneel hetzelfde als v2.0 blocks, maar verschijnen nu rechts in een persistent panel. - -### 2.3 Rol-specifieke Views - -| Rol | Primaire workflow | Artifact focus | -|-----|-------------------|----------------| -| **Verpleegkundige** | Notities maken tijdens dienst | DagnotatieBlock, RapportageBlock | -| **Psychiater** | Gefilterde overdracht lezen | OverdrachtBlock met AI-samenvatting | - ---- - -## 3. User Stories - -🎯 **Doel:** Beschrijven wat gebruikers moeten kunnen doen, vanuit hun perspectief. - -### 3.1 Nieuwe Stories (v3.0) - -| ID | Rol | Doel / Actie | Verwachte waarde | Prio | -|----|-----|--------------|------------------|------| -| US-15 | Alle gebruikers | Natuurlijke conversatie voeren met assistent | Voelt als praten met collega | πŸ”΄ P1 | -| US-16 | Alle gebruikers | Conversatiegeschiedenis zien | Context behouden tijdens werk | πŸ”΄ P1 | -| US-17 | Alle gebruikers | Doorvragen zonder opnieuw te beginnen | Flexibele workflow | πŸ”΄ P1 | -| US-18 | Alle gebruikers | Assistent stelt verduidelijkingsvragen | Minder fouten, betere data | 🟑 P2 | -| US-19 | Alle gebruikers | Meerdere acties in één conversatie | EfficiΓ«nte workflow | 🟑 P2 | -| US-20 | Verpleegkundige | Notities maken via spraak of typen | Hands-free documentatie | πŸ”΄ P1 | -| US-21 | Verpleegkundige | Zien welke notities relevant zijn voor psychiater | Transparantie in filtering | 🟑 P2 | -| US-22 | Psychiater | Alleen behandelrelevante info zien | Geen ruis, focus op behandeling | πŸ”΄ P1 | -| US-23 | Psychiater | Doorklikken naar originele bron | Verificatie en context | πŸ”΄ P1 | - -### 3.2 Bestaande Stories (herzien) - -| ID | Rol | Doel / Actie | Wijziging v3.0 | -|----|-----|--------------|----------------| -| US-01 | Verpleegkundige | Dagnotitie maken | Via conversatie: "Ik heb medicatie gegeven aan Jan" | -| US-02 | Verpleegkundige | PatiΓ«nt zoeken | Via conversatie: "Wie is Jan de Vries?" | -| US-04 | Verpleegkundige | Overdracht maken | Via conversatie: "Maak overdracht voor deze dienst" | - ---- - -## 4. Functionele werking per onderdeel - -🎯 **Doel:** Per component beschrijven wat de gebruiker kan doen en wat het systeem doet. - -### 4.1 Command Center (Hoofdscherm) - -**Beschrijving:** -Split-screen layout met chat links (40%) en artifacts rechts (60%). De gebruiker voert een natuurlijke conversatie met de Swift Assistent assistent. - -**Layout:** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ• Ochtend | 8 ptn Jan de Vries β–Ό πŸ‘€ SV β”‚ -β”‚ CONTEXT BAR β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ β”‚ -β”‚ CHAT PANEL (40%) β”‚ ARTIFACT AREA (60%) β”‚ -β”‚ β”‚ β”‚ -β”‚ πŸ‘€ "Ik heb net medicatie β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ gegeven aan Jan" β”‚ β”‚ πŸ“ Dagnotitie β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ πŸ€– Ik maak een dagnotitie β”‚ β”‚ PatiΓ«nt: Jan de Vries βœ“ β”‚ β”‚ -β”‚ voor Jan de Vries. β”‚ β”‚ Categorie: Medicatie βœ“ β”‚ β”‚ -β”‚ Categorie: Medicatie. β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ Notitie: β”‚ β”‚ -β”‚ Wil je nog iets β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚ -β”‚ toevoegen? β”‚ β”‚ β”‚ medicatie gegeven β”‚β”‚ β”‚ -β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚ -β”‚ πŸ‘€ "Nee, opslaan" β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ ☐ Relevant voor psychiater β”‚ β”‚ -β”‚ πŸ€– βœ“ Notitie opgeslagen β”‚ β”‚ β”‚ β”‚ -β”‚ voor Jan de Vries. β”‚ β”‚ [Annuleren] [πŸ’Ύ Opslaan] β”‚ β”‚ -β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ -β”‚ πŸ’¬ Typ of spreek... 🎀 β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Gedrag:** -- Bij laden: Chat input heeft focus, artifact area toont placeholder -- Keyboard shortcut `⌘K` focust chat input vanaf elke plek -- Artifacts verschijnen rechts met slide-in animatie (200ms) -- Chat blijft zichtbaar en scrollbaar tijdens werk met artifacts -- Meerdere artifacts mogelijk via tabs (max 3 tegelijk) - -**States:** - -| State | Chat Panel | Artifact Area | -|-------|------------|---------------| -| Initial | Welcome message | Placeholder: "Artifacts verschijnen hier" | -| Conversing | Chat history + streaming response | Ongewijzigd of artifact | -| Action triggered | Chat continues | Artifact slide-in | -| Working | Chat beschikbaar | Artifact actief | -| Completed | Success message in chat | Artifact sluit of blijft | - ---- - -### 4.2 Context Bar - -**Functie:** Toont essentiΓ«le context: dienst, actieve patiΓ«nt, gebruiker. - -**Elementen:** - -| Element | Beschrijving | Interactie | -|---------|--------------|------------| -| Dienst indicator | πŸ• Ochtend / Middag / Nacht + patiΓ«ntentelling | Geen | -| Actieve patiΓ«nt | Dropdown met recent geselecteerde patiΓ«nten | Klik opent selector | -| User info | Avatar + initialen | Klik opent menu | - -**Dienst kleuren:** - -| Dienst | Tijd | Kleur | -|--------|------|-------| -| Ochtend | 07:00-15:00 | Amber (#F59E0B) | -| Middag | 15:00-23:00 | Blue (#3B82F6) | -| Nacht | 23:00-07:00 | Indigo (#6366F1) | - ---- - -### 4.3 Chat Panel - -**Functie:** Toont doorlopende conversatie met Swift Assistent assistent. - -**Elementen:** - -| Element | Beschrijving | -|---------|--------------| -| Chat Messages | Scrollbare lijst van user en assistant messages | -| Message Bubbles | User: rechts, amber bg / Assistant: links, slate bg | -| Streaming Indicator | Pulsating dots tijdens AI response | -| Action Links | Klikbare links naar gerelateerde artifacts | -| Timestamps | Optioneel, alleen bij pauzes >5 minuten | - -**Message Types:** - -| Type | Weergave | Voorbeeld | -|------|----------|-----------| -| User message | Rechts, amber | "medicatie gegeven aan jan" | -| Assistant text | Links, slate | "Ik maak een dagnotitie..." | -| Assistant action | Links, met icon | "πŸ“ Dagnotitie geopend" (klikbaar) | -| System message | Centered, subtle | "βœ“ Notitie opgeslagen" | -| Error message | Links, red border | "Er ging iets mis. Probeer opnieuw." | - -**Gedrag:** -- Auto-scroll naar laatste message -- Scroll-lock wanneer gebruiker omhoog scrollt -- "Scroll to bottom" knop bij nieuwe messages -- Max 100 messages in view (pagination voor oudere) - ---- - -### 4.4 Chat Input - -**Functie:** Tekst + voice input voor conversatie met Swift Assistent. - -**States:** - -| State | Weergave | Trigger | -|-------|----------|---------| -| Default | "Typ of spreek..." + mic icon | β€” | -| Typing | Cursor + getypte tekst | Keyboard input | -| Listening | πŸ”΄ + waveform + live transcript | Mic click of spatie | -| Processing | Disabled, "Denkt na..." | Na submit | -| Streaming | Disabled, streaming in chat | Tijdens AI response | - -**Keyboard Shortcuts:** - -| Key | Actie | -|-----|-------| -| `Enter` | Submit message | -| `⌘Enter` / `Ctrl+Enter` | Force submit (ook tijdens streaming) | -| `Escape` | Clear input / cancel voice | -| `↑` | Vorige message (edit history) | -| `Space` (leeg) | Start voice recording | -| `⌘K` | Focus input | - -**Voice Flow:** -1. User klikt mic of drukt spatie (bij lege input) -2. Deepgram start streaming transcription -3. Live transcript verschijnt in input field -4. Pauze detectie (1.5 sec stilte) β†’ auto-submit -5. Of user klikt "Stop" β†’ submit - ---- - -### 4.5 Artifact Area - -**Functie:** Toont actieve artifacts (blocks) rechts van de chat. - -**Layout opties:** - -| Situatie | Weergave | -|----------|----------| -| Geen artifact | Placeholder met voorbeelden | -| EΓ©n artifact | Full width, centered | -| Meerdere artifacts | Tabs bovenaan (max 3) | - -**Artifact Lifecycle:** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 1. Intent detected in chat β”‚ -β”‚ β†’ AI response: "Ik maak een dagnotitie..." β”‚ -β”‚ β†’ Action object attached to response β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 2. Artifact appears β”‚ -β”‚ β†’ Slide-in animation (200ms, from right) β”‚ -β”‚ β†’ Pre-filled with extracted entities β”‚ -β”‚ β†’ Focus moves to first editable field β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 3. User interacts β”‚ -β”‚ β†’ Edits fields in artifact β”‚ -β”‚ β†’ Can continue chatting (e.g., "voeg toe: sliep goed") β”‚ -β”‚ β†’ Chat updates artifact in real-time β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 4. User saves or cancels β”‚ -β”‚ β†’ Success: toast + chat confirmation + artifact closes β”‚ -β”‚ β†’ Cancel: artifact closes, no confirmation β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Placeholder State:** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ πŸ’¬ Artifacts verschijnen hier β”‚ -β”‚ β”‚ -β”‚ Vraag me iets, bijvoorbeeld: β”‚ -β”‚ β€’ "Notitie voor Jan: medicatie gegeven" β”‚ -β”‚ β€’ "Zoek Marie van den Berg" β”‚ -β”‚ β€’ "Maak overdracht voor deze dienst" β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -### 4.6 Swift Assistent Chat API - -**Functie:** Chatbot endpoint die conversatie voert en intents herkent. - -**Endpoint:** `POST /api/swift/chat` - -**Request:** - -```typescript -interface ChatRequest { - message: string; // User message - messages: ChatMessage[]; // Conversation history (max 20) - context: { - activePatient?: Patient; // Currently selected patient - shift: 'ochtend' | 'middag' | 'nacht'; - userId: string; - recentActions: RecentAction[]; // Last 5 actions - }; -} -``` - -**Response (Server-Sent Events):** - -```typescript -// Text chunk (streaming) -{ type: 'text', content: string } - -// Action detected (end of response) -{ - type: 'action', - intent: Intent, - entities: ExtractedEntities, - confidence: number, - artifact?: { - type: ArtifactType, - prefill: PrefillData - } -} - -// Done -{ type: 'done' } -``` - -**System Prompt (samenvatting):** - -``` -Je bent een medische assistent (Swift Assistent) voor Swift, een Nederlands GGZ EPD. - -Je rol: -- Help zorgmedewerkers met documentatie en administratie -- Voer natuurlijke gesprekken in het Nederlands -- Herken intents en voer acties uit wanneer nodig -- Stel verduidelijkingsvragen bij onduidelijkheid -- Wees vriendelijk maar professioneel - -Intents die je herkent: -- dagnotitie: notitie maken voor patiΓ«nt -- zoeken: patiΓ«nt zoeken -- rapportage: behandelrapportage schrijven -- overdracht: dienst overdracht maken -- metingen: vitale functies invoeren -- agenda: afspraken bekijken - -Wanneer je een intent herkent, voeg een JSON action object toe aan je response. - -Huidige context: -- Actieve patiΓ«nt: {activePatient} -- Dienst: {shift} -- Recente acties: {recentActions} -``` - ---- - -### 4.7 Intent Engine (Hybrid) - -**Functie:** Herkent intents in conversatie met two-tier approach. - -**Tier 1: Local Pattern Matching (<50ms)** - -| Pattern | Intent | Entities | -|---------|--------|----------| -| "notitie [naam]" | dagnotitie | patient: naam | -| "zoek [naam]" | zoeken | query: naam | -| "overdracht" | overdracht | β€” | -| "bloeddruk [naam]" | metingen | patient: naam, type: bloeddruk | - -**Tier 2: AI Classification (via Chat API)** - -Wanneer local patterns geen match geven of confidence <0.8, bepaalt de Chat API het intent op basis van conversatie-context. - -**Voorbeelden:** - -| Conversatie | Intent | Methode | -|-------------|--------|---------| -| "notitie jan medicatie" | dagnotitie | Local (direct match) | -| "Ik heb net een gesprek gehad" | rapportage | AI (context needed) | -| "Hij geeft aan zich beter te voelen" | (context) | AI (follow-up) | -| "Wie was die mevrouw van kamer 12?" | zoeken | AI (indirect) | - ---- - -### 4.8 AI-Filtering voor Psychiater (Overdracht) - -**Functie:** Filtert verpleegkundige rapportages naar behandelrelevante informatie. - -**Wat WEL naar psychiater gaat:** - -| Categorie | Voorbeelden | -|-----------|-------------| -| Medicatie-issues | Weigering, bijwerkingen, therapierespons | -| Stemming/gedrag verandering | t.o.v. baseline, significante shifts | -| Risico-signalen | SuΓ―cidale uitingen, zelfbeschadiging, agressie | -| Signaleringsplan triggers | Oranje/rood fase signalen | -| Psychotische symptomen | Hallucinaties, wanen | -| Behandelplan stagnatie | Geen voortgang op doelen | - -**Wat NIET naar psychiater gaat:** - -| Categorie | Voorbeelden | -|-----------|-------------| -| Routine medicatie | "Medicatie volgens schema ingenomen" | -| ADL activiteiten | "Heeft gedoucht", "Ontbijt genuttigd" | -| Standaard observaties | "Rustige dag", "Goed geslapen" | -| Sociale activiteiten | "Bezoek gehad", "Mee naar dagactiviteit" | - -**Linked Evidence:** -Elke zin in de AI-samenvatting linkt naar de originele verpleegkundige notitie. De psychiater kan hover-to-preview of click-to-expand gebruiken. - -**UI in OverdrachtBlock:** - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ”„ Overdracht Ochtend β†’ Middag [Γ—] β”‚ -β”‚ 07:00 - 15:00 | 8 patiΓ«nten β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ Behandelrelevant (3 patiΓ«nten) β”‚ -β”‚ ─────────────────────────────────────────────────────── β”‚ -β”‚ β”‚ -β”‚ β–Ό Jan de Vries ⚠️ Alert β”‚ -β”‚ Weigerde ochtendmedicatie. Geeft aan last te hebben β”‚ -β”‚ van bijwerkingen (duizeligheid). Stemming somberder β”‚ -β”‚ dan gisteren. β”‚ -β”‚ πŸ“Ž 3 bronnotities [Bekijk bronnen] β”‚ -β”‚ β”‚ -β”‚ β–Ά Marie van den Berg β”‚ -β”‚ β–Ά Piet Jansen β”‚ -β”‚ β”‚ -β”‚ ─────────────────────────────────────────────────────── β”‚ -β”‚ Geen bijzonderheden (5 patiΓ«nten) β”‚ -β”‚ [Toon allen β–Ό] β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ [πŸ“‹ Kopieer] [πŸ“€ Naar EPD] [βœ“ Gezien] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 5. User Flows - -🎯 **Doel:** Laten zien hoe de gebruiker stap-voor-stap door het systeem gaat. - -### Flow 1: Dagnotitie via Conversatie - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 1. Verpleegkundige opent Swift β”‚ -β”‚ β†’ Chat: welcome message β”‚ -β”‚ β†’ Artifact: placeholder β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 2. Verpleegkundige typt: "Medicatie gegeven aan Jan" β”‚ -β”‚ β†’ Message verschijnt in chat β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 3. AI Response (streaming): β”‚ -β”‚ "Ik maak een dagnotitie voor Jan de Vries. β”‚ -β”‚ Categorie: Medicatie. Wil je nog iets toevoegen?" β”‚ -β”‚ β†’ Action: intent=dagnotitie, patient=Jan, cat=Medicatie β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 4. DagnotatieBlock verschijnt rechts: β”‚ -β”‚ β†’ Patient: Jan de Vries βœ“ (pre-filled) β”‚ -β”‚ β†’ Categorie: Medicatie βœ“ (pre-filled) β”‚ -β”‚ β†’ Text: "Medicatie gegeven" (pre-filled) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 5. Verpleegkundige: "Nee, opslaan" β”‚ -β”‚ β†’ Of: klikt direct op Opslaan knop β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 6. Resultaat: β”‚ -β”‚ β†’ Toast: "βœ“ Notitie opgeslagen" β”‚ -β”‚ β†’ Chat: "Notitie opgeslagen voor Jan de Vries." β”‚ -β”‚ β†’ Artifact sluit (of blijft voor volgende) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ TIJD: ~15 seconden β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Flow 2: Overdracht met AI-Filtering (Psychiater) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 1. Psychiater opent Swift β”‚ -β”‚ β†’ Chat: "Goedemorgen! Wil je de overdracht bekijken?" β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 2. Psychiater: "Ja, laat zien" β”‚ -β”‚ β†’ Of: "Overdracht ochtend" β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 3. AI Response: β”‚ -β”‚ "Ik haal de overdracht op. 3 patiΓ«nten hebben β”‚ -β”‚ behandelrelevante updates." β”‚ -β”‚ β†’ OverdrachtBlock verschijnt rechts β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 4. OverdrachtBlock toont: β”‚ -β”‚ β†’ Gefilterde samenvatting (alleen behandelrelevant) β”‚ -β”‚ β†’ PatiΓ«nten gesorteerd op urgentie β”‚ -β”‚ β†’ "Geen bijzonderheden" sectie ingeklapt β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 5. Psychiater klikt op "πŸ“Ž 3 bronnotities" bij Jan β”‚ -β”‚ β†’ Slide-in panel met originele verpleegkundige notities β”‚ -β”‚ β†’ Timestamps en auteurs zichtbaar β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 6. Psychiater in chat: "Wat was er gisteren met Jan?" β”‚ -β”‚ β†’ AI antwoordt met context uit eerdere notities β”‚ -β”‚ β†’ Geen nieuw artifact nodig β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 7. Psychiater klikt "βœ“ Gezien" β”‚ -β”‚ β†’ Overdracht gemarkeerd als gelezen β”‚ -β”‚ β†’ Chat: "Overdracht gemarkeerd als gezien." β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Flow 3: Rapportage met Verduidelijkingsvragen - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ 1. Verpleegkundige: "Ik heb een gesprek gehad" β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 2. AI: "Met welke patiΓ«nt had je het gesprek?" β”‚ -β”‚ β†’ Geen artifact (verduidelijking nodig) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 3. Verpleegkundige: "Jan" β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 4. AI: "Ik maak een rapportage voor Jan de Vries. β”‚ -β”‚ Wat wil je vastleggen?" β”‚ -β”‚ β†’ RapportageBlock verschijnt rechts (leeg) β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 5. Verpleegkundige: "Hij voelt zich beter, minder angstig" β”‚ -β”‚ β†’ Tekst verschijnt in RapportageBlock β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 6. AI: "Genoteerd. Wil je dit als voortgangsgesprek β”‚ -β”‚ opslaan of is er meer?" β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 7. Verpleegkundige: "Opslaan als voortgang" β”‚ -β”‚ β†’ Rapportage opgeslagen met tag "Voortgangsgesprek" β”‚ -β”‚ β†’ Toast + chat confirmation β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## 6. Interacties met AI - -🎯 **Doel:** Uitleggen waar AI in de flow voorkomt en wat de gebruiker ziet. - -| Locatie | AI-actie | Trigger | Output | -|---------|----------|---------|--------| -| Chat | Conversatie + intent detection | Elke user message | Streaming text + action object | -| Chat | Verduidelijkingsvraag | Onduidelijke intent | Vraag in chat (geen artifact) | -| Chat | Follow-up verwerking | User antwoord op vraag | Update artifact of nieuwe info | -| OverdrachtBlock | Relevantie-filtering | "overdracht" intent | Gefilterde samenvatting | -| OverdrachtBlock | Samenvatting generatie | Per patiΓ«nt | Behandelrelevante bullets | -| RapportageBlock | Tekst structureren | "Structureer" knop | Gestructureerde tekst | -| RapportageBlock | B1-niveau herschrijven | "Vereenvoudig" knop | Herschreven tekst | - -**Confidence Thresholds:** - -| Confidence | Actie | -|------------|-------| -| >0.9 | Direct artifact openen met prefill | -| 0.7-0.9 | Artifact openen + bevestigingsvraag in chat | -| 0.5-0.7 | Verduidelijkingsvraag in chat, geen artifact | -| <0.5 | Fallback: "Ik begrijp je niet helemaal. Kun je het anders formuleren?" | - ---- - -## 7. Gebruikersrollen en rechten - -🎯 **Doel:** Beschrijven welke rollen toegang hebben tot welke onderdelen. - -| Rol | Toegang | Artifacts | AI-filtering | -|-----|---------|-----------|--------------| -| **Verpleegkundige** | Eigen dienst patiΓ«nten | Alle P1/P2 artifacts | Input: alle notities | -| **Psychiater** | Alle patiΓ«nten in behandeling | OverdrachtBlock (read), PatientContextCard | Output: gefilterde samenvatting | -| **Behandelaar** | Eigen caseload | Alle artifacts | Beide views beschikbaar | - -**Permissies per Artifact:** - -| Artifact | Verpleegkundige | Psychiater | Behandelaar | -|----------|-----------------|------------|-------------| -| DagnotatieBlock | βœ… Create | ❌ | βœ… Create | -| RapportageBlock | βœ… Create | πŸ‘οΈ Read | βœ… Create | -| OverdrachtBlock | βœ… Create | πŸ‘οΈ Read (filtered) | βœ… Both | -| PatientContextCard | πŸ‘οΈ Read | πŸ‘οΈ Read | πŸ‘οΈ Read | - ---- - -## 8. Technische Specificaties - -### 8.1 API Routes - -| Route | Method | Functie | Status | -|-------|--------|---------|--------| -| `/api/swift/chat` | POST | Medical scribe chatbot | πŸ†• Nieuw | -| `/api/swift/overdracht/generate` | POST | AI-gefilterde overdracht | πŸ”„ Herzien | -| `/api/intent/classify` | POST | Intent classification | βœ… Bestaat | -| `/api/patients/search` | GET | Patient search | βœ… Bestaat | -| `/api/reports` | POST | Report opslaan | βœ… Bestaat | - -### 8.2 Store Uitbreiding - -```typescript -interface SwiftStore { - // Bestaande state - activePatient: Patient | null; - activeBlock: BlockType | null; - shift: 'ochtend' | 'middag' | 'nacht'; - - // Chat state (nieuw) - chatMessages: ChatMessage[]; - isStreaming: boolean; - pendingAction: Action | null; - - // Artifact state (nieuw) - openArtifacts: Artifact[]; // Max 3 - activeArtifactId: string | null; - - // Actions - addChatMessage: (message: ChatMessage) => void; - processAction: (action: Action) => void; - openArtifact: (artifact: Artifact) => void; - closeArtifact: (id: string) => void; -} -``` - -### 8.3 Component Structuur - -``` -components/swift/ -β”œβ”€β”€ command-center/ -β”‚ β”œβ”€β”€ command-center.tsx # Split-screen container -β”‚ β”œβ”€β”€ context-bar.tsx # Header met dienst/patient -β”‚ β”œβ”€β”€ chat-panel.tsx # πŸ†• Chat messages -β”‚ β”œβ”€β”€ chat-input.tsx # Herzien: conversational -β”‚ └── artifact-area.tsx # πŸ†• Artifact container -β”œβ”€β”€ chat/ -β”‚ β”œβ”€β”€ chat-message.tsx # πŸ†• Individual message -β”‚ β”œβ”€β”€ chat-action-link.tsx # πŸ†• Clickable action -β”‚ └── streaming-indicator.tsx # πŸ†• Typing dots -β”œβ”€β”€ artifacts/ -β”‚ β”œβ”€β”€ artifact-container.tsx # πŸ†• Wrapper met tabs -β”‚ β”œβ”€β”€ dagnotitie-block.tsx # Bestaand -β”‚ β”œβ”€β”€ zoeken-block.tsx # Bestaand -β”‚ β”œβ”€β”€ overdracht-block.tsx # Herzien: met filtering UI -β”‚ β”œβ”€β”€ rapportage-block.tsx # Bestaand -β”‚ └── patient-context-card.tsx # Bestaand -└── shared/ - β”œβ”€β”€ linked-evidence.tsx # πŸ†• Bron-verwijzing component - └── relevance-badge.tsx # πŸ†• "Behandelrelevant" indicator -``` - ---- - -## 9. UI Specificaties - -### 9.1 Layout Breakpoints - -| Viewport | Chat Panel | Artifact Area | -|----------|------------|---------------| -| Desktop (>1200px) | 40% | 60% | -| Tablet (768-1200px) | 45% | 55% | -| Mobile (<768px) | Full screen toggle | Full screen toggle | - -### 9.2 Chat Message Styling - -| Element | User Message | Assistant Message | -|---------|--------------|-------------------| -| Alignment | Right | Left | -| Background | Amber-50 (#FFFBEB) | Slate-100 (#F1F5F9) | -| Border | Amber-200 | Slate-200 | -| Max width | 80% | 80% | -| Border radius | 16px (top-right: 4px) | 16px (top-left: 4px) | - -### 9.3 Artifact Animation - -```css -/* Slide-in from right */ -@keyframes artifact-enter { - from { - transform: translateX(100%); - opacity: 0; - } - to { - transform: translateX(0); - opacity: 1; - } -} - -.artifact-enter { - animation: artifact-enter 200ms ease-out; -} -``` - ---- - -## 10. Bijlagen & Referenties - -🎯 **Doel:** Linken naar overige documenten. - -### Project Documentatie -- PRD Ephemeral UI: `nextgen-epd-prd-ephemeral-ui-epd.md` -- UX/UI Specs: `swift-ux-v2.1.md` -- UX Research: `nextgen-epd-onderzoeksverslag-ux-ui-patterns.md` -- Bouwplan: `bouwplan-swift-v2.md` -- Project Status: `PROJECT-STATUS-2024-12-27.md` - -### Externe Referenties -- [ChatGPT Canvas UX Analysis](https://altar.io/next-gen-of-human-ai-collaboration/) -- [Claude Artifacts Documentation](https://docs.anthropic.com) -- [Abridge Linked Evidence](https://www.abridge.com/product) -- [GGZ Zorgstandaarden](https://www.ggzstandaarden.nl) - ---- - -## Wijzigingslog - -| Versie | Datum | Wijzigingen | -|--------|-------|-------------| -| v2.0 | 23-12-2024 | Command Center met ephemeral blocks | -| v2.1 | 23-12-2024 | Prioriteitenlijst, intent mapping, P3 blocks | -| v3.0 | 27-12-2024 | **Redesign:** Chat + Artifact interface, Swift Assistent conversatie, AI-filtering voor psychiater | diff --git a/docs/swift/haalbaarheidsanalyse-v3.md b/docs/swift/haalbaarheidsanalyse-v3.md deleted file mode 100644 index 9b11314..0000000 --- a/docs/swift/haalbaarheidsanalyse-v3.md +++ /dev/null @@ -1,437 +0,0 @@ -# πŸ“Š Haalbaarheidsanalyse: Swift Medical Scribe v3.0 - -**Datum:** 27-12-2024 -**Document:** `fo-swift-medical-scribe-v3.md` -**Auteur:** AI Assistant - ---- - -## Executive Summary - -Het v3.0 redesign van Swift naar een medical scribe chatbot interface is **haalbaar**, maar vereist significante architecturale wijzigingen. De bestaande foundation (Command Center, blocks, intent classification) kan worden hergebruikt, maar de conversatie-laag en split-screen layout zijn nieuw. - -**Kernbevindingen:** -- βœ… **Sterke foundation:** Bestaande blocks, intent API, en voice input kunnen worden hergebruikt -- ⚠️ **Grote wijzigingen:** Conversatie-interface, chat API, en split-screen layout zijn nieuw -- βœ… **AI-infrastructuur:** Streaming chat API bestaat al (docs-chat), kan worden aangepast -- ⚠️ **Complexiteit:** Conversatiegeschiedenis en context management vereisen nieuwe state management - -**Geschatte effort:** 6-8 weken (1 developer, full-time) - ---- - -## 1. Inventarisatie Bestaande Componenten - -### 1.1 βœ… Wat bestaat al en kan worden hergebruikt - -| Component | Status | Locatie | Hergebruik | -|-----------|--------|---------|------------| -| **Command Center** | βœ… Done | `components/swift/command-center/` | ⚠️ Layout wijzigen naar split-screen | -| **Context Bar** | βœ… Done | `components/swift/command-center/context-bar.tsx` | βœ… Direct hergebruikbaar | -| **Blocks (Artifacts)** | βœ… Done | `components/swift/blocks/` | βœ… Direct herbruikbaar | -| **Intent Classification** | βœ… Done | `/api/intent/classify` | βœ… Herbruikbaar, maar moet worden uitgebreid | -| **Voice Input** | βœ… Done | `lib/swift/use-swift-voice.ts` | βœ… Direct herbruikbaar | -| **Swift Store** | βœ… Done | `stores/swift-store.ts` | ⚠️ Uitbreiden met chat state | -| **Overdracht API** | βœ… Done | `/api/overdracht/generate` | βœ… Bestaat, maar AI-filtering voor psychiater moet worden toegevoegd | -| **Streaming Chat API** | βœ… Bestaat | `/api/docs/chat` | βœ… Pattern kan worden gekopieerd | - -### 1.2 πŸ†• Wat nieuw moet worden gebouwd - -| Component | Complexiteit | Geschatte Effort | -|-----------|-------------|------------------| -| **Chat Panel** | Medium | 1 week | -| **Chat Input (conversational)** | Low | 3 dagen | -| **Chat API (`/api/swift/chat`)** | High | 1.5 week | -| **Artifact Area (split-screen)** | Medium | 1 week | -| **Chat Message Components** | Low | 3 dagen | -| **Conversation History Management** | Medium | 1 week | -| **AI-filtering voor psychiater** | Medium | 1 week | -| **Linked Evidence UI** | Low | 3 dagen | - -**Totaal nieuwe componenten:** ~6-7 weken - ---- - -## 2. Gedetailleerde Analyse per Sectie - -### 2.1 Command Center β†’ Split-Screen Layout - -**Huidige situatie:** -- 4-zone layout: Context Bar | Canvas Area | Recent Strip | Command Input -- Blocks verschijnen in Canvas Area (centered, full-width) - -**Vereiste wijziging:** -- Split-screen: Chat Panel (40%) links, Artifact Area (60%) rechts -- Recent Strip kan worden verwijderd of geΓ―ntegreerd in chat - -**Haalbaarheid:** βœ… **Goed** -- Layout wijziging is relatief eenvoudig met CSS Grid/Flexbox -- Bestaande blocks blijven werken, alleen positioning wijzigt -- **Effort:** 3-5 dagen - -**Risico's:** -- Responsive design voor mobile/tablet vereist toggle tussen chat en artifact -- Keyboard shortcuts moeten worden aangepast - ---- - -### 2.2 Chat Panel & Conversatie - -**Huidige situatie:** -- Geen chat interface -- Command Input stuurt direct naar intent classification - -**Vereiste wijziging:** -- Nieuwe Chat Panel component met message bubbles -- Conversatiegeschiedenis (max 100 messages) -- Streaming responses (zoals docs-chat) - -**Haalbaarheid:** βœ… **Goed** -- Pattern bestaat al in `components/docs-chat/` -- `use-docs-chat.ts` hook kan worden aangepast voor Swift -- **Effort:** 1 week - -**Risico's:** -- Performance bij lange conversaties (pagination nodig) -- State management voor chat history (Zustand store uitbreiden) - ---- - -### 2.3 Medical Scribe Chat API - -**Huidige situatie:** -- `/api/intent/classify` retourneert alleen intent + entities -- Geen conversatie, geen streaming - -**Vereiste wijziging:** -- Nieuwe `/api/swift/chat` endpoint -- Streaming responses (SSE) -- Conversatiegeschiedenis als input -- Action objects in response (intent + entities + artifact prefill) - -**Haalbaarheid:** ⚠️ **Middelmatig** -- Pattern bestaat in `/api/docs/chat` (streaming met Claude) -- Moet worden uitgebreid met: - - Intent detection tijdens conversatie - - Action object generation - - Context management (activePatient, shift, recentActions) -- **Effort:** 1.5 week - -**Risico's:** -- AI prompt engineering voor medical scribe persona -- Performance bij hoge load (rate limiting nodig) -- Kosten (Claude API calls per message) - -**Aanbeveling:** -```typescript -// Hybrid approach: local intent first, AI voor conversatie -1. Local pattern matching (<50ms) β†’ direct action -2. Als geen match β†’ AI chat API met conversatie context -3. AI detecteert intent + genereert response + action object -``` - ---- - -### 2.4 Intent Engine (Hybrid) - -**Huidige situatie:** -- Two-tier: local patterns β†’ AI fallback -- Werkt goed voor directe commando's - -**Vereiste wijziging:** -- Local patterns blijven voor snelle acties -- AI chat API voor conversatie + follow-up vragen -- Confidence thresholds voor artifact opening - -**Haalbaarheid:** βœ… **Goed** -- Bestaande intent classifier blijft werken -- Chat API gebruikt AI voor conversatie + intent detection -- **Effort:** 3 dagen (integratie) - ---- - -### 2.5 Artifact Area (Split-Screen) - -**Huidige situatie:** -- Blocks verschijnen centered in Canvas Area -- EΓ©n block tegelijk - -**Vereiste wijziging:** -- Artifacts rechts (60% width) -- Meerdere artifacts mogelijk (tabs, max 3) -- Slide-in animatie van rechts - -**Haalbaarheid:** βœ… **Goed** -- Bestaande blocks blijven werken -- Nieuwe wrapper component met tabs -- **Effort:** 1 week - -**Risico's:** -- State management voor meerdere open artifacts -- Tab switching UX - ---- - -### 2.6 AI-Filtering voor Psychiater - -**Huidige situatie:** -- `/api/overdracht/generate` genereert samenvatting voor alle notities -- Geen filtering op behandelrelevantie - -**Vereiste wijziging:** -- AI-filtering: alleen behandelrelevante notities -- Linked evidence: elke zin linkt naar bronnotitie -- UI: "Behandelrelevant" vs "Geen bijzonderheden" secties - -**Haalbaarheid:** ⚠️ **Middelmatig** -- AI prompt moet worden uitgebreid met filtering criteria -- Linked evidence vereist tracking van bronnotities per zin -- **Effort:** 1 week - -**Risico's:** -- AI filtering accuracy (false negatives = belangrijke info gemist) -- Linked evidence parsing (welke zin komt van welke notitie?) - -**Aanbeveling:** -- Start met simpele keyword-based filtering als fallback -- AI filtering als primary, met optie om "alles te tonen" - ---- - -### 2.7 Store Uitbreiding - -**Huidige situatie:** -```typescript -interface SwiftStore { - activePatient: Patient | null; - activeBlock: BlockType | null; - prefillData: BlockPrefillData; - // ... geen chat state -} -``` - -**Vereiste wijziging:** -```typescript -interface SwiftStore { - // Bestaand - activePatient: Patient | null; - activeBlock: BlockType | null; - - // Nieuw: Chat state - chatMessages: ChatMessage[]; - isStreaming: boolean; - pendingAction: Action | null; - - // Nieuw: Artifact state - openArtifacts: Artifact[]; // Max 3 - activeArtifactId: string | null; -} -``` - -**Haalbaarheid:** βœ… **Goed** -- Zustand store is makkelijk uit te breiden -- **Effort:** 2 dagen - ---- - -## 3. Technische Risico's & Uitdagingen - -### 3.1 πŸ”΄ Hoge Risico's - -| Risico | Impact | Mitigatie | -|--------|--------|-----------| -| **AI Prompt Engineering** | High | Medical scribe persona moet natuurlijk klinken, maar ook betrouwbaar zijn. Iteratief testen met echte gebruikers. | -| **Performance bij lange conversaties** | Medium | Pagination voor chat history, max 100 messages in view. Virtual scrolling overwegen. | -| **AI Kosten** | Medium | Rate limiting, caching van responses waar mogelijk. Local patterns gebruiken voor snelle acties. | -| **State Management Complexiteit** | Medium | Duidelijke scheiding tussen chat state en artifact state. UseReducer overwegen voor complexe state. | - -### 3.2 🟑 Middelmatige Risico's - -| Risico | Impact | Mitigatie | -|--------|--------|-----------| -| **Responsive Design** | Medium | Mobile: toggle tussen chat en artifact. Tablet: 45/55 split. | -| **Linked Evidence Parsing** | Medium | AI moet structured output geven met bronverwijzingen per zin. Fallback: keyword matching. | -| **Conversatie Context Verlies** | Low | Context manager bewaart actieve patiΓ«nt, shift, recente acties. Max 20 messages in API call. | - -### 3.3 🟒 Lage Risico's - -| Risico | Impact | Mitigatie | -|--------|--------|-----------| -| **Block Migratie** | Low | Bestaande blocks blijven werken, alleen wrapper wijzigt. | -| **Voice Input** | Low | Bestaande implementatie blijft werken. | - ---- - -## 4. Migratie Strategie - -### 4.1 Fase 1: Foundation (Week 1-2) -- βœ… Split-screen layout implementeren -- βœ… Chat Panel component bouwen -- βœ… Store uitbreiden met chat state -- βœ… Basis chat API endpoint - -**Deliverable:** Werkende split-screen met chat (zonder AI) - -### 4.2 Fase 2: Chat API & Conversatie (Week 3-4) -- βœ… Medical scribe chat API implementeren -- βœ… Streaming responses -- βœ… Intent detection in conversatie -- βœ… Action object generation - -**Deliverable:** Werkende conversatie met artifact opening - -### 4.3 Fase 3: Artifact Area (Week 5) -- βœ… Artifact Area component met tabs -- βœ… Meerdere artifacts ondersteuning -- βœ… Slide-in animaties - -**Deliverable:** Meerdere artifacts tegelijk mogelijk - -### 4.4 Fase 4: AI-Filtering & Polish (Week 6-7) -- βœ… AI-filtering voor psychiater overdracht -- βœ… Linked evidence UI -- βœ… Error handling & edge cases -- βœ… Performance optimalisatie - -**Deliverable:** Volledige v3.0 functionaliteit - -### 4.5 Fase 5: Testing & Refinement (Week 8) -- βœ… User testing -- βœ… Bug fixes -- βœ… Performance tuning -- βœ… Documentatie - -**Deliverable:** Production-ready v3.0 - ---- - -## 5. Aanbevelingen - -### 5.1 βœ… Doen - -1. **Hergebruik bestaande patterns** - - Kopieer `use-docs-chat.ts` hook als basis voor Swift chat - - Hergebruik streaming pattern van `/api/docs/chat` - -2. **Incrementele migratie** - - Behoud oude Command Center tijdens ontwikkeling - - Feature flag voor nieuwe interface - - A/B testing mogelijkheid - -3. **Local-first approach** - - Gebruik local patterns voor snelle acties (zoals nu) - - AI alleen voor conversatie en complexe queries - -4. **Performance monitoring** - - Track AI API response times - - Monitor chat history size - - Alert bij lange conversaties - -### 5.2 ⚠️ Overwegen - -1. **Hybrid Intent Detection** - - Local patterns voor P1 intents (dagnotitie, zoeken) - - AI chat voor P2 intents en follow-up vragen - -2. **Conversation Context Window** - - Max 20 messages in API call (zoals gespecificeerd) - - Summarization voor oudere messages - -3. **Artifact Persistence** - - Sla open artifacts op in localStorage - - Herstel bij page reload - -### 5.3 ❌ Niet Doen (YAGNI) - -1. **Geen volledige rewrite** - - Bestaande blocks blijven werken - - Alleen wrapper en layout wijzigen - -2. **Geen nieuwe voice engine** - - Bestaande Deepgram implementatie is voldoende - -3. **Geen real-time collaboration** - - Niet nodig voor MVP - ---- - -## 6. Conclusie - -### Haalbaarheid: βœ… **HAALBAAR** - -Het v3.0 redesign is haalbaar binnen 6-8 weken met 1 developer. De bestaande foundation is sterk en kan worden hergebruikt. De grootste uitdagingen zijn: - -1. **Chat API ontwikkeling** (1.5 week) -2. **AI prompt engineering** (iteratief, doorlopend) -3. **State management complexiteit** (manageable met Zustand) - -### Success Criteria - -- [ ] Split-screen layout werkt op desktop/tablet/mobile -- [ ] Conversatie voelt natuurlijk (niet robotisch) -- [ ] Artifacts openen binnen 2 seconden na intent detection -- [ ] AI-filtering voor psychiater heeft >90% accuracy -- [ ] Performance: <500ms voor local patterns, <3s voor AI responses - -### Volgende Stappen - -1. βœ… **Go/No-Go beslissing** op basis van deze analyse -2. βœ… **Bouwplan v3.0** opstellen met gedetailleerde stories -3. βœ… **Sprint planning** voor Fase 1-5 -4. βœ… **AI prompt engineering** starten (parallel met development) - ---- - -## Bijlagen - -### A. Bestaande Componenten Overzicht - -``` -components/swift/ -β”œβ”€β”€ command-center/ -β”‚ β”œβ”€β”€ command-center.tsx βœ… Herbruikbaar (layout wijzigen) -β”‚ β”œβ”€β”€ context-bar.tsx βœ… Direct herbruikbaar -β”‚ β”œβ”€β”€ command-input.tsx ⚠️ Aanpassen naar chat input -β”‚ β”œβ”€β”€ canvas-area.tsx ⚠️ Vervangen door artifact-area -β”‚ └── recent-strip.tsx ❓ Verwijderen of integreren -β”œβ”€β”€ blocks/ -β”‚ β”œβ”€β”€ dagnotitie-block.tsx βœ… Direct herbruikbaar -β”‚ β”œβ”€β”€ zoeken-block.tsx βœ… Direct herbruikbaar -β”‚ β”œβ”€β”€ overdracht-block.tsx ⚠️ Uitbreiden met AI-filtering -β”‚ └── patient-context-card.tsx βœ… Direct herbruikbaar -``` - -### B. Nieuwe Componenten Overzicht - -``` -components/swift/ -β”œβ”€β”€ chat/ πŸ†• Nieuw -β”‚ β”œβ”€β”€ chat-panel.tsx -β”‚ β”œβ”€β”€ chat-message.tsx -β”‚ β”œβ”€β”€ chat-action-link.tsx -β”‚ └── streaming-indicator.tsx -β”œβ”€β”€ artifacts/ πŸ†• Nieuw -β”‚ β”œβ”€β”€ artifact-container.tsx (wrapper met tabs) -β”‚ └── artifact-tab.tsx -└── shared/ πŸ†• Nieuw - β”œβ”€β”€ linked-evidence.tsx - └── relevance-badge.tsx -``` - -### C. API Routes Overzicht - -``` -app/api/ -β”œβ”€β”€ swift/ πŸ†• Nieuw -β”‚ └── chat/ -β”‚ └── route.ts (medical scribe chatbot) -β”œβ”€β”€ intent/ -β”‚ └── classify/ βœ… Bestaat (herbruikbaar) -└── overdracht/ - └── generate/ βœ… Bestaat (uitbreiden met filtering) -``` - ---- - -**Einde analyse** - diff --git a/docs/swift/implementation-e5-s1-action-routing.md b/docs/swift/implementation-e5-s1-action-routing.md deleted file mode 100644 index c998109..0000000 --- a/docs/swift/implementation-e5-s1-action-routing.md +++ /dev/null @@ -1,224 +0,0 @@ -# Epic 5.S1 Implementation: Action Routing - -**Story**: E5.S1 - Action routing -**Date**: 2025-12-27 -**Status**: βœ… Complete -**Story Points**: 2 SP - ---- - -## 🎯 Objective - -Implement intent routing logic that maps agenda intents to the AgendaBlock artifact with the appropriate mode and prefill data. - ---- - -## πŸ“ Implementation Summary - -### 1. Updated Action Parser Schemas - -**File**: `lib/swift/action-parser.ts` - -Added agenda intents to validation schemas: -- `agenda_query` -- `create_appointment` -- `cancel_appointment` -- `reschedule_appointment` - -### 2. Created Intent Routing Function - -**Function**: `routeIntentToArtifact(intent, entities, confidence)` - -**Purpose**: Maps intents to artifact configurations with: -- Artifact type -- Title -- Prefill data - -**Logic**: -```typescript -if (confidence < 0.7) return null; // Trigger fallback - -switch (intent) { - case 'agenda_query': - return { type: 'agenda_query', title: 'Agenda', prefill: { dateRange } }; - - case 'create_appointment': - if (!patientName && !patientId) return null; // Missing required entity - return { type: 'create_appointment', title: 'Nieuwe afspraak', prefill: {...} }; - - case 'cancel_appointment': - return { type: 'cancel_appointment', title: 'Afspraak annuleren', prefill: {...} }; - - case 'reschedule_appointment': - if (!identifier) return null; // Need to know which appointment - return { type: 'reschedule_appointment', title: 'Afspraak verzetten', prefill: {...} }; - - // ... other intents (dagnotitie, zoeken, overdracht) -} -``` - -**Key Features**: -- βœ… Confidence threshold (0.7) enforcement -- βœ… Required entity validation (patient for create, identifier for reschedule) -- βœ… Returns null to trigger clarification when needed -- βœ… Proper prefill data extraction for each intent - -### 3. Updated Command Input - -**File**: `components/swift/command-center/command-input.tsx` - -**Changes**: -1. Import `routeIntentToArtifact` from action-parser -2. Add `openArtifact` to store hooks -3. Replace legacy `openBlock` logic with routing: - -```typescript -// OLD (direct block opening): -if (intent !== 'unknown' && confidence >= 0.5) { - openBlock(intent as BlockType, entities); -} - -// NEW (routing with artifact system): -const artifactConfig = routeIntentToArtifact(intent, entities, confidence); -if (artifactConfig) { - openArtifact({ - type: artifactConfig.type, - title: artifactConfig.title, - prefill: artifactConfig.prefill, - }); -} -``` - ---- - -## πŸ”‘ Key Routing Rules - -| Intent | Artifact Type | Required Entities | Mode | -|--------|---------------|-------------------|------| -| `agenda_query` | `agenda_query` | None | List view with date filter | -| `create_appointment` | `create_appointment` | `patientName` OR `patientId` | Create form | -| `cancel_appointment` | `cancel_appointment` | None | Cancel view (may need disambiguation) | -| `reschedule_appointment` | `reschedule_appointment` | `identifier` | Reschedule form | - ---- - -## πŸ“Š Confidence Thresholds - -| Confidence | Action | Example | -|------------|--------|---------| -| **β‰₯ 0.7** | Open artifact directly | "afspraken vandaag" β†’ AgendaBlock opens | -| **< 0.7** | Show fallback picker | Low confidence β†’ User chooses intent manually | -| **Missing required entity** | Show fallback picker | "maak afspraak" (no patient) β†’ Clarification needed | - ---- - -## πŸ”„ Data Flow - -``` -User Input - ↓ -Intent Classification API (/api/intent/classify) - ↓ -{ intent, entities, confidence } - ↓ -routeIntentToArtifact() - ↓ -Artifact Config { type, title, prefill } OR null - ↓ -openArtifact() OR openBlock('fallback') - ↓ -AgendaBlock renders with prefilled data -``` - ---- - -## πŸ“ Files Modified - -``` -lib/swift/action-parser.ts -β”œβ”€β”€ Updated ActionSchema with agenda intents -β”œβ”€β”€ Updated artifact type enum -β”œβ”€β”€ Added routeIntentToArtifact() function -└── Updated validateArtifactType() for agenda intents - -components/swift/command-center/command-input.tsx -β”œβ”€β”€ Import routeIntentToArtifact -β”œβ”€β”€ Use openArtifact from store -└── Replace direct block opening with routing logic -``` - ---- - -## βœ… Acceptance Criteria - -| Criterion | Status | Notes | -|-----------|--------|-------| -| Agenda intents open AgendaBlock | βœ… | Via routing function | -| Correct mode selected | βœ… | Based on intent type | -| Prefill data passed correctly | βœ… | Mapped from entities | -| Confidence threshold enforced | βœ… | < 0.7 shows fallback | -| Required entities validated | βœ… | Returns null when missing | -| TypeScript type safety | βœ… | No compilation errors | - ---- - -## πŸ§ͺ Testing Scenarios - -### Scenario 1: High Confidence Agenda Query -**Input**: "afspraken vandaag" -**Expected**: -- Intent: `agenda_query` -- Confidence: ~0.95 -- Result: AgendaBlock opens in list mode with today's date range - -### Scenario 2: Create Appointment with Patient -**Input**: "maak afspraak jan morgen 14:00" -**Expected**: -- Intent: `create_appointment` -- Entities: `{ patientName: "jan", datetime: {...} }` -- Result: AgendaBlock opens in create mode with prefilled patient and time - -### Scenario 3: Create Appointment without Patient (Missing Entity) -**Input**: "maak afspraak morgen 14:00" -**Expected**: -- Intent: `create_appointment` -- Entities: `{ datetime: {...} }` (no patient) -- Result: FallbackPicker opens (routing returns null due to missing required entity) - -### Scenario 4: Low Confidence -**Input**: "agenda ding morgen" -**Expected**: -- Intent: `agenda_query` (maybe) -- Confidence: < 0.7 -- Result: FallbackPicker opens (routing returns null due to low confidence) - -### Scenario 5: Reschedule with Identifier -**Input**: "verzet 14:00 naar 15:00" -**Expected**: -- Intent: `reschedule_appointment` -- Entities: `{ identifier: {...}, newDatetime: {...} }` -- Result: AgendaBlock opens in reschedule mode - ---- - -## πŸš€ Next Steps - -1. **E5.S2**: Update chat API prompt to include agenda intent examples -2. **E5.S3**: Add error state handling with fallback links -3. **E6**: Manual QA testing of complete agenda flow - ---- - -## πŸ’‘ Lessons Learned - -1. **Artifact System**: Modern approach using `openArtifact()` is cleaner than legacy `openBlock()` -2. **Centralized Routing**: Single function makes intent mapping maintainable and testable -3. **Validation Early**: Checking required entities in routing prevents incomplete forms -4. **Confidence Thresholds**: 0.7 threshold balances automation with user control -5. **Type Safety**: TypeScript schemas ensure consistency across intent types - ---- - -**Implementation Status**: βœ… Complete -**Ready for**: E5.S2 (Chat prompt update) -**Estimated Testing Time**: 15-20 minutes (manual testing with various inputs) diff --git a/docs/swift/implementation-e5-s2-chat-prompt.md b/docs/swift/implementation-e5-s2-chat-prompt.md deleted file mode 100644 index dd05f4e..0000000 --- a/docs/swift/implementation-e5-s2-chat-prompt.md +++ /dev/null @@ -1,325 +0,0 @@ -# Epic 5.S2 Implementation: Chat Prompt Update - -**Story**: E5.S2 - Chat prompt update -**Date**: 2025-12-27 -**Status**: βœ… Complete -**Story Points**: 2 SP - ---- - -## 🎯 Objective - -Update the Swift chat API system prompt to include agenda intent descriptions, entity extraction rules, and action format examples. - ---- - -## πŸ“ Implementation Summary - -### File Modified - -**`app/api/swift/chat/route.ts`** - Function: `buildMedicalScribePrompt()` - -### Changes Made - -#### 1. Added Agenda Intents to P2 Section - -Added 4 new agenda intents to the P2 (belangrijk, middenfrequent) section: - -**agenda_query** - Afspraken opvragen -- Triggers: "afspraken vandaag", "agenda morgen", "wat is mijn volgende afspraak", "afspraken deze week" -- Entities: `dateRange` (vandaag/morgen/deze week/volgende week) -- Action: Toon lijst van afspraken in AgendaBlock - -**create_appointment** - Nieuwe afspraak maken -- Triggers: "maak afspraak [patient]", "plan intake [patient]", "afspraak maken met [patient] [datum] [tijd]" -- Entities: `patientName`, `datetime`, `appointmentType`, `location` -- Required: `patientName` OR `patientId`, `datetime` -- Optional: `appointmentType` (default: behandeling), `location` (default: praktijk) -- Action: Open create form met pre-fill - -**cancel_appointment** - Afspraak annuleren -- Triggers: "annuleer afspraak [patient]", "cancel [tijd]", "afspraak van [patient] annuleren" -- Entities: `identifier` (patient naam/tijd combinatie voor matching) -- Action: Toon confirmation dialog, bij meerdere matches: disambiguation - -**reschedule_appointment** - Afspraak verzetten -- Triggers: "verzet afspraak [patient]", "verzet [oude tijd] naar [nieuwe tijd]", "[patient] naar [nieuwe datum]" -- Entities: `identifier`, `newDatetime` -- Required: `identifier` -- Action: Toon edit form met oude en nieuwe tijd - -#### 2. Extended Clarification Questions - -Added agenda-specific clarification examples: -- "Voor welke datum wil je de afspraak maken?" (datum ontbreekt bij create_appointment) -- "Op welk tijdstip?" (tijd ontbreekt bij create_appointment) -- "Welke afspraak wil je verzetten?" (identifier onduidelijk bij reschedule/cancel) - -#### 3. Added Agenda Examples - -**Voorbeeld 5: Agenda query** -```json -{ - "type": "action", - "intent": "agenda_query", - "entities": { - "dateRange": { - "start": "2025-12-27", - "end": "2025-12-27", - "label": "vandaag" - } - }, - "confidence": 0.98, - "artifact": { - "type": "agenda_query", - "prefill": { - "dateRange": {...} - } - } -} -``` - -**Voorbeeld 6: Afspraak maken (compleet)** -```json -{ - "type": "action", - "intent": "create_appointment", - "entities": { - "patientName": "Jan", - "datetime": { - "date": "2025-12-28", - "time": "14:00" - }, - "appointmentType": "behandeling", - "location": "praktijk" - }, - "confidence": 0.95, - "artifact": { - "type": "create_appointment", - "prefill": {...} - } -} -``` - -**Voorbeeld 7: Afspraak maken (incompleet)** -User: "Plan intake Marie" -Response: "Voor welke datum en tijd wil je de intake voor Marie plannen?" -(Geen JSON action omdat datetime ontbreekt) - -**Voorbeeld 8: Afspraak verzetten** -```json -{ - "type": "action", - "intent": "reschedule_appointment", - "entities": { - "identifier": { - "type": "time", - "time": "14:00" - }, - "newDatetime": { - "date": "2025-12-27", - "time": "15:00" - } - }, - "confidence": 0.92, - "artifact": { - "type": "reschedule_appointment", - "prefill": {...} - } -} -``` - ---- - -## πŸ”‘ Key Prompt Additions - -### Entity Structure for Agenda Intents - -**dateRange** (agenda_query): -```json -{ - "start": "YYYY-MM-DD", - "end": "YYYY-MM-DD", - "label": "vandaag" | "morgen" | "deze week" | "volgende week" -} -``` - -**datetime** (create_appointment, reschedule_appointment): -```json -{ - "date": "YYYY-MM-DD", - "time": "HH:mm" -} -``` - -**identifier** (cancel_appointment, reschedule_appointment): -```json -{ - "type": "patient" | "time" | "both", - "patientName"?: "string", - "patientId"?: "uuid", - "time"?: "HH:mm", - "date"?: "YYYY-MM-DD", - "encounterId"?: "uuid" -} -``` - -**appointmentType** (create_appointment): -- intake -- behandeling (default) -- follow-up -- telefonisch -- huisbezoek -- online -- crisis - -**location** (create_appointment): -- praktijk (default) -- online -- thuis - ---- - -## βœ… Acceptance Criteria - -| Criterion | Status | Notes | -|-----------|--------|-------| -| Agenda intents described in prompt | βœ… | 4 intents added to P2 section | -| Entity extraction rules documented | βœ… | All entities with types and defaults | -| Required vs optional entities specified | βœ… | Clear for each intent | -| Clarification question examples | βœ… | 3 new agenda-specific examples | -| Action format examples | βœ… | 4 complete examples with JSON | -| Confidence thresholds mentioned | βœ… | Inherited from base prompt (β‰₯0.7) | -| TypeScript compilation | βœ… | 0 errors | - ---- - -## πŸ“Š Prompt Structure - -The updated prompt now includes: - -``` -Je rol -β”œβ”€β”€ Kernkwaliteiten -└── Tone of voice - -Wat je DOET -β”œβ”€β”€ 1. Intents herkennen -β”‚ β”œβ”€β”€ P1 Intents (dagnotitie, zoeken, overdracht) -β”‚ └── P2 Intents (rapportage, agenda_query, create_appointment, -β”‚ cancel_appointment, reschedule_appointment) ✨ NEW -β”œβ”€β”€ 2. Verduidelijkingsvragen stellen (+ agenda examples) ✨ UPDATED -β”œβ”€β”€ 3. Action objects genereren -└── 4. Follow-up conversatie - -Wat je NIET doet -Context die beschikbaar is - -Voorbeelden -β”œβ”€β”€ Voorbeeld 1-4 (bestaand) -β”œβ”€β”€ Voorbeeld 5: Agenda query ✨ NEW -β”œβ”€β”€ Voorbeeld 6: Afspraak maken (compleet) ✨ NEW -β”œβ”€β”€ Voorbeeld 7: Afspraak maken (incompleet) ✨ NEW -└── Voorbeeld 8: Afspraak verzetten ✨ NEW - -Error Handling -``` - ---- - -## πŸ§ͺ Testing Scenarios - -### Scenario 1: Agenda Query - High Confidence -**Input**: "afspraken vandaag" -**Expected Claude Response**: -- Text: "Ik toon je de afspraken voor vandaag." -- JSON: `{ intent: "agenda_query", confidence: 0.98, entities: { dateRange: {...} } }` - -### Scenario 2: Create Appointment - Complete -**Input**: "maak afspraak met Jan morgen 14:00" -**Expected Claude Response**: -- Text: "Ik maak een afspraak voor Jan morgen om 14:00." -- JSON: `{ intent: "create_appointment", confidence: 0.95, entities: { patientName, datetime } }` - -### Scenario 3: Create Appointment - Incomplete -**Input**: "plan intake Marie" -**Expected Claude Response**: -- Text: "Voor welke datum en tijd wil je de intake voor Marie plannen?" -- JSON: None (confidence < 0.7 due to missing datetime) - -### Scenario 4: Reschedule - Time Based -**Input**: "verzet 14:00 naar 15:00" -**Expected Claude Response**: -- Text: "Ik verzet de afspraak van 14:00 naar 15:00." -- JSON: `{ intent: "reschedule_appointment", confidence: 0.92, entities: { identifier, newDatetime } }` - -### Scenario 5: Cancel - Patient Based -**Input**: "annuleer afspraak Jan" -**Expected Claude Response**: -- Text: Confirmation or disambiguation if multiple Jans -- JSON: `{ intent: "cancel_appointment", entities: { identifier: { type: "patient", patientName: "Jan" } } }` - ---- - -## 🎯 Prompt Engineering Techniques Used - -1. **Clear Intent Definitions**: Each intent has triggers, entities, and actions clearly defined -2. **Required/Optional Distinction**: Helps Claude decide when to ask clarification questions -3. **Confidence Guidance**: Thresholds guide when to open artifacts vs ask questions -4. **Concrete Examples**: 4 full examples with expected JSON structure -5. **Error Cases**: Example 7 shows incomplete input handling -6. **Entity Templates**: JSON structures show exact format expected -7. **Natural Language Triggers**: Multiple trigger phrases per intent - ---- - -## πŸ’‘ Design Decisions - -### Why P2 Instead of P1? -Agenda management is important but not as critical/frequent as dagnotitie (P1). Healthcare workers make notes constantly but schedule appointments less frequently. - -### Why Include Defaults? -- `appointmentType`: "behandeling" (most common case) -- `location`: "praktijk" (most common location) - -This reduces friction - users don't need to specify every detail. - -### Why identifier Instead of encounterId? -The `identifier` structure allows flexible matching: -- By patient name: "annuleer afspraak Jan" -- By time: "cancel 14:00" -- By combination: "verzet Jan's afspraak" - -The backend (Epic 3 API + Epic 4 UI) handles the disambiguation. - -### Why Separate Examples for Complete/Incomplete? -Shows Claude two paths: -1. Complete data β†’ Generate action (Example 6) -2. Incomplete data β†’ Ask question (Example 7) - -This demonstrates the confidence threshold logic clearly. - ---- - -## πŸš€ Next Steps - -**E5.S3** - Error states -- Add error handling for API failures -- Add fallback links to `/epd/agenda` -- Handle offline/network errors gracefully - ---- - -## πŸ“ Files Modified - -``` -βœ… app/api/swift/chat/route.ts (Updated system prompt) -βœ… docs/swift/bouwplan-swift-agenda-planning.md (E5.S2 β†’ Done) -βœ… docs/swift/implementation-e5-s2-chat-prompt.md (New documentation) -``` - ---- - -**Implementation Status**: βœ… Complete -**Ready for**: E5.S3 (Error states) -**Prompt Length**: ~525 lines (was ~325 lines) - increased by ~60% diff --git a/docs/swift/implementation-e5-s3-error-states.md b/docs/swift/implementation-e5-s3-error-states.md deleted file mode 100644 index b9c7b30..0000000 --- a/docs/swift/implementation-e5-s3-error-states.md +++ /dev/null @@ -1,399 +0,0 @@ -# Epic 5.S3 Implementation: Error States - -**Story**: E5.S3 - Error states -**Date**: 2025-12-27 -**Status**: βœ… Complete -**Story Points**: 2 SP - ---- - -## 🎯 Objective - -Add user-friendly error states to agenda functionality with fallback links to `/epd/agenda` and proper error messaging in Dutch. - ---- - -## πŸ“ Implementation Summary - -### New Component Created - -**`components/swift/artifacts/blocks/agenda-error-state.tsx`** - -Created two reusable error components for consistent error handling across all agenda views: - -1. **AgendaErrorState** - Full-page error state with retry button -2. **AgendaErrorAlert** - Inline error alert for forms - -### Updated Components - -**`components/swift/artifacts/blocks/agenda-create-form.tsx`** -- Replaced basic error display with `AgendaErrorAlert` -- Added fallback link to full agenda -- Added dismiss functionality - ---- - -## πŸ”‘ Key Features - -### 1. User-Friendly Error Messages - -The `getUserFriendlyMessage()` function maps technical errors to Dutch user-facing messages: - -| Error Type | Technical | User Message | -|------------|-----------|--------------| -| **Auth (401)** | "401 Unauthorized" | "Je sessie is verlopen. Log opnieuw in." | -| **Not Found (404)** | "404 Not Found" | "De gevraagde afspraak kon niet worden gevonden." | -| **Forbidden (403)** | "403 Forbidden" | "Je hebt geen toegang tot deze afspraak." | -| **Server (500)** | "500 Internal Server Error" | "Er ging iets mis op de server. Probeer het opnieuw." | -| **Network** | "Failed to fetch" | "Geen internetverbinding. Controleer je netwerkverbinding." | -| **Timeout** | "Request timeout" | "De aanvraag duurde te lang. Probeer het opnieuw." | - -### 2. Context-Aware Messages - -Different default messages based on operation context: - -```typescript -context: 'query' β†’ "Er ging iets mis bij het ophalen van je afspraken." -context: 'create' β†’ "Er ging iets mis bij het aanmaken van de afspraak." -context: 'cancel' β†’ "Er ging iets mis bij het annuleren van de afspraak." -context: 'reschedule' β†’ "Er ging iets mis bij het verzetten van de afspraak." -``` - -### 3. Fallback Link to Full Agenda - -All error states include a prominent link to `/epd/agenda`: - -```tsx - -``` - -### 4. Automatic Auth Redirect - -Auth errors (401) automatically redirect to `/login`: - -```typescript -if (isAuthError) { - window.location.href = '/login'; - return null; -} -``` - -### 5. Retry Functionality - -Optional retry button for recoverable errors: - -```tsx - fetchAppointments()} - showFallbackLink={true} - context="query" -/> -``` - -### 6. Dev-Only Technical Details - -In development mode, shows collapsible technical details: - -```tsx -{process.env.NODE_ENV === 'development' && ( -
- Technische details (dev only) -
{error.stack}
-
-)} -``` - ---- - -## πŸ“ Component API - -### AgendaErrorState (Full-Page Error) - -```typescript -interface AgendaErrorStateProps { - error: string | Error; // Error to display - onRetry?: () => void; // Optional retry function - showFallbackLink?: boolean; // Show link to /epd/agenda (default: true) - context?: 'query' | 'create' | 'cancel' | 'reschedule'; -} -``` - -**Usage Example**: -```tsx - refetch()} - context="query" -/> -``` - -### AgendaErrorAlert (Inline Alert) - -```typescript -interface AgendaErrorAlertProps { - error: string | Error; // Error to display - onDismiss?: () => void; // Optional dismiss function - showFallbackLink?: boolean; // Show link to /epd/agenda (default: false) -} -``` - -**Usage Example**: -```tsx -{error && ( - setError(null)} - showFallbackLink={true} - /> -)} -``` - ---- - -## βœ… Acceptance Criteria - -| Criterion | Status | Implementation | -|-----------|--------|----------------| -| User-friendly error messages | βœ… | `getUserFriendlyMessage()` function | -| Dutch language errors | βœ… | All messages in Dutch | -| Fallback link to /epd/agenda | βœ… | "Open volledige agenda" button | -| Auth error redirect | βœ… | Automatic redirect to /login | -| Retry functionality | βœ… | Optional `onRetry` prop | -| Context-aware messages | βœ… | Different messages per operation type | -| Network error handling | βœ… | "Geen internetverbinding" message | -| Server error handling | βœ… | "Er ging iets mis op de server" message | -| TypeScript type safety | βœ… | Full type definitions | -| Consistent styling | βœ… | Matches existing UI patterns | - ---- - -## 🎨 UI Design - -### Full-Page Error State - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ πŸ”΄ (AlertCircle Icon) β”‚ -β”‚ β”‚ -β”‚ Er ging iets mis β”‚ -β”‚ β”‚ -β”‚ Er ging iets mis bij het β”‚ -β”‚ ophalen van je afspraken. β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ πŸ”„ Probeer β”‚ β”‚ πŸ”— Open β”‚ β”‚ -β”‚ β”‚ opnieuw β”‚ β”‚ volledige β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ agenda β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Inline Error Alert - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ ⚠️ Er ging iets mis bij het β”‚ -β”‚ aanmaken van de afspraak. β”‚ -β”‚ Open volledige agenda β†’ [Γ—] β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## πŸ§ͺ Testing Scenarios - -### Scenario 1: Network Error -**Trigger**: Disconnect internet, try to create appointment -**Expected**: -- Message: "Geen internetverbinding. Controleer je netwerkverbinding." -- Retry button enabled -- Fallback link visible - -### Scenario 2: Auth Error (401) -**Trigger**: Expired session token -**Expected**: -- Automatic redirect to `/login` -- No error component shown - -### Scenario 3: Server Error (500) -**Trigger**: Backend returns 500 -**Expected**: -- Message: "Er ging iets mis op de server. Probeer het opnieuw." -- Retry button enabled -- Fallback link visible - -### Scenario 4: Not Found (404) -**Trigger**: Try to cancel non-existent appointment -**Expected**: -- Message: "De gevraagde afspraak kon niet worden gevonden." -- Fallback link visible - -### Scenario 5: Validation Error -**Trigger**: Submit form with invalid data -**Expected**: -- Inline alert with specific validation message -- Fallback link visible -- Dismiss button works - -### Scenario 6: Retry Success -**Trigger**: Network error β†’ reconnect β†’ click retry -**Expected**: -- Retry function called -- Error cleared on success -- Content loads normally - ---- - -## πŸ’‘ Design Decisions - -### Why Two Components? - -1. **AgendaErrorState**: For full-page failures (query, list loading) -2. **AgendaErrorAlert**: For form-level errors (create, cancel, reschedule) - -Different UI patterns for different contexts. - -### Why Auto-Redirect for Auth Errors? - -Auth errors (401) are not user-recoverable in the UI. User must log in again, so immediate redirect provides better UX than showing an error message. - -### Why Show Fallback Link? - -If Swift fails, users can always fall back to the classic agenda UI at `/epd/agenda`. This provides a safety net and reduces frustration. - -### Why Context Parameter? - -Different operations have different error messages. Context makes messages more specific and actionable: -- Query failure β†’ "bij het ophalen" -- Create failure β†’ "bij het aanmaken" -- etc. - -### Why Dev-Only Technical Details? - -Technical stack traces are only useful for developers debugging issues. Production users should see user-friendly messages only. - ---- - -## πŸš€ Error Handling Best Practices - -### 1. Always Use getUserFriendlyMessage() - -```typescript -// ❌ Bad - Technical error exposed to user -setError(error.message); - -// βœ… Good - User-friendly Dutch message -const friendlyMessage = getUserFriendlyMessage(error, 'create'); -setError(friendlyMessage); -``` - -### 2. Provide Context - -```typescript -// ❌ Bad - Generic error - - -// βœ… Good - Context-specific error - -``` - -### 3. Offer Retry When Possible - -```typescript -// ❌ Bad - No recovery path - - -// βœ… Good - User can retry - refetchAppointments()} -/> -``` - -### 4. Use Inline Alerts for Forms - -```typescript -// ❌ Bad - Full-page error for form validation - - -// βœ… Good - Inline alert in form - setError(null)} -/> -``` - ---- - -## πŸ“Š Error Message Coverage - -Covered error types: -- βœ… Authentication (401) -- βœ… Authorization (403) -- βœ… Not Found (404) -- βœ… Server Error (500) -- βœ… Network/Offline -- βœ… Timeout -- βœ… Validation -- βœ… Generic/Unknown - -All with Dutch user-friendly messages. - ---- - -## πŸ“ Files Modified/Created - -``` -βœ… components/swift/artifacts/blocks/agenda-error-state.tsx (NEW - 225 lines) - β”œβ”€β”€ AgendaErrorState component - β”œβ”€β”€ AgendaErrorAlert component - └── getUserFriendlyMessage() utility - -βœ… components/swift/artifacts/blocks/agenda-create-form.tsx (UPDATED) - └── Replaced basic error with AgendaErrorAlert - -βœ… docs/swift/bouwplan-swift-agenda-planning.md (UPDATED) - └── E5.S3 β†’ Done, Epic 5 β†’ Done - -βœ… docs/swift/implementation-e5-s3-error-states.md (NEW) - └── This documentation -``` - ---- - -## 🎯 Impact - -### Before E5.S3 -- ❌ Technical error messages exposed to users -- ❌ No fallback when errors occur -- ❌ No retry functionality -- ❌ Inconsistent error handling - -### After E5.S3 -- βœ… User-friendly Dutch error messages -- βœ… Always provide fallback link to full agenda -- βœ… Retry button for recoverable errors -- βœ… Consistent error handling across all views -- βœ… Auto-redirect for auth errors -- βœ… Context-aware messaging - ---- - -## πŸš€ Next Steps - -**Epic 6 - QA & Docs** -- E6.S1: Manual test checklist (20 scenarios from build plan) -- E6.S2: Docs update (bouwplan + release note) -- E6.S3: Regression checks (Swift + klassieke agenda) - ---- - -**Implementation Status**: βœ… Complete -**Epic 5 Status**: βœ… Complete (All 3 stories done) -**Ready for**: Epic 6 (QA & Documentation) diff --git a/docs/swift/review-epic2.md b/docs/swift/review-epic2.md deleted file mode 100644 index e3a1013..0000000 --- a/docs/swift/review-epic2.md +++ /dev/null @@ -1,34 +0,0 @@ -# Epic 2 Review Findings - -Context: quick review of Epic 2 changes (date/time parsing + agenda entity extraction). - -## Findings -1. High - Patient name detection is too permissive for agenda intents and can misclassify appointment tokens as names. - - Details: create/cancel/reschedule extraction uses `filteredWords` + `isLikelyName`; tokens like "intake", "morgen", or times can be treated as names. - - Impact: wrong patient selected or wrong appointment targeted. - - Files: `lib/swift/entity-extractor.ts` - - Suggestion: skip tokens that parse as date/time or match appointment/location keywords before `isLikelyName`. - -2. Medium - Agenda query defaults to "vandaag" when no date is present (e.g., "volgende afspraak"). - - Impact: only today is queried, which can miss the actual next appointment. - - Files: `lib/swift/entity-extractor.ts` - - Suggestion: leave `dateRange` undefined or mark "from now" and let backend decide. - -3. Medium - `ExtractedEntities` now carries Date objects, but the classify API returns JSON, so Dates become strings. - - Impact: downstream date ops may break on serialized strings. - - Files: `lib/swift/types.ts` (see API flow in `app/api/intent/classify/route.ts`) - - Suggestion: use ISO strings in the DTO or normalize in the API response. - -4. Medium - Type drift between lib and store: the store `ExtractedEntities` does not include the new agenda structures. - - Impact: UI usage may drop agenda fields or require unsafe casting. - - Files: `stores/swift-store.ts`, `lib/swift/types.ts` - - Suggestion: align store types with lib types (or re-export the shared type). - -5. Low - AI fallback path does not run local extractor; low-confidence agenda intents lose structured entities. - - Impact: less reliable agenda prefill when AI is used. - - Files: `app/api/intent/classify/route.ts`, `lib/swift/intent-classifier-ai.ts` - - Suggestion: post-process AI results with local extractor for agenda intents. - -## Testing / QA notes -- Untracked tests exist: `lib/swift/__tests__/date-time-parser.test.ts`. -- Manual scripts exist: `lib/swift/verify-parser.ts` and `lib/swift/verify-entity-extraction.ts` (not run here). diff --git a/docs/swift/test-plan-epic3-backend.md b/docs/swift/test-plan-epic3-backend.md deleted file mode 100644 index 864e6f6..0000000 --- a/docs/swift/test-plan-epic3-backend.md +++ /dev/null @@ -1,474 +0,0 @@ -# Test Plan - Epic 3: Backend Integration - -**Epic**: Swift Agenda Planning - Backend Integration -**Version**: 1.0 -**Date**: 2025-12-27 -**Status**: βœ… Implementation Complete - ---- - -## 🎯 Overview - -Epic 3 implements the backend API layer for Swift Agenda Planning, providing RESTful endpoints for: -- Querying appointments by date range -- Creating new appointments -- Canceling appointments -- Rescheduling appointments -- Searching for patients (for disambiguation) - -All endpoints include: -- βœ… Authentication via Supabase Auth -- βœ… Input validation with Zod schemas -- βœ… Dutch error messages -- βœ… Security checks (user owns the resource) -- βœ… Reuse of existing server actions - ---- - -## πŸ“‹ Implementation Summary - -### Story E3.S1: Agenda Query API βœ… -**File**: `app/api/swift/agenda/route.ts` -- **Endpoint**: `GET /api/swift/agenda?start=YYYY-MM-DD&end=YYYY-MM-DD` -- **Auth**: Required (Supabase) -- **Filters**: Automatically filters by current user's practitioner_id -- **Response**: List of appointments (encounters) with patient details - -### Story E3.S2: Create Appointment API βœ… -**File**: `app/api/swift/agenda/create/route.ts` -- **Endpoint**: `POST /api/swift/agenda/create` -- **Body**: `{ patientId, datetime: { date, time }, type, location, notes? }` -- **Validation**: Date cannot be in past, appointment type and location must be valid -- **Mapping**: - - `type` β†’ FHIR encounter typeCode - - `location` β†’ FHIR classCode (AMB/VR/HH) - - Duration: 1 hour default - -### Story E3.S3: Cancel/Reschedule APIs βœ… -**Files**: -- `app/api/swift/agenda/cancel/route.ts` -- `app/api/swift/agenda/reschedule/route.ts` - -**Cancel Endpoint**: `POST /api/swift/agenda/cancel` -- **Body**: `{ encounterId }` -- **Security**: Verifies user owns the appointment -- **Validation**: Cannot cancel already cancelled appointment -- **Action**: Soft delete (status β†’ 'cancelled') - -**Reschedule Endpoint**: `POST /api/swift/agenda/reschedule` -- **Body**: `{ encounterId, newDatetime: { date, time } }` -- **Security**: Verifies user owns the appointment -- **Validation**: Cannot reschedule to past, cannot reschedule cancelled appointments -- **Duration**: Preserves original appointment duration - -### Story E3.S4: Patient Search API βœ… -**File**: `app/api/swift/patients/search/route.ts` -- **Endpoint**: `GET /api/swift/patients/search?q=` -- **Search**: Fuzzy match on name_family and name_given -- **Limit**: 10 results -- **Response**: Array of patients with id, name, bsn, birthDate - ---- - -## πŸ§ͺ Manual Test Scenarios - -### Test Category 1: Agenda Query (E3.S1) - -#### Test 1.1: Query appointments for today -**Prerequisites**: User is logged in, has appointments for today -```bash -curl -X GET 'http://localhost:3000/api/swift/agenda?start=2025-12-27&end=2025-12-27' \ - -H 'Cookie: ' -``` -**Expected**: -- Status: 200 -- Response: `{ appointments: [...], count: N, dateRange: { start, end } }` -- Appointments filtered by current user - -#### Test 1.2: Query with missing parameters -```bash -curl -X GET 'http://localhost:3000/api/swift/agenda?start=2025-12-27' \ - -H 'Cookie: ' -``` -**Expected**: -- Status: 400 -- Error: "start en end parameters zijn verplicht" - -#### Test 1.3: Query with invalid date format -```bash -curl -X GET 'http://localhost:3000/api/swift/agenda?start=invalid&end=2025-12-27' \ - -H 'Cookie: ' -``` -**Expected**: -- Status: 400 -- Error: "start moet een geldige datum zijn" - -#### Test 1.4: Query without authentication -```bash -curl -X GET 'http://localhost:3000/api/swift/agenda?start=2025-12-27&end=2025-12-27' -``` -**Expected**: -- Status: 401 -- Error: "Niet geautoriseerd. Log opnieuw in." - ---- - -### Test Category 2: Create Appointment (E3.S2) - -#### Test 2.1: Create valid appointment -**Prerequisites**: User is logged in, valid patient ID available -```bash -curl -X POST 'http://localhost:3000/api/swift/agenda/create' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "patientId": "", - "datetime": { - "date": "2025-12-28", - "time": "14:00" - }, - "type": "intake", - "location": "praktijk", - "notes": "Eerste afspraak" - }' -``` -**Expected**: -- Status: 201 -- Response: `{ success: true, encounterId: "", appointment: {...} }` -- Appointment visible in agenda - -#### Test 2.2: Create appointment in the past -```bash -curl -X POST 'http://localhost:3000/api/swift/agenda/create' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "patientId": "", - "datetime": { - "date": "2020-01-01", - "time": "14:00" - }, - "type": "intake", - "location": "praktijk" - }' -``` -**Expected**: -- Status: 400 -- Error: "Kan geen afspraken in het verleden maken" - -#### Test 2.3: Create appointment with invalid type -```bash -curl -X POST 'http://localhost:3000/api/swift/agenda/create' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "patientId": "", - "datetime": { - "date": "2025-12-28", - "time": "14:00" - }, - "type": "invalid_type", - "location": "praktijk" - }' -``` -**Expected**: -- Status: 400 -- Error: "type moet een geldig afspraaktype zijn" - -#### Test 2.4: Create appointment with missing required fields -```bash -curl -X POST 'http://localhost:3000/api/swift/agenda/create' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "patientId": "", - "datetime": { - "date": "2025-12-28" - }, - "type": "intake", - "location": "praktijk" - }' -``` -**Expected**: -- Status: 400 -- Error: Contains validation error about missing time - ---- - -### Test Category 3: Cancel Appointment (E3.S3a) - -#### Test 3.1: Cancel valid appointment -**Prerequisites**: User has an upcoming appointment -```bash -curl -X POST 'http://localhost:3000/api/swift/agenda/cancel' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "encounterId": "" - }' -``` -**Expected**: -- Status: 200 -- Response: `{ success: true, encounterId: "", message: "Afspraak succesvol geannuleerd" }` -- Appointment status updated to 'cancelled' - -#### Test 3.2: Cancel already cancelled appointment -```bash -curl -X POST 'http://localhost:3000/api/swift/agenda/cancel' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "encounterId": "" - }' -``` -**Expected**: -- Status: 400 -- Error: "Deze afspraak is al geannuleerd" - -#### Test 3.3: Cancel non-existent appointment -```bash -curl -X POST 'http://localhost:3000/api/swift/agenda/cancel' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "encounterId": "00000000-0000-0000-0000-000000000000" - }' -``` -**Expected**: -- Status: 404 -- Error: "Afspraak niet gevonden" - -#### Test 3.4: Cancel appointment owned by another user -**Prerequisites**: Have another user's appointment ID -```bash -curl -X POST 'http://localhost:3000/api/swift/agenda/cancel' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "encounterId": "" - }' -``` -**Expected**: -- Status: 403 -- Error: "Je hebt geen toegang tot deze afspraak" - ---- - -### Test Category 4: Reschedule Appointment (E3.S3b) - -#### Test 4.1: Reschedule valid appointment -**Prerequisites**: User has an upcoming appointment -```bash -curl -X POST 'http://localhost:3000/api/swift/agenda/reschedule' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "encounterId": "", - "newDatetime": { - "date": "2025-12-29", - "time": "15:00" - } - }' -``` -**Expected**: -- Status: 200 -- Response: `{ success: true, encounterId: "", appointment: {...}, message: "Afspraak succesvol verzet" }` -- Appointment period_start and period_end updated - -#### Test 4.2: Reschedule to past date -```bash -curl -X POST 'http://localhost:3000/api/swift/agenda/reschedule' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "encounterId": "", - "newDatetime": { - "date": "2020-01-01", - "time": "15:00" - } - }' -``` -**Expected**: -- Status: 400 -- Error: "Kan geen afspraken in het verleden verzetten" - -#### Test 4.3: Reschedule cancelled appointment -```bash -curl -X POST 'http://localhost:3000/api/swift/agenda/reschedule' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "encounterId": "", - "newDatetime": { - "date": "2025-12-29", - "time": "15:00" - } - }' -``` -**Expected**: -- Status: 400 -- Error: "Kan een geannuleerde afspraak niet verzetten" - -#### Test 4.4: Reschedule with preserved duration -**Prerequisites**: Create an appointment with 2-hour duration -```bash -# First, create appointment manually with 2-hour duration -# Then reschedule it -curl -X POST 'http://localhost:3000/api/swift/agenda/reschedule' \ - -H 'Content-Type: application/json' \ - -H 'Cookie: ' \ - -d '{ - "encounterId": "", - "newDatetime": { - "date": "2025-12-29", - "time": "10:00" - } - }' -``` -**Expected**: -- Status: 200 -- Response period_end is 2 hours after period_start (preserves original duration) - ---- - -### Test Category 5: Patient Search (E3.S4) - -#### Test 5.1: Search for existing patient -**Prerequisites**: Patient "Jan de Vries" exists in database -```bash -curl -X GET 'http://localhost:3000/api/swift/patients/search?q=jan' \ - -H 'Cookie: ' -``` -**Expected**: -- Status: 200 -- Response: `{ patients: [{id, name, bsn, birthDate}], count: N, query: "jan" }` -- Results include matching patients - -#### Test 5.2: Search with partial name -```bash -curl -X GET 'http://localhost:3000/api/swift/patients/search?q=vri' \ - -H 'Cookie: ' -``` -**Expected**: -- Status: 200 -- Response includes patients with "vri" in their name (e.g., "de Vries") - -#### Test 5.3: Search with no matches -```bash -curl -X GET 'http://localhost:3000/api/swift/patients/search?q=zzzzzzz' \ - -H 'Cookie: ' -``` -**Expected**: -- Status: 200 -- Response: `{ patients: [], count: 0, query: "zzzzzzz" }` - -#### Test 5.4: Search without query parameter -```bash -curl -X GET 'http://localhost:3000/api/swift/patients/search' \ - -H 'Cookie: ' -``` -**Expected**: -- Status: 400 -- Error: "Query parameter 'q' is verplicht" - -#### Test 5.5: Search with empty query -```bash -curl -X GET 'http://localhost:3000/api/swift/patients/search?q=' \ - -H 'Cookie: ' -``` -**Expected**: -- Status: 400 -- Error: "Zoekterm mag niet leeg zijn" - ---- - -## πŸ” Security Checklist - -| Check | Status | Notes | -|-------|--------|-------| -| All endpoints require authentication | βœ… | Returns 401 if not authenticated | -| User can only access their own appointments | βœ… | Filtered by practitioner_id | -| User cannot cancel/reschedule others' appointments | βœ… | Ownership verification in place | -| Input validation on all endpoints | βœ… | Zod schemas with Dutch error messages | -| SQL injection prevention | βœ… | Using Supabase client with parameterized queries | -| XSS prevention | βœ… | No direct HTML rendering | -| CSRF protection | βœ… | Next.js built-in CSRF protection | - ---- - -## πŸ› Known Issues / Edge Cases - -### Issue 1: Patient Search Query Performance -- **Description**: The patient search uses `ilike` which may be slow on large datasets -- **Mitigation**: Limited to 10 results -- **Future**: Consider adding database index on name_family/name_given - -### Issue 2: Timezone Handling -- **Description**: All dates stored in UTC, client must handle timezone conversion -- **Current**: Using ISO string format -- **Future**: Consider explicit timezone handling in API - -### Issue 3: Appointment Conflicts -- **Description**: No conflict detection when creating/rescheduling appointments -- **Status**: Out of scope for MVP -- **Future**: Add conflict warning in Epic 4 (UI layer) - ---- - -## πŸ“Š Test Results Summary - -| Story | Total Tests | Passed | Failed | Blocked | Coverage | -|-------|-------------|--------|--------|---------|----------| -| E3.S1 | 4 | - | - | - | Auth, Validation, Happy Path | -| E3.S2 | 4 | - | - | - | Validation, Security, Happy Path | -| E3.S3a | 4 | - | - | - | Security, Validation, Happy Path | -| E3.S3b | 4 | - | - | - | Security, Validation, Duration | -| E3.S4 | 5 | - | - | - | Search, Validation, Empty State | -| **Total** | **21** | **TBD** | **TBD** | **TBD** | **All scenarios** | - ---- - -## πŸš€ Next Steps - -After manual testing is complete: - -1. βœ… **Epic 3 Complete** β†’ Move to Epic 4 (AgendaBlock UI) -2. πŸ“ **Update Build Plan** β†’ Mark Epic 3 stories as "Done" -3. πŸ§ͺ **Integration Testing** β†’ Test with actual UI when Epic 4 is ready -4. πŸ“š **API Documentation** β†’ Generate OpenAPI/Swagger docs (optional) - ---- - -## πŸ“ Files Created - -``` -app/api/swift/ -β”œβ”€β”€ agenda/ -β”‚ β”œβ”€β”€ route.ts # E3.S1: Query endpoint -β”‚ β”œβ”€β”€ create/ -β”‚ β”‚ └── route.ts # E3.S2: Create endpoint -β”‚ β”œβ”€β”€ cancel/ -β”‚ β”‚ └── route.ts # E3.S3a: Cancel endpoint -β”‚ └── reschedule/ -β”‚ └── route.ts # E3.S3b: Reschedule endpoint -└── patients/ - └── search/ - └── route.ts # E3.S4: Patient search endpoint -``` - ---- - -## πŸŽ“ Lessons Learned - -1. **Zod Validation**: Use `validation.error.issues` not `validation.error.errors` -2. **Database Column Names**: Check generated types carefully (e.g., `identifier_bsn` vs `bsn`) -3. **Security First**: Always verify resource ownership before mutations -4. **Reuse Actions**: Existing server actions (`getEncounters`, `createEncounter`, etc.) work perfectly -5. **Type Safety**: TypeScript catches errors early - run `pnpm exec tsc` before testing - ---- - -**Test Plan Status**: βœ… Ready for Manual Testing -**Implementation Status**: βœ… Complete (All 4 stories) -**Type Check**: βœ… Passing -**Next Epic**: Epic 4 - AgendaBlock UI diff --git a/docs/swift/v3-redesign-met-huidige-styling.md b/docs/swift/v3-redesign-met-huidige-styling.md deleted file mode 100644 index e392879..0000000 --- a/docs/swift/v3-redesign-met-huidige-styling.md +++ /dev/null @@ -1,666 +0,0 @@ -# 🎨 Swift v3.0 Redesign β€” Van Command Center naar Medical Scribe - -**Datum:** 27-12-2024 -**Versie:** v3.0 Design Specification -**Samengesteld door:** AI Assistant - ---- - -## πŸ“‹ Inhoudsopgave - -1. [Executive Summary](#executive-summary) -2. [Van v2.1 naar v3.0: Wat verandert](#van-v21-naar-v30-wat-verandert) -3. [Huidige UX/Styling (v2.1)](#huidige-uxstyling-v21) -4. [Nieuwe UX/Styling (v3.0)](#nieuwe-uxstyling-v30) -5. [Wat blijft hetzelfde](#wat-blijft-hetzelfde) -6. [Wat wijzigt](#wat-wijzigt) -7. [Implementatie Strategie](#implementatie-strategie) -8. [Design Tokens & Styling](#design-tokens--styling) - ---- - -## Executive Summary - -Swift v3.0 transformeert van een **command-line style interface** naar een **conversational medical scribe chatbot**. De kernprincipes van Ephemeral UI blijven behouden, maar de interactie verschuift van transactioneel naar relationeel. - -### Kernveranderingen - -| Aspect | v2.1 (Command Center) | v3.0 (Medical Scribe) | -|--------|----------------------|----------------------| -| **Input model** | Command-line ("notitie jan medicatie") | Natuurlijke conversatie ("Ik heb medicatie gegeven aan Jan") | -| **UI paradigma** | Centered blocks (ephemeral) | Split-screen: Chat (40%) + Artifacts (60%) | -| **Context** | Per commando | Doorlopende conversatiegeschiedenis | -| **AI rol** | Intent classifier | Converserende medical scribe | -| **Interactie** | Transactioneel (one-shot) | Relationeel (follow-up mogelijk) | - -### Wat blijft - -βœ… **Ephemeral UI principe** β€” UI verschijnt/verdwijnt wanneer nodig -βœ… **Alle bestaande blocks** β€” DagnotatieBlock, ZoekenBlock, OverdrachtBlock, etc. -βœ… **Color system** β€” Shift colors, category colors, design tokens -βœ… **Keyboard shortcuts** β€” ⌘K, Escape, Enter, 1-9 -βœ… **Voice input** β€” Deepgram integratie blijft werken -βœ… **Context Bar** β€” Shift, patient, user info - -### Wat wijzigt - -πŸ”„ **Layout** β€” 4-zone β†’ Split-screen (chat + artifacts) -πŸ”„ **Input** β€” Command input β†’ Chat input met conversatie -πŸ”„ **Canvas Area** β†’ Artifact Area (rechts, 60%) -πŸ”„ **Recent Strip** β†’ Optioneel (kan geΓ―ntegreerd in chat) -πŸ”„ **AI Engine** β€” Intent classifier β†’ Medical scribe chatbot - ---- - -## Van v2.1 naar v3.0: Wat verandert - -### v2.1 Layout (Huidig) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ• Ochtend | 8 ptn Jan de Vries β–Ό πŸ‘€ SV β”‚ ← Context Bar (48px) -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ ACTIVE BLOCK β”‚ β”‚ ← Canvas Area (flex) -β”‚ β”‚ (centered) β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ Recent: [πŸ“ Jan-Med] [πŸ”„ Overdracht] [πŸ” Marie] β”‚ ← Recent Strip (48px) -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ 🎀 Typ of spreek wat je wilt doen... ⌘K β”‚ ← Command Input (64px) -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### v3.0 Layout (Nieuw) - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ πŸ• Ochtend | 8 ptn Jan de Vries β–Ό πŸ‘€ SV β”‚ ← Context Bar (48px) -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ β”‚ -β”‚ CHAT PANEL (40%) β”‚ ARTIFACT AREA (60%) β”‚ -β”‚ β”‚ β”‚ -β”‚ πŸ‘€ "Ik heb net medicatie β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ gegeven aan Jan" β”‚ β”‚ πŸ“ Dagnotitie β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ πŸ€– Ik maak een dagnotitie β”‚ β”‚ PatiΓ«nt: Jan de Vries βœ“ β”‚ β”‚ -β”‚ voor Jan de Vries. β”‚ β”‚ Categorie: Medicatie βœ“ β”‚ β”‚ -β”‚ Categorie: Medicatie. β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β”‚ [Opslaan] β”‚ β”‚ -β”‚ Wil je nog iets β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ toevoegen? β”‚ β”‚ -β”‚ β”‚ β”‚ -β”‚ πŸ‘€ "Nee, opslaan" β”‚ β”‚ -β”‚ β”‚ β”‚ -β”‚ πŸ€– βœ“ Notitie opgeslagen β”‚ β”‚ -β”‚ β”‚ β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ -β”‚ πŸ’¬ Typ of spreek... 🎀 β”‚ β”‚ ← Chat Input (64px) -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - ---- - -## Huidige UX/Styling (v2.1) - -### Layout Zones - -| Zone | Hoogte | Functie | Component | -|------|--------|---------|-----------| -| **Context Bar** | 48px (h-12) | Dienst, actieve patiΓ«nt, user | `context-bar.tsx` | -| **Canvas Area** | flex-1 | Waar blocks verschijnen (centered) | `canvas-area.tsx` | -| **Recent Strip** | 48px (h-12) | Laatste acties, quick access | `recent-strip.tsx` | -| **Command Input** | 64px (h-16) | Command-line style input + voice | `command-input.tsx` | - -### Context Bar (Blijft grotendeels hetzelfde) - -**Huidige implementatie:** -```tsx -
- {/* Left: Logo + Shift */} -
- Swift - {/* Sunrise/Sun/Sunset/Moon */} - {shiftLabel} {/* Ochtenddienst/Middagdienst/etc. */} -
- - {/* Center: Active Patient */} -
- {initials} - {patientName} - -
- - {/* Right: User */} -
- - Verpleegkundige -
-
-``` - -**Dienst kleuren:** -| Dienst | Tijd | Kleur | Icon | -|--------|------|-------|------| -| Ochtend | 07:00-15:00 | `text-amber-600` (#F59E0B) | Sunrise | -| Middag | 15:00-23:00 | `text-yellow-600` (#3B82F6) | Sun | -| Avond | 15:00-23:00 | `text-orange-600` | Sunset | -| Nacht | 23:00-07:00 | `text-indigo-600` (#6366F1) | Moon | - -### Command Input (Wijzigt naar Chat Input) - -**Huidige states:** -- **Default**: "Typ of spreek wat je wilt doen..." + mic icon -- **Typing**: Tekst + cursor -- **Listening**: πŸ”΄ + waveform + live transcript -- **Processing**: "Even kijken wat je bedoelt..." - -**Styling:** -```css -height: 64px (h-16) -background: #FFFFFF -border: 1px #E2E8F0, 2px #3B82F6 (focus) -border-radius: 16px -shadow: lg -font-size: 18px -position: fixed bottom, 24px padding -``` - -### Block Styling (Blijft hetzelfde) - -**Block sizes:** -| Size | Max-width | Use case | -|------|-----------|----------| -| Small | 480px | Quick entry (notitie, zoeken, meting) | -| Medium | 640px | Forms (rapportage, behandelplan) | -| Large | 900px | Overzichten (overdracht, patiΓ«ntenlijst) | -| XLarge | 1100px | Wizards (intake volledig) | - -**Categorie kleuren (verpleegkundig):** -| Categorie | Background | Accent | Icon | Keyboard | -|-----------|------------|--------|------|----------| -| Medicatie | `#FEF6DC` | `#F59E0B` | πŸ’Š | 1 | -| ADL | `#E8F8EF` | `#16A34A` | 🍽️ | 2 | -| Observatie | `#EFF6FF` | `#3B82F6` | πŸ‘οΈ | 3 | -| Incident | `#FEF2F2` | `#DC2626` | ⚠️ | 4 | -| Algemeen | `#F1F5F9` | `#64748B` | πŸ’¬ | 5 | - -### Keyboard Shortcuts (Blijft hetzelfde) - -| Key | Action | -|-----|--------| -| `⌘K` / `Ctrl+K` | Focus command input (blijft focus chat input) | -| `Escape` | Close active block (blijft) | -| `Enter` | Submit (blijft) | -| `⌘Enter` / `Ctrl+Enter` | Quick submit (blijft) | -| `↑` `↓` | Navigate results / history | -| `1-9` | Quick select in FallbackPicker | -| `Space` (empty input) | Start voice (blijft) | - -### Voice Input (Blijft hetzelfde) - -**Flow:** -1. User klikt mic of drukt spatie (bij lege input) -2. Deepgram start streaming transcription -3. Live transcript verschijnt in input field -4. Pauze detectie (1.5 sec stilte) β†’ auto-submit -5. Of user klikt "Stop" β†’ submit - ---- - -## Nieuwe UX/Styling (v3.0) - -### Layout Zones (Gewijzigd) - -| Zone | Breedte | Functie | Component | -|------|---------|---------|-----------| -| **Context Bar** | 100% x 48px | Dienst, actieve patiΓ«nt, user | `context-bar.tsx` (ongewijzigd) | -| **Chat Panel** | 40% x flex | Conversatie met medical scribe | `chat-panel.tsx` (nieuw) | -| **Artifact Area** | 60% x flex | Waar blocks/artifacts verschijnen | `artifact-area.tsx` (nieuw) | -| **Chat Input** | 40% x 64px | Conversational input + voice | `chat-input.tsx` (herzien) | - -### Chat Panel (Nieuw) - -**Message Types:** - -| Type | Alignment | Background | Border | Icon | -|------|-----------|------------|--------|------| -| User message | Right | Amber-50 (#FFFBEB) | Amber-200 | πŸ‘€ | -| Assistant text | Left | Slate-100 (#F1F5F9) | Slate-200 | πŸ€– | -| Assistant action | Left | Slate-100 | Slate-200 | πŸ“/πŸ”/πŸ”„ (klikbaar) | -| System message | Center | - | - | βœ“ | -| Error message | Left | Red-50 | Red-200 | ⚠️ | - -**Message Styling:** -```css -/* User message */ -.message-user { - align-self: flex-end; - background: #FFFBEB; - border: 1px solid #FED7AA; - border-radius: 16px; - border-top-right-radius: 4px; - max-width: 80%; - padding: 12px 16px; - margin: 4px 0; -} - -/* Assistant message */ -.message-assistant { - align-self: flex-start; - background: #F1F5F9; - border: 1px solid #CBD5E1; - border-radius: 16px; - border-top-left-radius: 4px; - max-width: 80%; - padding: 12px 16px; - margin: 4px 0; -} -``` - -**Gedrag:** -- Auto-scroll naar laatste message -- Scroll-lock wanneer gebruiker omhoog scrollt -- "Scroll to bottom" knop bij nieuwe messages (↓) -- Max 100 messages in view (pagination voor oudere) -- Streaming indicator tijdens AI response (pulsating dots) - -### Chat Input (Herzien) - -**States (blijven grotendeels hetzelfde):** - -| State | Weergave | Trigger | -|-------|----------|---------| -| Default | "Typ of spreek..." + mic icon | β€” | -| Typing | Cursor + getypte tekst | Keyboard input | -| Listening | πŸ”΄ + waveform + live transcript | Mic click of spatie | -| Processing | Disabled, "Denkt na..." | Na submit | -| Streaming | Disabled, streaming in chat | Tijdens AI response | - -**Keyboard Shortcuts (uitgebreid):** - -| Key | Actie | -|-----|-------| -| `Enter` | Submit message | -| `⌘Enter` / `Ctrl+Enter` | Force submit (ook tijdens streaming) | -| `Escape` | Clear input / cancel voice | -| `↑` | Vorige message (edit history) | -| `Space` (leeg) | Start voice recording | -| `⌘K` | Focus input | - -### Artifact Area (Nieuw) - -**Layout opties:** - -| Situatie | Weergave | -|----------|----------| -| Geen artifact | Placeholder met voorbeelden | -| EΓ©n artifact | Full width, centered | -| Meerdere artifacts | Tabs bovenaan (max 3) | - -**Placeholder State:** -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ β”‚ -β”‚ πŸ’¬ Artifacts verschijnen hier β”‚ -β”‚ β”‚ -β”‚ Vraag me iets, bijvoorbeeld: β”‚ -β”‚ β€’ "Notitie voor Jan: medicatie gegeven" β”‚ -β”‚ β€’ "Zoek Marie van den Berg" β”‚ -β”‚ β€’ "Maak overdracht voor deze dienst" β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -**Artifact Lifecycle:** -1. Intent detected in chat β†’ AI response: "Ik maak een dagnotitie..." -2. Artifact appears β†’ Slide-in animation (200ms, from right) -3. Pre-filled met extracted entities -4. User interacts β†’ Edits fields, kan blijven chatten -5. User saves β†’ Toast + chat confirmation + artifact closes (optioneel) - -**Artifact Animation:** -```css -@keyframes artifact-enter { - from { - transform: translateX(100%); - opacity: 0; - } - to { - transform: translateX(0); - opacity: 1; - } -} - -.artifact-enter { - animation: artifact-enter 200ms ease-out; -} -``` - -### Responsive Breakpoints (Nieuw) - -| Viewport | Chat Panel | Artifact Area | -|----------|------------|---------------| -| Desktop (>1200px) | 40% | 60% | -| Tablet (768-1200px) | 45% | 55% | -| Mobile (<768px) | Full screen toggle | Full screen toggle | - ---- - -## Wat blijft hetzelfde - -### βœ… Components die NIET wijzigen - -1. **Context Bar** β€” `context-bar.tsx` - - Shift indicator met kleuren - - Patient selector - - User info - -2. **Alle Block componenten** β€” `blocks/*.tsx` - - `DagnotatieBlock` βœ… - - `ZoekenBlock` βœ… - - `OverdrachtBlock` βœ… (wel uitbreiding AI-filtering) - - `RapportageBlock` βœ… - - `AgendaBlock` βœ… - - `MetingenBlock` βœ… - - `PatientContextCard` βœ… - -3. **Voice Input** β€” `lib/swift/use-swift-voice.ts` - - Deepgram streaming transcription - - Live transcript - - Pauze detectie - -4. **Store** β€” `stores/swift-store.ts` - - activePatient, shift, activeBlock - - Wordt uitgebreid, maar bestaande state blijft - -5. **Design Tokens** - - Color palette - - Category colors - - Shift colors - - Typography - - Spacing - -### βœ… Gedrag dat NIET wijzigt - -- Keyboard shortcuts (⌘K, Escape, Enter, etc.) -- Voice recording flow -- Block prefill logic -- Patient search -- Category selection (1-9 keys) -- Toast notifications -- Error handling (offline banner, retry logic) - ---- - -## Wat wijzigt - -### πŸ”„ Components die WIJZIGEN - -1. **CommandCenter** β€” `command-center.tsx` - - **Van:** 4-zone layout (context | canvas | recent | input) - - **Naar:** Split-screen layout (context | chat+artifact | input) - - **Effort:** 3-5 dagen - -2. **CommandInput** β†’ **ChatInput** β€” `command-input.tsx` - - **Van:** Single-line command input - - **Naar:** Multi-line chat input (onderaan chat panel, 40% width) - - **Blijft:** Voice input, keyboard shortcuts, states - - **Effort:** 3 dagen - -3. **CanvasArea** β†’ **ArtifactArea** β€” `canvas-area.tsx` - - **Van:** Centered block display - - **Naar:** Right-side artifact area (60% width) met tabs - - **Effort:** 1 week - -4. **RecentStrip** β€” `recent-strip.tsx` - - **Van:** Fixed bar onderaan canvas - - **Naar:** Optioneel (kan geΓ―ntegreerd in chat history of verwijderd) - - **Effort:** 1 dag (verwijderen of integreren) - -### πŸ†• Components die NIEUW zijn - -1. **ChatPanel** β€” `chat-panel.tsx` - - Scrollable message list - - User/assistant message bubbles - - Streaming indicator - - Action links - - **Effort:** 1 week - -2. **ChatMessage** β€” `chat-message.tsx` - - Message bubble component - - Different types (user, assistant, system, error) - - **Effort:** 2 dagen - -3. **StreamingIndicator** β€” `streaming-indicator.tsx` - - Pulsating dots tijdens AI response - - **Effort:** 1 dag - -4. **ChatActionLink** β€” `chat-action-link.tsx` - - Klikbare links in assistant messages naar artifacts - - **Effort:** 1 dag - -5. **ArtifactContainer** β€” `artifact-container.tsx` - - Wrapper met tabs (max 3 artifacts) - - Tab switching - - **Effort:** 3 dagen - -6. **LinkedEvidence** β€” `linked-evidence.tsx` - - Voor OverdrachtBlock: links naar bronnotities - - **Effort:** 2 dagen - -### πŸ”„ Backend/API die WIJZIGT - -1. **Intent Classification** β€” `/api/intent/classify` - - **Van:** Simple pattern matching + AI fallback - - **Naar:** Blijft werken, maar wordt geΓ―ntegreerd in chat API - - **Effort:** 1 dag (integratie) - -2. **Nieuwe Chat API** β€” `/api/swift/chat` - - Medical scribe chatbot endpoint - - Streaming responses (SSE) - - Conversatiegeschiedenis als input - - Action objects in response - - **Effort:** 1.5 week - -3. **Overdracht AI-Filtering** β€” `/api/overdracht/generate` - - **Van:** Alle notities samenvatten - - **Naar:** + Filtering op behandelrelevantie (voor psychiater) - - **Effort:** 1 week - ---- - -## Implementatie Strategie - -### Fase 1: Foundation (Week 1-2) - -**Doel:** Split-screen layout werkend krijgen zonder chat functionaliteit - -**Taken:** -1. CommandCenter layout wijzigen naar split-screen (40/60) -2. ChatPanel skeleton (nog zonder AI, gewoon tekst weergave) -3. ArtifactArea component (wrapper voor bestaande blocks) -4. Store uitbreiden met chat state (chatMessages, isStreaming) - -**Deliverable:** Split-screen layout zichtbaar, bestaande blocks werken in artifact area - -**Risico's:** -- Responsive design voor mobile/tablet -- Block positioning in artifact area (60% width i.p.v. centered) - ---- - -### Fase 2: Chat API & Conversatie (Week 3-4) - -**Doel:** Conversatie met medical scribe werkend krijgen - -**Taken:** -1. Chat API endpoint bouwen (`/api/swift/chat`) -2. Medical scribe system prompt -3. Streaming responses (SSE) implementeren -4. ChatMessage componenten bouwen -5. Intent detection in conversatie -6. Action object generation - -**Deliverable:** Werkende conversatie die artifacts kan openen - -**Risico's:** -- AI prompt engineering (natuurlijk klinken + betrouwbaar) -- Performance bij lange conversaties -- Kosten (Claude API calls) - ---- - -### Fase 3: Artifact Area & Polish (Week 5-6) - -**Doel:** Meerdere artifacts, polish, AI-filtering - -**Taken:** -1. Meerdere artifacts ondersteuning (tabs, max 3) -2. Slide-in animaties -3. AI-filtering voor psychiater overdracht -4. Linked evidence UI -5. Error handling & edge cases -6. Performance optimalisatie - -**Deliverable:** Volledige v3.0 functionaliteit - ---- - -### Fase 4: Testing & Refinement (Week 7-8) - -**Doel:** Production-ready maken - -**Taken:** -1. User testing -2. Bug fixes -3. Performance tuning -4. Documentatie -5. Migration plan (feature flag) - -**Deliverable:** Production-ready v3.0 - ---- - -## Design Tokens & Styling - -### Colors (Blijft hetzelfde) - -```css -/* App colors */ ---bg-app: #F8FAFC; ---bg-surface: #FFFFFF; ---text-primary: #0F172A; ---text-secondary: #475569; ---border: #E2E8F0; ---brand: #3B82F6; ---success: #16A34A; ---warning: #EAB308; ---error: #DC2626; - -/* Shift colors */ ---shift-ochtend: #F59E0B; ---shift-middag: #EAB308; ---shift-avond: #FB923C; ---shift-nacht: #6366F1; - -/* Category colors */ ---cat-medicatie-bg: #FEF6DC; ---cat-medicatie-accent: #F59E0B; ---cat-adl-bg: #E8F8EF; ---cat-adl-accent: #16A34A; ---cat-observatie-bg: #EFF6FF; ---cat-observatie-accent: #3B82F6; ---cat-incident-bg: #FEF2F2; ---cat-incident-accent: #DC2626; ---cat-algemeen-bg: #F1F5F9; ---cat-algemeen-accent: #64748B; -``` - -### Chat Message Colors (Nieuw) - -```css -/* Chat message colors */ ---chat-user-bg: #FFFBEB; ---chat-user-border: #FED7AA; ---chat-assistant-bg: #F1F5F9; ---chat-assistant-border: #CBD5E1; ---chat-system-text: #64748B; ---chat-error-bg: #FEF2F2; ---chat-error-border: #FECACA; -``` - -### Typography (Blijft hetzelfde) - -```css -/* Font sizes */ ---text-xs: 0.75rem; /* 12px */ ---text-sm: 0.875rem; /* 14px */ ---text-base: 1rem; /* 16px */ ---text-lg: 1.125rem; /* 18px */ ---text-xl: 1.25rem; /* 20px */ - -/* Font weights */ ---font-normal: 400; ---font-medium: 500; ---font-semibold: 600; ---font-bold: 700; -``` - -### Spacing (Blijft hetzelfde) - -```css -/* Spacing scale */ ---space-1: 0.25rem; /* 4px */ ---space-2: 0.5rem; /* 8px */ ---space-3: 0.75rem; /* 12px */ ---space-4: 1rem; /* 16px */ ---space-6: 1.5rem; /* 24px */ ---space-8: 2rem; /* 32px */ ---space-12: 3rem; /* 48px */ ---space-16: 4rem; /* 64px */ -``` - -### Border Radius (Blijft hetzelfde) - -```css ---radius-sm: 4px; ---radius-md: 8px; ---radius-lg: 16px; ---radius-full: 9999px; -``` - ---- - -## Conclusie - -Het v3.0 redesign is **haalbaar binnen 6-8 weken** omdat: - -1. βœ… **Sterke foundation** β€” Alle blocks, voice input, design tokens blijven werken -2. βœ… **Incrementele wijziging** β€” Geen complete rewrite, layout + conversatie laag toevoegen -3. βœ… **Bestaande patterns** β€” Chat API pattern bestaat al (`/api/docs/chat`) -4. βœ… **Design continuΓ―teit** β€” Kleuren, typography, spacing blijven hetzelfde - -**Grootste uitdagingen:** -- Medical scribe prompt engineering (natuurlijk + betrouwbaar) -- Chat state management (Zustand store uitbreiden) -- Performance bij lange conversaties - -**Grootste voordelen:** -- Natuurlijkere interactie (relationeel i.p.v. transactioneel) -- Follow-up vragen mogelijk -- Context behouden tijdens werk -- Overeenkomsten met ChatGPT/Claude (bekend voor gebruikers) - ---- - -## Referenties - -- **FO v3.0:** `fo-swift-medical-scribe-v3.md` β€” Functioneel ontwerp -- **Haalbaarheid:** `haalbaarheidsanalyse-v3.md` β€” Feasibility analysis -- **UX v2.1:** `archive/swift-ux-v2.1.md` β€” Huidige UX/styling -- **Bouwplan v2:** `bouwplan-swift-v2.md` β€” Development roadmap