diff --git a/.gitignore b/.gitignore
index cfb4871..263015d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,4 +45,8 @@ next-env.d.ts
.claude
.mcp.json
-/archive/*
\ No newline at end of file
+# documentation
+/archive/*
+/docs/archive/*
+/docs/specs/archive/*
+/docs/reports/archive/*
\ No newline at end of file
diff --git a/app/(marketing)/documentatie/[category]/page.tsx b/app/(marketing)/documentatie/[category]/page.tsx
index e678b82..af80399 100644
--- a/app/(marketing)/documentatie/[category]/page.tsx
+++ b/app/(marketing)/documentatie/[category]/page.tsx
@@ -41,6 +41,72 @@ export async function generateMetadata({ params }: ReleasePageProps) {
}
}
+function ArticleJsonLd({
+ title,
+ description,
+ releaseDate,
+ slug,
+}: {
+ title: string
+ description: string
+ releaseDate: string
+ slug: string
+}) {
+ const siteUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://aispeedrun.vercel.app'
+
+ const jsonLd = {
+ '@context': 'https://schema.org',
+ '@graph': [
+ {
+ '@type': 'Article',
+ '@id': `${siteUrl}/documentatie/${slug}#article`,
+ headline: title,
+ description: description,
+ datePublished: releaseDate,
+ dateModified: releaseDate,
+ author: {
+ '@type': 'Person',
+ name: 'Colin van der Heijden',
+ url: 'https://ikbenlit.nl',
+ },
+ publisher: { '@id': `${siteUrl}/#organization` },
+ mainEntityOfPage: `${siteUrl}/documentatie/${slug}`,
+ inLanguage: 'nl-NL',
+ },
+ {
+ '@type': 'BreadcrumbList',
+ '@id': `${siteUrl}/documentatie/${slug}#breadcrumb`,
+ itemListElement: [
+ {
+ '@type': 'ListItem',
+ position: 1,
+ name: 'Home',
+ item: siteUrl,
+ },
+ {
+ '@type': 'ListItem',
+ position: 2,
+ name: 'Documentatie',
+ item: `${siteUrl}/documentatie`,
+ },
+ {
+ '@type': 'ListItem',
+ position: 3,
+ name: title,
+ },
+ ],
+ },
+ ],
+ }
+
+ return (
+
+ )
+}
+
export default async function ReleasePage({ params }: ReleasePageProps) {
const { category } = await params
const release = await getRelease(category)
@@ -53,6 +119,12 @@ export default async function ReleasePage({ params }: ReleasePageProps) {
return (
+
{/* Header */}
diff --git a/app/api/docs/chat/route.ts b/app/api/docs/chat/route.ts
index a2072c6..061fff3 100644
--- a/app/api/docs/chat/route.ts
+++ b/app/api/docs/chat/route.ts
@@ -5,6 +5,9 @@ import { getSession } from '@/lib/auth/server'
import { detectCategories } from '@/lib/docs/category-detector'
import { loadKnowledgeSections } from '@/lib/docs/knowledge-loader'
import { buildSystemPrompt } from '@/lib/docs/prompt-builder'
+import { detectQuestionType } from '@/lib/docs/question-type-detector'
+import { loadClientContext } from '@/lib/docs/client-context-loader'
+import { buildClientPrompt, buildClientErrorPrompt } from '@/lib/docs/client-prompt-builder'
const DOCS_ASSISTANT_MODEL = process.env.DOCS_ASSISTANT_MODEL ?? 'claude-sonnet-4-20250514'
const MAX_HISTORY_MESSAGES = 10
@@ -52,6 +55,7 @@ const ChatMessageSchema = z.object({
const RequestSchema = z.object({
messages: z.array(ChatMessageSchema).optional(),
userMessage: z.string().min(1).max(MAX_USER_MESSAGE_LENGTH),
+ clientId: z.string().uuid().optional(), // UUID van actieve patiรซnt
})
type ChatMessage = z.infer
@@ -114,9 +118,28 @@ export async function POST(request: NextRequest) {
const conversation: ChatMessage[] = [...history, { role: 'user', content: rawUserMessage }]
- const categories = detectCategories(rawUserMessage)
- const knowledgeSections = await loadKnowledgeSections(categories)
- const systemPrompt = buildSystemPrompt(knowledgeSections)
+ // Detect question type and build appropriate prompt
+ const clientId = parsed.data.clientId
+ const questionType = detectQuestionType(rawUserMessage, !!clientId)
+
+ let systemPrompt: string
+
+ if (questionType === 'client' && clientId) {
+ // Client-specific question: load client context
+ const clientContext = await loadClientContext(clientId)
+
+ if (clientContext) {
+ systemPrompt = buildClientPrompt(clientContext)
+ } else {
+ // Client not found or error loading
+ systemPrompt = buildClientErrorPrompt()
+ }
+ } else {
+ // Documentation question: use existing knowledge base flow
+ const categories = detectCategories(rawUserMessage)
+ const knowledgeSections = await loadKnowledgeSections(categories)
+ systemPrompt = buildSystemPrompt(knowledgeSections)
+ }
const apiKey = process.env.ANTHROPIC_API_KEY
if (!apiKey) {
diff --git a/app/layout.tsx b/app/layout.tsx
index 68ab03e..2578915 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -119,6 +119,34 @@ export const metadata: Metadata = {
},
};
+const siteUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://aispeedrun.vercel.app'
+
+const jsonLd = {
+ '@context': 'https://schema.org',
+ '@graph': [
+ {
+ '@type': 'Organization',
+ '@id': `${siteUrl}/#organization`,
+ name: 'AI Speedrun',
+ url: siteUrl,
+ description: 'AI-powered EPD development experiment - bouw een EPD in 4 weken voor โฌ200',
+ founder: {
+ '@type': 'Person',
+ name: 'Colin van der Heijden',
+ url: 'https://ikbenlit.nl',
+ },
+ },
+ {
+ '@type': 'WebSite',
+ '@id': `${siteUrl}/#website`,
+ url: siteUrl,
+ name: 'AI Speedrun',
+ publisher: { '@id': `${siteUrl}/#organization` },
+ inLanguage: 'nl-NL',
+ },
+ ],
+}
+
export default function RootLayout({
children,
}: Readonly<{
@@ -126,6 +154,12 @@ export default function RootLayout({
}>) {
return (
+
+
+
diff --git a/app/sitemap.ts b/app/sitemap.ts
index 2a72b35..c678210 100644
--- a/app/sitemap.ts
+++ b/app/sitemap.ts
@@ -1,18 +1,32 @@
/**
* Sitemap Generator
- *
+ *
* Generates sitemap.xml for SEO.
* Next.js will automatically serve this at /sitemap.xml
*/
import type { MetadataRoute } from 'next'
+import { getAllReleases } from '@/lib/mdx/documentatie'
-export default function sitemap(): MetadataRoute.Sitemap {
+export default async function sitemap(): Promise {
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://aispeedrun.vercel.app'
-
- // Get current date for lastModified
const currentDate = new Date()
-
+
+ // Fetch all documentation releases dynamically
+ const releases = await getAllReleases()
+
+ const releaseUrls: MetadataRoute.Sitemap = releases.map((release) => {
+ const releaseDate = new Date(release.frontmatter.releaseDate)
+ const isValidDate = !isNaN(releaseDate.getTime())
+
+ return {
+ url: `${baseUrl}/documentatie/${release.slug}`,
+ lastModified: isValidDate ? releaseDate : currentDate,
+ changeFrequency: 'monthly',
+ priority: 0.8,
+ }
+ })
+
return [
{
url: baseUrl,
@@ -20,19 +34,19 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: 'weekly',
priority: 1.0,
},
- // Future routes can be added here:
- // {
- // url: `${baseUrl}/build-log`,
- // lastModified: currentDate,
- // changeFrequency: 'weekly',
- // priority: 0.8,
- // },
- // {
- // url: `${baseUrl}/demo`,
- // lastModified: currentDate,
- // changeFrequency: 'monthly',
- // priority: 0.7,
- // },
+ {
+ url: `${baseUrl}/documentatie`,
+ lastModified: currentDate,
+ changeFrequency: 'weekly',
+ priority: 0.9,
+ },
+ ...releaseUrls,
+ {
+ url: `${baseUrl}/contact`,
+ lastModified: currentDate,
+ changeFrequency: 'monthly',
+ priority: 0.7,
+ },
]
}
diff --git a/components/docs-chat/chat-suggestions.tsx b/components/docs-chat/chat-suggestions.tsx
index 0dcac30..80082af 100644
--- a/components/docs-chat/chat-suggestions.tsx
+++ b/components/docs-chat/chat-suggestions.tsx
@@ -12,7 +12,10 @@ interface SuggestionCategory {
questions: string[]
}
-const SUGGESTION_CATEGORIES: SuggestionCategory[] = [
+/**
+ * Documentation suggestions - shown when not in a patient dossier
+ */
+const DOC_SUGGESTION_CATEGORIES: SuggestionCategory[] = [
{
id: 'clienten',
label: 'Cliรซnten & Dossiers',
@@ -45,19 +48,63 @@ const SUGGESTION_CATEGORIES: SuggestionCategory[] = [
},
]
+/**
+ * Client suggestions - shown when in a patient dossier
+ */
+const CLIENT_SUGGESTION_CATEGORIES: SuggestionCategory[] = [
+ {
+ id: 'rapportages',
+ label: 'Rapportages',
+ icon: '๐',
+ questions: [
+ 'Geef een samenvatting van de rapportages',
+ 'Wat is er de laatste tijd genoteerd?',
+ 'Zijn er behandeladviezen?',
+ ],
+ },
+ {
+ id: 'intake',
+ label: 'Intake & Behandeling',
+ icon: '๐ฅ',
+ questions: [
+ 'Wat is het behandeladvies?',
+ 'Op welke afdeling loopt de intake?',
+ 'Is de intake afgerond?',
+ ],
+ },
+ {
+ id: 'screening',
+ label: 'Screening',
+ icon: '๐',
+ questions: [
+ 'Wat was de hulpvraag?',
+ 'Wat is de screeningbeslissing?',
+ 'Is de cliรซnt geschikt bevonden?',
+ ],
+ },
+]
+
interface ChatSuggestionsProps {
onSelect: (question: string) => void
disabled?: boolean
+ mode?: 'client' | 'documentation'
}
/**
* Two-step suggestion selector:
* 1. Show categories
* 2. After selecting category, show questions
+ *
+ * Supports two modes:
+ * - 'documentation': Questions about how to use the EPD system
+ * - 'client': Questions about the active patient (rapportages, intake, screening)
*/
-export function ChatSuggestions({ onSelect, disabled = false }: ChatSuggestionsProps) {
+export function ChatSuggestions({ onSelect, disabled = false, mode = 'documentation' }: ChatSuggestionsProps) {
const [selectedCategory, setSelectedCategory] = useState(null)
+ // Select the appropriate categories based on mode
+ const categories = mode === 'client' ? CLIENT_SUGGESTION_CATEGORIES : DOC_SUGGESTION_CATEGORIES
+
const handleQuestionSelect = (question: string) => {
onSelect(question)
setSelectedCategory(null)
@@ -106,9 +153,11 @@ export function ChatSuggestions({ onSelect, disabled = false }: ChatSuggestionsP
// Show category selection
return (
-
Kies een onderwerp:
+
+ {mode === 'client' ? 'Vragen over deze cliรซnt:' : 'Kies een onderwerp:'}
+
- {SUGGESTION_CATEGORIES.map((category) => (
+ {categories.map((category) => (
@@ -90,6 +123,16 @@ export function DocsChatWidget() {
+ {/* Client indicator - shown when in patient dossier */}
+ {hasClientContext && clientName && (
+
+
+
+ Dossier: {clientName}
+
+
+ )}
+
{/* Error banner */}
{error && (
@@ -120,6 +163,7 @@ export function DocsChatWidget() {
)}
diff --git a/components/docs-chat/use-docs-chat.ts b/components/docs-chat/use-docs-chat.ts
index 16091fa..4212181 100644
--- a/components/docs-chat/use-docs-chat.ts
+++ b/components/docs-chat/use-docs-chat.ts
@@ -23,6 +23,14 @@ interface UseDocsChatState {
rateLimitResetTime: number | null // timestamp when rate limit resets
}
+/**
+ * Hook options
+ */
+interface UseDocsChatOptions {
+ clientId?: string // UUID van actieve patiรซnt
+ clientName?: string // Naam van actieve patiรซnt (voor display)
+}
+
/**
* Hook return type
*/
@@ -31,6 +39,8 @@ interface UseDocsChatReturn extends UseDocsChatState {
clearMessages: () => void
clearError: () => void
clearRateLimit: () => void
+ hasClientContext: boolean
+ clientName: string | null
}
/**
@@ -58,12 +68,20 @@ const WELCOME_MESSAGE: ChatMessage = {
* - Streaming responses from Claude API
* - Loading and error states
* - Welcome message on init
+ * - Client-aware: sends clientId for patient-specific questions
*
* @example
+ * // Documentation-only mode
* const { messages, isLoading, sendMessage } = useDocsChat()
- * await sendMessage("Hoe maak ik een intake aan?")
+ *
+ * // Client-aware mode
+ * const { messages, sendMessage, hasClientContext } = useDocsChat({
+ * clientId: patient?.id,
+ * clientName: "Jan de Vries"
+ * })
*/
-export function useDocsChat(): UseDocsChatReturn {
+export function useDocsChat(options?: UseDocsChatOptions): UseDocsChatReturn {
+ const { clientId, clientName } = options ?? {}
const [state, setState] = useState
({
messages: [WELCOME_MESSAGE],
isLoading: false,
@@ -111,6 +129,7 @@ export function useDocsChat(): UseDocsChatReturn {
body: JSON.stringify({
messages: history,
userMessage: trimmedContent,
+ clientId, // Include clientId if available for patient-specific questions
}),
})
@@ -203,7 +222,7 @@ export function useDocsChat(): UseDocsChatReturn {
),
}))
}
- }, [state.messages])
+ }, [state.messages, clientId])
const clearMessages = useCallback(() => {
setState({
@@ -230,5 +249,7 @@ export function useDocsChat(): UseDocsChatReturn {
clearMessages,
clearError,
clearRateLimit,
+ hasClientContext: !!clientId,
+ clientName: clientName ?? null,
}
}
diff --git a/docs/specs/ai-integratie/bouwplan-ai-client-assistent-v1.md b/docs/specs/ai-integratie/bouwplan-ai-client-assistent-v1.md
new file mode 100644
index 0000000..422c9ef
--- /dev/null
+++ b/docs/specs/ai-integratie/bouwplan-ai-client-assistent-v1.md
@@ -0,0 +1,341 @@
+# Bouwplan โ AI Cliรซnt Assistent
+
+**Projectnaam:** Mini-ECD โ AI Cliรซnt Assistent
+**Versie:** v1.0
+**Datum:** 01-12-2025
+**Auteur:** Colin Lit
+
+---
+
+## 1. Doel en context
+
+**Doel:** Uitbreiding van de bestaande AI Documentatie Assistent met cliรซnt-awareness. Wanneer een behandelaar in een cliรซntdossier zit, kan de assistent vragen beantwoorden over dรญe specifieke cliรซnt.
+
+**Aanleiding:** Behandelaren besteden veel tijd aan het navigeren door verschillende schermen om informatie over een cliรซnt te verzamelen. Bij een overdracht of voorbereiding op een consult moeten zij rapportages doorbladeren, risico-assessments opzoeken, behandeladviezen teruglezen en screeningresultaten checken.
+
+**Referenties:**
+- PRD: `docs/specs/ai-integratie/prd-ai-client-assistent-v1.md`
+- FO: `docs/specs/ai-integratie/fo-ai-client-assistent-v1.md`
+- TO: `docs/specs/ai-integratie/to-ai-client-assistent-v1.md`
+
+---
+
+## 2. Uitgangspunten
+
+### 2.1 Technische Stack
+- **Frontend:** Next.js 15 + React + Tailwind CSS
+- **Backend:** Next.js API Routes
+- **Database:** Supabase (PostgreSQL) met RLS
+- **AI/ML:** Claude claude-sonnet-4-20250514 (Anthropic)
+- **Hosting:** Vercel
+- **Auth:** Supabase Auth
+- **Streaming:** Server-Sent Events (SSE)
+
+### 2.2 Projectkaders
+- **Bouwtijd:** ~8-12 uur (MVP)
+- **Team:** 1 developer
+- **Data:** Bestaande demo-data (21 rapportages, 9 intakes, 5 screenings)
+- **Doel:** Werkende cliรซnt-aware chat in bestaande docs-chat widget
+
+### 2.3 Bestaande Infrastructuur (Hergebruik)
+| Component | Status | Hergebruik |
+|-----------|--------|------------|
+| DocsChatWidget | โ
Compleet | ~80% |
+| Streaming (SSE) | โ
Werkt | 100% |
+| PatientContext | โ
Werkt | 100% |
+| Rate limiting | โ
Werkt | 100% |
+| Chat suggestions | โ
Werkt | Uitbreiden |
+| `/api/reports` | โ
Bestaat | Direct bruikbaar |
+| `/api/intakes` | โ
Bestaat | Direct bruikbaar |
+| `/api/screenings` | โ
Bestaat | Direct bruikbaar |
+
+### 2.4 Programmeer Uitgangspunten
+- **DRY:** Hergebruik bestaande docs-chat componenten
+- **KISS:** Minimale wijzigingen aan bestaande code
+- **SOC:** Nieuwe modules in `lib/docs/` voor client-specifieke logica
+- **YAGNI:** Alleen MVP features, geen toekomstige uitbreidingen
+
+---
+
+## 3. Epics & Stories Overzicht
+
+| Epic ID | Titel | Doel | Status | Stories |
+|---------|-------|------|--------|---------|
+| E1 | Backend Modules | Context loader, detector, prompt builder | โ
Done | 3 |
+| E2 | API Uitbreiding | Chat endpoint uitbreiden met clientId | โ
Done | 2 |
+| E3 | Frontend Uitbreiding | Indicator, suggestions, hook aanpassing | โ
Done | 3 |
+| E4 | Testing & Refinement | Integratie testen, prompt tuning | โ
Done | 2 |
+
+---
+
+## 4. Epics & Stories (Uitwerking)
+
+### Epic 1 โ Backend Modules
+**Epic Doel:** Nieuwe modules voor cliรซnt-context laden, vraagtype detectie en prompt building.
+
+| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
+|----------|--------------|---------------------|--------|------------------|----|
+| E1.S1 | Client Context Loader | Laadt patient + reports + intakes + screenings uit Supabase | โ
| โ | 3 |
+| E1.S2 | Question Type Detector | Detecteert 'client' vs 'documentation' vs 'ambiguous' | โ
| โ | 2 |
+| E1.S3 | Client Prompt Builder | Bouwt system prompt met cliรซnt-context | โ
| E1.S1 | 2 |
+
+**Technical Notes:**
+
+**E1.S1 - Client Context Loader** (`lib/docs/client-context-loader.ts`)
+```typescript
+interface ClientContext {
+ patient: { name: string; birthDate: string; status: string }
+ reports: Array<{ type: string; content: string; date: string }>
+ intakes: Array<{ title: string; treatmentAdvice: object; status: string }>
+ screening: { requestForHelp: string; decision: string } | null
+ riskAssessments: Array<{ type: string; level: string; rationale: string }>
+}
+
+// Directe Supabase queries (niet via HTTP voor performance)
+// Parallel laden: Promise.all([reports, intakes, screening, risks])
+// Laatste 5 rapportages, 3 intakes, 1 screening
+```
+
+**E1.S2 - Question Type Detector** (`lib/docs/question-type-detector.ts`)
+```typescript
+const CLIENT_KEYWORDS = [
+ 'rapportage', 'risico', 'behandeladvies', 'screening',
+ 'hulpvraag', 'samenvatting', 'dossier', 'deze cliรซnt'
+]
+const DOC_KEYWORDS = [
+ 'hoe', 'waar', 'wat is', 'tutorial', 'handleiding',
+ 'functie', 'knop', 'menu', 'systeem', 'epd'
+]
+// Return: 'client' | 'documentation' | 'ambiguous'
+```
+
+**E1.S3 - Client Prompt Builder** (`lib/docs/client-prompt-builder.ts`)
+- Strikte regels: alleen beschikbare data, geen hallucinatie
+- Geen medisch advies
+- Beknopt en professioneel
+- Max 4000 tokens context
+
+---
+
+### Epic 2 โ API Uitbreiding
+**Epic Doel:** Bestaande chat endpoint uitbreiden met cliรซnt-awareness.
+
+| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
+|----------|--------------|---------------------|--------|------------------|----|
+| E2.S1 | Request schema uitbreiden | Accepteert optioneel `clientId` parameter | โ
| E1.S1-S3 | 2 |
+| E2.S2 | Routing logica | Bij client-vraag: client prompt, bij doc-vraag: bestaande flow | โ
| E2.S1 | 3 |
+
+**Technical Notes:**
+
+**E2.S1 - Request Schema** (`app/api/docs/chat/route.ts`)
+```typescript
+// Huidige schema uitbreiden:
+{
+ messages: Array<{ role: 'user' | 'assistant', content: string }>,
+ userMessage: string,
+ clientId?: string // Nieuw: UUID van actieve patiรซnt
+}
+```
+
+**E2.S2 - Routing Logica**
+```typescript
+// Pseudocode:
+const questionType = detectQuestionType(userMessage, !!clientId)
+
+if (questionType === 'client' && clientId) {
+ const context = await loadClientContext(clientId)
+ const systemPrompt = buildClientPrompt(context, userMessage)
+ // Skip ai_events logging (privacy)
+} else {
+ // Bestaande documentatie flow
+ const categories = detectCategories(userMessage)
+ const knowledgeSections = await loadKnowledgeSections(categories)
+ const systemPrompt = buildSystemPrompt(knowledgeSections)
+}
+```
+
+---
+
+### Epic 3 โ Frontend Uitbreiding
+**Epic Doel:** UI aanpassingen voor cliรซnt-indicator en dynamische suggestions.
+
+| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
+|----------|--------------|---------------------|--------|------------------|----|
+| E3.S1 | useDocsChat hook uitbreiden | Stuurt clientId mee, exposed hasPatientContext | โ
| E2.S2 | 2 |
+| E3.S2 | Cliรซnt Indicator | Header toont "Dossier: [Naam]" wanneer in dossier | โ
| E3.S1 | 1 |
+| E3.S3 | Dynamische Suggestions | Cliรซnt-suggesties in dossier, doc-suggesties daarbuiten | โ
| E3.S1 | 2 |
+
+**Technical Notes:**
+
+**E3.S1 - Hook Uitbreiding** (`components/docs-chat/use-docs-chat.ts`)
+```typescript
+import { usePatientContext } from '@/app/epd/components/patient-context'
+
+// In hook:
+const { patient } = usePatientContext()
+
+// Bij sendMessage:
+body: JSON.stringify({
+ messages: recentMessages,
+ userMessage,
+ clientId: patient?.id // Meesturen als patient actief
+})
+
+// Exposed voor UI:
+return {
+ ...state,
+ hasPatientContext: !!patient,
+ patientName: patient?.name?.[0]?.text || null
+}
+```
+
+**E3.S2 - Cliรซnt Indicator** (`components/docs-chat/docs-chat-widget.tsx`)
+```tsx
+{hasPatientContext && patientName && (
+
+ Dossier: {patientName}
+
+)}
+```
+
+**E3.S3 - Dynamische Suggestions** (`components/docs-chat/chat-suggestions.tsx`)
+```typescript
+const CLIENT_SUGGESTION_CATEGORIES = [
+ {
+ id: 'rapportages',
+ label: 'Rapportages',
+ icon: 'FileText',
+ questions: [
+ 'Geef een samenvatting van de rapportages',
+ 'Wat is er de laatste tijd genoteerd?',
+ 'Zijn er behandeladviezen?',
+ ],
+ },
+ {
+ id: 'intake',
+ label: 'Intake & Behandeling',
+ icon: 'Building2',
+ questions: [
+ 'Wat is het behandeladvies?',
+ 'Op welke afdeling loopt de intake?',
+ 'Is de intake afgerond?',
+ ],
+ },
+ {
+ id: 'screening',
+ label: 'Screening',
+ icon: 'ClipboardList',
+ questions: [
+ 'Wat was de hulpvraag?',
+ 'Wat is de screeningbeslissing?',
+ 'Is de cliรซnt geschikt bevonden?',
+ ],
+ },
+]
+
+// Props toevoegen:
+interface ChatSuggestionsProps {
+ onSelect: (question: string) => void
+ disabled?: boolean
+ mode?: 'client' | 'documentation' // Nieuw
+}
+```
+
+---
+
+### Epic 4 โ Testing & Refinement
+**Epic Doel:** Integratie testen en prompt verfijning.
+
+| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
+|----------|--------------|---------------------|--------|------------------|----|
+| E4.S1 | Integratie tests | Happy flows werken voor alle 3 categorieรซn | โ
| E3.S3 | 2 |
+| E4.S2 | Prompt tuning | AI geeft accurate, beknopte antwoorden | โ
| E4.S1 | 2 |
+
+**Test Scenarios:**
+1. Open dossier -> chat toont indicator + cliรซnt-suggesties
+2. Vraag "Samenvatting rapportages" -> krijg rapportage overzicht
+3. Vraag "Wat is het behandeladvies?" -> krijg intake info
+4. Vraag "Hoe maak ik een intake?" -> krijg documentatie antwoord
+5. Buiten dossier -> chat toont doc-suggesties
+
+---
+
+## 5. Kwaliteit & Testplan
+
+### Acceptatiecriteria (uit PRD)
+| Criterium | Target |
+|-----------|--------|
+| Cliรซnt correct herkend | 100% (via URL/PatientContext) |
+| Vraagtype correct | >90% correcte classificatie |
+| Eerste token | < 3 seconden |
+| Context laden | < 200ms |
+| Data-integriteit | Alleen data van actieve cliรซnt |
+
+### Test Checklist
+- [ ] Cliรซnt-indicator toont correcte naam in dossier
+- [ ] Cliรซnt-suggesties verschijnen in dossier
+- [ ] Doc-suggesties verschijnen buiten dossier
+- [ ] Vraag over rapportages geeft correcte samenvatting
+- [ ] Vraag over risico's toont "geen data" (0 rows)
+- [ ] Doc-vraag vanuit dossier werkt normaal
+- [ ] Rate limiting werkt nog steeds
+- [ ] Streaming werkt nog steeds
+
+---
+
+## 6. Bestanden Overzicht
+
+### Te wijzigen
+| Bestand | Wijziging |
+|---------|-----------|
+| `app/api/docs/chat/route.ts` | clientId parameter, routing logica |
+| `components/docs-chat/use-docs-chat.ts` | PatientContext integratie |
+| `components/docs-chat/chat-suggestions.tsx` | mode prop, client categories |
+| `components/docs-chat/docs-chat-widget.tsx` | Cliรซnt indicator |
+
+### Nieuw aan te maken
+| Bestand | Doel |
+|---------|------|
+| `lib/docs/client-context-loader.ts` | Laadt cliรซntdata uit Supabase |
+| `lib/docs/question-type-detector.ts` | Detecteert vraagtype |
+| `lib/docs/client-prompt-builder.ts` | Bouwt AI prompt met context |
+
+### Referentie (te lezen)
+| Bestand | Waarom |
+|---------|--------|
+| `app/epd/components/patient-context.tsx` | PatientContext API |
+| `lib/docs/prompt-builder.ts` | Bestaande prompt structuur |
+| `lib/docs/knowledge-loader.ts` | Bestaande knowledge loading |
+
+---
+
+## 7. Risico's & Mitigatie
+
+| Risico | Kans | Impact | Mitigatie |
+|--------|------|--------|-----------|
+| AI hallucineert informatie | Middel | Hoog | Strikte prompt: "alleen beschikbare data" |
+| Geen risk_assessments data | Zeker | Laag | "Geen data" response (feature, niet bug) |
+| Token overflow | Laag | Middel | Truncatie met limit (4000 tokens) |
+| Verkeerde cliรซntdata | Laag | Kritiek | clientId uit PatientContext (betrouwbaar) |
+| Performance degradatie | Laag | Middel | Parallel queries, geen HTTP overhead |
+
+---
+
+## 8. Geschatte Doorlooptijd
+
+| Epic | Schatting |
+|------|-----------|
+| E1 - Backend Modules | 3-4 uur |
+| E2 - API Uitbreiding | 2-3 uur |
+| E3 - Frontend Uitbreiding | 2-3 uur |
+| E4 - Testing & Refinement | 1-2 uur |
+| **Totaal** | **8-12 uur** |
+
+---
+
+## Versiehistorie
+
+| Versie | Datum | Auteur | Wijziging |
+|--------|-------|--------|-----------|
+| v1.0 | 01-12-2025 | Colin Lit | Initiรซle versie op basis van PRD/FO/TO |
+| v1.1 | 02-12-2025 | Colin Lit | E1 (Backend Modules) afgerond, E2 gestart |
diff --git a/docs/specs/ai-integratie/bouwplan-ai-docs-assistent-v1.md b/docs/specs/ai-integratie/bouwplan-ai-docs-assistent-v1.md
deleted file mode 100644
index e96f450..0000000
--- a/docs/specs/ai-integratie/bouwplan-ai-docs-assistent-v1.md
+++ /dev/null
@@ -1,321 +0,0 @@
-# Mission Control โ Bouwplan AI Documentatie Assistent
-
-**Projectnaam:** Mini-ECD โ AI Documentatie Assistent
-**Versie:** v1.0
-**Datum:** 01-12-2025
-**Auteur:** Colin van der Heijden
-
----
-
-## 1. Doel en context
-
-**Doel:** Een floating chat widget bouwen die eindgebruikers van het EPD helpt door vragen te beantwoorden op basis van de systeemdocumentatie.
-
-**Context:** Dit is de eerste AI-integratie in het Mini-ECD prototype. Het dient als fundament voor toekomstige AI features (zoals AI Pre-fill Behandelplan). De widget maakt documentatie direct toegankelijk via een conversatie-interface.
-
-**Relatie met andere documenten:**
-- PRD: `prd-ai-docs-assistent-v1.md` โ Wat en waarom
-- FO: `fo-ai-docs-assistent-v1.md` โ Hoe het werkt voor gebruikers
-
----
-
-## 2. Uitgangspunten
-
-### 2.1 Technische Stack
-
-| Laag | Technologie |
-|------|-------------|
-| **Frontend** | Next.js 14.2 + React + Tailwind CSS |
-| **Backend** | Next.js API Routes (App Router) |
-| **Database** | Supabase PostgreSQL (alleen voor auth check) |
-| **AI** | Claude API (claude-sonnet-4-20250514) met streaming |
-| **Hosting** | Vercel |
-| **Icons** | Lucide React (Sparkles, X, Send) |
-
-### 2.2 Projectkaders
-
-| Aspect | Waarde |
-|--------|--------|
-| **Bouwtijd** | 1-2 dagen |
-| **Team** | 1 developer |
-| **Data** | Alleen bestaande MDX documentatie |
-| **Scope** | MVP โ chat widget met streaming responses |
-| **Persistentie** | Sessie-only (geen database opslag) |
-
-### 2.3 Programmeer Uitgangspunten
-
-**Code Quality Principles:**
-
-- **DRY** โ Herbruikbare hook voor chat state, centrale prompt configuratie
-- **KISS** โ Eenvoudige fetch naar Claude API, geen SDK overhead
-- **SOC** โ UI componenten gescheiden van API logic en knowledge base
-- **YAGNI** โ Geen RAG, geen database opslag, geen multi-provider support
-
-**Security:**
-- API key alleen server-side (Next.js API route)
-- Widget alleen voor ingelogde gebruikers
-- Geen logging van conversaties
-
----
-
-## 3. Epics & Stories Overzicht
-
-| Epic ID | Titel | Doel | Status | Stories |
-|---------|-------|------|--------|---------|
-| E0 | Knowledge Base Content | FAQ's en guidelines in markdown | โ
Done | 2 |
-| E1 | Knowledge Services | CategoryDetector, KnowledgeLoader, PromptBuilder | โ
Done | 3 |
-| E2 | API Endpoint | Streaming Claude integratie | โ
Done | 1 |
-| E3 | Chat UI Components | Widget, messages, input | โ
Done | 4 |
-| E4 | Integratie & Testing | Widget in EPD, testen | โ
Done | 2 |
-
-**Totaal:** 12 stories, ~18 story points
-
----
-
-## 4. Epics & Stories (Uitwerking)
-
-### Epic 0 โ Knowledge Base Content
-
-**Epic Doel:** Gestructureerde FAQ's en guidelines in markdown bestanden.
-
-| Story ID | Beschrijving | Acceptatiecriteria | Status | SP |
-|----------|--------------|---------------------|--------|-----|
-| E0.S1 | FAQ markdown bestanden | 6 FAQ bestanden met Q&A per categorie | โ
| 2 |
-| E0.S2 | Guidelines bestanden | 2 guideline bestanden (interface, technisch) | โ
| 1 |
-
-**Deliverables:**
-```
-lib/docs/knowledge/
-โโโ faq_clientbeheer.md # Cliรซnt aanmaken, zoeken, verwijderen
-โโโ faq_intake.md # Intake starten, notities, spraak
-โโโ faq_screening.md # Screening resultaten, vragenlijsten
-โโโ faq_behandelplan.md # Plan maken, doelen, interventies
-โโโ faq_spraak.md # Microfoon, dicteren, transcriptie
-โโโ faq_inloggen.md # Login, wachtwoord, rechten
-โโโ guidelines_interface.md # UI uitleg, navigatie, menu's
-โโโ guidelines_technisch.md # FHIR API, data model (devs)
-```
-
----
-
-### Epic 1 โ Knowledge Services
-
-**Epic Doel:** Intelligente services voor dynamische knowledge loading.
-
-| Story ID | Beschrijving | Acceptatiecriteria | Status | SP |
-|----------|--------------|---------------------|--------|-----|
-| E1.S1 | CategoryDetector | Keyword matching om relevante categorieรซn te bepalen | โ
| 2 |
-| E1.S2 | KnowledgeLoader | Laadt alleen relevante markdown bestanden | โ
| 2 |
-| E1.S3 | PromptBuilder | Combineert base prompt + relevante knowledge | โ
| 2 |
-
-**Deliverables:**
-```
-lib/docs/
-โโโ category-detector.ts # Analyseert vraag โ categorieรซn
-โโโ knowledge-loader.ts # Laadt relevante knowledge
-โโโ prompt-builder.ts # Bouwt geoptimaliseerde prompt
-```
-
-**Category Mapping:**
-```typescript
-const CATEGORY_KEYWORDS: Record = {
- clientbeheer: ['cliรซnt', 'patient', 'aanmaken', 'zoeken', 'dossier'],
- intake: ['intake', 'gesprek', 'notitie', 'verslag'],
- screening: ['screening', 'vragenlijst', 'score', 'resultaat'],
- behandelplan: ['behandelplan', 'doel', 'interventie', 'plan'],
- spraak: ['spraak', 'microfoon', 'dicteren', 'stem', 'transcriptie'],
- inloggen: ['inloggen', 'wachtwoord', 'login', 'account'],
- interface: ['menu', 'knop', 'scherm', 'navigatie', 'waar vind'],
- technisch: ['api', 'fhir', 'endpoint', 'database', 'developer']
-};
-```
-
-**Flow:**
-```
-Vraag: "Hoe maak ik een intake aan?"
- โ
-CategoryDetector โ ['intake']
- โ
-KnowledgeLoader โ laadt faq_intake.md
- โ
-PromptBuilder โ base prompt + intake FAQ
- โ
-Claude API โ streaming response
-```
-
----
-
-### Epic 2 โ API Endpoint
-
-**Epic Doel:** Streaming API endpoint met dynamische knowledge.
-
-| Story ID | Beschrijving | Acceptatiecriteria | Status | SP |
-|----------|--------------|---------------------|--------|-----|
-| E2.S1 | Streaming endpoint | `POST /api/docs/chat` met dynamic knowledge, SSE stream | โ
| 3 |
-
-**Deliverables:**
-```
-app/api/docs/chat/
- route.ts # Streaming API endpoint
-```
-
-**API Contract:**
-```typescript
-// Request
-POST /api/docs/chat
-{
- messages: Array<{ role: 'user' | 'assistant', content: string }>,
- userMessage: string
-}
-
-// Response: Server-Sent Events stream
-event: content_block_delta
-data: {"delta":{"text":"..."}}
-```
-
----
-
-### Epic 3 โ Chat UI Components
-
-**Epic Doel:** Complete chat widget UI volgens FO specificaties.
-
-| Story ID | Beschrijving | Acceptatiecriteria | Status | SP |
-|----------|--------------|---------------------|--------|-----|
-| E3.S1 | Chat state hook | `use-docs-chat.ts` met messages, loading, sendMessage, streaming | โ
| 2 |
-| E3.S2 | Message list component | `chat-messages.tsx` met styling, auto-scroll, streaming cursor | โ
| 1 |
-| E3.S3 | Input component | `chat-input.tsx` met textarea, send, Enter/Shift+Enter | โ
| 1 |
-| E3.S4 | Widget container | `docs-chat-widget.tsx` met trigger, panel, header, animaties | โ
| 2 |
-
-**Deliverables:**
-```
-components/docs-chat/
- use-docs-chat.ts # Custom hook
- chat-messages.tsx # Message list
- chat-input.tsx # Input area
- docs-chat-widget.tsx # Main container
-```
-
-**UI Specs (uit FO):**
-
-| Element | Specificatie |
-|---------|--------------|
-| Trigger button | 56x56px, amber gradient, Sparkles icon, `fixed bottom-6 right-6` |
-| Panel | 384px breed, max 80vh, slide-in animatie |
-| User messages | Rechts, `bg-amber-100`, rounded |
-| Assistant messages | Links, `bg-slate-100`, rounded |
-| Streaming | Pulserende cursor `โ` |
-
----
-
-### Epic 4 โ Integratie & Testing
-
-**Epic Doel:** Widget geรฏntegreerd in EPD en getest.
-
-| Story ID | Beschrijving | Acceptatiecriteria | Status | SP |
-|----------|--------------|---------------------|--------|-----|
-| E4.S1 | Widget integratie | `DocsChatWidget` in EPD layout, alleen ingelogde users | โ
| 1 |
-| E4.S2 | Smoke tests | Happy flow, error states, category detection werkt | โ
| 1 |
-
-**Te wijzigen bestand:**
-```
-app/epd/components/epd-layout-client.tsx
-```
-
----
-
-## 5. Kwaliteit & Testplan
-
-### Test Types
-
-| Test Type | Scope | Methode |
-|-----------|-------|---------|
-| Unit | Knowledge base loader | Console test |
-| Integration | API endpoint | curl/Postman |
-| Smoke | Volledige flow | Manual in browser |
-
-### Manual Test Checklist
-
-- [ ] Widget trigger button zichtbaar in EPD
-- [ ] Klik opent chat panel met animatie
-- [ ] Welkomstbericht wordt getoond
-- [ ] Vraag versturen werkt (Enter + button)
-- [ ] Streaming response verschijnt woord-voor-woord
-- [ ] Vervolgvraag behoudt context
-- [ ] X-knop sluit panel
-- [ ] Conversatie blijft behouden na sluiten/openen
-- [ ] Error state toont bij API failure
-- [ ] Widget verdwijnt bij uitloggen
-
-### Acceptatiecriteria (uit PRD)
-
-| Criterium | Target |
-|-----------|--------|
-| First token | < 2 seconden |
-| Volledige response | < 30 seconden |
-| Error rate | < 5% |
-
----
-
-## 6. Demo & Presentatieplan
-
-**Duur:** 3 minuten
-**Scenario:**
-
-1. **Intro** (30s): "Dit is de documentatie assistent"
-2. **Vraag 1** (45s): "Hoe maak ik een intake aan?" โ streaming antwoord
-3. **Vraag 2** (45s): "En hoe gebruik ik spraakherkenning?" โ context behouden
-4. **Edge case** (30s): "Wat is de beste behandeling?" โ "weet ik niet" response
-5. **Afsluiting** (30s): Widget sluiten, conversatie behouden
-
----
-
-## 7. Risico's & Mitigatie
-
-| Risico | Kans | Impact | Mitigatie |
-|--------|------|--------|-----------|
-| AI hallucineert | Middel | Hoog | Strikte system prompt, FAQ's eerst, "alleen uit docs" regel |
-| Trage response | Laag | Middel | Streaming UX, timeout na 30s |
-| Context te groot | Laag | Middel | ~119KB past in context window, monitoring |
-| API rate limits | Laag | Middel | Sessie-based (geen caching nodig) |
-
----
-
-## 8. Referenties
-
-### Mission Control Documents
-
-- **PRD:** `prd-ai-docs-assistent-v1.md`
-- **FO:** `fo-ai-docs-assistent-v1.md`
-- **Gerelateerd:** `prd-ai-prefill-behandelplan-v1.md`
-
-### Bestaande Code Patterns
-
-| Bestand | Pattern |
-|---------|---------|
-| `app/api/reports/classify/route.ts` | Claude API fetch pattern |
-| `lib/mdx/documentatie.ts` | MDX loading met gray-matter |
-| `components/ui/ai-button.tsx` | Amber AI styling |
-
-### Externe Referenties
-
-- [Claude API Docs](https://docs.anthropic.com)
-- [Anthropic Streaming](https://docs.anthropic.com/en/api/streaming)
-
----
-
-## 9. Glossary
-
-| Term | Betekenis |
-|------|-----------|
-| SSE | Server-Sent Events (streaming protocol) |
-| Knowledge Base | Verzameling documentatie voor AI context |
-| FAQ | Frequently Asked Questions |
-| Streaming | Real-time response, woord-voor-woord |
-
----
-
-**Versiehistorie:**
-
-| Versie | Datum | Auteur | Wijziging |
-|--------|-------|--------|-----------|
-| v1.0 | 01-12-2025 | Colin van der Heijden | Initiรซle versie |
diff --git a/docs/specs/ai-integratie/fo-ai-client-assistent-v1.md b/docs/specs/ai-integratie/fo-ai-client-assistent-v1.md
new file mode 100644
index 0000000..7842dba
--- /dev/null
+++ b/docs/specs/ai-integratie/fo-ai-client-assistent-v1.md
@@ -0,0 +1,367 @@
+# ๐งฉ Functioneel Ontwerp (FO) โ 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 het PRD
+
+**Doel van dit document:**
+Dit FO beschrijft hoe de AI Cliรซnt Assistent functioneel werkt vanuit gebruikersperspectief. Het PRD beschrijft *wat* we bouwen (cliรซnt-aware chat), dit FO laat zien *hoe* de gebruiker dit ervaart.
+
+**Scope (prototype):**
+Gebaseerd op de huidige data in het EPD:
+- **21 rapportages** (16 vrije notities, 5 behandeladviezen)
+- **9 intakes** (7 Volwassenen, 1 Jeugd)
+- **5 screenings** (1 geschikt, 1 niet geschikt, 3 open)
+- **0 risico-assessments** (tabel bestaat, geen data)
+
+---
+
+## 2. Overzicht van de onderdelen
+
+| Onderdeel | Beschrijving | Status |
+|-----------|--------------|--------|
+| **Chat Widget** | Bestaande floating widget rechtsonder | Uitbreiden |
+| **Cliรซnt Indicator** | Header die toont welke cliรซnt actief is | Nieuw |
+| **Cliรซnt Suggesties** | Voorbeeldvragen over de actieve cliรซnt | Nieuw |
+| **Vraagtype Detectie** | Herkent of vraag over cliรซnt of systeem gaat | Nieuw |
+
+---
+
+## 3. User Stories
+
+| ID | Rol | Doel / Actie | Verwachte waarde | Prioriteit |
+|----|-----|--------------|------------------|------------|
+| US-01 | Behandelaar | Samenvatting van rapportages opvragen | Snel overzicht voor consult | Hoog |
+| US-02 | Behandelaar | Behandeladvies opvragen | Inzicht in geadviseerde zorg | Hoog |
+| US-03 | Verpleegkundige | Recente notities bekijken | Overdracht voorbereiding | Hoog |
+| US-04 | Intaker | Hulpvraag en screening status opvragen | Intake afronden | Middel |
+| US-05 | Behandelaar | Documentatie-vraag stellen vanuit dossier | Hulp bij EPD gebruik | Middel |
+
+---
+
+## 4. Functionele werking per onderdeel
+
+### 4.1 Chat Widget (uitgebreid)
+
+**Huidige situatie:**
+- Floating button rechtsonder (amber, sparkles icon)
+- Beantwoordt alleen documentatie-vragen
+- Toont 3 categorieรซn met voorbeeldvragen
+
+**Nieuwe situatie:**
+- Detecteert automatisch of gebruiker in cliรซntdossier zit
+- Toont cliรซnt-indicator in header wanneer in dossier
+- Schakelt tussen cliรซnt- en documentatie-suggesties
+- Beantwoordt vragen over de actieve cliรซnt
+
+### 4.2 Cliรซnt Indicator
+
+**Locatie:** Header van chat widget, onder "EPD Assistent"
+
+**Weergave:**
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ โจ EPD Assistent โ
+โ ๐ Dossier: Jan de Vries โ โ Nieuw: cliรซnt indicator
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+**Gedrag:**
+| Context | Indicator |
+|---------|-----------|
+| In cliรซntdossier | `๐ Dossier: [Cliรซntnaam]` |
+| Buiten dossier | Geen indicator (alleen "EPD Assistent") |
+
+### 4.3 Cliรซnt Suggesties
+
+**Wanneer tonen:** Bij eerste opening chat in cliรซntdossier, alleen welkomstbericht zichtbaar
+
+**Categorieรซn en vragen (gebaseerd op beschikbare data):**
+
+| Categorie | Icon | Voorbeeldvragen |
+|-----------|------|-----------------|
+| **Rapportages** | ๐ | "Geef een samenvatting van de rapportages", "Wat is er de laatste tijd genoteerd?", "Zijn er behandeladviezen?" |
+| **Intake & Behandeling** | ๐ฅ | "Wat is het behandeladvies?", "Op welke afdeling loopt de intake?", "Is de intake afgerond?" |
+| **Screening** | ๐ | "Wat was de hulpvraag?", "Wat is de screeningbeslissing?", "Is de cliรซnt geschikt bevonden?" |
+
+**Interactie:**
+1. Gebruiker ziet 3 categorieรซn (knoppen)
+2. Klik op categorie โ toont 3 voorbeeldvragen
+3. Klik op vraag โ vraag wordt direct verstuurd
+4. "Terug" knop om naar categorieรซn te gaan
+
+### 4.4 Vraagtype Detectie
+
+**Doel:** Bepalen of een vraag over de cliรซnt of over het systeem gaat
+
+**Gedrag:**
+
+| Vraag | Detectie | Actie |
+|-------|----------|-------|
+| "Geef een samenvatting van de rapportages" | Cliรซnt | Beantwoord met cliรซntdata |
+| "Hoe maak ik een intake aan?" | Documentatie | Beantwoord met systeemdocumentatie |
+| "Wat zijn de risico's?" | Cliรซnt | Beantwoord met cliรซntdata (of "geen data") |
+| "Hoe werkt de spraakherkenning?" | Documentatie | Beantwoord met systeemdocumentatie |
+
+**Edge cases:**
+| Situatie | Gedrag |
+|----------|--------|
+| Ambigue vraag in dossier | Default naar documentatie, toon hint |
+| Cliรซnt-vraag buiten dossier | "Open eerst een cliรซntdossier om vragen te stellen" |
+| Data ontbreekt | "Er zijn nog geen [rapportages/risico's] voor deze cliรซnt" |
+
+---
+
+## 5. UI-overzicht
+
+### 5.1 Chat Widget Layout
+
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ โจ EPD Assistent [X] โ โ Header
+โ ๐ Dossier: Jan de Vries โ โ Cliรซnt indicator (nieuw)
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
+โ โ
+โ [Welkomstbericht] โ โ Messages area
+โ โ
+โ [Gebruiker vraag] โ โ
+โ [Assistent antwoord] โ โ
+โ โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
+โ Kies een onderwerp: โ โ Suggesties (context-aware)
+โ [๐ Rapportages] โ
+โ [๐ฅ Intake & Behandeling] โ
+โ [๐ Screening] โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
+โ [Typ een vraag... ] [Send] โ โ Input
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### 5.2 Suggestie Flow (twee stappen)
+
+**Stap 1: Categorieรซn**
+```
+Kies een onderwerp:
+โโโโโโโโโโโโโโโโโโโโโโโโ
+โ ๐ Rapportages โ
+โโโโโโโโโโโโโโโโโโโโโโโโค
+โ ๐ฅ Intake & Behandeling โ
+โโโโโโโโโโโโโโโโโโโโโโโโค
+โ ๐ Screening โ
+โโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+**Stap 2: Vragen (na klik op categorie)**
+```
+โ Terug
+๐ Rapportages
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ Geef een samenvatting van de โ
+โ rapportages โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
+โ Wat is er de laatste tijd genoteerd?โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
+โ Zijn er behandeladviezen? โ
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### 5.3 Context Switching
+
+| Locatie in EPD | Chat Gedrag |
+|----------------|-------------|
+| Dashboard (geen cliรซnt) | Documentatie-modus, standaard suggesties |
+| Cliรซntdossier | Cliรซnt-modus, cliรซnt-indicator, cliรซnt-suggesties |
+| Cliรซnt โ Dashboard | Terug naar documentatie-modus |
+
+---
+
+## 6. Interacties met AI
+
+### 6.1 Cliรซnt-vragen
+
+| Vraag | AI Context | Verwacht Antwoord |
+|-------|------------|-------------------|
+| "Samenvatting rapportages" | Laatste 5 reports | Bullets per rapportage met datum en type |
+| "Wat is het behandeladvies?" | intakes.treatment_advice | Advies, programma, afdeling |
+| "Wat was de hulpvraag?" | screenings.request_for_help | Hulpvraag tekst of "niet ingevuld" |
+| "Zijn er risico's?" | risk_assessments (leeg) | "Er zijn nog geen risico-assessments" |
+
+### 6.2 Voorbeeld Antwoorden
+
+**Vraag: "Geef een samenvatting van de rapportages"**
+
+```
+De laatste rapportages voor Jan de Vries:
+
+๐ 28-11-2025 - Vrije notitie
+Cliรซnt ervaart stemming als overwegend somber, maar benoemt ook
+positieve momenten tijdens sport. Slaapproblemen blijven aandachtspunt.
+
+๐ 25-11-2025 - Vrije notitie
+Gesprek over terugvalpreventie. Cliรซnt toont inzet en motivatie.
+
+๐ 22-11-2025 - Behandeladvies
+Doorzetten naar behandeling, FACT programma, afdeling Volwassenen.
+```
+
+**Vraag: "Wat is het behandeladvies?"**
+
+```
+Het behandeladvies voor Jan de Vries:
+
+โข Advies: Doorzetten naar behandeling
+โข Programma: FACT
+โข Afdeling: Volwassenen
+โข Uitkomst: In zorg
+
+Dit advies is vastgelegd bij intake "Intake Depressie" (afgerond).
+```
+
+**Vraag: "Wat zijn de risico's?"**
+
+```
+Er zijn nog geen risico-assessments vastgelegd voor Jan de Vries.
+
+Risico-assessments kunnen worden toegevoegd via de intake of
+het tabblad 'Risico's' in het cliรซntdossier.
+```
+
+### 6.3 Foutafhandeling
+
+| Situatie | Gebruiker ziet |
+|----------|----------------|
+| Geen rapportages | "Er zijn nog geen rapportages voor [naam]" |
+| API error | "Er ging iets mis. Probeer het opnieuw." |
+| Rate limit bereikt | Countdown timer + uitleg (bestaand) |
+
+---
+
+## 7. Gebruikersrollen en rechten
+
+**Prototype scope:** Alle ingelogde gebruikers hebben dezelfde rechten.
+
+| Rol | Toegang Chat | Cliรซnt Data |
+|-----|--------------|-------------|
+| Behandelaar | โ
| Eigen cliรซnten (via RLS) |
+| Demo-user | โ
| Fictieve demo-cliรซnten |
+
+**Security:**
+- Cliรซnt-ID komt uit URL/PatientContext (betrouwbaar)
+- RLS policies op database niveau
+- Geen cliรซntdata in logs
+
+---
+
+## 8. Configuratie Suggesties
+
+### 8.1 Cliรซnt Suggesties (nieuw)
+
+```typescript
+const CLIENT_SUGGESTION_CATEGORIES = [
+ {
+ id: 'rapportages',
+ label: 'Rapportages',
+ icon: '๐',
+ questions: [
+ 'Geef een samenvatting van de rapportages',
+ 'Wat is er de laatste tijd genoteerd?',
+ 'Zijn er behandeladviezen?',
+ ],
+ },
+ {
+ id: 'intake',
+ label: 'Intake & Behandeling',
+ icon: '๐ฅ',
+ questions: [
+ 'Wat is het behandeladvies?',
+ 'Op welke afdeling loopt de intake?',
+ 'Is de intake afgerond?',
+ ],
+ },
+ {
+ id: 'screening',
+ label: 'Screening',
+ icon: '๐',
+ questions: [
+ 'Wat was de hulpvraag?',
+ 'Wat is de screeningbeslissing?',
+ 'Is de cliรซnt geschikt bevonden?',
+ ],
+ },
+]
+```
+
+### 8.2 Documentatie Suggesties (bestaand, behouden)
+
+```typescript
+const DOC_SUGGESTION_CATEGORIES = [
+ {
+ id: 'clienten',
+ label: 'Cliรซnten & Dossiers',
+ icon: '๐ค',
+ questions: [
+ 'Hoe maak ik een nieuwe cliรซnt aan?',
+ 'Hoe zoek ik een bestaande cliรซnt?',
+ 'Hoe open ik een cliรซntdossier?',
+ ],
+ },
+ // ... bestaande categorieรซn
+]
+```
+
+---
+
+## 9. Acceptatiecriteria
+
+### 9.1 Functioneel
+
+| Criterium | Test |
+|-----------|------|
+| Cliรซnt-indicator toont correcte naam | Open dossier โ check header |
+| Cliรซnt-suggesties verschijnen in dossier | Open chat in dossier โ zie 3 categorieรซn |
+| Documentatie-suggesties buiten dossier | Open chat op dashboard โ zie bestaande categorieรซn |
+| Vraag over rapportages werkt | Stel vraag โ ontvang samenvatting |
+| Ontbrekende data wordt gemeld | Vraag naar risico's โ "geen data" bericht |
+
+### 9.2 Niet-functioneel
+
+| Criterium | Target |
+|-----------|--------|
+| Eerste antwoord | < 3 seconden |
+| Context laden | < 200ms |
+| Correcte cliรซnt | 100% (via URL) |
+
+---
+
+## 10. Bijlagen & Referenties
+
+### Projectdocumenten
+
+| Document | Locatie |
+|----------|---------|
+| PRD | `docs/specs/ai-integratie/prd-ai-client-assistent-v1.md` |
+| TO | `docs/specs/ai-integratie/to-ai-client-assistent-v1.md` |
+| Bestaande chat widget | `components/docs-chat/docs-chat-widget.tsx` |
+| Bestaande suggesties | `components/docs-chat/chat-suggestions.tsx` |
+
+### Data beschikbaarheid (prototype)
+
+| Tabel | Rows | Bruikbaar voor vragen |
+|-------|------|----------------------|
+| reports | 21 | โ
Samenvatting rapportages |
+| intakes | 9 | โ
Behandeladvies, status |
+| screenings | 5 | โ
Hulpvraag, beslissing |
+| risk_assessments | 0 | โ ๏ธ "Geen data" response |
+
+---
+
+## Versiehistorie
+
+| Versie | Datum | Auteur | Wijziging |
+|--------|-------|--------|-----------|
+| v1.0 | 01-12-2025 | Colin Lit | Initiรซle versie, prototype scope |
diff --git a/docs/specs/ai-integratie/fo-ai-docs-assistent-v1.md b/docs/specs/ai-integratie/fo-ai-docs-assistent-v1.md
deleted file mode 100644
index fcc3097..0000000
--- a/docs/specs/ai-integratie/fo-ai-docs-assistent-v1.md
+++ /dev/null
@@ -1,386 +0,0 @@
-# Functioneel Ontwerp (FO) โ AI Documentatie Assistent
-
-**Projectnaam:** Mini-ECD โ AI Documentatie Assistent
-**Versie:** v1.0
-**Datum:** 01-12-2025
-**Auteur:** Colin van der Heijden
-
----
-
-## 1. Doel en relatie met het PRD
-
-**Doel van dit document:**
-Dit Functioneel Ontwerp beschrijft **hoe** de AI Documentatie Assistent functioneel werkt โ wat de gebruiker ziet, doet en ervaart. Waar het PRD (`prd-ai-docs-assistent-v1.md`) uitlegt *wat en waarom*, laat dit FO zien *hoe dit in de praktijk werkt*.
-
-**Toelichting aan de lezer:**
-De AI Documentatie Assistent is een floating chat widget die eindgebruikers van het EPD helpt door vragen te beantwoorden op basis van de systeemdocumentatie. Dit is de eerste AI-integratie in het Mini-ECD prototype en dient als fundament voor toekomstige AI features.
-
----
-
-## 2. Overzicht van de belangrijkste onderdelen
-
-1. **Floating Trigger Button** โ Amber knop rechtsonder om widget te openen
-2. **Chat Panel** โ Uitklapbaar gesprekspaneel
-3. **Message List** โ Weergave van conversatie (gebruiker + assistent)
-4. **Input Area** โ Tekstveld voor vragen stellen
-5. **Streaming Response** โ Real-time weergave van AI antwoorden
-
----
-
-## 3. Userstories
-
-| ID | Rol | Doel / Actie | Verwachte waarde | Prioriteit |
-|----|------|---------------|------------------|-------------|
-| US-01 | Behandelaar | Vraag stellen over EPD functie | Direct antwoord zonder zoeken | Hoog |
-| US-02 | Verpleegkundige | Uitleg krijgen over onbekende functie | Zelfstandig werken zonder collega's te storen | Hoog |
-| US-03 | Nieuwe medewerker | Systeem leren kennen via vragen | Interactieve onboarding | Hoog |
-| US-04 | Behandelaar | Vervolgvraag stellen | Context behouden in gesprek | Middel |
-| US-05 | Developer | Technische vraag over API | Snelle referentie zonder docs te openen | Middel |
-| US-06 | Alle gebruikers | Widget sluiten | Terug naar werk zonder afleiding | Hoog |
-
-**User Story Details:**
-
-> **US-01:** Als behandelaar wil ik een vraag kunnen stellen over het EPD zodat ik direct antwoord krijg zonder door documentatie te hoeven zoeken.
-
-> **US-02:** Als verpleegkundige wil ik uitleg kunnen vragen over een functie die ik niet ken zodat ik zelfstandig verder kan werken.
-
-> **US-03:** Als nieuwe medewerker wil ik via vragen het systeem leren kennen zodat ik sneller productief ben.
-
----
-
-## 4. Functionele werking per onderdeel
-
-### 4.1 Floating Trigger Button
-
-**Locatie:** Rechtsonder in het scherm, altijd zichtbaar binnen EPD (`/epd/*` routes)
-
-**Gedrag:**
-- Amber gradient knop (56x56px) met Sparkles icon
-- Hover: lichte kleurverandering
-- Klik: opent chat panel, knop verdwijnt
-- Altijd bovenop andere content (z-index: 50)
-
-**States:**
-| State | Weergave |
-|-------|----------|
-| Default | Amber gradient met wit icon |
-| Hover | Donkerder amber |
-| Widget open | Knop verborgen |
-
----
-
-### 4.2 Chat Panel
-
-**Afmetingen:** 384px breed ร max 80vh hoog
-
-**Structuur:**
-```
-โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
-โ Header: titel + sluit-knop โ
-โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
-โ โ
-โ Message List (scrollbaar) โ
-โ โ
-โ โ
-โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
-โ Input Area: tekstveld + verzenden โ
-โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
-```
-
-**Header:**
-- Sparkles icon + "Documentatie Assistent" tekst
-- X-knop rechts om te sluiten
-- Amber/amber-100 achtergrond gradient
-
-**Gedrag bij openen:**
-1. Panel verschijnt met slide-in animatie (van onder)
-2. Welkomstbericht wordt getoond (indien eerste keer)
-3. Focus gaat naar input veld
-
-**Gedrag bij sluiten:**
-- Klik op X-knop โ panel verdwijnt
-- Trigger button verschijnt weer
-- Conversatie blijft behouden (sessie)
-
----
-
-### 4.3 Message List
-
-**Weergave van berichten:**
-
-| Type | Positie | Styling |
-|------|---------|---------|
-| Gebruiker | Rechts uitgelijnd | `bg-amber-100`, rounded |
-| Assistent | Links uitgelijnd | `bg-slate-100`, rounded |
-
-**Welkomstbericht (eerste bericht):**
-```
-Hallo! Ik ben de documentatie assistent voor het Mini-ECD.
-
-Stel gerust vragen over hoe het systeem werkt, bijvoorbeeld:
-โข Hoe maak ik een nieuwe intake aan?
-โข Hoe werkt de spraakherkenning?
-โข Waar vind ik de screening resultaten?
-```
-
-**Scroll gedrag:**
-- Automatisch scrollen naar nieuwste bericht
-- Gebruiker kan omhoog scrollen door historie
-- Bij nieuw bericht: scroll naar beneden
-
-**Streaming weergave:**
-- Tekst verschijnt woord-voor-woord
-- Pulserende cursor aan einde tijdens streaming
-- Cursor verdwijnt wanneer response compleet is
-
----
-
-### 4.4 Input Area
-
-**Componenten:**
-- Textarea (auto-resize, max 4 regels)
-- Verzend-knop (amber, pijl icon)
-
-**Interacties:**
-
-| Actie | Resultaat |
-|-------|-----------|
-| Enter | Verstuur bericht |
-| Shift + Enter | Nieuwe regel |
-| Klik verzend-knop | Verstuur bericht |
-| Leeg bericht versturen | Geen actie |
-
-**States:**
-
-| State | Textarea | Verzend-knop |
-|-------|----------|--------------|
-| Idle | Enabled, placeholder | Enabled (amber) |
-| Typing | Enabled, tekst zichtbaar | Enabled |
-| Loading | Disabled | Disabled (grijs) |
-| Error | Enabled | Enabled |
-
-**Placeholder tekst:** "Stel een vraag..."
-
----
-
-### 4.5 Streaming Response
-
-**Proces:**
-1. Gebruiker verstuurt vraag
-2. Input wordt disabled
-3. Nieuw assistent-bericht verschijnt (leeg)
-4. Tekst streamt woord-voor-woord in
-5. Bij completion: input wordt enabled
-
-**Visuele feedback tijdens streaming:**
-- Pulserende cursor (`โ`) aan einde van tekst
-- Tekst verschijnt met ~50ms interval per chunk
-
-**Timeout:**
-- Na 30 seconden zonder response: toon foutmelding
-- Gebruiker kan opnieuw proberen
-
----
-
-## 5. UI-overzicht (visuele structuur)
-
-### Widget Gesloten
-```
-โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
-โ โ
-โ EPD Interface โ
-โ โ
-โ โ
-โ โ
-โ โโโโโโโ โ
-โ โ โจ โ โ
-โ โโโโโโโ โ
-โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ
- Trigger Button
-```
-
-### Widget Open
-```
-โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
-โ โ
-โ EPD Interface โ
-โ โ
-โ โโโโโโโโโโโโโโโโโโโโโโโโโโค
-โ โ โจ Docs Assistent โ โ
-โ โโโโโโโโโโโโโโโโโโโโโโโโโโค
-โ โ Welkomstbericht... โ
-โ โ โ
-โ โ โโโโโโโโโโโโโโโโโโโโ โ
-โ โ โ Hoe maak ik... โโโโโโโ User
-โ โ โโโโโโโโโโโโโโโโโโโโ โ
-โ โ โ
-โ โ โโโโโโโโโโโโโโโโโโโโ โ
-โ โ โ Om een intake... โโโโโโโ Assistant
-โ โ โ ... โ โ
-โ โ โโโโโโโโโโโโโโโโโโโโ โ
-โ โโโโโโโโโโโโโโโโโโโโโโโโโโค
-โ โ [Stel een vraag...] โค โ
-โ โโโโโโโโโโโโโโโโโโโโโโโโโโ
-โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
-```
-
----
-
-## 6. Interacties met AI (functionele beschrijving)
-
-| Locatie | AI-actie | Trigger | Output |
-|---------|----------|---------|--------|
-| Chat widget | Vraag beantwoorden | Gebruiker verstuurt bericht | Streaming tekst-antwoord |
-| Chat widget | Vervolgvraag beantwoorden | Gebruiker stuurt vervolgvraag | Context-aware antwoord |
-| Chat widget | Buiten scope afhandelen | Vraag niet in documentatie | Eerlijk "weet ik niet" + suggesties |
-
-### AI Gedragsregels
-
-**Wel doen:**
-- Antwoorden baseren op de 14 MDX documentatiebestanden
-- Nederlands schrijven
-- Bullet points gebruiken voor stappen
-- Verwijzen naar specifieke menu's en knoppen
-- Eerlijk zeggen als informatie ontbreekt
-
-**Niet doen:**
-- Informatie verzinnen die niet in de documentatie staat
-- Medisch advies geven
-- Behandelsuggesties doen
-- Engels antwoorden (tenzij gevraagd)
-
-### Beschikbare Knowledge Base
-
-De assistent heeft toegang tot deze documentatie:
-
-| Bestand | Onderwerp |
-|---------|-----------|
-| `authentication.mdx` | Inloggen en authenticatie |
-| `client-management.mdx` | Cliรซntbeheer |
-| `intake-system.mdx` | Intake proces |
-| `screening-system.mdx` | Screening functionaliteit |
-| `treatment-planning.mdx` | Behandelplannen |
-| `interface-design.mdx` | UI uitleg |
-| `spraakgestuurde-verslaglegging.mdx` | Spraakfuncties (NL) |
-| `voice-controlled-reporting.mdx` | Spraakfuncties (EN) |
-| `verpleegkundige-overdracht.mdx` | Overdracht workflow |
-| `fhir-datamodel.mdx` | Data model |
-| `fhir-api.mdx` | API documentatie |
-| `release-notes-system.mdx` | Release notes |
-| `build-errors-fix.mdx` | Troubleshooting |
-| `webpack-module-resolution.mdx` | Technische docs |
-
----
-
-## 7. Gebruikersrollen en rechten
-
-| Rol | Toegang tot widget | Beperkingen |
-|-----|-------------------|-------------|
-| Behandelaar | Ja, binnen EPD | Geen |
-| Verpleegkundige | Ja, binnen EPD | Geen |
-| Admin | Ja, binnen EPD | Geen |
-| Niet-ingelogd | Nee | Widget niet zichtbaar |
-
-**Authenticatie:** Widget is alleen zichtbaar voor ingelogde gebruikers binnen `/epd/*` routes.
-
----
-
-## 8. Error States en Edge Cases
-
-### Error States
-
-| Situatie | Weergave | Gebruikersactie |
-|----------|----------|-----------------|
-| API timeout (>30s) | "Het duurt langer dan verwacht. Probeer het opnieuw." | Retry knop |
-| API error | "Er ging iets mis. Probeer het later opnieuw." | Retry knop |
-| Netwerk offline | "Geen internetverbinding." | - |
-| Rate limit | "Te veel verzoeken. Wacht even." | Automatisch retry |
-
-### Edge Cases
-
-| Situatie | Gedrag |
-|----------|--------|
-| Zeer lange vraag (>2000 chars) | Vraag wordt afgekapt met waarschuwing |
-| Lege vraag | Verzenden geblokkeerd |
-| Alleen spaties | Behandeld als lege vraag |
-| Snelle opeenvolgende vragen | Vorige request wordt geannuleerd |
-| Browser tab wisselen | Streaming gaat door |
-| Page refresh | Conversatie verloren (sessie-based) |
-
----
-
-## 9. Bijlagen & Referenties
-
-### Project Documentatie
-
-- PRD AI Documentatie Assistent (`prd-ai-docs-assistent-v1.md`)
-- PRD AI Pre-fill Behandelplan (`prd-ai-prefill-behandelplan-v1.md`)
-- UX Stylesheet (`ux-stylesheet.md`)
-- Technisch Ontwerp Mini-ECD (`to-mini-ecd-v1_2.md`)
-
-### Externe Referenties
-
-- [Claude API Documentation](https://docs.anthropic.com)
-- [Anthropic Streaming Guide](https://docs.anthropic.com/en/api/streaming)
-
----
-
-## Appendix A: Conversatie Voorbeelden
-
-### Voorbeeld 1: Intake Vraag
-
-**Gebruiker:** "Hoe maak ik een nieuwe intake aan?"
-
-**Assistent:**
-```
-Om een nieuwe intake aan te maken:
-
-1. Ga naar het cliรซntdossier via **Cliรซnten** in het hoofdmenu
-2. Selecteer de gewenste cliรซnt
-3. Klik op het tabblad **Intake**
-4. Klik op de knop **Nieuwe Intake**
-5. Vul de intake-informatie in het formulier
-6. Klik op **Opslaan** om de intake te bewaren
-
-Je kunt ook spraakherkenning gebruiken om de intake
-in te spreken via de microfoon-knop.
-```
-
-### Voorbeeld 2: Buiten Scope
-
-**Gebruiker:** "Wat is de beste behandeling voor depressie?"
-
-**Assistent:**
-```
-Die informatie heb ik niet. Ik kan alleen helpen met
-vragen over hoe het Mini-ECD systeem werkt.
-
-Misschien kan ik je helpen met:
-โข Hoe maak ik een behandelplan aan?
-โข Hoe voeg ik een diagnose toe?
-โข Hoe werkt de screening functie?
-```
-
-### Voorbeeld 3: Technische Vraag
-
-**Gebruiker:** "Welke FHIR resources worden ondersteund?"
-
-**Assistent:**
-```
-Het Mini-ECD ondersteunt de volgende FHIR R4 resources:
-
-**Kern resources:**
-โข Patient โ Cliรซntgegevens
-โข Practitioner โ Behandelaren
-โข Encounter โ Contactmomenten
-โข Condition โ Diagnoses/problemen
-โข Observation โ Metingen en observaties
-โข CarePlan โ Behandelplannen
-
-Zie de API documentatie voor endpoints en voorbeelden.
-```
-
----
-
-*Document gegenereerd als onderdeel van AI Speedrun โ Week 3*
diff --git a/docs/specs/ai-integratie/prd-ai-client-assistent-v1.md b/docs/specs/ai-integratie/prd-ai-client-assistent-v1.md
new file mode 100644
index 0000000..8cee4bc
--- /dev/null
+++ b/docs/specs/ai-integratie/prd-ai-client-assistent-v1.md
@@ -0,0 +1,205 @@
+# ๐ Product Requirements Document (PRD) โ AI Cliรซnt Assistent
+
+**Projectnaam:** Mini-ECD โ AI Cliรซnt Assistent
+**Versie:** v1.0
+**Datum:** 01-12-2025
+**Auteur:** Colin Lit
+
+---
+
+## 1. Doelstelling
+
+**Probleem:** Behandelaren besteden veel tijd aan het navigeren door verschillende schermen om informatie over een cliรซnt te verzamelen. Bij een overdracht of voorbereiding op een consult moeten zij:
+- Rapportages doorbladeren
+- Risico-assessments opzoeken
+- Behandeladviezen teruglezen
+- Screeningresultaten checken
+
+**Oplossing:** De bestaande AI Documentatie Assistent uitbreiden met cliรซnt-awareness. Wanneer een behandelaar in een cliรซntdossier zit, kan de assistent vragen beantwoorden over dรญe specifieke cliรซnt.
+
+**Voorbeeld interacties:**
+> "Geef een samenvatting van de laatste rapportages"
+> "Wat zijn de risico's van deze cliรซnt?"
+> "Wat staat er in het behandeladvies?"
+
+**Type:** MVP-uitbreiding op bestaande feature (AI Documentatie Assistent)
+
+---
+
+## 2. Doelgroep
+
+| Rol | Situatie | Behoefte |
+|-----|----------|----------|
+| **Behandelaar** | Voorbereiding op consult | Snel overzicht van recente rapportages en behandeladvies |
+| **Verpleegkundige** | Overdracht dienst | Risico's en actuele status checken |
+| **Intaker** | Afsluiten intake | Samenvatting van screeningresultaat en hulpvraag |
+| **Regiebehandelaar** | Caseload review | Per cliรซnt snel de status kunnen opvragen |
+
+**Kernbehoefte:** Informatie opvragen via natuurlijke taal, zonder te navigeren door meerdere schermen.
+
+---
+
+## 3. Kernfunctionaliteiten (MVP-scope)
+
+### 3.1 Automatische cliรซnt-herkenning
+De assistent weet automatisch over welke cliรซnt je praat op basis van het dossier waarin je zit. Geen handmatige selectie nodig.
+
+**Gedrag:**
+- In dossier van Jan de Vries โ assistent beantwoordt vragen over Jan de Vries
+- Buiten cliรซntdossier โ assistent beantwoordt alleen documentatie-vragen
+
+### 3.2 Cliรซnt-indicator in chat
+De gebruiker ziet duidelijk dat de assistent in "cliรซnt-modus" staat:
+
+```
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+โ โจ EPD Assistent โ
+โ ๐ Dossier: Jan de Vries โ โ Zichtbaar wanneer in dossier
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+```
+
+### 3.3 Ondersteunde vragen
+
+| Categorie | Voorbeeldvragen |
+|-----------|-----------------|
+| **Rapportages** | "Samenvatting van de rapportages", "Wat is er de laatste tijd genoteerd?" |
+| **Risico's** | "Wat zijn de risico's?", "Is er suรฏciderisico?" |
+| **Behandeladvies** | "Wat is het behandeladvies?", "Welke zorg is geadviseerd?" |
+| **Screening** | "Wat was de hulpvraag?", "Is de screening afgerond?" |
+| **Overzicht** | "Geef een samenvatting van dit dossier" |
+
+### 3.4 Context-aware suggesties
+Wanneer je in een cliรซntdossier zit, toont de assistent relevante voorbeeldvragen:
+- "Geef een samenvatting van de rapportages"
+- "Wat zijn de risico's?"
+- "Wat staat in het behandeladvies?"
+
+### 3.5 Gescheiden vraagtypen
+De assistent beantwoordt รณf vragen over de cliรซnt รณf vragen over het systeem, niet gemengd. Dit voorkomt verwarring.
+
+| Vraag | Type | Antwoord gebaseerd op |
+|-------|------|----------------------|
+| "Wat zijn de risico's?" | Cliรซnt | Dossiergegevens |
+| "Hoe maak ik een intake aan?" | Systeem | Documentatie |
+
+---
+
+## 4. Gebruikersflows
+
+### Flow 1: Snelle cliรซnt-check voor consult
+```
+Behandelaar opent dossier van cliรซnt
+ โ
+Ziet chat-widget rechtsonder, header toont "Dossier: Jan de Vries"
+ โ
+Klikt op suggestie "Wat zijn de risico's?"
+ โ
+Assistent toont overzicht: "Jan heeft 2 risico-assessments:
+โข Suรฏciderisico: laag (beoordeeld 15-11-2025)
+โข Agressierisico: middel (beoordeeld 10-11-2025)"
+```
+
+### Flow 2: Overdracht voorbereiding
+```
+Verpleegkundige opent dossier
+ โ
+Vraagt: "Geef een samenvatting van de laatste rapportages"
+ โ
+Assistent toont: "De laatste 3 rapportages:
+โข 28-11: Stabiele stemming, medicatie ongewijzigd
+โข 25-11: Gesprek over terugvalpreventie
+โข 22-11: Contactmoment familie, zorgen over isolatie"
+```
+
+### Flow 3: Documentatie-vraag vanuit dossier
+```
+Gebruiker is in dossier maar vraagt: "Hoe werkt de spraakherkenning?"
+ โ
+Systeem herkent: dit is een documentatie-vraag
+ โ
+Bestaande documentatie-flow wordt gevolgd
+ โ
+Antwoord komt uit systeemdocumentatie, niet uit cliรซntdossier
+```
+
+---
+
+## 5. Niet in Scope
+
+| Uitgesloten | Reden |
+|-------------|-------|
+| **Schrijven naar dossier** | Privacy, audit trail vereisten |
+| **Medisch advies geven** | Liability, AI mag niet adviseren |
+| **Multi-cliรซnt vergelijkingen** | Complexiteit, privacy |
+| **Historische trends** | "Hoe ging het vorige maand?" - te complex voor MVP |
+| **Bijlagen/PDF's lezen** | Technische complexiteit |
+| **Gemengde vragen** | "Hoe maak ik een intake voor deze cliรซnt?" - te ambigu |
+
+---
+
+## 6. Succescriteria
+
+| Criterium | Meetbaar doel |
+|-----------|---------------|
+| **Cliรซnt correct herkend** | 100% - als je in dossier zit, moet juiste cliรซnt actief zijn |
+| **Vraagtype correct** | >90% correcte classificatie (cliรซnt vs. documentatie) |
+| **Responstijd** | Eerste woord binnen 3 seconden |
+| **Data-integriteit** | Alleen data van actieve cliรซnt wordt getoond |
+| **Gebruikersacceptatie** | Positieve feedback in demo |
+
+---
+
+## 7. Risico's & Mitigatie
+
+| Risico | Impact | Kans | Mitigatie |
+|--------|--------|------|-----------|
+| **Verkeerde cliรซntdata tonen** | Kritiek | Laag | Cliรซnt-ID uit betrouwbare context (URL), niet uit vraag |
+| **AI hallucineert informatie** | Hoog | Middel | Strikte prompt: "alleen beschikbare data, zeg eerlijk als info ontbreekt" |
+| **Privacy-schending** | Kritiek | Laag | Bestaande autorisatie, RLS, geen logging van cliรซntdata |
+| **Ambigue vragen** | Middel | Middel | Duidelijke vraagtype-detectie, bij twijfel โ documentatie-modus |
+| **Te veel data in context** | Middel | Laag | Maximum 5 items per categorie laden |
+
+---
+
+## 8. Roadmap / Vervolg (Post-MVP)
+
+### Fase 2: Uitgebreidere context
+- Diagnoses en condities
+- Contactmomenten/encounters
+- Behandelplan doelen en voortgang
+- Medicatie-overzicht
+
+### Fase 3: Slimme acties
+- "Start een rapportage op basis van dit gesprek"
+- Suggesties voor behandelplan-updates
+- Pre-fill formulieren met AI
+
+### Fase 4: Caseload-niveau
+- "Welke cliรซnten hebben hoog risico?"
+- Overzicht van openstaande acties
+- Prioritering suggesties
+
+---
+
+## 9. Bijlagen & Referenties
+
+### Gerelateerde documenten
+| Document | Beschrijving |
+|----------|--------------|
+| `prd-ai-docs-assistent-v1.md` | PRD van basis documentatie assistent |
+| `fo-ai-docs-assistent-v1.md` | Functioneel ontwerp chat widget |
+| `bouwplan-ai-docs-assistent-v1.md` | Technisch implementatieplan v1 |
+
+### Beschikbare cliรซntdata (voor context)
+- **Rapportages** - Vrije notities en behandeladviezen
+- **Intakes** - Behandeladviezen, notities, status
+- **Risico-assessments** - Type, niveau, onderbouwing
+- **Screening** - Hulpvraag, beslissing
+
+---
+
+## Versiehistorie
+
+| Versie | Datum | Auteur | Wijziging |
+|--------|-------|--------|-----------|
+| v1.0 | 01-12-2025 | Colin Lit | Initiรซle versie |
diff --git a/docs/specs/ai-integratie/to-ai-client-assistent-v1.md b/docs/specs/ai-integratie/to-ai-client-assistent-v1.md
new file mode 100644
index 0000000..58ce5fa
--- /dev/null
+++ b/docs/specs/ai-integratie/to-ai-client-assistent-v1.md
@@ -0,0 +1,483 @@
+# โ๏ธ 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
+
+// lib/docs/client-prompt-builder.ts
+export function buildClientPrompt(
+ context: ClientContext,
+ question: string
+): string
+```
+
+---
+
+## 6. Security & Compliance
+
+### 6.1 Bestaande beveiliging (behouden)
+
+| Maatregel | Status | Implementatie |
+|-----------|--------|---------------|
+| **Authentication** | โ
| Supabase Auth, sessie vereist |
+| **RLS Policies** | โ
| Alle tabellen hebben RLS enabled |
+| **Rate Limiting** | โ
| 10 req/min per user (in-memory) |
+| **HTTPS** | โ
| Vercel enforced |
+
+### 6.2 Aanvullende maatregelen
+
+| Maatregel | Implementatie |
+|-----------|---------------|
+| **Client ID validatie** | UUID format check + bestaat in database |
+| **Context isolatie** | Alleen data van opgegeven clientId laden |
+| **Geen logging cliรซntdata** | AI responses niet loggen naar ai_events |
+| **Token limit** | Max 4000 tokens context om data-lekkage te beperken |
+
+### 6.3 Privacy overwegingen
+
+```typescript
+// NIET loggen naar ai_events bij cliรซnt-vragen
+if (questionType === 'client') {
+ // Skip ai_events insert - geen cliรซntdata in logs
+}
+
+// Wel loggen bij documentatie-vragen (bestaand gedrag)
+if (questionType === 'documentation') {
+ await logAiEvent({ kind: 'chat', request, response })
+}
+```
+
+---
+
+## 7. AI/LLM Integratie
+
+### 7.1 Vraagtype Detectie
+
+**Heuristiek voor detectie:**
+
+```typescript
+const CLIENT_KEYWORDS = [
+ 'rapportage', 'risico', 'behandeladvies', 'screening',
+ 'hulpvraag', 'samenvatting', 'dossier', 'deze cliรซnt',
+ 'zijn/haar', 'behandeling', 'medicatie', 'diagnose'
+]
+
+const DOC_KEYWORDS = [
+ 'hoe', 'waar', 'wat is', 'tutorial', 'handleiding',
+ 'functie', 'knop', 'menu', 'systeem', 'epd'
+]
+
+function detectQuestionType(question: string, hasClientContext: boolean): QuestionType {
+ if (!hasClientContext) return 'documentation'
+
+ const q = question.toLowerCase()
+ const clientScore = CLIENT_KEYWORDS.filter(k => q.includes(k)).length
+ const docScore = DOC_KEYWORDS.filter(k => q.includes(k)).length
+
+ if (clientScore > docScore) return 'client'
+ if (docScore > clientScore) return 'documentation'
+ return 'ambiguous' // Fallback naar documentation
+}
+```
+
+### 7.2 Client Prompt Template
+
+```typescript
+const CLIENT_SYSTEM_PROMPT = `Je bent een EPD-assistent die vragen beantwoordt over een specifieke cliรซnt.
+
+BELANGRIJKE REGELS:
+1. Beantwoord ALLEEN op basis van de gegeven context
+2. Als informatie ontbreekt, zeg dit eerlijk
+3. Geef NOOIT medisch advies of diagnoses
+4. Verzin NOOIT informatie die niet in de context staat
+5. Antwoord beknopt en professioneel
+
+CLIรNT: {patientName}
+GEBOORTEDATUM: {birthDate}
+STATUS: {status}
+
+RAPPORTAGES (laatste {reportCount}):
+{reportsFormatted}
+
+BEHANDELADVIES:
+{treatmentAdviceFormatted}
+
+SCREENING/HULPVRAAG:
+{screeningFormatted}
+
+RISICO-ASSESSMENTS:
+{riskAssessmentsFormatted}
+`
+```
+
+### 7.3 Fallback bij ambigue vragen
+
+Bij `questionType === 'ambiguous'`:
+- Default naar documentatie-modus
+- Toon hint: "Bedoelde je een vraag over de documentatie of over deze cliรซnt?"
+
+---
+
+## 8. Performance & Scalability
+
+### 8.1 Performance Targets
+
+| Metric | Target | Huidige baseline |
+|--------|--------|------------------|
+| Context laden | < 200ms | N.v.t. (nieuw) |
+| Vraagtype detectie | < 10ms | N.v.t. (nieuw) |
+| Eerste token | < 3 sec | ~2 sec (docs) |
+| Totale response | < 10 sec | ~5-8 sec (docs) |
+
+### 8.2 Optimalisaties
+
+```typescript
+// Parallel laden van context
+const [reports, intakes, screening, risks] = await Promise.all([
+ loadReports(clientId),
+ loadIntakes(clientId),
+ loadScreening(clientId),
+ loadRiskAssessments(clientId)
+])
+
+// Token budget management
+const MAX_CONTEXT_TOKENS = 4000
+const contextText = truncateToTokenLimit(
+ formatContext(reports, intakes, screening, risks),
+ MAX_CONTEXT_TOKENS
+)
+```
+
+### 8.3 Caching strategie
+
+| Data | Cache | TTL |
+|------|-------|-----|
+| Cliรซnt context | Geen | - |
+| Documentatie chunks | In-memory | Session |
+| Rate limit state | In-memory | 60 sec |
+
+**Geen caching van cliรซntdata** - altijd verse data uit database voor medische nauwkeurigheid.
+
+---
+
+## 9. Haalbaarheidsanalyse
+
+### 9.1 Technische haalbaarheid: โ
HOOG
+
+| Aspect | Beoordeling | Toelichting |
+|--------|-------------|-------------|
+| **Datamodel** | โ
Compleet | Alle benodigde tabellen bestaan en bevatten data |
+| **API structuur** | โ
Eenvoudig | Kleine uitbreiding op bestaande endpoint |
+| **Frontend** | โ
Minimaal | PatientContext bestaat al |
+| **AI integratie** | โ
Bewezen | Zelfde Claude API als documentatie-chat |
+
+### 9.2 Data beschikbaarheid
+
+| Categorie | PRD Requirement | Database Status |
+|-----------|-----------------|-----------------|
+| Rapportages | โ
| 21 rows, SOAP-format content |
+| Behandeladvies | โ
| JSONB in intakes.treatment_advice |
+| Risico's | โ ๏ธ | Tabel bestaat, 0 rows (seed data nodig) |
+| Screening | โ
| 5 rows, hulpvraag veld beschikbaar |
+
+### 9.3 Geschatte implementatietijd
+
+| Component | Schatting |
+|-----------|-----------|
+| `question-type-detector.ts` | 2 uur |
+| `client-context-loader.ts` | 3 uur |
+| `client-prompt-builder.ts` | 2 uur |
+| API route uitbreiding | 2 uur |
+| Frontend (indicator + suggestions) | 3 uur |
+| Testing & refinement | 4 uur |
+| **Totaal** | **~16 uur** |
+
+### 9.4 Risico's en mitigatie
+
+| Risico | Impact | Mitigatie |
+|--------|--------|-----------|
+| **Geen risk_assessments data** | Middel | Seed data toevoegen of feature uitstellen |
+| **Token overflow** | Laag | Truncatie met prioriteit (nieuwste eerst) |
+| **Hallucinatie** | Hoog | Strikte prompt + "ik weet het niet" response |
+| **Performance** | Laag | Parallel queries, geen joins |
+
+---
+
+## 10. Conclusie & Aanbeveling
+
+### Haalbaarheid: โ
JA
+
+De AI Cliรซnt Assistent is technisch haalbaar binnen de huidige architectuur:
+
+1. **Datamodel is compleet** - Alle benodigde tabellen bestaan met RLS
+2. **Geen nieuwe dependencies** - Bouwt voort op bestaande stack
+3. **Minimale frontend wijzigingen** - PatientContext hergebruiken
+4. **Bewezen AI integratie** - Zelfde Claude API als docs-chat
+
+### Aanbevolen aanpak
+
+1. **Fase 1:** Seed data voor risk_assessments (test coverage)
+2. **Fase 2:** Backend modules (detector, loader, prompt builder)
+3. **Fase 3:** API route uitbreiding
+4. **Fase 4:** Frontend indicator en dynamische suggestions
+5. **Fase 5:** Integratie testing met echte cliรซntdata
+
+---
+
+## 11. Bijlagen & Referenties
+
+### Projectdocumenten
+| Document | Locatie |
+|----------|---------|
+| PRD | `docs/specs/ai-integratie/prd-ai-client-assistent-v1.md` |
+| Bestaande docs-chat | `components/docs-chat/` |
+| API route | `app/api/docs/chat/route.ts` |
+| PatientContext | `contexts/patient-context.tsx` |
+
+### Database schema
+- Volledige schema via `mcp__supabase__list_tables`
+- RLS policies actief op alle tabellen
+
+---
+
+## Versiehistorie
+
+| Versie | Datum | Auteur | Wijziging |
+|--------|-------|--------|-----------|
+| v1.0 | 01-12-2025 | Colin Lit | Initiรซle versie met haalbaarheidsanalyse |
+| v1.1 | 01-12-2025 | Colin Lit | FHIR/REST API analyse toegevoegd, data access strategie onderbouwd |
diff --git a/lib/docs/client-context-loader.ts b/lib/docs/client-context-loader.ts
new file mode 100644
index 0000000..15e1684
--- /dev/null
+++ b/lib/docs/client-context-loader.ts
@@ -0,0 +1,263 @@
+/**
+ * Client Context Loader
+ *
+ * Loads client-specific data from Supabase for the AI Client Assistant.
+ * Uses direct database queries for performance (not HTTP APIs).
+ */
+
+import { supabaseAdmin } from '@/lib/supabase/server'
+import type { Database } from '@/lib/supabase/database.types'
+
+type Patient = Database['public']['Tables']['patients']['Row']
+type Report = Database['public']['Tables']['reports']['Row']
+type Intake = Database['public']['Tables']['intakes']['Row']
+type Screening = Database['public']['Tables']['screenings']['Row']
+type RiskAssessment = Database['public']['Tables']['risk_assessments']['Row']
+
+/**
+ * Simplified patient info for AI context
+ */
+export interface ClientPatient {
+ name: string
+ birthDate: string
+ status: string | null
+}
+
+/**
+ * Simplified report for AI context
+ */
+export interface ClientReport {
+ type: string
+ content: string
+ date: string
+}
+
+/**
+ * Simplified intake for AI context
+ */
+export interface ClientIntake {
+ title: string
+ department: string
+ status: string
+ treatmentAdvice: {
+ advice?: string
+ outcome?: string
+ program?: string
+ department?: string
+ } | null
+ notes: string | null
+}
+
+/**
+ * Simplified screening for AI context
+ */
+export interface ClientScreening {
+ requestForHelp: string | null
+ decision: string | null
+ decisionNotes: string | null
+}
+
+/**
+ * Simplified risk assessment for AI context
+ */
+export interface ClientRiskAssessment {
+ type: string
+ level: string
+ rationale: string
+ date: string
+}
+
+/**
+ * Complete client context for AI prompt
+ */
+export interface ClientContext {
+ patient: ClientPatient
+ reports: ClientReport[]
+ intakes: ClientIntake[]
+ screening: ClientScreening | null
+ riskAssessments: ClientRiskAssessment[]
+}
+
+/**
+ * Format patient name from database fields
+ */
+function formatPatientName(patient: Patient): string {
+ const givenNames = patient.name_given?.join(' ') || ''
+ const prefix = patient.name_prefix ? `${patient.name_prefix} ` : ''
+ return `${givenNames} ${prefix}${patient.name_family}`.trim()
+}
+
+/**
+ * Format date for display (Dutch format)
+ */
+function formatDate(dateString: string): string {
+ const date = new Date(dateString)
+ return date.toLocaleDateString('nl-NL', {
+ day: '2-digit',
+ month: '2-digit',
+ year: 'numeric',
+ })
+}
+
+/**
+ * Load patient basic info
+ */
+async function loadPatient(clientId: string): Promise {
+ const { data, error } = await supabaseAdmin
+ .from('patients')
+ .select('name_given, name_family, name_prefix, birth_date, status')
+ .eq('id', clientId)
+ .single()
+
+ if (error || !data) {
+ console.error('Error loading patient:', error)
+ return null
+ }
+
+ return {
+ name: formatPatientName(data as Patient),
+ birthDate: formatDate(data.birth_date),
+ status: data.status,
+ }
+}
+
+/**
+ * Load recent reports (max 5, newest first)
+ */
+async function loadReports(clientId: string): Promise {
+ const { data, error } = await supabaseAdmin
+ .from('reports')
+ .select('type, content, created_at')
+ .eq('patient_id', clientId)
+ .is('deleted_at', null)
+ .order('created_at', { ascending: false })
+ .limit(5)
+
+ if (error || !data) {
+ console.error('Error loading reports:', error)
+ return []
+ }
+
+ return data.map((report) => ({
+ type: report.type === 'behandeladvies' ? 'Behandeladvies' : 'Vrije notitie',
+ content: report.content,
+ date: formatDate(report.created_at!),
+ }))
+}
+
+/**
+ * Load recent intakes with treatment advice (max 3, newest first)
+ */
+async function loadIntakes(clientId: string): Promise {
+ const { data, error } = await supabaseAdmin
+ .from('intakes')
+ .select('title, department, status, treatment_advice, notes')
+ .eq('patient_id', clientId)
+ .order('created_at', { ascending: false })
+ .limit(3)
+
+ if (error || !data) {
+ console.error('Error loading intakes:', error)
+ return []
+ }
+
+ return data.map((intake) => ({
+ title: intake.title,
+ department: intake.department,
+ status: intake.status === 'afgerond' ? 'Afgerond' : 'Bezig',
+ treatmentAdvice: intake.treatment_advice as ClientIntake['treatmentAdvice'],
+ notes: intake.notes,
+ }))
+}
+
+/**
+ * Load most recent screening
+ */
+async function loadScreening(clientId: string): Promise {
+ const { data, error } = await supabaseAdmin
+ .from('screenings')
+ .select('request_for_help, decision, decision_notes')
+ .eq('patient_id', clientId)
+ .order('created_at', { ascending: false })
+ .limit(1)
+ .single()
+
+ if (error || !data) {
+ // No screening is a valid state, not an error
+ return null
+ }
+
+ return {
+ requestForHelp: data.request_for_help,
+ decision: data.decision === 'geschikt' ? 'Geschikt' : data.decision === 'niet_geschikt' ? 'Niet geschikt' : null,
+ decisionNotes: data.decision_notes,
+ }
+}
+
+/**
+ * Load risk assessments via intakes (max 5, newest first)
+ */
+async function loadRiskAssessments(clientId: string): Promise {
+ // First get intake IDs for this patient
+ const { data: intakes, error: intakesError } = await supabaseAdmin
+ .from('intakes')
+ .select('id')
+ .eq('patient_id', clientId)
+
+ if (intakesError || !intakes || intakes.length === 0) {
+ return []
+ }
+
+ const intakeIds = intakes.map((i) => i.id)
+
+ // Then get risk assessments for those intakes
+ const { data, error } = await supabaseAdmin
+ .from('risk_assessments')
+ .select('risk_type, risk_level, rationale, assessment_date')
+ .in('intake_id', intakeIds)
+ .order('assessment_date', { ascending: false })
+ .limit(5)
+
+ if (error || !data) {
+ console.error('Error loading risk assessments:', error)
+ return []
+ }
+
+ return data.map((ra) => ({
+ type: ra.risk_type,
+ level: ra.risk_level,
+ rationale: ra.rationale,
+ date: formatDate(ra.assessment_date),
+ }))
+}
+
+/**
+ * Load complete client context for AI assistant
+ * Loads all data in parallel for performance
+ *
+ * @param clientId - UUID of the patient
+ * @returns ClientContext or null if patient not found
+ */
+export async function loadClientContext(clientId: string): Promise {
+ // Load all data in parallel
+ const [patient, reports, intakes, screening, riskAssessments] = await Promise.all([
+ loadPatient(clientId),
+ loadReports(clientId),
+ loadIntakes(clientId),
+ loadScreening(clientId),
+ loadRiskAssessments(clientId),
+ ])
+
+ // Patient must exist
+ if (!patient) {
+ return null
+ }
+
+ return {
+ patient,
+ reports,
+ intakes,
+ screening,
+ riskAssessments,
+ }
+}
diff --git a/lib/docs/client-prompt-builder.ts b/lib/docs/client-prompt-builder.ts
new file mode 100644
index 0000000..9be36d6
--- /dev/null
+++ b/lib/docs/client-prompt-builder.ts
@@ -0,0 +1,170 @@
+/**
+ * Client Prompt Builder
+ *
+ * Builds the system prompt for client-specific questions.
+ * Includes patient context, reports, intakes, screenings, and risk assessments.
+ */
+
+import type { ClientContext } from './client-context-loader'
+
+/**
+ * Base system prompt for client questions
+ */
+const CLIENT_BASE_PROMPT = `Je bent een EPD-assistent die vragen beantwoordt over een specifieke cliรซnt in het Mini-ECD systeem.
+
+## Belangrijke regels
+1. Beantwoord ALLEEN op basis van de gegeven cliรซntgegevens hieronder
+2. Als informatie ontbreekt, zeg dit eerlijk (bijv. "Er zijn nog geen rapportages voor deze cliรซnt")
+3. Geef NOOIT medisch advies, diagnoses of behandelsuggesties
+4. Verzin NOOIT informatie die niet in de context staat
+5. Antwoord beknopt en professioneel
+
+## Jouw publiek
+Zorgprofessionals (behandelaars, verpleegkundigen) die het EPD gebruiken.
+
+## Stijl
+- Schrijf in het Nederlands
+- Wees beknopt maar volledig
+- Gebruik bullet points voor overzichten
+- Vermeld datums waar relevant`
+
+/**
+ * Format reports for prompt context
+ */
+function formatReports(reports: ClientContext['reports']): string {
+ if (reports.length === 0) {
+ return 'Geen rapportages beschikbaar.'
+ }
+
+ return reports
+ .map((report, index) => {
+ const truncatedContent =
+ report.content.length > 500 ? report.content.substring(0, 500) + '...' : report.content
+ return `${index + 1}. [${report.date}] ${report.type}\n${truncatedContent}`
+ })
+ .join('\n\n')
+}
+
+/**
+ * Format intakes for prompt context
+ */
+function formatIntakes(intakes: ClientContext['intakes']): string {
+ if (intakes.length === 0) {
+ return 'Geen intakes beschikbaar.'
+ }
+
+ return intakes
+ .map((intake, index) => {
+ let text = `${index + 1}. ${intake.title}\n`
+ text += ` - Afdeling: ${intake.department}\n`
+ text += ` - Status: ${intake.status}`
+
+ if (intake.treatmentAdvice) {
+ const ta = intake.treatmentAdvice
+ if (ta.advice) text += `\n - Advies: ${ta.advice.replace(/<[^>]*>/g, '')}`
+ if (ta.program) text += `\n - Programma: ${ta.program}`
+ if (ta.outcome) text += `\n - Uitkomst: ${ta.outcome}`
+ }
+
+ if (intake.notes) {
+ const truncatedNotes =
+ intake.notes.length > 200 ? intake.notes.substring(0, 200) + '...' : intake.notes
+ text += `\n - Notities: ${truncatedNotes}`
+ }
+
+ return text
+ })
+ .join('\n\n')
+}
+
+/**
+ * Format screening for prompt context
+ */
+function formatScreening(screening: ClientContext['screening']): string {
+ if (!screening) {
+ return 'Geen screening beschikbaar.'
+ }
+
+ let text = ''
+
+ if (screening.requestForHelp) {
+ text += `Hulpvraag: ${screening.requestForHelp}\n`
+ } else {
+ text += 'Hulpvraag: Niet ingevuld\n'
+ }
+
+ if (screening.decision) {
+ text += `Beslissing: ${screening.decision}`
+ if (screening.decisionNotes) {
+ text += ` - ${screening.decisionNotes}`
+ }
+ } else {
+ text += 'Beslissing: Nog niet genomen'
+ }
+
+ return text
+}
+
+/**
+ * Format risk assessments for prompt context
+ */
+function formatRiskAssessments(riskAssessments: ClientContext['riskAssessments']): string {
+ if (riskAssessments.length === 0) {
+ return 'Geen risico-assessments beschikbaar.'
+ }
+
+ return riskAssessments
+ .map((ra, index) => {
+ return `${index + 1}. ${ra.type} - Niveau: ${ra.level} (${ra.date})\n Onderbouwing: ${ra.rationale}`
+ })
+ .join('\n\n')
+}
+
+/**
+ * Build the complete system prompt with client context
+ *
+ * @param context - The loaded client context
+ * @returns The complete system prompt string
+ */
+export function buildClientPrompt(context: ClientContext): string {
+ const sections = [
+ CLIENT_BASE_PROMPT,
+ '---',
+ `## Cliรซnt: ${context.patient.name}`,
+ `Geboortedatum: ${context.patient.birthDate}`,
+ context.patient.status ? `Status: ${context.patient.status}` : '',
+ '',
+ '---',
+ '## Rapportages (laatste 5)',
+ formatReports(context.reports),
+ '',
+ '---',
+ '## Intakes & Behandeladvies',
+ formatIntakes(context.intakes),
+ '',
+ '---',
+ '## Screening / Hulpvraag',
+ formatScreening(context.screening),
+ '',
+ '---',
+ "## Risico-assessments",
+ formatRiskAssessments(context.riskAssessments),
+ '---',
+ ]
+
+ return sections.filter(Boolean).join('\n')
+}
+
+/**
+ * Build a fallback prompt when client context fails to load
+ */
+export function buildClientErrorPrompt(): string {
+ return `${CLIENT_BASE_PROMPT}
+
+---
+
+Er is een fout opgetreden bij het laden van de cliรซntgegevens.
+Vraag de gebruiker om de pagina te verversen of later opnieuw te proberen.
+
+---`
+}
diff --git a/lib/docs/question-type-detector.ts b/lib/docs/question-type-detector.ts
new file mode 100644
index 0000000..fd89544
--- /dev/null
+++ b/lib/docs/question-type-detector.ts
@@ -0,0 +1,154 @@
+/**
+ * Question Type Detector
+ *
+ * Detects whether a user question is about:
+ * - 'client': Questions about the active patient/client
+ * - 'documentation': Questions about how to use the EPD system
+ * - 'ambiguous': Unclear, defaults to documentation
+ */
+
+export type QuestionType = 'client' | 'documentation' | 'ambiguous'
+
+/**
+ * Keywords that indicate a client-related question
+ */
+const CLIENT_KEYWORDS = [
+ // Direct client references
+ 'rapportage',
+ 'rapportages',
+ 'rapportage',
+ 'notitie',
+ 'notities',
+ 'risico',
+ "risico's",
+ 'risicoassessment',
+ 'behandeladvies',
+ 'behandeladviezen',
+ 'screening',
+ 'hulpvraag',
+ 'samenvatting',
+ 'dossier',
+ 'deze cliรซnt',
+ 'deze client',
+ 'deze patiรซnt',
+ 'deze patient',
+ // Client data questions
+ 'wat staat er',
+ 'wat is er genoteerd',
+ 'laatste',
+ 'recente',
+ 'actuele',
+ 'huidige status',
+ 'zijn risico',
+ 'haar risico',
+ 'zijn behandeling',
+ 'haar behandeling',
+ // Actions on client data
+ 'geef een overzicht',
+ 'vat samen',
+ 'samenvatten',
+ 'wat weten we',
+]
+
+/**
+ * Keywords that indicate a documentation/system question
+ */
+const DOC_KEYWORDS = [
+ // How-to questions
+ 'hoe',
+ 'hoe maak ik',
+ 'hoe kan ik',
+ 'hoe werkt',
+ 'hoe doe ik',
+ // System references
+ 'waar',
+ 'waar vind ik',
+ 'waar kan ik',
+ 'wat is',
+ 'wat betekent',
+ 'wat doet',
+ // UI elements
+ 'knop',
+ 'menu',
+ 'scherm',
+ 'tab',
+ 'tabblad',
+ 'pagina',
+ 'formulier',
+ // Feature references
+ 'functie',
+ 'functionaliteit',
+ 'feature',
+ 'optie',
+ 'instelling',
+ // Documentation terms
+ 'tutorial',
+ 'handleiding',
+ 'uitleg',
+ 'instructie',
+ 'help',
+ // System references
+ 'systeem',
+ 'epd',
+ 'applicatie',
+ 'software',
+ 'spraakherkenning',
+ 'spraak',
+]
+
+/**
+ * Count keyword matches in a question
+ */
+function countKeywordMatches(question: string, keywords: string[]): number {
+ const lowerQuestion = question.toLowerCase()
+ return keywords.filter((keyword) => lowerQuestion.includes(keyword.toLowerCase())).length
+}
+
+/**
+ * Detect the type of question based on keywords and context
+ *
+ * @param question - The user's question
+ * @param hasClientContext - Whether a client is currently active
+ * @returns The detected question type
+ */
+export function detectQuestionType(question: string, hasClientContext: boolean): QuestionType {
+ // If no client context, always treat as documentation question
+ if (!hasClientContext) {
+ return 'documentation'
+ }
+
+ const clientScore = countKeywordMatches(question, CLIENT_KEYWORDS)
+ const docScore = countKeywordMatches(question, DOC_KEYWORDS)
+
+ // Clear winner
+ if (clientScore > docScore) {
+ return 'client'
+ }
+
+ if (docScore > clientScore) {
+ return 'documentation'
+ }
+
+ // Tie or no matches - check for implicit client references
+ const lowerQuestion = question.toLowerCase()
+
+ // Short questions in client context are often about the client
+ if (hasClientContext && question.length < 50) {
+ // Check for implicit client questions
+ const implicitClientPatterns = [
+ /^wat zijn/i,
+ /^wat is de/i,
+ /^geef/i,
+ /^toon/i,
+ /^overzicht/i,
+ /\?$/,
+ ]
+
+ if (implicitClientPatterns.some((pattern) => pattern.test(lowerQuestion))) {
+ return 'ambiguous' // Let the system handle ambiguity gracefully
+ }
+ }
+
+ // Default to documentation for safety
+ return 'ambiguous'
+}