diff --git a/docs/swift/bouwplan-swift-v3.md b/docs/swift/bouwplan-swift-v3.md index 3008dbf..6252e8f 100644 --- a/docs/swift/bouwplan-swift-v3.md +++ b/docs/swift/bouwplan-swift-v3.md @@ -822,32 +822,259 @@ E4.S4 (Placeholder state) is geskipt omdat: **Technical Notes:** -**E5.S1 - AI-filtering:** +**E5.S1 - AI-filtering psychiater (Swift OverdrachtBlock):** + +**Context:** +- OverdrachtBlock is een Swift artifact (geopend via chat) +- Toont patient lijst met AI samenvattingen +- Gebruikt bestaande `/api/overdracht/generate` endpoint +- Verpleegkundigen hebben items gemarkeerd met `include_in_handover = true` + +**Implementatie - Role Toggle in OverdrachtBlock:** +```tsx +// components/swift/blocks/overdracht-block.tsx + +export function OverdrachtBlock({ prefill }: OverdrachtBlockProps) { + const [period, setPeriod] = useState('1d'); + const [filterRole, setFilterRole] = useState<'verpleegkundige' | 'psychiater'>('verpleegkundige'); // πŸ†• + + // Update generateSummary to include filterRole + const generateSummary = useCallback(async (patientId: string) => { + const response = await retryFetch( + () => safeFetch( + '/api/overdracht/generate', + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + patientId, + period, + filterForRole: filterRole // πŸ†• Add role parameter + }), + }, + { operation: 'Overdracht genereren' } + ), + 3, + 1000 + ); + // ... + }, [period, filterRole]); // πŸ†• Add filterRole dependency + + return ( + +
+ {/* πŸ†• Role Selector - NIEUW */} +
+ +
+ + +
+

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

+
+ + {/* Period Selector - blijft hetzelfde */} + {/* ... */} +
+
+ ); +} +``` + +**API Schema Update:** +```typescript +// lib/types/overdracht.ts +export const GenerateOverdrachtSchema = z.object({ + patientId: z.string().uuid('Patient ID moet een geldige UUID zijn'), + period: z.enum(['1d', '3d', '7d', '14d']).optional().default('1d'), + filterForRole: z.enum(['psychiater', 'verpleegkundige']).optional().default('verpleegkundige'), // πŸ†• +}); + +export type GenerateOverdrachtInput = z.infer; +``` + +**API Route Update:** ```typescript // app/api/overdracht/generate/route.ts -// Uitbreiden met filtering parameter -interface GenerateOverdrachtRequest { - shift: ShiftType; - filterForRole?: 'psychiater' | 'verpleegkundige'; + +export async function POST(request: NextRequest) { + const body = await request.json(); + const result = GenerateOverdrachtSchema.safeParse(body); + + const { patientId, period, filterForRole } = result.data; // πŸ†• Extract filterForRole + + // Load context (data loading blijft HETZELFDE - altijd include_in_handover=true) + const context = await loadOverdrachtContext(supabase, patientId, period); + + // Call Claude API with role-specific prompt + const aiResult = await callClaudeAPI(context, filterForRole); // πŸ†• Pass role + + // ... } -// AI prompt voor filtering -const FILTER_PROMPT = ` -Analyseer deze verpleegkundige notities en selecteer ALLEEN behandelrelevante informatie voor de psychiater: +// πŸ†• Update callClaudeAPI signature +async function callClaudeAPI( + context: OverdrachtContext, + role: 'psychiater' | 'verpleegkundige' = 'verpleegkundige' // πŸ†• Add parameter +): Promise<{ + samenvatting: string; + aandachtspunten: Aandachtspunt[]; + actiepunten: string[]; +}> { + const systemPrompt = buildSystemPrompt(role); // πŸ†• Role-specific prompt + const userPrompt = buildOverdrachtUserPrompt(context); // Blijft hetzelfde -WEL relevant: -- Medicatie-issues (weigering, bijwerkingen) -- Stemming/gedrag veranderingen -- Risico-signalen (suΓ―cidale uitingen, agressie) -- Psychotische symptomen + const response = await fetch('https://api.anthropic.com/v1/messages', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': apiKey, + 'anthropic-version': '2023-06-01', + }, + body: JSON.stringify({ + model: 'claude-sonnet-4-20250514', + max_tokens: 2048, + temperature: 0.3, + system: systemPrompt, // πŸ†• Role-specific + messages: [{ role: 'user', content: userPrompt }], + }), + }); -NIET relevant: -- Routine medicatie ("volgens schema") -- ADL activiteiten ("gedoucht", "ontbijt") -- Standaard observaties ("rustige dag") -`; + // ... rest blijft hetzelfde +} ``` +**AI Prompt - Role-specific Filtering:** +```typescript +// lib/ai/overdracht-prompt.ts + +// πŸ†• New function for role-specific prompts +export function buildSystemPrompt(role: 'psychiater' | 'verpleegkundige'): string { + const basePrompt = OVERDRACHT_SYSTEM_PROMPT; // Bestaande prompt voor verpleegkundige + + if (role === 'psychiater') { + return `${basePrompt} + +## PSYCHIATER FILTERING +Je maakt overdracht voor een PSYCHIATER. Filter STRIKT op behandelrelevantie. + +De verpleegkundige heeft al items geselecteerd (include_in_handover=true), maar jij moet VERDER FILTEREN. + +βœ… WEL RELEVANT (include in samenvatting): +- Medicatie-issues: weigering, bijwerkingen, dosisaanpassingen, therapietrouw +- Stemming/gedrag: veranderingen van baseline, afwijkend gedrag, agitatie +- Risico-signalen: suΓ―cidale uitingen, automutilatie, agressie +- Psychotische symptomen: wanen, hallucinaties, desorganisatie, paranoia +- Crisis/dwang: separatie, fixatie, dwangmedicatie, vrijheidsbeperkende maatregelen +- Afwijkende vitals: HH (kritiek hoog), LL (kritiek laag) met behandelimpact + +❌ FILTER UIT (niet in samenvatting): +- Routine medicatie: "medicatie volgens schema", "zonder problemen", "ingenomen conform afspraak" +- ADL activiteiten: douchen, aankleden, eten, drinken (tenzij significant afwijkend/weigering) +- Sociale activiteiten: "deelgenomen aan groepstherapie", "gesprek gehad", "koffie gedronken" +- Standaard observaties: "rustige dag", "geen bijzonderheden", "normaal functioneren" +- Routine vitals: bloeddruk/pols binnen normaalwaarden (N interpretatie) +- Dagstructuur: "dagprogramma gevolgd", "aanwezig bij activiteit" + +VUISTREGEL: Include ALLEEN als een psychiater op basis van deze info een BEHANDELBESLISSING kan nemen. + +Beperkingen: +- Maximum 3 aandachtspunten (ALLEEN behandelrelevant, geen routine items) +- Maximum 2 actiepunten (ALLEEN actionable voor psychiater) +- Bij twijfel of iets relevant is β†’ FILTER UIT + +Voorbeelden: +βœ… INCLUDE: "Jan weigerde haloperidol, zegt dat medicatie hem controleert" β†’ Medicatie-compliance issue +βœ… INCLUDE: "Marie uitte suΓ―cidale gedachten tijdens gesprek" β†’ Risicosignaal, urgent +βœ… INCLUDE: "Piet verbaal en fysiek agressief, separatie 30 min" β†’ Crisis, gedragsverandering +❌ FILTER: "Jan heeft goed gegeten, ontbijt en lunch zonder problemen" β†’ Routine ADL +❌ FILTER: "Marie deelgenomen aan groepstherapie" β†’ Sociale activiteit, geen issues +❌ FILTER: "Piet heeft medicatie ingenomen volgens schema" β†’ Routine medicatie + +Geef je antwoord als PURE JSON, zonder markdown code blocks.`; + } + + // Verpleegkundige gebruikt bestaande prompt (geen filtering) + return basePrompt; +} + +// Bestaande OVERDRACHT_SYSTEM_PROMPT blijft voor verpleegkundige view +export const OVERDRACHT_SYSTEM_PROMPT = `Je bent een ervaren verpleegkundige die overdrachten maakt in een GGZ-instelling. +...`; // Blijft hetzelfde +``` + +**Filtering Logic:** +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Report Filtering Flow β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Stap 1 (Server - ALTIJD): + β”œβ”€ Filter: include_in_handover = true + └─ Result: Alleen aangevinkte items (bijv. 8 reports) + +Stap 2 (AI - Role-afhankelijk): + β”œβ”€ Verpleegkundige: Geen extra filtering (toon alle 8 reports) + └─ Psychiater: Filter op behandelrelevantie (bijv. 3 relevante reports) + +Output: + β”œβ”€ Verpleegkundige: 5 aandachtspunten, 3 actiepunten (volledige context) + └─ Psychiater: 2-3 aandachtspunten, 1-2 actiepunten (behandelrelevant) +``` + +**Deliverables (E5.S1):** +- [ ] `lib/types/overdracht.ts` β€” Update GenerateOverdrachtSchema met filterForRole +- [ ] `lib/ai/overdracht-prompt.ts` β€” buildSystemPrompt(role) functie met psychiater filtering +- [ ] `app/api/overdracht/generate/route.ts` β€” callClaudeAPI met role parameter +- [ ] `components/swift/blocks/overdracht-block.tsx` β€” Role toggle UI (Verpleegkundige/Psychiater) +- [ ] API call updated met filterForRole in request body +- [ ] Psychiater prompt: max 3 aandachtspunten, 2 actiepunten, strict filtering +- [ ] Verpleegkundige prompt: blijft hetzelfde (geen filtering) +- [ ] UI: Role selector met beschrijving per rol +- [ ] Build succesvol zonder errors +- [ ] Test: verpleegkundige view toont alle items, psychiater view toont alleen behandelrelevante items + +**Acceptatiecriteria:** +1. βœ… Role toggle zichtbaar in OverdrachtBlock (boven period selector) +2. βœ… Default role = "verpleegkundige" (backwards compatible) +3. βœ… Psychiater view filtert op behandelrelevantie (medicatie-issues, gedrag, risico) +4. βœ… Psychiater view filtert UIT: routine medicatie, ADL, sociale activiteiten +5. βœ… Verpleegkundige view blijft werken zoals voorheen (alle aangevinkte items) +6. βœ… AI prompt duidelijk onderscheid tussen WEL/NIET relevant voor psychiater +7. βœ… Build succesvol, geen type errors + +**Git Commits:** +- (to be committed) β€” E5.S1 (AI-filtering psychiater in OverdrachtBlock) + +--- + **E5.S2 - Linked evidence:** ```tsx // components/swift/shared/linked-evidence.tsx