# ⚙️ Technisch Ontwerp (TO) – AI Cliënt Assistent **Projectnaam:** Mini-ECD – AI Cliënt Assistent **Versie:** v1.0 **Datum:** 01-12-2025 **Auteur:** Colin Lit --- ## 1. Doel en relatie met PRD en FO **Doel van dit document:** Dit TO beschrijft de technische implementatie van de AI Cliënt Assistent: een uitbreiding op de bestaande AI Documentatie Assistent die vragen over specifieke cliënten kan beantwoorden. **Relatie met PRD:** - PRD beschrijft *wat* we bouwen: cliënt-aware chat die rapportages, risico's en behandeladvies kan samenvatten - TO beschrijft *hoe* we dit technisch realiseren binnen de bestaande architectuur **Scope:** - Uitbreiding van bestaande `docs-chat` component - Nieuwe context loader voor cliëntdata - Vraagtype-detectie (cliënt vs. documentatie) - Cliënt-specifieke prompt templates --- ## 2. Technische Architectuur Overzicht ``` ┌─────────────────────────────────────────────────────────────────┐ │ Frontend (Next.js) │ │ ┌─────────────────┐ ┌──────────────────┐ ┌────────────────┐ │ │ │ DocsChatWidget │ │ PatientContext │ │ ChatSuggestions│ │ │ │ (uitgebreid) │──│ (bestaand) │ │ (dynamisch) │ │ │ └────────┬────────┘ └────────┬─────────┘ └────────────────┘ │ │ │ │ │ └───────────┼────────────────────┼─────────────────────────────────┘ │ │ ▼ ▼ ┌───────────────────────────────────────────────────────────────────┐ │ API Route: /api/docs/chat │ │ ┌──────────────────┐ ┌───────────────────┐ ┌────────────────┐ │ │ │ QuestionDetector │ │ ClientContextLoader│ │ PromptBuilder │ │ │ │ (nieuw) │ │ (nieuw) │ │ (uitgebreid) │ │ │ └────────┬─────────┘ └─────────┬──────────┘ └───────┬────────┘ │ │ │ │ │ │ │ └──────────────────────┼─────────────────────┘ │ │ ▼ │ │ ┌───────────────┐ │ │ │ Claude API │ │ │ │ (streaming) │ │ │ └───────────────┘ │ └───────────────────────────────────────────────────────────────────┘ │ ▼ ┌───────────────────────────────────────────────────────────────────┐ │ Supabase (PostgreSQL) │ │ ┌──────────┐ ┌──────────┐ ┌────────────┐ ┌─────────────────┐ │ │ │ patients │ │ reports │ │ intakes │ │ risk_assessments│ │ │ │ (6 rows) │ │ (21 rows)│ │ (9 rows) │ │ (via intake) │ │ │ └──────────┘ └──────────┘ └────────────┘ └─────────────────┘ │ │ ┌──────────────┐ ┌────────────┐ │ │ │ screenings │ │ care_plans │ │ │ │ (5 rows) │ │ (0 rows) │ │ │ └──────────────┘ └────────────┘ │ └───────────────────────────────────────────────────────────────────┘ ``` --- ## 3. Techstack Selectie | Component | Technologie | Argumentatie | |-----------|-------------|--------------| | Frontend | Next.js 15 + React | Bestaande stack, geen wijziging | | State | PatientContext | Bestaande context, hergebruiken | | API | Next.js API Routes | Bestaande `/api/docs/chat` uitbreiden | | AI | Claude claude-sonnet-4-20250514 | Huidige model, goed voor Nederlands | | Database | Supabase (PostgreSQL) | Bestaand, RLS enabled | | Streaming | Server-Sent Events | Bestaande implementatie | **Geen nieuwe dependencies nodig** - alles bouwt voort op bestaande technologie. --- ## 4. Datamodel Analyse ### 4.1 Beschikbare data per cliënt Op basis van database-analyse is de volgende data beschikbaar: | Tabel | Veld | Beschikbaar | Bruikbaar voor AI | |-------|------|-------------|-------------------| | **patients** | name, birth_date, status | ✅ 6 patiënten | Context header | | **reports** | content, type, created_at | ✅ 21 rapportages | Samenvatting rapportages | | **intakes** | treatment_advice (JSONB), notes | ✅ 9 intakes | Behandeladvies vragen | | **screenings** | request_for_help, decision | ✅ 5 screenings | Hulpvraag/beslissing | | **risk_assessments** | risk_type, risk_level, rationale | ⚠️ 0 rows (via intake) | Risico-overzicht | | **care_plans** | goals, activities (JSONB) | ⚠️ 0 rows | Behandelplan doelen | ### 4.2 Datastructuur voorbeelden **Reports (content):** ``` S – Subjectief: Cliënt geeft aan dat piekergedachten over werk... O – Objectief: Cliënt verschijnt op tijd en verzorgd... E – Evaluatie: Er is sprake van lichte verbetering... P – Plan: Cliënt gaat komende week dagelijks... ``` **Intakes (treatment_advice JSONB):** ```json { "advice": "
Doorzetten naar behandeling
", "outcome": "in_zorg", "program": "FACT", "department": "Volwassenen", "psychologist": "Colin" } ``` ### 4.3 Context Loading Query ```sql -- Rapportages (laatste 5) SELECT type, content, created_at FROM reports WHERE patient_id = $1 AND deleted_at IS NULL ORDER BY created_at DESC LIMIT 5; -- Intakes met behandeladvies SELECT title, department, status, treatment_advice, notes FROM intakes WHERE patient_id = $1 ORDER BY created_at DESC LIMIT 3; -- Screening hulpvraag SELECT request_for_help, decision, decision_notes FROM screenings WHERE patient_id = $1 ORDER BY created_at DESC LIMIT 1; -- Risico-assessments (via intake) SELECT ra.risk_type, ra.risk_level, ra.rationale, ra.assessment_date FROM risk_assessments ra JOIN intakes i ON ra.intake_id = i.id WHERE i.patient_id = $1 ORDER BY ra.assessment_date DESC LIMIT 5; ``` --- ## 5. API Ontwerp ### 5.1 Bestaande API's Analyse **FHIR API's (bestaand):** | Endpoint | Methode | Bruikbaar voor AI Chat | |----------|---------|------------------------| | `/api/fhir/Patient/[id]` | GET | ⚠️ Beperkt - alleen demographics | | `/api/fhir/Patient` | GET/POST | ❌ Niet nodig | | `/api/fhir/Practitioner/[id]` | GET | ❌ Niet relevant | **REST API's (bestaand):** | Endpoint | Methode | Data | Bruikbaar | |----------|---------|------|-----------| | `/api/reports?patientId=` | GET | Rapportages met content | ✅ **Zeer bruikbaar** | | `/api/intakes/[id]` | GET | Intake + treatment_advice | ✅ **Zeer bruikbaar** | | `/api/screenings/[id]` | GET | Hulpvraag + beslissing + activities | ✅ **Zeer bruikbaar** | ### 5.2 Data Access Strategie **Overwogen opties:** | Optie | Beschrijving | Voordelen | Nadelen | |-------|--------------|-----------|---------| | **A: Bestaande API's** | Fetch naar `/api/reports`, `/api/intakes`, etc. | Hergebruik, consistentie | Extra HTTP overhead, intakes/screenings list endpoints ontbreken | | **B: Directe Supabase** | Server-side queries in API route | Sneller, 1 DB roundtrip, RLS automatisch | Duplicatie van query logic | | **C: FHIR $summary** | Nieuw endpoint `GET /api/fhir/Patient/[id]/$summary` | FHIR-compliant, extern bruikbaar | Meeste werk, overkill voor MVP | **Gekozen: Optie B - Directe Supabase queries** Argumentatie: 1. **Performance**: 1 database roundtrip vs. 3-4 HTTP calls 2. **Simpliciteit**: Geen nieuwe endpoints nodig voor MVP 3. **Security**: RLS policies werken automatisch op server-side queries 4. **Latency**: ~50ms vs. ~200ms+ bij HTTP calls **Post-MVP overweging:** Een FHIR `$summary` operation kan waardevol zijn voor externe systeem-integraties. ### 5.3 Chat endpoint uitbreiden **Endpoint:** `POST /api/docs/chat` **Huidige input:** ```typescript { messages: Array<{ role: 'user' | 'assistant', content: string }> } ``` **Uitgebreide input:** ```typescript { messages: Array<{ role: 'user' | 'assistant', content: string }>, clientId?: string // UUID van actieve patiënt (optioneel) } ``` **Response:** Ongewijzigd (SSE streaming) ### 5.4 Nieuwe interne modules ```typescript // lib/docs/question-type-detector.ts export type QuestionType = 'client' | 'documentation' | 'ambiguous' export function detectQuestionType( question: string, hasClientContext: boolean ): QuestionType // lib/docs/client-context-loader.ts export interface ClientContext { patient: { name: string; birthDate: string; status: string } reports: Array<{ type: string; content: string; date: string }> intakes: Array<{ title: string; treatmentAdvice: object }> screening: { requestForHelp: string; decision: string } | null riskAssessments: Array<{ type: string; level: string; rationale: string }> } export async function loadClientContext( clientId: string ): Promise