From 855b1e99ae3ca880eea99cdd1e4267eaf5913c0e Mon Sep 17 00:00:00 2001 From: colinislit Date: Tue, 23 Dec 2025 22:28:41 +0100 Subject: [PATCH] feat(swift): E0 Setup & Foundation + documentatie MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Swift - Contextual UI EPD: "Van 12 klikken naar 1 zin" Documentatie: - PRD, FO, TO, UX specificaties - Bouwplan met 6 epics, 27 stories (68 SP) - Analyse en onderzoeksdocumenten E0 Setup & Foundation: - E0.S1: Zustand v5.0.9 geΓ―nstalleerd - E0.S2: Swift store met context, blocks, input state - E0.S3: /epd/swift route met eigen layout (dark theme) - E0.S4: Folder structuur components/swift/, lib/swift/ Components: - CommandCenter (container) - ContextBar (shift, patient) - CommandInput (text + voice button) - RecentStrip (laatste 5 acties) - BlockContainer (wrapper voor blocks) πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/epd/swift/layout.tsx | 28 + app/epd/swift/page.tsx | 29 + components/swift/blocks/block-container.tsx | 50 + components/swift/blocks/index.ts | 8 + .../swift/command-center/command-center.tsx | 30 + .../swift/command-center/command-input.tsx | 47 + .../swift/command-center/context-bar.tsx | 33 + components/swift/command-center/index.ts | 8 + .../swift/command-center/recent-strip.tsx | 34 + components/swift/index.ts | 6 + docs/swift/bouwplan-swift-v1.md | 532 +++++++ ...-epd-analyse-ephemeral-ui-perspectieven.md | 675 +++++++++ docs/swift/nextgen-epd-claude-vision-epd.txt | 217 +++ ...xtgen-epd-mvp-prioritering-ephemeral-ui.md | 512 +++++++ ...en-epd-onderzoeksverslag-ux-ui-patterns.md | 430 ++++++ .../swift/nextgen-epd-prd-ephemeral-ui-epd.md | 607 ++++++++ ...nextgen-epd-waarde-analyse-ephemeral-ui.md | 551 ++++++++ docs/swift/swift-fo-ai.md | 987 +++++++++++++ docs/swift/swift-prd.md | 632 +++++++++ docs/swift/swift-ux-v2.1.md | 1070 ++++++++++++++ docs/swift/taken-en-vragen-analyse.md | 486 +++++++ docs/swift/to-swift-v1.md | 1257 +++++++++++++++++ lib/swift/index.ts | 5 + lib/swift/types.ts | 73 + package.json | 3 +- pnpm-lock.yaml | 29 +- stores/swift-store.ts | 171 +++ 27 files changed, 8496 insertions(+), 14 deletions(-) create mode 100644 app/epd/swift/layout.tsx create mode 100644 app/epd/swift/page.tsx create mode 100644 components/swift/blocks/block-container.tsx create mode 100644 components/swift/blocks/index.ts create mode 100644 components/swift/command-center/command-center.tsx create mode 100644 components/swift/command-center/command-input.tsx create mode 100644 components/swift/command-center/context-bar.tsx create mode 100644 components/swift/command-center/index.ts create mode 100644 components/swift/command-center/recent-strip.tsx create mode 100644 components/swift/index.ts create mode 100644 docs/swift/bouwplan-swift-v1.md create mode 100644 docs/swift/nextgen-epd-analyse-ephemeral-ui-perspectieven.md create mode 100644 docs/swift/nextgen-epd-claude-vision-epd.txt create mode 100644 docs/swift/nextgen-epd-mvp-prioritering-ephemeral-ui.md create mode 100644 docs/swift/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md create mode 100644 docs/swift/nextgen-epd-prd-ephemeral-ui-epd.md create mode 100644 docs/swift/nextgen-epd-waarde-analyse-ephemeral-ui.md create mode 100644 docs/swift/swift-fo-ai.md create mode 100644 docs/swift/swift-prd.md create mode 100644 docs/swift/swift-ux-v2.1.md create mode 100644 docs/swift/taken-en-vragen-analyse.md create mode 100644 docs/swift/to-swift-v1.md create mode 100644 lib/swift/index.ts create mode 100644 lib/swift/types.ts create mode 100644 stores/swift-store.ts diff --git a/app/epd/swift/layout.tsx b/app/epd/swift/layout.tsx new file mode 100644 index 0000000..fe4268f --- /dev/null +++ b/app/epd/swift/layout.tsx @@ -0,0 +1,28 @@ +/** + * Swift Layout + * + * Full-screen layout for Swift Command Center. + * No sidebar - the entire screen is the Command Center. + */ + +import type { ReactNode } from 'react'; +import { getUser } from '@/lib/auth/server'; +import { redirect } from 'next/navigation'; + +interface SwiftLayoutProps { + children: ReactNode; +} + +export default async function SwiftLayout({ children }: SwiftLayoutProps) { + const user = await getUser(); + + if (!user) { + redirect('/login'); + } + + return ( +
+ {children} +
+ ); +} diff --git a/app/epd/swift/page.tsx b/app/epd/swift/page.tsx new file mode 100644 index 0000000..005bde7 --- /dev/null +++ b/app/epd/swift/page.tsx @@ -0,0 +1,29 @@ +'use client'; + +/** + * Swift Command Center Page + * + * Main entry point for Swift - the Contextual UI EPD. + */ + +import { useSwiftStore } from '@/stores/swift-store'; +import { CommandCenter } from '@/components/swift'; + +export default function SwiftPage() { + const { activeBlock } = useSwiftStore(); + + return ( + + {activeBlock ? ( +
Block: {activeBlock}
+ ) : ( +
+

Wat wil je doen?

+

+ Typ of spreek je intentie, bijvoorbeeld: "notitie jan medicatie" +

+
+ )} +
+ ); +} diff --git a/components/swift/blocks/block-container.tsx b/components/swift/blocks/block-container.tsx new file mode 100644 index 0000000..37a4048 --- /dev/null +++ b/components/swift/blocks/block-container.tsx @@ -0,0 +1,50 @@ +'use client'; + +/** + * Block Container + * + * Wrapper for ephemeral blocks with animation, close button, and sizing. + */ + +import { ReactNode } from 'react'; +import { X } from 'lucide-react'; +import { useSwiftStore } from '@/stores/swift-store'; +import type { BlockSize } from '@/lib/swift/types'; + +interface BlockContainerProps { + title: string; + size?: BlockSize; + children: ReactNode; +} + +const SIZE_CLASSES: Record = { + sm: 'max-w-sm', + md: 'max-w-md', + lg: 'max-w-2xl', + full: 'max-w-4xl', +}; + +export function BlockContainer({ title, size = 'md', children }: BlockContainerProps) { + const { closeBlock } = useSwiftStore(); + + return ( +
+ {/* Header */} +
+

{title}

+ +
+ + {/* Content */} +
{children}
+
+ ); +} diff --git a/components/swift/blocks/index.ts b/components/swift/blocks/index.ts new file mode 100644 index 0000000..adb3985 --- /dev/null +++ b/components/swift/blocks/index.ts @@ -0,0 +1,8 @@ +/** + * Swift Blocks Barrel Export + */ + +export { BlockContainer } from './block-container'; +// export { DagnotatieBlock } from './dagnotitie-block'; +// export { ZoekenBlock } from './zoeken-block'; +// export { OverdrachtBlock } from './overdracht-block'; diff --git a/components/swift/command-center/command-center.tsx b/components/swift/command-center/command-center.tsx new file mode 100644 index 0000000..6fc88f1 --- /dev/null +++ b/components/swift/command-center/command-center.tsx @@ -0,0 +1,30 @@ +'use client'; + +/** + * Command Center + * + * Main container for the Swift interface. + * Orchestrates Context Bar, Canvas, Recent Strip, and Command Input. + */ + +import { ReactNode } from 'react'; +import { ContextBar } from './context-bar'; +import { CommandInput } from './command-input'; +import { RecentStrip } from './recent-strip'; + +interface CommandCenterProps { + children?: ReactNode; +} + +export function CommandCenter({ children }: CommandCenterProps) { + return ( + <> + +
+ {children} +
+ + + + ); +} diff --git a/components/swift/command-center/command-input.tsx b/components/swift/command-center/command-input.tsx new file mode 100644 index 0000000..2aec289 --- /dev/null +++ b/components/swift/command-center/command-input.tsx @@ -0,0 +1,47 @@ +'use client'; + +/** + * Command Input + * + * Bottom input bar for text and voice commands. + */ + +import { useSwiftStore } from '@/stores/swift-store'; +import { Mic } from 'lucide-react'; + +export function CommandInput() { + const { inputValue, setInputValue, isVoiceActive, setVoiceActive } = useSwiftStore(); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + // TODO: Process intent (E2) + console.log('Submit:', inputValue); + }; + + return ( +
+
+ setInputValue(e.target.value)} + placeholder="Typ je intentie... (bijv. 'notitie jan medicatie')" + className="flex-1 bg-slate-800 border border-slate-600 rounded-lg px-4 py-2 text-white placeholder:text-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + autoFocus + /> + +
+
+ ); +} diff --git a/components/swift/command-center/context-bar.tsx b/components/swift/command-center/context-bar.tsx new file mode 100644 index 0000000..325a9ed --- /dev/null +++ b/components/swift/command-center/context-bar.tsx @@ -0,0 +1,33 @@ +'use client'; + +/** + * Context Bar + * + * Top bar showing current context: shift, selected patient, user info. + */ + +import { useSwiftStore } from '@/stores/swift-store'; + +export function ContextBar() { + const { shift, activePatient } = useSwiftStore(); + + return ( +
+
+ Swift + + {shift}dienst + +
+
+ {activePatient ? ( + + {activePatient.name_given.join(' ')} {activePatient.name_family} + + ) : ( + Geen patiΓ«nt geselecteerd + )} +
+
+ ); +} diff --git a/components/swift/command-center/index.ts b/components/swift/command-center/index.ts new file mode 100644 index 0000000..6686bc3 --- /dev/null +++ b/components/swift/command-center/index.ts @@ -0,0 +1,8 @@ +/** + * Command Center Barrel Export + */ + +export { CommandCenter } from './command-center'; +export { CommandInput } from './command-input'; +export { ContextBar } from './context-bar'; +export { RecentStrip } from './recent-strip'; diff --git a/components/swift/command-center/recent-strip.tsx b/components/swift/command-center/recent-strip.tsx new file mode 100644 index 0000000..966f109 --- /dev/null +++ b/components/swift/command-center/recent-strip.tsx @@ -0,0 +1,34 @@ +'use client'; + +/** + * Recent Strip + * + * Shows last 5 actions as clickable chips for quick repeat. + */ + +import { useSwiftStore } from '@/stores/swift-store'; + +export function RecentStrip() { + const { recentActions } = useSwiftStore(); + + return ( +
+ Recent: + {recentActions.length === 0 ? ( + Nog geen acties + ) : ( +
+ {recentActions.map((action) => ( + + ))} +
+ )} +
+ ); +} diff --git a/components/swift/index.ts b/components/swift/index.ts new file mode 100644 index 0000000..6b06b46 --- /dev/null +++ b/components/swift/index.ts @@ -0,0 +1,6 @@ +/** + * Swift Components Barrel Export + */ + +export * from './command-center'; +export * from './blocks'; diff --git a/docs/swift/bouwplan-swift-v1.md b/docs/swift/bouwplan-swift-v1.md new file mode 100644 index 0000000..1c3e8b8 --- /dev/null +++ b/docs/swift/bouwplan-swift-v1.md @@ -0,0 +1,532 @@ +# 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 | ⏳ To Do | 4 | 8 SP | +| E1 | Command Center | Input, voice, context bar | ⏳ To Do | 5 | 13 SP | +| E2 | Intent Classification | Local + AI fallback | ⏳ To Do | 4 | 10 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: 27 stories, 68 story points** + +**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 | + +**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, + ], +}; +``` + +--- + +### 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 | diff --git a/docs/swift/nextgen-epd-analyse-ephemeral-ui-perspectieven.md b/docs/swift/nextgen-epd-analyse-ephemeral-ui-perspectieven.md new file mode 100644 index 0000000..f57d6f7 --- /dev/null +++ b/docs/swift/nextgen-epd-analyse-ephemeral-ui-perspectieven.md @@ -0,0 +1,675 @@ +# 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/nextgen-epd-claude-vision-epd.txt b/docs/swift/nextgen-epd-claude-vision-epd.txt new file mode 100644 index 0000000..d23583c --- /dev/null +++ b/docs/swift/nextgen-epd-claude-vision-epd.txt @@ -0,0 +1,217 @@ +> 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/nextgen-epd-mvp-prioritering-ephemeral-ui.md b/docs/swift/nextgen-epd-mvp-prioritering-ephemeral-ui.md new file mode 100644 index 0000000..55c2a97 --- /dev/null +++ b/docs/swift/nextgen-epd-mvp-prioritering-ephemeral-ui.md @@ -0,0 +1,512 @@ +# MVP & Prioritering Ephemeral UI EPD + +**Document:** MVP Scope en Implementatie Prioritering +**Datum:** december 2024 +**Status:** Definitief + +--- + +## 1. MVP Definitie + +### 1.1 EΓ©n Zin + +> **MVP = Een Command Center waarmee je met tekst of voice een dagnotitie of rapportage maakt, met automatische patient herkenning.** + +### 1.2 MVP Scope + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ MVP SCOPE β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ IN SCOPE (Must Have) β”‚ +β”‚ ───────────────────── β”‚ +β”‚ βœ“ Command Center pagina β”‚ +β”‚ βœ“ Text input met intent herkenning β”‚ +β”‚ βœ“ Voice input (Deepgram - bestaat al) β”‚ +β”‚ βœ“ Dagnotitie blok β”‚ +β”‚ βœ“ Zoeken blok β”‚ +β”‚ βœ“ Patient pre-fill uit input β”‚ +β”‚ βœ“ Fallback blok-picker β”‚ +β”‚ β”‚ +β”‚ SHOULD HAVE (Demo Enhanced) β”‚ +β”‚ ─────────────────────────── β”‚ +β”‚ β—‹ Rapportage blok β”‚ +β”‚ β—‹ Overdracht blok met AI β”‚ +β”‚ β—‹ Recent actions tracking β”‚ +β”‚ β—‹ Context bar (dienst info) β”‚ +β”‚ β”‚ +β”‚ OUT OF SCOPE (v1) β”‚ +β”‚ ───────────────── β”‚ +β”‚ βœ— Behandelplan blok β”‚ +β”‚ βœ— Intake blok β”‚ +β”‚ βœ— Agenda blok β”‚ +β”‚ βœ— Metingen blok β”‚ +β”‚ βœ— Ambient listening β”‚ +β”‚ βœ— Multi-user realtime β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### 1.3 Waarom Deze Scope? + +| Keuze | Rationale | +|-------|-----------| +| Dagnotitie eerst | Hoogste frequentie (20x/dag), simpelste form | +| Zoeken als fundament | Elke actie begint met "wie" - zonder zoeken geen pre-fill | +| Voice must-have | "Ik draag handschoenen" - zorg context vereist hands-free | +| Fallback verplicht | Vertrouwen: nooit een doodlopende straat | +| Geen behandelplan | Te complex, lage frequentie, bestaande UI voldoet | + +--- + +## 2. Hergebruik Bestaande Code + +### 2.1 Direct Herbruikbaar + +| Component | Locatie | Hergebruik | +|-----------|---------|------------| +| **Speech Recorder** | `components/speech-recorder.tsx` | 100% - drop-in | +| **Deepgram API** | `api/deepgram/transcribe/route.ts` | 100% - werkt | +| **Toast System** | `lib/hooks/use-toast.ts` | 100% - feedback | +| **Command (cmdk)** | `components/ui/command.tsx` | 90% - zoek basis | +| **Dagregistratie Form** | `app/epd/dagregistratie/` | 80% - wrap als blok | +| **Report Types** | `lib/types/report.ts` | 100% - validatie | +| **Verpleegkundig API** | `api/reports/route.ts` | 100% - save | + +### 2.2 Gedeeltelijk Herbruikbaar + +| Component | Locatie | Aanpassing Nodig | +|-----------|---------|------------------| +| **Patient List** | `app/epd/verpleegrapportage/` | β†’ PatientCard voor zoeken | +| **EPD Layout** | `app/epd/layout.tsx` | β†’ Command Center layout | +| **Report Composer** | `app/epd/patients/[id]/rapportage/` | β†’ RapportageBlock wrapper | + +### 2.3 Nieuw te Bouwen + +| Component | Geschatte Effort | Prioriteit | +|-----------|------------------|------------| +| `/app/command-center/page.tsx` | 4h | P1 | +| `/api/intent/classify/route.ts` | 6h | P1 | +| `CommandInput.tsx` | 3h | P1 | +| `BlockContainer.tsx` | 2h | P1 | +| `DagnotitieBlock.tsx` | 3h | P1 | +| `ZoekenBlock.tsx` | 4h | P1 | +| `FallbackPicker.tsx` | 2h | P1 | +| `PatientResolver.ts` | 2h | P1 | +| `useCommandCenter.ts` (store) | 3h | P1 | +| **Totaal MVP** | **~29h** | - | + +--- + +## 3. Prioritering: MoSCoW + +### 3.1 Must Have (Release Blocker) + +``` +M1. Command Center Layout + └── Centrale pagina met input field + └── Route: /command-center + +M2. Intent Classification + └── API endpoint dat input analyseert + └── Returns: { intent, entities, confidence } + +M3. Dagnotitie Blok + └── Simpele form: patient, categorie, tekst + └── Pre-fill support + └── 1-click save + +M4. Zoeken Blok + └── Patient search met cmdk + └── PatientCard met quick actions + └── Set active patient + +M5. Voice Input + └── Deepgram integratie in Command input + └── Live transcript display + +M6. Fallback Picker + └── Grid met blok icons + └── Toont bij lage confidence of onbekende intent + +M7. Patient Pre-fill + └── Entity extraction uit input + └── Patient name β†’ ID resolver +``` + +### 3.2 Should Have (Demo Value) + +``` +S1. Rapportage Blok + └── Wrapper rond bestaande ReportComposer + └── Voice dictation in editor + └── AI structurering knop + +S2. Overdracht Blok + └── AI samenvatting (API bestaat) + └── Multi-patient view + └── Bronverwijzingen + +S3. Recent Actions + └── Badge strip onder input + └── Click to re-open + +S4. Context Bar + └── "Ochtend dienst | 8 patiΓ«nten" + └── Shift awareness +``` + +### 3.3 Could Have (Nice to Have) + +``` +C1. Categorie Herkenning + └── "medicatie" β†’ Medicatie category + └── Keyword mapping + +C2. Animaties + └── Block slide-in + └── Pre-fill highlight + └── Success celebration + +C3. Keyboard Shortcuts + └── Cmd+K β†’ focus input + └── Enter β†’ submit + └── Esc β†’ close block + +C4. Onboarding Hints + └── "Probeer: notitie jan" + └── First-time user guidance +``` + +### 3.4 Won't Have (Explicit Out) + +``` +W1. Behandelplan Blok - te complex, lage frequentie +W2. Intake Blok - wizard is complex, 1x/maand +W3. Agenda Blok - bestaande werkt, lage urgentie +W4. Metingen Blok - lage waarde-perceptie +W5. Ambient Listening - v2+ feature +W6. Offline Mode - v2+ feature +``` + +--- + +## 4. Implementatie Volgorde + +### 4.1 Dependency Graph + +``` + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Command Center β”‚ + β”‚ Layout β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ β”‚ β”‚ + β–Ό β–Ό β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Voice β”‚ β”‚ Intent β”‚ β”‚ Fallback β”‚ + β”‚ Input β”‚ β”‚ API β”‚ β”‚ Picker β”‚ + β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β” + β”‚ β”‚ β”‚ + β–Ό β–Ό β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Zoeken β”‚ β”‚ Dagnotitie β”‚ + β”‚ Blok β”‚ β”‚ Blok β”‚ + β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Pre-fill β”‚ + β”‚ Logic β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### 4.2 Sprint Planning + +#### Sprint 1: Foundation (Dag 1-3) + +| # | Taak | Afhankelijk van | Output | +|---|------|-----------------|--------| +| 1.1 | Command Center page layout | - | `/app/command-center/page.tsx` | +| 1.2 | CommandInput component | 1.1 | Text input met submit | +| 1.3 | BlockContainer wrapper | 1.1 | Generic block frame | +| 1.4 | Zustand store setup | - | `useCommandCenter` hook | +| 1.5 | Voice integratie | 1.2 | Mic button in input | + +**Deliverable:** Command Center opent, voice werkt, geen blokken nog. + +#### Sprint 2: Intent & Zoeken (Dag 4-6) + +| # | Taak | Afhankelijk van | Output | +|---|------|-----------------|--------| +| 2.1 | Intent API route | - | `/api/intent/classify` | +| 2.2 | Entity extraction | 2.1 | Patient name uit tekst | +| 2.3 | Patient search API | - | `/api/patients/search` | +| 2.4 | ZoekenBlock | 1.3, 2.3 | Patient cards + select | +| 2.5 | Fallback picker | 1.3 | Grid met blok icons | + +**Deliverable:** "zoek jan" werkt, patient selectie mogelijk. + +#### Sprint 3: Dagnotitie Flow (Dag 7-9) + +| # | Taak | Afhankelijk van | Output | +|---|------|-----------------|--------| +| 3.1 | DagnotitieBlock | 1.3 | Quick entry form | +| 3.2 | Pre-fill logic | 2.2, 3.1 | Patient + categorie auto | +| 3.3 | Save flow | 3.1 | Toast + recent badge | +| 3.4 | Intent β†’ Block routing | 2.1, 3.1 | "notitie jan" β†’ block | + +**Deliverable:** "notitie voor jan: medicatie gegeven" werkt end-to-end. + +#### Sprint 4: Polish & Demo (Dag 10-12) + +| # | Taak | Afhankelijk van | Output | +|---|------|-----------------|--------| +| 4.1 | RapportageBlock | 1.3 | Wrapper rond composer | +| 4.2 | Recent actions strip | 3.3 | Clickable badges | +| 4.3 | Animaties | All | Smooth transitions | +| 4.4 | Demo scenarios | All | 3 happy paths | +| 4.5 | Bug fixes | All | Stability | + +**Deliverable:** Demo-ready voor stakeholders. + +--- + +## 5. Technische Beslissingen + +### 5.1 State Management + +**Besluit:** Zustand + +```typescript +// stores/command-center.ts +interface CommandCenterState { + // Active state + activeBlock: 'dagnotitie' | 'zoeken' | 'rapportage' | 'overdracht' | null + activePatient: Patient | null + + // Input state + inputValue: string + isListening: boolean + transcript: string + + // Pre-fill data + prefillData: { + patientName?: string + category?: string + text?: string + } + + // History + recentActions: Action[] + + // Actions + processInput: (text: string) => Promise + 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/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md b/docs/swift/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md new file mode 100644 index 0000000..1a63c4f --- /dev/null +++ b/docs/swift/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md @@ -0,0 +1,430 @@ +# 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/nextgen-epd-prd-ephemeral-ui-epd.md b/docs/swift/nextgen-epd-prd-ephemeral-ui-epd.md new file mode 100644 index 0000000..e8527dd --- /dev/null +++ b/docs/swift/nextgen-epd-prd-ephemeral-ui-epd.md @@ -0,0 +1,607 @@ +# πŸ“„ 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/nextgen-epd-waarde-analyse-ephemeral-ui.md b/docs/swift/nextgen-epd-waarde-analyse-ephemeral-ui.md new file mode 100644 index 0000000..877c1bf --- /dev/null +++ b/docs/swift/nextgen-epd-waarde-analyse-ephemeral-ui.md @@ -0,0 +1,551 @@ +# 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/swift-fo-ai.md b/docs/swift/swift-fo-ai.md new file mode 100644 index 0000000..a968e2a --- /dev/null +++ b/docs/swift/swift-fo-ai.md @@ -0,0 +1,987 @@ +# 🧩 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/swift-prd.md b/docs/swift/swift-prd.md new file mode 100644 index 0000000..0da3d8c --- /dev/null +++ b/docs/swift/swift-prd.md @@ -0,0 +1,632 @@ +# πŸ“„ 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/swift-ux-v2.1.md b/docs/swift/swift-ux-v2.1.md new file mode 100644 index 0000000..5889be0 --- /dev/null +++ b/docs/swift/swift-ux-v2.1.md @@ -0,0 +1,1070 @@ +# 🎨 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/taken-en-vragen-analyse.md b/docs/swift/taken-en-vragen-analyse.md new file mode 100644 index 0000000..e548404 --- /dev/null +++ b/docs/swift/taken-en-vragen-analyse.md @@ -0,0 +1,486 @@ +# 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/to-swift-v1.md b/docs/swift/to-swift-v1.md new file mode 100644 index 0000000..d3a229a --- /dev/null +++ b/docs/swift/to-swift-v1.md @@ -0,0 +1,1257 @@ +# 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/lib/swift/index.ts b/lib/swift/index.ts new file mode 100644 index 0000000..73c4fe0 --- /dev/null +++ b/lib/swift/index.ts @@ -0,0 +1,5 @@ +/** + * Swift Library Barrel Export + */ + +export * from './types'; diff --git a/lib/swift/types.ts b/lib/swift/types.ts new file mode 100644 index 0000000..d0c7d95 --- /dev/null +++ b/lib/swift/types.ts @@ -0,0 +1,73 @@ +/** + * Swift Type Definitions + * + * Core types for the Swift Contextual UI system. + */ + +import type { VerpleegkundigCategory } from '@/lib/types/report'; + +// Intent types +export type SwiftIntent = 'dagnotitie' | 'zoeken' | 'overdracht' | 'unknown'; + +export type BlockType = Exclude; + +// Shift types +export type ShiftType = 'nacht' | 'ochtend' | 'middag' | 'avond'; + +// Intent classification result +export interface IntentClassificationResult { + intent: SwiftIntent; + confidence: number; + entities: ExtractedEntities; + source: 'local' | 'ai'; +} + +// Extracted entities from user input +export interface ExtractedEntities { + patientName?: string; + patientId?: string; + category?: VerpleegkundigCategory; + content?: string; +} + +// Block sizes +export type BlockSize = 'sm' | 'md' | 'lg' | 'full'; + +// Block configuration +export interface BlockConfig { + type: BlockType; + title: string; + size: BlockSize; + icon: string; +} + +// Block configs for each type +export const BLOCK_CONFIGS: Record = { + dagnotitie: { + type: 'dagnotitie', + title: 'Dagnotitie', + size: 'md', + icon: 'FileText', + }, + zoeken: { + type: 'zoeken', + title: 'PatiΓ«nt zoeken', + size: 'md', + icon: 'Search', + }, + overdracht: { + type: 'overdracht', + title: 'Overdracht', + size: 'lg', + icon: 'ArrowRightLeft', + }, +}; + +// Recent action type +export interface RecentAction { + id: string; + intent: SwiftIntent; + label: string; + timestamp: Date; + patientName?: string; +} diff --git a/package.json b/package.json index 97cc8d3..00237c7 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,8 @@ "tailwindcss-animate": "^1.0.7", "three": "^0.181.1", "tsx": "^4.20.6", - "zod": "^4.1.12" + "zod": "^4.1.12", + "zustand": "^5.0.9" }, "devDependencies": { "@tailwindcss/postcss": "^4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 34f2798..6e5539d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -146,6 +146,9 @@ importers: zod: specifier: ^4.1.12 version: 4.1.12 + zustand: + specifier: ^5.0.9 + version: 5.0.9(@types/react@18.3.27)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) devDependencies: '@tailwindcss/postcss': specifier: ^4 @@ -3903,8 +3906,8 @@ packages: react: optional: true - zustand@5.0.8: - resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} + zustand@5.0.9: + resolution: {integrity: sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==} engines: {node: '>=12.20.0'} peerDependencies: '@types/react': '>=18.0.0' @@ -4745,7 +4748,7 @@ snapshots: tunnel-rat: 0.1.2(@types/react@18.3.27)(react@18.3.1) use-sync-external-store: 1.6.0(react@18.3.1) utility-types: 3.11.0 - zustand: 5.0.8(@types/react@18.3.27)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + zustand: 5.0.9(@types/react@18.3.27)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) optionalDependencies: react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: @@ -4768,7 +4771,7 @@ snapshots: suspend-react: 0.1.3(react@18.3.1) three: 0.181.2 use-sync-external-store: 1.6.0(react@18.3.1) - zustand: 5.0.8(@types/react@18.3.27)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + zustand: 5.0.9(@types/react@18.3.27)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) optionalDependencies: react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: @@ -5892,8 +5895,8 @@ snapshots: '@typescript-eslint/parser': 8.47.0(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.5(eslint@8.57.1) eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.57.1) @@ -5912,7 +5915,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 @@ -5923,22 +5926,22 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.47.0(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -5949,7 +5952,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.47.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -8193,7 +8196,7 @@ snapshots: '@types/react': 18.3.27 react: 18.3.1 - zustand@5.0.8(@types/react@18.3.27)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): + zustand@5.0.9(@types/react@18.3.27)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): optionalDependencies: '@types/react': 18.3.27 react: 18.3.1 diff --git a/stores/swift-store.ts b/stores/swift-store.ts new file mode 100644 index 0000000..bd7daf6 --- /dev/null +++ b/stores/swift-store.ts @@ -0,0 +1,171 @@ +import { create } from 'zustand'; +import { devtools } from 'zustand/middleware'; +import type { Database } from '@/lib/supabase/database.types'; +import type { VerpleegkundigCategory } from '@/lib/types/report'; + +// Database types +export type Patient = Database['public']['Tables']['patients']['Row']; + +// Swift-specific types +export type ShiftType = 'nacht' | 'ochtend' | 'middag' | 'avond'; + +export type SwiftIntent = + | 'dagnotitie' + | 'zoeken' + | 'overdracht' + | 'unknown'; + +export type BlockType = Exclude; + +// Extracted entities from user input +export interface ExtractedEntities { + patientName?: string; + patientId?: string; + category?: VerpleegkundigCategory; + content?: string; +} + +// Block prefill data +export interface BlockPrefillData extends ExtractedEntities { + // Additional prefill data specific to blocks +} + +// Recent action for the Recent Strip +export interface RecentAction { + id: string; + intent: SwiftIntent; + label: string; + timestamp: Date; + patientName?: string; +} + +// Store interface +interface SwiftStore { + // Context + activePatient: Patient | null; + shift: ShiftType; + + // Block state + activeBlock: BlockType | null; + prefillData: BlockPrefillData; + isBlockLoading: boolean; + + // Input state + inputValue: string; + isVoiceActive: boolean; + + // Recent actions + recentActions: RecentAction[]; + + // Context actions + setActivePatient: (patient: Patient | null) => void; + setShift: (shift: ShiftType) => void; + + // Block actions + openBlock: (type: BlockType, prefill?: BlockPrefillData) => void; + closeBlock: () => void; + setBlockLoading: (loading: boolean) => void; + + // Input actions + setInputValue: (value: string) => void; + setVoiceActive: (active: boolean) => void; + clearInput: () => void; + + // Recent actions + addRecentAction: (action: Omit) => void; + + // Reset + reset: () => void; +} + +// Helper to calculate current shift based on time +function getCurrentShift(): ShiftType { + const hour = new Date().getHours(); + if (hour >= 0 && hour < 7) return 'nacht'; + if (hour >= 7 && hour < 12) return 'ochtend'; + if (hour >= 12 && hour < 17) return 'middag'; + return 'avond'; +} + +// Initial state +const initialState = { + activePatient: null, + shift: getCurrentShift(), + activeBlock: null, + prefillData: {}, + isBlockLoading: false, + inputValue: '', + isVoiceActive: false, + recentActions: [], +}; + +// Create the store +export const useSwiftStore = create()( + devtools( + (set, get) => ({ + ...initialState, + + // Context actions + setActivePatient: (patient) => set({ activePatient: patient }, false, 'setActivePatient'), + + setShift: (shift) => set({ shift }, false, 'setShift'), + + // Block actions + openBlock: (type, prefill = {}) => { + set( + { + activeBlock: type, + prefillData: prefill, + isBlockLoading: false, + }, + false, + 'openBlock' + ); + }, + + closeBlock: () => { + set( + { + activeBlock: null, + prefillData: {}, + isBlockLoading: false, + }, + false, + 'closeBlock' + ); + }, + + setBlockLoading: (loading) => set({ isBlockLoading: loading }, false, 'setBlockLoading'), + + // Input actions + setInputValue: (value) => set({ inputValue: value }, false, 'setInputValue'), + + setVoiceActive: (active) => set({ isVoiceActive: active }, false, 'setVoiceActive'), + + clearInput: () => set({ inputValue: '' }, false, 'clearInput'), + + // Recent actions + addRecentAction: (action) => { + const newAction: RecentAction = { + ...action, + id: crypto.randomUUID(), + timestamp: new Date(), + }; + + set( + (state) => ({ + recentActions: [newAction, ...state.recentActions].slice(0, 5), + }), + false, + 'addRecentAction' + ); + }, + + // Reset + reset: () => set(initialState, false, 'reset'), + }), + { + name: 'swift-store', + } + ) +);