# π Beoordeling Bouwplan Swift: Diagnostiek Workflow **Datum:** 23-12-2024 **Beoordelaar:** AI Code Review **Versie:** v1.0 --- ## Executive Summary **Algemene Beoordeling:** β **HAALBAAR met enkele kritieke aanvullingen** Het bouwplan is goed gestructureerd en bouwt slim voort op bestaande componenten. De geschatte 21 story points voor 2 weken zijn realistisch, maar er zijn enkele belangrijke technische hiaten die eerst opgelost moeten worden voordat de implementatie kan starten. **Kritieke Bevindingen:** 1. β **Report type "diagnostiek" ontbreekt** in `REPORT_TYPES` enum 2. β **Swift intent types** moeten uitgebreid worden met nieuwe intents 3. β οΈ **Entity extraction** voor datum/tijd parsing ontbreekt in plan 4. β οΈ **Intake selectie** voor diagnoses niet duidelijk uitgewerkt 5. β **Hergebruik componenten** is goed geanalyseerd en realistisch **Blokkerende Bevindingen (Swift Foundation - 24-12-2024):** 6. π΄ **E2.S5 Input β Block wiring ontbreekt** - handleSubmit is placeholder 7. π΄ **CanvasArea block rendering ontbreekt** - Blocks worden niet gerenderd 8. π΄ **P1 Blocks (E3) niet geΓ―mplementeerd** - DagnotatieBlock, ZoekenBlock, OverdrachtBlock bestaan niet 9. β οΈ **Type duplicatie** - SwiftIntent in zowel types.ts als swift-store.ts --- ## 1. Compleetheid Analyse ### 1.1 β Sterke Punten **Goed Gedocumenteerd:** - Duidelijke epic/story breakdown met acceptatiecriteria - Realistische effort schattingen (21 SP voor 2 weken) - Goede referenties naar bestaande code - Testplan met concrete checklists - Risico analyse met mitigaties **Technische Analyse:** - Correcte identificatie van hergebruikbare componenten - Wrapper pattern goed uitgelegd - API routes strategie is logisch ### 1.2 β Ontbrekende Elementen #### Kritiek: Report Type "diagnostiek" **Probleem:** Het bouwplan noemt het toevoegen van report type "diagnostiek" (regel 179), maar dit type bestaat niet in de `REPORT_TYPES` enum. **Huidige situatie:** ```typescript // lib/types/report.ts export const REPORT_TYPES = [ 'voortgang', 'observatie', 'incident', 'medicatie', 'contact', 'crisis', 'intake', 'behandeladvies', 'vrije_notitie', 'verpleegkundig' ] as const; ``` **Impact:** - Database validatie zal falen bij POST `/api/reports` met type "diagnostiek" - Zod schema moet uitgebreid worden - Mogelijk database constraint check nodig **Aanbeveling:** Voeg story toe: **E-D1.S0: Report type "diagnostiek" toevoegen** (1 SP) - Update `REPORT_TYPES` enum - Update Zod schema `CreateReportSchema` - Database migratie indien nodig (check constraints) #### Kritiek: Swift Intent Types Uitbreiding **Probleem:** Het bouwplan beschrijft nieuwe intent patterns, maar de `SwiftIntent` type definitie moet uitgebreid worden. **Huidige situatie:** ```typescript // lib/swift/types.ts export type SwiftIntent = 'dagnotitie' | 'zoeken' | 'overdracht' | 'unknown'; ``` **Nodig:** ```typescript export type SwiftIntent = | 'dagnotitie' | 'zoeken' | 'overdracht' | 'afspraak_maken' // NIEUW | 'rapportage' // NIEUW | 'diagnose_bekijken' // NIEUW | 'diagnose_toevoegen' // NIEUW | 'diagnose_wijzigen' // NIEUW | 'unknown'; ``` **Impact:** - TypeScript compile errors zonder deze uitbreiding - Block configs moeten uitgebreid worden - Intent classifier moet nieuwe types ondersteunen **Aanbeveling:** Voeg toe aan E-D1.S1 en E-D2.S1: - Update `SwiftIntent` type - Update `BLOCK_CONFIGS` met nieuwe block types - Update `BlockType` type (exclude 'unknown') #### Waarschuwing: Entity Extraction voor Datum/Tijd **Probleem:** Het bouwplan beschrijft intent patterns die datum/tijd moeten extraheren (bijv. "morgen 10:00"), maar er is geen plan voor entity extraction van deze waarden. **Voorbeeld uit plan:** ``` /^afspraak\s+(\w+)\s+(morgen|vandaag)\s+(\d{1,2}:\d{2})/i ``` **Ontbrekend:** - Functie om "morgen" β Date object te converteren - Functie om "10:00" β tijd te parseren - Validatie van datum/tijd combinaties - Fallback naar date picker bij onduidelijke input **Huidige situatie:** `lib/swift/entity-extractor.ts` bestaat, maar bevat alleen patient name extraction. **Aanbeveling:** Voeg toe aan E-D1.S1: - `extractDateTime(input: string): { date?: Date; time?: string }` - Integratie met date-fns voor Nederlandse datum parsing - Fallback logica voor onduidelijke input #### Waarschuwing: Intake Selectie voor Diagnoses **Probleem:** Het bouwplan beschrijft diagnose toevoegen, maar `DiagnosisDetailForm` vereist een `intakeId` (encounter_id). Het plan beschrijft niet hoe dit wordt bepaald vanuit Swift context. **Huidige situatie:** ```typescript // app/epd/patients/[id]/diagnose/components/diagnosis-detail-form.tsx // Vereist: intakes array en selectedIntakeId ``` **Vragen:** - Moet Swift automatisch de laatste intake selecteren? - Moet Swift een intake selector tonen? - Kan diagnose zonder intake (direct encounter koppeling)? **Aanbeveling:** Voeg toe aan E-D2.S3: - Beslissing: automatisch laatste intake of selector tonen - Documenteer in acceptatiecriteria - Update DiagnoseFormBlock implementatie ### 1.3 β οΈ Onduidelijkheden #### Appointment Modal Hergebruik **Vraag:** Het plan zegt "80% hergebruik" van `AppointmentModal`, maar deze component is een Dialog met veel interne state. Hoe wordt dit geΓ―ntegreerd in Swift blocks? **Huidige situatie:** - `AppointmentModal` is een volledig Dialog component - Swift blocks gebruiken `BlockContainer` (geen Dialog) - Dark theme styling moet aangepast worden **Aanbeveling:** Clarificeer in E-D1.S2: - Option A: Extract form logica naar shared component, wrapper in beide contexts - Option B: Hergebruik AppointmentModal maar wrap in BlockContainer (mogelijk styling issues) - Option C: Nieuwe Swift-specifieke component met shared business logic #### Encounter ID Callback Pattern **Vraag:** Het plan zegt "encounter_id teruggeven via callback", maar hoe wordt dit gebruikt voor de volgende stap (rapportage)? **Scenario:** 1. User: "afspraak diagnostiek jan morgen 10:00" 2. AfspraakBlock β encounter_id = "abc-123" 3. User: "rapportage diagnostiek gesprek met jan" 4. Hoe weet RapportageBlock dat encounter_id "abc-123" moet gebruiken? **Aanbeveling:** Clarificeer: - Option A: Swift store houdt laatste encounter_id bij per patient - Option B: User moet encounter expliciet selecteren - Option C: AI fallback om encounter te matchen op datum/tijd --- ## 2. Haalbaarheid Analyse ### 2.1 β Realistische Schattingen **Story Points Breakdown:** - E-D1.S1: 2 SP (intent patterns) β **Realistisch** - E-D1.S2: 5 SP (AfspraakBlock) β **Realistisch** (met hergebruik) - E-D1.S3: 4 SP (RapportageBlock) β **Realistisch** - E-D2.S1: 2 SP (intent patterns) β **Realistisch** - E-D2.S2: 3 SP (DiagnoseBlock) β **Realistisch** - E-D2.S3: 5 SP (DiagnoseFormBlock) β **Realistisch** **Totaal: 21 SP voor 2 weken = ~10 SP/week** Dit is haalbaar voor 1 developer met goede focus. ### 2.2 β οΈ Risico's op Vertraging **Hoog Risico:** 1. **Appointment Modal Integratie** (E-D1.S2) - Hergebruik Dialog component in Block context kan complex zijn - Styling aanpassingen kunnen meer tijd kosten dan geschat - **Mitigatie:** Start met proof-of-concept, pas schatting aan indien nodig 2. **Datum/Tijd Parsing** (E-D1.S1) - Nederlandse datum parsing ("morgen", "volgende week") kan edge cases hebben - Tijdzone handling voor afspraken - **Mitigatie:** Gebruik date-fns met Nederlandse locale, test grondig **Middel Risico:** 1. **ICD-10 Zoeker Verbetering** (E-D2.S3) - Plan zegt "fuzzy search verbeteren" maar geeft geen specificaties - Bestaande zoeker werkt al redelijk goed - **Mitigatie:** Eerst testen of verbetering nodig is, anders scope verkleinen 2. **Encounter Koppeling** (E-D1.S3) - Automatische koppeling tussen afspraak en rapportage kan complex zijn - **Mitigatie:** Start met optionele koppeling, voeg automatische matching later toe ### 2.3 β Goede Foundation **Bestaande Componenten:** - β AppointmentModal bestaat en is goed gestructureerd - β ReportComposer bestaat en ondersteunt al `linkedEncounterId` - β DiagnosisDetailForm bestaat met ICD-10 zoeker - β Actions bestaan en zijn herbruikbaar - β ICD-10 zoeker werkt al met fuzzy search **Bestaande Infrastructuur:** - β Swift foundation (Command Center, Intent Classification) werkt - β Block system bestaat (`BlockContainer`) - β API routes pattern is duidelijk - β Supabase RLS policies zijn al geΓ―mplementeerd --- ## 3. Technische Aanbevelingen ### 3.1 Kritieke Toevoegingen #### Story E-D1.S0: Report Type "diagnostiek" (NIEUW - 1 SP) **Beschrijving:** Voeg report type "diagnostiek" toe aan het systeem. **Acceptatiecriteria:** - [ ] `REPORT_TYPES` enum bevat "diagnostiek" - [ ] Zod schema `CreateReportSchema` accepteert "diagnostiek" - [ ] Database constraint check (indien nodig) - [ ] QuickActions component toont "diagnostiek" optie (indien van toepassing) **Technical Notes:** ```typescript // lib/types/report.ts export const REPORT_TYPES = [ // ... bestaande types 'diagnostiek', // NIEUW ] as const; ``` #### Story E-D1.S1 Uitbreiding: Entity Extraction **Toevoegen aan E-D1.S1:** - [ ] `extractDateTime(input: string)` functie - [ ] Nederlandse datum parsing ("morgen", "vandaag", "volgende week") - [ ] Tijd parsing ("10:00", "14:30") - [ ] Fallback naar date picker bij onduidelijke input **Technical Notes:** ```typescript // lib/swift/entity-extractor.ts export function extractDateTime(input: string): { date?: Date; time?: string; confidence: number; } { // Parse "morgen 10:00" β { date: tomorrow, time: "10:00" } // Parse "vandaag 14:30" β { date: today, time: "14:30" } // Return confidence voor fallback beslissing } ``` #### Story E-D2.S3 Uitbreiding: Intake Selectie **Clarificatie nodig:** - [ ] Beslissing: automatisch laatste intake of selector? - [ ] Documenteer in acceptatiecriteria - [ ] Implementeer gekozen aanpak **Aanbeveling:** Automatisch laatste intake selecteren, met optie om te wijzigen: ```typescript // DiagnoseFormBlock const intakes = await getPatientIntakes(patientId); const defaultIntakeId = intakes[0]?.id; // Laatste intake // Toon dropdown indien meerdere intakes beschikbaar ``` ### 3.2 Verbeteringen #### Intent Patterns Verbeteren **Huidige patterns zijn te specifiek:** ```typescript // Te specifiek - mist veel variaties /^afspraak\s+(diagnostiek|behandeling)\s+(\w+)/i ``` **Aanbeveling:** Voeg meer variaties toe: ```typescript afspraak_maken: [ // Basis patterns { pattern: /^afspraak\s+(diagnostiek|behandeling)\s+(\w+)/i, weight: 1.0 }, { pattern: /^plan\s+(diagnostiek|behandeling)\s+(\w+)/i, weight: 0.95 }, // Met datum/tijd { pattern: /^afspraak\s+(\w+)\s+(morgen|vandaag)\s+(\d{1,2}:\d{2})/i, weight: 1.0 }, { pattern: /^plan\s+(\w+)\s+(morgen|vandaag)\s+(\d{1,2}:\d{2})/i, weight: 0.95 }, // Zonder type (default diagnostiek) { pattern: /^afspraak\s+(\w+)\s+(morgen|vandaag)/i, weight: 0.85 }, // Alleen "afspraak" met patient naam { pattern: /^afspraak\s+(\w+)/i, weight: 0.7 }, ], ``` #### API Routes Specificatie **Huidige beschrijving is te vaag:** ```typescript // app/api/appointments/route.ts export async function POST(request: NextRequest) { // Wrapper rond app/epd/agenda/actions.ts createEncounter // Retourneert encounter_id voor volgende stap } ``` **Aanbeveling:** Specificeer volledige API contract: ```typescript // POST /api/appointments // Request body: { patientId: string; periodStart: string; // ISO 8601 periodEnd?: string; typeCode: 'diagnostiek' | 'behandeling' | ...; typeDisplay: string; classCode: 'AMB' | 'HH' | 'VR'; classDisplay: string; notes?: string; } // Response: { success: boolean; data?: { id: string; // encounter_id // ... andere encounter velden }; error?: string; } ``` --- ## 4. Testplan Verbeteringen ### 4.1 Ontbrekende Test Cases **Entity Extraction Tests:** - [ ] "morgen 10:00" β correcte datum + tijd - [ ] "vandaag 14:30" β correcte datum + tijd - [ ] "volgende week maandag" β correcte datum - [ ] "afspraak jan" β alleen patient, geen datum β fallback date picker - [ ] "afspraak jan morgen" β patient + datum, geen tijd β fallback time picker **Encounter Koppeling Tests:** - [ ] Afspraak aanmaken β encounter_id opgeslagen - [ ] Rapportage met encounter_id β correct gekoppeld - [ ] Rapportage zonder encounter_id β optioneel (geen error) - [ ] Meerdere encounters opzelfde dag β juiste selectie **Diagnose Intake Tests:** - [ ] PatiΓ«nt met 1 intake β automatisch geselecteerd - [ ] PatiΓ«nt met meerdere intakes β laatste geselecteerd - [ ] PatiΓ«nt zonder intakes β error/fallback ### 4.2 Integration Test Scenarios **End-to-End Flow:** ``` 1. "afspraak diagnostiek jan morgen 10:00" β AfspraakBlock opent β Patient "jan" gevonden β Datum: morgen β Tijd: 10:00 β Type: diagnostiek β Opslaan β encounter_id = "abc-123" 2. "rapportage diagnostiek gesprek met jan" β RapportageBlock opent β Patient "jan" gevonden β Type: diagnostiek β Encounter: "abc-123" (laatste encounter van jan) β Content invoeren β Opslaan β report gekoppeld aan encounter 3. "diagnose jan" β DiagnoseBlock opent β Overzicht diagnoses van jan β Filter: Actief 4. "diagnose toevoegen jan F41.1" β DiagnoseFormBlock opent β Patient: jan β ICD-10: F41.1 (pre-filled) β Intake: laatste intake (automatisch) β Type: nevendiagnose (default) β Opslaan β diagnose toegevoegd ``` --- ## 5. Swift Foundation Status (24-12-2024) > **BELANGRIJK:** De diagnostiek workflow bouwt voort op de Swift foundation (bouwplan-swift-v1.md). > De foundation is nog niet compleet, waardoor de diagnostiek workflow nog niet kan starten. ### 5.1 Foundation Status Overzicht | Epic | Status | Impact op Diagnostiek | |------|--------|----------------------| | E0 Setup & Foundation | β Done | Geen blokkade | | E1 Command Center | β Done | Geen blokkade | | E2 Intent Classification | β³ In Progress | π΄ **BLOKKADE** | | E3 P1 Blocks | β³ To Do | π΄ **BLOKKADE** | | E4 Navigation & Auth | β³ To Do | Geen blokkade | | E5 Polish & Testing | β³ To Do | Geen blokkade | ### 5.2 Blokkerende Issues #### π΄ Blokkade 1: E2.S5 Input β Block Wiring **Huidige situatie:** ```typescript // components/swift/command-center/command-input.tsx:120 const handleSubmit = async (e: React.FormEvent) => { // TODO: Process intent (E2) console.log('Submit:', inputValue); clearInput(); }; ``` **Probleem:** De intent classificatie API bestaat (`/api/intent/classify`), maar wordt niet aangeroepen. Het resultaat wordt niet gebruikt om `openBlock()` aan te roepen. **Impact:** Zonder deze wiring kan geen enkel block geopend worden via tekst/spraak input. **Story toegevoegd aan bouwplan-swift-v1.md (v1.5):** ```markdown | E2.S5 | Input β Block wiring | CommandInput submit β API β openBlock | β³ | E2.S4 | 2 | ``` #### π΄ Blokkade 2: CanvasArea Block Rendering **Huidige situatie:** ```typescript // components/swift/command-center/canvas-area.tsx:18 {activeBlock ? (