diff --git a/components/swift/blocks/dagnotitie-block.tsx b/components/swift/blocks/dagnotitie-block.tsx index b88cb4c..cea91ba 100644 --- a/components/swift/blocks/dagnotitie-block.tsx +++ b/components/swift/blocks/dagnotitie-block.tsx @@ -169,9 +169,7 @@ export function DagnotatieBlock({ prefill }: DagnotitieBlockProps) { const [isSubmitting, setIsSubmitting] = useState(false); - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - + const handleSave = useCallback(async () => { if (!patientId) { toast({ variant: 'destructive', @@ -243,6 +241,11 @@ export function DagnotatieBlock({ prefill }: DagnotitieBlockProps) { } finally { setIsSubmitting(false); } + }, [patientId, content, category, includeInHandover, patientName, toast, closeBlock]); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + await handleSave(); }; // Keyboard shortcut: Cmd/Ctrl+Enter to save diff --git a/docs/swift/PROJECT-STATUS-2024-12-27.md b/docs/swift/archive/PROJECT-STATUS-2024-12-27.md similarity index 100% rename from docs/swift/PROJECT-STATUS-2024-12-27.md rename to docs/swift/archive/PROJECT-STATUS-2024-12-27.md diff --git a/docs/swift/keyboard-shortcuts-reference.md b/docs/swift/archive/keyboard-shortcuts-reference.md similarity index 100% rename from docs/swift/keyboard-shortcuts-reference.md rename to docs/swift/archive/keyboard-shortcuts-reference.md diff --git a/docs/swift/nextgen-epd-analyse-ephemeral-ui-perspectieven.md b/docs/swift/archive/nextgen-epd-analyse-ephemeral-ui-perspectieven.md similarity index 100% rename from docs/swift/nextgen-epd-analyse-ephemeral-ui-perspectieven.md rename to docs/swift/archive/nextgen-epd-analyse-ephemeral-ui-perspectieven.md diff --git a/docs/swift/nextgen-epd-claude-vision-epd.txt b/docs/swift/archive/nextgen-epd-claude-vision-epd.txt similarity index 100% rename from docs/swift/nextgen-epd-claude-vision-epd.txt rename to docs/swift/archive/nextgen-epd-claude-vision-epd.txt diff --git a/docs/swift/nextgen-epd-mvp-prioritering-ephemeral-ui.md b/docs/swift/archive/nextgen-epd-mvp-prioritering-ephemeral-ui.md similarity index 100% rename from docs/swift/nextgen-epd-mvp-prioritering-ephemeral-ui.md rename to docs/swift/archive/nextgen-epd-mvp-prioritering-ephemeral-ui.md diff --git a/docs/swift/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md b/docs/swift/archive/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md similarity index 100% rename from docs/swift/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md rename to docs/swift/archive/nextgen-epd-onderzoeksverslag-ux-ui-patterns.md diff --git a/docs/swift/nextgen-epd-prd-ephemeral-ui-epd.md b/docs/swift/archive/nextgen-epd-prd-ephemeral-ui-epd.md similarity index 100% rename from docs/swift/nextgen-epd-prd-ephemeral-ui-epd.md rename to docs/swift/archive/nextgen-epd-prd-ephemeral-ui-epd.md diff --git a/docs/swift/nextgen-epd-waarde-analyse-ephemeral-ui.md b/docs/swift/archive/nextgen-epd-waarde-analyse-ephemeral-ui.md similarity index 100% rename from docs/swift/nextgen-epd-waarde-analyse-ephemeral-ui.md rename to docs/swift/archive/nextgen-epd-waarde-analyse-ephemeral-ui.md diff --git a/docs/swift/swift-fo-ai.md b/docs/swift/archive/swift-fo-ai.md similarity index 100% rename from docs/swift/swift-fo-ai.md rename to docs/swift/archive/swift-fo-ai.md diff --git a/docs/swift/swift-fo-diagnostiek-workflow.md b/docs/swift/archive/swift-fo-diagnostiek-workflow.md similarity index 100% rename from docs/swift/swift-fo-diagnostiek-workflow.md rename to docs/swift/archive/swift-fo-diagnostiek-workflow.md diff --git a/docs/swift/swift-prd.md b/docs/swift/archive/swift-prd.md similarity index 100% rename from docs/swift/swift-prd.md rename to docs/swift/archive/swift-prd.md diff --git a/docs/swift/swift-ux-diagnostiek-workflow.md b/docs/swift/archive/swift-ux-diagnostiek-workflow.md similarity index 100% rename from docs/swift/swift-ux-diagnostiek-workflow.md rename to docs/swift/archive/swift-ux-diagnostiek-workflow.md diff --git a/docs/swift/swift-ux-v2.1.md b/docs/swift/archive/swift-ux-v2.1.md similarity index 100% rename from docs/swift/swift-ux-v2.1.md rename to docs/swift/archive/swift-ux-v2.1.md diff --git a/docs/swift/taken-en-vragen-analyse.md b/docs/swift/archive/taken-en-vragen-analyse.md similarity index 100% rename from docs/swift/taken-en-vragen-analyse.md rename to docs/swift/archive/taken-en-vragen-analyse.md diff --git a/docs/swift/test-plan-e5-s2-error-handling.md b/docs/swift/archive/test-plan-e5-s2-error-handling.md similarity index 100% rename from docs/swift/test-plan-e5-s2-error-handling.md rename to docs/swift/archive/test-plan-e5-s2-error-handling.md diff --git a/docs/swift/test-plan-e5-s3-keyboard-shortcuts.md b/docs/swift/archive/test-plan-e5-s3-keyboard-shortcuts.md similarity index 100% rename from docs/swift/test-plan-e5-s3-keyboard-shortcuts.md rename to docs/swift/archive/test-plan-e5-s3-keyboard-shortcuts.md diff --git a/docs/swift/test-plan-epic3.md b/docs/swift/archive/test-plan-epic3.md similarity index 100% rename from docs/swift/test-plan-epic3.md rename to docs/swift/archive/test-plan-epic3.md diff --git a/docs/swift/to-swift-v1.md b/docs/swift/archive/to-swift-v1.md similarity index 100% rename from docs/swift/to-swift-v1.md rename to docs/swift/archive/to-swift-v1.md diff --git a/docs/swift/bouwplan-swift-v3.md b/docs/swift/bouwplan-swift-v3.md new file mode 100644 index 0000000..455011d --- /dev/null +++ b/docs/swift/bouwplan-swift-v3.md @@ -0,0 +1,1069 @@ +# πŸš€ Mission Control β€” Bouwplan Swift v3.0 + +πŸ’‘ **Transformatie:** Van Command Center naar Medical Scribe Chatbot Interface + +--- + +**Projectnaam:** Swift Medical Scribe v3.0 +**Versie:** v3.0 +**Datum:** 27-12-2024 +**Auteur:** Colin Lit + +--- + +## 1. Doel en context + +🎯 **Doel:** Swift transformeren van een command-line style interface naar een conversational medical scribe chatbot met split-screen layout (chat links, artifacts rechts). + +πŸ“˜ **Context:** +De huidige Swift v2.1 werkt met een command-line paradigma waar gebruikers kort commando's typen ("notitie jan medicatie"). Dit werkt goed, maar voelt transactioneel aan. Gebruikers willen doorvragen, context behouden, en natuurlijker interacteren met het systeem. + +**De transformatie:** +- **Van:** Command-line input β†’ Centered blocks β†’ Recent strip +- **Naar:** Chat conversation β†’ Split-screen (40/60) β†’ Artifacts rechts + +**Waarom deze verandering:** +1. **Natuurlijkere interactie** β€” Voelt als praten met collega i.p.v. commando's typen +2. **Context behoud** β€” Conversatiegeschiedenis blijft zichtbaar +3. **Follow-up mogelijk** β€” Gebruiker kan doorvragen zonder opnieuw te beginnen +4. **Bekende UX** β€” Lijkt op ChatGPT Canvas / Claude Artifacts (bekend voor gebruikers) + +**Referenties:** +- **FO v3.0:** `fo-swift-medical-scribe-v3.md` β€” Functioneel ontwerp medical scribe +- **Haalbaarheid:** `haalbaarheidsanalyse-v3.md` β€” Feasibility analysis (6-8 weken, haalbaar) +- **UX Analyse:** `v3-redesign-met-huidige-styling.md` β€” Wat blijft vs. wijzigt +- **UX v2.1:** `archive/swift-ux-v2.1.md` β€” Huidige UX/styling + +--- + +## 2. Uitgangspunten + +### 2.1 Technische Stack + +**Frontend:** +- Next.js 14 (App Router) βœ… Bestaand +- React 18 met TypeScript βœ… Bestaand +- Tailwind CSS + shadcn/ui βœ… Bestaand +- Lucide Icons βœ… Bestaand +- Zustand (state management) βœ… Bestaand + +**Backend & Database:** +- Supabase (PostgreSQL + Auth) βœ… Bestaand +- FHIR-inspired datamodel βœ… Bestaand +- Row Level Security (RLS) βœ… Bestaand + +**AI/ML Services:** +- Anthropic Claude API (Sonnet 4.5) βœ… Bestaand +- Deepgram (speech-to-text) βœ… Bestaand +- Streaming API responses (SSE) πŸ†• Nieuw patroon voor chat + +**Hosting & Deploy:** +- Vercel (production deployment) βœ… Bestaand +- Environment variables via `.env.local` βœ… Bestaand + +**Nieuwe Dependencies:** +- Geen nieuwe externe libraries nodig +- Hergebruik van bestaande `/api/docs/chat` streaming pattern + +### 2.2 Projectkaders + +**Tijd:** +- **Totaal:** 6-8 weken bouwtijd +- **Fase 1 (Foundation):** Week 1-2 +- **Fase 2 (Chat API):** Week 3-4 +- **Fase 3 (Artifacts & Polish):** Week 5-6 +- **Fase 4 (Testing):** Week 7-8 + +**Team:** +- 1 developer (full-time) +- AI assistant (Claude Code) voor development support + +**Scope:** +- **In scope:** Alle P1 intents (dagnotitie, zoeken, overdracht, patient context) +- **Out of scope:** P2/P3 intents blijven werken maar geen redesign +- **Feature flag:** v3.0 achter feature flag zodat v2.1 beschikbaar blijft + +**Data:** +- Alle bestaande Supabase data blijft werken +- Geen database migraties nodig +- Alleen nieuwe API endpoints + frontend components + +**Risicomanagement:** +- Incremental rollout via feature flag +- v2.1 blijft beschikbaar als fallback +- A/B testing mogelijk voor user feedback + +### 2.3 Programmeer Uitgangspunten + +**Code Quality Principles:** + +- **DRY (Don't Repeat Yourself)** + - Herbruikbare chat components (`ChatMessage`, `ChatBubble`) + - Centrale config voor message types + - Shared utilities voor streaming responses + +- **KISS (Keep It Simple, Stupid)** + - Geen overengineering van chat state + - Eenvoudige Zustand store uitbreiding + - Geen nieuwe frameworks/libraries indien niet nodig + +- **SOC (Separation of Concerns)** + - Chat UI gescheiden van artifact logic + - Message rendering gescheiden van streaming logic + - API calls in dedicated `/lib/swift/chat-api.ts` + +- **YAGNI (You Aren't Gonna Need It)** + - Bouw alleen conversation features die in FO staan + - Geen "nice to have" features (bijv. message editing, reactions) + - Start met max 3 artifacts, niet meer + +**Development Practices:** + +- **Code Organization** + ``` + components/swift/ + β”œβ”€β”€ chat/ # πŸ†• Nieuwe chat components + β”‚ β”œβ”€β”€ chat-panel.tsx + β”‚ β”œβ”€β”€ chat-message.tsx + β”‚ β”œβ”€β”€ chat-input.tsx + β”‚ └── streaming-indicator.tsx + β”œβ”€β”€ artifacts/ # πŸ†• Nieuwe artifact wrapper + β”‚ β”œβ”€β”€ artifact-container.tsx + β”‚ └── artifact-tab.tsx + β”œβ”€β”€ blocks/ # βœ… Bestaand, blijft werken + β”‚ β”œβ”€β”€ dagnotitie-block.tsx + β”‚ β”œβ”€β”€ zoeken-block.tsx + β”‚ └── overdracht-block.tsx + └── command-center/ # πŸ”„ Wijzigt naar split-screen + β”œβ”€β”€ command-center.tsx + β”œβ”€β”€ context-bar.tsx # βœ… Blijft ongewijzigd + └── offline-banner.tsx # βœ… Blijft ongewijzigd + ``` + +- **Error Handling** + - Hergebruik bestaande `lib/swift/error-handler.ts` + - Chat-specific error states (connection lost, stream interrupted) + - User-friendly foutmeldingen in chat ("Er ging iets mis, probeer opnieuw") + +- **Security** + - API keys blijven server-side (Claude API key) + - Chat messages niet persistent opgeslagen (alleen in session state) + - RLS rules blijven gelden voor artifacts + +- **Performance** + - Virtual scrolling voor lange chat histories (>100 messages) + - Debounce op typing indicator (300ms) + - Lazy load artifacts (alleen renderen wanneer actief) + - Streaming responses via SSE (Server-Sent Events) + +- **Testing** + - Manual smoke tests voor alle chat flows + - Integration tests voor `/api/swift/chat` endpoint + - Edge case testing (stream interruption, long messages, etc.) + +**Voorbeeld implementatie:** +```typescript +// βœ… DRY - Herbruikbare message component +interface ChatMessageProps { + type: 'user' | 'assistant' | 'system' | 'error'; + content: string; + timestamp?: Date; +} + +export function ChatMessage({ type, content, timestamp }: ChatMessageProps) { + const styles = MESSAGE_STYLES[type]; // Centrale config + return ( +
+ {/* ... */} +
+ ); +} + +// βœ… SOC - API logic gescheiden +// In /lib/swift/chat-api.ts +export async function sendChatMessage( + message: string, + history: ChatMessage[] +): Promise { + const response = await fetch('/api/swift/chat', { + method: 'POST', + body: JSON.stringify({ message, history }), + }); + return response.body!; +} + +// βœ… KISS - Simpele state management +interface ChatState { + messages: ChatMessage[]; + isStreaming: boolean; + addMessage: (msg: ChatMessage) => void; +} + +const useChatStore = create((set) => ({ + messages: [], + isStreaming: false, + addMessage: (msg) => set((s) => ({ + messages: [...s.messages, msg] + })), +})); +``` + +--- + +## 3. Epics & Stories Overzicht + +🎯 **Doel:** De bouw opdelen in 6 logische epics met concrete deliverables. + +**Epic Structuur:** + +| Epic ID | Titel | Doel | Status | Stories | Story Points | Opmerkingen | +|---------|-------|------|--------|---------|--------------|-------------| +| E0 | Pre-work & Planning | Design tokens, component audit, system prompt | ⏳ To Do | 3 | 5 SP | Voorbereiding | +| E1 | Foundation - Split-screen | Layout naar 40/60 split | ⏳ To Do | 4 | 13 SP | Week 1-2 | +| E2 | Chat Panel & Messages | Chat UI zonder AI | ⏳ To Do | 5 | 13 SP | Week 2-3 | +| E3 | Chat API & Medical Scribe | AI conversatie werkend | ⏳ To Do | 6 | 21 SP | Week 3-4 | +| E4 | Artifact Area & Tabs | Meerdere artifacts mogelijk | ⏳ To Do | 4 | 13 SP | Week 5 | +| E5 | AI-Filtering & Polish | Psychiater filtering, polish | ⏳ To Do | 5 | 13 SP | Week 6 | +| E6 | Testing & Refinement | QA, bugs, performance | ⏳ To Do | 4 | 8 SP | Week 7-8 | + +**Totaal:** 31 stories, **86 Story Points** (~7 weken Γ  12 SP/week) + +**Belangrijk:** +- ⚠️ Voer niet in 1x het volledige plan uit. Bouw per epic en per story. +- ⚠️ Dependencies/migraties moeten eerst aan Colin worden gemeld. +- Feature flag vanaf E1: `FEATURE_FLAG_SWIFT_V3=true` in `.env.local` + +--- + +## 4. Epics & Stories (Uitwerking) + +### Epic 0 β€” Pre-work & Planning + +**Epic Doel:** Voorbereiding werk voordat development start. Design tokens verificatie, component audit, medical scribe system prompt. + +| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | +|----------|--------------|---------------------|--------|------------------|--------------| +| E0.S1 | Design tokens audit | Alle kleuren/spacing/typography gedocumenteerd in v3 doc | ⏳ | β€” | 1 | +| E0.S2 | Component inventory | Lijst van alle blocks die herbruikbaar zijn | ⏳ | β€” | 2 | +| E0.S3 | Medical scribe system prompt | Eerste versie prompt voor `/api/swift/chat`, getest met Claude | ⏳ | β€” | 2 | + +**Technical Notes:** +- E0.S1: Check of alle tokens uit v2.1 nog kloppen voor v3.0 +- E0.S2: Maak lijst van blocks die NIET wijzigen vs. die WEL wijzigen +- E0.S3: Prompt moet Nederlands zijn, vriendelijk maar professioneel, intent detection + +**Deliverable:** Planning document met component lijst + prompt v1 + +--- + +### Epic 1 β€” Foundation - Split-screen Layout + +**Epic Doel:** CommandCenter omzetten naar split-screen layout (40% chat, 60% artifacts). + +| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | +|----------|--------------|---------------------|--------|------------------|--------------| +| E1.S1 | Feature flag setup | `FEATURE_FLAG_SWIFT_V3` in `.env` + conditional rendering | ⏳ | E0.S2 | 1 | +| E1.S2 | CommandCenter layout wijzigen | Split-screen grid (40/60), context bar blijft | ⏳ | E1.S1 | 5 | +| E1.S3 | Placeholder componenten | ChatPanel (lege div), ArtifactArea (lege div) | ⏳ | E1.S2 | 2 | +| E1.S4 | Responsive breakpoints | Desktop/tablet/mobile toggle tussen chat/artifact | ⏳ | E1.S3 | 5 | + +**Technical Notes:** +```tsx +// E1.S2 - Layout structuur +
+ {/* Blijft ongewijzigd */} + +
+ {/* Chat Panel - 40% */} +
+ {/* Placeholder in E1.S3 */} +
+ + {/* Artifact Area - 60% */} +
+ {/* Placeholder in E1.S3 */} +
+
+
+``` + +**Responsive breakpoints (E1.S4):** +- Desktop (>1200px): 40/60 split zichtbaar +- Tablet (768-1200px): 45/55 split +- Mobile (<768px): Toggle tussen chat en artifact (full screen) + +**Deliverable:** Split-screen layout zichtbaar, feature flag werkt, v2.1 nog beschikbaar + +--- + +### Epic 2 β€” Chat Panel & Messages + +**Epic Doel:** Chat UI werkend krijgen zonder AI (hardcoded responses voor testing). + +| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | +|----------|--------------|---------------------|--------|------------------|--------------| +| E2.S1 | Store uitbreiding | `chatMessages`, `isStreaming` in swift-store.ts | ⏳ | E1.S4 | 2 | +| E2.S2 | ChatMessage component | User/assistant/system/error message types met styling | ⏳ | E2.S1 | 3 | +| E2.S3 | ChatPanel component | Scrollable message list, auto-scroll, scroll-lock | ⏳ | E2.S2 | 5 | +| E2.S4 | ChatInput component | Tekst input onderaan chat (40% width), enter to send | ⏳ | E2.S3 | 2 | +| E2.S5 | Keyboard shortcuts | ⌘K focus, Escape clear, Enter submit | ⏳ | E2.S4 | 1 | + +**Technical Notes:** + +**E2.S1 - Store uitbreiding:** +```typescript +// stores/swift-store.ts +interface SwiftStore { + // Bestaand + activePatient: Patient | null; + activeBlock: BlockType | null; + shift: ShiftType; + + // Nieuw voor chat + chatMessages: ChatMessage[]; + isStreaming: boolean; + pendingAction: Action | null; + + // Actions + addChatMessage: (message: ChatMessage) => void; + clearChat: () => void; + setStreaming: (streaming: boolean) => void; +} +``` + +**E2.S2 - Message styling:** +```tsx +// components/swift/chat/chat-message.tsx +const MESSAGE_STYLES = { + user: { + container: 'self-end bg-amber-50 border-amber-200', + borderRadius: 'rounded-2xl rounded-tr-sm', + }, + assistant: { + container: 'self-start bg-slate-100 border-slate-200', + borderRadius: 'rounded-2xl rounded-tl-sm', + }, + system: { + container: 'self-center bg-transparent text-slate-500 text-sm', + borderRadius: '', + }, + error: { + container: 'self-start bg-red-50 border-red-200', + borderRadius: 'rounded-2xl', + }, +}; +``` + +**E2.S3 - Auto-scroll gedrag:** +- Auto-scroll naar laatste message bij nieuwe message +- Scroll-lock wanneer user omhoog scrollt (detecteer scroll position) +- "↓ Scroll to bottom" knop verschijnt bij nieuwe messages tijdens scroll-lock + +**E2.S4 - Chat input:** +- Onderaan chat panel (40% width) +- Multi-line support (Shift+Enter voor new line) +- Enter submit (tenzij Shift pressed) +- Placeholder: "Typ of spreek..." + +**Deliverable:** Werkende chat UI (zonder AI), gebruiker kan typen en ziet messages verschijnen + +--- + +### Epic 3 β€” Chat API & Medical Scribe + +**Epic Doel:** AI conversatie werkend krijgen met intent detection en artifact opening. + +| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | +|----------|--------------|---------------------|--------|------------------|--------------| +| E3.S1 | Chat API endpoint skeleton | `/api/swift/chat` route met SSE setup | ⏳ | E2.S5 | 3 | +| E3.S2 | Streaming response logic | Claude API streaming werkt, chunks naar frontend | ⏳ | E3.S1 | 5 | +| E3.S3 | Medical scribe system prompt | Prompt met role, intents, examples, Nederlands | ⏳ | E3.S2 | 3 | +| E3.S4 | Intent detection in response | AI genereert action objects (intent + entities) | ⏳ | E3.S3 | 5 | +| E3.S5 | Frontend streaming handling | useChatStream hook, message chunks renderen | ⏳ | E3.S4 | 3 | +| E3.S6 | Artifact opening from chat | Action object opent juiste block met prefill | ⏳ | E3.S5 | 2 | + +**Technical Notes:** + +**E3.S1 - API Route:** +```typescript +// app/api/swift/chat/route.ts +export async function POST(req: Request) { + const { message, messages, context } = await req.json(); + + // Streaming response + const encoder = new TextEncoder(); + const stream = new ReadableStream({ + async start(controller) { + // Claude API streaming logic + }, + }); + + return new Response(stream, { + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + }, + }); +} +``` + +**E3.S3 - System Prompt (samenvatting):** +``` +Je bent een medische assistent (medical scribe) voor Swift, een Nederlands GGZ EPD. + +Je rol: +- Help zorgmedewerkers met documentatie en administratie +- Voer natuurlijke gesprekken in het Nederlands +- Herken intents en voer acties uit wanneer nodig +- Stel verduidelijkingsvragen bij onduidelijkheid +- Wees vriendelijk maar professioneel + +Intents die je herkent: +- dagnotitie: notitie maken voor patiΓ«nt +- zoeken: patiΓ«nt zoeken +- rapportage: behandelrapportage schrijven +- overdracht: dienst overdracht maken + +Wanneer je een intent herkent, voeg een JSON action object toe: +{ + "type": "action", + "intent": "dagnotitie", + "entities": { "patient": "Jan de Vries", "category": "medicatie" }, + "confidence": 0.95 +} + +Context: +- Actieve patiΓ«nt: {{activePatient}} +- Dienst: {{shift}} +- Recente acties: {{recentActions}} +``` + +**E3.S4 - Action object format:** +```typescript +interface Action { + type: 'action'; + intent: IntentType; + entities: { + patient?: string; + patientId?: string; + category?: VerpleegkundigCategory; + content?: string; + }; + confidence: number; + artifact?: { + type: BlockType; + prefill: BlockPrefillData; + }; +} +``` + +**E3.S5 - Frontend streaming:** +```typescript +// lib/swift/use-chat-stream.ts +export function useChatStream() { + const addMessage = useSwiftStore((s) => s.addChatMessage); + const setStreaming = useSwiftStore((s) => s.setStreaming); + + const sendMessage = async (message: string) => { + setStreaming(true); + const response = await fetch('/api/swift/chat', { + method: 'POST', + body: JSON.stringify({ message, messages: /* ... */ }), + }); + + const reader = response.body!.getReader(); + let accumulatedText = ''; + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = new TextDecoder().decode(value); + accumulatedText += chunk; + + // Update message in UI + addMessage({ type: 'assistant', content: accumulatedText }); + } + + setStreaming(false); + }; + + return { sendMessage }; +} +``` + +**E3.S6 - Artifact opening:** +- Parse action object uit AI response +- Open juiste block via `openBlock(artifact.type, artifact.prefill)` +- Block verschijnt rechts in artifact area + +**Deliverable:** Werkende conversatie met AI, intents worden herkend, blocks openen + +--- + +### Epic 4 β€” Artifact Area & Tabs + +**Epic Doel:** Meerdere artifacts tegelijk mogelijk met tabs, slide-in animaties. + +| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | +|----------|--------------|---------------------|--------|------------------|--------------| +| E4.S1 | ArtifactContainer component | Wrapper met tabs bovenaan, max 3 artifacts | ⏳ | E3.S6 | 5 | +| E4.S2 | Artifact lifecycle management | Open/close/switch tussen artifacts in store | ⏳ | E4.S1 | 3 | +| E4.S3 | Slide-in animatie | Artifact slide-in van rechts (200ms ease-out) | ⏳ | E4.S2 | 2 | +| E4.S4 | Placeholder state | "Artifacts verschijnen hier" met voorbeelden | ⏳ | E4.S3 | 3 | + +**Technical Notes:** + +**E4.S1 - ArtifactContainer:** +```tsx +// components/swift/artifacts/artifact-container.tsx +interface Artifact { + id: string; + type: BlockType; + prefill: BlockPrefillData; + title: string; +} + +export function ArtifactContainer() { + const { openArtifacts, activeArtifactId } = useSwiftStore(); + + if (openArtifacts.length === 0) { + return ; + } + + return ( +
+ {/* Tabs - alleen tonen bij >1 artifact */} + {openArtifacts.length > 1 && ( +
+ {openArtifacts.map((artifact) => ( + + ))} +
+ )} + + {/* Active artifact */} +
+ {renderArtifact(activeArtifact)} +
+
+ ); +} +``` + +**E4.S2 - Store uitbreiding:** +```typescript +interface SwiftStore { + // ... bestaand + + // Artifact state + openArtifacts: Artifact[]; // Max 3 + activeArtifactId: string | null; + + // Actions + openArtifact: (artifact: Artifact) => void; + closeArtifact: (id: string) => void; + switchArtifact: (id: string) => void; +} + +// Logic: max 3 artifacts, oudste wordt gesloten bij 4e +const openArtifact = (artifact: Artifact) => { + set((state) => { + let artifacts = [...state.openArtifacts]; + if (artifacts.length >= 3) { + artifacts = artifacts.slice(1); // Remove oldest + } + return { + openArtifacts: [...artifacts, artifact], + activeArtifactId: artifact.id, + }; + }); +}; +``` + +**E4.S3 - Animatie:** +```css +/* globals.css */ +@keyframes artifact-enter { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } +} + +.artifact-enter { + animation: artifact-enter 200ms ease-out; +} +``` + +**E4.S4 - Placeholder:** +```tsx +function ArtifactPlaceholder() { + return ( +
+
πŸ’¬
+

Artifacts verschijnen hier

+

Vraag me iets, bijvoorbeeld:

+
    +
  • β€’ "Notitie voor Jan: medicatie gegeven"
  • +
  • β€’ "Zoek Marie van den Berg"
  • +
  • β€’ "Maak overdracht voor deze dienst"
  • +
+
+ ); +} +``` + +**Deliverable:** Meerdere artifacts mogelijk, smooth transitions, placeholder state + +--- + +### Epic 5 β€” AI-Filtering & Polish + +**Epic Doel:** AI-filtering voor psychiater overdracht, linked evidence, final polish. + +| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | +|----------|--------------|---------------------|--------|------------------|--------------| +| E5.S1 | AI-filtering psychiater | `/api/overdracht/generate` filtert op behandelrelevantie | ⏳ | E4.S4 | 5 | +| E5.S2 | Linked evidence UI | Bronnotitie links in OverdrachtBlock, hover preview | ⏳ | E5.S1 | 3 | +| E5.S3 | Voice input integratie | Bestaande Deepgram blijft werken in chat input | ⏳ | E2.S4 | 2 | +| E5.S4 | Error states & offline | Chat error messages, offline banner margin fix | ⏳ | E3.S2 | 2 | +| E5.S5 | Polish & animations | Smooth transitions, loading states, toast confirmations | ⏳ | E5.S4 | 1 | + +**Technical Notes:** + +**E5.S1 - AI-filtering:** +```typescript +// app/api/overdracht/generate/route.ts +// Uitbreiden met filtering parameter +interface GenerateOverdrachtRequest { + shift: ShiftType; + filterForRole?: 'psychiater' | 'verpleegkundige'; +} + +// AI prompt voor filtering +const FILTER_PROMPT = ` +Analyseer deze verpleegkundige notities en selecteer ALLEEN behandelrelevante informatie voor de psychiater: + +WEL relevant: +- Medicatie-issues (weigering, bijwerkingen) +- Stemming/gedrag veranderingen +- Risico-signalen (suΓ―cidale uitingen, agressie) +- Psychotische symptomen + +NIET relevant: +- Routine medicatie ("volgens schema") +- ADL activiteiten ("gedoucht", "ontbijt") +- Standaard observaties ("rustige dag") +`; +``` + +**E5.S2 - Linked evidence:** +```tsx +// components/swift/shared/linked-evidence.tsx +interface LinkedEvidenceProps { + sourceNotes: Report[]; + highlightedText: string; +} + +export function LinkedEvidence({ sourceNotes, highlightedText }: LinkedEvidenceProps) { + return ( + + + {highlightedText} + + +
+ {sourceNotes.map((note) => ( +
+
{note.author} - {note.timestamp}
+
{note.content}
+
+ ))} +
+
+
+ ); +} +``` + +**E5.S3 - Voice input:** +- Bestaande `use-swift-voice.ts` hook blijft werken +- Integreren in ChatInput component +- Mic icon rechts van input field +- Live transcript verschijnt in input tijdens recording + +**E5.S4 - Error states:** +```tsx +// Error message types in chat +const ERROR_MESSAGES = { + network: "Er ging iets mis met de verbinding. Probeer het opnieuw.", + stream_interrupted: "De verbinding werd onderbroken. Probeer je bericht opnieuw te versturen.", + rate_limit: "Even geduld, er zijn te veel aanvragen. Wacht 30 seconden.", + unknown: "Er is een fout opgetreden. Probeer het later opnieuw.", +}; +``` + +**Deliverable:** AI-filtering werkt, linked evidence klikbaar, voice input geΓ―ntegreerd + +--- + +### Epic 6 β€” Testing & Refinement + +**Epic Doel:** Volledige QA, bug fixes, performance tuning, documentatie. + +| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | +|----------|--------------|---------------------|--------|------------------|--------------| +| E6.S1 | Manual smoke tests | Alle P1 flows werken zonder crashes (checklist) | ⏳ | E5.S5 | 3 | +| E6.S2 | Performance optimalisatie | Chat scroll performance, virtual scrolling >100 msgs | ⏳ | E6.S1 | 3 | +| E6.S3 | Bug fixes | Alle gemelde bugs opgelost, edge cases getest | ⏳ | E6.S2 | 1 | +| E6.S4 | Documentatie update | README, CLAUDE.md, migration guide | ⏳ | E6.S3 | 1 | + +**Technical Notes:** + +**E6.S1 - Test checklist:** +```markdown +### P1 Flow Tests + +**Dagnotitie via conversatie:** +- [ ] User typt "Ik heb medicatie gegeven aan Jan" +- [ ] AI herkent intent (dagnotitie) en patient (Jan) +- [ ] DagnotatieBlock opent met prefill +- [ ] User kan opslaan β†’ Toast confirmation +- [ ] Chat toont "βœ“ Notitie opgeslagen" + +**PatiΓ«nt zoeken:** +- [ ] User typt "Zoek Marie van den Berg" +- [ ] ZoekenBlock opent rechts +- [ ] Patient search werkt +- [ ] Selecteren patient β†’ PatientContextCard opent + +**Overdracht maken:** +- [ ] User typt "Maak overdracht" +- [ ] OverdrachtBlock opent +- [ ] AI genereert samenvattingen +- [ ] Psychiater ziet alleen behandelrelevante info +- [ ] Linked evidence klikbaar + +**Follow-up conversatie:** +- [ ] User typt "Voeg toe: goed geslapen" +- [ ] AI begrijpt context (laatste artifact = dagnotitie) +- [ ] Tekst wordt toegevoegd aan artifact + +**Meerdere artifacts:** +- [ ] User opent 3 artifacts achter elkaar +- [ ] Tabs verschijnen bovenaan +- [ ] Switching tussen artifacts werkt +- [ ] 4e artifact openen β†’ oudste sluit automatisch + +**Voice input:** +- [ ] Mic icon werkt +- [ ] Deepgram transcriptie verschijnt live +- [ ] Pauze detectie β†’ auto-submit +- [ ] Voice message wordt verwerkt zoals typed message + +**Error handling:** +- [ ] Offline β†’ banner verschijnt +- [ ] Stream interrupted β†’ error message in chat +- [ ] Rate limit β†’ friendly message + retry suggestion +- [ ] Network error β†’ retry button +``` + +**E6.S2 - Performance:** +- Virtual scrolling met `react-window` of `@tanstack/react-virtual` (>100 messages) +- Debounce typing indicator (300ms) +- Memoize message components (`React.memo`) +- Lazy load artifacts (niet renderen tot actief) + +**E6.S3 - Edge cases:** +- Zeer lange messages (>1000 chars) +- Special characters in patient names +- Concurrent artifact opening +- Browser back/forward navigation +- Tab close tijdens streaming + +**E6.S4 - Documentatie:** +- Update `CLAUDE.md` met v3.0 architecture +- Migration guide voor users (v2.1 β†’ v3.0) +- Developer README met chat API docs +- Prompt versioning doc + +**Deliverable:** Production-ready v3.0, alle tests passed, gedocumenteerd + +--- + +## 5. Kwaliteit & Testplan + +🎯 **Doel:** Borgen kwaliteit van v3.0 via gestructureerd testplan. + +### Test Types + +| Test Type | Scope | Tools | Verantwoordelijke | +|-----------|-------|-------|-------------------| +| **Manual Smoke Tests** | Alle P1 flows + edge cases | Checklist (zie E6.S1) | Developer | +| **Integration Tests** | `/api/swift/chat` endpoint | Playwright / Jest | Developer | +| **Performance Tests** | Chat scroll, streaming latency | Chrome DevTools, Lighthouse | Developer | +| **User Acceptance** | Real-world flows met zorgmedewerkers | User feedback sessie | PM + Developer | +| **Security Tests** | API keys, RLS, XSS in chat | Manual audit | Developer | + +### Test Coverage Targets + +- **Manual smoke tests:** 100% van P1 flows (dagnotitie, zoeken, overdracht, patient context) +- **Integration tests:** `/api/swift/chat` endpoint (streaming, action generation) +- **Performance:** Chat scroll <16ms frame time, streaming latency <500ms + +### Manual Test Checklist + +**Pre-deployment checklist:** +- [ ] Feature flag `FEATURE_FLAG_SWIFT_V3=true` werkt +- [ ] v2.1 nog steeds beschikbaar (fallback) +- [ ] Alle P1 flows getest (zie E6.S1) +- [ ] Edge cases getest (lange messages, concurrent actions, etc.) +- [ ] Mobile responsive (toggle tussen chat/artifact) +- [ ] Keyboard shortcuts werken (⌘K, Escape, Enter) +- [ ] Voice input geΓ―ntegreerd en werkend +- [ ] Error states tonen user-friendly messages +- [ ] Offline banner werkt +- [ ] Performance: scroll smooth, streaming <500ms latency +- [ ] AI-filtering psychiater werkt (alleen behandelrelevante info) +- [ ] Linked evidence klikbaar en toont bronnotities +- [ ] Toast notifications bij save/error +- [ ] Browser back/forward navigation werkt + +### Acceptance Criteria (MVP) + +**Minimaal werkend voor release:** +1. βœ… Split-screen layout werkend (desktop/tablet/mobile) +2. βœ… Conversatie met medical scribe voelt natuurlijk (niet robotisch) +3. βœ… Artifacts openen binnen 2 sec na intent detection +4. βœ… AI-filtering psychiater >85% accuracy (behandelrelevante info) +5. βœ… Voice input geΓ―ntegreerd en werkend +6. βœ… P1 flows (dagnotitie, zoeken, overdracht, patient context) 100% werkend +7. βœ… Error handling: netwerk errors, offline, stream interrupted +8. βœ… Performance: <500ms streaming latency, smooth scroll + +--- + +## 6. Demo & Presentatieplan + +🎯 **Doel:** Presenteren van v3.0 aan stakeholders en users voor feedback. + +### Demo Scenario + +**Duur:** 15 minuten +**Doelgroep:** Zorgmedewerkers (verpleegkundigen + psychiaters), product team +**Locatie:** Vercel staging environment (`swift-v3-staging.vercel.app`) + +**Flow:** + +1. **Intro (2 min):** + - Context: "We hebben Swift getransformeerd naar een conversational interface" + - Toon v2.1 vs. v3.0 screenshot (voor/na) + +2. **Dagnotitie flow (3 min):** + - Typ: "Ik heb net medicatie gegeven aan Jan de Vries" + - AI herkent intent, DagnotatieBlock opent rechts met prefill + - Toon follow-up: "Voeg toe: hij voelt zich beter vandaag" + - Opslaan β†’ Chat confirmation + +3. **PatiΓ«nt zoeken + context (3 min):** + - Typ: "Wie is Marie van den Berg?" + - ZoekenBlock opent, selecteer patient + - PatientContextCard toont laatste notities, vitals, diagnose + - Chat vraag: "Wat was er gisteren met Marie?" + - AI antwoordt met context uit notities + +4. **Overdracht met AI-filtering (4 min):** + - Typ: "Maak overdracht voor deze dienst" + - OverdrachtBlock opent + - Toon psychiater view: alleen behandelrelevante info + - Klik op linked evidence β†’ bronnotitie preview + - Toon verschil tussen verpleegkundige vs. psychiater view + +5. **Voice input (2 min):** + - Klik mic icon + - Spreek: "Notitie voor Jan: bloeddruk gemeten, 135 over 85" + - Live transcript verschijnt + - DagnotatieBlock opent met prefill + +6. **Q&A (1 min):** + - Vragen beantwoorden + - Feedback verzamelen + +**Backup Plan:** +- Lokale versie klaar bij internet/API issues +- Pre-recorded video als complete fallback +- Screenshots voor elk stap + +--- + +## 7. Risico's & Mitigatie + +🎯 **Doel:** Risico's vroeg signaleren en mitigeren. + +| Risico | Kans | Impact | Mitigatie | Owner | +|--------|------|--------|-----------|-------| +| **AI prompt niet natuurlijk genoeg** | Hoog | Hoog | Iteratief testen met users, prompt versioning, A/B testing | Developer | +| **Streaming latency >1s** | Middel | Hoog | Claude Haiku model overwegen (sneller), caching, local patterns voor snelle acties | Developer | +| **Performance bij >100 messages** | Middel | Middel | Virtual scrolling, pagination, max 100 messages in view | Developer | +| **Chat state memory leak** | Middel | Middel | Proper cleanup in useEffect, memory profiling | Developer | +| **AI kosten te hoog** | Middel | Middel | Rate limiting, local pattern matching eerst, cache responses | PM | +| **Mobile UX awkward** | Hoog | Middel | Extensive mobile testing, toggle UX refinement | Developer | +| **v2.1 users niet willen switchen** | Hoog | Laag | Feature flag (optioneel), user onboarding, feedback loop | PM | +| **Intent detection accuracy <80%** | Middel | Hoog | Hybrid approach (local + AI), confidence thresholds, fallback picker | Developer | +| **Browser compatibility issues** | Laag | Middel | Test Chrome/Safari/Firefox, SSE polyfill if needed | Developer | +| **Concurrent artifact state bugs** | Middel | Middel | Thorough testing, max 3 artifacts enforced, state validation | Developer | + +**Top 3 Risks & Mitigation:** + +1. **AI Prompt Engineering (Kans: Hoog, Impact: Hoog)** + - **Mitigatie:** Start met simpele prompt v1 in E0.S3, iteratief verfijnen met user feedback, prompt versioning (v1, v2, v3), A/B testing tussen prompts + - **Success metric:** >80% user satisfaction "voelt natuurlijk aan" + +2. **Performance - Streaming Latency (Kans: Middel, Impact: Hoog)** + - **Mitigatie:** Local patterns voor P1 intents (dagnotitie, zoeken) β†’ <100ms, AI alleen voor complex/conversational, Claude Haiku overwegen, response caching + - **Success metric:** <500ms tot eerste AI token, <2s tot artifact open + +3. **Mobile UX Toggle (Kans: Hoog, Impact: Middel)** + - **Mitigatie:** Extensive mobile testing, bottom sheet voor artifact (native feel), swipe gestures, user testing met zorgmedewerkers + - **Success metric:** >70% mobile users vindt toggle intuΓ―tief + +--- + +## 8. Evaluatie & Lessons Learned + +🎯 **Doel:** Reflecteren na elke epic en einde project. + +**Na elke epic (weekly retro):** +- Wat ging goed deze week? +- Welke blockers hadden we? +- Welke AI-prompts werkten het beste? +- Waar liepen we vertraging op? +- Wat passen we aan voor volgende epic? + +**Na project (final retro):** + +**Te documenteren:** +1. **Successen:** + - Welke componenten zijn herbruikbaar voor volgende projecten? + - Welke development patterns werkten goed? + - Welke AI-prompts waren meest effectief? + +2. **Uitdagingen:** + - Waar liepen we vast? + - Welke technical debt ontstond? + - Welke estimates waren te optimistisch/pessimistisch? + +3. **Metrics:** + - Actual time spent vs. estimated (story points) + - User satisfaction score (survey) + - Performance metrics (latency, scroll FPS) + - AI kosten (Claude API usage) + +4. **Next Steps:** + - P2/P3 features roadmap + - Technical debt payoff plan + - User feedback integration plan + +**Template voor lessons learned:** +```markdown +## Epic X - Lessons Learned + +### What went well +- ... + +### What didn't go well +- ... + +### Action items for next epic +- ... + +### Reusable components/patterns +- ... +``` + +--- + +## 9. Referenties + +🎯 **Doel:** Koppelen aan overige Mission Control-documenten. + +**Mission Control Documents:** +- **PRD Ephemeral UI:** `docs/swift/archive/nextgen-epd-prd-ephemeral-ui-epd.md` β€” Product vision +- **FO v3.0:** `docs/swift/fo-swift-medical-scribe-v3.md` β€” Functioneel ontwerp medical scribe +- **Haalbaarheid:** `docs/swift/haalbaarheidsanalyse-v3.md` β€” Feasibility analysis +- **UX v2.1:** `docs/swift/archive/swift-ux-v2.1.md` β€” Huidige UX/styling +- **UX Analyse v3:** `docs/swift/v3-redesign-met-huidige-styling.md` β€” Wat blijft vs. wijzigt +- **Bouwplan v2:** `docs/swift/bouwplan-swift-v2.md` β€” Previous roadmap (v2.1) + +**Technical Resources:** +- Repository: `https://github.com/[org]/mini-epd-prototype` +- Staging: `https://swift-v3-staging.vercel.app` (to be created) +- Production: `https://mini-epd.vercel.app` (existing) +- Component Library: `components/swift/` folder +- API Documentation: `/docs/api/` (to be created) + +**External References:** +- [ChatGPT Canvas UX](https://altar.io/next-gen-of-human-ai-collaboration/) β€” Inspiration +- [Claude Artifacts](https://docs.anthropic.com) β€” Pattern reference +- [Abridge Linked Evidence](https://www.abridge.com/product) β€” Evidence linking pattern +- [Anthropic Streaming API](https://docs.anthropic.com/en/api/streaming) β€” SSE implementation + +--- + +## 10. Glossary & Abbreviations + +| Term | Betekenis | +|------|-----------| +| **Epic** | Grote feature of fase in development (bevat meerdere stories) | +| **Story** | Kleine, uitvoerbare taak binnen een epic | +| **Story Points** | Schatting van complexiteit (Fibonacci: 1, 2, 3, 5, 8, 13, 21) | +| **SP** | Story Points (afkorting) | +| **MVP** | Minimum Viable Product | +| **P1/P2/P3** | Priority tiers (P1 = kritiek, P2 = belangrijk, P3 = waardevol) | +| **SSE** | Server-Sent Events (streaming protocol) | +| **DRY** | Don't Repeat Yourself | +| **KISS** | Keep It Simple, Stupid | +| **SOC** | Separation of Concerns | +| **YAGNI** | You Aren't Gonna Need It | +| **RLS** | Row Level Security (Supabase) | +| **Intent** | Gebruikersintentie (dagnotitie, zoeken, overdracht, etc.) | +| **Artifact** | UI-component die verschijnt in artifact area (block) | +| **Block** | Herbruikbare UI-component (DagnotatieBlock, ZoekenBlock, etc.) | +| **Prefill** | Vooringevulde data in artifact o.b.v. AI entity extraction | +| **Medical Scribe** | AI-assistent die medische documentatie ondersteunt | +| **Linked Evidence** | Klikbare links naar bronnotities in AI-samenvatting | + +--- + +## 11. Story Points Reference + +**Fibonacci schaal voor story points:** + +| Points | Complexiteit | Geschatte tijd | Voorbeelden | +|--------|--------------|----------------|-------------| +| 1 | Trivial | 1-2 uur | Feature flag setup, config wijziging | +| 2 | Simple | 2-4 uur | Component skeleton, store uitbreiding (1 field) | +| 3 | Small | 4-8 uur | Simpele component met state, basic API endpoint | +| 5 | Medium | 1-2 dagen | Complex component, API met business logic | +| 8 | Large | 2-3 dagen | Feature met meerdere componenten, integrations | +| 13 | Very Large | 3-5 dagen | Epic-level feature, major refactor | +| 21 | Extra Large | 1 week+ | Waarschijnlijk te groot, split in kleinere stories | + +**Velocity tracking:** +- **Target velocity:** ~12 SP per week (1 developer) +- **Sprint length:** 1 week +- **Total project:** 86 SP β‰ˆ 7 weken (met buffer = 8 weken) + +--- + +**Versiehistorie:** + +| Versie | Datum | Auteur | Wijziging | +|--------|-------|--------|-----------| +| v1.0 | 27-12-2024 | Colin Lit | InitiΓ«le versie - complete bouwplan v3.0 | diff --git a/docs/swift/fo-swift-medical-scribe-v3.md b/docs/swift/fo-swift-medical-scribe-v3.md new file mode 100644 index 0000000..1e17e7c --- /dev/null +++ b/docs/swift/fo-swift-medical-scribe-v3.md @@ -0,0 +1,742 @@ +# 🧩 Functioneel Ontwerp (FO) β€” Swift Medical Scribe Chatbot + +**Projectnaam:** Swift β€” Medical Scribe Chatbot Interface +**Versie:** v3.0 +**Datum:** 27-12-2024 +**Auteur:** Colin Lit + +--- + +## 1. Doel en relatie met het PRD + +🎯 **Doel van dit document:** +Dit Functioneel Ontwerp beschrijft het **redesign** van Swift naar een medical scribe chatbot interface. De gebruiker voert een natuurlijke conversatie met een AI-assistent die intents herkent, acties uitvoert, en relevante UI-componenten toont in een split-screen layout. + +πŸ“˜ **Relatie met andere documenten:** +- **PRD:** `nextgen-epd-prd-ephemeral-ui-epd.md` β€” Ephemeral UI visie +- **UX/UI:** `swift-ux-v2.1.md` β€” Visuele specificaties (wordt herzien) +- **UX Research:** `nextgen-epd-onderzoeksverslag-ux-ui-patterns.md` β€” Marktanalyse +- **Bouwplan:** `bouwplan-swift-v2.md` β€” Development roadmap + +**Kernprincipe:** +> De gebruiker voert een natuurlijke conversatie met een medical scribe assistent. De assistent herkent intents, voert acties uit, en toont relevante UI-componenten (artifacts) rechts in beeld. De conversatie blijft zichtbaar en doorlopend β€” zoals ChatGPT Canvas of Claude Artifacts. + +**Belangrijkste wijzigingen t.o.v. v2.0:** + +| Aspect | v2.0 (Command Center) | v3.0 (Medical Scribe) | +|--------|----------------------|----------------------| +| Input model | Command-line stijl | Natuurlijke conversatie | +| UI paradigma | Blocks die verschijnen/verdwijnen | Chat links, artifacts rechts | +| Context | Per commando | Doorlopende conversatiegeschiedenis | +| AI rol | Intent classifier | Converserende medical scribe | +| Interactie | Transactioneel | Relationeel, follow-up mogelijk | + +--- + +## 2. Overzicht van de belangrijkste onderdelen + +🎯 **Doel:** Overzicht van alle modules en hun relaties. + +### 2.1 Systeemcomponenten + +| # | Component | Beschrijving | Type | +|---|-----------|--------------|------| +| 1 | **Command Center** | Hoofdscherm met split-screen layout | Scherm | +| 2 | **Context Bar** | Dienst, actieve patiΓ«nt, user info | UI Zone | +| 3 | **Chat Panel** | Doorlopende conversatie (links, 40%) | UI Zone | +| 4 | **Artifact Area** | Waar blocks verschijnen (rechts, 60%) | UI Zone | +| 5 | **Chat Input** | Tekst + voice input (onderaan chat) | UI Zone | +| 6 | **Chat API** | Medical scribe chatbot endpoint | Backend | +| 7 | **Intent Engine** | Herkent intents in conversatie (hybrid) | Backend | +| 8 | **Context Manager** | Beheert sessie context + chat history | Backend | + +### 2.2 Artifacts (Bouwblokken) + +| Prio | Artifact | Functie | Trigger voorbeelden | +|------|----------|---------|---------------------| +| P1 | **DagnotatieBlock** | Snelle notitie invoer | "medicatie gegeven aan jan" | +| P1 | **ZoekenBlock** | PatiΓ«nt zoeken | "wie is jan de vries" | +| P1 | **PatientContextCard** | PatiΓ«nt overzicht | Na zoeken / selectie | +| P1 | **OverdrachtBlock** | Dienst overdracht met AI-filtering | "maak overdracht" | +| P2 | **RapportageBlock** | Behandelrapportage | "gesprek gehad met jan" | +| P2 | **AgendaBlock** | Afspraken | "mijn afspraken vandaag" | +| P2 | **MetingenBlock** | Vitale functies | "bloeddruk invoeren" | + +**Belangrijk:** Artifacts blijven functioneel hetzelfde als v2.0 blocks, maar verschijnen nu rechts in een persistent panel. + +### 2.3 Rol-specifieke Views + +| Rol | Primaire workflow | Artifact focus | +|-----|-------------------|----------------| +| **Verpleegkundige** | Notities maken tijdens dienst | DagnotatieBlock, RapportageBlock | +| **Psychiater** | Gefilterde overdracht lezen | OverdrachtBlock met AI-samenvatting | + +--- + +## 3. User Stories + +🎯 **Doel:** Beschrijven wat gebruikers moeten kunnen doen, vanuit hun perspectief. + +### 3.1 Nieuwe Stories (v3.0) + +| ID | Rol | Doel / Actie | Verwachte waarde | Prio | +|----|-----|--------------|------------------|------| +| US-15 | Alle gebruikers | Natuurlijke conversatie voeren met assistent | Voelt als praten met collega | πŸ”΄ P1 | +| US-16 | Alle gebruikers | Conversatiegeschiedenis zien | Context behouden tijdens werk | πŸ”΄ P1 | +| US-17 | Alle gebruikers | Doorvragen zonder opnieuw te beginnen | Flexibele workflow | πŸ”΄ P1 | +| US-18 | Alle gebruikers | Assistent stelt verduidelijkingsvragen | Minder fouten, betere data | 🟑 P2 | +| US-19 | Alle gebruikers | Meerdere acties in één conversatie | EfficiΓ«nte workflow | 🟑 P2 | +| US-20 | Verpleegkundige | Notities maken via spraak of typen | Hands-free documentatie | πŸ”΄ P1 | +| US-21 | Verpleegkundige | Zien welke notities relevant zijn voor psychiater | Transparantie in filtering | 🟑 P2 | +| US-22 | Psychiater | Alleen behandelrelevante info zien | Geen ruis, focus op behandeling | πŸ”΄ P1 | +| US-23 | Psychiater | Doorklikken naar originele bron | Verificatie en context | πŸ”΄ P1 | + +### 3.2 Bestaande Stories (herzien) + +| ID | Rol | Doel / Actie | Wijziging v3.0 | +|----|-----|--------------|----------------| +| US-01 | Verpleegkundige | Dagnotitie maken | Via conversatie: "Ik heb medicatie gegeven aan Jan" | +| US-02 | Verpleegkundige | PatiΓ«nt zoeken | Via conversatie: "Wie is Jan de Vries?" | +| US-04 | Verpleegkundige | Overdracht maken | Via conversatie: "Maak overdracht voor deze dienst" | + +--- + +## 4. Functionele werking per onderdeel + +🎯 **Doel:** Per component beschrijven wat de gebruiker kan doen en wat het systeem doet. + +### 4.1 Command Center (Hoofdscherm) + +**Beschrijving:** +Split-screen layout met chat links (40%) en artifacts rechts (60%). De gebruiker voert een natuurlijke conversatie met de medical scribe assistent. + +**Layout:** + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ πŸ• Ochtend | 8 ptn Jan de Vries β–Ό πŸ‘€ SV β”‚ +β”‚ CONTEXT BAR β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ β”‚ +β”‚ CHAT PANEL (40%) β”‚ ARTIFACT AREA (60%) β”‚ +β”‚ β”‚ β”‚ +β”‚ πŸ‘€ "Ik heb net medicatie β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ gegeven aan Jan" β”‚ β”‚ πŸ“ Dagnotitie β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ πŸ€– Ik maak een dagnotitie β”‚ β”‚ PatiΓ«nt: Jan de Vries βœ“ β”‚ β”‚ +β”‚ voor Jan de Vries. β”‚ β”‚ Categorie: Medicatie βœ“ β”‚ β”‚ +β”‚ Categorie: Medicatie. β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ Notitie: β”‚ β”‚ +β”‚ Wil je nog iets β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚ +β”‚ toevoegen? β”‚ β”‚ β”‚ medicatie gegeven β”‚β”‚ β”‚ +β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚ +β”‚ πŸ‘€ "Nee, opslaan" β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ ☐ Relevant voor psychiater β”‚ β”‚ +β”‚ πŸ€– βœ“ Notitie opgeslagen β”‚ β”‚ β”‚ β”‚ +β”‚ voor Jan de Vries. β”‚ β”‚ [Annuleren] [πŸ’Ύ Opslaan] β”‚ β”‚ +β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ +β”‚ πŸ’¬ Typ of spreek... 🎀 β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +**Gedrag:** +- Bij laden: Chat input heeft focus, artifact area toont placeholder +- Keyboard shortcut `⌘K` focust chat input vanaf elke plek +- Artifacts verschijnen rechts met slide-in animatie (200ms) +- Chat blijft zichtbaar en scrollbaar tijdens werk met artifacts +- Meerdere artifacts mogelijk via tabs (max 3 tegelijk) + +**States:** + +| State | Chat Panel | Artifact Area | +|-------|------------|---------------| +| Initial | Welcome message | Placeholder: "Artifacts verschijnen hier" | +| Conversing | Chat history + streaming response | Ongewijzigd of artifact | +| Action triggered | Chat continues | Artifact slide-in | +| Working | Chat beschikbaar | Artifact actief | +| Completed | Success message in chat | Artifact sluit of blijft | + +--- + +### 4.2 Context Bar + +**Functie:** Toont essentiΓ«le context: dienst, actieve patiΓ«nt, gebruiker. + +**Elementen:** + +| Element | Beschrijving | Interactie | +|---------|--------------|------------| +| Dienst indicator | πŸ• Ochtend / Middag / Nacht + patiΓ«ntentelling | Geen | +| Actieve patiΓ«nt | Dropdown met recent geselecteerde patiΓ«nten | Klik opent selector | +| User info | Avatar + initialen | Klik opent menu | + +**Dienst kleuren:** + +| Dienst | Tijd | Kleur | +|--------|------|-------| +| Ochtend | 07:00-15:00 | Amber (#F59E0B) | +| Middag | 15:00-23:00 | Blue (#3B82F6) | +| Nacht | 23:00-07:00 | Indigo (#6366F1) | + +--- + +### 4.3 Chat Panel + +**Functie:** Toont doorlopende conversatie met medical scribe assistent. + +**Elementen:** + +| Element | Beschrijving | +|---------|--------------| +| Chat Messages | Scrollbare lijst van user en assistant messages | +| Message Bubbles | User: rechts, amber bg / Assistant: links, slate bg | +| Streaming Indicator | Pulsating dots tijdens AI response | +| Action Links | Klikbare links naar gerelateerde artifacts | +| Timestamps | Optioneel, alleen bij pauzes >5 minuten | + +**Message Types:** + +| Type | Weergave | Voorbeeld | +|------|----------|-----------| +| User message | Rechts, amber | "medicatie gegeven aan jan" | +| Assistant text | Links, slate | "Ik maak een dagnotitie..." | +| Assistant action | Links, met icon | "πŸ“ Dagnotitie geopend" (klikbaar) | +| System message | Centered, subtle | "βœ“ Notitie opgeslagen" | +| Error message | Links, red border | "Er ging iets mis. Probeer opnieuw." | + +**Gedrag:** +- Auto-scroll naar laatste message +- Scroll-lock wanneer gebruiker omhoog scrollt +- "Scroll to bottom" knop bij nieuwe messages +- Max 100 messages in view (pagination voor oudere) + +--- + +### 4.4 Chat Input + +**Functie:** Tekst + voice input voor conversatie met medical scribe. + +**States:** + +| State | Weergave | Trigger | +|-------|----------|---------| +| Default | "Typ of spreek..." + mic icon | β€” | +| Typing | Cursor + getypte tekst | Keyboard input | +| Listening | πŸ”΄ + waveform + live transcript | Mic click of spatie | +| Processing | Disabled, "Denkt na..." | Na submit | +| Streaming | Disabled, streaming in chat | Tijdens AI response | + +**Keyboard Shortcuts:** + +| Key | Actie | +|-----|-------| +| `Enter` | Submit message | +| `⌘Enter` / `Ctrl+Enter` | Force submit (ook tijdens streaming) | +| `Escape` | Clear input / cancel voice | +| `↑` | Vorige message (edit history) | +| `Space` (leeg) | Start voice recording | +| `⌘K` | Focus input | + +**Voice Flow:** +1. User klikt mic of drukt spatie (bij lege input) +2. Deepgram start streaming transcription +3. Live transcript verschijnt in input field +4. Pauze detectie (1.5 sec stilte) β†’ auto-submit +5. Of user klikt "Stop" β†’ submit + +--- + +### 4.5 Artifact Area + +**Functie:** Toont actieve artifacts (blocks) rechts van de chat. + +**Layout opties:** + +| Situatie | Weergave | +|----------|----------| +| Geen artifact | Placeholder met voorbeelden | +| EΓ©n artifact | Full width, centered | +| Meerdere artifacts | Tabs bovenaan (max 3) | + +**Artifact Lifecycle:** + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 1. Intent detected in chat β”‚ +β”‚ β†’ AI response: "Ik maak een dagnotitie..." β”‚ +β”‚ β†’ Action object attached to response β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 2. Artifact appears β”‚ +β”‚ β†’ Slide-in animation (200ms, from right) β”‚ +β”‚ β†’ Pre-filled with extracted entities β”‚ +β”‚ β†’ Focus moves to first editable field β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 3. User interacts β”‚ +β”‚ β†’ Edits fields in artifact β”‚ +β”‚ β†’ Can continue chatting (e.g., "voeg toe: sliep goed") β”‚ +β”‚ β†’ Chat updates artifact in real-time β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 4. User saves or cancels β”‚ +β”‚ β†’ Success: toast + chat confirmation + artifact closes β”‚ +β”‚ β†’ Cancel: artifact closes, no confirmation β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +**Placeholder State:** + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ β”‚ +β”‚ πŸ’¬ Artifacts verschijnen hier β”‚ +β”‚ β”‚ +β”‚ Vraag me iets, bijvoorbeeld: β”‚ +β”‚ β€’ "Notitie voor Jan: medicatie gegeven" β”‚ +β”‚ β€’ "Zoek Marie van den Berg" β”‚ +β”‚ β€’ "Maak overdracht voor deze dienst" β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +--- + +### 4.6 Medical Scribe Chat API + +**Functie:** Chatbot endpoint die conversatie voert en intents herkent. + +**Endpoint:** `POST /api/swift/chat` + +**Request:** + +```typescript +interface ChatRequest { + message: string; // User message + messages: ChatMessage[]; // Conversation history (max 20) + context: { + activePatient?: Patient; // Currently selected patient + shift: 'ochtend' | 'middag' | 'nacht'; + userId: string; + recentActions: RecentAction[]; // Last 5 actions + }; +} +``` + +**Response (Server-Sent Events):** + +```typescript +// Text chunk (streaming) +{ type: 'text', content: string } + +// Action detected (end of response) +{ + type: 'action', + intent: Intent, + entities: ExtractedEntities, + confidence: number, + artifact?: { + type: ArtifactType, + prefill: PrefillData + } +} + +// Done +{ type: 'done' } +``` + +**System Prompt (samenvatting):** + +``` +Je bent een medische assistent (medical scribe) voor Swift, een Nederlands GGZ EPD. + +Je rol: +- Help zorgmedewerkers met documentatie en administratie +- Voer natuurlijke gesprekken in het Nederlands +- Herken intents en voer acties uit wanneer nodig +- Stel verduidelijkingsvragen bij onduidelijkheid +- Wees vriendelijk maar professioneel + +Intents die je herkent: +- dagnotitie: notitie maken voor patiΓ«nt +- zoeken: patiΓ«nt zoeken +- rapportage: behandelrapportage schrijven +- overdracht: dienst overdracht maken +- metingen: vitale functies invoeren +- agenda: afspraken bekijken + +Wanneer je een intent herkent, voeg een JSON action object toe aan je response. + +Huidige context: +- Actieve patiΓ«nt: {activePatient} +- Dienst: {shift} +- Recente acties: {recentActions} +``` + +--- + +### 4.7 Intent Engine (Hybrid) + +**Functie:** Herkent intents in conversatie met two-tier approach. + +**Tier 1: Local Pattern Matching (<50ms)** + +| Pattern | Intent | Entities | +|---------|--------|----------| +| "notitie [naam]" | dagnotitie | patient: naam | +| "zoek [naam]" | zoeken | query: naam | +| "overdracht" | overdracht | β€” | +| "bloeddruk [naam]" | metingen | patient: naam, type: bloeddruk | + +**Tier 2: AI Classification (via Chat API)** + +Wanneer local patterns geen match geven of confidence <0.8, bepaalt de Chat API het intent op basis van conversatie-context. + +**Voorbeelden:** + +| Conversatie | Intent | Methode | +|-------------|--------|---------| +| "notitie jan medicatie" | dagnotitie | Local (direct match) | +| "Ik heb net een gesprek gehad" | rapportage | AI (context needed) | +| "Hij geeft aan zich beter te voelen" | (context) | AI (follow-up) | +| "Wie was die mevrouw van kamer 12?" | zoeken | AI (indirect) | + +--- + +### 4.8 AI-Filtering voor Psychiater (Overdracht) + +**Functie:** Filtert verpleegkundige rapportages naar behandelrelevante informatie. + +**Wat WEL naar psychiater gaat:** + +| Categorie | Voorbeelden | +|-----------|-------------| +| Medicatie-issues | Weigering, bijwerkingen, therapierespons | +| Stemming/gedrag verandering | t.o.v. baseline, significante shifts | +| Risico-signalen | SuΓ―cidale uitingen, zelfbeschadiging, agressie | +| Signaleringsplan triggers | Oranje/rood fase signalen | +| Psychotische symptomen | Hallucinaties, wanen | +| Behandelplan stagnatie | Geen voortgang op doelen | + +**Wat NIET naar psychiater gaat:** + +| Categorie | Voorbeelden | +|-----------|-------------| +| Routine medicatie | "Medicatie volgens schema ingenomen" | +| ADL activiteiten | "Heeft gedoucht", "Ontbijt genuttigd" | +| Standaard observaties | "Rustige dag", "Goed geslapen" | +| Sociale activiteiten | "Bezoek gehad", "Mee naar dagactiviteit" | + +**Linked Evidence:** +Elke zin in de AI-samenvatting linkt naar de originele verpleegkundige notitie. De psychiater kan hover-to-preview of click-to-expand gebruiken. + +**UI in OverdrachtBlock:** + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ πŸ”„ Overdracht Ochtend β†’ Middag [Γ—] β”‚ +β”‚ 07:00 - 15:00 | 8 patiΓ«nten β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ Behandelrelevant (3 patiΓ«nten) β”‚ +β”‚ ─────────────────────────────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ β–Ό Jan de Vries ⚠️ Alert β”‚ +β”‚ Weigerde ochtendmedicatie. Geeft aan last te hebben β”‚ +β”‚ van bijwerkingen (duizeligheid). Stemming somberder β”‚ +β”‚ dan gisteren. β”‚ +β”‚ πŸ“Ž 3 bronnotities [Bekijk bronnen] β”‚ +β”‚ β”‚ +β”‚ β–Ά Marie van den Berg β”‚ +β”‚ β–Ά Piet Jansen β”‚ +β”‚ β”‚ +β”‚ ─────────────────────────────────────────────────────── β”‚ +β”‚ Geen bijzonderheden (5 patiΓ«nten) β”‚ +β”‚ [Toon allen β–Ό] β”‚ +β”‚ β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ [πŸ“‹ Kopieer] [πŸ“€ Naar EPD] [βœ“ Gezien] β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +--- + +## 5. User Flows + +🎯 **Doel:** Laten zien hoe de gebruiker stap-voor-stap door het systeem gaat. + +### Flow 1: Dagnotitie via Conversatie + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 1. Verpleegkundige opent Swift β”‚ +β”‚ β†’ Chat: welcome message β”‚ +β”‚ β†’ Artifact: placeholder β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 2. Verpleegkundige typt: "Medicatie gegeven aan Jan" β”‚ +β”‚ β†’ Message verschijnt in chat β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 3. AI Response (streaming): β”‚ +β”‚ "Ik maak een dagnotitie voor Jan de Vries. β”‚ +β”‚ Categorie: Medicatie. Wil je nog iets toevoegen?" β”‚ +β”‚ β†’ Action: intent=dagnotitie, patient=Jan, cat=Medicatie β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 4. DagnotatieBlock verschijnt rechts: β”‚ +β”‚ β†’ Patient: Jan de Vries βœ“ (pre-filled) β”‚ +β”‚ β†’ Categorie: Medicatie βœ“ (pre-filled) β”‚ +β”‚ β†’ Text: "Medicatie gegeven" (pre-filled) β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 5. Verpleegkundige: "Nee, opslaan" β”‚ +β”‚ β†’ Of: klikt direct op Opslaan knop β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 6. Resultaat: β”‚ +β”‚ β†’ Toast: "βœ“ Notitie opgeslagen" β”‚ +β”‚ β†’ Chat: "Notitie opgeslagen voor Jan de Vries." β”‚ +β”‚ β†’ Artifact sluit (of blijft voor volgende) β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ TIJD: ~15 seconden β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Flow 2: Overdracht met AI-Filtering (Psychiater) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 1. Psychiater opent Swift β”‚ +β”‚ β†’ Chat: "Goedemorgen! Wil je de overdracht bekijken?" β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 2. Psychiater: "Ja, laat zien" β”‚ +β”‚ β†’ Of: "Overdracht ochtend" β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 3. AI Response: β”‚ +β”‚ "Ik haal de overdracht op. 3 patiΓ«nten hebben β”‚ +β”‚ behandelrelevante updates." β”‚ +β”‚ β†’ OverdrachtBlock verschijnt rechts β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 4. OverdrachtBlock toont: β”‚ +β”‚ β†’ Gefilterde samenvatting (alleen behandelrelevant) β”‚ +β”‚ β†’ PatiΓ«nten gesorteerd op urgentie β”‚ +β”‚ β†’ "Geen bijzonderheden" sectie ingeklapt β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 5. Psychiater klikt op "πŸ“Ž 3 bronnotities" bij Jan β”‚ +β”‚ β†’ Slide-in panel met originele verpleegkundige notities β”‚ +β”‚ β†’ Timestamps en auteurs zichtbaar β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 6. Psychiater in chat: "Wat was er gisteren met Jan?" β”‚ +β”‚ β†’ AI antwoordt met context uit eerdere notities β”‚ +β”‚ β†’ Geen nieuw artifact nodig β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 7. Psychiater klikt "βœ“ Gezien" β”‚ +β”‚ β†’ Overdracht gemarkeerd als gelezen β”‚ +β”‚ β†’ Chat: "Overdracht gemarkeerd als gezien." β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Flow 3: Rapportage met Verduidelijkingsvragen + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 1. Verpleegkundige: "Ik heb een gesprek gehad" β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 2. AI: "Met welke patiΓ«nt had je het gesprek?" β”‚ +β”‚ β†’ Geen artifact (verduidelijking nodig) β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 3. Verpleegkundige: "Jan" β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 4. AI: "Ik maak een rapportage voor Jan de Vries. β”‚ +β”‚ Wat wil je vastleggen?" β”‚ +β”‚ β†’ RapportageBlock verschijnt rechts (leeg) β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 5. Verpleegkundige: "Hij voelt zich beter, minder angstig" β”‚ +β”‚ β†’ Tekst verschijnt in RapportageBlock β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 6. AI: "Genoteerd. Wil je dit als voortgangsgesprek β”‚ +β”‚ opslaan of is er meer?" β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 7. Verpleegkundige: "Opslaan als voortgang" β”‚ +β”‚ β†’ Rapportage opgeslagen met tag "Voortgangsgesprek" β”‚ +β”‚ β†’ Toast + chat confirmation β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +--- + +## 6. Interacties met AI + +🎯 **Doel:** Uitleggen waar AI in de flow voorkomt en wat de gebruiker ziet. + +| Locatie | AI-actie | Trigger | Output | +|---------|----------|---------|--------| +| Chat | Conversatie + intent detection | Elke user message | Streaming text + action object | +| Chat | Verduidelijkingsvraag | Onduidelijke intent | Vraag in chat (geen artifact) | +| Chat | Follow-up verwerking | User antwoord op vraag | Update artifact of nieuwe info | +| OverdrachtBlock | Relevantie-filtering | "overdracht" intent | Gefilterde samenvatting | +| OverdrachtBlock | Samenvatting generatie | Per patiΓ«nt | Behandelrelevante bullets | +| RapportageBlock | Tekst structureren | "Structureer" knop | Gestructureerde tekst | +| RapportageBlock | B1-niveau herschrijven | "Vereenvoudig" knop | Herschreven tekst | + +**Confidence Thresholds:** + +| Confidence | Actie | +|------------|-------| +| >0.9 | Direct artifact openen met prefill | +| 0.7-0.9 | Artifact openen + bevestigingsvraag in chat | +| 0.5-0.7 | Verduidelijkingsvraag in chat, geen artifact | +| <0.5 | Fallback: "Ik begrijp je niet helemaal. Kun je het anders formuleren?" | + +--- + +## 7. Gebruikersrollen en rechten + +🎯 **Doel:** Beschrijven welke rollen toegang hebben tot welke onderdelen. + +| Rol | Toegang | Artifacts | AI-filtering | +|-----|---------|-----------|--------------| +| **Verpleegkundige** | Eigen dienst patiΓ«nten | Alle P1/P2 artifacts | Input: alle notities | +| **Psychiater** | Alle patiΓ«nten in behandeling | OverdrachtBlock (read), PatientContextCard | Output: gefilterde samenvatting | +| **Behandelaar** | Eigen caseload | Alle artifacts | Beide views beschikbaar | + +**Permissies per Artifact:** + +| Artifact | Verpleegkundige | Psychiater | Behandelaar | +|----------|-----------------|------------|-------------| +| DagnotatieBlock | βœ… Create | ❌ | βœ… Create | +| RapportageBlock | βœ… Create | πŸ‘οΈ Read | βœ… Create | +| OverdrachtBlock | βœ… Create | πŸ‘οΈ Read (filtered) | βœ… Both | +| PatientContextCard | πŸ‘οΈ Read | πŸ‘οΈ Read | πŸ‘οΈ Read | + +--- + +## 8. Technische Specificaties + +### 8.1 API Routes + +| Route | Method | Functie | Status | +|-------|--------|---------|--------| +| `/api/swift/chat` | POST | Medical scribe chatbot | πŸ†• Nieuw | +| `/api/swift/overdracht/generate` | POST | AI-gefilterde overdracht | πŸ”„ Herzien | +| `/api/intent/classify` | POST | Intent classification | βœ… Bestaat | +| `/api/patients/search` | GET | Patient search | βœ… Bestaat | +| `/api/reports` | POST | Report opslaan | βœ… Bestaat | + +### 8.2 Store Uitbreiding + +```typescript +interface SwiftStore { + // Bestaande state + activePatient: Patient | null; + activeBlock: BlockType | null; + shift: 'ochtend' | 'middag' | 'nacht'; + + // Chat state (nieuw) + chatMessages: ChatMessage[]; + isStreaming: boolean; + pendingAction: Action | null; + + // Artifact state (nieuw) + openArtifacts: Artifact[]; // Max 3 + activeArtifactId: string | null; + + // Actions + addChatMessage: (message: ChatMessage) => void; + processAction: (action: Action) => void; + openArtifact: (artifact: Artifact) => void; + closeArtifact: (id: string) => void; +} +``` + +### 8.3 Component Structuur + +``` +components/swift/ +β”œβ”€β”€ command-center/ +β”‚ β”œβ”€β”€ command-center.tsx # Split-screen container +β”‚ β”œβ”€β”€ context-bar.tsx # Header met dienst/patient +β”‚ β”œβ”€β”€ chat-panel.tsx # πŸ†• Chat messages +β”‚ β”œβ”€β”€ chat-input.tsx # Herzien: conversational +β”‚ └── artifact-area.tsx # πŸ†• Artifact container +β”œβ”€β”€ chat/ +β”‚ β”œβ”€β”€ chat-message.tsx # πŸ†• Individual message +β”‚ β”œβ”€β”€ chat-action-link.tsx # πŸ†• Clickable action +β”‚ └── streaming-indicator.tsx # πŸ†• Typing dots +β”œβ”€β”€ artifacts/ +β”‚ β”œβ”€β”€ artifact-container.tsx # πŸ†• Wrapper met tabs +β”‚ β”œβ”€β”€ dagnotitie-block.tsx # Bestaand +β”‚ β”œβ”€β”€ zoeken-block.tsx # Bestaand +β”‚ β”œβ”€β”€ overdracht-block.tsx # Herzien: met filtering UI +β”‚ β”œβ”€β”€ rapportage-block.tsx # Bestaand +β”‚ └── patient-context-card.tsx # Bestaand +└── shared/ + β”œβ”€β”€ linked-evidence.tsx # πŸ†• Bron-verwijzing component + └── relevance-badge.tsx # πŸ†• "Behandelrelevant" indicator +``` + +--- + +## 9. UI Specificaties + +### 9.1 Layout Breakpoints + +| Viewport | Chat Panel | Artifact Area | +|----------|------------|---------------| +| Desktop (>1200px) | 40% | 60% | +| Tablet (768-1200px) | 45% | 55% | +| Mobile (<768px) | Full screen toggle | Full screen toggle | + +### 9.2 Chat Message Styling + +| Element | User Message | Assistant Message | +|---------|--------------|-------------------| +| Alignment | Right | Left | +| Background | Amber-50 (#FFFBEB) | Slate-100 (#F1F5F9) | +| Border | Amber-200 | Slate-200 | +| Max width | 80% | 80% | +| Border radius | 16px (top-right: 4px) | 16px (top-left: 4px) | + +### 9.3 Artifact Animation + +```css +/* Slide-in from right */ +@keyframes artifact-enter { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } +} + +.artifact-enter { + animation: artifact-enter 200ms ease-out; +} +``` + +--- + +## 10. Bijlagen & Referenties + +🎯 **Doel:** Linken naar overige documenten. + +### Project Documentatie +- PRD Ephemeral UI: `nextgen-epd-prd-ephemeral-ui-epd.md` +- UX/UI Specs: `swift-ux-v2.1.md` +- UX Research: `nextgen-epd-onderzoeksverslag-ux-ui-patterns.md` +- Bouwplan: `bouwplan-swift-v2.md` +- Project Status: `PROJECT-STATUS-2024-12-27.md` + +### Externe Referenties +- [ChatGPT Canvas UX Analysis](https://altar.io/next-gen-of-human-ai-collaboration/) +- [Claude Artifacts Documentation](https://docs.anthropic.com) +- [Abridge Linked Evidence](https://www.abridge.com/product) +- [GGZ Zorgstandaarden](https://www.ggzstandaarden.nl) + +--- + +## Wijzigingslog + +| Versie | Datum | Wijzigingen | +|--------|-------|-------------| +| v2.0 | 23-12-2024 | Command Center met ephemeral blocks | +| v2.1 | 23-12-2024 | Prioriteitenlijst, intent mapping, P3 blocks | +| v3.0 | 27-12-2024 | **Redesign:** Chat + Artifact interface, Medical Scribe conversatie, AI-filtering voor psychiater | diff --git a/docs/swift/haalbaarheidsanalyse-v3.md b/docs/swift/haalbaarheidsanalyse-v3.md new file mode 100644 index 0000000..9b11314 --- /dev/null +++ b/docs/swift/haalbaarheidsanalyse-v3.md @@ -0,0 +1,437 @@ +# πŸ“Š Haalbaarheidsanalyse: Swift Medical Scribe v3.0 + +**Datum:** 27-12-2024 +**Document:** `fo-swift-medical-scribe-v3.md` +**Auteur:** AI Assistant + +--- + +## Executive Summary + +Het v3.0 redesign van Swift naar een medical scribe chatbot interface is **haalbaar**, maar vereist significante architecturale wijzigingen. De bestaande foundation (Command Center, blocks, intent classification) kan worden hergebruikt, maar de conversatie-laag en split-screen layout zijn nieuw. + +**Kernbevindingen:** +- βœ… **Sterke foundation:** Bestaande blocks, intent API, en voice input kunnen worden hergebruikt +- ⚠️ **Grote wijzigingen:** Conversatie-interface, chat API, en split-screen layout zijn nieuw +- βœ… **AI-infrastructuur:** Streaming chat API bestaat al (docs-chat), kan worden aangepast +- ⚠️ **Complexiteit:** Conversatiegeschiedenis en context management vereisen nieuwe state management + +**Geschatte effort:** 6-8 weken (1 developer, full-time) + +--- + +## 1. Inventarisatie Bestaande Componenten + +### 1.1 βœ… Wat bestaat al en kan worden hergebruikt + +| Component | Status | Locatie | Hergebruik | +|-----------|--------|---------|------------| +| **Command Center** | βœ… Done | `components/swift/command-center/` | ⚠️ Layout wijzigen naar split-screen | +| **Context Bar** | βœ… Done | `components/swift/command-center/context-bar.tsx` | βœ… Direct hergebruikbaar | +| **Blocks (Artifacts)** | βœ… Done | `components/swift/blocks/` | βœ… Direct herbruikbaar | +| **Intent Classification** | βœ… Done | `/api/intent/classify` | βœ… Herbruikbaar, maar moet worden uitgebreid | +| **Voice Input** | βœ… Done | `lib/swift/use-swift-voice.ts` | βœ… Direct herbruikbaar | +| **Swift Store** | βœ… Done | `stores/swift-store.ts` | ⚠️ Uitbreiden met chat state | +| **Overdracht API** | βœ… Done | `/api/overdracht/generate` | βœ… Bestaat, maar AI-filtering voor psychiater moet worden toegevoegd | +| **Streaming Chat API** | βœ… Bestaat | `/api/docs/chat` | βœ… Pattern kan worden gekopieerd | + +### 1.2 πŸ†• Wat nieuw moet worden gebouwd + +| Component | Complexiteit | Geschatte Effort | +|-----------|-------------|------------------| +| **Chat Panel** | Medium | 1 week | +| **Chat Input (conversational)** | Low | 3 dagen | +| **Chat API (`/api/swift/chat`)** | High | 1.5 week | +| **Artifact Area (split-screen)** | Medium | 1 week | +| **Chat Message Components** | Low | 3 dagen | +| **Conversation History Management** | Medium | 1 week | +| **AI-filtering voor psychiater** | Medium | 1 week | +| **Linked Evidence UI** | Low | 3 dagen | + +**Totaal nieuwe componenten:** ~6-7 weken + +--- + +## 2. Gedetailleerde Analyse per Sectie + +### 2.1 Command Center β†’ Split-Screen Layout + +**Huidige situatie:** +- 4-zone layout: Context Bar | Canvas Area | Recent Strip | Command Input +- Blocks verschijnen in Canvas Area (centered, full-width) + +**Vereiste wijziging:** +- Split-screen: Chat Panel (40%) links, Artifact Area (60%) rechts +- Recent Strip kan worden verwijderd of geΓ―ntegreerd in chat + +**Haalbaarheid:** βœ… **Goed** +- Layout wijziging is relatief eenvoudig met CSS Grid/Flexbox +- Bestaande blocks blijven werken, alleen positioning wijzigt +- **Effort:** 3-5 dagen + +**Risico's:** +- Responsive design voor mobile/tablet vereist toggle tussen chat en artifact +- Keyboard shortcuts moeten worden aangepast + +--- + +### 2.2 Chat Panel & Conversatie + +**Huidige situatie:** +- Geen chat interface +- Command Input stuurt direct naar intent classification + +**Vereiste wijziging:** +- Nieuwe Chat Panel component met message bubbles +- Conversatiegeschiedenis (max 100 messages) +- Streaming responses (zoals docs-chat) + +**Haalbaarheid:** βœ… **Goed** +- Pattern bestaat al in `components/docs-chat/` +- `use-docs-chat.ts` hook kan worden aangepast voor Swift +- **Effort:** 1 week + +**Risico's:** +- Performance bij lange conversaties (pagination nodig) +- State management voor chat history (Zustand store uitbreiden) + +--- + +### 2.3 Medical Scribe Chat API + +**Huidige situatie:** +- `/api/intent/classify` retourneert alleen intent + entities +- Geen conversatie, geen streaming + +**Vereiste wijziging:** +- Nieuwe `/api/swift/chat` endpoint +- Streaming responses (SSE) +- Conversatiegeschiedenis als input +- Action objects in response (intent + entities + artifact prefill) + +**Haalbaarheid:** ⚠️ **Middelmatig** +- Pattern bestaat in `/api/docs/chat` (streaming met Claude) +- Moet worden uitgebreid met: + - Intent detection tijdens conversatie + - Action object generation + - Context management (activePatient, shift, recentActions) +- **Effort:** 1.5 week + +**Risico's:** +- AI prompt engineering voor medical scribe persona +- Performance bij hoge load (rate limiting nodig) +- Kosten (Claude API calls per message) + +**Aanbeveling:** +```typescript +// Hybrid approach: local intent first, AI voor conversatie +1. Local pattern matching (<50ms) β†’ direct action +2. Als geen match β†’ AI chat API met conversatie context +3. AI detecteert intent + genereert response + action object +``` + +--- + +### 2.4 Intent Engine (Hybrid) + +**Huidige situatie:** +- Two-tier: local patterns β†’ AI fallback +- Werkt goed voor directe commando's + +**Vereiste wijziging:** +- Local patterns blijven voor snelle acties +- AI chat API voor conversatie + follow-up vragen +- Confidence thresholds voor artifact opening + +**Haalbaarheid:** βœ… **Goed** +- Bestaande intent classifier blijft werken +- Chat API gebruikt AI voor conversatie + intent detection +- **Effort:** 3 dagen (integratie) + +--- + +### 2.5 Artifact Area (Split-Screen) + +**Huidige situatie:** +- Blocks verschijnen centered in Canvas Area +- EΓ©n block tegelijk + +**Vereiste wijziging:** +- Artifacts rechts (60% width) +- Meerdere artifacts mogelijk (tabs, max 3) +- Slide-in animatie van rechts + +**Haalbaarheid:** βœ… **Goed** +- Bestaande blocks blijven werken +- Nieuwe wrapper component met tabs +- **Effort:** 1 week + +**Risico's:** +- State management voor meerdere open artifacts +- Tab switching UX + +--- + +### 2.6 AI-Filtering voor Psychiater + +**Huidige situatie:** +- `/api/overdracht/generate` genereert samenvatting voor alle notities +- Geen filtering op behandelrelevantie + +**Vereiste wijziging:** +- AI-filtering: alleen behandelrelevante notities +- Linked evidence: elke zin linkt naar bronnotitie +- UI: "Behandelrelevant" vs "Geen bijzonderheden" secties + +**Haalbaarheid:** ⚠️ **Middelmatig** +- AI prompt moet worden uitgebreid met filtering criteria +- Linked evidence vereist tracking van bronnotities per zin +- **Effort:** 1 week + +**Risico's:** +- AI filtering accuracy (false negatives = belangrijke info gemist) +- Linked evidence parsing (welke zin komt van welke notitie?) + +**Aanbeveling:** +- Start met simpele keyword-based filtering als fallback +- AI filtering als primary, met optie om "alles te tonen" + +--- + +### 2.7 Store Uitbreiding + +**Huidige situatie:** +```typescript +interface SwiftStore { + activePatient: Patient | null; + activeBlock: BlockType | null; + prefillData: BlockPrefillData; + // ... geen chat state +} +``` + +**Vereiste wijziging:** +```typescript +interface SwiftStore { + // Bestaand + activePatient: Patient | null; + activeBlock: BlockType | null; + + // Nieuw: Chat state + chatMessages: ChatMessage[]; + isStreaming: boolean; + pendingAction: Action | null; + + // Nieuw: Artifact state + openArtifacts: Artifact[]; // Max 3 + activeArtifactId: string | null; +} +``` + +**Haalbaarheid:** βœ… **Goed** +- Zustand store is makkelijk uit te breiden +- **Effort:** 2 dagen + +--- + +## 3. Technische Risico's & Uitdagingen + +### 3.1 πŸ”΄ Hoge Risico's + +| Risico | Impact | Mitigatie | +|--------|--------|-----------| +| **AI Prompt Engineering** | High | Medical scribe persona moet natuurlijk klinken, maar ook betrouwbaar zijn. Iteratief testen met echte gebruikers. | +| **Performance bij lange conversaties** | Medium | Pagination voor chat history, max 100 messages in view. Virtual scrolling overwegen. | +| **AI Kosten** | Medium | Rate limiting, caching van responses waar mogelijk. Local patterns gebruiken voor snelle acties. | +| **State Management Complexiteit** | Medium | Duidelijke scheiding tussen chat state en artifact state. UseReducer overwegen voor complexe state. | + +### 3.2 🟑 Middelmatige Risico's + +| Risico | Impact | Mitigatie | +|--------|--------|-----------| +| **Responsive Design** | Medium | Mobile: toggle tussen chat en artifact. Tablet: 45/55 split. | +| **Linked Evidence Parsing** | Medium | AI moet structured output geven met bronverwijzingen per zin. Fallback: keyword matching. | +| **Conversatie Context Verlies** | Low | Context manager bewaart actieve patiΓ«nt, shift, recente acties. Max 20 messages in API call. | + +### 3.3 🟒 Lage Risico's + +| Risico | Impact | Mitigatie | +|--------|--------|-----------| +| **Block Migratie** | Low | Bestaande blocks blijven werken, alleen wrapper wijzigt. | +| **Voice Input** | Low | Bestaande implementatie blijft werken. | + +--- + +## 4. Migratie Strategie + +### 4.1 Fase 1: Foundation (Week 1-2) +- βœ… Split-screen layout implementeren +- βœ… Chat Panel component bouwen +- βœ… Store uitbreiden met chat state +- βœ… Basis chat API endpoint + +**Deliverable:** Werkende split-screen met chat (zonder AI) + +### 4.2 Fase 2: Chat API & Conversatie (Week 3-4) +- βœ… Medical scribe chat API implementeren +- βœ… Streaming responses +- βœ… Intent detection in conversatie +- βœ… Action object generation + +**Deliverable:** Werkende conversatie met artifact opening + +### 4.3 Fase 3: Artifact Area (Week 5) +- βœ… Artifact Area component met tabs +- βœ… Meerdere artifacts ondersteuning +- βœ… Slide-in animaties + +**Deliverable:** Meerdere artifacts tegelijk mogelijk + +### 4.4 Fase 4: AI-Filtering & Polish (Week 6-7) +- βœ… AI-filtering voor psychiater overdracht +- βœ… Linked evidence UI +- βœ… Error handling & edge cases +- βœ… Performance optimalisatie + +**Deliverable:** Volledige v3.0 functionaliteit + +### 4.5 Fase 5: Testing & Refinement (Week 8) +- βœ… User testing +- βœ… Bug fixes +- βœ… Performance tuning +- βœ… Documentatie + +**Deliverable:** Production-ready v3.0 + +--- + +## 5. Aanbevelingen + +### 5.1 βœ… Doen + +1. **Hergebruik bestaande patterns** + - Kopieer `use-docs-chat.ts` hook als basis voor Swift chat + - Hergebruik streaming pattern van `/api/docs/chat` + +2. **Incrementele migratie** + - Behoud oude Command Center tijdens ontwikkeling + - Feature flag voor nieuwe interface + - A/B testing mogelijkheid + +3. **Local-first approach** + - Gebruik local patterns voor snelle acties (zoals nu) + - AI alleen voor conversatie en complexe queries + +4. **Performance monitoring** + - Track AI API response times + - Monitor chat history size + - Alert bij lange conversaties + +### 5.2 ⚠️ Overwegen + +1. **Hybrid Intent Detection** + - Local patterns voor P1 intents (dagnotitie, zoeken) + - AI chat voor P2 intents en follow-up vragen + +2. **Conversation Context Window** + - Max 20 messages in API call (zoals gespecificeerd) + - Summarization voor oudere messages + +3. **Artifact Persistence** + - Sla open artifacts op in localStorage + - Herstel bij page reload + +### 5.3 ❌ Niet Doen (YAGNI) + +1. **Geen volledige rewrite** + - Bestaande blocks blijven werken + - Alleen wrapper en layout wijzigen + +2. **Geen nieuwe voice engine** + - Bestaande Deepgram implementatie is voldoende + +3. **Geen real-time collaboration** + - Niet nodig voor MVP + +--- + +## 6. Conclusie + +### Haalbaarheid: βœ… **HAALBAAR** + +Het v3.0 redesign is haalbaar binnen 6-8 weken met 1 developer. De bestaande foundation is sterk en kan worden hergebruikt. De grootste uitdagingen zijn: + +1. **Chat API ontwikkeling** (1.5 week) +2. **AI prompt engineering** (iteratief, doorlopend) +3. **State management complexiteit** (manageable met Zustand) + +### Success Criteria + +- [ ] Split-screen layout werkt op desktop/tablet/mobile +- [ ] Conversatie voelt natuurlijk (niet robotisch) +- [ ] Artifacts openen binnen 2 seconden na intent detection +- [ ] AI-filtering voor psychiater heeft >90% accuracy +- [ ] Performance: <500ms voor local patterns, <3s voor AI responses + +### Volgende Stappen + +1. βœ… **Go/No-Go beslissing** op basis van deze analyse +2. βœ… **Bouwplan v3.0** opstellen met gedetailleerde stories +3. βœ… **Sprint planning** voor Fase 1-5 +4. βœ… **AI prompt engineering** starten (parallel met development) + +--- + +## Bijlagen + +### A. Bestaande Componenten Overzicht + +``` +components/swift/ +β”œβ”€β”€ command-center/ +β”‚ β”œβ”€β”€ command-center.tsx βœ… Herbruikbaar (layout wijzigen) +β”‚ β”œβ”€β”€ context-bar.tsx βœ… Direct herbruikbaar +β”‚ β”œβ”€β”€ command-input.tsx ⚠️ Aanpassen naar chat input +β”‚ β”œβ”€β”€ canvas-area.tsx ⚠️ Vervangen door artifact-area +β”‚ └── recent-strip.tsx ❓ Verwijderen of integreren +β”œβ”€β”€ blocks/ +β”‚ β”œβ”€β”€ dagnotitie-block.tsx βœ… Direct herbruikbaar +β”‚ β”œβ”€β”€ zoeken-block.tsx βœ… Direct herbruikbaar +β”‚ β”œβ”€β”€ overdracht-block.tsx ⚠️ Uitbreiden met AI-filtering +β”‚ └── patient-context-card.tsx βœ… Direct herbruikbaar +``` + +### B. Nieuwe Componenten Overzicht + +``` +components/swift/ +β”œβ”€β”€ chat/ πŸ†• Nieuw +β”‚ β”œβ”€β”€ chat-panel.tsx +β”‚ β”œβ”€β”€ chat-message.tsx +β”‚ β”œβ”€β”€ chat-action-link.tsx +β”‚ └── streaming-indicator.tsx +β”œβ”€β”€ artifacts/ πŸ†• Nieuw +β”‚ β”œβ”€β”€ artifact-container.tsx (wrapper met tabs) +β”‚ └── artifact-tab.tsx +└── shared/ πŸ†• Nieuw + β”œβ”€β”€ linked-evidence.tsx + └── relevance-badge.tsx +``` + +### C. API Routes Overzicht + +``` +app/api/ +β”œβ”€β”€ swift/ πŸ†• Nieuw +β”‚ └── chat/ +β”‚ └── route.ts (medical scribe chatbot) +β”œβ”€β”€ intent/ +β”‚ └── classify/ βœ… Bestaat (herbruikbaar) +└── overdracht/ + └── generate/ βœ… Bestaat (uitbreiden met filtering) +``` + +--- + +**Einde analyse** + diff --git a/docs/swift/v3-redesign-met-huidige-styling.md b/docs/swift/v3-redesign-met-huidige-styling.md new file mode 100644 index 0000000..e392879 --- /dev/null +++ b/docs/swift/v3-redesign-met-huidige-styling.md @@ -0,0 +1,666 @@ +# 🎨 Swift v3.0 Redesign β€” Van Command Center naar Medical Scribe + +**Datum:** 27-12-2024 +**Versie:** v3.0 Design Specification +**Samengesteld door:** AI Assistant + +--- + +## πŸ“‹ Inhoudsopgave + +1. [Executive Summary](#executive-summary) +2. [Van v2.1 naar v3.0: Wat verandert](#van-v21-naar-v30-wat-verandert) +3. [Huidige UX/Styling (v2.1)](#huidige-uxstyling-v21) +4. [Nieuwe UX/Styling (v3.0)](#nieuwe-uxstyling-v30) +5. [Wat blijft hetzelfde](#wat-blijft-hetzelfde) +6. [Wat wijzigt](#wat-wijzigt) +7. [Implementatie Strategie](#implementatie-strategie) +8. [Design Tokens & Styling](#design-tokens--styling) + +--- + +## Executive Summary + +Swift v3.0 transformeert van een **command-line style interface** naar een **conversational medical scribe chatbot**. De kernprincipes van Ephemeral UI blijven behouden, maar de interactie verschuift van transactioneel naar relationeel. + +### Kernveranderingen + +| Aspect | v2.1 (Command Center) | v3.0 (Medical Scribe) | +|--------|----------------------|----------------------| +| **Input model** | Command-line ("notitie jan medicatie") | Natuurlijke conversatie ("Ik heb medicatie gegeven aan Jan") | +| **UI paradigma** | Centered blocks (ephemeral) | Split-screen: Chat (40%) + Artifacts (60%) | +| **Context** | Per commando | Doorlopende conversatiegeschiedenis | +| **AI rol** | Intent classifier | Converserende medical scribe | +| **Interactie** | Transactioneel (one-shot) | Relationeel (follow-up mogelijk) | + +### Wat blijft + +βœ… **Ephemeral UI principe** β€” UI verschijnt/verdwijnt wanneer nodig +βœ… **Alle bestaande blocks** β€” DagnotatieBlock, ZoekenBlock, OverdrachtBlock, etc. +βœ… **Color system** β€” Shift colors, category colors, design tokens +βœ… **Keyboard shortcuts** β€” ⌘K, Escape, Enter, 1-9 +βœ… **Voice input** β€” Deepgram integratie blijft werken +βœ… **Context Bar** β€” Shift, patient, user info + +### Wat wijzigt + +πŸ”„ **Layout** β€” 4-zone β†’ Split-screen (chat + artifacts) +πŸ”„ **Input** β€” Command input β†’ Chat input met conversatie +πŸ”„ **Canvas Area** β†’ Artifact Area (rechts, 60%) +πŸ”„ **Recent Strip** β†’ Optioneel (kan geΓ―ntegreerd in chat) +πŸ”„ **AI Engine** β€” Intent classifier β†’ Medical scribe chatbot + +--- + +## Van v2.1 naar v3.0: Wat verandert + +### v2.1 Layout (Huidig) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ πŸ• Ochtend | 8 ptn Jan de Vries β–Ό πŸ‘€ SV β”‚ ← Context Bar (48px) +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ ACTIVE BLOCK β”‚ β”‚ ← Canvas Area (flex) +β”‚ β”‚ (centered) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ Recent: [πŸ“ Jan-Med] [πŸ”„ Overdracht] [πŸ” Marie] β”‚ ← Recent Strip (48px) +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ 🎀 Typ of spreek wat je wilt doen... ⌘K β”‚ ← Command Input (64px) +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### v3.0 Layout (Nieuw) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ πŸ• Ochtend | 8 ptn Jan de Vries β–Ό πŸ‘€ SV β”‚ ← Context Bar (48px) +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ β”‚ +β”‚ CHAT PANEL (40%) β”‚ ARTIFACT AREA (60%) β”‚ +β”‚ β”‚ β”‚ +β”‚ πŸ‘€ "Ik heb net medicatie β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ gegeven aan Jan" β”‚ β”‚ πŸ“ Dagnotitie β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ πŸ€– Ik maak een dagnotitie β”‚ β”‚ PatiΓ«nt: Jan de Vries βœ“ β”‚ β”‚ +β”‚ voor Jan de Vries. β”‚ β”‚ Categorie: Medicatie βœ“ β”‚ β”‚ +β”‚ Categorie: Medicatie. β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ [Opslaan] β”‚ β”‚ +β”‚ Wil je nog iets β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ toevoegen? β”‚ β”‚ +β”‚ β”‚ β”‚ +β”‚ πŸ‘€ "Nee, opslaan" β”‚ β”‚ +β”‚ β”‚ β”‚ +β”‚ πŸ€– βœ“ Notitie opgeslagen β”‚ β”‚ +β”‚ β”‚ β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ +β”‚ πŸ’¬ Typ of spreek... 🎀 β”‚ β”‚ ← Chat Input (64px) +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +--- + +## Huidige UX/Styling (v2.1) + +### Layout Zones + +| Zone | Hoogte | Functie | Component | +|------|--------|---------|-----------| +| **Context Bar** | 48px (h-12) | Dienst, actieve patiΓ«nt, user | `context-bar.tsx` | +| **Canvas Area** | flex-1 | Waar blocks verschijnen (centered) | `canvas-area.tsx` | +| **Recent Strip** | 48px (h-12) | Laatste acties, quick access | `recent-strip.tsx` | +| **Command Input** | 64px (h-16) | Command-line style input + voice | `command-input.tsx` | + +### Context Bar (Blijft grotendeels hetzelfde) + +**Huidige implementatie:** +```tsx +
+ {/* Left: Logo + Shift */} +
+ Swift + {/* Sunrise/Sun/Sunset/Moon */} + {shiftLabel} {/* Ochtenddienst/Middagdienst/etc. */} +
+ + {/* Center: Active Patient */} +
+ {initials} + {patientName} + +
+ + {/* Right: User */} +
+ + Verpleegkundige +
+
+``` + +**Dienst kleuren:** +| Dienst | Tijd | Kleur | Icon | +|--------|------|-------|------| +| Ochtend | 07:00-15:00 | `text-amber-600` (#F59E0B) | Sunrise | +| Middag | 15:00-23:00 | `text-yellow-600` (#3B82F6) | Sun | +| Avond | 15:00-23:00 | `text-orange-600` | Sunset | +| Nacht | 23:00-07:00 | `text-indigo-600` (#6366F1) | Moon | + +### Command Input (Wijzigt naar Chat Input) + +**Huidige states:** +- **Default**: "Typ of spreek wat je wilt doen..." + mic icon +- **Typing**: Tekst + cursor +- **Listening**: πŸ”΄ + waveform + live transcript +- **Processing**: "Even kijken wat je bedoelt..." + +**Styling:** +```css +height: 64px (h-16) +background: #FFFFFF +border: 1px #E2E8F0, 2px #3B82F6 (focus) +border-radius: 16px +shadow: lg +font-size: 18px +position: fixed bottom, 24px padding +``` + +### Block Styling (Blijft hetzelfde) + +**Block sizes:** +| Size | Max-width | Use case | +|------|-----------|----------| +| Small | 480px | Quick entry (notitie, zoeken, meting) | +| Medium | 640px | Forms (rapportage, behandelplan) | +| Large | 900px | Overzichten (overdracht, patiΓ«ntenlijst) | +| XLarge | 1100px | Wizards (intake volledig) | + +**Categorie kleuren (verpleegkundig):** +| Categorie | Background | Accent | Icon | Keyboard | +|-----------|------------|--------|------|----------| +| Medicatie | `#FEF6DC` | `#F59E0B` | πŸ’Š | 1 | +| ADL | `#E8F8EF` | `#16A34A` | 🍽️ | 2 | +| Observatie | `#EFF6FF` | `#3B82F6` | πŸ‘οΈ | 3 | +| Incident | `#FEF2F2` | `#DC2626` | ⚠️ | 4 | +| Algemeen | `#F1F5F9` | `#64748B` | πŸ’¬ | 5 | + +### Keyboard Shortcuts (Blijft hetzelfde) + +| Key | Action | +|-----|--------| +| `⌘K` / `Ctrl+K` | Focus command input (blijft focus chat input) | +| `Escape` | Close active block (blijft) | +| `Enter` | Submit (blijft) | +| `⌘Enter` / `Ctrl+Enter` | Quick submit (blijft) | +| `↑` `↓` | Navigate results / history | +| `1-9` | Quick select in FallbackPicker | +| `Space` (empty input) | Start voice (blijft) | + +### Voice Input (Blijft hetzelfde) + +**Flow:** +1. User klikt mic of drukt spatie (bij lege input) +2. Deepgram start streaming transcription +3. Live transcript verschijnt in input field +4. Pauze detectie (1.5 sec stilte) β†’ auto-submit +5. Of user klikt "Stop" β†’ submit + +--- + +## Nieuwe UX/Styling (v3.0) + +### Layout Zones (Gewijzigd) + +| Zone | Breedte | Functie | Component | +|------|---------|---------|-----------| +| **Context Bar** | 100% x 48px | Dienst, actieve patiΓ«nt, user | `context-bar.tsx` (ongewijzigd) | +| **Chat Panel** | 40% x flex | Conversatie met medical scribe | `chat-panel.tsx` (nieuw) | +| **Artifact Area** | 60% x flex | Waar blocks/artifacts verschijnen | `artifact-area.tsx` (nieuw) | +| **Chat Input** | 40% x 64px | Conversational input + voice | `chat-input.tsx` (herzien) | + +### Chat Panel (Nieuw) + +**Message Types:** + +| Type | Alignment | Background | Border | Icon | +|------|-----------|------------|--------|------| +| User message | Right | Amber-50 (#FFFBEB) | Amber-200 | πŸ‘€ | +| Assistant text | Left | Slate-100 (#F1F5F9) | Slate-200 | πŸ€– | +| Assistant action | Left | Slate-100 | Slate-200 | πŸ“/πŸ”/πŸ”„ (klikbaar) | +| System message | Center | - | - | βœ“ | +| Error message | Left | Red-50 | Red-200 | ⚠️ | + +**Message Styling:** +```css +/* User message */ +.message-user { + align-self: flex-end; + background: #FFFBEB; + border: 1px solid #FED7AA; + border-radius: 16px; + border-top-right-radius: 4px; + max-width: 80%; + padding: 12px 16px; + margin: 4px 0; +} + +/* Assistant message */ +.message-assistant { + align-self: flex-start; + background: #F1F5F9; + border: 1px solid #CBD5E1; + border-radius: 16px; + border-top-left-radius: 4px; + max-width: 80%; + padding: 12px 16px; + margin: 4px 0; +} +``` + +**Gedrag:** +- Auto-scroll naar laatste message +- Scroll-lock wanneer gebruiker omhoog scrollt +- "Scroll to bottom" knop bij nieuwe messages (↓) +- Max 100 messages in view (pagination voor oudere) +- Streaming indicator tijdens AI response (pulsating dots) + +### Chat Input (Herzien) + +**States (blijven grotendeels hetzelfde):** + +| State | Weergave | Trigger | +|-------|----------|---------| +| Default | "Typ of spreek..." + mic icon | β€” | +| Typing | Cursor + getypte tekst | Keyboard input | +| Listening | πŸ”΄ + waveform + live transcript | Mic click of spatie | +| Processing | Disabled, "Denkt na..." | Na submit | +| Streaming | Disabled, streaming in chat | Tijdens AI response | + +**Keyboard Shortcuts (uitgebreid):** + +| Key | Actie | +|-----|-------| +| `Enter` | Submit message | +| `⌘Enter` / `Ctrl+Enter` | Force submit (ook tijdens streaming) | +| `Escape` | Clear input / cancel voice | +| `↑` | Vorige message (edit history) | +| `Space` (leeg) | Start voice recording | +| `⌘K` | Focus input | + +### Artifact Area (Nieuw) + +**Layout opties:** + +| Situatie | Weergave | +|----------|----------| +| Geen artifact | Placeholder met voorbeelden | +| EΓ©n artifact | Full width, centered | +| Meerdere artifacts | Tabs bovenaan (max 3) | + +**Placeholder State:** +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ β”‚ +β”‚ πŸ’¬ Artifacts verschijnen hier β”‚ +β”‚ β”‚ +β”‚ Vraag me iets, bijvoorbeeld: β”‚ +β”‚ β€’ "Notitie voor Jan: medicatie gegeven" β”‚ +β”‚ β€’ "Zoek Marie van den Berg" β”‚ +β”‚ β€’ "Maak overdracht voor deze dienst" β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +**Artifact Lifecycle:** +1. Intent detected in chat β†’ AI response: "Ik maak een dagnotitie..." +2. Artifact appears β†’ Slide-in animation (200ms, from right) +3. Pre-filled met extracted entities +4. User interacts β†’ Edits fields, kan blijven chatten +5. User saves β†’ Toast + chat confirmation + artifact closes (optioneel) + +**Artifact Animation:** +```css +@keyframes artifact-enter { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } +} + +.artifact-enter { + animation: artifact-enter 200ms ease-out; +} +``` + +### Responsive Breakpoints (Nieuw) + +| Viewport | Chat Panel | Artifact Area | +|----------|------------|---------------| +| Desktop (>1200px) | 40% | 60% | +| Tablet (768-1200px) | 45% | 55% | +| Mobile (<768px) | Full screen toggle | Full screen toggle | + +--- + +## Wat blijft hetzelfde + +### βœ… Components die NIET wijzigen + +1. **Context Bar** β€” `context-bar.tsx` + - Shift indicator met kleuren + - Patient selector + - User info + +2. **Alle Block componenten** β€” `blocks/*.tsx` + - `DagnotatieBlock` βœ… + - `ZoekenBlock` βœ… + - `OverdrachtBlock` βœ… (wel uitbreiding AI-filtering) + - `RapportageBlock` βœ… + - `AgendaBlock` βœ… + - `MetingenBlock` βœ… + - `PatientContextCard` βœ… + +3. **Voice Input** β€” `lib/swift/use-swift-voice.ts` + - Deepgram streaming transcription + - Live transcript + - Pauze detectie + +4. **Store** β€” `stores/swift-store.ts` + - activePatient, shift, activeBlock + - Wordt uitgebreid, maar bestaande state blijft + +5. **Design Tokens** + - Color palette + - Category colors + - Shift colors + - Typography + - Spacing + +### βœ… Gedrag dat NIET wijzigt + +- Keyboard shortcuts (⌘K, Escape, Enter, etc.) +- Voice recording flow +- Block prefill logic +- Patient search +- Category selection (1-9 keys) +- Toast notifications +- Error handling (offline banner, retry logic) + +--- + +## Wat wijzigt + +### πŸ”„ Components die WIJZIGEN + +1. **CommandCenter** β€” `command-center.tsx` + - **Van:** 4-zone layout (context | canvas | recent | input) + - **Naar:** Split-screen layout (context | chat+artifact | input) + - **Effort:** 3-5 dagen + +2. **CommandInput** β†’ **ChatInput** β€” `command-input.tsx` + - **Van:** Single-line command input + - **Naar:** Multi-line chat input (onderaan chat panel, 40% width) + - **Blijft:** Voice input, keyboard shortcuts, states + - **Effort:** 3 dagen + +3. **CanvasArea** β†’ **ArtifactArea** β€” `canvas-area.tsx` + - **Van:** Centered block display + - **Naar:** Right-side artifact area (60% width) met tabs + - **Effort:** 1 week + +4. **RecentStrip** β€” `recent-strip.tsx` + - **Van:** Fixed bar onderaan canvas + - **Naar:** Optioneel (kan geΓ―ntegreerd in chat history of verwijderd) + - **Effort:** 1 dag (verwijderen of integreren) + +### πŸ†• Components die NIEUW zijn + +1. **ChatPanel** β€” `chat-panel.tsx` + - Scrollable message list + - User/assistant message bubbles + - Streaming indicator + - Action links + - **Effort:** 1 week + +2. **ChatMessage** β€” `chat-message.tsx` + - Message bubble component + - Different types (user, assistant, system, error) + - **Effort:** 2 dagen + +3. **StreamingIndicator** β€” `streaming-indicator.tsx` + - Pulsating dots tijdens AI response + - **Effort:** 1 dag + +4. **ChatActionLink** β€” `chat-action-link.tsx` + - Klikbare links in assistant messages naar artifacts + - **Effort:** 1 dag + +5. **ArtifactContainer** β€” `artifact-container.tsx` + - Wrapper met tabs (max 3 artifacts) + - Tab switching + - **Effort:** 3 dagen + +6. **LinkedEvidence** β€” `linked-evidence.tsx` + - Voor OverdrachtBlock: links naar bronnotities + - **Effort:** 2 dagen + +### πŸ”„ Backend/API die WIJZIGT + +1. **Intent Classification** β€” `/api/intent/classify` + - **Van:** Simple pattern matching + AI fallback + - **Naar:** Blijft werken, maar wordt geΓ―ntegreerd in chat API + - **Effort:** 1 dag (integratie) + +2. **Nieuwe Chat API** β€” `/api/swift/chat` + - Medical scribe chatbot endpoint + - Streaming responses (SSE) + - Conversatiegeschiedenis als input + - Action objects in response + - **Effort:** 1.5 week + +3. **Overdracht AI-Filtering** β€” `/api/overdracht/generate` + - **Van:** Alle notities samenvatten + - **Naar:** + Filtering op behandelrelevantie (voor psychiater) + - **Effort:** 1 week + +--- + +## Implementatie Strategie + +### Fase 1: Foundation (Week 1-2) + +**Doel:** Split-screen layout werkend krijgen zonder chat functionaliteit + +**Taken:** +1. CommandCenter layout wijzigen naar split-screen (40/60) +2. ChatPanel skeleton (nog zonder AI, gewoon tekst weergave) +3. ArtifactArea component (wrapper voor bestaande blocks) +4. Store uitbreiden met chat state (chatMessages, isStreaming) + +**Deliverable:** Split-screen layout zichtbaar, bestaande blocks werken in artifact area + +**Risico's:** +- Responsive design voor mobile/tablet +- Block positioning in artifact area (60% width i.p.v. centered) + +--- + +### Fase 2: Chat API & Conversatie (Week 3-4) + +**Doel:** Conversatie met medical scribe werkend krijgen + +**Taken:** +1. Chat API endpoint bouwen (`/api/swift/chat`) +2. Medical scribe system prompt +3. Streaming responses (SSE) implementeren +4. ChatMessage componenten bouwen +5. Intent detection in conversatie +6. Action object generation + +**Deliverable:** Werkende conversatie die artifacts kan openen + +**Risico's:** +- AI prompt engineering (natuurlijk klinken + betrouwbaar) +- Performance bij lange conversaties +- Kosten (Claude API calls) + +--- + +### Fase 3: Artifact Area & Polish (Week 5-6) + +**Doel:** Meerdere artifacts, polish, AI-filtering + +**Taken:** +1. Meerdere artifacts ondersteuning (tabs, max 3) +2. Slide-in animaties +3. AI-filtering voor psychiater overdracht +4. Linked evidence UI +5. Error handling & edge cases +6. Performance optimalisatie + +**Deliverable:** Volledige v3.0 functionaliteit + +--- + +### Fase 4: Testing & Refinement (Week 7-8) + +**Doel:** Production-ready maken + +**Taken:** +1. User testing +2. Bug fixes +3. Performance tuning +4. Documentatie +5. Migration plan (feature flag) + +**Deliverable:** Production-ready v3.0 + +--- + +## Design Tokens & Styling + +### Colors (Blijft hetzelfde) + +```css +/* App colors */ +--bg-app: #F8FAFC; +--bg-surface: #FFFFFF; +--text-primary: #0F172A; +--text-secondary: #475569; +--border: #E2E8F0; +--brand: #3B82F6; +--success: #16A34A; +--warning: #EAB308; +--error: #DC2626; + +/* Shift colors */ +--shift-ochtend: #F59E0B; +--shift-middag: #EAB308; +--shift-avond: #FB923C; +--shift-nacht: #6366F1; + +/* Category colors */ +--cat-medicatie-bg: #FEF6DC; +--cat-medicatie-accent: #F59E0B; +--cat-adl-bg: #E8F8EF; +--cat-adl-accent: #16A34A; +--cat-observatie-bg: #EFF6FF; +--cat-observatie-accent: #3B82F6; +--cat-incident-bg: #FEF2F2; +--cat-incident-accent: #DC2626; +--cat-algemeen-bg: #F1F5F9; +--cat-algemeen-accent: #64748B; +``` + +### Chat Message Colors (Nieuw) + +```css +/* Chat message colors */ +--chat-user-bg: #FFFBEB; +--chat-user-border: #FED7AA; +--chat-assistant-bg: #F1F5F9; +--chat-assistant-border: #CBD5E1; +--chat-system-text: #64748B; +--chat-error-bg: #FEF2F2; +--chat-error-border: #FECACA; +``` + +### Typography (Blijft hetzelfde) + +```css +/* Font sizes */ +--text-xs: 0.75rem; /* 12px */ +--text-sm: 0.875rem; /* 14px */ +--text-base: 1rem; /* 16px */ +--text-lg: 1.125rem; /* 18px */ +--text-xl: 1.25rem; /* 20px */ + +/* Font weights */ +--font-normal: 400; +--font-medium: 500; +--font-semibold: 600; +--font-bold: 700; +``` + +### Spacing (Blijft hetzelfde) + +```css +/* Spacing scale */ +--space-1: 0.25rem; /* 4px */ +--space-2: 0.5rem; /* 8px */ +--space-3: 0.75rem; /* 12px */ +--space-4: 1rem; /* 16px */ +--space-6: 1.5rem; /* 24px */ +--space-8: 2rem; /* 32px */ +--space-12: 3rem; /* 48px */ +--space-16: 4rem; /* 64px */ +``` + +### Border Radius (Blijft hetzelfde) + +```css +--radius-sm: 4px; +--radius-md: 8px; +--radius-lg: 16px; +--radius-full: 9999px; +``` + +--- + +## Conclusie + +Het v3.0 redesign is **haalbaar binnen 6-8 weken** omdat: + +1. βœ… **Sterke foundation** β€” Alle blocks, voice input, design tokens blijven werken +2. βœ… **Incrementele wijziging** β€” Geen complete rewrite, layout + conversatie laag toevoegen +3. βœ… **Bestaande patterns** β€” Chat API pattern bestaat al (`/api/docs/chat`) +4. βœ… **Design continuΓ―teit** β€” Kleuren, typography, spacing blijven hetzelfde + +**Grootste uitdagingen:** +- Medical scribe prompt engineering (natuurlijk + betrouwbaar) +- Chat state management (Zustand store uitbreiden) +- Performance bij lange conversaties + +**Grootste voordelen:** +- Natuurlijkere interactie (relationeel i.p.v. transactioneel) +- Follow-up vragen mogelijk +- Context behouden tijdens werk +- Overeenkomsten met ChatGPT/Claude (bekend voor gebruikers) + +--- + +## Referenties + +- **FO v3.0:** `fo-swift-medical-scribe-v3.md` β€” Functioneel ontwerp +- **Haalbaarheid:** `haalbaarheidsanalyse-v3.md` β€” Feasibility analysis +- **UX v2.1:** `archive/swift-ux-v2.1.md` β€” Huidige UX/styling +- **Bouwplan v2:** `bouwplan-swift-v2.md` β€” Development roadmap diff --git a/mcp.json b/mcp.json new file mode 100644 index 0000000..338e80a --- /dev/null +++ b/mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "supabase": { + "type": "http", + "url": "https://mcp.supabase.com/mcp?project_ref=dqugbrpwtisgyxscpefg", + "headers": { + "Authorization": "Bearer sbp_6598641b9c7afc57968d9a362088f506e9f3e20b" + } + } + } + } \ No newline at end of file diff --git a/supabase/check-patients.sql b/supabase/check-patients.sql new file mode 100644 index 0000000..c0ff602 --- /dev/null +++ b/supabase/check-patients.sql @@ -0,0 +1,10 @@ +-- Check welke patiΓ«nten er in de database zitten +SELECT + id, + name_given, + name_family, + name_prefix, + birth_date +FROM patients +ORDER BY created_at DESC +LIMIT 20; diff --git a/supabase/migrations/20251227_seed_verpleegkundige_overdracht_data.sql b/supabase/migrations/20251227_seed_verpleegkundige_overdracht_data.sql new file mode 100644 index 0000000..131e52b --- /dev/null +++ b/supabase/migrations/20251227_seed_verpleegkundige_overdracht_data.sql @@ -0,0 +1,398 @@ +-- ============================================================================ +-- SEED VERPLEEGKUNDIGE OVERDRACHT DATA +-- ============================================================================ +-- Created: 2024-12-27 +-- Purpose: Populate reports table with realistic nursing handover data +-- to demonstrate the verpleegkundige overdracht (nursing handover) features +-- ============================================================================ + +DO $$ +DECLARE + patient_colin_id UUID; + patient_jan_id UUID; + patient_optimus_id UUID; + practitioner_sarah_id UUID := '10000000-0000-0000-0000-000000000001'::uuid; + practitioner_mark_id UUID := '10000000-0000-0000-0000-000000000002'::uuid; + practitioner_lisa_id UUID := '10000000-0000-0000-0000-000000000003'::uuid; + + -- Datums voor realistische tijdlijn + vandaag DATE := CURRENT_DATE; + gisteren DATE := CURRENT_DATE - INTERVAL '1 day'; + eergisteren DATE := CURRENT_DATE - INTERVAL '2 days'; +BEGIN + -- Get patient IDs + SELECT id INTO patient_colin_id FROM patients WHERE name_family = 'Lit' AND 'Colin' = ANY(name_given); + SELECT id INTO patient_jan_id FROM patients WHERE name_family = 'de Vriesh' AND 'Jan' = ANY(name_given); + SELECT id INTO patient_optimus_id FROM patients WHERE name_family = 'Prime' AND 'Optimus' = ANY(name_given); + + -- ============================================================================ + -- VANDAAG - Diverse rapportages gedurende de dag + -- ============================================================================ + + -- NACHT (02:00) - Colin - Observatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_colin_id, 'verpleegkundig', + 'PatiΓ«nt slaapt rustig. Geen bijzonderheden.', + practitioner_lisa_id, + vandaag + TIME '02:00:00', + gisteren, -- Nachtdienst hoort bij vorige dag + false, + jsonb_build_object('category', 'observatie') + ) ON CONFLICT DO NOTHING; + + -- OCHTEND (07:30) - Colin - ADL + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_colin_id, 'verpleegkundig', + 'PatiΓ«nt zelfstandig gedoucht en aangekleed. Heeft ontbijt genuttigd (brood, yoghurt). Stemming lijkt iets somberder dan gisteren.', + practitioner_sarah_id, + vandaag + TIME '07:30:00', + vandaag, + true, -- Belangrijk voor overdracht: stemming somberder + jsonb_build_object('category', 'adl') + ) ON CONFLICT DO NOTHING; + + -- OCHTEND (08:15) - Colin - Medicatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_colin_id, 'verpleegkundig', + 'Ochtendmedicatie toegediend: Sertraline 50mg. PatiΓ«nt heeft goed ingenomen.', + practitioner_sarah_id, + vandaag + TIME '08:15:00', + vandaag, + false, + jsonb_build_object('category', 'medicatie') + ) ON CONFLICT DO NOTHING; + + -- OCHTEND (10:00) - Jan - Gedragsobservatie (belangrijk!) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'PatiΓ«nt geagiteerd en gespannen. Heeft meerdere keren om geruststelling gevraagd. Gesprek gevoerd, maar blijft piekeren over gezondheid. Ademhalingsoefening gedaan.', + practitioner_sarah_id, + vandaag + TIME '10:00:00', + vandaag, + true, -- Belangrijk voor overdracht + jsonb_build_object('category', 'gedrag') + ) ON CONFLICT DO NOTHING; + + -- OCHTEND (11:00) - Optimus - Observatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_optimus_id, 'verpleegkundig', + 'PatiΓ«nt werkt geconcentreerd aan zijn cognitieve oefeningen. Sociaal contact beperkt, maar dit lijkt karakteristiek voor hem.', + practitioner_sarah_id, + vandaag + TIME '11:00:00', + vandaag, + false, + jsonb_build_object('category', 'observatie') + ) ON CONFLICT DO NOTHING; + + -- MIDDAG (13:30) - Jan - Medicatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'Middagmedicatie toegediend: Oxazepam 10mg (SOS, ivm toegenomen angst). Effect na 30 min: patiΓ«nt rustiger.', + practitioner_mark_id, + vandaag + TIME '13:30:00', + vandaag, + true, -- SOS medicatie is belangrijk + jsonb_build_object('category', 'medicatie') + ) ON CONFLICT DO NOTHING; + + -- MIDDAG (14:00) - Colin - Gedragsobservatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_colin_id, 'verpleegkundig', + 'PatiΓ«nt heeft deelgenomen aan groepstherapie. Gaf aan zich vandaag moe te voelen. Heeft zich teruggetrokken op kamer na de sessie.', + practitioner_mark_id, + vandaag + TIME '14:00:00', + vandaag, + false, + jsonb_build_object('category', 'gedrag') + ) ON CONFLICT DO NOTHING; + + -- MIDDAG (15:00) - Optimus - ADL + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_optimus_id, 'verpleegkundig', + 'PatiΓ«nt neemt zelfstandig maaltijden. Blijft voorkeur houden voor vaste routine en structuur.', + practitioner_mark_id, + vandaag + TIME '15:00:00', + vandaag, + false, + jsonb_build_object('category', 'adl') + ) ON CONFLICT DO NOTHING; + + -- AVOND (18:30) - Colin - Medicatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_colin_id, 'verpleegkundig', + 'Avondmedicatie toegediend: Sertraline 50mg, Melatonine 3mg. Goed ingenomen.', + practitioner_lisa_id, + vandaag + TIME '18:30:00', + vandaag, + false, + jsonb_build_object('category', 'medicatie') + ) ON CONFLICT DO NOTHING; + + -- AVOND (19:45) - Jan - Observatie (belangrijk!) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'Na avondeten gesprek met partner (Emma) via telefoon. Gesprek verliep goed. PatiΓ«nt minder gespannen daarna. Belangrijk: oefent met minder vaak bellen om geruststelling.', + practitioner_lisa_id, + vandaag + TIME '19:45:00', + vandaag, + true, -- Positieve ontwikkeling + jsonb_build_object('category', 'observatie') + ) ON CONFLICT DO NOTHING; + + -- ============================================================================ + -- GISTEREN - Volledige dag voor context + -- ============================================================================ + + -- OCHTEND (08:00) - Colin - ADL (gisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_colin_id, 'verpleegkundig', + 'PatiΓ«nt wakker om 07:00. Gedoucht en aangekleed zonder problemen. Ontbijt goed gegeten.', + practitioner_sarah_id, + gisteren + TIME '08:00:00', + gisteren, + false, + jsonb_build_object('category', 'adl') + ) ON CONFLICT DO NOTHING; + + -- OCHTEND (09:00) - Colin - Medicatie (gisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_colin_id, 'verpleegkundig', + 'Ochtendmedicatie: Sertraline 50mg toegediend en ingenomen.', + practitioner_sarah_id, + gisteren + TIME '09:00:00', + gisteren, + false, + jsonb_build_object('category', 'medicatie') + ) ON CONFLICT DO NOTHING; + + -- MIDDAG (13:00) - Jan - Incident (belangrijk!) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'PatiΓ«nt in paniek ivm vermeende hartkloppingen. Vitale functies gecontroleerd (bloeddruk, hartslag normaal). Arts geΓ―nformeerd. Na gesprek en ademhalingsoefeningen gekalmeerd.', + practitioner_mark_id, + gisteren + TIME '13:00:00', + gisteren, + true, + jsonb_build_object('category', 'incident') + ) ON CONFLICT DO NOTHING; + + -- MIDDAG (14:30) - Colin - Gedragsobservatie (gisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_colin_id, 'verpleegkundig', + 'Therapiesessie met psycholoog. PatiΓ«nt gaf na afloop aan zich begrepen te voelen. Stemming leek opgewekt.', + practitioner_mark_id, + gisteren + TIME '14:30:00', + gisteren, + false, + jsonb_build_object('category', 'gedrag') + ) ON CONFLICT DO NOTHING; + + -- AVOND (20:00) - Jan - Medicatie (gisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'Avondmedicatie: Paroxetine 20mg, Melatonine 3mg toegediend.', + practitioner_lisa_id, + gisteren + TIME '20:00:00', + gisteren, + false, + jsonb_build_object('category', 'medicatie') + ) ON CONFLICT DO NOTHING; + + -- AVOND (21:30) - Optimus - Observatie (gisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_optimus_id, 'verpleegkundig', + 'PatiΓ«nt leest op kamer. Geeft aan niet moe te zijn. Gaat naar bed rond 23:00 (vaste routine).', + practitioner_lisa_id, + gisteren + TIME '21:30:00', + gisteren, + false, + jsonb_build_object('category', 'observatie') + ) ON CONFLICT DO NOTHING; + + -- ============================================================================ + -- EERGISTEREN - Enkele belangrijke rapportages voor geschiedenis + -- ============================================================================ + + -- OCHTEND (10:00) - Colin - Gedragsobservatie (eergisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_colin_id, 'verpleegkundig', + 'Intake gesprek met familie. Moeder op bezoek. Goed contact. PatiΓ«nt emotioneel maar opgelucht na gesprek.', + practitioner_sarah_id, + eergisteren + TIME '10:00:00', + eergisteren, + true, -- Belangrijk: familiecontact + jsonb_build_object('category', 'gedrag') + ) ON CONFLICT DO NOTHING; + + -- MIDDAG (14:00) - Jan - Gedragsobservatie (eergisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'Mindfulness groep. PatiΓ«nt heeft moeite met stilzitten en concentratie. Blijft piekeren. Individuele nabespreking gehad.', + practitioner_mark_id, + eergisteren + TIME '14:00:00', + eergisteren, + false, + jsonb_build_object('category', 'gedrag') + ) ON CONFLICT DO NOTHING; + + -- AVOND (19:00) - Optimus - ADL (eergisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_optimus_id, 'verpleegkundig', + 'PatiΓ«nt heeft zelfstandig avondmaaltijd gebruikt. Keurig opgeruimd. Houdt zich goed aan afdelingregels.', + practitioner_lisa_id, + eergisteren + TIME '19:00:00', + eergisteren, + false, + jsonb_build_object('category', 'adl') + ) ON CONFLICT DO NOTHING; + + -- ============================================================================ + -- Extra rapportages voor diversiteit - 3 dagen geleden + -- ============================================================================ + + -- Medicatie wijziging (belangrijk voor overdracht) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_colin_id, 'verpleegkundig', + 'Medicatie aangepast door psychiater: Sertraline verhoogd van 25mg naar 50mg. Start vandaag. Extra observatie op bijwerkingen.', + practitioner_sarah_id, + CURRENT_DATE - INTERVAL '3 days' + TIME '10:00:00', + CURRENT_DATE - INTERVAL '3 days', + true, -- Medicatiewijziging is altijd belangrijk + jsonb_build_object('category', 'medicatie') + ) ON CONFLICT DO NOTHING; + + -- Incident met goede afloop + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'PatiΓ«nt wilde afdeling verlaten tijdens piekmoment. Gesprek gevoerd over contractafspraken. PatiΓ«nt kon uiteindelijk zelf kalmeren en bleef. Geen dwangmiddelen nodig.', + practitioner_mark_id, + CURRENT_DATE - INTERVAL '3 days' + TIME '15:30:00', + CURRENT_DATE - INTERVAL '3 days', + true, + jsonb_build_object('category', 'incident') + ) ON CONFLICT DO NOTHING; + + RAISE NOTICE 'βœ“ Seeded verpleegkundige overdracht rapportages'; + RAISE NOTICE ' - Colin Lit: % rapportages', (SELECT COUNT(*) FROM reports WHERE patient_id = patient_colin_id AND type = 'verpleegkundig'); + RAISE NOTICE ' - Jan de Vriesh: % rapportages', (SELECT COUNT(*) FROM reports WHERE patient_id = patient_jan_id AND type = 'verpleegkundig'); + RAISE NOTICE ' - Optimus Prime: % rapportages', (SELECT COUNT(*) FROM reports WHERE patient_id = patient_optimus_id AND type = 'verpleegkundig'); + RAISE NOTICE ' - Overdracht items: %', (SELECT COUNT(*) FROM reports WHERE type = 'verpleegkundig' AND include_in_handover = true); +END $$; + +-- ============================================================================ +-- VERIFICATION +-- ============================================================================ + +DO $$ +DECLARE + verpleegkundig_count INTEGER; + overdracht_count INTEGER; + categories_count INTEGER; +BEGIN + SELECT COUNT(*) INTO verpleegkundig_count + FROM reports + WHERE type = 'verpleegkundig' AND deleted_at IS NULL; + + SELECT COUNT(*) INTO overdracht_count + FROM reports + WHERE type = 'verpleegkundig' AND include_in_handover = true AND deleted_at IS NULL; + + SELECT COUNT(DISTINCT structured_data->>'category') INTO categories_count + FROM reports + WHERE type = 'verpleegkundig' AND deleted_at IS NULL; + + RAISE NOTICE '=== VERPLEEGKUNDIGE OVERDRACHT SEED SUMMARY ==='; + RAISE NOTICE 'Totaal verpleegkundige rapportages: %', verpleegkundig_count; + RAISE NOTICE 'Overdracht items (include_in_handover=true): %', overdracht_count; + RAISE NOTICE 'Verschillende categorieΓ«n: %', categories_count; + + IF verpleegkundig_count >= 20 THEN + RAISE NOTICE 'βœ“ Verpleegkundige overdracht data succesvol ingevoerd!'; + ELSE + RAISE WARNING '⚠ Mogelijk niet alle data ingevoerd'; + END IF; +END $$; + +-- ============================================================================ +-- SUMMARY +-- ============================================================================ +-- βœ“ Realistische verpleegkundige rapportages over 4 dagen +-- βœ“ Alle categorieΓ«n vertegenwoordigd: +-- - medicatie (medicatie toediening, wijzigingen) +-- - adl (douchen, eten, zelfverzorging) +-- - gedrag (observaties, groepstherapie, gesprekken) +-- - incident (paniek, conflict, crises) +-- - observatie (algemene observaties) +-- βœ“ Verschillende tijdstippen (nacht, ochtend, middag, avond) +-- βœ“ Include_in_handover flags voor belangrijke items +-- βœ“ Shift_date correct berekend (nachtdienst voor 07:00 = vorige dag) +-- +-- GEBRUIK: +-- - Verpleegkundige overdracht module (/epd/verpleegrapportage) +-- - Timeline visualisatie per dagdeel +-- - AI samenvatting generatie +-- - Handover filtering (include_in_handover=true) +-- ============================================================================ diff --git a/supabase/migrations/20251227_seed_verpleegkundige_overdracht_data_v2.sql b/supabase/migrations/20251227_seed_verpleegkundige_overdracht_data_v2.sql new file mode 100644 index 0000000..6478ecb --- /dev/null +++ b/supabase/migrations/20251227_seed_verpleegkundige_overdracht_data_v2.sql @@ -0,0 +1,402 @@ +-- ============================================================================ +-- SEED VERPLEEGKUNDIGE OVERDRACHT DATA (Aangepaste versie) +-- ============================================================================ +-- Created: 2024-12-27 +-- Purpose: Populate reports table with realistic nursing handover data +-- Works with existing patients in your database +-- ============================================================================ + +DO $$ +DECLARE + -- Use existing patients from your database + patient_piet_id UUID := '2abadccb-7c29-4ea4-94b1-538a3927824c'::uuid; -- Piet Janssen + patient_jan_id UUID := 'd16935c9-e0fe-4972-832f-175b7a38f9b9'::uuid; -- Jan de Vriesh + patient_optimus_id UUID := 'a94ac0ce-ff90-404b-ac62-592db93df76e'::uuid; -- Optimus Prime + + -- Practitioners (assuming these exist from your setup) + practitioner_sarah_id UUID := '10000000-0000-0000-0000-000000000001'::uuid; + practitioner_mark_id UUID := '10000000-0000-0000-0000-000000000002'::uuid; + practitioner_lisa_id UUID := '10000000-0000-0000-0000-000000000003'::uuid; + + -- Datums voor realistische tijdlijn + vandaag DATE := CURRENT_DATE; + gisteren DATE := CURRENT_DATE - INTERVAL '1 day'; + eergisteren DATE := CURRENT_DATE - INTERVAL '2 days'; +BEGIN + + -- ============================================================================ + -- VANDAAG - Diverse rapportages gedurende de dag + -- ============================================================================ + + -- NACHT (02:00) - Piet - Observatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_piet_id, 'verpleegkundig', + 'PatiΓ«nt slaapt rustig. Geen bijzonderheden.', + practitioner_lisa_id, + vandaag + TIME '02:00:00', + gisteren, -- Nachtdienst hoort bij vorige dag + false, + jsonb_build_object('category', 'observatie') + ); + + -- OCHTEND (07:30) - Piet - ADL + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_piet_id, 'verpleegkundig', + 'PatiΓ«nt zelfstandig gedoucht en aangekleed. Heeft ontbijt genuttigd (brood, yoghurt). Stemming lijkt iets somberder dan gisteren.', + practitioner_sarah_id, + vandaag + TIME '07:30:00', + vandaag, + true, -- Belangrijk voor overdracht: stemming somberder + jsonb_build_object('category', 'adl') + ); + + -- OCHTEND (08:15) - Piet - Medicatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_piet_id, 'verpleegkundig', + 'Ochtendmedicatie toegediend: Sertraline 50mg. PatiΓ«nt heeft goed ingenomen.', + practitioner_sarah_id, + vandaag + TIME '08:15:00', + vandaag, + false, + jsonb_build_object('category', 'medicatie') + ); + + -- OCHTEND (10:00) - Jan - Gedragsobservatie (belangrijk!) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'PatiΓ«nt geagiteerd en gespannen. Heeft meerdere keren om geruststelling gevraagd. Gesprek gevoerd, maar blijft piekeren over gezondheid. Ademhalingsoefening gedaan.', + practitioner_sarah_id, + vandaag + TIME '10:00:00', + vandaag, + true, -- Belangrijk voor overdracht + jsonb_build_object('category', 'gedrag') + ); + + -- OCHTEND (11:00) - Optimus - Observatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_optimus_id, 'verpleegkundig', + 'PatiΓ«nt werkt geconcentreerd aan zijn cognitieve oefeningen. Sociaal contact beperkt, maar dit lijkt karakteristiek voor hem.', + practitioner_sarah_id, + vandaag + TIME '11:00:00', + vandaag, + false, + jsonb_build_object('category', 'observatie') + ); + + -- MIDDAG (13:30) - Jan - Medicatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'Middagmedicatie toegediend: Oxazepam 10mg (SOS, ivm toegenomen angst). Effect na 30 min: patiΓ«nt rustiger.', + practitioner_mark_id, + vandaag + TIME '13:30:00', + vandaag, + true, -- SOS medicatie is belangrijk + jsonb_build_object('category', 'medicatie') + ); + + -- MIDDAG (14:00) - Piet - Gedragsobservatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_piet_id, 'verpleegkundig', + 'PatiΓ«nt heeft deelgenomen aan groepstherapie. Gaf aan zich vandaag moe te voelen. Heeft zich teruggetrokken op kamer na de sessie.', + practitioner_mark_id, + vandaag + TIME '14:00:00', + vandaag, + false, + jsonb_build_object('category', 'gedrag') + ); + + -- MIDDAG (15:00) - Optimus - ADL + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_optimus_id, 'verpleegkundig', + 'PatiΓ«nt neemt zelfstandig maaltijden. Blijft voorkeur houden voor vaste routine en structuur.', + practitioner_mark_id, + vandaag + TIME '15:00:00', + vandaag, + false, + jsonb_build_object('category', 'adl') + ); + + -- AVOND (18:30) - Piet - Medicatie + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_piet_id, 'verpleegkundig', + 'Avondmedicatie toegediend: Sertraline 50mg, Melatonine 3mg. Goed ingenomen.', + practitioner_lisa_id, + vandaag + TIME '18:30:00', + vandaag, + false, + jsonb_build_object('category', 'medicatie') + ); + + -- AVOND (19:45) - Jan - Observatie (belangrijk!) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'Na avondeten gesprek met partner (Emma) via telefoon. Gesprek verliep goed. PatiΓ«nt minder gespannen daarna. Belangrijk: oefent met minder vaak bellen om geruststelling.', + practitioner_lisa_id, + vandaag + TIME '19:45:00', + vandaag, + true, -- Positieve ontwikkeling + jsonb_build_object('category', 'observatie') + ); + + -- ============================================================================ + -- GISTEREN - Volledige dag voor context + -- ============================================================================ + + -- OCHTEND (08:00) - Piet - ADL (gisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_piet_id, 'verpleegkundig', + 'PatiΓ«nt wakker om 07:00. Gedoucht en aangekleed zonder problemen. Ontbijt goed gegeten.', + practitioner_sarah_id, + gisteren + TIME '08:00:00', + gisteren, + false, + jsonb_build_object('category', 'adl') + ); + + -- OCHTEND (09:00) - Piet - Medicatie (gisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_piet_id, 'verpleegkundig', + 'Ochtendmedicatie: Sertraline 50mg toegediend en ingenomen.', + practitioner_sarah_id, + gisteren + TIME '09:00:00', + gisteren, + false, + jsonb_build_object('category', 'medicatie') + ); + + -- MIDDAG (13:00) - Jan - Incident (belangrijk!) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'PatiΓ«nt in paniek ivm vermeende hartkloppingen. Vitale functies gecontroleerd (bloeddruk, hartslag normaal). Arts geΓ―nformeerd. Na gesprek en ademhalingsoefeningen gekalmeerd.', + practitioner_mark_id, + gisteren + TIME '13:00:00', + gisteren, + true, + jsonb_build_object('category', 'incident') + ); + + -- MIDDAG (14:30) - Piet - Gedragsobservatie (gisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_piet_id, 'verpleegkundig', + 'Therapiesessie met psycholoog. PatiΓ«nt gaf na afloop aan zich begrepen te voelen. Stemming leek opgewekt.', + practitioner_mark_id, + gisteren + TIME '14:30:00', + gisteren, + false, + jsonb_build_object('category', 'gedrag') + ); + + -- AVOND (20:00) - Jan - Medicatie (gisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'Avondmedicatie: Paroxetine 20mg, Melatonine 3mg toegediend.', + practitioner_lisa_id, + gisteren + TIME '20:00:00', + gisteren, + false, + jsonb_build_object('category', 'medicatie') + ); + + -- AVOND (21:30) - Optimus - Observatie (gisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_optimus_id, 'verpleegkundig', + 'PatiΓ«nt leest op kamer. Geeft aan niet moe te zijn. Gaat naar bed rond 23:00 (vaste routine).', + practitioner_lisa_id, + gisteren + TIME '21:30:00', + gisteren, + false, + jsonb_build_object('category', 'observatie') + ); + + -- ============================================================================ + -- EERGISTEREN - Enkele belangrijke rapportages voor geschiedenis + -- ============================================================================ + + -- OCHTEND (10:00) - Piet - Gedragsobservatie (eergisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_piet_id, 'verpleegkundig', + 'Intake gesprek met familie. Moeder op bezoek. Goed contact. PatiΓ«nt emotioneel maar opgelucht na gesprek.', + practitioner_sarah_id, + eergisteren + TIME '10:00:00', + eergisteren, + true, -- Belangrijk: familiecontact + jsonb_build_object('category', 'gedrag') + ); + + -- MIDDAG (14:00) - Jan - Gedragsobservatie (eergisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'Mindfulness groep. PatiΓ«nt heeft moeite met stilzitten en concentratie. Blijft piekeren. Individuele nabespreking gehad.', + practitioner_mark_id, + eergisteren + TIME '14:00:00', + eergisteren, + false, + jsonb_build_object('category', 'gedrag') + ); + + -- AVOND (19:00) - Optimus - ADL (eergisteren) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_optimus_id, 'verpleegkundig', + 'PatiΓ«nt heeft zelfstandig avondmaaltijd gebruikt. Keurig opgeruimd. Houdt zich goed aan afdelingregels.', + practitioner_lisa_id, + eergisteren + TIME '19:00:00', + eergisteren, + false, + jsonb_build_object('category', 'adl') + ); + + -- ============================================================================ + -- Extra rapportages voor diversiteit - 3 dagen geleden + -- ============================================================================ + + -- Medicatie wijziging (belangrijk voor overdracht) + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_piet_id, 'verpleegkundig', + 'Medicatie aangepast door psychiater: Sertraline verhoogd van 25mg naar 50mg. Start vandaag. Extra observatie op bijwerkingen.', + practitioner_sarah_id, + CURRENT_DATE - INTERVAL '3 days' + TIME '10:00:00', + CURRENT_DATE - INTERVAL '3 days', + true, -- Medicatiewijziging is altijd belangrijk + jsonb_build_object('category', 'medicatie') + ); + + -- Incident met goede afloop + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'PatiΓ«nt wilde afdeling verlaten tijdens piekmoment. Gesprek gevoerd over contractafspraken. PatiΓ«nt kon uiteindelijk zelf kalmeren en bleef. Geen dwangmiddelen nodig.', + practitioner_mark_id, + CURRENT_DATE - INTERVAL '3 days' + TIME '15:30:00', + CURRENT_DATE - INTERVAL '3 days', + true, + jsonb_build_object('category', 'incident') + ); + + -- Extra rapportages voor meer volume + -- VANDAAG - Extra observaties + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_piet_id, 'verpleegkundig', + 'PatiΓ«nt wandelt buiten met medepatiΓ«nt. Ziet er ontspannen uit.', + practitioner_mark_id, + vandaag + TIME '16:00:00', + vandaag, + false, + jsonb_build_object('category', 'observatie') + ); + + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_jan_id, 'verpleegkundig', + 'PatiΓ«nt heeft deelgenomen aan creatieve therapie. Maakte schilderij. Leek meer ontspannen tijdens activiteit.', + practitioner_mark_id, + vandaag + TIME '16:30:00', + vandaag, + false, + jsonb_build_object('category', 'gedrag') + ); + + INSERT INTO reports ( + patient_id, type, content, created_by, created_at, shift_date, + include_in_handover, structured_data + ) VALUES ( + patient_optimus_id, 'verpleegkundig', + 'Avondmedicatie: Melatonine 3mg ingenomen.', + practitioner_lisa_id, + vandaag + TIME '21:00:00', + vandaag, + false, + jsonb_build_object('category', 'medicatie') + ); + + RAISE NOTICE 'βœ“ Verpleegkundige overdracht rapportages toegevoegd'; +END $$; + +-- ============================================================================ +-- VERIFICATION +-- ============================================================================ + +DO $$ +DECLARE + verpleegkundig_count INTEGER; + overdracht_count INTEGER; +BEGIN + SELECT COUNT(*) INTO verpleegkundig_count + FROM reports + WHERE type = 'verpleegkundig' AND deleted_at IS NULL; + + SELECT COUNT(*) INTO overdracht_count + FROM reports + WHERE type = 'verpleegkundig' AND include_in_handover = true AND deleted_at IS NULL; + + RAISE NOTICE '=== VERPLEEGKUNDIGE OVERDRACHT SEED SUMMARY ==='; + RAISE NOTICE 'Totaal verpleegkundige rapportages: %', verpleegkundig_count; + RAISE NOTICE 'Overdracht items (belangrijk): %', overdracht_count; + RAISE NOTICE 'βœ“ Data succesvol ingevoerd!'; +END $$;