chore: Opruimen oude documentatie
Verwijderd: - docs/specs/ (UI, agenda, ai-integratie, behandelplan, diagnose, overdracht, screening-intake, speech) - docs/troubleshooting/ - docs/performance/ - Losse docs (audit, migratie, seed data) Documentatie is verplaatst naar Google Drive of vervangen door Swift specs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,191 +0,0 @@
|
||||
# Technische Audit - Mini-EPD Prototype
|
||||
## Rapport voor Product Owner
|
||||
|
||||
**Datum:** December 2025
|
||||
**Doel:** Overzicht van technische staat en aandachtspunten
|
||||
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
Dit is een **prototype/experiment** om te demonstreren hoe ver je komt met AI-tooling in zorgsoftware ontwikkeling. Het systeem bevat **geen echte cliëntgegevens** - alleen testdata voor demonstratiedoeleinden.
|
||||
|
||||
**Doel van dit rapport:** Inzicht geven in de technische staat en wat nodig zou zijn als dit prototype ooit doorontwikkeld wordt naar productie.
|
||||
|
||||
---
|
||||
|
||||
## Samenvatting
|
||||
|
||||
| Gebied | Status | Relevantie voor Prototype | Bij Doorontwikkeling |
|
||||
|--------|--------|---------------------------|----------------------|
|
||||
| Beveiliging | Basis | Voldoende voor demo | Moet verbeterd worden |
|
||||
| Prestaties | Matig | Acceptabel voor demo | Optimalisatie nodig |
|
||||
| Onderhoud | Matig | Prima voor experiment | Refactoring wenselijk |
|
||||
| Schaalbaarheid | Beperkt | Niet relevant nu | Kritiek bij groei |
|
||||
|
||||
**Kernboodschap:** Voor een prototype dat AI-tooling demonstreert is de huidige staat prima. Dit rapport documenteert wat er nodig zou zijn voor eventuele doorontwikkeling.
|
||||
|
||||
---
|
||||
|
||||
## 1. Beveiliging
|
||||
|
||||
### Huidige staat (acceptabel voor prototype)
|
||||
|
||||
**Punt 1: Next.js versie**
|
||||
- De huidige versie heeft een bekende kwetsbaarheid
|
||||
- **Voor prototype:** Geen risico (geen echte data)
|
||||
- **Bij doorontwikkeling:** Update naar nieuwste versie nodig
|
||||
|
||||
**Punt 2: Gegevensscheiding**
|
||||
- Alle ingelogde gebruikers kunnen alle testdata zien
|
||||
- **Voor prototype:** Bewuste keuze voor eenvoud
|
||||
- **Bij doorontwikkeling:** Rollen en rechten per afdeling/organisatie
|
||||
|
||||
**Punt 3: Geen geautomatiseerde tests**
|
||||
- Typisch voor een prototype/experiment
|
||||
- **Voor prototype:** Acceptabel
|
||||
- **Bij doorontwikkeling:** Testsuite opzetten voor stabiliteit
|
||||
|
||||
### Bij doorontwikkeling nodig
|
||||
|
||||
| Actie | Inspanning | Wanneer |
|
||||
|-------|------------|---------|
|
||||
| Next.js updaten | 30 minuten | Voor productie |
|
||||
| Toegangsrechten implementeren | 1-2 dagen | Voor productie |
|
||||
| Testsuite opzetten | 2-3 dagen | Voor productie |
|
||||
|
||||
---
|
||||
|
||||
## 2. Prestaties
|
||||
|
||||
### Huidige staat (acceptabel voor prototype)
|
||||
|
||||
**Punt 1: Laden van grote hoeveelheden data**
|
||||
- Het systeem haalt alle gegevens in één keer op
|
||||
- **Voor prototype:** Prima met testdata
|
||||
- **Bij doorontwikkeling:** Pagination nodig bij veel records
|
||||
|
||||
**Punt 2: Sequentieel laden**
|
||||
- Pagina's laden gegevens één voor één (sequentieel)
|
||||
- **Voor prototype:** Merkbaar maar acceptabel
|
||||
- **Bij doorontwikkeling:** Parallel laden maakt 2-3x sneller
|
||||
|
||||
**Punt 3: Laad-feedback**
|
||||
- Geen loading indicators of foutmeldingen
|
||||
- **Voor prototype:** Werkt voor demo's
|
||||
- **Bij doorontwikkeling:** Professionelere UX wenselijk
|
||||
|
||||
### Bij doorontwikkeling nodig
|
||||
|
||||
| Actie | Inspanning | Effect |
|
||||
|-------|------------|--------|
|
||||
| Pagination toevoegen | 4 uur | Schaalbaarheid |
|
||||
| Parallel laden | 2 uur | 2-3x sneller |
|
||||
| Loading states | 4 uur | Betere UX |
|
||||
|
||||
---
|
||||
|
||||
## 3. Schaalbaarheid
|
||||
|
||||
### Huidige capaciteit (voldoende voor prototype)
|
||||
|
||||
| Scenario | Gedrag | Status |
|
||||
|----------|--------|--------|
|
||||
| <50 cliënten | Soepel | Prototype |
|
||||
| 50-200 cliënten | Acceptabel | Lichte optimalisatie |
|
||||
| >200 cliënten | Aanpassingen nodig | Productie-ready maken |
|
||||
|
||||
**Conclusie:** Voor een demo/experiment met testdata is de huidige capaciteit ruim voldoende.
|
||||
|
||||
### Bij doorontwikkeling nodig
|
||||
|
||||
Als het prototype ooit doorgroeit naar productie:
|
||||
- Database indexen toevoegen
|
||||
- Pagination in API's
|
||||
- Caching strategie
|
||||
|
||||
---
|
||||
|
||||
## 4. Onderhoudbaarheid
|
||||
|
||||
### Huidige staat (typisch voor prototype)
|
||||
|
||||
**Punt 1: Code duplicatie**
|
||||
- Sommige logica staat op meerdere plekken
|
||||
- **Voor prototype:** Normale trade-off voor snelheid van ontwikkeling
|
||||
- **Bij doorontwikkeling:** Centraliseren voor onderhoudbaarheid
|
||||
|
||||
**Punt 2: Codestructuur**
|
||||
- Business logica zit verspreid
|
||||
- **Voor prototype:** Acceptabel - snel itereren was prioriteit
|
||||
- **Bij doorontwikkeling:** Service-laag introduceren
|
||||
|
||||
**Punt 3: Foutafhandeling**
|
||||
- Niet overal consistent
|
||||
- **Voor prototype:** Werkt voor demo's
|
||||
- **Bij doorontwikkeling:** Standaardiseren
|
||||
|
||||
### Bij doorontwikkeling nodig
|
||||
|
||||
| Actie | Inspanning | Effect |
|
||||
|-------|------------|--------|
|
||||
| Code centraliseren | 4 uur | Minder duplicatie |
|
||||
| Foutafhandeling standaardiseren | 4 uur | Consistentie |
|
||||
| Service-laag | 2-3 dagen | Betere structuur |
|
||||
|
||||
---
|
||||
|
||||
## 5. Wat laat dit prototype zien?
|
||||
|
||||
### Succesvol gedemonstreerd met AI-tooling
|
||||
|
||||
Dit prototype toont aan wat mogelijk is met moderne AI-assisted development:
|
||||
|
||||
| Functionaliteit | Status | Opmerking |
|
||||
|-----------------|--------|-----------|
|
||||
| Volledige EPD basis | Werkend | Patiëntdossiers, rapportages, intakes |
|
||||
| AI-gestuurde samenvattingen | Werkend | Overdrachtsrapporten |
|
||||
| Spraak-naar-tekst | Werkend | Deepgram integratie |
|
||||
| Agenda & planning | Werkend | FullCalendar |
|
||||
| Behandelplannen | Werkend | SMART-doelen, interventies |
|
||||
| Nederlandse UI | Volledig | Alle teksten in het Nederlands |
|
||||
|
||||
### Technische stack
|
||||
|
||||
- **Frontend:** Next.js 14, React, Tailwind CSS
|
||||
- **Backend:** Supabase (PostgreSQL + Auth)
|
||||
- **AI:** Claude API, Deepgram
|
||||
- **Ontwikkeld met:** AI-tooling (Claude Code)
|
||||
|
||||
---
|
||||
|
||||
## 6. Roadmap bij doorontwikkeling
|
||||
|
||||
Mocht dit prototype doorontwikkeld worden naar productie, dan is dit de aanbevolen volgorde:
|
||||
|
||||
### Fase 1: Productie-ready maken
|
||||
1. Next.js updaten (30 min)
|
||||
2. Toegangsrechten implementeren (1-2 dagen)
|
||||
3. Basis testsuite (2-3 dagen)
|
||||
|
||||
### Fase 2: Schaalbaarheid
|
||||
4. Pagination in API's (4 uur)
|
||||
5. Loading states (4 uur)
|
||||
6. Database optimalisatie (1 dag)
|
||||
|
||||
### Fase 3: Professionalisering
|
||||
7. Code refactoring (2-3 dagen)
|
||||
8. Monitoring & logging (1 dag)
|
||||
9. CI/CD pipeline (1 dag)
|
||||
|
||||
---
|
||||
|
||||
## 7. Conclusie
|
||||
|
||||
Dit prototype demonstreert succesvol hoe ver je kunt komen met AI-tooling in zorgsoftware ontwikkeling. De technische staat is **passend voor een experiment** - functioneel, demonstreerbaar, maar niet productie-ready.
|
||||
|
||||
**Belangrijkste inzicht:** Met relatief beperkte investering kan dit prototype doorontwikkeld worden naar een productie-waardig systeem. De basis is solide.
|
||||
|
||||
---
|
||||
|
||||
*Dit rapport is gegenereerd op basis van een technische analyse van de codebase (december 2025).*
|
||||
@@ -1,655 +0,0 @@
|
||||
# 🚀 Migratieplan: `/clients/` → `/patients/` Route Consolidatie
|
||||
|
||||
**Datum:** 2025-11-22
|
||||
**Versie:** 1.0
|
||||
**Status:** ✅ Voltooid
|
||||
**Gekozen Strategie:** Custom API (Optie B)
|
||||
|
||||
---
|
||||
|
||||
## 📋 Executive Summary
|
||||
|
||||
**Doel:** Consolideer beide routes naar één FHIR-compliant `/patients/` route met Custom API voor Intakes.
|
||||
|
||||
**Inschatting:** 10-12 story points (2-3 werkdagen)
|
||||
**Risico Level:** Medium
|
||||
**Breaking Changes:** Ja (mitigated door redirects)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Fase 0 — Schema & Runbook
|
||||
|
||||
**Status:** ✅ Repo gealigneerd (feb 2026). Alle Supabase-migraties leven nu in `supabase/migrations/` en kunnen in één keer worden toegepast met de standaard CLI.
|
||||
|
||||
### Benodigde migraties
|
||||
- `20241115000001_create_leads_table.sql`
|
||||
- `20241115000002_create_epd_core_tables.sql`
|
||||
- `20241115000004_create_demo_users.sql`
|
||||
- `20241121_migrate_legacy_to_fhir.sql`
|
||||
- `20241121_seed_demo_data.sql`
|
||||
- `20251119094908_auth_hook_duplicate_email.sql`
|
||||
- `20251122_screening_intake_schema.sql`
|
||||
- `20251122_seed_default_organization.sql`
|
||||
|
||||
### Runbook
|
||||
1. Start Supabase lokaal (`supabase start`) of log in op de gewenste omgeving.
|
||||
2. Draai alle migraties: `supabase db reset --use-migrations` (dev) of `supabase db push` (staging/production). Hiermee wordt het schema gelijkgetrokken met `supabase/migrations/`.
|
||||
3. Seed basisdata: `pnpm ts-node scripts/seed-organization.ts` (voegt default organisatie + demo practitioners toe) en `pnpm ts-node scripts/apply-organization-seed.sh` indien nodig.
|
||||
4. Controleer dat er geen drifts zijn: `supabase db diff` mag geen output produceren.
|
||||
5. Smoke-test FHIR + Custom API:
|
||||
- `curl -s http://localhost:3000/api/fhir/Patient?_count=1`
|
||||
- `curl -s http://localhost:3000/api/intakes?patientId=<uuid>`
|
||||
6. Handmatige datafix (eenmalig): archiveer legacy `/clients/` records met `UPDATE clients SET archived=true` of verwijder de oude tabellen na validatie. Nieuwe dossiers worden uitsluitend via `patients` beheerd.
|
||||
7. Documenteer de uitvoering in release-notes (datum, operator, eventuele afwijkingen).
|
||||
|
||||
> Let op: RLS policies staan aan op alle nieuwe tabellen (`screenings`, `screening_activities`, `screening_documents`, `intakes`, enz.). Voer `supabase tests` of `supabase db lint` uit vlak na het toepassen om zeker te zijn dat policies geladen zijn.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Probleem Statement
|
||||
|
||||
Momenteel bestaan er twee parallelle implementaties voor patiënt/cliënt beheer:
|
||||
|
||||
1. **`/app/epd/clients/`** - Oudere implementatie (17-19 nov)
|
||||
- Directe Supabase queries
|
||||
- Bevat werkende Intake module (Epic 4)
|
||||
- Niet FHIR-compliant
|
||||
|
||||
2. **`/app/epd/patients/`** - Nieuwere implementatie (21-22 nov)
|
||||
- FHIR API compliant
|
||||
- Betere features (BSN validatie, filters, paginatie)
|
||||
- Intake nog placeholder
|
||||
|
||||
**Impact:**
|
||||
- Verwarring over canonical route
|
||||
- Code duplicatie
|
||||
- Inconsistente architectuur
|
||||
- Moeilijke maintenance
|
||||
|
||||
---
|
||||
|
||||
## 📊 Huidige Situatie Analyse
|
||||
|
||||
### `/clients/` Route Inventory
|
||||
|
||||
**✅ Volledig Geïmplementeerd:**
|
||||
|
||||
| Component | LOC | Functionaliteit |
|
||||
|-----------|-----|-----------------|
|
||||
| `intakes/components/intake-list.tsx` | 50 | Lijst van alle intakes per cliënt |
|
||||
| `intakes/components/intake-card.tsx` | 70 | Individuele intake kaart display |
|
||||
| `intakes/components/new-intake-form.tsx` | 137 | Formulier nieuwe intake (Zod validatie) |
|
||||
| `intakes/[intakeId]/components/intake-header.tsx` | 65 | Header met titel, status, datums |
|
||||
| `intakes/[intakeId]/components/intake-tabs.tsx` | 52 | Tab navigatie binnen intake |
|
||||
| `intakes/[intakeId]/page.tsx` | 52 | Intake detail algemene informatie |
|
||||
| `intakes/[intakeId]/layout.tsx` | 29 | Layout wrapper voor intake detail |
|
||||
| `intakes/actions.ts` | 83 | Server actions (CRUD operations) |
|
||||
|
||||
**Total:** ~538 LOC werkende functionaliteit
|
||||
|
||||
**Server Actions (Supabase-based):**
|
||||
```typescript
|
||||
export async function getIntakesByClientId(clientId: string)
|
||||
export async function createIntake(input: CreateIntakeInput)
|
||||
export async function getIntakeById(intakeId: string)
|
||||
```
|
||||
|
||||
**⏳ Placeholders (geen migratie nodig):**
|
||||
- Profile Tab ("Coming Soon Week 3")
|
||||
- Plan Tab ("Coming Soon Week 3")
|
||||
- Reports pagina
|
||||
- Diagnose pagina
|
||||
|
||||
**📦 Basis Functionaliteit (inferieur aan /patients/):**
|
||||
- Client list (geen status/gender filters, geen paginatie)
|
||||
- Client form (geen BSN validatie, geen John Doe)
|
||||
- Dashboard (basic, geen unique features)
|
||||
|
||||
### `/patients/` Route Inventory
|
||||
|
||||
**✅ Al Geïmplementeerd (Superieur):**
|
||||
- Patient list met advanced filtering
|
||||
- Patient form met BSN 11-proef validatie
|
||||
- John Doe support
|
||||
- Delete functionaliteit (two-step confirmation)
|
||||
- Modern layout (ClientHeader + ClientSidebar)
|
||||
- Dashboard met quick actions
|
||||
|
||||
**❌ Ontbreekt (te migreren van /clients/):**
|
||||
- Intake module (volledig)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Gekozen Architectuur: Custom API (Optie B)
|
||||
|
||||
### Waarom Custom API?
|
||||
|
||||
**✅ Voordelen:**
|
||||
- Snellere implementatie (1-2 dagen vs 3-4 dagen)
|
||||
- Eenvoudiger data model (direct mapping naar `intakes` tabel)
|
||||
- Minder transformatie logica nodig
|
||||
- Bestaande database schema hergebruiken
|
||||
- Type safety met TypeScript
|
||||
|
||||
**⚠️ Trade-offs:**
|
||||
- Niet FHIR Encounter-compliant (maar acceptabel voor MVP)
|
||||
- Toekomstige refactor naar FHIR mogelijk nodig
|
||||
- Aparte API naast FHIR Patient/Practitioner
|
||||
|
||||
**🔮 Toekomst Path:**
|
||||
- Behoud Custom API voor Intakes in MVP
|
||||
- Plan FHIR Encounter mapping in latere fase (Epic 5/6)
|
||||
- Incrementele migratie mogelijk zonder breaking changes
|
||||
|
||||
### API Specificatie
|
||||
|
||||
**Endpoint:** `/api/intakes`
|
||||
|
||||
**Routes:**
|
||||
```typescript
|
||||
GET /api/intakes?patientId={id} // List intakes for patient
|
||||
POST /api/intakes // Create new intake
|
||||
GET /api/intakes/{intakeId} // Get intake by ID
|
||||
PUT /api/intakes/{intakeId} // Update intake
|
||||
DELETE /api/intakes/{intakeId} // Delete intake
|
||||
```
|
||||
|
||||
**Request/Response Types:**
|
||||
```typescript
|
||||
interface Intake {
|
||||
id: string;
|
||||
patient_id: string;
|
||||
title: string;
|
||||
department: 'Volwassenen' | 'Jeugd' | 'Ouderen';
|
||||
status: 'Open' | 'Afgerond';
|
||||
start_date: string;
|
||||
end_date?: string;
|
||||
notes?: string;
|
||||
psychologist_id?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
interface CreateIntakeInput {
|
||||
patient_id: string;
|
||||
title: string;
|
||||
department: 'Volwassenen' | 'Jeugd' | 'Ouderen';
|
||||
start_date: string;
|
||||
}
|
||||
|
||||
interface IntakeListResponse {
|
||||
intakes: Intake[];
|
||||
total: number;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Gedetailleerd Migratieplan
|
||||
|
||||
### Fase 1: Intake API Ontwikkeling (3 SP)
|
||||
|
||||
**Doel:** Bouw Custom API voor Intake operaties
|
||||
|
||||
#### 1.1 API Route Setup (1 SP)
|
||||
|
||||
**Bestanden aan te maken:**
|
||||
```
|
||||
app/api/intakes/
|
||||
├── route.ts // GET (list), POST (create)
|
||||
└── [intakeId]/
|
||||
└── route.ts // GET, PUT, DELETE
|
||||
```
|
||||
|
||||
**Implementatie:**
|
||||
- Supabase client met RLS
|
||||
- Error handling
|
||||
- Input validatie (Zod schemas)
|
||||
- Response formatting
|
||||
|
||||
**Acceptatie Criteria:**
|
||||
- [x] GET `/api/intakes?patientId={id}` retourneert alle intakes
|
||||
- [x] POST `/api/intakes` creëert nieuwe intake
|
||||
- [x] GET `/api/intakes/{id}` retourneert specifieke intake
|
||||
- [x] PUT `/api/intakes/{id}` update intake
|
||||
- [x] DELETE `/api/intakes/{id}` verwijdert intake
|
||||
- [x] Alle endpoints hebben error handling
|
||||
- [x] Input validatie werkt
|
||||
|
||||
#### 1.2 Type Definitions (0.5 SP) ✅
|
||||
|
||||
**Bestand:** `lib/types/intake.ts`
|
||||
|
||||
**Inhoud:**
|
||||
- ✅ Intake interface
|
||||
- ✅ CreateIntakeInput, UpdateIntakeInput types
|
||||
- ✅ IntakeListResponse type
|
||||
- ✅ Zod validation schemas
|
||||
|
||||
#### 1.3 Server Actions Refactor (1.5 SP) ✅
|
||||
|
||||
**Bestand:** `app/epd/patients/[id]/intakes/actions.ts`
|
||||
|
||||
**Wijzigingen:**
|
||||
```typescript
|
||||
// VOOR (Supabase direct):
|
||||
const { data } = await supabase.from('intakes').select('*')
|
||||
|
||||
// NA (API call):
|
||||
const response = await fetch(`/api/intakes?patientId=${patientId}`)
|
||||
const data = await response.json()
|
||||
```
|
||||
|
||||
**Updates:**
|
||||
- ✅ `getIntakesByClientId` → `getIntakesByPatientId`
|
||||
- ✅ `createIntake` - gebruik POST `/api/intakes`
|
||||
- ✅ `getIntakeById` - gebruik GET `/api/intakes/{id}`
|
||||
- ✅ Cookies worden doorgegeven aan fetch calls
|
||||
- ✅ Error handling voor auth redirects
|
||||
|
||||
**Complexiteit:** Medium
|
||||
**Risico:** Laag
|
||||
|
||||
---
|
||||
|
||||
### Fase 2: Component Migratie (3 SP)
|
||||
|
||||
**Doel:** Verplaats alle Intake componenten naar `/patients/`
|
||||
|
||||
#### 2.1 Directory Structuur (0.5 SP) ✅
|
||||
|
||||
**Creëer structuur:**
|
||||
```
|
||||
app/epd/patients/[id]/intakes/
|
||||
├── components/
|
||||
│ ├── intake-card.tsx ✅
|
||||
│ ├── intake-list.tsx ✅
|
||||
│ └── new-intake-form.tsx ✅
|
||||
├── [intakeId]/
|
||||
│ ├── components/
|
||||
│ │ ├── intake-header.tsx ✅
|
||||
│ │ └── intake-tabs.tsx ✅
|
||||
│ ├── layout.tsx ✅
|
||||
│ └── page.tsx ✅
|
||||
├── new/
|
||||
│ └── page.tsx ✅
|
||||
└── actions.ts ✅
|
||||
```
|
||||
|
||||
#### 2.2 Kopieer en Pas Aan (2 SP) ✅
|
||||
|
||||
**Voor elk component:**
|
||||
1. ✅ Kopieer van `/clients/[id]/intakes/` naar `/patients/[id]/intakes/`
|
||||
2. ✅ Update imports:
|
||||
- `clientId` → `patientId` (props en variabelen)
|
||||
- `/epd/clients/` → `/epd/patients/` (routes)
|
||||
- Type imports naar `@/lib/types/intake`
|
||||
3. ✅ Update server action calls (gebruik nieuwe actions.ts)
|
||||
4. ✅ Import paden gecorrigeerd
|
||||
|
||||
**Specifieke wijzigingen:**
|
||||
|
||||
**intake-list.tsx:**
|
||||
- ✅ Props: `clientId` → `patientId`
|
||||
- ✅ Link urls: `/clients/` → `/patients/`
|
||||
|
||||
**new-intake-form.tsx:**
|
||||
- ✅ Form field: `patient_id` ipv `client_id`
|
||||
- ✅ Redirect: `/patients/` ipv `/clients/`
|
||||
|
||||
**intake-header.tsx:**
|
||||
- ✅ Breadcrumb: `/patients/` ipv `/clients/`
|
||||
- ✅ Type imports gecorrigeerd
|
||||
|
||||
**Complexiteit:** Laag (copy-paste + find/replace)
|
||||
**Risico:** Laag
|
||||
|
||||
#### 2.3 Verwijder Placeholder (0.5 SP) ✅
|
||||
|
||||
**Bestand:** `app/epd/patients/[id]/intake/page.tsx`
|
||||
|
||||
**Actie:** ✅ Verwijder placeholder, vervang door redirect:
|
||||
```typescript
|
||||
export default async function IntakeRedirect({ params }) {
|
||||
const { id } = await params;
|
||||
redirect(`/epd/patients/${id}/intakes`);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Fase 3: Navigatie Integratie (2 SP)
|
||||
|
||||
**Doel:** Integreer Intake tab in patient navigatie
|
||||
|
||||
#### 3.1 Update ClientSidebar (1 SP) ✅
|
||||
|
||||
**Bestand:** `app/epd/patients/[id]/components/client-sidebar.tsx`
|
||||
|
||||
**Wijzigingen:**
|
||||
- ✅ Maak "Intake" tab interactief (verwijder placeholder styling)
|
||||
- ✅ Link naar `/patients/{id}/intakes`
|
||||
- ✅ Active state logic voor subroutes
|
||||
- Optioneel: Badge met aantal openstaande intakes (nog niet geïmplementeerd)
|
||||
|
||||
#### 3.2 Update Dashboard (1 SP) ✅
|
||||
|
||||
**Bestand:** `app/epd/patients/[id]/page.tsx`
|
||||
|
||||
**Wijzigingen:**
|
||||
- ✅ Update "Volgende stappen" sectie
|
||||
- ✅ Verwijs naar intake functionaliteit
|
||||
- ✅ Intake quick action card linkt naar nieuwe route
|
||||
- ✅ Optioneel: Toon recent intake in dashboard (geïmplementeerd)
|
||||
|
||||
**Complexiteit:** Laag
|
||||
**Risico:** Laag
|
||||
|
||||
---
|
||||
|
||||
### Fase 4: Route Consolidatie (2 SP)
|
||||
|
||||
**Doel:** Deprecate `/clients/` en setup redirects
|
||||
|
||||
#### 4.1 Catch-all Redirect (1 SP) ✅
|
||||
|
||||
**Bestand:** `app/epd/clients/[...path]/route.ts` (nieuw)
|
||||
|
||||
**Implementatie:**
|
||||
```typescript
|
||||
import { redirect } from 'next/navigation';
|
||||
import { NextRequest } from 'next/server';
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ path: string[] }> }
|
||||
) {
|
||||
const { path } = await params;
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
const newPath = `/epd/patients/${path.join('/')}`;
|
||||
const newUrl = new URL(newPath, request.url);
|
||||
searchParams.forEach((value, key) => {
|
||||
newUrl.searchParams.set(key, value);
|
||||
});
|
||||
redirect(newUrl.toString());
|
||||
}
|
||||
```
|
||||
|
||||
**Test scenarios:**
|
||||
- ✅ `/epd/clients` → `/epd/patients` (via `page.tsx` redirect)
|
||||
- ✅ `/epd/clients/{id}` → `/epd/patients/{id}`
|
||||
- ✅ `/epd/clients/{id}/intakes` → `/epd/patients/{id}/intakes`
|
||||
- ✅ `/epd/clients/{id}/intakes/{intakeId}` → `/epd/patients/{id}/intakes/{intakeId}`
|
||||
- ✅ Query parameters worden behouden
|
||||
|
||||
#### 4.2 Archive Old Code (0.5 SP) ✅
|
||||
|
||||
**Acties:**
|
||||
- ✅ `mkdir -p app/epd/_archive`
|
||||
- ✅ `mv app/epd/clients app/epd/_archive/clients_backup_20251122`
|
||||
- ✅ Redirect routes teruggeplaatst in `app/epd/clients/`
|
||||
- ✅ Oude code volledig gearchiveerd
|
||||
|
||||
#### 4.3 Update Documentatie (0.5 SP) ✅
|
||||
|
||||
**Bestanden bij te werken:**
|
||||
- ✅ `docs/specs/UI/bouwplan-mini-epd-v1.0.md` - Update `/clients/` naar `/patients/`
|
||||
- ✅ `CHANGELOG.md` - Entry toegevoegd met breaking changes
|
||||
- ✅ `docs/migratie-clients-naar-patients.md` - Dit document bijgewerkt
|
||||
- `docs/bouwplan-mini-epd.md` - Nog te updaten indien aanwezig
|
||||
- `README.md` - Nog te updaten indien screenshots/links aanwezig
|
||||
|
||||
**Changelog:**
|
||||
- ✅ Entry toegevoegd aan `CHANGELOG.md` met breaking changes en mitigatie
|
||||
|
||||
**Complexiteit:** Laag
|
||||
**Risico:** Laag
|
||||
|
||||
---
|
||||
|
||||
### Fase 5: Testing & Validatie (2 SP)
|
||||
|
||||
**Doel:** Verifieer feature parity en stabiliteit
|
||||
|
||||
#### 5.1 Functionele Tests (1 SP)
|
||||
|
||||
**Test Checklist:**
|
||||
|
||||
**Intake List:**
|
||||
- [ ] Navigeer naar `/patients/{id}/intakes`
|
||||
- [ ] Lijst toont alle intakes voor patient
|
||||
- [ ] Empty state toont bij geen intakes
|
||||
- [ ] "Nieuwe intake" button werkt
|
||||
|
||||
**Nieuwe Intake:**
|
||||
- [ ] Formulier opent via "Nieuwe intake" button
|
||||
- [ ] Alle velden valideren correct
|
||||
- [ ] Submit creëert intake in database
|
||||
- [ ] Redirect naar intake lijst na succes
|
||||
- [ ] Intake verschijnt in lijst
|
||||
|
||||
**Intake Detail:**
|
||||
- [ ] Klik op intake card opent detail
|
||||
- [ ] Header toont correcte titel, status, datums
|
||||
- [ ] Tabs tonen (ook al zijn ze placeholder)
|
||||
- [ ] Algemene informatie tab toont data
|
||||
- [ ] Notities sectie werkt
|
||||
|
||||
**Navigatie:**
|
||||
- [ ] Sidebar "Intake" tab is actief
|
||||
- [ ] Breadcrumbs kloppen
|
||||
- [ ] Terug naar patiënten werkt
|
||||
|
||||
**Redirects:**
|
||||
- [ ] `/clients/{id}` → `/patients/{id}` werkt
|
||||
- [ ] `/clients/{id}/intakes` → `/patients/{id}/intakes` werkt
|
||||
- [ ] Query parameters behouden blijven
|
||||
|
||||
#### 5.2 API Tests (0.5 SP)
|
||||
|
||||
**Test alle endpoints:**
|
||||
```bash
|
||||
# List intakes
|
||||
curl http://localhost:3000/api/intakes?patientId={uuid}
|
||||
|
||||
# Create intake
|
||||
curl -X POST http://localhost:3000/api/intakes \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"patient_id":"uuid","title":"Test","department":"Volwassenen","start_date":"2025-11-22"}'
|
||||
|
||||
# Get intake
|
||||
curl http://localhost:3000/api/intakes/{intakeId}
|
||||
|
||||
# Update intake
|
||||
curl -X PUT http://localhost:3000/api/intakes/{intakeId} \
|
||||
-d '{"status":"Afgerond"}'
|
||||
|
||||
# Delete intake
|
||||
curl -X DELETE http://localhost:3000/api/intakes/{intakeId}
|
||||
```
|
||||
|
||||
**Verifieer:**
|
||||
- [ ] Response status codes correct (200, 201, 404, etc.)
|
||||
- [ ] Response bodies bevatten verwachte data
|
||||
- [ ] Errors worden netjes afgehandeld
|
||||
- [ ] RLS policies werken (unauthorized access blocked)
|
||||
|
||||
#### 5.3 Regressie Tests (0.5 SP)
|
||||
|
||||
**Verifieer bestaande functionaliteit:**
|
||||
- [ ] Patient list werkt nog
|
||||
- [ ] Patient create/update/delete werkt nog
|
||||
- [ ] Screening tab (placeholder) werkt nog
|
||||
- [ ] Andere tabs onveranderd
|
||||
|
||||
**Complexiteit:** Medium
|
||||
**Risico:** Medium
|
||||
|
||||
---
|
||||
|
||||
## 📈 Story Point Breakdown
|
||||
|
||||
| Fase | Taak | SP | Complexiteit | Risico |
|
||||
|------|------|------|--------------|--------|
|
||||
| 1.1 | API Route Setup | 1 | Medium | Laag |
|
||||
| 1.2 | Type Definitions | 0.5 | Laag | Laag |
|
||||
| 1.3 | Server Actions Refactor | 1.5 | Medium | Laag |
|
||||
| 2.1 | Directory Structuur | 0.5 | Laag | Laag |
|
||||
| 2.2 | Kopieer en Pas Aan | 2 | Laag | Laag |
|
||||
| 2.3 | Verwijder Placeholder | 0.5 | Laag | Laag |
|
||||
| 3.1 | Update ClientSidebar | 1 | Laag | Laag |
|
||||
| 3.2 | Update Dashboard | 1 | Laag | Laag |
|
||||
| 4.1 | Catch-all Redirect | 1 | Medium | Laag |
|
||||
| 4.2 | Archive Old Code | 0.5 | Laag | Laag |
|
||||
| 4.3 | Update Documentatie | 0.5 | Laag | Laag |
|
||||
| 5.1 | Functionele Tests | 1 | Medium | Medium |
|
||||
| 5.2 | API Tests | 0.5 | Medium | Medium |
|
||||
| 5.3 | Regressie Tests | 0.5 | Laag | Laag |
|
||||
| **TOTAAL** | | **12 SP** | **Laag-Medium** | **Laag-Medium** |
|
||||
|
||||
**Geschatte Tijdsduur:** 2-3 werkdagen (16-24 uur development tijd)
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Risico's en Mitigatie
|
||||
|
||||
| Risico | Impact | Waarschijnlijkheid | Mitigatie |
|
||||
|--------|--------|-------------------|-----------|
|
||||
| Breaking changes in productie | Hoog | Laag | Redirects + grondige testing |
|
||||
| Data inconsistentie (intakes) | Hoog | Laag | Gebruik dezelfde database tabel |
|
||||
| Gemiste edge cases | Medium | Medium | Uitgebreide test checklist |
|
||||
| Performance issues (API overhead) | Laag | Laag | Cache strategie, index optimization |
|
||||
| Type errors na migratie | Medium | Medium | TypeScript strict mode, thorough testing |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Acceptatie Criteria (Definition of Done)
|
||||
|
||||
**Functioneel:**
|
||||
- [x] Alle Intake functionaliteit werkt in `/patients/` route
|
||||
- [x] Feature parity met originele `/clients/` implementatie
|
||||
- [x] Redirects werken voor alle `/clients/` URLs
|
||||
- [x] Geen broken links in applicatie
|
||||
|
||||
**Technisch:**
|
||||
- [x] API endpoints geïmplementeerd en werkend
|
||||
- [x] Type definitions compleet (`lib/types/intake.ts`)
|
||||
- [x] Error handling geïmplementeerd (inclusief auth redirects)
|
||||
- [x] Cookies worden correct doorgegeven aan API calls
|
||||
- [ ] RLS policies getest (nog te valideren)
|
||||
|
||||
**Testing:**
|
||||
- [x] Basis functionele tests uitgevoerd (componenten werken)
|
||||
- [x] API tests uitgevoerd (endpoints werken)
|
||||
- [x] Import paden gecorrigeerd
|
||||
- [x] Geen TypeScript errors
|
||||
- [ ] Volledige regressie tests (nog te doen)
|
||||
|
||||
**Documentatie:**
|
||||
- [x] Bouwplannen bijgewerkt (`bouwplan-mini-epd-v1.0.md`)
|
||||
- [x] CHANGELOG.md entry toegevoegd
|
||||
- [x] API documentatie beschikbaar (`docs/api/intakes-api.md`)
|
||||
- [x] Migration guide voor developers (dit document)
|
||||
|
||||
**Cleanup:**
|
||||
- [x] Oude `/clients/` code gearchiveerd
|
||||
- [x] Geen duplicate code
|
||||
- [x] Import paden gecorrigeerd
|
||||
- [ ] Console warnings/errors check (nog te doen)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Implementatie Volgorde (Aanbevolen)
|
||||
|
||||
### Dag 1: API Foundation
|
||||
1. **Ochtend:** Fase 1.1 + 1.2 (API routes + types)
|
||||
2. **Middag:** Fase 1.3 (Server actions refactor)
|
||||
3. **Eind dag:** Fase 5.2 (API tests)
|
||||
|
||||
**Deliverable:** Werkende Intake API
|
||||
|
||||
### Dag 2: Component Migratie
|
||||
1. **Ochtend:** Fase 2.1 + 2.2 (Kopieer componenten)
|
||||
2. **Middag:** Fase 2.3 + 3.1 + 3.2 (Navigatie integratie)
|
||||
3. **Eind dag:** Fase 5.1 (Functionele tests)
|
||||
|
||||
**Deliverable:** Werkende Intake module in `/patients/`
|
||||
|
||||
### Dag 3: Consolidatie & Cleanup
|
||||
1. **Ochtend:** Fase 4.1 + 4.2 (Redirects + archive)
|
||||
2. **Middag:** Fase 4.3 (Documentatie)
|
||||
3. **Eind dag:** Fase 5.3 (Regressie tests)
|
||||
|
||||
**Deliverable:** Volledige migratie afgerond
|
||||
|
||||
---
|
||||
|
||||
## 📦 Deliverables Checklist
|
||||
|
||||
**Code:**
|
||||
- [x] `/app/api/intakes/` - API routes (GET, POST)
|
||||
- [x] `/app/api/intakes/[intakeId]/` - API routes (GET, PUT, DELETE)
|
||||
- [x] `/app/epd/patients/[id]/intakes/` - Volledige module
|
||||
- [x] `/app/epd/clients/[...path]/route.ts` - Redirect (catch-all)
|
||||
- [x] `/app/epd/clients/page.tsx` - Root redirect
|
||||
- [x] `/lib/types/intake.ts` - Type definitions
|
||||
|
||||
**Documentatie:**
|
||||
- [x] `docs/migratie-clients-naar-patients.md` - Dit document (bijgewerkt)
|
||||
- [x] `docs/api/intakes-api.md` - API documentatie
|
||||
- [x] Updated bouwplannen (`bouwplan-mini-epd-v1.0.md`)
|
||||
- [x] CHANGELOG.md entry
|
||||
|
||||
**Tests:**
|
||||
- [ ] Test rapport met resultaten
|
||||
- [ ] Screenshot van werkende features
|
||||
- [ ] Performance metrics (optioneel)
|
||||
|
||||
**Archief:**
|
||||
- [ ] `/app/epd/_archive/clients_backup_20251122/` - Oude code
|
||||
|
||||
---
|
||||
|
||||
## 🔮 Toekomstige Verbeteringen (Out of Scope)
|
||||
|
||||
**FHIR Compliance:**
|
||||
- Migreer Custom Intake API naar FHIR Encounter
|
||||
- Mapping van `intakes` tabel naar FHIR resources
|
||||
- Implementeer FHIR search parameters
|
||||
|
||||
**Features:**
|
||||
- Intake status workflow (bezig → afgerond met validaties)
|
||||
- Intake templates per afdeling
|
||||
- Notities met rich text editor
|
||||
- Document attachments per intake
|
||||
- Intake duplicatie/klonen
|
||||
- Bulk operations (meerdere intakes tegelijk)
|
||||
|
||||
**Performance:**
|
||||
- API response caching
|
||||
- Optimistic UI updates
|
||||
- Lazy loading van intake details
|
||||
- Pagination voor intake lists (bij >50 intakes)
|
||||
|
||||
**Analytics:**
|
||||
- Intake completion metrics
|
||||
- Average intake duration per afdeling
|
||||
- Psychologist workload dashboard
|
||||
|
||||
---
|
||||
|
||||
## 📞 Ondersteuning en Vragen
|
||||
|
||||
**Contact:**
|
||||
- Developer: Colin Lit
|
||||
- Email: colin@ikbenlit.nl
|
||||
|
||||
**Resources:**
|
||||
- Bouwplan Screening & Intake: `docs/specs/screening-intake/bouwplan-screening-intake-v1.0.md`
|
||||
- FHIR Bouwplan: `docs/bouwplan-pragmatisch-fhir.md`
|
||||
- Database Schema: `supabase/migrations/20251122_screening_intake_schema.sql`
|
||||
|
||||
---
|
||||
|
||||
**Versie Historie:**
|
||||
- v1.0 (2025-11-22): Initial migration plan met Custom API strategie
|
||||
@@ -1,243 +0,0 @@
|
||||
=== BASELINE PERFORMANCE METINGEN ===
|
||||
Datum: Fri Dec 12 14:14:19 CET 2025
|
||||
|
||||
## Server Response Times (TTFB)
|
||||
|
||||
### API Endpoints
|
||||
```
|
||||
GET /api/reports (patient d16935c9...):
|
||||
TTFB: 1.759250s, Total: 1.759686s, Size: 24 bytes
|
||||
GET /api/overdracht/patients:
|
||||
TTFB: 0.535994s, Total: 0.536342s, Size: 45 bytes
|
||||
```
|
||||
|
||||
## Bundle Analysis
|
||||
|
||||
### Grootste chunks in build:
|
||||
```
|
||||
-rw-r--r-- 1 colin colin 5.9M Dec 12 13:34 .next/static/chunks/main-app.js
|
||||
-rw-r--r-- 1 colin colin 2.7M Dec 12 13:34 .next/static/chunks/app/(marketing)/page.js
|
||||
-rw-r--r-- 1 colin colin 2.3M Dec 12 13:35 .next/static/chunks/app/epd/layout.js
|
||||
-rw-r--r-- 1 colin colin 919K Dec 12 13:34 .next/static/chunks/app/layout.js
|
||||
-rw-r--r-- 1 colin colin 649K Dec 12 13:34 .next/static/chunks/app/(marketing)/layout.js
|
||||
-rw-r--r-- 1 colin colin 502K Dec 12 13:35 .next/static/chunks/app/epd/patients/page.js
|
||||
-rw-r--r-- 1 colin colin 220K Dec 12 13:35 .next/static/chunks/app/epd/patients/[id]/page.js
|
||||
-rw-r--r-- 1 colin colin 220K Dec 12 13:34 .next/static/chunks/app/not-found.js
|
||||
-rw-r--r-- 1 colin colin 143K Dec 12 13:34 .next/static/chunks/app-pages-internals.js
|
||||
-rw-r--r-- 1 colin colin 132K Dec 12 13:35 .next/static/chunks/app/epd/patients/[id]/layout.js
|
||||
```
|
||||
|
||||
### Grootste dependencies:
|
||||
```
|
||||
24K node_modules/@fullcalendar
|
||||
16K node_modules/@tiptap
|
||||
0 node_modules/three
|
||||
```
|
||||
|
||||
## Samenvatting Baseline
|
||||
|
||||
### Kritieke Bevindingen
|
||||
|
||||
| Metric | Waarde | Beoordeling |
|
||||
|--------|--------|-------------|
|
||||
| main-app.js | 5.9 MB | ⚠️ Groot (dev mode) |
|
||||
| epd/layout.js | 2.3 MB | ⚠️ Groot |
|
||||
| patient/[id]/page.js | 220 KB | ✅ Acceptabel |
|
||||
| Reports API TTFB | 1.76s | ⚠️ Traag |
|
||||
| Overdracht API TTFB | 0.54s | ✅ Acceptabel |
|
||||
|
||||
### Opmerkingen
|
||||
|
||||
1. **Bundle sizes zijn development mode** - productie build zal kleiner zijn door minification
|
||||
2. **API TTFB van 1.76s** suggereert database query optimalisatie nodig
|
||||
3. **5.9MB main-app.js** bevat alle dependencies - tree shaking en code splitting kan dit verbeteren
|
||||
|
||||
### Aanbevolen optimalisaties
|
||||
|
||||
1. ✅ Parallel data fetching (Promise.all)
|
||||
2. ✅ Lazy loading van zware componenten (FullCalendar)
|
||||
3. ✅ Loading states voor betere perceived performance
|
||||
4. ⚡ Database query optimalisatie (indexes)
|
||||
|
||||
---
|
||||
|
||||
*Gemeten op: development server (localhost:3000)*
|
||||
*Let op: Lighthouse kon niet draaien in WSL - Chrome headless issues*
|
||||
|
||||
---
|
||||
|
||||
## Iteratie 1: Parallel Fetching
|
||||
|
||||
**Datum:** 12 dec 2025
|
||||
|
||||
### Wijziging
|
||||
|
||||
**Bestand:** `app/epd/patients/[id]/page.tsx`
|
||||
|
||||
**Voor:** 4 sequentiële fetches (elke fetch wacht op vorige)
|
||||
```typescript
|
||||
const intakes = await getIntakesByPatientId(id);
|
||||
const encounters = await getPatientEncounters(id);
|
||||
const carePlan = await getActiveCarePlan(id);
|
||||
const intakes = await getPatientIntakes(id); // DUBBEL!
|
||||
```
|
||||
|
||||
**Na:** 3 parallelle fetches met Promise.all
|
||||
```typescript
|
||||
const [intakes, encounters, carePlan] = await Promise.all([
|
||||
getIntakesByPatientId(id).catch(() => []),
|
||||
getPatientEncounters(id).catch(() => []),
|
||||
getActiveCarePlan(id).catch(() => null),
|
||||
]);
|
||||
```
|
||||
|
||||
### Verbeteringen
|
||||
|
||||
1. ✅ Verwijderd: dubbele `getPatientIntakes()` call
|
||||
2. ✅ Parallel fetching met Promise.all
|
||||
3. ✅ Graceful error handling met .catch()
|
||||
|
||||
### Verwachte impact
|
||||
|
||||
- **Theoretisch:** Van ~800ms sequentieel naar ~250ms parallel (3x sneller)
|
||||
- **Praktijk:** Test in browser nodig (curl geeft login redirect)
|
||||
|
||||
### Gemeten resultaat (browser test)
|
||||
|
||||
| Pagina | Voor (geschat) | Na | Verbetering |
|
||||
|--------|----------------|-----|-------------|
|
||||
| `/epd/patients/[id]` | ~800ms | **440ms** | ~45% sneller |
|
||||
|
||||
### Bevinding: Reports API bottleneck
|
||||
|
||||
De `/api/reports` endpoint is de echte bottleneck:
|
||||
- **1671ms** response time
|
||||
- Beïnvloedt `/epd/patients/[id]/rapportage` (2051ms totaal)
|
||||
- Dit is een database query probleem, niet parallel fetching
|
||||
|
||||
### Status
|
||||
|
||||
✅ Iteratie 1 voltooid - parallel fetching werkt
|
||||
|
||||
---
|
||||
|
||||
## Iteratie 2: Loading States
|
||||
|
||||
**Datum:** 12 dec 2025
|
||||
|
||||
### Toegevoegde bestanden
|
||||
|
||||
| Bestand | Doel |
|
||||
|---------|------|
|
||||
| `app/epd/loading.tsx` | Algemene EPD loading spinner |
|
||||
| `app/epd/patients/[id]/loading.tsx` | Patient dashboard skeleton |
|
||||
| `app/epd/agenda/loading.tsx` | Agenda skeleton |
|
||||
| `app/epd/patients/[id]/rapportage/loading.tsx` | Rapportage timeline skeleton |
|
||||
|
||||
### Wat dit doet
|
||||
|
||||
Next.js toont automatisch deze loading states terwijl Server Components laden:
|
||||
- Gebruiker ziet direct visuele feedback (skeleton/spinner)
|
||||
- Geen "blank screen" meer tijdens laden
|
||||
- Perceived performance verbetert significant
|
||||
|
||||
### Status
|
||||
|
||||
✅ Iteratie 2 voltooid - loading states toegevoegd
|
||||
|
||||
---
|
||||
|
||||
## Iteratie 3: Lazy Load FullCalendar
|
||||
|
||||
**Datum:** 12 dec 2025
|
||||
|
||||
### Wijziging
|
||||
|
||||
**Bestand:** `app/epd/agenda/components/agenda-view.tsx`
|
||||
|
||||
**Voor:**
|
||||
```typescript
|
||||
import { AgendaCalendar } from './agenda-calendar';
|
||||
```
|
||||
|
||||
**Na:**
|
||||
```typescript
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const AgendaCalendar = dynamic(
|
||||
() => import('./agenda-calendar').then((mod) => mod.AgendaCalendar),
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => <LoadingSpinner />,
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Wat dit doet
|
||||
|
||||
- FullCalendar en alle plugins worden nu **apart gebundeld**
|
||||
- Component laadt alleen wanneer agenda pagina bezocht wordt
|
||||
- Gebruiker ziet spinner tijdens laden van agenda
|
||||
- **Geschatte besparing:** ~150-200KB op initiële bundle
|
||||
|
||||
### Status
|
||||
|
||||
✅ Iteratie 3 voltooid - FullCalendar lazy loaded
|
||||
|
||||
---
|
||||
|
||||
## Samenvatting Optimalisaties
|
||||
|
||||
| Iteratie | Wijziging | Effect |
|
||||
|----------|-----------|--------|
|
||||
| 1 | Parallel Fetching | Patient dashboard: ~800ms → 440ms |
|
||||
| 2 | Loading States | Betere perceived performance |
|
||||
| 3 | Lazy Load FullCalendar | ~150KB minder initiële bundle |
|
||||
|
||||
### Resterende bottleneck
|
||||
|
||||
`/api/reports` endpoint: **1671ms** - geoptimaliseerd in Iteratie 4
|
||||
|
||||
---
|
||||
|
||||
## Iteratie 4: /api/reports Optimalisatie
|
||||
|
||||
**Datum:** 12 dec 2025
|
||||
|
||||
### Stap 4.1: Selectieve Kolommen
|
||||
|
||||
**Bestand:** `app/api/reports/route.ts`
|
||||
|
||||
Gewijzigd van `SELECT *` naar selectieve kolommen:
|
||||
- id, patient_id, type, content, created_at, updated_at, shift_date, include_in_handover, structured_data, created_by
|
||||
|
||||
**Verwacht effect:** -40% databandwidth
|
||||
|
||||
---
|
||||
|
||||
### Stap 4.2: Server-Side Pagination
|
||||
|
||||
**Bestanden:**
|
||||
- `app/api/reports/route.ts` - limit/offset parameters toegevoegd
|
||||
- `app/epd/patients/[id]/rapportage/actions.ts` - `getReportsPaginated()` functie
|
||||
|
||||
Response bevat nu: `{ reports, total, limit, offset, hasMore }`
|
||||
|
||||
**Verwacht effect:** -70% TTFB (alleen eerste 50 reports laden)
|
||||
|
||||
---
|
||||
|
||||
### Stap 4.3: Database Index
|
||||
|
||||
**Migratie:** `supabase/migrations/20251212_add_reports_timeline_index.sql`
|
||||
|
||||
```sql
|
||||
CREATE INDEX idx_reports_timeline ON reports(patient_id, created_at DESC) WHERE deleted_at IS NULL;
|
||||
CREATE INDEX idx_reports_patient_type ON reports(patient_id, type) WHERE deleted_at IS NULL;
|
||||
```
|
||||
|
||||
**Let op:** Voer deze migration handmatig uit in Supabase Dashboard of via CLI.
|
||||
|
||||
### Status
|
||||
|
||||
✅ Iteratie 4 volledig voltooid (incl. database indexes)
|
||||
@@ -1,464 +0,0 @@
|
||||
# Plan: Menu Performance Optimalisatie (<250ms response)
|
||||
|
||||
## Probleem
|
||||
|
||||
Trage menu-reacties bij:
|
||||
1. **EPD Sidebar** (hoofdnavigatie links)
|
||||
2. **Patient tabs** (binnen patiënt dossier)
|
||||
|
||||
Huidige performance: ~260ms, doel: <250ms
|
||||
|
||||
## Diagnose
|
||||
|
||||
### EPD Sidebar bottlenecks
|
||||
- Re-renders bij elke `usePathname()` change
|
||||
- `.map()` creëert nieuwe array (50+ items) per render
|
||||
- Geen `React.memo` bescherming
|
||||
- Regex match bij elke render
|
||||
|
||||
### Patient Tabs bottlenecks
|
||||
- Re-renders bij elke sub-route navigatie
|
||||
- Geen memoization van active state
|
||||
|
||||
### Context cascade
|
||||
- PatientContext reset bij unmount → flashing
|
||||
- Header herberekent derived state (40+ regels) per render
|
||||
|
||||
## Aanpak
|
||||
|
||||
**Fase 3 (Server Components) zou NIET helpen** - dit zijn client-side React performance issues.
|
||||
|
||||
### Quick wins (hoogste impact)
|
||||
|
||||
1. **EPD Sidebar optimalisatie** (~80ms besparing)
|
||||
2. **Patient Tabs memoization** (~40ms besparing)
|
||||
3. **Header derived state memoization** (~30ms besparing)
|
||||
4. **Context reset pattern verbeteren** (~20ms besparing)
|
||||
|
||||
Totaal: ~170ms besparing → target <90ms
|
||||
|
||||
---
|
||||
|
||||
## Implementatie
|
||||
|
||||
> **Status Update (26-11-2025):** Alle 4 stappen zijn geïmplementeerd en klaar voor testing.
|
||||
|
||||
### Stap 1: EPD Sidebar optimalisatie ✅ VOLTOOID
|
||||
|
||||
**Bestand:** `app/epd/components/epd-sidebar.tsx`
|
||||
|
||||
**Status:** Geïmplementeerd - alle optimalisaties toegepast
|
||||
|
||||
**Probleem:**
|
||||
```tsx
|
||||
const navigationItems = isPatientContext
|
||||
? level2NavigationItems.map(item => ({
|
||||
...item,
|
||||
href: `/epd/patients/${patientId}${item.href}`
|
||||
}))
|
||||
: level1NavigationItems;
|
||||
```
|
||||
|
||||
**Oplossing:**
|
||||
|
||||
1. Memoize navigation items:
|
||||
```tsx
|
||||
const navigationItems = useMemo(() => {
|
||||
if (isPatientContext) {
|
||||
return level2NavigationItems.map(item => ({
|
||||
...item,
|
||||
href: `/epd/patients/${patientId}${item.href}`
|
||||
}));
|
||||
}
|
||||
return level1NavigationItems;
|
||||
}, [isPatientContext, patientId]);
|
||||
```
|
||||
|
||||
2. Maak SidebarItem component met React.memo:
|
||||
```tsx
|
||||
const SidebarItem = memo(({ item, isActive, isCollapsed }: Props) => {
|
||||
return (
|
||||
<Link
|
||||
href={item.href}
|
||||
className={cn(...)}
|
||||
>
|
||||
<item.icon className="h-5 w-5" />
|
||||
{!isCollapsed && <span>{item.label}</span>}
|
||||
</Link>
|
||||
);
|
||||
}, (prev, next) => {
|
||||
// Shallow compare
|
||||
return prev.item.href === next.item.href &&
|
||||
prev.isActive === next.isActive &&
|
||||
prev.isCollapsed === next.isCollapsed;
|
||||
});
|
||||
```
|
||||
|
||||
3. Memoize isActive check:
|
||||
```tsx
|
||||
const getIsActive = useCallback((href: string) => {
|
||||
return pathname === href || pathname?.startsWith(`${href}/`);
|
||||
}, [pathname]);
|
||||
```
|
||||
|
||||
4. Stabilize event handlers:
|
||||
```tsx
|
||||
const handleToggle = useCallback(() => {
|
||||
setIsCollapsed(prev => !prev);
|
||||
}, []);
|
||||
|
||||
const handleMobileToggle = useCallback(() => {
|
||||
setIsOpen(prev => !prev);
|
||||
}, []);
|
||||
```
|
||||
|
||||
**Geïmplementeerde wijzigingen:**
|
||||
- ✅ Toegevoegd: `useMemo`, `useCallback`, `memo` imports
|
||||
- ✅ Nieuwe `SidebarItem` component met React.memo en custom comparison
|
||||
- ✅ navigationItems gememoized met useMemo
|
||||
- ✅ Event handlers gestabiliseerd met useCallback (toggleSidebar, toggleCollapse, handleItemClick)
|
||||
- ✅ getIsActive functie gememoized
|
||||
- ✅ Rendering vervangen door SidebarItem component
|
||||
|
||||
---
|
||||
|
||||
### Stap 2: Patient Tabs optimalisatie ✅ VOLTOOID
|
||||
|
||||
**Bestand:** `app/epd/patients/[id]/intakes/[intakeId]/components/intake-tabs.tsx`
|
||||
|
||||
**Status:** Geïmplementeerd - alle optimalisaties toegepast
|
||||
|
||||
**Probleem:**
|
||||
- Re-renders bij elke pathname change
|
||||
- Geen memoization
|
||||
|
||||
**Oplossing:**
|
||||
|
||||
1. Memoize tab items:
|
||||
```tsx
|
||||
const tabs = useMemo(() => [
|
||||
{ href: `/epd/patients/${patientId}/intakes/${intakeId}/anamnese`, label: 'Anamnese' },
|
||||
{ href: `/epd/patients/${patientId}/intakes/${intakeId}/diagnosis`, label: 'Diagnose' },
|
||||
// ... rest
|
||||
], [patientId, intakeId]);
|
||||
```
|
||||
|
||||
2. Maak TabItem component met memo:
|
||||
```tsx
|
||||
const TabItem = memo(({ tab, isActive }: { tab: Tab; isActive: boolean }) => {
|
||||
return (
|
||||
<Link
|
||||
href={tab.href}
|
||||
className={cn(
|
||||
'px-4 py-2 text-sm font-medium rounded-lg transition-colors',
|
||||
isActive ? 'bg-teal-100 text-teal-900' : 'text-slate-600 hover:text-slate-900'
|
||||
)}
|
||||
>
|
||||
{tab.label}
|
||||
</Link>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
3. Memoize active check:
|
||||
```tsx
|
||||
const isTabActive = useCallback((href: string) => {
|
||||
return pathname === href;
|
||||
}, [pathname]);
|
||||
```
|
||||
|
||||
**Geïmplementeerde wijzigingen:**
|
||||
- ✅ Toegevoegd: `useMemo`, `useCallback`, `memo` imports
|
||||
- ✅ Nieuwe `TabItem` component met React.memo
|
||||
- ✅ tabs array gememoized met useMemo
|
||||
- ✅ baseUrl gememoized
|
||||
- ✅ getIsActive functie gememoized met useCallback
|
||||
- ✅ Rendering vervangen door TabItem component
|
||||
|
||||
---
|
||||
|
||||
### Stap 3: EPD Header memoization ✅ VOLTOOID
|
||||
|
||||
**Bestand:** `app/epd/components/epd-header.tsx`
|
||||
|
||||
**Status:** Geïmplementeerd - component volledig geoptimaliseerd
|
||||
|
||||
**Probleem:**
|
||||
- 40+ regels berekeningen per render
|
||||
- Geen useMemo
|
||||
|
||||
**Oplossing:**
|
||||
|
||||
1. Memoize patient display data:
|
||||
```tsx
|
||||
const patientDisplay = useMemo(() => {
|
||||
if (!patient) return null;
|
||||
|
||||
const name = patient.name?.[0];
|
||||
const displayName = name
|
||||
? [...(name.prefix || []), ...(name.given || []), name.family]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
: 'Onbekende patiënt';
|
||||
|
||||
const birthDate = patient.birthDate
|
||||
? new Date(patient.birthDate).toLocaleDateString('nl-NL')
|
||||
: null;
|
||||
|
||||
const bsn = patient.identifier?.find(id =>
|
||||
id.system === 'http://fhir.nl/fhir/NamingSystem/bsn'
|
||||
)?.value;
|
||||
|
||||
const statusExtension = patient.extension?.find(ext =>
|
||||
ext.url === 'http://hl7.org/fhir/StructureDefinition/patient-status'
|
||||
);
|
||||
|
||||
const isJohnDoe = patient.extension?.some(ext =>
|
||||
ext.url === 'http://hl7.org/fhir/StructureDefinition/data-absent-reason' &&
|
||||
ext.valueCode === 'temp-unknown'
|
||||
);
|
||||
|
||||
return { displayName, birthDate, bsn, statusExtension, isJohnDoe };
|
||||
}, [patient]);
|
||||
```
|
||||
|
||||
2. Stabilize event handlers:
|
||||
```tsx
|
||||
const handleNewReportClick = useCallback(() => {
|
||||
if (!patient?.id) return;
|
||||
|
||||
const rapportagePath = `/epd/patients/${patient.id}/rapportage`;
|
||||
const onRapportagePage = pathname?.startsWith(rapportagePath);
|
||||
|
||||
if (onRapportagePage) {
|
||||
const element = document.getElementById('rapportage-composer');
|
||||
element?.scrollIntoView({ behavior: 'smooth' });
|
||||
} else {
|
||||
router.push(`${rapportagePath}#rapportage-composer`);
|
||||
}
|
||||
}, [patient?.id, pathname, router]);
|
||||
```
|
||||
|
||||
3. Wrap component in memo:
|
||||
```tsx
|
||||
export const EPDHeader = memo(function EPDHeader() {
|
||||
// ... component body
|
||||
});
|
||||
```
|
||||
|
||||
**Geïmplementeerde wijzigingen:**
|
||||
- ✅ Toegevoegd: `useMemo`, `useCallback`, `memo` imports
|
||||
- ✅ patientDisplay object gememoized met useMemo (alle 40+ regels berekeningen)
|
||||
- ✅ handleNewReportClick gestabiliseerd met useCallback
|
||||
- ✅ Component gewrapped in memo() export
|
||||
- ✅ Destructuring van gememoized values voor cleaner JSX
|
||||
|
||||
---
|
||||
|
||||
### Stap 4: PatientContext reset pattern ✅ VOLTOOID
|
||||
|
||||
**Bestand:** `app/epd/components/patient-context.tsx`
|
||||
|
||||
**Status:** Quick fix geïmplementeerd - geen flashing meer
|
||||
|
||||
**Probleem:**
|
||||
```tsx
|
||||
useEffect(() => {
|
||||
setPatient(patient);
|
||||
return () => setPatient(null); // ← Veroorzaakt flashing
|
||||
}, [patient, setPatient]);
|
||||
```
|
||||
|
||||
**Oplossing 1 (Quick fix):**
|
||||
|
||||
Verwijder cleanup als patient ID niet verandert:
|
||||
```tsx
|
||||
export function useSetPatient(patient: FHIRPatient | null) {
|
||||
const { patient: currentPatient, setPatient } = usePatientContext();
|
||||
|
||||
useEffect(() => {
|
||||
// Only update if patient ID changed
|
||||
if (patient?.id !== currentPatient?.id) {
|
||||
setPatient(patient);
|
||||
}
|
||||
}, [patient?.id, currentPatient?.id, setPatient]);
|
||||
|
||||
// No cleanup - keep patient in context during navigation
|
||||
}
|
||||
```
|
||||
|
||||
**Oplossing 2 (Beter, maar meer werk):**
|
||||
|
||||
Gebruik URL-based patient ID als single source of truth:
|
||||
```tsx
|
||||
export function PatientProvider({ children }: { children: ReactNode }) {
|
||||
const pathname = usePathname();
|
||||
const [patients, setPatients] = useState<Map<string, FHIRPatient>>(new Map());
|
||||
|
||||
// Extract patient ID from URL
|
||||
const patientId = useMemo(() => {
|
||||
const match = pathname?.match(/\/epd\/patients\/([^\/]+)/);
|
||||
return match?.[1] || null;
|
||||
}, [pathname]);
|
||||
|
||||
const currentPatient = patientId ? patients.get(patientId) : null;
|
||||
|
||||
const setPatient = useCallback((patient: FHIRPatient | null) => {
|
||||
if (patient?.id) {
|
||||
setPatients(prev => new Map(prev).set(patient.id, patient));
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PatientContext.Provider value={{ patient: currentPatient, setPatient }}>
|
||||
{children}
|
||||
</PatientContext.Provider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Aanbeveling:** Start met Oplossing 1 (quick fix), migreer later naar Oplossing 2.
|
||||
|
||||
**Geïmplementeerde oplossing:** Oplossing 1 (Quick fix)
|
||||
- ✅ Toegevoegd: ID comparison check voordat update
|
||||
- ✅ Verwijderd: cleanup functie die flashing veroorzaakte
|
||||
- ✅ Context blijft nu persistent tijdens navigatie
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
> **Status:** Klaar voor performance testing
|
||||
|
||||
### Performance meting
|
||||
|
||||
1. Chrome DevTools Performance profiler:
|
||||
```bash
|
||||
# Voor optimalisatie
|
||||
- Sidebar click: ~260ms
|
||||
- Tab switch: ~200ms
|
||||
|
||||
# Na optimalisatie
|
||||
- Sidebar click: <90ms (target: <250ms) ✓
|
||||
- Tab switch: <80ms (target: <250ms) ✓
|
||||
```
|
||||
|
||||
2. React DevTools Profiler:
|
||||
- Meet aantal re-renders per navigatie
|
||||
- Check "why did this render?"
|
||||
|
||||
### Functionele tests
|
||||
|
||||
1. **EPD Sidebar:**
|
||||
- [ ] Navigatie tussen Dashboard, Cliënten werkt
|
||||
- [ ] Context switch Level 1 → Level 2 werkt
|
||||
- [ ] Mobile hamburger menu werkt
|
||||
- [ ] Collapsed state persistent
|
||||
|
||||
2. **Patient Tabs:**
|
||||
- [ ] Alle tabs bereikbaar
|
||||
- [ ] Active state correct
|
||||
- [ ] Navigatie history werkt
|
||||
|
||||
3. **Header:**
|
||||
- [ ] Patient info toont correct
|
||||
- [ ] Nieuwe rapportage button werkt
|
||||
- [ ] Geen flashing bij navigatie
|
||||
|
||||
---
|
||||
|
||||
## Rollout
|
||||
|
||||
### ✅ Implementatie voltooid (26-11-2025)
|
||||
|
||||
Alle stappen zijn uitgevoerd in de aanbevolen volgorde:
|
||||
|
||||
1. ✅ **Stap 3** (Header memoization) - laag risico, medium impact
|
||||
2. ✅ **Stap 4** Quick fix (Context cleanup) - laag risico, medium impact
|
||||
3. ✅ **Stap 1** (Sidebar optimalisatie) - medium risico, high impact
|
||||
4. ✅ **Stap 2** (Tabs optimalisatie) - laag risico, medium impact
|
||||
|
||||
### Volgende stappen
|
||||
|
||||
1. **Performance testing** - Meet met Chrome DevTools
|
||||
2. **Functionele testing** - Verifieer alle features werken
|
||||
3. **Gebruikers feedback** - Test in praktijk (<250ms?)
|
||||
|
||||
### Originele planning
|
||||
|
||||
1. **Week 1:** Stap 3 (Header memoization) - laag risico, medium impact
|
||||
2. **Week 1:** Stap 4 Quick fix (Context cleanup) - laag risico, medium impact
|
||||
3. **Week 2:** Stap 1 (Sidebar optimalisatie) - medium risico, high impact
|
||||
4. **Week 2:** Stap 2 (Tabs optimalisatie) - laag risico, medium impact
|
||||
|
||||
### Rollback plan
|
||||
|
||||
Elke stap is onafhankelijk - bij issues een stap terugdraaien:
|
||||
```bash
|
||||
git revert <commit-hash>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Alternatieven overwogen
|
||||
|
||||
### Waarom NIET Fase 3 (Server Components)?
|
||||
|
||||
Server Components helpen bij:
|
||||
- Initial page load (minder JS)
|
||||
- Data fetching server-side
|
||||
|
||||
Maar NIET bij:
|
||||
- Client-side navigatie performance
|
||||
- React re-render optimalisatie
|
||||
- Menu click response time
|
||||
|
||||
→ Verkeerde tool voor dit probleem
|
||||
|
||||
### Waarom NIET React Query/SWR?
|
||||
|
||||
Zou helpen met:
|
||||
- API call caching
|
||||
- Stale-while-revalidate
|
||||
|
||||
Maar NIET met:
|
||||
- Re-render frequency (primaire probleem)
|
||||
- Component memoization
|
||||
|
||||
→ Overkill voor huidig probleem, kan later als Fase 3
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [ ] Menu click response <250ms (gemeten met Chrome DevTools) - **PENDING TEST**
|
||||
- [x] Geen visuele regressies (flashing, wrong active state) - **CODE REVIEW PASSED**
|
||||
- [x] Alle functionaliteit behouden - **CODE REVIEW PASSED**
|
||||
- [x] Geen breaking changes voor gebruikers - **CODE REVIEW PASSED**
|
||||
|
||||
## Files Modified ✅
|
||||
|
||||
**Alle bestanden succesvol geoptimaliseerd:**
|
||||
|
||||
## Files Modified (COMPLETED)
|
||||
|
||||
1. ✅ `app/epd/components/epd-sidebar.tsx` - Stap 1 (HIGH IMPACT)
|
||||
- Toegevoegd: SidebarItem component met React.memo
|
||||
- Gememoized: navigationItems, event handlers, isActive check
|
||||
- Impact: ~80ms besparing verwacht
|
||||
|
||||
2. ✅ `app/epd/patients/[id]/intakes/[intakeId]/components/intake-tabs.tsx` - Stap 2 (MEDIUM IMPACT)
|
||||
- Toegevoegd: TabItem component met React.memo
|
||||
- Gememoized: tabs array, baseUrl, isActive check
|
||||
- Impact: ~40ms besparing verwacht
|
||||
|
||||
3. ✅ `app/epd/components/epd-header.tsx` - Stap 3 (MEDIUM IMPACT)
|
||||
- Gememoized: patient display data (40+ regels)
|
||||
- Gestabiliseerd: event handlers
|
||||
- Wrapped in memo()
|
||||
- Impact: ~30ms besparing verwacht
|
||||
|
||||
4. ✅ `app/epd/components/patient-context.tsx` - Stap 4 (LOW IMPACT, CRITICAL FIX)
|
||||
- Fixed: context reset flashing
|
||||
- Verbeterd: ID comparison voor updates
|
||||
- Impact: ~20ms besparing + geen visuele glitches
|
||||
@@ -1,294 +0,0 @@
|
||||
# Reports Seed Data Documentatie
|
||||
|
||||
Deze documentatie beschrijft hoe je testdata voor rapportages kunt inladen om AI-samenvattingsfunctionaliteit te demonstreren.
|
||||
|
||||
## Overzicht
|
||||
|
||||
De seed data bevat **10 realistische rapportages** verdeeld over 3 patiënten:
|
||||
|
||||
### Patiënten & Rapportages
|
||||
|
||||
#### 1. Colin Lit - Depressie Behandeling (5 rapportages)
|
||||
- **Intake behandeladvies** - Uitgebreide intake met DSM classificatie, ROM scores en CGT behandelplan
|
||||
- **Sessie 2 notitie** - Voortgang gedragsactivatie
|
||||
- **Sessie 4 notitie** - Significante vooruitgang, PHQ-9 verbeterd
|
||||
- **Crisis interventie** - Tussentijds telefonisch contact
|
||||
- **Voortgangsrapportage** - Evaluatie na 8 sessies met ROM vergelijking
|
||||
|
||||
**Gebruik voor demonstratie:**
|
||||
- Timeline visualisatie van behandelverloop
|
||||
- ROM score tracking (PHQ-9: 14 → 6)
|
||||
- Behandeleffectiviteit analyse
|
||||
- Crisis moment herkenning
|
||||
|
||||
#### 2. Jan de Vriesh - Angststoornis (3 rapportages)
|
||||
- **Intake behandeladvies** - GAD diagnose met ACT behandelplan
|
||||
- **Sessie 3 notitie** - Mindfulness en acceptance technieken
|
||||
- **Sessie 6 notitie** - Uitgebreide relatiedynamiek analyse
|
||||
|
||||
**Gebruik voor demonstratie:**
|
||||
- ACT interventie tracking
|
||||
- Relationele problematiek identificatie
|
||||
- Emotionele doorbraken herkennen
|
||||
- Lange vorm notities samenvatten
|
||||
|
||||
#### 3. Optimus Prime - Diagnostiek (2 rapportages) 🤖
|
||||
- **Diagnostisch rapport** - Uitgebreid neuropsychologisch onderzoek met WAIS-IV scores
|
||||
- **Follow-up notitie** - Bespreking diagnostische bevindingen
|
||||
|
||||
**Gebruik voor demonstratie:**
|
||||
- Complexe diagnostiek samenvatten
|
||||
- Test resultaten extractie
|
||||
- Atypische presentaties herkennen
|
||||
- Easter egg functionaliteit 😊
|
||||
|
||||
## Installatie Methoden
|
||||
|
||||
### Methode 1: SQL Migratie (Aanbevolen voor development)
|
||||
|
||||
```bash
|
||||
# Voer de SQL migratie uit via Supabase CLI
|
||||
npx supabase db push
|
||||
|
||||
# Of direct via psql
|
||||
psql $DATABASE_URL -f supabase/migrations/20251124_seed_reports_data.sql
|
||||
```
|
||||
|
||||
**Voordelen:**
|
||||
- Snelste methode
|
||||
- Idempotent (ON CONFLICT DO NOTHING)
|
||||
- Onderdeel van migratie geschiedenis
|
||||
|
||||
### Methode 2: TypeScript Seed Script
|
||||
|
||||
```bash
|
||||
# Zorg dat environment variables zijn ingesteld
|
||||
export NEXT_PUBLIC_SUPABASE_URL="your-project-url"
|
||||
export SUPABASE_SERVICE_ROLE_KEY="your-service-role-key"
|
||||
|
||||
# Voer het seed script uit
|
||||
pnpm tsx scripts/seed-reports.ts
|
||||
```
|
||||
|
||||
**Voordelen:**
|
||||
- Meer flexibel voor aanpassingen
|
||||
- Betere error handling en feedback
|
||||
- Makkelijk uit te breiden met extra logica
|
||||
|
||||
## Data Structuur
|
||||
|
||||
### Report Types
|
||||
|
||||
```typescript
|
||||
type ReportType = 'behandeladvies' | 'vrije_notitie';
|
||||
```
|
||||
|
||||
- **behandeladvies**: Gestructureerde rapportages met diagnoses en behandelplannen
|
||||
- **vrije_notitie**: Vrije vorm sessie notities
|
||||
|
||||
### Structured Data Examples
|
||||
|
||||
#### Behandeladvies
|
||||
```json
|
||||
{
|
||||
"diagnosis_codes": ["F32.1", "F51.0"],
|
||||
"rom_scores": {
|
||||
"PHQ-9": 14,
|
||||
"GAD-7": 8
|
||||
},
|
||||
"treatment_plan": {
|
||||
"type": "CGT",
|
||||
"sessions": 12,
|
||||
"frequency": "wekelijks"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Sessie Notitie
|
||||
```json
|
||||
{
|
||||
"session_number": 4,
|
||||
"phq9_score": 9,
|
||||
"treatment_progress": "goed"
|
||||
}
|
||||
```
|
||||
|
||||
### AI Confidence Scores
|
||||
|
||||
Sommige rapportages bevatten AI confidence scores voor ML training:
|
||||
|
||||
```typescript
|
||||
{
|
||||
ai_confidence: 0.92, // 0.0 - 1.0
|
||||
ai_reasoning: "Clearly structured intake report with treatment advice section"
|
||||
}
|
||||
```
|
||||
|
||||
## Use Cases voor AI Demonstratie
|
||||
|
||||
### 1. Automatische Samenvatting
|
||||
```
|
||||
Input: Lange rapportage (1000+ woorden)
|
||||
Output: Beknopte samenvatting (200 woorden) met key points
|
||||
```
|
||||
|
||||
### 2. ROM Score Extractie
|
||||
```
|
||||
Input: Behandelverloop van Colin (5 rapportages)
|
||||
Output: PHQ-9 timeline: [14, -, 9, -, 6]
|
||||
Trend: Significante verbetering
|
||||
```
|
||||
|
||||
### 3. Behandelplan Identificatie
|
||||
```
|
||||
Input: Intake rapportages
|
||||
Output:
|
||||
- Colin: CGT, 12 sessies, wekelijks
|
||||
- Jan: ACT, 16 sessies, wekelijks
|
||||
- Optimus: Geen behandeling, consultatief
|
||||
```
|
||||
|
||||
### 4. Rapportage Classificatie
|
||||
```
|
||||
Input: Rapport content
|
||||
Output: Type: behandeladvies (confidence: 0.92)
|
||||
```
|
||||
|
||||
### 5. Crisis Moment Detectie
|
||||
```
|
||||
Input: Alle rapportages van patiënt
|
||||
Output: Crisis interventie gedetecteerd op 2024-10-28
|
||||
Severity: laag
|
||||
Actie: extra sessie gepland
|
||||
```
|
||||
|
||||
### 6. Thematische Analyse
|
||||
```
|
||||
Input: Jan's rapportages
|
||||
Output: Terugkerende thema's:
|
||||
- Piekeren / worry
|
||||
- Relatiedynamiek
|
||||
- Geruststelling zoeken
|
||||
- Mindfulness challenges
|
||||
```
|
||||
|
||||
## Query Voorbeelden
|
||||
|
||||
### Alle rapportages voor een patiënt
|
||||
```sql
|
||||
SELECT
|
||||
r.*,
|
||||
p.name_given || ' ' || p.name_family as patient_name,
|
||||
pr.name_given || ' ' || pr.name_family as practitioner_name
|
||||
FROM reports r
|
||||
JOIN patients p ON r.patient_id = p.id
|
||||
LEFT JOIN practitioners pr ON r.created_by = pr.id
|
||||
WHERE p.name_family = 'Lit' AND 'Colin' = ANY(p.name_given)
|
||||
ORDER BY r.created_at ASC;
|
||||
```
|
||||
|
||||
### ROM scores over tijd
|
||||
```sql
|
||||
SELECT
|
||||
created_at,
|
||||
structured_data->'rom_scores' as rom_scores,
|
||||
structured_data->'session_number' as session
|
||||
FROM reports
|
||||
WHERE patient_id = 'colin-lit-uuid'
|
||||
AND structured_data ? 'rom_scores'
|
||||
ORDER BY created_at;
|
||||
```
|
||||
|
||||
### Behandeladvies rapportages
|
||||
```sql
|
||||
SELECT
|
||||
p.name_family,
|
||||
r.content,
|
||||
r.structured_data->'treatment_plan' as treatment_plan,
|
||||
r.ai_confidence
|
||||
FROM reports r
|
||||
JOIN patients p ON r.patient_id = p.id
|
||||
WHERE r.type = 'behandeladvies'
|
||||
AND r.ai_confidence > 0.9
|
||||
ORDER BY r.created_at DESC;
|
||||
```
|
||||
|
||||
## Data Reset
|
||||
|
||||
Om de seed data opnieuw in te laden:
|
||||
|
||||
```sql
|
||||
-- Verwijder bestaande reports (soft delete)
|
||||
UPDATE reports
|
||||
SET deleted_at = NOW()
|
||||
WHERE created_at >= '2024-10-15'
|
||||
AND created_at <= '2024-11-22';
|
||||
|
||||
-- Of hard delete (wees voorzichtig!)
|
||||
DELETE FROM reports
|
||||
WHERE created_at >= '2024-10-15'
|
||||
AND created_at <= '2024-11-22';
|
||||
```
|
||||
|
||||
Dan kun je de seed scripts opnieuw uitvoeren.
|
||||
|
||||
## Uitbreidingen
|
||||
|
||||
### Meer rapportages toevoegen
|
||||
|
||||
Edit `scripts/seed-reports.ts` en voeg nieuwe entries toe aan `seedReportsData`:
|
||||
|
||||
```typescript
|
||||
{
|
||||
patient_family_name: 'Lit',
|
||||
patient_given_name: 'Colin',
|
||||
practitioner_index: 1,
|
||||
type: 'vrije_notitie',
|
||||
content: 'Nieuwe sessie notitie...',
|
||||
created_at: '2024-11-25T10:00:00Z',
|
||||
structured_data: {
|
||||
session_number: 9,
|
||||
// ... meer data
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Andere patiënten
|
||||
|
||||
Voeg eerst nieuwe patiënt toe aan de database, en gebruik dan dezelfde structuur in het seed script.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Patient not found" error
|
||||
- Controleer of de seed data voor patients is geladen
|
||||
- Verifieer de naam spelling (case-sensitive!)
|
||||
- Check of `name_given` een array is
|
||||
|
||||
### "Foreign key violation" error
|
||||
- Zorg dat practitioners zijn geladen (zie `20241121_seed_demo_data.sql`)
|
||||
- Verifieer dat de practitioner IDs kloppen
|
||||
|
||||
### Duplicate key errors
|
||||
- De SQL migratie gebruikt `ON CONFLICT DO NOTHING`
|
||||
- Het TypeScript script zal dubbele entries overslaan
|
||||
- Als je opnieuw wilt seeden, verwijder eerst de oude data
|
||||
|
||||
## Next Steps
|
||||
|
||||
Na het laden van seed data:
|
||||
|
||||
1. **Test de rapportage UI** - Ga naar `/epd/patients/[id]/rapportage`
|
||||
2. **Implementeer AI samenvatting** - Gebruik Claude API om rapportages samen te vatten
|
||||
3. **Bouw timeline visualisatie** - Toon chronologisch overzicht van behandeling
|
||||
4. **ROM tracking dashboard** - Visualiseer scores over tijd
|
||||
5. **Zoek functionaliteit** - Full-text search over rapportage content
|
||||
|
||||
## Contact & Support
|
||||
|
||||
Voor vragen over de seed data of uitbreidingen, zie de main project README of open een issue in het project.
|
||||
|
||||
---
|
||||
|
||||
**Created:** 2024-11-24
|
||||
**Last Updated:** 2024-11-24
|
||||
**Version:** 1.0
|
||||
@@ -1,282 +0,0 @@
|
||||
# Seed Data: Verpleegkundige Notities
|
||||
|
||||
Handmatig verpleegkundige notities toevoegen aan de database via SQL.
|
||||
|
||||
## Stap 1: Patient ID opzoeken
|
||||
|
||||
Zoek eerst de UUID van de patient:
|
||||
|
||||
```sql
|
||||
SELECT id, name_given, name_family
|
||||
FROM patients
|
||||
WHERE name_family ILIKE '%achternaam%'
|
||||
ORDER BY name_family;
|
||||
```
|
||||
|
||||
## Stap 2: Notities invoegen
|
||||
|
||||
### Beschikbare categorieën
|
||||
|
||||
| Categorie | Beschrijving |
|
||||
|-----------|--------------|
|
||||
| `medicatie` | Medicatie gerelateerde notities |
|
||||
| `adl` | ADL/verzorging (eten, wassen, etc.) |
|
||||
| `gedrag` | Gedragsobservaties |
|
||||
| `incident` | Incidenten en ongewenste gebeurtenissen |
|
||||
| `observatie` | Algemene observaties |
|
||||
|
||||
### SQL Template
|
||||
|
||||
Vervang `'PATIENT_UUID_HIER'` met de gevonden patient ID:
|
||||
|
||||
```sql
|
||||
-- Verpleegkundige notities voor een patient
|
||||
INSERT INTO reports (patient_id, type, content, structured_data, include_in_handover, shift_date, created_at)
|
||||
VALUES
|
||||
-- Medicatie notitie
|
||||
('PATIENT_UUID_HIER', 'verpleegkundig',
|
||||
'Medicatie uitgereikt om 08:00. Patient nam zonder problemen in.',
|
||||
'{"category": "medicatie"}', false, CURRENT_DATE, NOW()),
|
||||
|
||||
-- ADL notitie
|
||||
('PATIENT_UUID_HIER', 'verpleegkundig',
|
||||
'Geholpen met ochtendzorg. Zelfstandig tanden gepoetst.',
|
||||
'{"category": "adl"}', false, CURRENT_DATE, NOW()),
|
||||
|
||||
-- Gedragsobservatie
|
||||
('PATIENT_UUID_HIER', 'verpleegkundig',
|
||||
'Rustige ochtend. Patient las de krant in de huiskamer.',
|
||||
'{"category": "gedrag"}', false, CURRENT_DATE, NOW()),
|
||||
|
||||
-- Incident
|
||||
('PATIENT_UUID_HIER', 'verpleegkundig',
|
||||
'Licht gestruikeld bij opstaan uit stoel. Geen letsel. Valrisico besproken.',
|
||||
'{"category": "incident"}', true, CURRENT_DATE, NOW()),
|
||||
|
||||
-- Algemene observatie (voor overdracht)
|
||||
('PATIENT_UUID_HIER', 'verpleegkundig',
|
||||
'Sliep onrustig vannacht. Klaagt over hoofdpijn. Arts informeren.',
|
||||
'{"category": "observatie"}', true, CURRENT_DATE, NOW());
|
||||
```
|
||||
|
||||
### Met specifieke tijdstippen
|
||||
|
||||
```sql
|
||||
INSERT INTO reports (patient_id, type, content, structured_data, include_in_handover, shift_date, created_at)
|
||||
VALUES
|
||||
-- Nachtdienst (voor 07:00 = vorige dag shift_date)
|
||||
('PATIENT_UUID_HIER', 'verpleegkundig',
|
||||
'Twee keer wakker geworden. Om 03:00 toiletgang, om 05:30 onrustig.',
|
||||
'{"category": "observatie"}', true,
|
||||
CURRENT_DATE - INTERVAL '1 day', -- shift_date = gisteren
|
||||
CURRENT_DATE + TIME '05:30'), -- created_at = vandaag 05:30
|
||||
|
||||
-- Ochtend
|
||||
('PATIENT_UUID_HIER', 'verpleegkundig',
|
||||
'Ontbijt goed gegeten. Koffie met melk.',
|
||||
'{"category": "adl"}', false, CURRENT_DATE, CURRENT_DATE + TIME '08:30'),
|
||||
|
||||
-- Middag
|
||||
('PATIENT_UUID_HIER', 'verpleegkundig',
|
||||
'Bezoek van dochter. Positieve stemming.',
|
||||
'{"category": "gedrag"}', false, CURRENT_DATE, CURRENT_DATE + TIME '14:00'),
|
||||
|
||||
-- Avond
|
||||
('PATIENT_UUID_HIER', 'verpleegkundig',
|
||||
'Avondmedicatie gegeven. Slaapmedicatie om 21:00.',
|
||||
'{"category": "medicatie"}', true, CURRENT_DATE, CURRENT_DATE + TIME '21:00');
|
||||
```
|
||||
|
||||
## Velden uitleg
|
||||
|
||||
| Veld | Waarde | Toelichting |
|
||||
|------|--------|-------------|
|
||||
| `type` | `'verpleegkundig'` | Altijd deze waarde voor korte notities |
|
||||
| `content` | string (1-500 tekens) | De notitie tekst |
|
||||
| `structured_data` | `'{"category": "..."}'` | JSON met categorie |
|
||||
| `include_in_handover` | `true/false` | Tonen in overdracht |
|
||||
| `shift_date` | `CURRENT_DATE` | Dienstdatum (voor 07:00 = vorige dag) |
|
||||
| `created_at` | `NOW()` | Aanmaaktijd |
|
||||
|
||||
## Voorbeelddata per categorie
|
||||
|
||||
### Medicatie voorbeelden
|
||||
```sql
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Paracetamol 500mg gegeven om 10:00 i.v.m. hoofdpijn.', '{"category": "medicatie"}', false, CURRENT_DATE, NOW()),
|
||||
('PATIENT_UUID', 'verpleegkundig', 'PRN lorazepam geweigerd. Patient wilde eerst ontspanningsoefeningen proberen.', '{"category": "medicatie"}', true, CURRENT_DATE, NOW()),
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Insuline toegediend voor avondeten. BG: 8.2 mmol/L.', '{"category": "medicatie"}', false, CURRENT_DATE, NOW())
|
||||
```
|
||||
|
||||
### ADL voorbeelden
|
||||
```sql
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Volledig geholpen met douchen. Huid intact, geen bijzonderheden.', '{"category": "adl"}', false, CURRENT_DATE, NOW()),
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Lunch: halve boterham gegeten, 1 kopje soep. Eetlust matig.', '{"category": "adl"}', true, CURRENT_DATE, NOW()),
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Continentie: 1x incontinent voor urine. Verschoond.', '{"category": "adl"}', false, CURRENT_DATE, NOW())
|
||||
```
|
||||
|
||||
### Gedrag voorbeelden
|
||||
```sql
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Goede dag. Actief deelgenomen aan groepsactiviteit.', '{"category": "gedrag"}', false, CURRENT_DATE, NOW()),
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Teruggetrokken gedrag. Wil op kamer blijven. Gesprek aangeboden.', '{"category": "gedrag"}', true, CURRENT_DATE, NOW()),
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Conflict met medebewoner over TV. Situatie de-escaleerd door afleiding.', '{"category": "gedrag"}', true, CURRENT_DATE, NOW())
|
||||
```
|
||||
|
||||
### Incident voorbeelden
|
||||
```sql
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Val uit bed om 04:00. Geen zichtbaar letsel. Arts geinformeerd.', '{"category": "incident"}', true, CURRENT_DATE, NOW()),
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Agressief gedrag richting personeel. Time-out op kamer. Gesprek na 30 min.', '{"category": "incident"}', true, CURRENT_DATE, NOW()),
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Verslikking tijdens eten. Heimlich niet nodig, spontaan uitgekucht.', '{"category": "incident"}', true, CURRENT_DATE, NOW())
|
||||
```
|
||||
|
||||
### Observatie voorbeelden
|
||||
```sql
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Temperatuur 37.8. Licht verhoogd. Monitoren.', '{"category": "observatie"}', true, CURRENT_DATE, NOW()),
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Zuurstof saturatie stabiel: 96% op kamerlucht.', '{"category": "observatie"}', false, CURRENT_DATE, NOW()),
|
||||
('PATIENT_UUID', 'verpleegkundig', 'Nieuwe rode plek op stuit. Decubitus preventie protocol gestart.', '{"category": "observatie"}', true, CURRENT_DATE, NOW())
|
||||
```
|
||||
|
||||
## Alles verwijderen voor een patient
|
||||
|
||||
```sql
|
||||
-- Soft delete (aanbevolen)
|
||||
UPDATE reports
|
||||
SET deleted_at = NOW()
|
||||
WHERE patient_id = 'PATIENT_UUID'
|
||||
AND type = 'verpleegkundig';
|
||||
|
||||
-- Hard delete (definitief)
|
||||
DELETE FROM reports
|
||||
WHERE patient_id = 'PATIENT_UUID'
|
||||
AND type = 'verpleegkundig';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Kant-en-klare seed data (Colin Lit & Jan de Vriesh)
|
||||
|
||||
Kopieer onderstaande SQL en voer uit in Supabase SQL Editor.
|
||||
**Let op:** Vervang de UUIDs eerst met de juiste waarden uit je database.
|
||||
|
||||
```sql
|
||||
-- Seed data voor Colin Lit en Jan de Vriesh (afgelopen week)
|
||||
-- Kopieer en plak direct in Supabase SQL Editor
|
||||
|
||||
INSERT INTO reports (patient_id, type, content, structured_data, include_in_handover, shift_date, created_at)
|
||||
VALUES
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- COLIN LIT (f3fb1396-d326-450a-9f00-d60340f25deb)
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
-- Vandaag
|
||||
('f3fb1396-d326-450a-9f00-d60340f25deb', 'verpleegkundig',
|
||||
'Ochtendmedicatie uitgereikt. Inname zonder problemen.',
|
||||
'{"category": "medicatie"}', false, CURRENT_DATE, CURRENT_DATE + TIME '08:15'),
|
||||
|
||||
('f3fb1396-d326-450a-9f00-d60340f25deb', 'verpleegkundig',
|
||||
'Rustige ochtend. Zat in huiskamer te lezen.',
|
||||
'{"category": "gedrag"}', false, CURRENT_DATE, CURRENT_DATE + TIME '10:30'),
|
||||
|
||||
-- Gisteren
|
||||
('f3fb1396-d326-450a-9f00-d60340f25deb', 'verpleegkundig',
|
||||
'Geholpen met douchen. Huid intact, geen bijzonderheden.',
|
||||
'{"category": "adl"}', false, CURRENT_DATE - INTERVAL '1 day', CURRENT_DATE - INTERVAL '1 day' + TIME '09:00'),
|
||||
|
||||
('f3fb1396-d326-450a-9f00-d60340f25deb', 'verpleegkundig',
|
||||
'Klaagt over slecht slapen. Piekert veel. Gesprek aangeboden.',
|
||||
'{"category": "observatie"}', true, CURRENT_DATE - INTERVAL '1 day', CURRENT_DATE - INTERVAL '1 day' + TIME '14:30'),
|
||||
|
||||
('f3fb1396-d326-450a-9f00-d60340f25deb', 'verpleegkundig',
|
||||
'Avondmedicatie gegeven incl. slaapmedicatie.',
|
||||
'{"category": "medicatie"}', false, CURRENT_DATE - INTERVAL '1 day', CURRENT_DATE - INTERVAL '1 day' + TIME '21:00'),
|
||||
|
||||
-- 3 dagen geleden
|
||||
('f3fb1396-d326-450a-9f00-d60340f25deb', 'verpleegkundig',
|
||||
'Goede dag gehad. Deelgenomen aan groepsactiviteit.',
|
||||
'{"category": "gedrag"}', false, CURRENT_DATE - INTERVAL '3 days', CURRENT_DATE - INTERVAL '3 days' + TIME '16:00'),
|
||||
|
||||
('f3fb1396-d326-450a-9f00-d60340f25deb', 'verpleegkundig',
|
||||
'Lunch volledig opgegeten. Eetlust lijkt verbeterd.',
|
||||
'{"category": "adl"}', false, CURRENT_DATE - INTERVAL '3 days', CURRENT_DATE - INTERVAL '3 days' + TIME '12:30'),
|
||||
|
||||
-- 5 dagen geleden
|
||||
('f3fb1396-d326-450a-9f00-d60340f25deb', 'verpleegkundig',
|
||||
'Somber vanmorgen. Wilde niet uit bed komen. Na gesprek toch opgestaan.',
|
||||
'{"category": "gedrag"}', true, CURRENT_DATE - INTERVAL '5 days', CURRENT_DATE - INTERVAL '5 days' + TIME '09:30'),
|
||||
|
||||
('f3fb1396-d326-450a-9f00-d60340f25deb', 'verpleegkundig',
|
||||
'Paracetamol gegeven i.v.m. hoofdpijn.',
|
||||
'{"category": "medicatie"}', false, CURRENT_DATE - INTERVAL '5 days', CURRENT_DATE - INTERVAL '5 days' + TIME '11:00'),
|
||||
|
||||
-- 6 dagen geleden
|
||||
('f3fb1396-d326-450a-9f00-d60340f25deb', 'verpleegkundig',
|
||||
'Bezoek van partner gehad. Positief gesprek, stemming opgeklaard.',
|
||||
'{"category": "observatie"}', false, CURRENT_DATE - INTERVAL '6 days', CURRENT_DATE - INTERVAL '6 days' + TIME '15:00'),
|
||||
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- JAN DE VRIESH (d16935c9-e0fe-4972-832f-175b7a38f9b9)
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
-- Vandaag
|
||||
('d16935c9-e0fe-4972-832f-175b7a38f9b9', 'verpleegkundig',
|
||||
'Onrustige nacht. Meerdere keren wakker, piekeren over financien.',
|
||||
'{"category": "observatie"}', true, CURRENT_DATE, CURRENT_DATE + TIME '07:15'),
|
||||
|
||||
('d16935c9-e0fe-4972-832f-175b7a38f9b9', 'verpleegkundig',
|
||||
'PRN lorazepam aangeboden, geweigerd. Wil eerst ademhalingsoefeningen proberen.',
|
||||
'{"category": "medicatie"}', true, CURRENT_DATE, CURRENT_DATE + TIME '09:45'),
|
||||
|
||||
-- Gisteren
|
||||
('d16935c9-e0fe-4972-832f-175b7a38f9b9', 'verpleegkundig',
|
||||
'Teruggetrokken gedrag. Hele ochtend op kamer gebleven.',
|
||||
'{"category": "gedrag"}', true, CURRENT_DATE - INTERVAL '1 day', CURRENT_DATE - INTERVAL '1 day' + TIME '11:00'),
|
||||
|
||||
('d16935c9-e0fe-4972-832f-175b7a38f9b9', 'verpleegkundig',
|
||||
'Halve boterham lunch. Eetlust matig.',
|
||||
'{"category": "adl"}', false, CURRENT_DATE - INTERVAL '1 day', CURRENT_DATE - INTERVAL '1 day' + TIME '12:45'),
|
||||
|
||||
-- 2 dagen geleden
|
||||
('d16935c9-e0fe-4972-832f-175b7a38f9b9', 'verpleegkundig',
|
||||
'Gespannen tijdens groepstherapie. Eerder vertrokken.',
|
||||
'{"category": "gedrag"}', true, CURRENT_DATE - INTERVAL '2 days', CURRENT_DATE - INTERVAL '2 days' + TIME '10:30'),
|
||||
|
||||
('d16935c9-e0fe-4972-832f-175b7a38f9b9', 'verpleegkundig',
|
||||
'Avondmedicatie geweigerd, later alsnog ingenomen na gesprek.',
|
||||
'{"category": "medicatie"}', true, CURRENT_DATE - INTERVAL '2 days', CURRENT_DATE - INTERVAL '2 days' + TIME '21:30'),
|
||||
|
||||
-- 4 dagen geleden
|
||||
('d16935c9-e0fe-4972-832f-175b7a38f9b9', 'verpleegkundig',
|
||||
'Licht gestruikeld in gang. Geen letsel. Was duizelig, bloeddruk gecontroleerd: 118/72.',
|
||||
'{"category": "incident"}', true, CURRENT_DATE - INTERVAL '4 days', CURRENT_DATE - INTERVAL '4 days' + TIME '14:00'),
|
||||
|
||||
('d16935c9-e0fe-4972-832f-175b7a38f9b9', 'verpleegkundig',
|
||||
'Na incident rustiger. Middagdutje gedaan.',
|
||||
'{"category": "observatie"}', false, CURRENT_DATE - INTERVAL '4 days', CURRENT_DATE - INTERVAL '4 days' + TIME '16:30'),
|
||||
|
||||
-- 5 dagen geleden
|
||||
('d16935c9-e0fe-4972-832f-175b7a38f9b9', 'verpleegkundig',
|
||||
'Goede dag. Wandeling gemaakt op terrein met begeleiding.',
|
||||
'{"category": "gedrag"}', false, CURRENT_DATE - INTERVAL '5 days', CURRENT_DATE - INTERVAL '5 days' + TIME '11:00'),
|
||||
|
||||
('d16935c9-e0fe-4972-832f-175b7a38f9b9', 'verpleegkundig',
|
||||
'Zelfstandig gedoucht. Compliment gegeven voor zelfstandigheid.',
|
||||
'{"category": "adl"}', false, CURRENT_DATE - INTERVAL '5 days', CURRENT_DATE - INTERVAL '5 days' + TIME '08:30'),
|
||||
|
||||
-- 7 dagen geleden
|
||||
('d16935c9-e0fe-4972-832f-175b7a38f9b9', 'verpleegkundig',
|
||||
'Intake gesprek met nieuwe psychiater gehad. Medicatie wordt geevalueerd.',
|
||||
'{"category": "observatie"}', true, CURRENT_DATE - INTERVAL '7 days', CURRENT_DATE - INTERVAL '7 days' + TIME '10:00');
|
||||
```
|
||||
|
||||
### Snelle opschoning (indien nodig)
|
||||
|
||||
```sql
|
||||
-- Verwijder alle seed notities van afgelopen week
|
||||
UPDATE reports
|
||||
SET deleted_at = NOW()
|
||||
WHERE type = 'verpleegkundig'
|
||||
AND created_at >= CURRENT_DATE - INTERVAL '7 days';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Tip:** Voer SQL uit via Supabase Dashboard > SQL Editor of via `psql`.
|
||||
@@ -1,583 +0,0 @@
|
||||
# 🚀 Bouwplan — Mini EPD Prototype
|
||||
|
||||
**Projectnaam:** Mini EPD Prototype
|
||||
**Versie:** v1.0
|
||||
**Datum:** 19-11-2025
|
||||
**Auteur:** Development Team
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en Context
|
||||
|
||||
🎯 **Doel:** Een werkend MVP bouwen van een desktop EPD (Electronisch Patiënten Dossier) systeem voor de geestelijke gezondheidszorg met AI-ondersteuning.
|
||||
|
||||
**Context:**
|
||||
Het Mini EPD is een modern dossier systeem voor behandelaren in de GGZ. Het ondersteunt de volledige workflow van intake tot behandelplan met AI-assistentie voor:
|
||||
- Intake notities en samenvattingen
|
||||
- DSM-light diagnose classificatie
|
||||
- SMART behandelplan generatie
|
||||
|
||||
**Scope MVP:**
|
||||
- Desktop-only (min-width 1280px, optimized voor 1440-1920px)
|
||||
- Two-level navigation systeem (Behandelaar ↔ Client Dossier context)
|
||||
- 5 core database tables (clients, intake_notes, problem_profiles, treatment_plans, ai_events)
|
||||
- TipTap rich text editor voor notities
|
||||
- AI features: summarize, classify, generate plans
|
||||
|
||||
**Referenties:**
|
||||
- Interface Design: `docs/specs/UI/interface-design-plan.md`
|
||||
- User Flows: `docs/specs/UI/mocks-ui-flow.md`
|
||||
- Database Schema: `supabase/migrations/20241115000002_create_epd_core_tables.sql`
|
||||
|
||||
---
|
||||
|
||||
## 2. Uitgangspunten
|
||||
|
||||
### 2.1 Technische Stack
|
||||
|
||||
- **Frontend:** Next.js 15 + React 19 + TypeScript
|
||||
- **Styling:** Tailwind CSS v4
|
||||
- **UI Components:** Radix UI + shadcn/ui patterns
|
||||
- **Icons:** Lucide React
|
||||
- **Rich Text:** TipTap (ProseMirror)
|
||||
- **Database:** Supabase (PostgreSQL)
|
||||
- **Auth:** Supabase Auth (email/password + OAuth)
|
||||
- **AI/ML:** OpenAI API / Vertex AI (Gemini) - TBD
|
||||
- **Hosting:** Vercel
|
||||
- **State Management:** React Context + URL state
|
||||
|
||||
### 2.2 Projectkaders
|
||||
|
||||
- **Platform:** Desktop only (MVP), no mobile optimization
|
||||
- **Timeline:** Iteratief, focus op core workflows eerst
|
||||
- **Data:** Demo data, geen echte patiëntgegevens
|
||||
- **Team:** 1-2 developers
|
||||
- **Performance:** Target < 2s page load, < 5s AI responses
|
||||
|
||||
### 2.3 Programmeer Uitgangspunten
|
||||
|
||||
**Code Quality Principles:**
|
||||
|
||||
- **DRY:** Herbruikbare componenten (`/components/epd/`, `/lib/epd/`)
|
||||
- **SOC:**
|
||||
- UI components in `/app/epd/components/`
|
||||
- Business logic in `/lib/epd/`
|
||||
- Database queries in `/lib/supabase/queries/`
|
||||
- API routes in `/app/api/`
|
||||
- **KISS:** Geen premature abstraction, iteratief verfijnen
|
||||
- **YAGNI:** Alleen Week 1-2 features, AI features in Week 3
|
||||
|
||||
**Development Practices:**
|
||||
|
||||
- **Error Handling:** Try-catch op alle async ops, user-friendly messages
|
||||
- **Security:**
|
||||
- RLS policies op alle tables
|
||||
- API keys in environment variables
|
||||
- Input validation op alle forms
|
||||
- **Performance:**
|
||||
- Server Components waar mogelijk
|
||||
- Client Components alleen voor interactiviteit
|
||||
- Lazy loading voor AI features
|
||||
- Debounce op search (300ms)
|
||||
- **Accessibility:**
|
||||
- WCAG AA compliance
|
||||
- Keyboard navigation (Tab, Enter, Escape)
|
||||
- ARIA labels op alle interactive elements
|
||||
- Focus states visible
|
||||
|
||||
---
|
||||
|
||||
## 3. Epics & Stories Overzicht
|
||||
|
||||
| Epic ID | Titel | Doel | Status | Stories | Opmerkingen |
|
||||
|---------|-------|------|--------|---------|-------------|
|
||||
| E0 | Setup & Configuratie | Repo, database, auth werkend | ✅ | 3 | Grotendeels klaar |
|
||||
| E1 | Layout & Navigation | Two-level context systeem | 🔄 | 4 | In progress |
|
||||
| E2 | Cliënten Management | CRUD clients, search/filter | ⏳ | 5 | Week 1-2 |
|
||||
| E3 | Intake Systeem | TipTap editor, CRUD notes | ⏳ | 6 | Week 1-2 |
|
||||
| E4 | Diagnose & Probleemprofiel | DSM-light categories, manual entry | ⏳ | 4 | Week 2 |
|
||||
| E5 | Behandelplan | SMART goals, interventions, versioning | ⏳ | 5 | Week 2-3 |
|
||||
| E6 | AI Integration | Summarize, classify, generate (Week 3) | ⏳ | 4 | Week 3 |
|
||||
| E7 | Testing & Polish | QA, accessibility, performance | ⏳ | 3 | Ongoing |
|
||||
|
||||
---
|
||||
|
||||
## 4. Epics & Stories (Uitwerking)
|
||||
|
||||
### Epic 0 — Setup & Configuratie
|
||||
|
||||
**Status:** ✅ Grotendeels gereed
|
||||
|
||||
| Story ID | Beschrijving | AC | Status | Points |
|
||||
|----------|--------------|-----|--------|--------|
|
||||
| E0.S1 | Repository + Next.js 15 setup | App draait lokaal op :3000 | ✅ | 2 |
|
||||
| E0.S2 | Supabase project + schema | 5 core tables aangemaakt | ✅ | 3 |
|
||||
| E0.S3 | Auth flows (login/logout) | Email/password werkt, OAuth ready | ✅ | 5 |
|
||||
|
||||
**Tech Notes:**
|
||||
- Database migrations in `supabase/migrations/`
|
||||
- Auth flows in `app/auth/` (callback, logout, reset-password)
|
||||
- Environment vars: `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_ANON_KEY`
|
||||
|
||||
---
|
||||
|
||||
### Epic 1 — Layout & Navigation
|
||||
|
||||
**Doel:** Two-level context systeem werkend met context-aware sidebar en header
|
||||
|
||||
| Story ID | Beschrijving | AC | Status | Points |
|
||||
|----------|--------------|-----|--------|--------|
|
||||
| E1.S1 | EPD root layout | Fixed header + sidebar layout | 🔄 | 3 |
|
||||
| E1.S2 | Context-aware sidebar | Level 1 vs Level 2 menu dynamisch | 🔄 | 5 |
|
||||
| E1.S3 | Context-aware header | Client dropdown in Level 2, search bar | 🔄 | 5 |
|
||||
| E1.S4 | URL-based context detection | Layout past zich aan op basis van URL | ⏳ | 3 |
|
||||
|
||||
**Tech Notes:**
|
||||
|
||||
**Routing structure:**
|
||||
```
|
||||
/epd/dashboard → Behandelaar dashboard (Level 1)
|
||||
/epd/patients → Patiënten lijst (Level 1)
|
||||
/epd/patients/[id] → Patient dashboard (Level 2)
|
||||
/epd/patients/[id]/intakes → Intake sectie (Level 2)
|
||||
/epd/patients/[id]/diagnose → Diagnose sectie (Level 2)
|
||||
/epd/patients/[id]/plan → Behandelplan (Level 2)
|
||||
```
|
||||
|
||||
**Context detection logic:**
|
||||
```typescript
|
||||
const isPatientDossier = pathname.includes('/patients/') &&
|
||||
pathname.match(/\/patients\/[^\/]+/);
|
||||
const patientId = isPatientDossier ? pathname.split('/')[3] : null;
|
||||
```
|
||||
|
||||
**Components:**
|
||||
- `app/epd/layout.tsx` - Root EPD layout met context detection
|
||||
- `app/epd/components/epd-header.tsx` - Context-aware header
|
||||
- `app/epd/components/epd-sidebar.tsx` - Context-aware sidebar
|
||||
|
||||
---
|
||||
|
||||
### Epic 2 — Cliënten Management
|
||||
|
||||
**Doel:** CRUD voor cliënten, search/filter, recent clients
|
||||
|
||||
| Story ID | Beschrijving | AC | Status | Points |
|
||||
|----------|--------------|-----|--------|--------|
|
||||
| E2.S1 | Cliënten lijst view | Table met search, filters werkend | ⏳ | 5 |
|
||||
| E2.S2 | Nieuwe cliënt formulier | Modal/page met validatie, opslaan werkt | ⏳ | 5 |
|
||||
| E2.S3 | Client detail edit | Bestaande client gegevens bewerken | ⏳ | 3 |
|
||||
| E2.S4 | Search & filter functionaliteit | Real-time zoeken op naam, BSN, ID | ⏳ | 5 |
|
||||
| E2.S5 | Recent clients tracking | localStorage, max 5 items, dropdown | ⏳ | 3 |
|
||||
|
||||
**Tech Notes:**
|
||||
|
||||
**Database queries:**
|
||||
```typescript
|
||||
// lib/supabase/queries/clients.ts
|
||||
export async function getClients(filters: ClientFilters) {
|
||||
const query = supabase
|
||||
.from('clients')
|
||||
.select('id, first_name, last_name, birth_date, created_at')
|
||||
.order('last_name', { ascending: true });
|
||||
|
||||
if (filters.search) {
|
||||
query.or(`first_name.ilike.%${filters.search}%,last_name.ilike.%${filters.search}%`);
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
```
|
||||
|
||||
**Search debounce:**
|
||||
```typescript
|
||||
const debouncedSearch = useMemo(
|
||||
() => debounce((value: string) => setSearchQuery(value), 300),
|
||||
[]
|
||||
);
|
||||
```
|
||||
|
||||
**Components:**
|
||||
- `app/epd/patients/page.tsx` - Patiënten lijst
|
||||
- `app/epd/patients/components/patient-list.tsx`
|
||||
- `app/epd/patients/components/patient-search.tsx`
|
||||
- `app/epd/patients/new/page.tsx` - Nieuwe patiënt form
|
||||
|
||||
---
|
||||
|
||||
### Epic 3 — Intake Systeem
|
||||
|
||||
**Doel:** TipTap editor voor intake notities met CRUD functionaliteit
|
||||
|
||||
| Story ID | Beschrijving | AC | Status | Points |
|
||||
|----------|--------------|-----|--------|--------|
|
||||
| E3.S1 | TipTap editor setup | Rich text editor werkend, formatting | ⏳ | 8 |
|
||||
| E3.S2 | Intake lijst view | Toon alle intakes per client, sorteerbaar | ⏳ | 3 |
|
||||
| E3.S3 | Nieuwe intake aanmaken | Editor opent, opslaan werkt, JSONB storage | ⏳ | 5 |
|
||||
| E3.S4 | Intake detail slide-in | 400px panel, scroll, edit/delete | ⏳ | 5 |
|
||||
| E3.S5 | Content text extraction | JSONB → plain text voor search index | ⏳ | 3 |
|
||||
| E3.S6 | Auto-save drafts | localStorage, 30s interval, restore on return | ⏳ | 5 |
|
||||
|
||||
**Tech Notes:**
|
||||
|
||||
**TipTap configuration:**
|
||||
```typescript
|
||||
import { useEditor } from '@tiptap/react'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
|
||||
const editor = useEditor({
|
||||
extensions: [StarterKit],
|
||||
content: initialContent,
|
||||
onUpdate: ({ editor }) => {
|
||||
const json = editor.getJSON()
|
||||
const text = editor.getText()
|
||||
// Save to state/DB
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**Database structure:**
|
||||
```sql
|
||||
intake_notes (
|
||||
id UUID,
|
||||
client_id UUID,
|
||||
title TEXT,
|
||||
tag TEXT ('Intake', 'Evaluatie', 'Plan'),
|
||||
content_json JSONB, -- TipTap document
|
||||
content_text TEXT, -- Plain text for FTS
|
||||
created_at TIMESTAMPTZ
|
||||
)
|
||||
```
|
||||
|
||||
**Components:**
|
||||
- `app/epd/patients/[id]/intakes/page.tsx` - Intake lijst
|
||||
- `app/epd/patients/[id]/intakes/components/intake-editor.tsx`
|
||||
- `app/epd/patients/[id]/intakes/components/intake-detail-panel.tsx`
|
||||
|
||||
---
|
||||
|
||||
### Epic 4 — Diagnose & Probleemprofiel
|
||||
|
||||
**Doel:** DSM-light categorieën met severity tracking (manual entry MVP)
|
||||
|
||||
| Story ID | Beschrijving | AC | Status | Points |
|
||||
|----------|--------------|-----|--------|--------|
|
||||
| E4.S1 | DSM categories grid UI | 6 categorieën visueel, severity badges | ⏳ | 5 |
|
||||
| E4.S2 | Problem profile CRUD | Aanmaken/bewerken/verwijderen per categorie | ⏳ | 5 |
|
||||
| E4.S3 | Severity indicator | Laag/Middel/Hoog visueel duidelijk | ⏳ | 2 |
|
||||
| E4.S4 | Source linking | Link diagnose → intake note (bronverwijzing) | ⏳ | 3 |
|
||||
|
||||
**Tech Notes:**
|
||||
|
||||
**DSM-light categories:**
|
||||
```typescript
|
||||
const DSM_CATEGORIES = [
|
||||
{ id: 'stemming_depressie', label: 'Stemming & Depressie', color: 'blue' },
|
||||
{ id: 'angst', label: 'Angst', color: 'purple' },
|
||||
{ id: 'gedrag_impuls', label: 'Gedrag & Impuls', color: 'red' },
|
||||
{ id: 'middelen_gebruik', label: 'Middelengebruik', color: 'orange' },
|
||||
{ id: 'cognitief', label: 'Cognitief', color: 'green' },
|
||||
{ id: 'context_psychosociaal', label: 'Context & Psychosociaal', color: 'teal' },
|
||||
] as const;
|
||||
```
|
||||
|
||||
**Severity levels:**
|
||||
```typescript
|
||||
type Severity = 'laag' | 'middel' | 'hoog';
|
||||
|
||||
const SEVERITY_CONFIG = {
|
||||
laag: { label: 'Laag', color: 'green', dots: 1 },
|
||||
middel: { label: 'Middel', color: 'yellow', dots: 3 },
|
||||
hoog: { label: 'Hoog', color: 'red', dots: 5 },
|
||||
};
|
||||
```
|
||||
|
||||
**Components:**
|
||||
- `app/epd/patients/[id]/diagnose/page.tsx`
|
||||
- `app/epd/patients/[id]/diagnose/components/dsm-categories.tsx`
|
||||
- `app/epd/patients/[id]/diagnose/components/severity-indicator.tsx`
|
||||
|
||||
---
|
||||
|
||||
### Epic 5 — Behandelplan
|
||||
|
||||
**Doel:** SMART doelen tracking met interventies en versioning
|
||||
|
||||
| Story ID | Beschrijving | AC | Status | Points |
|
||||
|----------|--------------|-----|--------|--------|
|
||||
| E5.S1 | Treatment plan data model | JSONB structure + versioning | ⏳ | 3 |
|
||||
| E5.S2 | SMART goals editor | Lijst van doelen, progress tracking | ⏳ | 8 |
|
||||
| E5.S3 | Interventies sectie | Evidence-based methoden lijst | ⏳ | 5 |
|
||||
| E5.S4 | Frequentie & planning | Sessie planning, duration estimate | ⏳ | 3 |
|
||||
| E5.S5 | Plan versioning | v1, v2, concept/gepubliceerd status | ⏳ | 5 |
|
||||
|
||||
**Tech Notes:**
|
||||
|
||||
**Treatment plan JSONB structure:**
|
||||
```typescript
|
||||
interface TreatmentPlan {
|
||||
doelen: Array<{
|
||||
id: string;
|
||||
beschrijving: string;
|
||||
specifiek: string; // S - Specific
|
||||
meetbaar: string; // M - Measurable
|
||||
acceptabel: boolean; // A - Acceptable
|
||||
realistisch: boolean; // R - Realistic
|
||||
tijdgebonden: string; // T - Time-bound
|
||||
voortgang: number; // 0-100%
|
||||
}>;
|
||||
interventies: Array<{
|
||||
naam: string; // "CGT", "ACT", "EMDR"
|
||||
beschrijving: string;
|
||||
doel_ids: string[]; // Links to goals
|
||||
}>;
|
||||
frequentie: {
|
||||
sessies_per_week: number;
|
||||
totaal_sessies: number;
|
||||
duur_minuten: number;
|
||||
};
|
||||
meetmomenten: Array<{
|
||||
week: number;
|
||||
beschrijving: string;
|
||||
}>;
|
||||
}
|
||||
```
|
||||
|
||||
**Versioning logic:**
|
||||
```typescript
|
||||
// When creating new version:
|
||||
const latestVersion = await getLatestPlanVersion(clientId);
|
||||
const newVersion = latestVersion ? latestVersion.version + 1 : 1;
|
||||
|
||||
// Publish: concept → gepubliceerd
|
||||
await supabase
|
||||
.from('treatment_plans')
|
||||
.update({ status: 'gepubliceerd', published_at: new Date() })
|
||||
.eq('id', planId);
|
||||
```
|
||||
|
||||
**Components:**
|
||||
- `app/epd/patients/[id]/plan/page.tsx`
|
||||
- `app/epd/patients/[id]/plan/components/smart-goals.tsx`
|
||||
- `app/epd/patients/[id]/plan/components/interventions.tsx`
|
||||
- `app/epd/patients/[id]/plan/components/plan-version-selector.tsx`
|
||||
|
||||
---
|
||||
|
||||
### Epic 6 — AI Integration (Week 3)
|
||||
|
||||
**Doel:** AI-powered features voor summarize, classify, generate
|
||||
|
||||
| Story ID | Beschrijving | AC | Status | Points |
|
||||
|----------|--------------|-----|--------|--------|
|
||||
| E6.S1 | AI API configuratie | OpenAI/Vertex setup, test call works | ⏳ | 3 |
|
||||
| E6.S2 | Intake samenvatting | /api/ai/summarize endpoint, <5s response | ⏳ | 8 |
|
||||
| E6.S3 | Diagnose classificatie | /api/ai/classify endpoint, DSM mapping | ⏳ | 8 |
|
||||
| E6.S4 | Behandelplan generatie | /api/ai/generate-plan, SMART goals output | ⏳ | 13 |
|
||||
|
||||
**Tech Notes:**
|
||||
|
||||
**API Routes:**
|
||||
```
|
||||
POST /api/ai/summarize - Samenvatting van intake note
|
||||
POST /api/ai/classify - DSM-light classificatie
|
||||
POST /api/ai/generate-plan - Behandelplan generatie
|
||||
```
|
||||
|
||||
**AI Events logging:**
|
||||
```typescript
|
||||
await supabase.from('ai_events').insert({
|
||||
kind: 'summarize',
|
||||
client_id: clientId,
|
||||
note_id: noteId,
|
||||
request: { prompt, model },
|
||||
response: { output, tokens },
|
||||
duration_ms: responseTime,
|
||||
});
|
||||
```
|
||||
|
||||
**Prompt templates:**
|
||||
```typescript
|
||||
const SUMMARIZE_PROMPT = `
|
||||
Je bent een GGZ-professional. Vat de volgende intake notitie samen in 3-5 bullet points.
|
||||
Focus op: klachten, achtergrond, observaties.
|
||||
|
||||
Notitie:
|
||||
{content}
|
||||
`;
|
||||
```
|
||||
|
||||
**Components:**
|
||||
- `app/api/ai/summarize/route.ts`
|
||||
- `app/api/ai/classify/route.ts`
|
||||
- `app/api/ai/generate-plan/route.ts`
|
||||
- `lib/ai/prompts.ts`
|
||||
- `lib/ai/client.ts` (OpenAI/Vertex wrapper)
|
||||
|
||||
---
|
||||
|
||||
### Epic 7 — Testing & Polish
|
||||
|
||||
**Doel:** QA, accessibility audit, performance optimization
|
||||
|
||||
| Story ID | Beschrijving | AC | Status | Points |
|
||||
|----------|--------------|-----|--------|--------|
|
||||
| E7.S1 | Manual test scenarios | Alle happy flows werken zonder errors | ⏳ | 5 |
|
||||
| E7.S2 | Accessibility audit | WCAG AA compliance, keyboard nav werkt | ⏳ | 5 |
|
||||
| E7.S3 | Performance optimization | Lighthouse score >90, <2s load | ⏳ | 3 |
|
||||
|
||||
---
|
||||
|
||||
## 5. Kwaliteit & Testplan
|
||||
|
||||
### Test Types
|
||||
|
||||
| Test Type | Scope | Verantwoordelijke |
|
||||
|-----------|-------|-------------------|
|
||||
| Manual Testing | Happy flows, edge cases | Developer |
|
||||
| Accessibility | Keyboard nav, screen reader | Developer |
|
||||
| Performance | Lighthouse, load times | Developer |
|
||||
|
||||
### Manual Test Checklist
|
||||
|
||||
**Level 1 - Behandelaar Context:**
|
||||
- [ ] Login werkt (email/password)
|
||||
- [ ] Dashboard toont correct (caseload, aandachtspunten)
|
||||
- [ ] Cliënten lijst laadt, search werkt
|
||||
- [ ] Nieuwe cliënt aanmaken werkt
|
||||
- [ ] Klik op client → switch naar Level 2
|
||||
|
||||
**Level 2 - Client Dossier Context:**
|
||||
- [ ] Client dashboard toont correct (info, laatste intake, diagnose)
|
||||
- [ ] Sidebar toont "← Cliënten" button
|
||||
- [ ] Header toont client dropdown
|
||||
- [ ] Navigatie tussen secties werkt (Intake, Diagnose, Plan)
|
||||
- [ ] "← Cliënten" button → terug naar Level 1
|
||||
|
||||
**Intake:**
|
||||
- [ ] TipTap editor opent, formatting werkt
|
||||
- [ ] Opslaan intake werkt (JSONB + text extraction)
|
||||
- [ ] Intake lijst toont alle notities
|
||||
- [ ] Slide-in detail panel opent/sluit correct
|
||||
- [ ] Bewerken intake werkt
|
||||
|
||||
**Diagnose:**
|
||||
- [ ] DSM categories grid toont 6 categorieën
|
||||
- [ ] Severity indicator werkt (laag/middel/hoog)
|
||||
- [ ] Problem profile aanmaken/bewerken werkt
|
||||
- [ ] Bronverwijzing naar intake note werkt
|
||||
|
||||
**Behandelplan:**
|
||||
- [ ] SMART goals toevoegen/bewerken werkt
|
||||
- [ ] Interventies sectie werkt
|
||||
- [ ] Progress tracking werkt (0-100%)
|
||||
- [ ] Versioning werkt (v1, v2, concept/gepubliceerd)
|
||||
|
||||
**AI Features (Week 3):**
|
||||
- [ ] Samenvatting genereert binnen 5 seconden
|
||||
- [ ] Classificatie geeft valide DSM categories
|
||||
- [ ] Behandelplan generator werkt, output is bruikbaar
|
||||
- [ ] AI events worden gelogd
|
||||
|
||||
**Accessibility:**
|
||||
- [ ] Alle interactive elements keyboard accessible
|
||||
- [ ] Focus states zichtbaar
|
||||
- [ ] ARIA labels correct
|
||||
- [ ] Color contrast WCAG AA
|
||||
|
||||
---
|
||||
|
||||
## 6. Demo & Presentatieplan
|
||||
|
||||
**Duur:** 15 minuten
|
||||
**Doelgroep:** Stakeholders, GGZ-professionals
|
||||
**Demo Scenario:**
|
||||
|
||||
1. **Login** (1 min) - Toon authenticatie flow
|
||||
2. **Behandelaar Dashboard** (2 min) - Overzicht caseload, aandachtspunten
|
||||
3. **Nieuwe Cliënt** (2 min) - Voeg "Bas Jansen" toe
|
||||
4. **Intake Notitie** (3 min) - TipTap editor, rich text, opslaan
|
||||
5. **AI Samenvatting** (2 min) - Genereer samenvatting (Week 3 feature)
|
||||
6. **Diagnose** (2 min) - DSM classificatie, severity
|
||||
7. **Behandelplan** (2 min) - SMART goals, interventies
|
||||
8. **Q&A** (1 min)
|
||||
|
||||
**Backup Plan:**
|
||||
- Localhost als Vercel deployment faalt
|
||||
- Pre-seeded demo data
|
||||
- Screenshots als fallback
|
||||
|
||||
---
|
||||
|
||||
## 7. Risico's & Mitigatie
|
||||
|
||||
| Risico | Kans | Impact | Mitigatie | Owner |
|
||||
|--------|------|--------|-----------|-------|
|
||||
| TipTap integratie complex | Middel | Hoog | Start met StarterKit, uitbreiden later | Dev |
|
||||
| AI API rate limits | Hoog | Middel | Caching, response fallbacks, debounce | Dev |
|
||||
| Context switching bugs | Middel | Hoog | Uitgebreide URL-based state tests | Dev |
|
||||
| Performance met grote datasets | Middel | Middel | Pagination, lazy loading, indexing | Dev |
|
||||
| RLS policies te open (demo) | Laag | Hoog | Duidelijke comments, productie checklist | Dev |
|
||||
| Two-level navigation verwarrend | Middel | Middel | User testing, clear visual feedback | Dev |
|
||||
|
||||
---
|
||||
|
||||
## 8. Evaluatie & Lessons Learned
|
||||
|
||||
**Te documenteren na MVP:**
|
||||
- Welke onderdelen namen meer tijd dan verwacht?
|
||||
- TipTap editor challenges en oplossingen
|
||||
- AI prompt engineering insights (Week 3)
|
||||
- Two-level navigation UX feedback
|
||||
- Performance bottlenecks en optimalisaties
|
||||
- Herbruikbare patterns voor volgende projecten
|
||||
|
||||
---
|
||||
|
||||
## 9. Referenties
|
||||
|
||||
**Mission Control Documents:**
|
||||
- **Interface Design:** `docs/specs/UI/interface-design-plan.md`
|
||||
- **User Flows:** `docs/specs/UI/mocks-ui-flow.md`
|
||||
- **Database Schema:** `supabase/migrations/20241115000002_create_epd_core_tables.sql`
|
||||
|
||||
**Codebase:**
|
||||
- **Repository:** `/home/colin/development/15-mini-epd-prototype`
|
||||
- **EPD App:** `app/epd/`
|
||||
- **Components:** `components/ui/`, `app/epd/components/`
|
||||
- **Database Queries:** `lib/supabase/queries/`
|
||||
- **Migrations:** `supabase/migrations/`
|
||||
|
||||
**External Resources:**
|
||||
- Next.js 15 Docs: https://nextjs.org/docs
|
||||
- Supabase Docs: https://supabase.com/docs
|
||||
- TipTap Docs: https://tiptap.dev
|
||||
- Radix UI: https://radix-ui.com
|
||||
- Tailwind CSS: https://tailwindcss.com
|
||||
|
||||
---
|
||||
|
||||
## 10. Glossary & Abbreviations
|
||||
|
||||
| Term | Betekenis |
|
||||
|------|-----------|
|
||||
| EPD | Electronisch Patiënten Dossier |
|
||||
| GGZ | Geestelijke Gezondheidszorg |
|
||||
| DSM | Diagnostic and Statistical Manual (psychiatric classification) |
|
||||
| DSM-light | Vereenvoudigde categorisatie (6 hoofdgroepen) |
|
||||
| SMART | Specific, Measurable, Acceptable, Realistic, Time-bound |
|
||||
| TipTap | Rich text editor gebouwd op ProseMirror |
|
||||
| RLS | Row Level Security (Supabase/PostgreSQL) |
|
||||
| Level 1 | Behandelaar Context (caseload overzicht) |
|
||||
| Level 2 | Client Dossier Context (individuele cliënt focus) |
|
||||
| Context Switch | Navigatie tussen Level 1 ↔ Level 2 |
|
||||
| FTS | Full-Text Search |
|
||||
| JSONB | PostgreSQL JSON Binary data type |
|
||||
|
||||
---
|
||||
|
||||
**Versiehistorie:**
|
||||
|
||||
| Versie | Datum | Auteur | Wijziging |
|
||||
|--------|-------|--------|-----------|
|
||||
| v1.0 | 19-11-2025 | Development Team | Initiële versie op basis van UI specs |
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 111 KiB |
@@ -1,900 +0,0 @@
|
||||
# Mini-ECD Interface Design - Complete MVP Specification
|
||||
|
||||
## Technical Specs
|
||||
- Target: Desktop only, min-width 1280px
|
||||
- Optimized for: 1440px - 1920px screens
|
||||
- Framework: Next.js 15, TailwindCSS, shadcn/ui
|
||||
- No mobile optimization in MVP
|
||||
|
||||
---
|
||||
|
||||
## Navigation Architecture
|
||||
|
||||
### Two-Level Context System
|
||||
|
||||
**LEVEL 1: Behandelaar Context** (No client selected)
|
||||
- Sidebar shows: Dashboard | Cliënten | Agenda | Rapportage
|
||||
- Header: No client dropdown (or disabled/empty)
|
||||
- Focus: Behandelaar's caseload, tasks, and global views
|
||||
|
||||
**LEVEL 2: Client Dossier Context** (Client selected)
|
||||
- Sidebar shows: ← Cliënten | Dashboard | Intake | Diagnose | Behandelplan | Rapportage
|
||||
- Header: Shows selected client with dropdown "Bas Jansen ▼"
|
||||
- Focus: Individual client data and treatment information
|
||||
|
||||
**Context Switch Trigger:**
|
||||
- Clicking a client row in the cliënten lijst switches from Level 1 → Level 2
|
||||
- Clicking "← Cliënten" in sidebar switches from Level 2 → Level 1
|
||||
|
||||
---
|
||||
|
||||
## Layout Components
|
||||
|
||||
### Header Bar (Fixed, 60px height)
|
||||
- Background: White with subtle bottom border
|
||||
- Padding: 16px vertical, 24px horizontal
|
||||
- Layout (flex, space-between):
|
||||
- **Left**: "Mini-ECD" text/logo (medium weight)
|
||||
- **Center**: Context-aware client selector
|
||||
- **In Behandelaar Context**: Empty or behandelaar name (optional)
|
||||
- **In Client Dossier Context**: Client dropdown "Bas Jansen ▼" (clickable)
|
||||
- Sub-text below: "ID: CL0002 | Geb: 20-11-1992" (small, muted)
|
||||
- Dropdown shows recent clients for quick switching
|
||||
- **Right**: Search input "Zoek cliënt..." with icon (rounded, light border)
|
||||
- Always available for quick client lookup
|
||||
|
||||
### Sidebar (Fixed left, 240px width)
|
||||
- Background: Very light gray
|
||||
- Padding: 16px
|
||||
|
||||
**Context-Aware Navigation:**
|
||||
|
||||
**BEHANDELAAR CONTEXT (Level 1) - No client selected:**
|
||||
- Dashboard (icon + text) → Behandelaar dashboard (caseload, taken, aandachtspunten)
|
||||
- Cliënten (icon + text) → Caseload overzicht met zoek/filter
|
||||
- Agenda (icon + text) → Behandelaar agenda (alle afspraken)
|
||||
- Rapportage (icon + text) → BI dashboards en statistieken
|
||||
|
||||
**CLIENT DOSSIER CONTEXT (Level 2) - Client selected:**
|
||||
- "← Cliënten" button (full width, left-aligned, subtle hover) → Terug naar behandelaar context
|
||||
- Subtle horizontal divider (8px margin bottom)
|
||||
- Dashboard (icon + text) → Client dossier overzicht (afgelopen/komende afspraken)
|
||||
- Intake (icon + text) → Intake gesprekken en notities
|
||||
- Diagnose (icon + text) → DSM-classificatie, probleemprofiel
|
||||
- Behandelplan (icon + text) → Doelen, interventies, planning
|
||||
- Rapportage (icon + text) → Client-specifieke voortgang en metrics
|
||||
|
||||
**Styling:**
|
||||
- Each item: 12px padding vertical, 12px padding horizontal
|
||||
- Icons: 20px, 12px gap to text
|
||||
- Item spacing: 4px between items
|
||||
- Active state: highlighted background, emphasized text, left border accent
|
||||
- Hover state: subtle background change
|
||||
- Text: medium weight, 15px
|
||||
|
||||
### Main Content Area (Scrollable)
|
||||
- Background: White
|
||||
- Padding: 32px all sides
|
||||
- Min-height: calc(100vh - 60px)
|
||||
|
||||
---
|
||||
|
||||
## LEVEL 1 SCREENS: Behandelaar Context
|
||||
|
||||
---
|
||||
|
||||
## Screen 1A: Behandelaar Dashboard
|
||||
|
||||
### Sidebar
|
||||
- **Dashboard** ← ACTIVE
|
||||
- Cliënten
|
||||
- Agenda
|
||||
- Rapportage
|
||||
|
||||
### Main Content
|
||||
**Page title:** "Dashboard" (large, semi-bold)
|
||||
**Subtitle:** "Welkom terug, [Behandelaar naam]" (optional)
|
||||
|
||||
**Content (to be further defined):**
|
||||
- Caseload overzicht (aantal actieve cliënten, wachtlijst, etc.)
|
||||
- Aandachtspunten (urgente taken, follow-ups)
|
||||
- Behandelplannen die nog niet definitief zijn
|
||||
- Berichten en notificaties
|
||||
- Recente activiteit
|
||||
- Aankomende afspraken (vandaag/deze week)
|
||||
|
||||
**Note:** Detailed content and layout to be specified in later iteration.
|
||||
|
||||
---
|
||||
|
||||
## Screen 1B: Cliënten (Search/List View)
|
||||
|
||||
### Sidebar
|
||||
- Dashboard
|
||||
- **Cliënten** ← ACTIVE
|
||||
- Agenda
|
||||
- Rapportage
|
||||
|
||||
### Header
|
||||
- No client dropdown in center (behandelaar context)
|
||||
- Search bar available in top right
|
||||
|
||||
### Main Content
|
||||
**Top bar:**
|
||||
- Title: "Cliënten" (large, semi-bold, left)
|
||||
- Button: "+ Nieuwe Cliënt" (primary style, right)
|
||||
- Space-between layout
|
||||
|
||||
**Search & Filter bar (below title):**
|
||||
- Full-width input field
|
||||
- Placeholder: "Zoek op naam, BSN, of cliënt ID..."
|
||||
- Icon: magnifying glass left side
|
||||
- Filter options (to be specified):
|
||||
- Afdeling filter
|
||||
- Team filter
|
||||
- Status filter (Actief, Wachtlijst, Afgesloten)
|
||||
- 16px margin bottom
|
||||
|
||||
**Recent clients section (optional):**
|
||||
- "Recent bekeken" subtitle (small, muted)
|
||||
- 3-5 most recent client cards (compact)
|
||||
- Horizontal scroll or grid
|
||||
|
||||
**Client list (table/card hybrid):**
|
||||
|
||||
Header row:
|
||||
- Columns: Naam | ID | Geboortedatum | Status | Laatste Contact
|
||||
- Subtle bottom border, muted text, small size
|
||||
|
||||
Client rows (3-4 visible):
|
||||
|
||||
Row 1:
|
||||
- Naam: "Bas Jansen"
|
||||
- ID: "CL0002"
|
||||
- Geboortedatum: "20-11-1992"
|
||||
- Status: "Actief" (green badge)
|
||||
- Laatste contact: "12-10-2023"
|
||||
- Hover state: subtle background, pointer cursor
|
||||
- Click: navigates to client dashboard
|
||||
|
||||
Row 2:
|
||||
- Naam: "Anna de Vries"
|
||||
- ID: "CL0001"
|
||||
- Geboortedatum: "15-03-1988"
|
||||
- Status: "Actief" (green badge)
|
||||
- Laatste contact: "08-10-2023"
|
||||
|
||||
Row 3:
|
||||
- Naam: "Peter Smit"
|
||||
- ID: "CL0003"
|
||||
- Geboortedatum: "22-07-1995"
|
||||
- Status: "Wachtlijst" (yellow badge)
|
||||
- Laatste contact: "01-10-2023"
|
||||
|
||||
**Empty state (if no clients):**
|
||||
- Centered icon (users/people illustration)
|
||||
- Text: "Nog geen cliënten"
|
||||
- Subtext: "Voeg je eerste cliënt toe om te beginnen"
|
||||
- "+ Nieuwe Cliënt" button (primary, centered)
|
||||
|
||||
**Layout structure:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Header: Logo | (no client) | Search │
|
||||
├───────────┬─────────────────────────────────────┤
|
||||
│Dashboard │ Cliënten [+ Nieuwe Cliënt] │
|
||||
│Cliënten ← │ │
|
||||
│Agenda │ [Zoek op naam, BSN, of cliënt ID] │
|
||||
│Rapportage │ [Filters: Afdeling, Team, Status] │
|
||||
│ │ │
|
||||
│ │ Naam ID Geb Status │
|
||||
│ │ ────────────────────────────────── │
|
||||
│ │ Bas J. CL0002 20-11 Actief │
|
||||
│ │ Anna dV CL0001 15-03 Actief │
|
||||
│ │ Peter S. CL0003 22-07 Wachtlijst │
|
||||
└───────────┴─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**User action to switch context:**
|
||||
- Click on a client row (e.g., "Bas Jansen") → Switches to Level 2 (Client Dossier Context)
|
||||
|
||||
---
|
||||
|
||||
## Screen 1C: Behandelaar Agenda
|
||||
|
||||
### Sidebar
|
||||
- Dashboard
|
||||
- Cliënten
|
||||
- **Agenda** ← ACTIVE
|
||||
- Rapportage
|
||||
|
||||
### Main Content
|
||||
**Page title:** "Agenda" (large, semi-bold)
|
||||
|
||||
**Content (to be further defined):**
|
||||
- Calendar view (week/month)
|
||||
- Behandelaar's appointments (all clients)
|
||||
- Appointment details: time, client, type
|
||||
- Create new appointment button
|
||||
|
||||
**Note:** Detailed content and layout to be specified in later iteration.
|
||||
|
||||
---
|
||||
|
||||
## Screen 1D: Behandelaar Rapportage
|
||||
|
||||
### Sidebar
|
||||
- Dashboard
|
||||
- Cliënten
|
||||
- Agenda
|
||||
- **Rapportage** ← ACTIVE
|
||||
|
||||
### Main Content
|
||||
**Page title:** "Rapportage" (large, semi-bold)
|
||||
|
||||
**Content (to be further defined):**
|
||||
- BI-style dashboards
|
||||
- KPI's (aantal cliënten, gemiddelde behandelduur, etc.)
|
||||
- Trends en statistieken
|
||||
- Export functionaliteit
|
||||
|
||||
**Note:** Detailed content and layout to be specified in later iteration.
|
||||
|
||||
---
|
||||
|
||||
## LEVEL 2 SCREENS: Client Dossier Context
|
||||
|
||||
**Context Switch:** User clicked on a client in the cliënten lijst
|
||||
|
||||
---
|
||||
|
||||
## Screen 2A: Client Dashboard (Dossier Overzicht)
|
||||
|
||||
### Header
|
||||
- **Center**: "Bas Jansen ▼" dropdown visible
|
||||
- Sub-text: "ID: CL0002 | Geb: 20-11-1992"
|
||||
- Dropdown shows recent clients for quick switching
|
||||
- **Right**: Search bar still available
|
||||
|
||||
### Sidebar
|
||||
- "← Cliënten" button at top (returns to behandelaar context)
|
||||
- Horizontal divider
|
||||
- **Dashboard** ← ACTIVE
|
||||
- Intake
|
||||
- Diagnose
|
||||
- Behandelplan
|
||||
- Rapportage
|
||||
|
||||
### Main Content
|
||||
**Page title:** "Dossier Overzicht" (large, semi-bold, 16px margin bottom)
|
||||
|
||||
**Grid layout:**
|
||||
|
||||
**Row 1: 3 equal columns (gap: 24px)**
|
||||
|
||||
Column 1 - Cliëntinformatie card:
|
||||
- Card style: white bg, subtle border, 8px radius, 16px padding
|
||||
- Title: "Cliëntinformatie" (medium, semi-bold)
|
||||
- List layout:
|
||||
- Label: Value pairs, stacked vertically
|
||||
- Cliënt ID: CL0002
|
||||
- Naam: Bas Jansen
|
||||
- Geboortedatum: 20-11-1992
|
||||
- Leeftijd: 31 jaar (computed)
|
||||
- Verzekering: [naam verzekeraar]
|
||||
- BSN: [nummer]
|
||||
- Labels: muted, small
|
||||
- Values: normal weight, darker
|
||||
- Action: "Bewerken →" link (small, at bottom)
|
||||
|
||||
Column 2 - Laatste Intake card:
|
||||
- Card style: same as column 1
|
||||
- Title: "Laatste Intake"
|
||||
- Date/time: "12-10-2023, 14:30" (small, muted)
|
||||
- Preview text (3 lines max):
|
||||
"Bas komt op gesprek vanwege spanningsklachten en paniekeaanvallen. Hij beschrijft situaties in het openbaar vervoer en drukke winkels als triggerend..."
|
||||
- "Bekijk intake →" link (small, at bottom) → navigates to Intake section
|
||||
|
||||
Column 3 - Diagnose card:
|
||||
- Card style: same as above
|
||||
- Title: "Diagnose"
|
||||
- Status badge: "Hoog" (red/warning bg, red text, rounded pill, inline with title)
|
||||
- Subtitle: "Angststoornissen" (medium weight)
|
||||
- Description text:
|
||||
"Panietstoornis met agorafobie. De frequentie van paniekeaanvallen en het vermijdingsgedrag zijn..."
|
||||
- "Bekijk diagnose →" link (small, at bottom) → navigates to Diagnose section
|
||||
|
||||
**Row 2: Full width (margin top: 24px)**
|
||||
|
||||
Behandelplan card:
|
||||
- Card style: same
|
||||
- Title: "Behandelplan"
|
||||
- If exists: Show summary with status badge (Concept, Actief, Afgerond)
|
||||
- If not exists (empty state):
|
||||
- Light gray background section inside card
|
||||
- Centered text: "Geen behandelplan gevonden."
|
||||
- "+ Maak behandelplan" button (secondary style, centered below)
|
||||
- "Bekijk behandelplan →" link → navigates to Behandelplan section
|
||||
|
||||
**Row 3: Full width (margin top: 24px)**
|
||||
|
||||
Afspraken card:
|
||||
- Card style: same
|
||||
- Title: "Afspraken"
|
||||
|
||||
Section 1:
|
||||
- Subtitle: "Afgelopen Afspraak" (small, muted, 8px margin bottom)
|
||||
- Item: "14-11-2025, 16:26 - Intake gesprek" (with subtle icon left)
|
||||
- Shows: type, duration, practitioner (if available)
|
||||
|
||||
Divider line (subtle, 16px margin vertical)
|
||||
|
||||
Section 2:
|
||||
- Subtitle: "Komende Afspraken" (small, muted)
|
||||
- Item 1: "22-11-2025, 16:26 - Psycho-educatie"
|
||||
- Item 2: "29-11-2025, 16:26 - Exposure therapie sessie"
|
||||
- Item 3: "06-12-2025, 16:26 - Evaluatie gesprek"
|
||||
- Each with subtle left border accent (blue)
|
||||
- Shows: date, time, type
|
||||
- If no appointments: "Geen geplande afspraken" (muted text)
|
||||
|
||||
**Layout structure:**
|
||||
```
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Header: Logo | Bas Jansen ▼ | Search │
|
||||
│ | ID: CL0002 | Geb: 20-11-1992 │
|
||||
├──────────┬───────────────────────────────────────┤
|
||||
│← Cliënten│ Dossier Overzicht │
|
||||
│────── │ │
|
||||
│Dashboard │ ┌─────────┬─────────┬──────────┐ │
|
||||
│Intake │ │ Info │ Intake │ Diagnose │ │
|
||||
│Diagnose │ │ Card │ Card │ Card │ │
|
||||
│Behandel │ └─────────┴─────────┴──────────┘ │
|
||||
│Rapport │ ┌──────────────────────────────┐ │
|
||||
│ │ │ Behandelplan Card │ │
|
||||
│ │ └──────────────────────────────┘ │
|
||||
│ │ ┌──────────────────────────────┐ │
|
||||
│ │ │ Afspraken Card │ │
|
||||
│ │ └──────────────────────────────┘ │
|
||||
└──────────┴───────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Screen 2B: Intake (Client Dossier)
|
||||
|
||||
### Header
|
||||
- **Center**: "Bas Jansen ▼" with ID and birthdate
|
||||
- **Right**: Search bar available
|
||||
|
||||
### Sidebar
|
||||
- "← Cliënten" button (returns to behandelaar context)
|
||||
- Divider
|
||||
- Dashboard
|
||||
- **Intake** ← ACTIVE
|
||||
- Diagnose
|
||||
- Behandelplan
|
||||
- Rapportage
|
||||
|
||||
### Main Content
|
||||
**Breadcrumb:** "Intakes > Overzicht"
|
||||
|
||||
**Top bar (flex, space-between):**
|
||||
- Title: "Intakes" (large, semi-bold, left)
|
||||
- Button: "+ Nieuwe Intake" (primary style, right)
|
||||
|
||||
**Intakes list (16px margin top):**
|
||||
|
||||
Header row:
|
||||
- Columns: Datum | Type | Status | Samenvatting | Acties
|
||||
- Subtle bottom border, muted text, small font
|
||||
- 8px padding bottom
|
||||
|
||||
Intake item 1 (card-like row):
|
||||
- Padding: 16px vertical
|
||||
- Bottom border (subtle)
|
||||
- Hover state: light background
|
||||
|
||||
Content:
|
||||
- Date: "12-10-2023, 14:30" (medium weight)
|
||||
- Type: "Intake gesprek" (small badge/pill, light blue bg)
|
||||
- Status: "Afgerond" (small badge/pill, green bg)
|
||||
- Summary: "Eerste intake. Cliënt presenteert zich met angst- en paniekkl..." (truncated ~60 chars, lighter weight)
|
||||
- Actions: "Bekijk" button (small, secondary style, becomes prominent on row hover)
|
||||
|
||||
Intake item 2:
|
||||
- Date: "05-10-2023, 10:15"
|
||||
- Type: "Telefonische intake" (badge)
|
||||
- Status: "Afgerond" (green badge)
|
||||
- Summary: "Korte telefonische screening. Doorverwijzing naar intake..."
|
||||
- Actions: "Bekijk" button
|
||||
|
||||
Intake item 3:
|
||||
- Date: "28-09-2023, 16:00"
|
||||
- Type: "Intake gesprek" (badge)
|
||||
- Status: "Afgerond" (green badge)
|
||||
- Summary: "Geen show. Cliënt niet verschenen, geen afmelding..."
|
||||
- Actions: "Bekijk" button
|
||||
|
||||
**Empty state (alternative if no intakes):**
|
||||
- Centered layout
|
||||
- Icon: document/clipboard illustration (gray, 64px)
|
||||
- Text: "Nog geen intakes" (medium, semi-bold)
|
||||
- Subtext: "Klik op 'Nieuwe Intake' om te beginnen" (small, muted)
|
||||
- "+ Nieuwe Intake" button (primary, centered, 16px margin top)
|
||||
|
||||
**Layout structure:**
|
||||
```
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Header: Logo | Bas Jansen ▼ | Search │
|
||||
│ | ID: CL0002 | Geb: 20-11-1992 │
|
||||
├──────────┬───────────────────────────────────────┤
|
||||
│← Cliënten│ Intake [+ Nieuwe Intake] │
|
||||
│────── │ │
|
||||
│Dashboard │ Datum Type Status Samenvat.. │
|
||||
│Intake ← │ ───────────────────────────────── │
|
||||
│Diagnose │ 12-10 Intake Afgr. Eerste... │
|
||||
│Behandel │ 05-10 Telef. Afgr. Korte... │
|
||||
│Rapport │ 28-09 Intake Afgr. Geen sh... │
|
||||
│ │ │
|
||||
└──────────┴───────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Screen 2C: Diagnose (Client Dossier)
|
||||
|
||||
### Header
|
||||
- **Center**: "Bas Jansen ▼" with ID and birthdate
|
||||
- **Right**: Search bar available
|
||||
|
||||
### Sidebar
|
||||
- "← Cliënten" button (returns to behandelaar context)
|
||||
- Divider
|
||||
- Dashboard
|
||||
- Intake
|
||||
- **Diagnose** ← ACTIVE
|
||||
- Behandelplan
|
||||
- Rapportage
|
||||
|
||||
### Main Content
|
||||
**Top bar:**
|
||||
- Title: "Diagnose & Probleemprofiel" (large, semi-bold, left)
|
||||
- Button: "AI Analyse" (primary style with sparkles icon, right)
|
||||
|
||||
**DSM-light Categorieën:**
|
||||
- Visual grid/dashboard showing classified problem areas
|
||||
- Categories:
|
||||
- Stemming & Depressie (blauw)
|
||||
- Angst (paars)
|
||||
- Gedrag & Impuls (rood)
|
||||
- Middelengebruik (oranje)
|
||||
- Cognitief (groen)
|
||||
- Context & Psychosociaal (teal)
|
||||
|
||||
**Ernst Indicatie:**
|
||||
- Visual indicator: Laag (green) | Middel (yellow) | Hoog (red)
|
||||
- Linked to intake sources (bronverwijzing)
|
||||
|
||||
**Content (to be further defined in Week 3):**
|
||||
- AI-generated classification based on intake notes
|
||||
- Manual override/editing capability
|
||||
- Timeline/history of diagnoses
|
||||
- Notes and observations section
|
||||
|
||||
**Layout structure:**
|
||||
```
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Header: Logo | Bas Jansen ▼ | Search │
|
||||
├──────────┬───────────────────────────────────────┤
|
||||
│← Cliënten│ Diagnose & Probleemprofiel [AI Analyse]│
|
||||
│────── │ │
|
||||
│Dashboard │ DSM-light Categorieën: │
|
||||
│Intake │ ┌────────┬────────┬────────┐ │
|
||||
│Diagnose← │ │Stemming│ Angst │ Gedrag │ │
|
||||
│Behandel │ │ Hoog │Middel │ Laag │ │
|
||||
│Rapport │ └────────┴────────┴────────┘ │
|
||||
│ │ ┌──────────────────────────┐ │
|
||||
│ │ │ Ernst: ●●●○○ (Hoog) │ │
|
||||
│ │ │ Bronnen: Intake 12-10 │ │
|
||||
│ │ └──────────────────────────┘ │
|
||||
└──────────┴───────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Screen 2D: Behandelplan (Client Dossier)
|
||||
|
||||
### Header
|
||||
- **Center**: "Bas Jansen ▼" with ID and birthdate
|
||||
- **Right**: Search bar available
|
||||
|
||||
### Sidebar
|
||||
- "← Cliënten" button (returns to behandelaar context)
|
||||
- Divider
|
||||
- Dashboard
|
||||
- Intake
|
||||
- Diagnose
|
||||
- **Behandelplan** ← ACTIVE
|
||||
- Rapportage
|
||||
|
||||
### Main Content
|
||||
**Top bar:**
|
||||
- Title: "Behandelplan" (large, semi-bold, left)
|
||||
- Buttons:
|
||||
- "Genereer Plan" (primary style with AI icon, right)
|
||||
- "Nieuwe Versie" (secondary style, if plan exists)
|
||||
|
||||
**Plan Structuur:**
|
||||
1. **SMART Doelen** section
|
||||
- Specifieke, Meetbare, Acceptabele, Realistische, Tijdgebonden doelen
|
||||
- Multiple goals per plan
|
||||
- Status tracking per goal
|
||||
|
||||
2. **Interventies** section
|
||||
- Evidence-based behandelmethoden (CGT, ACT, EMDR, etc.)
|
||||
- Linked to specific goals
|
||||
- Description and rationale
|
||||
|
||||
3. **Frequentie & Planning** section
|
||||
- Sessie planning
|
||||
- Behandelintensiteit
|
||||
- Duration estimate
|
||||
|
||||
4. **Meetmomenten** section
|
||||
- Evaluation schedule
|
||||
- Progress measurements
|
||||
- Review dates
|
||||
|
||||
**Versioning:**
|
||||
- Multiple versions per client (v1, v2, etc.)
|
||||
- Status: Concept | Actief | Afgerond
|
||||
- Timestamp and practitioner info
|
||||
|
||||
**Content (to be further defined in Week 3):**
|
||||
- AI plan generator based on intake + diagnose
|
||||
- JSONB data structure for flexibility
|
||||
- PDF export functionality
|
||||
|
||||
**Layout structure:**
|
||||
```
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Header: Logo | Bas Jansen ▼ | Search │
|
||||
├──────────┬───────────────────────────────────────┤
|
||||
│← Cliënten│ Behandelplan [Genereer Plan] │
|
||||
│────── │ │
|
||||
│Dashboard │ Versie 1 - Actief | 12-10-2023 │
|
||||
│Intake │ │
|
||||
│Diagnose │ 1. SMART Doelen │
|
||||
│Behandel← │ ┌──────────────────────────────┐ │
|
||||
│Rapport │ │ • Verminderen paniekeaanv.. │ │
|
||||
│ │ │ • Uitbreiden sociale activ.. │ │
|
||||
│ │ └──────────────────────────────┘ │
|
||||
│ │ 2. Interventies │
|
||||
│ │ ┌──────────────────────────────┐ │
|
||||
│ │ │ • CGT - Cognitieve herstr... │ │
|
||||
│ │ │ • Exposure therapie │ │
|
||||
│ │ └──────────────────────────────┘ │
|
||||
└──────────┴───────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Screen 2E: Rapportage (Client Dossier)
|
||||
|
||||
### Header
|
||||
- **Center**: "Bas Jansen ▼" with ID and birthdate
|
||||
- **Right**: Search bar available
|
||||
|
||||
### Sidebar
|
||||
- "← Cliënten" button (returns to behandelaar context)
|
||||
- Divider
|
||||
- Dashboard
|
||||
- Intake
|
||||
- Diagnose
|
||||
- Behandelplan
|
||||
- **Rapportage** ← ACTIVE
|
||||
|
||||
### Main Content
|
||||
**Page title:** "Rapportage & Voortgang" (large, semi-bold)
|
||||
|
||||
**Content (to be further defined):**
|
||||
- Client-specific progress metrics
|
||||
- Treatment timeline
|
||||
- Session attendance
|
||||
- Goal achievement tracking
|
||||
- Measurement instruments (ROM, questionnaires)
|
||||
- Graphs and visualizations
|
||||
- Export functionality (PDF, CSV)
|
||||
|
||||
**Layout structure:**
|
||||
```
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Header: Logo | Bas Jansen ▼ | Search │
|
||||
├──────────┬───────────────────────────────────────┤
|
||||
│← Cliënten│ Rapportage & Voortgang │
|
||||
│────── │ │
|
||||
│Dashboard │ ┌──────────────────────────────┐ │
|
||||
│Intake │ │ Behandelduur: 8 weken │ │
|
||||
│Diagnose │ │ Sessies: 6 van 12 │ │
|
||||
│Behandel │ │ Voortgang: ████████░░░░ 67% │ │
|
||||
│Rapport ← │ └──────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ Doelvoortgang: │
|
||||
│ │ [Graph/Chart placeholder] │
|
||||
└──────────┴───────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Intake Detail View (Modal/Slide-in)
|
||||
|
||||
**Trigger:** Click "Bekijk" button on any intake item
|
||||
|
||||
**Display options:**
|
||||
1. Slide-in panel from right (400px width, overlays content)
|
||||
2. Modal overlay (centered, 600px width, backdrop blur)
|
||||
|
||||
**Recommended: Slide-in panel** (keeps context visible)
|
||||
|
||||
### Slide-in Panel Structure
|
||||
|
||||
**Header (sticky):**
|
||||
- Background: light gray
|
||||
- Padding: 16px
|
||||
- Title: "Intake - 12-10-2023" (medium, semi-bold)
|
||||
- Close button: "×" (top right, large, clickable)
|
||||
|
||||
**Content (scrollable):**
|
||||
|
||||
Section 1 - Algemene informatie:
|
||||
- Background: white
|
||||
- Padding: 16px
|
||||
- Title: "Algemene informatie" (small, semi-bold, 8px margin bottom)
|
||||
- Items (label: value):
|
||||
- Datum & tijd: 12-10-2023, 14:30
|
||||
- Type: Intake gesprek
|
||||
- Behandelaar: [naam]
|
||||
- Duur: 60 minuten
|
||||
|
||||
Divider (subtle, 16px margin vertical)
|
||||
|
||||
Section 2 - Gespreksnotities:
|
||||
- Title: "Gespreksnotities" (small, semi-bold)
|
||||
- Text area (full content, scrollable if long):
|
||||
"Bas komt op gesprek vanwege spanningsklachten en paniekeaanvallen. Hij beschrijft situaties in het openbaar vervoer en drukke winkels als triggerend. De aanvallen kenmerken zich door hartkloppingen, duizeligheid en benauwdheid.
|
||||
|
||||
Anamnese: Klachten bestaan sinds ongeveer 1 jaar. Begonnen na stressvolle periode op werk. Eerste aanval in supermarkt, sindsdien toenemend vermijdingsgedrag.
|
||||
|
||||
Observatie: Cliënt presenteert zich alert en coöperatief. Spreekt openlijk over klachten. Lichte spanning zichtbaar bij bespreken van aanvallen..."
|
||||
|
||||
Divider
|
||||
|
||||
Section 3 - AI Samenvatting (optional for MVP):
|
||||
- Background: very light blue (distinguish from manual notes)
|
||||
- Padding: 12px
|
||||
- Icon: sparkles/AI icon (small, top left)
|
||||
- Title: "AI Samenvatting" (small, semi-bold)
|
||||
- Generated text: bullet points with key findings
|
||||
- Font: slightly smaller than main text
|
||||
|
||||
Divider
|
||||
|
||||
**Footer (sticky bottom):**
|
||||
- Background: light gray
|
||||
- Padding: 16px
|
||||
- Buttons layout (flex, space-between):
|
||||
- Left: "Verwijderen" button (destructive/red style, subtle)
|
||||
- Right: "Bewerken" button (secondary style)
|
||||
|
||||
---
|
||||
|
||||
## Design Tokens Reference
|
||||
|
||||
### Spacing Scale
|
||||
- xs: 4px
|
||||
- sm: 8px
|
||||
- md: 16px
|
||||
- lg: 24px
|
||||
- xl: 32px
|
||||
|
||||
### Border Radius
|
||||
- Small (badges): 12px
|
||||
- Medium (buttons): 6px
|
||||
- Large (cards): 8px
|
||||
|
||||
### Typography Scale
|
||||
- Page title: 28px, semi-bold
|
||||
- Card title: 18px, semi-bold
|
||||
- Section title: 14px, semi-bold
|
||||
- Body text: 15px, normal
|
||||
- Small text: 13px, normal
|
||||
- Tiny text: 12px, normal
|
||||
|
||||
### Shadows
|
||||
- Card: 0 1px 3px rgba(0,0,0,0.1)
|
||||
- Card hover: 0 4px 6px rgba(0,0,0,0.1)
|
||||
- Modal: 0 20px 25px rgba(0,0,0,0.15)
|
||||
|
||||
### Common Patterns
|
||||
|
||||
**Card component:**
|
||||
- White background
|
||||
- Border: 1px solid (light gray)
|
||||
- Border radius: 8px
|
||||
- Padding: 16px
|
||||
- Shadow: subtle (see above)
|
||||
|
||||
**Badge/pill component:**
|
||||
- Small font size (13px)
|
||||
- Padding: 4px 12px
|
||||
- Border radius: 12px (full rounded)
|
||||
- Background: contextual (green for success, yellow for warning, etc.)
|
||||
- Font weight: medium
|
||||
|
||||
**Button styles:**
|
||||
- Primary: solid background, white text, medium weight
|
||||
- Secondary: border outline, normal text
|
||||
- Destructive: red color scheme
|
||||
- Padding: 8px 16px
|
||||
- Border radius: 6px
|
||||
|
||||
**List/table row:**
|
||||
- Padding: 16px vertical
|
||||
- Border bottom: 1px solid (light gray)
|
||||
- Hover: light background change
|
||||
- Cursor: pointer (if clickable)
|
||||
|
||||
---
|
||||
|
||||
## Interaction Notes
|
||||
|
||||
### Navigation flow:
|
||||
1. Start: Behandelaar Dashboard (Level 1)
|
||||
2. Sidebar navigation: Dashboard | Cliënten | Agenda | Rapportage
|
||||
3. Click "Cliënten" → Cliënten list view
|
||||
4. Click client row → Context switch to Level 2 (Client Dossier)
|
||||
5. Sidebar changes to: ← Cliënten | Dashboard | Intake | Diagnose | Behandelplan | Rapportage
|
||||
6. Header shows selected client: "Bas Jansen ▼" with dropdown
|
||||
7. Navigate within client dossier using sidebar menu
|
||||
8. Click "← Cliënten" → Context switch back to Level 1
|
||||
9. Header client dropdown always available (in Level 2) for quick client switching
|
||||
10. Header search always available for quick client lookup
|
||||
|
||||
### State management:
|
||||
- Active menu item: always visible (highlighted)
|
||||
- Breadcrumbs: show current location
|
||||
- Empty states: guide users to next action
|
||||
- Loading states: skeleton screens for cards (not specified, but recommended)
|
||||
|
||||
### Accessibility considerations:
|
||||
- All interactive elements: keyboard accessible
|
||||
- Focus states: visible outlines
|
||||
- Color contrast: WCAG AA minimum
|
||||
- Alt text for icons (not visible, but in code)
|
||||
|
||||
---
|
||||
|
||||
## Technical Implementation Notes
|
||||
|
||||
### Routing structure (Next.js):
|
||||
```
|
||||
LEVEL 1: Behandelaar Context
|
||||
/epd/dashboard → Behandelaar dashboard (caseload, taken, aandachtspunten)
|
||||
/epd/clients → Cliënten list (zoek, filter, recent)
|
||||
/epd/agenda → Behandelaar agenda (alle afspraken)
|
||||
/epd/reports → BI rapportage (statistieken, KPI's)
|
||||
|
||||
LEVEL 2: Client Dossier Context
|
||||
/epd/clients/[id] → Client dashboard (dossier overzicht)
|
||||
/epd/clients/[id]/intake → Intake lijst en notities
|
||||
/epd/clients/[id]/intake/[intakeId] → Intake detail (modal/slide-in)
|
||||
/epd/clients/[id]/diagnose → Diagnose en probleemprofiel
|
||||
/epd/clients/[id]/plan → Behandelplan (SMART doelen, interventies)
|
||||
/epd/clients/[id]/reports → Client rapportage (voortgang, metrics)
|
||||
|
||||
Utility routes:
|
||||
/epd/clients/new → Nieuwe cliënt formulier
|
||||
/epd/clients/[id]/edit → Cliënt gegevens bewerken
|
||||
```
|
||||
|
||||
### Component structure:
|
||||
```
|
||||
app/epd/
|
||||
├── layout.tsx // Root EPD layout (detects context)
|
||||
├── components/
|
||||
│ ├── epd-header.tsx // Context-aware header
|
||||
│ └── epd-sidebar.tsx // Context-aware sidebar
|
||||
│
|
||||
├── dashboard/
|
||||
│ └── page.tsx // Behandelaar dashboard
|
||||
│
|
||||
├── clients/
|
||||
│ ├── page.tsx // Cliënten lijst (Level 1)
|
||||
│ ├── components/
|
||||
│ │ ├── client-list.tsx
|
||||
│ │ ├── client-search.tsx
|
||||
│ │ └── client-filters.tsx
|
||||
│ ├── new/
|
||||
│ │ └── page.tsx // Nieuwe cliënt form
|
||||
│ └── [id]/
|
||||
│ ├── layout.tsx // Client dossier layout (Level 2 context)
|
||||
│ ├── page.tsx // Client dashboard (dossier overzicht)
|
||||
│ ├── edit/
|
||||
│ │ └── page.tsx // Edit client
|
||||
│ ├── intake/
|
||||
│ │ ├── page.tsx // Intake lijst
|
||||
│ │ ├── components/
|
||||
│ │ │ ├── intake-list.tsx
|
||||
│ │ │ └── intake-editor.tsx
|
||||
│ │ └── [intakeId]/
|
||||
│ │ └── page.tsx // Intake detail (modal/slide-in)
|
||||
│ ├── diagnose/
|
||||
│ │ ├── page.tsx // Diagnose & probleemprofiel
|
||||
│ │ └── components/
|
||||
│ │ ├── dsm-categories.tsx
|
||||
│ │ └── severity-indicator.tsx
|
||||
│ ├── plan/
|
||||
│ │ ├── page.tsx // Behandelplan
|
||||
│ │ └── components/
|
||||
│ │ ├── smart-goals.tsx
|
||||
│ │ ├── interventions.tsx
|
||||
│ │ └── plan-generator.tsx
|
||||
│ └── reports/
|
||||
│ ├── page.tsx // Client rapportage
|
||||
│ └── components/
|
||||
│ ├── progress-chart.tsx
|
||||
│ └── metrics-dashboard.tsx
|
||||
│
|
||||
├── agenda/
|
||||
│ └── page.tsx // Behandelaar agenda
|
||||
│
|
||||
└── reports/
|
||||
└── page.tsx // BI rapportage (behandelaar)
|
||||
```
|
||||
|
||||
### Key Implementation Details:
|
||||
|
||||
**app/epd/layout.tsx:**
|
||||
- Detects current context (Level 1 vs Level 2) based on URL
|
||||
- Passes context to EPDSidebar and EPDHeader
|
||||
- Manages global state for selected client
|
||||
|
||||
**app/epd/clients/[id]/layout.tsx:**
|
||||
- Wraps all client dossier pages
|
||||
- Fetches client data and provides to children
|
||||
- Ensures sidebar shows Level 2 navigation
|
||||
- Ensures header shows client dropdown
|
||||
|
||||
**Context Detection Logic:**
|
||||
```typescript
|
||||
// In app/epd/layout.tsx
|
||||
const isClientDossier = pathname.includes('/clients/') &&
|
||||
pathname.match(/\/clients\/[^\/]+\/?[^\/]*$/);
|
||||
const clientId = isClientDossier ? pathname.split('/')[3] : null;
|
||||
```
|
||||
|
||||
### Data requirements:
|
||||
- Client list: id, name, bsn, birthdate, status, last_contact
|
||||
- Dashboard: aggregate data from intakes, problem profile, treatment plan
|
||||
- Intakes: date, type, status, summary, full_notes, practitioner
|
||||
- Problem profile: severity, diagnoses, notes
|
||||
- Treatment plan: goals, interventions, status
|
||||
- Appointments: date, type, notes
|
||||
|
||||
---
|
||||
|
||||
## Out of Scope for MVP
|
||||
- Mobile responsive design
|
||||
- Dark mode
|
||||
- Multi-user roles/permissions
|
||||
- Advanced filtering (beyond search)
|
||||
- Bulk actions
|
||||
- Export functionality
|
||||
- Calendar integration
|
||||
- Notifications system
|
||||
- Audit logs
|
||||
- Custom fields
|
||||
- Templates for intakes/plans
|
||||
|
||||
These can be added post-MVP based on user feedback.
|
||||
@@ -1,802 +0,0 @@
|
||||
# Mini-ECD Interface Mocks & User Flow
|
||||
|
||||
## Navigation Architecture: Two-Level System
|
||||
|
||||
**LEVEL 1: Behandelaar Context** - Praktijkbeheerder overstijgend
|
||||
- Dashboard → Behandelaar overzicht (caseload, taken, berichten)
|
||||
- Cliënten → Zoeken, filteren, recent bekeken
|
||||
- Agenda → Behandelaar agenda (alle afspraken)
|
||||
- Rapportage → BI dashboards (KPI's, statistieken)
|
||||
|
||||
**LEVEL 2: Client Dossier Context** - Individuele cliënt focus
|
||||
- Dashboard → Dossier overzicht (laatste info, afspraken)
|
||||
- Intake → Gesprekken en notities
|
||||
- Diagnose → DSM-classificatie, probleemprofiel
|
||||
- Behandelplan → SMART doelen, interventies
|
||||
- Rapportage → Client voortgang en metrics
|
||||
|
||||
## User Flow Overview
|
||||
```
|
||||
START: Behandelaar Dashboard (Level 1)
|
||||
↓
|
||||
[Sidebar: Dashboard | Cliënten | Agenda | Rapportage]
|
||||
↓
|
||||
Klik "Cliënten"
|
||||
↓
|
||||
[Cliënten Lijst met zoek/filter] ←────────────────┐
|
||||
↓ (klik op cliënt rij) │
|
||||
↓ │
|
||||
⚡ CONTEXT SWITCH naar Level 2 ⚡ │
|
||||
↓ │
|
||||
[Sidebar verandert] │
|
||||
[Header toont: "Bas Jansen ▼"] │
|
||||
↓ │
|
||||
[Client Dashboard - Bas Jansen] ←──────┐ │
|
||||
↓ │ │
|
||||
[Sidebar: ← Cliënten | Dashboard | Intake | ... ]│
|
||||
↓ │ │
|
||||
├─→ [Intake] │ │
|
||||
├─→ [Diagnose] │ │
|
||||
├─→ [Behandelplan] │ │
|
||||
└─→ [Rapportage] │ │
|
||||
↓ │ │
|
||||
(sidebar menu switch binnen dossier)─┘ │
|
||||
↓ │
|
||||
(klik "← Cliënten" in sidebar)────────────────┘
|
||||
↓
|
||||
⚡ CONTEXT SWITCH terug naar Level 1 ⚡
|
||||
↓
|
||||
[Terug naar Cliënten Lijst]
|
||||
↓
|
||||
(header dropdown "Bas Jansen ▼") → Quick switch naar andere client
|
||||
↓
|
||||
[Client Dashboard - Anna de Vries]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## LEVEL 1 MOCKS: Behandelaar Context
|
||||
|
||||
---
|
||||
|
||||
## Mock 1A: Behandelaar Dashboard (Entry Point)
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD [Zoek cliënt...] │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
┌─────────────┬──────────────────────────────────────────────────┐
|
||||
│ │ │
|
||||
│ Dashboard ◄ │ Dashboard │
|
||||
│ Cliënten │ Welkom terug, Dr. van den Berg │
|
||||
│ Agenda │ │
|
||||
│ Rapportage │ ┌──────────────┬──────────────┬──────────────┐ │
|
||||
│ │ │ Caseload │ Aandachts- │ Berichten │ │
|
||||
│ │ │ 24 actief │ punten: 3 │ 2 nieuw │ │
|
||||
│ │ │ 2 wachtlijst │ │ │ │
|
||||
│ │ └──────────────┴──────────────┴──────────────┘ │
|
||||
│ │ │
|
||||
│ │ Behandelplannen concept: │
|
||||
│ │ • Bas Jansen - Review nodig │
|
||||
│ │ • Anna de Vries - Nog opstellen │
|
||||
│ │ │
|
||||
│ │ Aankomende afspraken (vandaag): │
|
||||
│ │ • 14:00 - Peter Smit (Intake) │
|
||||
│ │ • 16:30 - Bas Jansen (Sessie 3) │
|
||||
│ │ │
|
||||
└─────────────┴──────────────────────────────────────────────────┘
|
||||
|
||||
User actions:
|
||||
→ Bekijk caseload overzicht en statistieken
|
||||
→ Klik op aandachtspunt: navigeer naar relevante pagina
|
||||
→ Klik op client naam: navigeer naar client dossier (Level 2 switch)
|
||||
→ Sidebar navigatie naar andere Level 1 schermen
|
||||
|
||||
Note: Detailed content to be further defined.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mock 1B: Cliënten Lijst
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD [Zoek cliënt...] │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
┌─────────────┬──────────────────────────────────────────────────┐
|
||||
│ │ │
|
||||
│ Dashboard │ Cliënten [+ Nieuwe Cliënt] │
|
||||
│ Cliënten ◄ │ │
|
||||
│ Agenda │ [Zoek op naam, BSN, of cliënt ID...........] │
|
||||
│ Rapportage │ [Filters: Afdeling ▼ | Team ▼ | Status ▼] │
|
||||
│ │ │
|
||||
│ │ Recent bekeken: │
|
||||
│ │ [Bas J.] [Anna dV.] [Peter S.] │
|
||||
│ │ │
|
||||
│ │ Naam ID Geb Status │
|
||||
│ │ ──────────────────────────────────────── │
|
||||
│ │ Bas Jansen CL0002 20-11-1992 ● Actief │
|
||||
│ │ Anna de Vries CL0001 15-03-1988 ● Actief │
|
||||
│ │ Peter Smit CL0003 22-07-1995 ● Wachtlijst │
|
||||
│ │ Maria Jansen CL0004 11-09-1990 ● Actief │
|
||||
│ │ │
|
||||
│ │ │
|
||||
└─────────────┴──────────────────────────────────────────────────┘
|
||||
|
||||
User actions:
|
||||
→ Type in zoekbalk: filters lijst real-time (naam, BSN, ID, geboortedatum)
|
||||
→ Selecteer filters: Afdeling, Team, Status
|
||||
→ Klik recent bekeken: snel naar die client
|
||||
→ Klik op rij (bijv. Bas Jansen): ⚡ CONTEXT SWITCH → Client Dossier (Level 2)
|
||||
→ Klik [+ Nieuwe Cliënt]: open modal/form om nieuwe cliënt toe te voegen
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mock 1C: Behandelaar Agenda
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD [Zoek cliënt...] │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
┌─────────────┬──────────────────────────────────────────────────┐
|
||||
│ │ │
|
||||
│ Dashboard │ Agenda [+ Nieuwe Afspraak] │
|
||||
│ Cliënten │ Week 46 | 13-19 Nov 2025 [< Vorige >]│
|
||||
│ Agenda ◄ │ │
|
||||
│ Rapportage │ [Kalender weergave placeholder] │
|
||||
│ │ │
|
||||
│ │ Vandaag - 19 november 2025: │
|
||||
│ │ ┌────────────────────────────────────────────┐ │
|
||||
│ │ │ 14:00-15:00 Peter Smit - Intake │ │
|
||||
│ │ │ 16:30-17:30 Bas Jansen - Sessie 3 │ │
|
||||
│ │ └────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ Morgen - 20 november: │
|
||||
│ │ ┌────────────────────────────────────────────┐ │
|
||||
│ │ │ 10:00-11:00 Anna de Vries - Evaluatie │ │
|
||||
│ │ └────────────────────────────────────────────┘ │
|
||||
└─────────────┴──────────────────────────────────────────────────┘
|
||||
|
||||
User actions:
|
||||
→ Bekijk agenda (week/maand weergave)
|
||||
→ Klik op afspraak: bekijk details of navigeer naar client dossier
|
||||
→ Klik [+ Nieuwe Afspraak]: open afspraak formulier
|
||||
→ Navigeer tussen weken met [< >] knoppen
|
||||
|
||||
Note: Detailed calendar component to be specified.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mock 1D: Behandelaar Rapportage
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD [Zoek cliënt...] │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
┌─────────────┬──────────────────────────────────────────────────┐
|
||||
│ │ │
|
||||
│ Dashboard │ Rapportage [Exporteer PDF] │
|
||||
│ Cliënten │ Overzicht praktijk statistieken │
|
||||
│ Agenda │ │
|
||||
│ Rapportage◄ │ ┌──────────────┬──────────────┬──────────────┐ │
|
||||
│ │ │ Totaal │ Gemiddelde │ Wachtlijst │ │
|
||||
│ │ │ Cliënten │ Behandel- │ Wachttijd │ │
|
||||
│ │ │ 26 │ duur: 12 wk │ 2 weken │ │
|
||||
│ │ └──────────────┴──────────────┴──────────────┘ │
|
||||
│ │ │
|
||||
│ │ [Graph: Cliënten over tijd] │
|
||||
│ │ [Graph: Behandelduur distributie] │
|
||||
│ │ [Graph: Diagnose categorieën] │
|
||||
│ │ │
|
||||
└─────────────┴──────────────────────────────────────────────────┘
|
||||
|
||||
User actions:
|
||||
→ Bekijk BI dashboards en KPI's
|
||||
→ Interactie met grafieken (zoom, filter)
|
||||
→ Klik [Exporteer PDF]: download rapport
|
||||
→ Filter op periode, afdeling, team
|
||||
|
||||
Note: Detailed BI components and metrics to be defined.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## LEVEL 2 MOCKS: Client Dossier Context
|
||||
|
||||
**Context:** User heeft op een cliënt geklikt in de cliëntenlijst
|
||||
**State:** Sidebar en Header zijn veranderd naar client-specifieke weergave
|
||||
|
||||
---
|
||||
|
||||
## Mock 2A: Client Dashboard (Dossier Overzicht - Bas Jansen)
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD Bas Jansen ▼ [Zoek cliënt...] │
|
||||
│ ID: CL0002 | Geb: 20-11-1992 │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
┌─────────────┬──────────────────────────────────────────────────┐
|
||||
│ │ │
|
||||
│ ← Cliënten │ Dossier Overzicht │
|
||||
│ ───────── │ │
|
||||
│ Dashboard ◄ │ ┌──────────────┬──────────────┬──────────────┐ │
|
||||
│ Intake │ │Cliëntinfo │Laatste Intake│Diagnose │ │
|
||||
│ Diagnose │ │ │ │ │ │
|
||||
│ Behandel │ │ID: CL0002 │12-10-2023 │Ernst: Hoog ● │ │
|
||||
│ Rapportage │ │Naam: Bas J. │14:30 │Angststoornis │ │
|
||||
│ │ │Geb: 20-11-92 │ │Panietstoornis│ │
|
||||
│ │ │Leeftijd: 31 │"Bas komt op │met agorafobie│ │
|
||||
│ │ │Verz: [naam] │gesprek..." │ │ │
|
||||
│ │ │BSN: [nummer] │ │ │ │
|
||||
│ │ │ │Bekijk → │Bekijk → │ │
|
||||
│ │ └──────────────┴──────────────┴──────────────┘ │
|
||||
│ │ │
|
||||
│ │ ┌────────────────────────────────────────────┐ │
|
||||
│ │ │ Behandelplan Status: Concept │ │
|
||||
│ │ │ │ │
|
||||
│ │ │ SMART Doelen (3): │ │
|
||||
│ │ │ • Verminderen paniekeaanvallen │ │
|
||||
│ │ │ • Uitbreiden sociale activiteiten │ │
|
||||
│ │ │ • Verbeteren coping strategieën │ │
|
||||
│ │ │ │ │
|
||||
│ │ │ Interventies: CGT, Exposure therapie │ │
|
||||
│ │ │ Bekijk plan → │ │
|
||||
│ │ └────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ ┌────────────────────────────────────────────┐ │
|
||||
│ │ │ Afspraken │ │
|
||||
│ │ │ │ │
|
||||
│ │ │ Afgelopen Afspraak │ │
|
||||
│ │ │ │ 14-11-2025, 16:26 - Intake (60 min) │ │
|
||||
│ │ │ │ │
|
||||
│ │ │ Komende Afspraken │ │
|
||||
│ │ │ │ 22-11-2025, 16:26 - Psycho-educatie │ │
|
||||
│ │ │ │ 29-11-2025, 16:26 - Exposure therapie │ │
|
||||
│ │ │ │ 06-12-2025, 16:26 - Evaluatie gesprek │ │
|
||||
│ │ └────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
└─────────────┴──────────────────────────────────────────────────┘
|
||||
|
||||
User actions:
|
||||
→ Klik "← Cliënten": ⚡ CONTEXT SWITCH terug naar Level 1 (cliëntenlijst)
|
||||
→ Klik "Bas Jansen ▼": dropdown met recente cliënten voor quick switch
|
||||
→ Type in [Zoek cliënt]: autocomplete zoeken, direct switchen naar andere client
|
||||
→ Klik sidebar item (bijv. Intake): navigeer binnen client dossier
|
||||
→ Klik "Bekijk →" links: navigeer naar detail sectie
|
||||
→ Klik [+ Maak behandelplan]: open behandelplan wizard (als leeg)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mock 2B: Intake (Client Dossier - Bas Jansen)
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD Bas Jansen ▼ [Zoek cliënt...] │
|
||||
│ ID: CL0002 | Geb: 20-11-1992 │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
┌─────────────┬──────────────────────────────────────────────────┐
|
||||
│ │ │
|
||||
│ ← Cliënten │ Intake [+ Nieuwe Intake] │
|
||||
│ ───────── │ │
|
||||
│ Dashboard │ Datum Type Status Samenvatting │
|
||||
│ Intake ◄ │ ───────────────────────────────────────────── │
|
||||
│ Diagnose │ │
|
||||
│ Behandel │ 12-10-2023 Intake ●Afgerond │
|
||||
│ Rapportage │ 14:30 gesprek │
|
||||
│ │ Eerste intake. Cliënt presenteert │
|
||||
│ │ zich met angst- en paniekkl... │
|
||||
│ │ [Bekijk] │
|
||||
│ │ ───────────────────────────────────────────────│
|
||||
│ │ │
|
||||
│ │ 05-10-2023 Telefonisch ●Afgerond │
|
||||
│ │ 10:15 intake │
|
||||
│ │ Korte telefonische screening. │
|
||||
│ │ Doorverwijzing naar intake... │
|
||||
│ │ [Bekijk] │
|
||||
│ │ ───────────────────────────────────────────────│
|
||||
│ │ │
|
||||
│ │ 28-09-2023 Intake ●Afgerond │
|
||||
│ │ 16:00 gesprek │
|
||||
│ │ Geen show. Cliënt niet verschenen, │
|
||||
│ │ geen afmelding... │
|
||||
│ │ [Bekijk] │
|
||||
│ │ │
|
||||
└─────────────┴──────────────────────────────────────────────────┘
|
||||
|
||||
User actions:
|
||||
→ Klik [+ Nieuwe Intake]: open TipTap editor voor nieuwe intake notitie
|
||||
→ Klik [Bekijk]: open intake detail slide-in panel (zie Mock 2F)
|
||||
→ Hover over rij: highlight, [Bekijk] button wordt prominent
|
||||
→ Sidebar navigatie: blijf binnen client dossier context
|
||||
→ Klik "← Cliënten": terug naar Level 1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mock 2C: Diagnose (Client Dossier - Bas Jansen)
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD Bas Jansen ▼ [Zoek cliënt...] │
|
||||
│ ID: CL0002 | Geb: 20-11-1992 │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
┌─────────────┬──────────────────────────────────────────────────┐
|
||||
│ │ │
|
||||
│ ← Cliënten │ Diagnose & Probleemprofiel [AI Analyse] │
|
||||
│ ───────── │ │
|
||||
│ Dashboard │ DSM-light Categorieën: │
|
||||
│ Intake │ │
|
||||
│ Diagnose ◄ │ ┌──────────┬──────────┬──────────┐ │
|
||||
│ Behandel │ │ Stemming │ Angst │ Gedrag │ │
|
||||
│ Rapportage │ │ ○○○○○ │ ●●●●○ │ ○○○○○ │ │
|
||||
│ │ │ Geen │ Hoog │ Geen │ │
|
||||
│ │ └──────────┴──────────┴──────────┘ │
|
||||
│ │ ┌──────────┬──────────┬──────────┐ │
|
||||
│ │ │ Middelen │ Cognitief│ Context │ │
|
||||
│ │ │ ○○○○○ │ ○○○○○ │ ●●○○○ │ │
|
||||
│ │ │ Geen │ Geen │ Middel │ │
|
||||
│ │ └──────────┴──────────┴──────────┘ │
|
||||
│ │ │
|
||||
│ │ Hoofddiagnose: │
|
||||
│ │ ┌────────────────────────────────────────────┐ │
|
||||
│ │ │ Panietstoornis met agorafobie │ │
|
||||
│ │ │ Ernst: Hoog ●●●●○ │ │
|
||||
│ │ │ │ │
|
||||
│ │ │ Bron: Intake 12-10-2023 │ │
|
||||
│ │ │ Observaties: Frequente aanvallen, sterke │ │
|
||||
│ │ │ vermijding openbare ruimtes │ │
|
||||
│ │ └────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
└─────────────┴──────────────────────────────────────────────────┘
|
||||
|
||||
User actions:
|
||||
→ Klik [AI Analyse]: genereer/update diagnose classificatie
|
||||
→ Bekijk DSM-categorieën met ernst indicatie
|
||||
→ Klik op categorie: bekijk details en bronnen
|
||||
→ Bewerk diagnose handmatig indien nodig
|
||||
|
||||
Note: Week 3 feature - AI-powered classification
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mock 2D: Behandelplan (Client Dossier - Bas Jansen)
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD Bas Jansen ▼ [Zoek cliënt...] │
|
||||
│ ID: CL0002 | Geb: 20-11-1992 │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
┌─────────────┬──────────────────────────────────────────────────┐
|
||||
│ │ │
|
||||
│ ← Cliënten │ Behandelplan [Genereer Plan] [v1▼] │
|
||||
│ ───────── │ Status: Actief | Laatste update: 15-10-2023 │
|
||||
│ Dashboard │ │
|
||||
│ Intake │ 1. SMART Doelen │
|
||||
│ Diagnose │ ┌────────────────────────────────────────────┐ │
|
||||
│ Behandel ◄ │ │ Doel 1: Verminderen paniekeaanvallen │ │
|
||||
│ Rapportage │ │ Van 3x/week naar max 1x/week binnen 8 wk │ │
|
||||
│ │ │ Voortgang: ████████░░░░ 67% │ │
|
||||
│ │ │ │ │
|
||||
│ │ │ Doel 2: Uitbreiden sociale activiteiten │ │
|
||||
│ │ │ Zelfstandig boodschappen binnen 6 weken │ │
|
||||
│ │ │ Voortgang: ████░░░░░░░░ 33% │ │
|
||||
│ │ └────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ 2. Interventies │
|
||||
│ │ ┌────────────────────────────────────────────┐ │
|
||||
│ │ │ • CGT - Cognitieve herstructurering │ │
|
||||
│ │ │ • Exposure therapie (gradueel) │ │
|
||||
│ │ │ • Ontspanningstechnieken │ │
|
||||
│ │ └────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ 3. Frequentie: Wekelijks, 12 sessies │
|
||||
│ │ 4. Meetmomenten: Week 4, 8, 12 │
|
||||
│ │ │
|
||||
└─────────────┴──────────────────────────────────────────────────┘
|
||||
|
||||
User actions:
|
||||
→ Klik [Genereer Plan]: AI genereert behandelplan op basis van intake+diagnose
|
||||
→ Klik [v1▼]: bekijk of wissel tussen plan versies
|
||||
→ Bewerk doelen, interventies, frequentie
|
||||
→ Track voortgang per doel
|
||||
→ Exporteer plan naar PDF
|
||||
|
||||
Note: Week 3 feature - AI plan generator
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mock 2E: Rapportage (Client Dossier - Bas Jansen)
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD Bas Jansen ▼ [Zoek cliënt...] │
|
||||
│ ID: CL0002 | Geb: 20-11-1992 │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
┌─────────────┬──────────────────────────────────────────────────┐
|
||||
│ │ │
|
||||
│ ← Cliënten │ Rapportage & Voortgang [Exporteer PDF] │
|
||||
│ ───────── │ │
|
||||
│ Dashboard │ ┌──────────────┬──────────────┬──────────────┐ │
|
||||
│ Intake │ │ Behandel- │ Sessies │ Algehele │ │
|
||||
│ Diagnose │ │ duur │ Voltooid │ Voortgang │ │
|
||||
│ Behandel │ │ 8 weken │ 6 van 12 │ 67% │ │
|
||||
│ Rapportage◄ │ └──────────────┴──────────────┴──────────────┘ │
|
||||
│ │ │
|
||||
│ │ Doelvoortgang over tijd: │
|
||||
│ │ [Line graph showing progress on goals] │
|
||||
│ │ │
|
||||
│ │ Sessie overzicht: │
|
||||
│ │ ┌────────────────────────────────────────────┐ │
|
||||
│ │ │ 12-10 Intake ✓ Aanwezig │ │
|
||||
│ │ │ 19-10 Sessie 1 ✓ Aanwezig │ │
|
||||
│ │ │ 26-10 Sessie 2 ✓ Aanwezig │ │
|
||||
│ │ │ 02-11 Sessie 3 ✓ Aanwezig │ │
|
||||
│ │ │ 09-11 Sessie 4 ✗ No-show │ │
|
||||
│ │ │ 16-11 Sessie 5 ✓ Aanwezig │ │
|
||||
│ │ └────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
└─────────────┴──────────────────────────────────────────────────┘
|
||||
|
||||
User actions:
|
||||
→ Bekijk voortgang visualisaties
|
||||
→ Filter op periode, doel, interventie
|
||||
→ Klik [Exporteer PDF]: download rapport voor dossier
|
||||
→ Bekijk attendance en sessie details
|
||||
|
||||
Note: Content and metrics to be further defined.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mock 2F: Intake Detail (Slide-in Panel)
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD Bas Jansen ▼ [Zoek cliënt...] │
|
||||
│ ID: CL0002 | Geb: 20-11-1992 │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
┌─────────────┬──────────────────────────┬───────────────────────┐
|
||||
│ │ │ │
|
||||
│ ← Cliënten │ Intake [+ Nieuwe] │ Intake - 12-10-2023 ✕ │
|
||||
│ ───────── │ │ ─────────────────────│
|
||||
│ Dashboard │ Datum Type Status │ Algemene informatie │
|
||||
│ Intake ◄ │ ─────────────────── │ │
|
||||
│ Diagnose │ │ Datum & tijd: │
|
||||
│ Behandel │ 12-10 Intake ●Afgr. │ 12-10-2023, 14:30 │
|
||||
│ Rapportage │ [row highlighted] │ │
|
||||
│ │ [Bekijk] │ Type: Intake gesprek │
|
||||
│ │ ───────────────── │ Behandelaar: [naam] │
|
||||
│ │ │ Duur: 60 minuten │
|
||||
│ │ 05-10 Telef. ●Afgr. │ │
|
||||
│ │ [Bekijk] │ ─────────────────── │
|
||||
│ │ ───────────────── │ │
|
||||
│ │ │ Gespreksnotities │
|
||||
│ │ 28-09 Intake ●Afgr. │ │
|
||||
│ │ [Bekijk] │ Bas komt op gesprek │
|
||||
│ │ │ vanwege spannings- │
|
||||
│ │ │ klachten en paniek- │
|
||||
│ │ │ aanvallen. Hij be- │
|
||||
│ │ │ schrijft situaties │
|
||||
│ │ │ in het openbaar... │
|
||||
│ │ │ │
|
||||
│ │ │ Anamnese: Klachten │
|
||||
│ │ │ bestaan sinds 1 jaar │
|
||||
│ │ │ Begonnen na stress- │
|
||||
│ │ │ volle periode... │
|
||||
│ │ │ │
|
||||
│ │ │ [scrollable content] │
|
||||
│ │ │ │
|
||||
│ │ │ ─────────────────── │
|
||||
│ │ │ │
|
||||
│ │ │ [Verwijderen] [Bewerken]│
|
||||
│ │ │ │
|
||||
└─────────────┴──────────────────────────┴───────────────────────┘
|
||||
|
||||
User actions:
|
||||
→ Klik ✕: sluit panel, terug naar Intakes lijst
|
||||
→ Klik [Bewerken]: open intake in edit mode
|
||||
→ Klik [Verwijderen]: confirmatie dialog → verwijder intake
|
||||
→ Scroll in panel: bekijk volledige notities
|
||||
→ Klik buiten panel (op main content): sluit panel
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mock 2G: Client Switcher (Dropdown from Header)
|
||||
|
||||
**Context:** Alleen beschikbaar in Level 2 (Client Dossier Context)
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD ┌─────────────────────────┐ [Zoek cliënt...] │
|
||||
│ │ Bas Jansen ▼ │ │
|
||||
│ │ ID: CL0002 | 20-11-1992 │ │
|
||||
│ ├─────────────────────────┤ │
|
||||
│ │ Recente cliënten: │ │
|
||||
│ │ ───────────────────── │ │
|
||||
│ │ ● Anna de Vries │ │
|
||||
│ │ CL0001 | 15-03-1988 │ │
|
||||
│ │ │ │
|
||||
│ │ ● Peter Smit │ │
|
||||
│ │ CL0003 | 22-07-1995 │ │
|
||||
│ │ │ │
|
||||
│ │ ● Maria Jansen │ │
|
||||
│ │ CL0004 | 11-09-1990 │ │
|
||||
│ │ │ │
|
||||
│ │ ───────────────────── │ │
|
||||
│ │ [Alle cliënten →] │ │
|
||||
│ └─────────────────────────┘ │
|
||||
└────────────────────────────────────────────────────────────────┘
|
||||
|
||||
User actions:
|
||||
→ Klik op naam in dropdown: switch naar die cliënt (blijf op zelfde sectie)
|
||||
Bijv: Op Intake pagina van Bas → klik Anna → ga naar Intake pagina van Anna
|
||||
→ Klik [Alle cliënten →]: ⚡ CONTEXT SWITCH naar Level 1 (cliëntenlijst)
|
||||
→ Klik buiten dropdown: sluit dropdown
|
||||
→ Type in zoekbalk: autocomplete met alle cliënten
|
||||
|
||||
Note: Recent cliënten worden automatisch bijgewerkt bij navigatie
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete User Flow Scenarios
|
||||
|
||||
### Scenario 1: Start applicatie → Client dossier bekijken
|
||||
```
|
||||
1. User logt in en start op [Behandelaar Dashboard] (Level 1)
|
||||
2. Bekijk caseload overzicht en aandachtspunten
|
||||
3. Klik sidebar "Cliënten"
|
||||
4. Navigeer naar [Cliënten Lijst]
|
||||
5. Type "Bas" in zoekbalk, zie gefilterde resultaten
|
||||
6. Klik op "Bas Jansen" rij
|
||||
7. ⚡ CONTEXT SWITCH naar Level 2
|
||||
8. Sidebar verandert: "← Cliënten | Dashboard | Intake | ..."
|
||||
9. Header toont: "Bas Jansen ▼ | ID: CL0002 | Geb: 20-11-1992"
|
||||
10. Bekijk [Client Dashboard - Bas Jansen] met overzicht
|
||||
```
|
||||
|
||||
### Scenario 2: Nieuwe intake toevoegen
|
||||
```
|
||||
1. User zit in [Client Dashboard - Bas Jansen] (Level 2)
|
||||
2. Klik sidebar "Intake"
|
||||
3. Navigeer naar [Intake - Bas Jansen]
|
||||
4. Klik [+ Nieuwe Intake]
|
||||
5. TipTap editor opent voor nieuwe notitie
|
||||
6. Type gespreknotities met rich text formatting
|
||||
7. Klik [AI Samenvatting] (optioneel, Week 3 feature)
|
||||
8. AI genereert samenvatting in 5 seconden
|
||||
9. Klik [Opslaan]
|
||||
10. Nieuwe intake verschijnt bovenaan lijst met status badge
|
||||
```
|
||||
|
||||
### Scenario 3: Tussen cliënten switchen tijdens werk
|
||||
```
|
||||
1. User zit in [Intake - Bas Jansen] (Level 2)
|
||||
2. Klik "Bas Jansen ▼" in header center
|
||||
3. Dropdown opent met recente cliënten
|
||||
4. Klik "Anna de Vries"
|
||||
5. Blijf in Level 2, navigeer naar [Intake - Anna de Vries]
|
||||
6. Sidebar blijft client-specifiek, header update naar Anna's gegevens
|
||||
```
|
||||
|
||||
### Scenario 4: Van client dossier terug naar behandelaar overzicht
|
||||
```
|
||||
1. User zit in [Behandelplan - Bas Jansen] (Level 2)
|
||||
2. Klaar met werk aan behandelplan
|
||||
3. Klik "← Cliënten" in sidebar
|
||||
4. ⚡ CONTEXT SWITCH terug naar Level 1
|
||||
5. Sidebar verandert: "Dashboard | Cliënten | Agenda | Rapportage"
|
||||
6. Header center wordt leeg (geen client dropdown)
|
||||
7. Navigeer naar [Cliënten Lijst]
|
||||
8. User kan nieuwe client selecteren of naar ander Level 1 scherm
|
||||
```
|
||||
|
||||
### Scenario 5: Behandelplan genereren met AI
|
||||
```
|
||||
1. User zit in [Client Dashboard - Bas Jansen] (Level 2)
|
||||
2. Bekijk diagnose card: "Ernst: Hoog - Panietstoornis"
|
||||
3. Bekijk behandelplan card: "Geen behandelplan gevonden"
|
||||
4. Klik [+ Maak behandelplan]
|
||||
5. Navigeer naar [Behandelplan - Bas Jansen]
|
||||
6. Klik [Genereer Plan] button
|
||||
7. AI analyseert intake notities + diagnose
|
||||
8. Plan wordt gegenereerd met SMART doelen en interventies
|
||||
9. User beoordeelt en past aan indien nodig
|
||||
10. Klik [Opslaan als Concept] of [Publiceren]
|
||||
11. Plan verschijnt op Client Dashboard met status badge
|
||||
```
|
||||
|
||||
### Scenario 6: Intake detail bekijken en bewerken
|
||||
```
|
||||
1. User zit in [Intake - Bas Jansen] (Level 2)
|
||||
2. Klik [Bekijk] bij intake van 12-10-2023
|
||||
3. Slide-in panel opent aan rechterkant (400px breed)
|
||||
4. Bekijk algemene informatie en volledige gespreksnotities
|
||||
5. Scroll door notities, lees AI samenvatting (indien aanwezig)
|
||||
6. Klik [Bewerken] in panel footer
|
||||
7. TipTap editor opent in bewerkmodus
|
||||
8. Wijzig notities, voeg toe, pas formatting aan
|
||||
9. Klik [Opslaan]
|
||||
10. Panel sluit, terug naar [Intake - Bas Jansen] lijst
|
||||
11. Gewijzigde intake toont "Bewerkt" timestamp
|
||||
```
|
||||
|
||||
### Scenario 7: Quick search tussen contexten
|
||||
```
|
||||
1. User zit in [Behandelaar Dashboard] (Level 1)
|
||||
2. Type "CL0002" in header zoekbalk
|
||||
3. Autocomplete toont "Bas Jansen - CL0002 | 20-11-1992"
|
||||
4. Klik op resultaat
|
||||
5. ⚡ CONTEXT SWITCH naar Level 2
|
||||
6. Navigeer direct naar [Client Dashboard - Bas Jansen]
|
||||
7. Header en sidebar passen zich aan
|
||||
|
||||
Alternative vanaf Level 2:
|
||||
1. User zit in [Diagnose - Anna de Vries] (Level 2)
|
||||
2. Type "Peter" in header zoekbalk
|
||||
3. Autocomplete toont "Peter Smit - CL0003"
|
||||
4. Klik op resultaat
|
||||
5. Blijf in Level 2, navigeer naar [Diagnose - Peter Smit]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Navigation Rules
|
||||
|
||||
### Context Switching (Level 1 ↔ Level 2):
|
||||
|
||||
**Van Level 1 naar Level 2:**
|
||||
- Trigger: Klik op een client rij in cliëntenlijst
|
||||
- Effect: Sidebar verandert naar client-specifiek menu
|
||||
- Effect: Header center toont client dropdown "Bas Jansen ▼"
|
||||
- Navigeert naar: Client Dashboard (dossier overzicht)
|
||||
|
||||
**Van Level 2 naar Level 1:**
|
||||
- Trigger: Klik "← Cliënten" button in sidebar
|
||||
- Effect: Sidebar verandert terug naar behandelaar menu
|
||||
- Effect: Header center wordt leeg/disabled
|
||||
- Navigeert naar: Cliënten Lijst
|
||||
- Keyboard shortcut: Esc (of Alt+C)
|
||||
|
||||
### Sidebar Behavior:
|
||||
|
||||
**In Level 1 (Behandelaar Context):**
|
||||
- Menu items: Dashboard | Cliënten | Agenda | Rapportage
|
||||
- Geen "← Cliënten" button
|
||||
- Active state op huidige pagina
|
||||
- Navigatie blijft binnen Level 1
|
||||
|
||||
**In Level 2 (Client Dossier Context):**
|
||||
- "← Cliënten" button bovenaan (back to Level 1)
|
||||
- Divider
|
||||
- Menu items: Dashboard | Intake | Diagnose | Behandelplan | Rapportage
|
||||
- Active state op huidige sectie
|
||||
- Navigatie blijft binnen hetzelfde client dossier
|
||||
- Switchen tussen clients via header dropdown blijft in Level 2
|
||||
|
||||
### Header Client Dropdown:
|
||||
|
||||
**Alleen beschikbaar in Level 2:**
|
||||
- Toont geselecteerde client: "Bas Jansen ▼"
|
||||
- Sub-text: "ID: CL0002 | Geb: 20-11-1992"
|
||||
- Dropdown inhoud:
|
||||
- Recente cliënten (laatste 3-5 bezocht)
|
||||
- Divider
|
||||
- "Alle cliënten →" link (navigeert naar Level 1)
|
||||
- Switchen behoudt huidige sectie type
|
||||
- Bijv: Intake van Bas → klik Anna → Intake van Anna
|
||||
- Keyboard shortcut: Alt+K
|
||||
|
||||
**In Level 1:**
|
||||
- Geen client dropdown (of disabled/grayed out)
|
||||
- Optioneel: Behandelaar naam/info
|
||||
|
||||
### Header Zoekbalk:
|
||||
|
||||
**Beschikbaar in beide levels:**
|
||||
- Live autocomplete tijdens typen
|
||||
- Zoekt op: naam, BSN, cliënt ID, geboortedatum
|
||||
- Toont: Naam - ID | Geboortedatum in resultaten
|
||||
- Keyboard shortcut: Cmd/Ctrl+K
|
||||
|
||||
**Gedrag in Level 1:**
|
||||
- Enter of klik op resultaat: Switch naar Level 2, navigeer naar Client Dashboard
|
||||
|
||||
**Gedrag in Level 2:**
|
||||
- Enter of klik op resultaat: Blijf in Level 2, switch naar gekozen client
|
||||
- Behoudt huidige sectie (blijf op Intake als je op Intake zat)
|
||||
|
||||
### Active State Indicators:
|
||||
|
||||
**Sidebar:**
|
||||
- Highlighted background (licht blauw/grijs)
|
||||
- Bold text
|
||||
- Left border accent (3px teal/blauw)
|
||||
- Icon kleurt mee
|
||||
|
||||
**Tab/Section:**
|
||||
- Visual feedback dat huidige sectie actief is
|
||||
- Breadcrumb (optioneel) toont pad
|
||||
|
||||
### URL Structure & Browser Back:
|
||||
|
||||
**URL patterns:**
|
||||
```
|
||||
Level 1:
|
||||
/epd/dashboard → Behandelaar dashboard
|
||||
/epd/clients → Cliënten lijst
|
||||
/epd/agenda → Behandelaar agenda
|
||||
/epd/reports → Rapportage/BI
|
||||
|
||||
Level 2:
|
||||
/epd/clients/CL0002 → Client dashboard
|
||||
/epd/clients/CL0002/intake → Intake sectie
|
||||
/epd/clients/CL0002/diagnose → Diagnose sectie
|
||||
/epd/clients/CL0002/plan → Behandelplan
|
||||
/epd/clients/CL0002/reports → Client rapportage
|
||||
```
|
||||
|
||||
**Browser back button:**
|
||||
- Werkt zoals verwacht door URL geschiedenis
|
||||
- Van Level 2 terug naar vorige Level 2 pagina
|
||||
- Van Client Dashboard terug naar Cliënten Lijst (Level 1)
|
||||
- Sidebar en header passen zich automatisch aan op basis van URL
|
||||
|
||||
---
|
||||
|
||||
## State Persistence
|
||||
|
||||
### User komt terug in app:
|
||||
- Heropent laatste bezochte scherm (via localStorage of session)
|
||||
- Als dat Level 2 was: herstel client context (sidebar + header)
|
||||
- Als dat Level 1 was: toon behandelaar context
|
||||
- Als sessie verlopen: start bij [Behandelaar Dashboard] (Level 1)
|
||||
|
||||
### Browser refresh:
|
||||
- URL bepaalt welk scherm en context
|
||||
- URL parsing detecteert automatisch Level 1 vs Level 2
|
||||
- Sidebar en header worden automatisch geconfigureerd
|
||||
|
||||
**Level 1 URL's:**
|
||||
```
|
||||
/epd/dashboard → Behandelaar dashboard
|
||||
/epd/clients → Cliënten lijst
|
||||
/epd/agenda → Behandelaar agenda
|
||||
/epd/reports → BI rapportage
|
||||
```
|
||||
|
||||
**Level 2 URL's:**
|
||||
```
|
||||
/epd/clients/CL0002 → Client dashboard (Bas)
|
||||
/epd/clients/CL0002/intake → Intake van Bas
|
||||
/epd/clients/CL0002/diagnose → Diagnose van Bas
|
||||
/epd/clients/CL0002/plan → Behandelplan van Bas
|
||||
```
|
||||
|
||||
### Recent clients lijst:
|
||||
- Opgeslagen in localStorage: `recent_clients: string[]`
|
||||
- Wordt bijgewerkt bij elke client view (Level 2 entry)
|
||||
- Max 5 items
|
||||
- Gesorteerd op laatst bezocht (nieuwste bovenaan)
|
||||
- Format per item:
|
||||
```typescript
|
||||
{
|
||||
id: string; // "CL0002"
|
||||
name: string; // "Bas Jansen"
|
||||
birthDate: string; // "20-11-1992"
|
||||
lastVisited: Date; // timestamp
|
||||
}
|
||||
```
|
||||
|
||||
### Context State Management:
|
||||
- Global state tracks: `currentContext: 'behandelaar' | 'client'`
|
||||
- If context === 'client', also track: `selectedClientId: string`
|
||||
- Sidebar component subscribes to context changes
|
||||
- Header component subscribes to context + selectedClient changes
|
||||
- Context changes trigger sidebar/header re-render
|
||||
|
||||
### Scroll Position & Form State:
|
||||
- Scroll position bewaard per pagina (Level 1 en Level 2 apart)
|
||||
- Formulieren met unsaved changes: waarschuwing bij navigatie
|
||||
- TipTap editor: auto-save draft elke 30 seconden (localStorage)
|
||||
|
||||
### URL Query Parameters (optioneel):
|
||||
- Tab states: `/epd/clients/CL0002?tab=intake`
|
||||
- Filter states: `/epd/clients?status=actief&team=team-a`
|
||||
- Sorting: `/epd/clients?sortBy=name&order=asc`
|
||||
@@ -1,506 +0,0 @@
|
||||
# Bouwplan — Agenda Module
|
||||
|
||||
**Projectnaam:** Mini-EPD Agenda Module
|
||||
**Versie:** v1.0
|
||||
**Datum:** 02-12-2024
|
||||
**Auteur:** Colin
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en context
|
||||
|
||||
**Doel:** Een volledige agendafunctionaliteit bouwen voor het Mini-EPD systeem waarmee behandelaars afspraken kunnen plannen, beheren en koppelen aan EPD-documenten.
|
||||
|
||||
**Toelichting:** De agenda is een kernfunctionaliteit binnen elk EPD-systeem. Momenteel bestaat er alleen een placeholder pagina op `/epd/agenda`. Deze module bouwt voort op de bestaande `encounters` tabel (FHIR-compliant) en breidt deze uit met volledige kalenderfunctionaliteit en bidirectionele koppelingen met rapportages.
|
||||
|
||||
**Kernfunctionaliteiten:**
|
||||
- Kalenderweergaven (dag/week/werkdagen)
|
||||
- Afspraakbeheer (maken, verzetten, annuleren)
|
||||
- Patiënt-selectie bij afspraken
|
||||
- Koppeling afspraak ↔ verslag (bidirectioneel)
|
||||
|
||||
---
|
||||
|
||||
## 2. Uitgangspunten
|
||||
|
||||
### 2.1 Technische Stack
|
||||
|
||||
| Component | Technologie |
|
||||
|-----------|-------------|
|
||||
| **Frontend** | Next.js 14 (App Router) + React 18 + TypeScript |
|
||||
| **UI Components** | shadcn/ui (Radix primitives) + Tailwind CSS |
|
||||
| **Calendar Library** | FullCalendar (@fullcalendar/react) |
|
||||
| **Datepicker** | shadcn/ui Calendar (bestaand) |
|
||||
| **Database** | Supabase (PostgreSQL) |
|
||||
| **Date Handling** | date-fns (al in project) |
|
||||
| **State Management** | React Server Components + Server Actions |
|
||||
|
||||
### 2.2 Projectkaders
|
||||
|
||||
| Aspect | Waarde |
|
||||
|--------|--------|
|
||||
| **Scope** | MVP met uitbreidingsmogelijkheden |
|
||||
| **Data** | Bestaande `encounters` tabel + uitbreiding `reports` |
|
||||
| **Integratie** | Naadloos met bestaande patient/intake flows |
|
||||
| **Gebruikers** | Behandelaars (practitioners) |
|
||||
|
||||
### 2.3 Programmeer Uitgangspunten
|
||||
|
||||
**Bestaande patronen volgen:**
|
||||
- Server Actions voor mutaties (`actions.ts` per route)
|
||||
- API routes voor complexe queries
|
||||
- FHIR-compliant datastructuren
|
||||
- shadcn/ui component styling
|
||||
|
||||
**Code Quality:**
|
||||
- TypeScript strict mode
|
||||
- Zod validatie voor alle inputs
|
||||
- Error boundaries voor UI failures
|
||||
- Optimistic updates waar mogelijk
|
||||
|
||||
---
|
||||
|
||||
## 3. Epics & Stories Overzicht
|
||||
|
||||
| Epic ID | Titel | Doel | Status | Stories |
|
||||
|---------|-------|------|--------|---------|
|
||||
| E0 | Database & Types | Schema uitbreiden, types genereren | ✅ Done | 3 |
|
||||
| E1 | Calendar Views | Dag/week/werkdagen weergaven | ✅ Done | 4 |
|
||||
| E2 | Afspraak CRUD | Maken, bewerken, annuleren | ✅ Done | 5 |
|
||||
| E3 | Patiënt Integratie | Selectie, zoeken, quick-create | ✅ Done | 3 |
|
||||
| E4 | EPD Koppeling | Verslag ↔ Afspraak bidirectioneel | ✅ Done | 4 |
|
||||
| E5 | Polish & Testing | UX verfijning, edge cases | ⏳ To Do | 3 |
|
||||
|
||||
---
|
||||
|
||||
## 4. Epics & Stories (Uitwerking)
|
||||
|
||||
### Epic 0 — Database & Types
|
||||
|
||||
**Epic Doel:** Database schema uitbreiden voor report-encounter koppeling en TypeScript types updaten.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
|
||||
|----------|--------------|---------------------|--------|------------------|----|
|
||||
| E0.S1 | Migration: encounter_id toevoegen aan reports | `encounter_id` en `intake_id` kolommen bestaan, foreign keys werken | ✅ | — | 2 |
|
||||
| E0.S2 | Index toevoegen voor performance | `idx_reports_encounter`, `idx_encounters_period` indices bestaan | ✅ | E0.S1 | 1 |
|
||||
| E0.S3 | TypeScript types regenereren | `database.types.ts` bevat nieuwe kolommen | ✅ | E0.S2 | 1 |
|
||||
|
||||
**Technical Notes:**
|
||||
```sql
|
||||
-- Migration E0.S1
|
||||
ALTER TABLE reports
|
||||
ADD COLUMN encounter_id UUID REFERENCES encounters(id) ON DELETE SET NULL,
|
||||
ADD COLUMN intake_id UUID REFERENCES intakes(id) ON DELETE SET NULL;
|
||||
|
||||
-- Migration E0.S2
|
||||
CREATE INDEX idx_reports_encounter ON reports(encounter_id);
|
||||
CREATE INDEX idx_reports_intake ON reports(intake_id);
|
||||
CREATE INDEX idx_encounters_period ON encounters(period_start, period_end);
|
||||
CREATE INDEX idx_encounters_practitioner ON encounters(practitioner_id);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Epic 1 — Calendar Views
|
||||
|
||||
**Epic Doel:** Interactieve kalenderweergaven met dag, week en werkdagen views.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
|
||||
|----------|--------------|---------------------|--------|------------------|----|
|
||||
| E1.S1 | FullCalendar installatie & setup | Library geïnstalleerd, basis component rendert | ✅ | E0.S3 | 2 |
|
||||
| E1.S2 | Dag view implementeren | Uurblokken 08:00-18:00, afspraken zichtbaar | ✅ | E1.S1 | 3 |
|
||||
| E1.S3 | Week view implementeren | 7-dagen grid, drag-resize werkt | ✅ | E1.S2 | 3 |
|
||||
| E1.S4 | Werkdagen view (ma-vr) | Filter voor weekend, business hours highlight | ✅ | E1.S3 | 2 |
|
||||
|
||||
**Technical Notes:**
|
||||
```bash
|
||||
pnpm add @fullcalendar/react @fullcalendar/daygrid @fullcalendar/timegrid @fullcalendar/interaction
|
||||
```
|
||||
|
||||
**Component Structuur:**
|
||||
```
|
||||
app/epd/agenda/
|
||||
├── page.tsx # Server component, data fetching
|
||||
├── components/
|
||||
│ ├── agenda-calendar.tsx # FullCalendar wrapper (client)
|
||||
│ ├── agenda-toolbar.tsx # View switcher, date nav
|
||||
│ ├── agenda-sidebar.tsx # Mini calendar + filters
|
||||
│ └── appointment-card.tsx # Event rendering
|
||||
├── actions.ts # Server actions
|
||||
└── types.ts # Agenda-specific types
|
||||
```
|
||||
|
||||
**Styling:**
|
||||
- FullCalendar CSS overschrijven met Tailwind
|
||||
- Consistent met shadcn/ui design tokens
|
||||
- Dark mode support (later)
|
||||
|
||||
---
|
||||
|
||||
### Epic 2 — Afspraak CRUD
|
||||
|
||||
**Epic Doel:** Volledige afspraakbeheer functionaliteit.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
|
||||
|----------|--------------|---------------------|--------|------------------|----|
|
||||
| E2.S1 | Afspraak aanmaken modal | Form met alle velden, validatie, opslaan werkt | ⏳ | E1.S2 | 5 |
|
||||
| E2.S2 | Afspraak bewerken | Click op event → edit modal, wijzigingen opslaan | ⏳ | E2.S1 | 3 |
|
||||
| E2.S3 | Afspraak verzetten (drag-drop) | Drag event naar nieuwe tijd, confirm dialog | ⏳ | E2.S2 | 3 |
|
||||
| E2.S4 | Afspraak annuleren | Soft delete (status=cancelled), confirm dialog | ⏳ | E2.S2 | 2 |
|
||||
| E2.S5 | Afspraak details view | Click voor volledige info, quick actions | ⏳ | E2.S2 | 2 |
|
||||
|
||||
**Appointment Modal Fields:**
|
||||
|
||||
| Veld | Type | Verplicht | Bron |
|
||||
|------|------|-----------|------|
|
||||
| Patiënt | Patient selector | Ja | patients tabel |
|
||||
| Datum | Date picker | Ja | — |
|
||||
| Starttijd | Time picker | Ja | — |
|
||||
| Eindtijd | Time picker | Nee | — |
|
||||
| Type | Select | Ja | encounter types |
|
||||
| Locatie | Select | Nee | class_code |
|
||||
| Behandelaar | Select | Ja | practitioners |
|
||||
| Notities | Textarea | Nee | — |
|
||||
|
||||
**Appointment Types (type_code):**
|
||||
- `intake` - Intakegesprek
|
||||
- `behandeling` - Behandelsessie
|
||||
- `follow-up` - Vervolggesprek
|
||||
- `telefonisch` - Telefonisch contact
|
||||
- `huisbezoek` - Huisbezoek
|
||||
- `online` - Online consult
|
||||
- `crisis` - Crisiscontact
|
||||
- `overig` - Overig
|
||||
|
||||
**Status Flow:**
|
||||
```
|
||||
planned → in-progress → completed
|
||||
↓
|
||||
cancelled
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Epic 3 — Patiënt Integratie
|
||||
|
||||
**Epic Doel:** Naadloze patiëntselectie bij het maken van afspraken.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
|
||||
|----------|--------------|---------------------|--------|------------------|----|
|
||||
| E3.S1 | Patient search component | Zoeken op naam, BSN, clientnummer | ⏳ | E2.S1 | 3 |
|
||||
| E3.S2 | Recent patients dropdown | Laatste 5 patiënten snel selecteren | ⏳ | E3.S1 | 2 |
|
||||
| E3.S3 | Quick patient info | Naam, geboortedatum, actieve intake tonen | ⏳ | E3.S2 | 2 |
|
||||
|
||||
**Patient Selector Component:**
|
||||
```typescript
|
||||
interface PatientSelectorProps {
|
||||
value?: string; // patient_id
|
||||
onChange: (patientId: string) => void;
|
||||
showRecentPatients?: boolean;
|
||||
allowCreate?: boolean; // Future: quick create
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Epic 4 — EPD Koppeling
|
||||
|
||||
**Epic Doel:** Bidirectionele koppeling tussen afspraken en verslagen.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
|
||||
|----------|--------------|---------------------|--------|------------------|----|
|
||||
| E4.S1 | Verslag maken vanuit afspraak | Button op appointment → report composer met encounter_id | ✅ | E2.S5 | 3 |
|
||||
| E4.S2 | Afspraak koppelen vanuit verslag | In rapportage: link naar bestaande/nieuwe afspraak | ✅ | E4.S1 | 3 |
|
||||
| E4.S3 | Gekoppelde items tonen | In afspraak details: linked reports zichtbaar | ✅ | E4.S2 | 2 |
|
||||
| E4.S4 | Navigatie tussen afspraak ↔ verslag | Click-through links beide kanten | ✅ | E4.S3 | 2 |
|
||||
|
||||
**Integration Points:**
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Agenda │ │ Rapportage │
|
||||
│ │ │ │
|
||||
│ [Afspraak] │───────────────▶│ [Verslag] │
|
||||
│ └─ + Verslag │ │ └─ encounter │
|
||||
│ │◀───────────────│ └─ + Koppel │
|
||||
└─────────────────┘ └─────────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ encounters │
|
||||
│ id, patient_id, period_start, period_end, ... │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ reports │
|
||||
│ id, patient_id, encounter_id, intake_id, ... │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Report Composer Updates:**
|
||||
- Nieuwe prop: `encounterId?: string`
|
||||
- Pre-fill patient_id vanuit encounter
|
||||
- Toon encounter info (datum, type) in composer
|
||||
|
||||
---
|
||||
|
||||
### Epic 5 — Polish & Testing
|
||||
|
||||
**Epic Doel:** UX verfijning en edge case handling.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
|
||||
|----------|--------------|---------------------|--------|------------------|----|
|
||||
| E5.S1 | Loading states & skeletons | Alle async operaties hebben loading feedback | ⏳ | E4.S4 | 2 |
|
||||
| E5.S2 | Error handling | User-friendly errors, retry mogelijkheden | ⏳ | E5.S1 | 2 |
|
||||
| E5.S3 | Responsive design | Mobile-friendly, touch gestures | ⏳ | E5.S2 | 3 |
|
||||
|
||||
---
|
||||
|
||||
## 5. Kwaliteit & Testplan
|
||||
|
||||
### Test Types
|
||||
|
||||
| Test Type | Scope | Tools |
|
||||
|-----------|-------|-------|
|
||||
| Unit Tests | Date utilities, validators | Vitest |
|
||||
| Integration | API endpoints, database | Playwright |
|
||||
| Smoke Tests | Kritieke flows | Manual |
|
||||
| Visual | UI consistency | Manual |
|
||||
|
||||
### Manual Test Checklist
|
||||
|
||||
**Afspraak Flow:**
|
||||
- [ ] Nieuwe afspraak aanmaken met alle velden
|
||||
- [ ] Afspraak bewerken (tijd, type, notities)
|
||||
- [ ] Afspraak verzetten via drag-drop
|
||||
- [ ] Afspraak annuleren met bevestiging
|
||||
- [ ] Patiënt zoeken en selecteren
|
||||
|
||||
**Calendar Views:**
|
||||
- [ ] Dag view toont correcte uren
|
||||
- [ ] Week view toont 7 dagen
|
||||
- [ ] Werkdagen view filtert weekend
|
||||
- [ ] Navigatie (vorige/volgende) werkt
|
||||
- [ ] Vandaag button springt naar huidige dag
|
||||
|
||||
**EPD Koppeling:**
|
||||
- [ ] Verslag maken vanuit afspraak
|
||||
- [ ] Afspraak koppelen vanuit verslag
|
||||
- [ ] Gekoppelde items zijn zichtbaar
|
||||
- [ ] Navigatie werkt beide kanten
|
||||
|
||||
---
|
||||
|
||||
## 6. Data Model
|
||||
|
||||
### Encounters (uitgebreid)
|
||||
|
||||
```typescript
|
||||
interface Encounter {
|
||||
id: string;
|
||||
identifier: string;
|
||||
status: 'planned' | 'in-progress' | 'on-hold' | 'completed' | 'cancelled';
|
||||
class_code: string; // AMB, VR, HH (home health)
|
||||
class_display: string;
|
||||
type_code: string; // intake, behandeling, follow-up, etc.
|
||||
type_display: string;
|
||||
patient_id: string;
|
||||
practitioner_id: string;
|
||||
organization_id?: string;
|
||||
period_start: string; // ISO datetime
|
||||
period_end?: string;
|
||||
notes?: string;
|
||||
intake_id?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Reports (uitgebreid)
|
||||
|
||||
```typescript
|
||||
interface Report {
|
||||
id: string;
|
||||
patient_id: string;
|
||||
created_by?: string;
|
||||
type: 'behandeladvies' | 'vrije_notitie' | 'intake' | 'voortgang' | 'crisis' | 'contact';
|
||||
content: string;
|
||||
encounter_id?: string; // NEW: koppeling met afspraak
|
||||
intake_id?: string; // NEW: koppeling met intake
|
||||
// ... existing fields
|
||||
}
|
||||
```
|
||||
|
||||
### Calendar Event (voor FullCalendar)
|
||||
|
||||
```typescript
|
||||
interface CalendarEvent {
|
||||
id: string;
|
||||
title: string; // Patient naam
|
||||
start: Date;
|
||||
end?: Date;
|
||||
extendedProps: {
|
||||
encounter: Encounter;
|
||||
patient: Patient;
|
||||
linkedReports: Report[];
|
||||
};
|
||||
backgroundColor?: string; // Based on type
|
||||
borderColor?: string;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. API Endpoints
|
||||
|
||||
### Nieuwe Endpoints
|
||||
|
||||
| Methode | Endpoint | Beschrijving |
|
||||
|---------|----------|--------------|
|
||||
| GET | `/api/agenda/encounters` | Haal afspraken op (met filters) |
|
||||
| POST | `/api/agenda/encounters` | Nieuwe afspraak aanmaken |
|
||||
| PUT | `/api/agenda/encounters/[id]` | Afspraak bewerken |
|
||||
| PATCH | `/api/agenda/encounters/[id]/cancel` | Afspraak annuleren |
|
||||
| GET | `/api/agenda/encounters/[id]/reports` | Gekoppelde verslagen |
|
||||
|
||||
### Query Parameters (GET encounters)
|
||||
|
||||
```typescript
|
||||
interface EncounterFilters {
|
||||
start_date: string; // ISO date
|
||||
end_date: string;
|
||||
practitioner_id?: string;
|
||||
patient_id?: string;
|
||||
status?: string[];
|
||||
type_code?: string[];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Risico's & Mitigatie
|
||||
|
||||
| Risico | Kans | Impact | Mitigatie |
|
||||
|--------|------|--------|-----------|
|
||||
| FullCalendar styling conflicten | Middel | Middel | CSS isolation, custom theme |
|
||||
| Performance bij veel afspraken | Laag | Hoog | Pagination, date range filtering |
|
||||
| Timezone issues | Middel | Hoog | Altijd UTC opslaan, lokaal tonen |
|
||||
| Drag-drop UX op mobile | Middel | Middel | Touch-friendly alternatives |
|
||||
| Concurrent edits | Laag | Middel | Optimistic locking, conflict resolution |
|
||||
|
||||
---
|
||||
|
||||
## 9. UI/UX Specificaties
|
||||
|
||||
### Agenda Layout
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ EPD Header [User] │
|
||||
├────────┬───────────────────────────────────────────────────────┤
|
||||
│ │ Agenda [+ Nieuwe Afspraak] │
|
||||
│ Nav │───────────────────────────────────────────────────────│
|
||||
│ │ [< Vorige] [Vandaag] [Volgende >] [Dag|Week|Werk] │
|
||||
│ │───────────────────────────────────────────────────────│
|
||||
│ │ ┌──────────┐ │
|
||||
│ │ │ December │ ┌─────────────────────────────────────┐│
|
||||
│ │ │ 2024 │ │ Ma │ Di │ Wo │ Do │ Vr ││
|
||||
│ │ │ [Cal] │ │──────┼──────┼──────┼──────┼────────││
|
||||
│ │ └──────────┘ │ 08:00│ │ │ │ ││
|
||||
│ │ │──────│ [Pnt]│ │ │ ││
|
||||
│ │ Filters: │ 09:00│ │ [Int]│ │ ││
|
||||
│ │ □ Intakes │──────│ │ │ │ ││
|
||||
│ │ □ Behandeling │ 10:00│ │ │ [Beh]│ ││
|
||||
│ │ □ Telefonisch │──────│ │ │ │ ││
|
||||
│ │ │ ... │ │ │ │ ││
|
||||
│ │ └─────────────────────────────────────┘│
|
||||
└────────┴───────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Afspraak Card (in kalender)
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ 09:00 - 10:00 │
|
||||
│ ● Jan de Vries │
|
||||
│ Intakegesprek │
|
||||
│ [📝] [✏️] │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
### Afspraak Modal
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Nieuwe Afspraak [X] │
|
||||
├─────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Patiënt * │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ 🔍 Zoek patiënt... │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Datum * Tijd * │
|
||||
│ ┌──────────────┐ ┌──────┐ - ┌──────┐│
|
||||
│ │ 02-12-2024 │ │09:00 │ │10:00 ││
|
||||
│ └──────────────┘ └──────┘ └──────┘│
|
||||
│ │
|
||||
│ Type afspraak * │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ Intakegesprek ▼ │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Locatie │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ Praktijk ▼ │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Notities │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [Annuleren] [Opslaan] │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Referenties
|
||||
|
||||
**Interne Documenten:**
|
||||
- FO Mini-EPD v1.2
|
||||
- TO Mini-EPD v1.2
|
||||
- Screening-Intake Bouwplan
|
||||
|
||||
**Libraries:**
|
||||
- [FullCalendar React](https://fullcalendar.io/docs/react)
|
||||
- [shadcn/ui Calendar](https://ui.shadcn.com/docs/components/calendar)
|
||||
- [date-fns](https://date-fns.org/)
|
||||
|
||||
**Database:**
|
||||
- `encounters` tabel (FHIR Encounter)
|
||||
- `reports` tabel
|
||||
- `patients` tabel
|
||||
- `practitioners` tabel
|
||||
|
||||
---
|
||||
|
||||
## 11. Glossary
|
||||
|
||||
| Term | Betekenis |
|
||||
|------|-----------|
|
||||
| Encounter | FHIR term voor een contact/afspraak moment |
|
||||
| period_start | Starttijd van een afspraak (ISO datetime) |
|
||||
| class_code | Type locatie (AMB=ambulant, VR=virtueel, HH=thuis) |
|
||||
| type_code | Type afspraak (intake, behandeling, etc.) |
|
||||
| Bidirectioneel | Koppeling werkt beide kanten op |
|
||||
|
||||
---
|
||||
|
||||
**Versiehistorie:**
|
||||
|
||||
| Versie | Datum | Auteur | Wijziging |
|
||||
|--------|-------|--------|-----------|
|
||||
| v1.0 | 02-12-2024 | Colin | Initiële versie |
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,695 +0,0 @@
|
||||
# 📄 Product Requirements Document (PRD) — Agenda Module
|
||||
|
||||
**Projectnaam:** Mini-EPD Agenda Module
|
||||
**Versie:** v1.0
|
||||
**Datum:** 02-12-2024
|
||||
**Auteur:** Colin
|
||||
|
||||
---
|
||||
|
||||
## 1. Doelstelling
|
||||
|
||||
🎯 **Doel van deze sectie:** Beschrijf waarom dit product of prototype wordt gebouwd en wat het beoogde resultaat is.
|
||||
|
||||
### Waarom deze module?
|
||||
|
||||
De agenda is het **kloppend hart** van elk EPD-systeem. Zonder agenda geen structuur, geen overzicht, geen efficiënte praktijkvoering. Voor het AI Speedrun project is de agenda module cruciaal omdat het:
|
||||
|
||||
1. **De workflow compleet maakt**: Intake → Behandelplan → Afspraken → Verslaglegging → Herhaal
|
||||
2. **Dagelijks gebruik afdwingt**: Een EPD zonder agenda wordt niet gebruikt, want behandelaars hebben dit elke dag nodig
|
||||
3. **AI-integratie natuurlijk maakt**: Afspraak → AI-verslag in 1 klik, naadloos in de dagelijkse workflow
|
||||
4. **Geloofwaardigheid toevoegt**: "Zonder agenda is het geen echt EPD" — dit maakt het prototype serieus
|
||||
|
||||
### Wat willen we bereiken?
|
||||
|
||||
Een **werkende agenda module** die behandelaars:
|
||||
- Laat plannen, verzetten en annuleren van afspraken
|
||||
- Koppelt aan patiëntendossiers én verslagen (bidirectioneel)
|
||||
- Waarschuwt bij dubbele boekingen (maar niet blokkeert — flexibiliteit!)
|
||||
- Integreert met bestaande intake/rapportage flows
|
||||
|
||||
**Type oplevering:** MVP voor AI Speedrun demo + basis voor productieversie
|
||||
|
||||
**Kernboodschap voor demo:**
|
||||
> "Dit is geen speeltje — dit is een werkend EPD waar je morgen mee aan de slag kunt. Hier is mijn agenda voor deze week, klik, nieuwe afspraak, patient selecteren, opslaan. En nu direct een verslag maken. Dat is AI in de praktijk."
|
||||
|
||||
---
|
||||
|
||||
## 2. Doelgroep
|
||||
|
||||
🎯 **Doel:** Schets wie de eindgebruikers, stakeholders en testers zijn.
|
||||
|
||||
### Primaire gebruikers (direct)
|
||||
|
||||
**1. Behandelaars in de GGZ**
|
||||
- **Behoefte:** Overzicht van hun dag/week, snel afspraken plannen, direct verslagen kunnen maken
|
||||
- **Pijnpunten met huidige systemen:**
|
||||
- Te veel klikken om een afspraak te maken
|
||||
- Geen koppeling tussen afspraak en verslag
|
||||
- Geen waarschuwing bij dubbele boekingen
|
||||
- Slow and clunky interfaces
|
||||
- **Wat ze willen zien:** "Kan ik hier echt mijn praktijk mee runnen?"
|
||||
|
||||
**2. Praktijkassistenten / Secretaresses**
|
||||
- **Behoefte:** Afspraken inplannen voor behandelaars, overzicht van beschikbaarheid
|
||||
- **Pijnpunten:** Veel telefoontjes, handmatige planning, geen real-time updates
|
||||
- **Opmerking:** Dit is stretch voor MVP — focus ligt op single-user (behandelaar)
|
||||
|
||||
### Secundaire stakeholders (indirect)
|
||||
|
||||
**3. Zorgmanagers / Praktijkhouders**
|
||||
- **Interesse:** Kan dit hun praktijk efficiënter maken?
|
||||
- **Vraag:** "Hoeveel kost dit vs. PinkRoccade/Nedap?"
|
||||
- **Demo-moment:** Laten zien hoe snel afspraken worden ingepland vs. legacy systemen
|
||||
|
||||
**4. Developers / Tech Managers**
|
||||
- **Interesse:** Hoe is dit gebouwd? Wat kan AI echt?
|
||||
- **Vraag:** "Hoeveel werk is dit geweest? Kan ons team dit ook?"
|
||||
- **Demo-moment:** Transparantie over buildtime, tech stack, AI-gebruik
|
||||
|
||||
**5. Potentiële klanten (via LinkedIn)**
|
||||
- **Interesse:** Proof of concept dat "Software on Demand" werkt
|
||||
- **Vraag:** "Is dit echt in 4 weken gebouwd?"
|
||||
- **Demo-moment:** Build metrics, transparante timeline
|
||||
|
||||
### Persona's
|
||||
|
||||
**Persona 1: Marieke (Psycholoog, 38 jaar)**
|
||||
- Zelfstandig gevestigd, 3 dagen per week cliënten
|
||||
- Gebruikt nu Google Agenda + Word voor verslagen
|
||||
- Frustratie: "Ik moet alles dubbel invoeren en kan niks terugvinden"
|
||||
- Wens: "Gewoon een simpel systeem waar alles bij elkaar staat"
|
||||
|
||||
**Persona 2: Bas (Psychiater, 52 jaar)**
|
||||
- Werkt in instelling met Nedap ECD
|
||||
- Frustratie: "Het kost me 5 minuten om een afspraak te maken, en dan crasht het nog"
|
||||
- Wens: "Iets wat gewoon werkt, zoals Outlook maar dan met verslagen"
|
||||
|
||||
---
|
||||
|
||||
## 3. Kernfunctionaliteiten (MVP-scope)
|
||||
|
||||
🎯 **Doel:** Afbakenen van de minimale werkende functies.
|
||||
|
||||
### Must-Have (MVP)
|
||||
|
||||
1. **Kalenderweergave**
|
||||
- **Input:** Datum selectie
|
||||
- **Output:** Dag/Week/Werkdagen view met afspraken
|
||||
- **Interactie:** Klikken op tijdslot = nieuwe afspraak, klikken op afspraak = details
|
||||
- **Demo-waarde:** "Dit is mijn agenda, net als Outlook"
|
||||
|
||||
2. **Afspraak maken**
|
||||
- **Input:** Patient, datum/tijd, type afspraak (intake/behandeling/follow-up)
|
||||
- **Output:** Nieuwe afspraak in kalender
|
||||
- **Interactie:** Modal form, patient zoeken, tijd kiezen
|
||||
- **Demo-waarde:** "Kijk hoe snel dit gaat — patient zoeken, tijd kiezen, klaar"
|
||||
|
||||
3. **Dubbele boeking waarschuwing**
|
||||
- **Input:** Overlappende tijden voor zelfde behandelaar
|
||||
- **Output:** Warning met overzicht bestaande afspraken + optie om toch in te plannen
|
||||
- **Interactie:** Dialog met "Wijzigen" of "Toch inplannen" knoppen
|
||||
- **Demo-waarde:** "Het systeem waarschuwt me, maar ik kan het overrulen — flexibiliteit!"
|
||||
|
||||
4. **Afspraak verzetten & annuleren**
|
||||
- **Input:** Drag-drop (desktop) of Edit button (mobile)
|
||||
- **Output:** Gewijzigde tijd of status 'cancelled'
|
||||
- **Interactie:** Confirm dialog bij grote wijzigingen
|
||||
- **Demo-waarde:** "Even snel een afspraak verzetten, done"
|
||||
|
||||
5. **Patient koppeling**
|
||||
- **Input:** Patient search (naam/BSN)
|
||||
- **Output:** Patient geselecteerd, afspraak gekoppeld
|
||||
- **Interactie:** Autocomplete search in modal
|
||||
- **Demo-waarde:** "Alle patiëntgegevens direct beschikbaar"
|
||||
|
||||
6. **Afspraak ↔ Verslag koppeling (bidirectioneel)**
|
||||
- **Input:** "Maak verslag" button in afspraak detail
|
||||
- **Output:** Verslag editor met afspraak pre-filled
|
||||
- **Interactie:** Click-through tussen afspraak en verslag
|
||||
- **Demo-waarde:** **"DIT is waar AI echt helpt — afspraak gehad, 1 klik, verslag maken"**
|
||||
|
||||
### Nice-to-Have (Stretch voor MVP)
|
||||
|
||||
7. **(Stretch) Recent patients dropdown**
|
||||
- Laatste 5 patiënten snel selecteren
|
||||
- Demo-waarde: Extra snelheid voor repeat gebruikers
|
||||
|
||||
8. **(Stretch) Color coding per type**
|
||||
- Intake = blauw, Behandeling = groen, etc.
|
||||
- Demo-waarde: Visueel overzicht
|
||||
|
||||
9. **(Stretch) Mini calendar sidebar**
|
||||
- Maandoverzicht met navigatie
|
||||
- Demo-waarde: Extra polish, maar niet essentieel
|
||||
|
||||
### Expliciet NIET in MVP
|
||||
|
||||
- ❌ Recurring appointments (herhaling)
|
||||
- ❌ Multi-practitioner view (agenda's van meerdere behandelaars)
|
||||
- ❌ Email/SMS notificaties naar patiënten
|
||||
- ❌ Patient portal (patiënten zelf afspraken maken)
|
||||
- ❌ Wachtlijstbeheer
|
||||
- ❌ Video call integratie
|
||||
|
||||
---
|
||||
|
||||
## 4. Gebruikersflows (Demo- of MVP-flows)
|
||||
|
||||
🎯 **Doel:** Laten zien hoe de gebruiker stap-voor-stap door het systeem gaat.
|
||||
|
||||
### Flow 1: Nieuwe afspraak maken (Snelste pad)
|
||||
|
||||
**Scenario:** Behandelaar krijgt patient aan de telefoon, wil snel afspraak inplannen
|
||||
|
||||
1. **Start:** Behandelaar kijkt naar agenda (week view)
|
||||
2. **Actie:** Klikt op lege tijdslot (bijv. donderdag 14:00)
|
||||
3. **Systeem:** Modal opent met pre-filled datum/tijd
|
||||
4. **Actie:** Typt patient naam in zoekbalk: "Jan de"
|
||||
5. **Systeem:** Autocomplete toont "Jan de Vries (12-03-1985)"
|
||||
6. **Actie:** Selecteert patient, kiest type "Behandeling", klikt "Opslaan"
|
||||
7. **Systeem:** Afspraak verschijnt in kalender
|
||||
8. **Resultaat:** Afspraak ingepland in ~10 seconden
|
||||
|
||||
**Demo-tijd:** 15 seconden (met uitleg: 30 sec)
|
||||
|
||||
### Flow 2: Afspraak maken met dubbele boeking
|
||||
|
||||
**Scenario:** Behandelaar vergist zich, wil afspraak maken op al bezet tijdslot
|
||||
|
||||
1. **Start:** Behandelaar klikt op tijdslot 14:00 (al bezet met andere patient)
|
||||
2. **Systeem:** Modal opent, behandelaar vult patient "Maria Jansen" in
|
||||
3. **Actie:** Klikt "Opslaan"
|
||||
4. **Systeem:** ⚠️ Warning toont: "Let op: dubbele boeking — Je hebt al een afspraak: Jan de Vries - 14:00 (Intake)"
|
||||
5. **Beslismoment:** Behandelaar ziet twee opties:
|
||||
- "Wijzigen" → terug naar form, andere tijd kiezen
|
||||
- "Toch inplannen" → override, beide afspraken staan er
|
||||
6. **Actie:** Klikt "Wijzigen", kiest 15:00
|
||||
7. **Systeem:** Geen warning, afspraak wordt opgeslagen
|
||||
8. **Resultaat:** Conflict voorkomen, afspraak correct ingepland
|
||||
|
||||
**Demo-tijd:** 30 seconden (laat zien: systeem helpt je, maar dwingt niet af)
|
||||
|
||||
### Flow 3: Afspraak → Verslag (De AI-kracht)
|
||||
|
||||
**Scenario:** Behandelaar heeft zojuist intake gehad, wil direct verslag maken
|
||||
|
||||
1. **Start:** Behandelaar klikt op afspraak in kalender (net geweest: 10:00-11:00)
|
||||
2. **Systeem:** Afspraak detail popup toont:
|
||||
- Patient: Jan de Vries
|
||||
- Type: Intakegesprek
|
||||
- Notities: [leeg of korte aantekeningen]
|
||||
- **Button: "📝 Maak verslag"**
|
||||
3. **Actie:** Klikt "Maak verslag"
|
||||
4. **Systeem:** Navigeert naar Rapportage module met:
|
||||
- Patient pre-filled: Jan de Vries
|
||||
- Type pre-selected: Intake verslag
|
||||
- Afspraak linked: 02-12-2024 10:00
|
||||
5. **Actie:** Behandelaar gebruikt AI-transcriptie of typt verslag
|
||||
6. **Systeem:** AI genereert structuur, samenvatting, suggesties
|
||||
7. **Actie:** Behandelaar bewerkt, klikt "Opslaan"
|
||||
8. **Systeem:** Verslag opgeslagen + automatisch gekoppeld aan afspraak
|
||||
9. **Resultaat:** In agenda: afspraak toont nu 📝 icon (verslag aanwezig)
|
||||
|
||||
**Demo-tijd:** 45 seconden (zonder verslag schrijven, alleen workflow tonen)
|
||||
|
||||
**Demo-impact:** 🔥 **DIT is de killer feature** — naadloze integratie afspraak ↔ verslag ↔ AI
|
||||
|
||||
### Flow 4: Afspraak verzetten (Desktop drag-drop)
|
||||
|
||||
**Scenario:** Patient belt, kan niet op dinsdag, moet naar woensdag
|
||||
|
||||
1. **Start:** Behandelaar ziet afspraak op dinsdag 14:00
|
||||
2. **Actie:** Klikt en houdt vast op afspraak card
|
||||
3. **Systeem:** Afspraak wordt "draggable", cursor changes
|
||||
4. **Actie:** Sleept naar woensdag 15:00 tijdslot
|
||||
5. **Systeem:** Confirm dialog: "Afspraak verzetten naar wo 03-12 15:00?"
|
||||
6. **Actie:** Klikt "Ja, verplaatsen"
|
||||
7. **Systeem:** Afspraak verplaatst, conflict check uitgevoerd (geen warning)
|
||||
8. **Resultaat:** Afspraak staat nu op woensdag 15:00
|
||||
|
||||
**Demo-tijd:** 10 seconden (visual impressive)
|
||||
|
||||
---
|
||||
|
||||
## 5. Niet in Scope
|
||||
|
||||
🎯 **Doel:** Duidelijk maken wat (nog) niet wordt gebouwd.
|
||||
|
||||
### Features die NIET in MVP zitten
|
||||
|
||||
**1. Multi-user & Rechtenbeheer**
|
||||
- Geen rollen (admin/behandelaar/assistent)
|
||||
- Geen gebruikersbeheer (toevoegen/verwijderen users)
|
||||
- Geen rechten per patient/afspraak
|
||||
- **Reden:** MVP is single-user demo, complexiteit te hoog voor Speedrun
|
||||
|
||||
**2. Patient Portal & Self-Service**
|
||||
- Patiënten kunnen niet zelf afspraken maken
|
||||
- Geen patient login
|
||||
- Geen afspraak bevestigingen/herinneringen via email/SMS
|
||||
- **Reden:** Focus ligt op behandelaar workflow, patient side is apart product
|
||||
|
||||
**3. Advanced Scheduling**
|
||||
- Geen recurring appointments (wekelijks, maandelijks)
|
||||
- Geen wachtlijstbeheer
|
||||
- Geen automatische slot-filling
|
||||
- Geen "find first available" functie
|
||||
- **Reden:** Te complex voor MVP, weinig demo-waarde
|
||||
|
||||
**4. External Integrations**
|
||||
- Geen Google Calendar sync
|
||||
- Geen Outlook sync
|
||||
- Geen Teams integratie
|
||||
- Geen iCal export
|
||||
- **Reden:** Integraties vragen maanden werk, geen core functionaliteit
|
||||
|
||||
**5. Advanced Analytics**
|
||||
- Geen no-show tracking
|
||||
- Geen bezettingsgraad dashboard
|
||||
- Geen revenue/billing integratie
|
||||
- **Reden:** Dit is post-MVP "nice to have"
|
||||
|
||||
**6. Video Call Features**
|
||||
- Geen ingebouwde video calling
|
||||
- Geen Zoom/Teams meeting links automatisch genereren
|
||||
- **Reden:** Complex, weinig meerwaarde voor demo
|
||||
|
||||
**7. Production-Grade Features**
|
||||
- Geen audit logging (wie heeft wat gewijzigd)
|
||||
- Geen versioning van afspraken
|
||||
- Geen backup/restore functionaliteit
|
||||
- Geen advanced error recovery
|
||||
- **Reden:** MVP is demo, niet productie-ready
|
||||
|
||||
### Waarom deze keuzes?
|
||||
|
||||
**Principe:** Focus op **snelheid** en **demo-impact**, niet op completeness.
|
||||
|
||||
De agenda module moet:
|
||||
✅ Werken voor 1 behandelaar
|
||||
✅ Integreren met bestaande intake/rapportage flows
|
||||
✅ Laten zien dat AI naadloos past in dagelijkse workflow
|
||||
✅ Indruk maken: "Dit is geen speeltje, dit werkt écht"
|
||||
|
||||
**Niet:**
|
||||
❌ Alle edge cases afvangen
|
||||
❌ Multi-tenant ready zijn
|
||||
❌ Productie-grade security/performance
|
||||
❌ Feature parity met legacy systemen
|
||||
|
||||
---
|
||||
|
||||
## 6. Succescriteria
|
||||
|
||||
🎯 **Doel:** Objectieve meetlat voor een geslaagde oplevering.
|
||||
|
||||
### Demo Succescriteria
|
||||
|
||||
**1. Demo Flow Compleetheid**
|
||||
- [ ] Volledige flow 1-4 werkend zonder bugs
|
||||
- [ ] Demo kan in **< 5 minuten** worden gedaan (inclusief uitleg)
|
||||
- [ ] Geen "let's pretend" moments — alles werkt écht
|
||||
- [ ] Mobile view werkt (backup als desktop faalt)
|
||||
|
||||
**2. AI Integratie Showcase**
|
||||
- [ ] Afspraak → Verslag flow werkt in **< 3 clicks**
|
||||
- [ ] AI-generated content zichtbaar in verslag
|
||||
- [ ] Bidirectionele link werkt (afspraak ↔ verslag beide kanten)
|
||||
|
||||
**3. Gebruikerservaring**
|
||||
- [ ] Conflict warning toont correcte info (patient naam, tijd)
|
||||
- [ ] Patient search werkt met **< 500ms response time**
|
||||
- [ ] Drag-drop feels responsive (< 100ms visual feedback)
|
||||
- [ ] Geen UI glitches op demo tijdstip
|
||||
|
||||
**4. Technische Stabiliteit**
|
||||
- [ ] Geen crashes tijdens demo flow
|
||||
- [ ] Database queries < 2 seconden
|
||||
- [ ] Timezone handling correct (NL-tijd in UI, UTC in DB)
|
||||
|
||||
### LinkedIn Content Succescriteria
|
||||
|
||||
**5. Viral Potential**
|
||||
- [ ] Screenshot-worthy moments (bijv. conflict warning, AI-verslag)
|
||||
- [ ] "Build in public" metrics: X story points, Y hours, €Z kosten
|
||||
- [ ] Quote-worthy moment: "4 weken, €50/maand, volledig werkend EPD"
|
||||
|
||||
**6. Geloofwaardigheid**
|
||||
- [ ] Live demo URL werkt (vercel deployment)
|
||||
- [ ] Code op GitHub (public repo)
|
||||
- [ ] Geen fake data in screenshots (echte-looking test data)
|
||||
|
||||
### Post-Demo Validatie
|
||||
|
||||
**7. User Feedback**
|
||||
- [ ] Minimaal 1 zorgprofessional test het live
|
||||
- [ ] Feedback verzameld: "Zou je dit gebruiken?"
|
||||
- [ ] Top 3 missing features geïdentificeerd
|
||||
|
||||
**8. Technical Learnings**
|
||||
- [ ] AI prompt quality documented (wat werkte, wat niet)
|
||||
- [ ] Performance bottlenecks geïdentificeerd
|
||||
- [ ] Timezone edge cases getest (zomertijd transitie)
|
||||
|
||||
### Kwantitatieve Metrics
|
||||
|
||||
| Metric | Target | Stretch |
|
||||
|--------|--------|---------|
|
||||
| **Demo tijd** | < 5 min | < 3 min |
|
||||
| **Page load tijd** | < 2s | < 1s |
|
||||
| **Afspraak maken** | < 10 sec | < 5 sec |
|
||||
| **Patient search response** | < 500ms | < 200ms |
|
||||
| **LinkedIn impressions** | 5,000 | 10,000 |
|
||||
| **Engagement rate** | 2% | 5% |
|
||||
| **Inbound leads** | 2 | 5 |
|
||||
|
||||
---
|
||||
|
||||
## 7. Risico's & Mitigatie
|
||||
|
||||
🎯 **Doel:** Risico's vroeg signaleren en plannen hoe ermee om te gaan.
|
||||
|
||||
### Technische Risico's
|
||||
|
||||
| Risico | Kans | Impact | Mitigatie |
|
||||
|--------|------|--------|-----------|
|
||||
| **FullCalendar styling conflicts** | Middel | Middel | Prototype early (week 1), CSS isolation strategy, fallback naar simpeler calendar |
|
||||
| **Timezone bugs** | Middel | Hoog | Test zomertijd transitie (29 maart), gebruik date-fns-tz, TIMESTAMPTZ in DB |
|
||||
| **Performance bij veel afspraken** | Laag | Middel | Query optimization met indices, date range filtering, pagination if needed |
|
||||
| **Drag-drop mobile UX** | Hoog | Laag | Accept limitation: desktop-only drag, mobile uses Edit button |
|
||||
| **Conflict detection edge cases** | Middel | Middel | Document assumptions, test concurrent edits, graceful degradation |
|
||||
|
||||
### Scope & Planning Risico's
|
||||
|
||||
| Risico | Kans | Impact | Mitigatie |
|
||||
|--------|------|--------|-----------|
|
||||
| **Scope creep** | Hoog | Hoog | **Hard blocker:** PRD is frozen. Extra features → post-MVP backlog |
|
||||
| **Underestimated complexity** | Middel | Hoog | Buffer 20% op story points, drop stretch features first |
|
||||
| **Demo prep time onderschat** | Middel | Middel | Test demo flow 2 dagen voor launch, record backup video |
|
||||
| **Integration breaking changes** | Laag | Hoog | Freeze intake/rapportage modules week voor agenda start |
|
||||
|
||||
### Demo & Marketing Risico's
|
||||
|
||||
| Risico | Kans | Impact | Mitigatie |
|
||||
|--------|------|--------|-----------|
|
||||
| **Live demo fails** | Middel | Hoog | Pre-record video backup, test deployment morning-of, have fallback slides |
|
||||
| **LinkedIn post flops** | Middel | Middel | A/B test headlines, post at optimal time (dinsdag 9:00), engage in comments |
|
||||
| **Negative feedback** | Laag | Middel | Respond professionally, use as learning, "building in public = warts and all" |
|
||||
| **Competitor copies idea** | Laag | Laag | Accept risk, speed-to-market is advantage, open source = marketing |
|
||||
|
||||
### Data & Privacy Risico's
|
||||
|
||||
| Risico | Kans | Impact | Mitigatie |
|
||||
|--------|------|--------|-----------|
|
||||
| **Demo data looks fake** | Middel | Middel | Use realistic names/dates, Nederlandse context, avoid "Test User 1" |
|
||||
| **Accidentally expose PII** | Laag | Hoog | **Only use fake data**, sanitize screenshots, no real BSN/medical info |
|
||||
| **GDPR concerns** | Laag | Middel | Demo data only, privacy policy placeholder, mention "demo purposes" |
|
||||
|
||||
### Mitigation Strategies
|
||||
|
||||
**1. Technical Blockers (FullCalendar, Timezone)**
|
||||
- **Week 1 Action:** Spike FullCalendar integration, confirm it works
|
||||
- **Fallback:** If FullCalendar too complex → simple custom grid view (bare minimum)
|
||||
- **Test Plan:** Timezone edge case tests (E5.S3) before launch
|
||||
|
||||
**2. Scope Management**
|
||||
- **Weekly Check:** "Are we building MVP or nice-to-have?"
|
||||
- **Decision Rule:** "Does this feature appear in demo flow? No → backlog"
|
||||
- **Communication:** Update Mission Control daily with scope decisions
|
||||
|
||||
**3. Demo Insurance**
|
||||
- **T-2 days:** Full dry-run with fresh browser
|
||||
- **T-1 day:** Record backup video (Plan B)
|
||||
- **Demo day:** Local fallback if Vercel down, screenshots ready
|
||||
|
||||
**4. Marketing Hedge**
|
||||
- **Content Calendar:** 3 LinkedIn posts drafted in advance
|
||||
- **Engagement Plan:** Reply to every comment within 1 hour
|
||||
- **Narrative Pivot:** If build too fast → "How I did it", if too slow → "Lessons learned"
|
||||
|
||||
---
|
||||
|
||||
## 8. Roadmap / Vervolg (Post-MVP)
|
||||
|
||||
🎯 **Doel:** Richting geven aan toekomstige uitbreidingen.
|
||||
|
||||
### Fase 1: MVP Launch (Week 1-2 van Agenda Build)
|
||||
- ✅ Basic calendar views (dag/week/werkdagen)
|
||||
- ✅ Afspraak CRUD (make, edit, cancel)
|
||||
- ✅ Conflict detection met override
|
||||
- ✅ Afspraak ↔ Verslag koppeling
|
||||
- ✅ Patient search
|
||||
|
||||
**Output:** Demo-ready agenda voor AI Speedrun showcase
|
||||
|
||||
---
|
||||
|
||||
### Fase 2: Production Readiness (Post-Speedrun, Week +4-8)
|
||||
|
||||
**Prioriteit: Hoog** (als klant interesse toont)
|
||||
|
||||
1. **Multi-User Support**
|
||||
- Rollenbeheer (admin, behandelaar, assistent)
|
||||
- User management (toevoegen/verwijderen)
|
||||
- Per-user agenda view
|
||||
- **Business Value:** Nodig voor praktijken met >1 behandelaar
|
||||
|
||||
2. **Security Hardening**
|
||||
- Row Level Security (RLS) policies
|
||||
- Audit logging (wie deed wat wanneer)
|
||||
- Session management
|
||||
- **Business Value:** Compliance voor echte zorgdata
|
||||
|
||||
3. **Performance Optimization**
|
||||
- Query optimization
|
||||
- Caching strategie
|
||||
- Pagination voor grote datasets
|
||||
- **Business Value:** Schaalbaar naar 100+ afspraken/dag
|
||||
|
||||
4. **Error Handling & Monitoring**
|
||||
- Sentry integratie
|
||||
- Graceful degradation
|
||||
- Retry mechanisms
|
||||
- **Business Value:** Productie-grade stabiliteit
|
||||
|
||||
**Effort:** ~3-4 weken (1 FTE)
|
||||
**Business Case:** Nodig voor betalende klanten
|
||||
|
||||
---
|
||||
|
||||
### Fase 3: Feature Parity (Month 3-4)
|
||||
|
||||
**Prioriteit: Middel** (nice-to-have, niet blocker)
|
||||
|
||||
1. **Advanced Scheduling**
|
||||
- Recurring appointments (wekelijks/maandelijks)
|
||||
- Wachtlijstbeheer
|
||||
- "Find first available" slot
|
||||
- **Business Value:** Efficiency boost voor drukke praktijken
|
||||
|
||||
2. **Patient Communications**
|
||||
- Email herinneringen (24u voor afspraak)
|
||||
- SMS notificaties (optioneel)
|
||||
- Cancellation confirmations
|
||||
- **Business Value:** Reduce no-shows (vaak 10-20% in GGZ)
|
||||
|
||||
3. **Multi-Practitioner View**
|
||||
- Agenda van meerdere behandelaars naast elkaar
|
||||
- Resource allocation (kamers, apparatuur)
|
||||
- Team scheduling
|
||||
- **Business Value:** Voor grotere praktijken/instellingen
|
||||
|
||||
4. **Reporting & Analytics**
|
||||
- Bezettingsgraad dashboard
|
||||
- No-show tracking
|
||||
- Revenue per practitioner (indien billing)
|
||||
- **Business Value:** Management insights
|
||||
|
||||
**Effort:** ~4-6 weken (1 FTE)
|
||||
**Business Case:** Upsell opportunity, premium features
|
||||
|
||||
---
|
||||
|
||||
### Fase 4: Ecosystem Integration (Month 5-6)
|
||||
|
||||
**Prioriteit: Laag** (tenzij strategische partnerships)
|
||||
|
||||
1. **Calendar Sync**
|
||||
- Google Calendar sync (two-way)
|
||||
- Outlook sync
|
||||
- iCal export
|
||||
- **Business Value:** Reduce double-entry, increase adoption
|
||||
|
||||
2. **Video Call Integration**
|
||||
- Zoom meeting auto-generation
|
||||
- Teams meeting links
|
||||
- In-browser video (WebRTC)
|
||||
- **Business Value:** COVID-era feature, online consulten
|
||||
|
||||
3. **External System Integration**
|
||||
- PinkRoccade koppeling (indien klant vraagt)
|
||||
- Nedap ECD import/export
|
||||
- Zorgdomein connectie
|
||||
- **Business Value:** Migration path van legacy systemen
|
||||
|
||||
**Effort:** ~6-12 weken (1 FTE)
|
||||
**Business Case:** Vereist voor enterprise deals
|
||||
|
||||
---
|
||||
|
||||
### Fase 5: Patient Self-Service (Month 7-9)
|
||||
|
||||
**Prioriteit: Hoog** (maar separate product)
|
||||
|
||||
1. **Patient Portal**
|
||||
- Inloggen met DigiD
|
||||
- Eigen afspraken bekijken
|
||||
- Afspraken maken (binnen beschikbare slots)
|
||||
- Afspraken annuleren (met policy)
|
||||
- **Business Value:** Reduce admin workload, 24/7 booking
|
||||
|
||||
2. **Patient Experience**
|
||||
- Intake formulieren online invullen
|
||||
- Documenten uploaden (verwijsbrieven, etc.)
|
||||
- Vragenlijsten invullen (ROM, etc.)
|
||||
- **Business Value:** Efficiency, patient empowerment
|
||||
|
||||
**Effort:** ~8-12 weken (1 FTE)
|
||||
**Business Case:** Dit kan separate SaaS product zijn
|
||||
|
||||
---
|
||||
|
||||
### Strategic Considerations
|
||||
|
||||
**Build vs. Integrate Decision Tree:**
|
||||
|
||||
```
|
||||
Feature request
|
||||
│
|
||||
├─ Is it core to EPD?
|
||||
│ ├─ Yes → Build it
|
||||
│ └─ No → Can we integrate?
|
||||
│ ├─ Yes → Use API/webhook
|
||||
│ └─ No → Deprioritize
|
||||
│
|
||||
└─ Does it differentiate us?
|
||||
├─ Yes → Build it (competitive advantage)
|
||||
└─ No → Buy/integrate (focus on AI)
|
||||
```
|
||||
|
||||
**Example:**
|
||||
- Video calling → **Integrate** (Zoom API)
|
||||
- AI-powered scheduling → **Build** (our secret sauce)
|
||||
- Billing/invoicing → **Integrate** (Mollie, etc.)
|
||||
- Treatment plan generation → **Build** (core AI value)
|
||||
|
||||
---
|
||||
|
||||
### Parking Lot (Ideas, geen commitment)
|
||||
|
||||
- AI-powered "optimal scheduling" (ML-based slot recommendations)
|
||||
- Predictive no-show scoring (AI flags high-risk appointments)
|
||||
- Voice-controlled agenda ("Schedule Jan de Vries for Thursday 2pm")
|
||||
- WhatsApp integration for reminders
|
||||
- Apple Health / Google Fit data import (for lifestyle coaching)
|
||||
- Group session management (multiple patients per appointment)
|
||||
|
||||
**Criteria for moving from Parking Lot → Roadmap:**
|
||||
1. Customer explicitly asks for it (at least 3 requests)
|
||||
2. Clear business case (revenue, retention, or viral potential)
|
||||
3. Feasible effort (< 4 weeks build time)
|
||||
|
||||
---
|
||||
|
||||
## 9. Bijlagen & Referenties
|
||||
|
||||
🎯 **Doel:** Bronnen koppelen voor context en consistentie.
|
||||
|
||||
### Interne Documenten
|
||||
|
||||
**Strategisch:**
|
||||
- [AI Speedrun Manifesto](link) — Overall projectvisie
|
||||
- [Mission Control v1](link) — Project status tracking
|
||||
- [Build Metrics Tracking](link) — Transparante build log
|
||||
|
||||
**Functioneel:**
|
||||
- FO Mini-EPD v2.0 — Volledige functionele specificatie
|
||||
- TO Mini-EPD v1.2 — Technische architectuur
|
||||
- PRD Intake Module v1 — Hoe intake werkt (dependency)
|
||||
- PRD Rapportage Module v1 — Hoe verslagen werken (integration point)
|
||||
|
||||
**Technisch:**
|
||||
- Bouwplan Agenda Module v1.1 — Gedetailleerde technische implementatie (dit volgt ná PRD approval)
|
||||
- API Access Mini-ECD — AI integratie documentatie
|
||||
- Database Schema FHIR GGZ — Data model
|
||||
|
||||
**UX/UI:**
|
||||
- UX Stylesheet — Design system & component library
|
||||
- Interface Design Plan — Wireframes en user flows
|
||||
- Mocks UI Flow — Visual designs
|
||||
|
||||
### Externe Referenties
|
||||
|
||||
**Standards & Compliance:**
|
||||
- [FHIR R4 Encounter Resource](https://www.hl7.org/fhir/encounter.html) — Healthcare data standard
|
||||
- [ISO 8601 DateTime](https://en.wikipedia.org/wiki/ISO_8601) — Date/time formatting
|
||||
- [IANA Time Zones](https://www.iana.org/time-zones) — Timezone database
|
||||
|
||||
**Technology:**
|
||||
- [FullCalendar Documentation](https://fullcalendar.io/docs) — Calendar library we'll use
|
||||
- [shadcn/ui Components](https://ui.shadcn.com/docs/components) — UI component library
|
||||
- [Supabase Auth](https://supabase.com/docs/guides/auth) — Authentication
|
||||
- [date-fns](https://date-fns.org/) — Date manipulation library
|
||||
|
||||
**Inspiration & Benchmarks:**
|
||||
- [Cal.com](https://cal.com) — Open-source scheduling (UI inspiration)
|
||||
- [Calendly](https://calendly.com) — Modern scheduling UX (simplicity benchmark)
|
||||
- [Acuity Scheduling](https://acuityscheduling.com) — Healthcare scheduling features
|
||||
- Google Calendar — De facto standard, users expect this UX
|
||||
|
||||
### Competitive Analysis (Legacy GGZ Systems)
|
||||
|
||||
**Why we're better:**
|
||||
|
||||
| Feature | PinkRoccade | Nedap ECD | Zorgdomein | **Mini-EPD** |
|
||||
|---------|-------------|-----------|------------|--------------|
|
||||
| Afspraak maken | 5+ clicks, slow | 4-5 clicks | 6+ clicks | **2-3 clicks** |
|
||||
| Dubbele boeking | Hard block | Warning | Hard block | **Warning + override** |
|
||||
| Afspraak ↔ Verslag | Manual link | No link | Manual link | **1-click bidirectioneel** |
|
||||
| AI-assisted verslag | ❌ | ❌ | ❌ | **✅ Core feature** |
|
||||
| Mobile UX | Terrible | Desktop-only | Barely works | **Responsive + optimized** |
|
||||
| Load time | 5-10s | 3-5s | 4-8s | **< 2s** |
|
||||
| Training tijd | 2-4 dagen | 1-2 dagen | 2-3 dagen | **< 10 minuten** |
|
||||
| Kosten | €200-400/maand | €150-300/maand | €180-350/maand | **€50/maand** |
|
||||
|
||||
**Key Differentiators:**
|
||||
1. 🚀 **Speed:** Zowel UX als development speed
|
||||
2. 🤖 **AI Integration:** Naadloos, niet als afterthought
|
||||
3. 💰 **Price:** 1/4e van legacy systemen
|
||||
4. 🎯 **Focus:** Alleen wat je nodig hebt, geen bloat
|
||||
|
||||
---
|
||||
|
||||
### Contact & Feedback
|
||||
|
||||
**Product Owner:** Colin
|
||||
**Email:** [email]
|
||||
**LinkedIn:** [profile]
|
||||
**GitHub Repo:** [link to public repo]
|
||||
|
||||
**Feedback Welcome:**
|
||||
- 💬 DM op LinkedIn
|
||||
- 🐛 GitHub Issues voor bugs
|
||||
- 💡 Feature requests via Google Form [link]
|
||||
|
||||
---
|
||||
|
||||
**Document Status:** ✅ Approved
|
||||
**Next Step:** → Bouwplan Agenda Module v1.1 (technische uitwerking)
|
||||
|
||||
**Changelog:**
|
||||
|
||||
| Versie | Datum | Auteur | Wijziging |
|
||||
|--------|-------|--------|-----------|
|
||||
| v1.0 | 02-12-2024 | Colin | Initiële PRD — scope, flows, success criteria gedefinieerd |
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,341 +0,0 @@
|
||||
# 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 && (
|
||||
<div className="px-4 py-1 text-xs text-amber-700 bg-amber-50 border-b">
|
||||
Dossier: {patientName}
|
||||
</div>
|
||||
)}
|
||||
```
|
||||
|
||||
**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 |
|
||||
@@ -1,367 +0,0 @@
|
||||
# 🧩 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 |
|
||||
@@ -1,205 +0,0 @@
|
||||
# 📄 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 |
|
||||
@@ -1,403 +0,0 @@
|
||||
# Product Requirements Document (PRD) — AI Documentatie Assistent
|
||||
|
||||
**Projectnaam:** Mini-ECD – AI Documentatie Assistent
|
||||
**Versie:** v1.0
|
||||
**Datum:** 01-12-2025
|
||||
**Auteur:** Colin Lit
|
||||
**Status:** Draft – Ready for Review
|
||||
|
||||
---
|
||||
|
||||
## 1. Doelstelling
|
||||
|
||||
**Doel van deze sectie:** Beschrijf waarom dit product wordt gebouwd en wat het beoogde resultaat is.
|
||||
|
||||
**Toelichting:** Een intelligente chat-assistent die eindgebruikers van het EPD helpt door vragen te beantwoorden op basis van de systeemdocumentatie. De focus ligt op het direct beschikbaar maken van informatie zonder dat gebruikers zelf door documentatie hoeven te zoeken.
|
||||
|
||||
> **Kernbelofte:** Direct antwoord op vragen over het EPD systeem, 24/7 beschikbaar via een handige chat widget.
|
||||
|
||||
**Type:** MVP Feature binnen Mini-ECD Prototype — Eerste AI-integratie als opstap naar complexere features (zoals AI Pre-fill Behandelplan)
|
||||
|
||||
**Relatie tot andere features:** Dit is de eerste AI-integratie die:
|
||||
1. De Claude API infrastructuur opzet
|
||||
2. Streaming responses implementeert
|
||||
3. AI UI patterns (amber thema) in productie brengt
|
||||
4. Als fundament dient voor toekomstige AI features
|
||||
|
||||
---
|
||||
|
||||
## 2. Doelgroep
|
||||
|
||||
**Doel:** Schets wie de eindgebruikers en stakeholders zijn.
|
||||
|
||||
### Primaire gebruikers
|
||||
|
||||
| Rol | Behoefte | Pijnpunt nu |
|
||||
|-----|----------|-------------|
|
||||
| **GGZ Behandelaar** | Snel antwoord op "hoe werkt X?" | Documentatie doorzoeken kost tijd |
|
||||
| **Verpleegkundige** | Hulp bij onbekende functies | Moet collega's vragen of zelf uitzoeken |
|
||||
| **Nieuwe medewerker** | Systeem leren kennen | Geen interactieve onboarding |
|
||||
|
||||
### Secundaire stakeholders
|
||||
|
||||
- **Demo-bezoekers:** Product owners/managers die AI-mogelijkheden willen zien
|
||||
- **Developers:** Technische professionals geïnteresseerd in AI-integratie patterns
|
||||
- **Support team:** (toekomst) Minder support tickets door self-service
|
||||
|
||||
---
|
||||
|
||||
## 3. Kernfunctionaliteiten (MVP-scope)
|
||||
|
||||
**Doel:** Afbakenen van de minimale werkende functies.
|
||||
|
||||
### 3.1 Floating Chat Widget
|
||||
|
||||
| Aspect | Specificatie |
|
||||
|--------|--------------|
|
||||
| **Positie** | Rechtsonder in EPD interface |
|
||||
| **Trigger** | Amber knop met Sparkles icon |
|
||||
| **Paneel** | 384px breed, max 80vh hoog |
|
||||
| **Animatie** | Slide-in van onder + fade |
|
||||
|
||||
### 3.2 Documentatie-gebaseerde Antwoorden
|
||||
|
||||
| Aspect | Specificatie |
|
||||
|--------|--------------|
|
||||
| **Knowledge Base** | 14 MDX bestanden in `/content/nl/documentatie/` |
|
||||
| **Taal** | Nederlands (input en output) |
|
||||
| **Scope** | Alleen informatie uit documentatie |
|
||||
| **Eerlijkheid** | "Weet ik niet" bij ontbrekende info |
|
||||
|
||||
**Beschikbare documentatie:**
|
||||
- `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
|
||||
- `voice-controlled-reporting.mdx` - Voice features (EN)
|
||||
- `verpleegkundige-overdracht.mdx` - Overdracht workflow
|
||||
- `fhir-datamodel.mdx` - Data model uitleg
|
||||
- `fhir-api.mdx` - API documentatie
|
||||
- `release-notes-system.mdx` - Release notes
|
||||
- `build-errors-fix.mdx` - Troubleshooting
|
||||
- `webpack-module-resolution.mdx` - Technische docs
|
||||
|
||||
### 3.3 Streaming Responses
|
||||
|
||||
| Aspect | Specificatie |
|
||||
|--------|--------------|
|
||||
| **Model** | Claude claude-sonnet-4-20250514 |
|
||||
| **Streaming** | Server-Sent Events (SSE) |
|
||||
| **UX** | Tekst verschijnt woord-voor-woord |
|
||||
| **Timeout** | 30 seconden max |
|
||||
|
||||
### 3.4 Sessie-based Conversatie
|
||||
|
||||
| Aspect | Specificatie |
|
||||
|--------|--------------|
|
||||
| **Persistentie** | Alleen tijdens browser sessie |
|
||||
| **Context** | Volledige conversatie wordt meegestuurd |
|
||||
| **Welkomstbericht** | Automatisch bij openen widget |
|
||||
| **Opslag** | React state (geen database) |
|
||||
|
||||
---
|
||||
|
||||
## 4. Gebruikersflows (Demo- en MVP-flows)
|
||||
|
||||
**Doel:** Laten zien hoe de gebruiker stap-voor-stap door het systeem gaat.
|
||||
|
||||
### Flow 1: Happy Path — Vraag Stellen
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 1. Gebruiker werkt in EPD en heeft vraag │
|
||||
│ ↓ │
|
||||
│ 2. Klikt op amber chat-knop rechtsonder │
|
||||
│ ↓ │
|
||||
│ 3. Widget opent met welkomstbericht │
|
||||
│ ↓ │
|
||||
│ 4. Typt vraag: "Hoe maak ik een intake aan?" │
|
||||
│ ↓ │
|
||||
│ 5. Ziet streaming antwoord verschijnen │
|
||||
│ ↓ │
|
||||
│ 6. Stelt eventueel vervolgvraag │
|
||||
│ ↓ │
|
||||
│ 7. Sluit widget en gaat verder met werk │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Doorlooptijd:** < 30 seconden voor antwoord
|
||||
|
||||
### Flow 2: Vraag Buiten Scope
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 1. Gebruiker vraagt: "Wat is de beste behandeling voor X?" │
|
||||
│ ↓ │
|
||||
│ 2. Assistent antwoordt: │
|
||||
│ "Die informatie heb ik niet. Ik kan alleen helpen met │
|
||||
│ vragen over hoe het EPD systeem werkt. Probeer: │
|
||||
│ - Hoe maak ik een behandelplan? │
|
||||
│ - Hoe werkt de screening?" │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Flow 3: Technische Vraag
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 1. Developer vraagt: "Hoe werkt de FHIR API?" │
|
||||
│ ↓ │
|
||||
│ 2. Assistent geeft technische uitleg uit fhir-api.mdx │
|
||||
│ ↓ │
|
||||
│ 3. Verwijst naar relevante endpoints en voorbeelden │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Niet in Scope
|
||||
|
||||
**Doel:** Duidelijk maken wat (nog) niet wordt gebouwd.
|
||||
|
||||
| Feature | Reden |
|
||||
|---------|-------|
|
||||
| Conversatie opslaan in database | Complexiteit, privacy overwegingen |
|
||||
| Meerdere AI providers | Alleen Claude voor nu |
|
||||
| RAG / Vector search | Documentatie past in context window |
|
||||
| Proactieve suggesties | Focus op vraag-antwoord eerst |
|
||||
| Voice input | Aparte feature (spraakherkenning bestaat al) |
|
||||
| Multi-language | Alleen Nederlands voor MVP |
|
||||
| Admin dashboard voor prompts | Hardcoded prompts voor nu |
|
||||
| Feedback/rating systeem | Post-MVP |
|
||||
|
||||
---
|
||||
|
||||
## 6. Succescriteria
|
||||
|
||||
**Doel:** Objectieve meetlat voor een geslaagde oplevering.
|
||||
|
||||
| Criterium | Target | Meetmethode |
|
||||
|-----------|--------|-------------|
|
||||
| **Response Time** | First token < 2 sec | Console timing |
|
||||
| **Antwoord Kwaliteit** | Relevant en correct | User feedback |
|
||||
| **Widget Laadtijd** | < 100ms | Performance metrics |
|
||||
| **Error Rate** | < 5% API failures | Error logging |
|
||||
| **Demo Doorlooptijd** | Vraag → Antwoord < 30 sec | Live demo |
|
||||
| **Beschikbaarheid** | Widget altijd zichtbaar in EPD | Visual check |
|
||||
|
||||
---
|
||||
|
||||
## 7. Risico's & Mitigatie
|
||||
|
||||
**Doel:** Risico's vroeg signaleren en plannen hoe ermee om te gaan.
|
||||
|
||||
| Risico | Impact | Mitigatie |
|
||||
|--------|--------|-----------|
|
||||
| **AI hallucineert informatie** | Hoog | Strikte system prompt; "alleen uit docs"; duidelijk AI label |
|
||||
| **Documentatie te groot voor context** | Middel | ~119KB past; monitoring van token usage |
|
||||
| **API rate limits / kosten** | Middel | Geen caching nodig (sessie-based); prompt optimalisatie |
|
||||
| **Trage response (>5s)** | Middel | Streaming UX; skeleton loader; timeout handling |
|
||||
| **Privacy vragen in chat** | Laag | Geen logging; sessie-only; duidelijke scope communicatie |
|
||||
|
||||
---
|
||||
|
||||
## 8. Roadmap / Vervolg (Post-MVP)
|
||||
|
||||
**Doel:** Richting geven aan toekomstige uitbreidingen.
|
||||
|
||||
### Fase 2: Enhanced Assistant (Q1 2026)
|
||||
|
||||
1. **Conversatie Persistentie** — Gesprekken opslaan per gebruiker
|
||||
2. **Feedback Systeem** — Thumbs up/down op antwoorden
|
||||
3. **Suggestie Chips** — Voorgestelde vragen tonen
|
||||
4. **Context Awareness** — Weet op welke pagina gebruiker zit
|
||||
|
||||
### Fase 3: Proactive Help (Q2 2026)
|
||||
|
||||
5. **Onboarding Flow** — Guided tour via chat
|
||||
6. **Error Recovery** — Automatisch hulp bij errors
|
||||
7. **Tooltip Integration** — AI uitleg bij complexe UI elementen
|
||||
|
||||
### Fase 4: Advanced AI (Q2-Q3 2026)
|
||||
|
||||
8. **AI Pre-fill Behandelplan** — Zie `prd-ai-prefill-behandelplan-v1.md`
|
||||
9. **Multi-provider Support** — OpenAI/Gemini fallback
|
||||
10. **RAG Implementation** — Voor grotere knowledge bases
|
||||
|
||||
---
|
||||
|
||||
## 9. Bijlagen & Referenties
|
||||
|
||||
**Doel:** Bronnen koppelen voor context en consistentie.
|
||||
|
||||
### Project Documentatie
|
||||
|
||||
- PRD AI Pre-fill Behandelplan (`prd-ai-prefill-behandelplan-v1.md`)
|
||||
- PRD Mini-ECD v1.2 (`prd-mini-ecd-v1_2.md`)
|
||||
- Functioneel Ontwerp v2 (`fo-mini-ecd-v2.md`)
|
||||
- UX Stylesheet (`ux-stylesheet.md`)
|
||||
|
||||
### Externe Referenties
|
||||
|
||||
- [Claude API Documentation](https://docs.anthropic.com)
|
||||
- [Anthropic Streaming Guide](https://docs.anthropic.com/en/api/streaming)
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: Technische Specificatie
|
||||
|
||||
### A.1 Architectuur
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌──────────────────┐ ┌─────────────┐
|
||||
│ DocsChatWidget │────▶│ /api/docs/chat │────▶│ Claude API │
|
||||
│ (React State) │◀────│ (Streaming SSE) │◀────│ (streaming) │
|
||||
└─────────────────┘ └──────────────────┘ └─────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ knowledge-base.ts│
|
||||
│ (laadt 14 MDX) │
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
### A.2 Bestandsstructuur
|
||||
|
||||
**Nieuwe bestanden:**
|
||||
|
||||
```
|
||||
lib/
|
||||
docs/
|
||||
knowledge-base.ts # Documentatie loader
|
||||
|
||||
app/
|
||||
api/
|
||||
docs/
|
||||
chat/
|
||||
route.ts # Streaming API endpoint
|
||||
|
||||
components/
|
||||
docs-chat/
|
||||
docs-chat-widget.tsx # Floating widget container
|
||||
chat-messages.tsx # Message list component
|
||||
chat-input.tsx # Input met send button
|
||||
use-docs-chat.ts # Custom hook voor state
|
||||
```
|
||||
|
||||
**Te wijzigen:**
|
||||
|
||||
```
|
||||
app/epd/components/epd-layout-client.tsx # Widget toevoegen
|
||||
```
|
||||
|
||||
### A.3 API Endpoint
|
||||
|
||||
```
|
||||
POST /api/docs/chat
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"messages": [
|
||||
{ "role": "user", "content": "Hoe maak ik een intake?" },
|
||||
{ "role": "assistant", "content": "Om een intake aan te maken..." }
|
||||
],
|
||||
"userMessage": "En hoe voeg ik notities toe?"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** Server-Sent Events stream
|
||||
|
||||
```
|
||||
event: content_block_delta
|
||||
data: {"type":"content_block_delta","delta":{"type":"text_delta","text":"Om "}}
|
||||
|
||||
event: content_block_delta
|
||||
data: {"type":"content_block_delta","delta":{"type":"text_delta","text":"notities "}}
|
||||
...
|
||||
```
|
||||
|
||||
### A.4 System Prompt
|
||||
|
||||
```
|
||||
Je bent een vriendelijke documentatie assistent voor het Mini-ECD,
|
||||
een GGZ EPD (Elektronisch Patiënt Dossier) systeem.
|
||||
|
||||
## Jouw rol
|
||||
- Beantwoord vragen over hoe het EPD systeem werkt
|
||||
- Help gebruikers functies te vinden en te gebruiken
|
||||
- Verwijs naar relevante documentatie secties
|
||||
|
||||
## Belangrijke regels
|
||||
- Je ENIGE kennisbron is de onderstaande documentatie
|
||||
- Beantwoord vragen ALLEEN op basis van deze informatie
|
||||
- Als informatie ontbreekt: zeg eerlijk dat je het niet weet
|
||||
- Verzin NOOIT informatie die niet in de documentatie staat
|
||||
- Geef GEEN medisch advies of behandelsuggesties
|
||||
|
||||
## Jouw publiek
|
||||
Zorgprofessionals (behandelaars, verpleegkundigen) die het EPD gebruiken.
|
||||
|
||||
## Stijl
|
||||
- Schrijf in het Nederlands
|
||||
- Wees beknopt maar vriendelijk
|
||||
- Gebruik bullet points voor stappen
|
||||
- Verwijs naar specifieke menu's en knoppen waar relevant
|
||||
|
||||
---
|
||||
DOCUMENTATIE:
|
||||
|
||||
{content van alle 14 MDX bestanden}
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
### A.5 Component Specificaties
|
||||
|
||||
**DocsChatWidget:**
|
||||
- Positie: `fixed bottom-6 right-6`
|
||||
- Z-index: `z-50`
|
||||
- Trigger: 56x56px amber gradient button
|
||||
- Panel: 384px breed, max 80vh hoog
|
||||
- Animatie: `animate-in slide-in-from-bottom-4 fade-in`
|
||||
|
||||
**ChatMessages:**
|
||||
- Scroll: `overflow-y-auto`
|
||||
- User bubbles: rechts, `bg-amber-100`
|
||||
- Assistant bubbles: links, `bg-slate-100`
|
||||
- Streaming indicator: pulserende cursor
|
||||
|
||||
**ChatInput:**
|
||||
- Textarea: auto-resize, max 4 regels
|
||||
- Send button: amber, disabled tijdens loading
|
||||
- Enter: verstuur (Shift+Enter: nieuwe regel)
|
||||
|
||||
---
|
||||
|
||||
## Appendix B: UI States
|
||||
|
||||
### Widget States
|
||||
|
||||
| State | Weergave | Actie |
|
||||
|-------|----------|-------|
|
||||
| **Gesloten** | Amber floating button | Klik → Open |
|
||||
| **Open - Idle** | Chat panel met welkomst | Type vraag |
|
||||
| **Open - Loading** | Streaming indicator | Wacht |
|
||||
| **Open - Streaming** | Tekst verschijnt | Lees |
|
||||
| **Open - Error** | Foutmelding | Retry knop |
|
||||
|
||||
### Welkomstbericht
|
||||
|
||||
> "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?"
|
||||
|
||||
---
|
||||
|
||||
*Document gegenereerd als onderdeel van AI Speedrun — Week 3*
|
||||
@@ -1,349 +0,0 @@
|
||||
# 📄 Product Requirements Document (PRD) — AI Pre-fill Behandelplan
|
||||
|
||||
**Projectnaam:** Mini-ECD – AI Pre-fill Behandelplan
|
||||
**Versie:** v1.0
|
||||
**Datum:** 30-11-2025
|
||||
**Auteur:** Colin Lit
|
||||
**Status:** Draft – Ready for Review
|
||||
|
||||
---
|
||||
|
||||
## 1. Doelstelling
|
||||
|
||||
🎯 **Doel van deze sectie:** Beschrijf waarom dit product wordt gebouwd en wat het beoogde resultaat is.
|
||||
|
||||
📘 **Toelichting:** Een intelligent pre-fill systeem dat automatisch behandelplanconcepten genereert op basis van intake-notities en probleemprofielen. De focus ligt op het drastisch verminderen van administratieve last terwijl klinische kwaliteit behouden blijft.
|
||||
|
||||
> **Kernbelofte:** Van 30+ minuten handmatig behandelplan schrijven naar <5 minuten review en publiceren.
|
||||
|
||||
**Type:** MVP Feature binnen Mini-ECD Prototype (Week 3-4 AI Speedrun)
|
||||
|
||||
---
|
||||
|
||||
## 2. Doelgroep
|
||||
|
||||
🎯 **Doel:** Schets wie de eindgebruikers en stakeholders zijn.
|
||||
|
||||
### Primaire gebruikers
|
||||
|
||||
| Rol | Behoefte | Pijnpunt nu |
|
||||
|-----|----------|-------------|
|
||||
| **GGZ Behandelaar** | Snel bruikbaar behandelplan | 30+ min typen per plan |
|
||||
| **Regiebehandelaar** | Review & accorderen | Wachten op aanlevering |
|
||||
|
||||
### Secundaire stakeholders
|
||||
|
||||
- **Demo-bezoekers:** Product owners/managers die AI-mogelijkheden willen zien
|
||||
- **Developers:** Technische professionals geïnteresseerd in AI-integratie patterns
|
||||
- **Zorgverzekeraars:** (toekomst) Compliance met zorgstandaarden
|
||||
|
||||
---
|
||||
|
||||
## 3. Kernfunctionaliteiten (MVP-scope)
|
||||
|
||||
🎯 **Doel:** Afbakenen van de minimale werkende functies.
|
||||
|
||||
### 3.1 Automatische Draft Generatie
|
||||
|
||||
| Aspect | Specificatie |
|
||||
|--------|--------------|
|
||||
| **Trigger** | Probleemprofiel opgeslagen → AI genereert draft |
|
||||
| **Input** | Intake-notities + DSM-categorie + Severity |
|
||||
| **Output** | Concept behandelplan (4 secties) |
|
||||
| **Timing** | On-demand bij navigatie naar Behandelplan tab |
|
||||
|
||||
### 3.2 SMART Doelen Generatie
|
||||
|
||||
1. AI extraheert concrete klachten uit intake-notities
|
||||
2. Genereert 2-4 SMART-doelen afgestemd op DSM-categorie en severity
|
||||
3. Elk doel bevat:
|
||||
- **S**pecifiek gedrag/situatie
|
||||
- **M**eetbaar criterium (frequentie, intensiteit)
|
||||
- **A**cceptabel voor cliënt
|
||||
- **R**ealistisch binnen behandelkader
|
||||
- **T**ijdgebonden (X weken)
|
||||
|
||||
**Voorbeeld output:**
|
||||
> "Cliënt ervaart maximaal 1 paniekaanval per week (nu: 3x/week) binnen 8 weken behandeling"
|
||||
|
||||
### 3.3 Evidence-based Interventie Mapping
|
||||
|
||||
| DSM-Categorie | Primaire Interventies | Severity → Intensiteit |
|
||||
|---------------|----------------------|------------------------|
|
||||
| Angststoornissen | CGT, Exposure, ACT | Hoog → 12-16 sessies |
|
||||
| Stemmingsklachten | CGT, IPT, Gedragsactivatie | Middel → 8-12 sessies |
|
||||
| Trauma/PTSS | EMDR, Narratieve therapie | Hoog → 12+ sessies |
|
||||
| Persoonlijkheid | Schematherapie, MBT | Hoog → 20+ sessies |
|
||||
|
||||
### 3.4 Micro-AI Regeneratie
|
||||
|
||||
- Per sectie/item een **[↻ Regenereer]** knop
|
||||
- Behandelaar kan specifieke onderdelen laten hergenereren
|
||||
- Behoudt context van overige secties
|
||||
- Optioneel: korte instructie meegeven ("maak concreter", "focus op werk")
|
||||
|
||||
### 3.5 *(Stretch)* ROM Score Integratie
|
||||
|
||||
- Indien ROM-scores beschikbaar: meenemen in doelbepaling
|
||||
- Baseline scores automatisch toevoegen aan meetmomenten
|
||||
- Suggestie voor ROM-instrument bij evaluatiemomenten
|
||||
|
||||
---
|
||||
|
||||
## 4. Gebruikersflows (Demo- en MVP-flows)
|
||||
|
||||
🎯 **Doel:** Laten zien hoe de gebruiker stap-voor-stap door het systeem gaat.
|
||||
|
||||
### Flow 1: Happy Path — Intake → Behandelplan
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 1. Behandelaar voltooit intake en slaat notities op │
|
||||
│ ↓ │
|
||||
│ 2. Klikt [AI › Analyseer intake] │
|
||||
│ ↓ │
|
||||
│ 3. Probleemprofiel wordt gegenereerd (DSM + Severity) │
|
||||
│ ↓ │
|
||||
│ 4. Accepteert/bewerkt profiel → Slaat op │
|
||||
│ ↓ │
|
||||
│ 5. Navigeert naar Behandelplan tab │
|
||||
│ ↓ │
|
||||
│ 6. Ziet: "⚡ AI heeft een concept klaargezet" │
|
||||
│ ↓ │
|
||||
│ 7. Reviewt SMART-doelen, past aan indien nodig │
|
||||
│ ↓ │
|
||||
│ 8. Klikt [Accepteer & Publiceer] → Plan v1 actief │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Doorlooptijd:** < 3 minuten (vs. 30+ minuten traditioneel)
|
||||
|
||||
### Flow 2: Regeneratie van specifiek onderdeel
|
||||
|
||||
1. Behandelaar vindt Doel 2 niet passend
|
||||
2. Klikt **[↻ Regenereer]** bij Doel 2
|
||||
3. AI genereert alternatief doel met zelfde context
|
||||
4. Behandelaar selecteert nieuw voorstel of bewerkt handmatig
|
||||
|
||||
### Flow 3: Handmatige start (geen AI)
|
||||
|
||||
1. Behandelaar opent Behandelplan zonder probleemprofiel
|
||||
2. Ziet melding: *"Geen concept beschikbaar. Vul eerst probleemprofiel in of start handmatig."*
|
||||
3. Keuze: **[Naar Probleemprofiel]** of **[Start leeg plan]**
|
||||
|
||||
---
|
||||
|
||||
## 5. Niet in Scope
|
||||
|
||||
🎯 **Doel:** Duidelijk maken wat (nog) niet wordt gebouwd.
|
||||
|
||||
| Feature | Reden |
|
||||
|---------|-------|
|
||||
| Volledige DSM-5 classificatie | Alleen DSM-light (6 categorieën) voor prototype |
|
||||
| Multi-disciplinaire plannen (MDO) | Complexiteit, geen meerwaarde voor demo |
|
||||
| DBC/ZPM declaratie-koppeling | Vereist externe integraties |
|
||||
| Real-time collaboration | Technisch complex, lage prioriteit |
|
||||
| Volledige ROM-vragenlijst afname | Alleen scores indien al beschikbaar |
|
||||
| Productie audit logging | Demo-only, geen compliance vereist |
|
||||
| Meerdere AI providers | Alleen Claude voor nu |
|
||||
|
||||
---
|
||||
|
||||
## 6. Succescriteria
|
||||
|
||||
🎯 **Doel:** Objectieve meetlat voor een geslaagde oplevering.
|
||||
|
||||
| Criterium | Target | Meetmethode |
|
||||
|-----------|--------|-------------|
|
||||
| **AI Response Time** | < 5 seconden | Console timing |
|
||||
| **Draft Kwaliteit** | ≥ 80% bruikbaar zonder grote edits | User feedback |
|
||||
| **Tijdsbesparing** | Van 30+ min → < 5 min | Stopwatch demo |
|
||||
| **Demo Doorlooptijd** | Intake → Plan in < 3 min | Live demo |
|
||||
| **Error Rate** | < 5% API failures | Error logging |
|
||||
| **User Acceptance** | Min. 2 testers positief | Feedback forms |
|
||||
|
||||
---
|
||||
|
||||
## 7. Risico's & Mitigatie
|
||||
|
||||
🎯 **Doel:** Risico's vroeg signaleren en plannen hoe ermee om te gaan.
|
||||
|
||||
| Risico | Impact | Mitigatie |
|
||||
|--------|--------|-----------|
|
||||
| **AI output klinisch onbruikbaar** | 🔴 Hoog | Prompts testen met GGZ-professionals; few-shot examples; "AI Concept" label |
|
||||
| **Hallucinaties in doelen/interventies** | 🟡 Middel | Strikte JSON schema validatie; verplichte menselijke review |
|
||||
| **API rate limits / kosten** | 🟡 Middel | Caching van drafts; prompt optimalisatie voor tokens |
|
||||
| **Trage response (>10s)** | 🟡 Middel | Streaming response; skeleton loaders; timeout handling |
|
||||
| **Scope creep ("nog even dit erbij")** | 🟡 Middel | Strikte PRD; "Post-MVP" parkeren |
|
||||
| **Privacy concerns demo-data** | 🟢 Laag | Alleen fictieve cliëntdata gebruiken |
|
||||
|
||||
---
|
||||
|
||||
## 8. Roadmap / Vervolg (Post-MVP)
|
||||
|
||||
🎯 **Doel:** Richting geven aan toekomstige uitbreidingen.
|
||||
|
||||
### Fase 2: Enhanced AI (Q1 2026)
|
||||
|
||||
1. **Background Generation** — Draft al genereren bij opslaan probleemprofiel
|
||||
2. **Template Bibliotheek** — Voorgedefinieerde templates per diagnose
|
||||
3. **Prompt Tuning** — A/B testen van verschillende prompt strategieën
|
||||
|
||||
### Fase 3: Clinical Intelligence (Q2 2026)
|
||||
|
||||
4. **Sessie-over-Sessie Tracking** — AI vergelijkt voortgang vs. doelen
|
||||
5. **ROM Integratie** — Automatische vragenlijst afname en scoring
|
||||
6. **Risico Detectie** — Flagging bij zorgwekkende patronen
|
||||
|
||||
### Fase 4: Compliance & Scale (Q3 2026)
|
||||
|
||||
7. **Zorgstandaard Compliance** — Check tegen GGZ richtlijnen
|
||||
8. **Multi-provider Support** — OpenAI/Gemini fallback
|
||||
9. **Audit Trail** — Volledige logging voor verantwoording
|
||||
|
||||
---
|
||||
|
||||
## 9. Bijlagen & Referenties
|
||||
|
||||
🎯 **Doel:** Bronnen koppelen voor context en consistentie.
|
||||
|
||||
### Project Documentatie
|
||||
|
||||
- PRD Mini-ECD v1.2 (`prd-mini-ecd-v1_2.md`)
|
||||
- Functioneel Ontwerp v2 (`fo-mini-ecd-v2.md`)
|
||||
- Technisch Ontwerp (`to-mini-ecd-v1_2.md`)
|
||||
- UX Stylesheet (`ux-stylesheet.md`)
|
||||
- Live Transcriptie FO (`fo-live-transcriptie-v1.md`)
|
||||
- FHIR GGZ Schema (`20241121_fhir_ggz_schema.sql`)
|
||||
|
||||
### Externe Referenties
|
||||
|
||||
- [Claude API Documentation](https://docs.anthropic.com)
|
||||
- [GGZ Zorgstandaarden](https://www.ggzstandaarden.nl)
|
||||
- [SMART Doelen Framework](https://www.ggzstandaarden.nl/generieke-modules/individueel-zorgplan)
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: Technische Specificatie
|
||||
|
||||
### A.1 Data Flow
|
||||
|
||||
```
|
||||
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||||
│ Intake Notities │────▶│ │────▶│ Behandelplan │
|
||||
│ (document_ref) │ │ Claude API │ │ Draft (JSONB) │
|
||||
├──────────────────┤ │ │ ├──────────────────┤
|
||||
│ Probleemprofiel │────▶│ /v1/messages │ │ - doelen[] │
|
||||
│ (DSM + Severity)│ │ │ │ - interventies[]│
|
||||
└──────────────────┘ └──────────────────┘ │ - frequentie │
|
||||
│ - meetmomenten[]│
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
### A.2 API Endpoint
|
||||
|
||||
```
|
||||
POST /api/ai/generate-behandelplan
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"clientId": "uuid",
|
||||
"intakeIds": ["uuid", "uuid"],
|
||||
"probleemProfiel": {
|
||||
"categorie": "Angststoornissen",
|
||||
"severity": "Hoog",
|
||||
"opmerkingen": "Paniekaanvallen 3x/week, vermijding openbare ruimtes"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"draft": {
|
||||
"doelen": [
|
||||
{
|
||||
"id": "doel-1",
|
||||
"tekst": "Frequentie paniekaanvallen verminderen van 3x/week naar max 1x/week",
|
||||
"tijdslimiet": "8 weken",
|
||||
"meetbaar": "Dagboekregistratie"
|
||||
}
|
||||
],
|
||||
"interventies": [
|
||||
{
|
||||
"id": "int-1",
|
||||
"naam": "Cognitieve Gedragstherapie (CGT)",
|
||||
"sessies": 12,
|
||||
"rationale": "Evidence-based voor paniekstoornis"
|
||||
}
|
||||
],
|
||||
"frequentie": "Wekelijks, 50 minuten per sessie",
|
||||
"meetmomenten": [
|
||||
{ "moment": "Baseline", "week": 0 },
|
||||
{ "moment": "Tussentijds", "week": 4 },
|
||||
{ "moment": "Tussentijds", "week": 8 },
|
||||
{ "moment": "Afsluiting", "week": 12 }
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"model": "claude-sonnet-4-20250514",
|
||||
"tokens_used": 1847,
|
||||
"generation_time_ms": 3200
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### A.3 Claude Prompt Template (Conceptueel)
|
||||
|
||||
```
|
||||
Je bent een ervaren GGZ-behandelaar die behandelplannen opstelt volgens
|
||||
de Nederlandse zorgstandaarden.
|
||||
|
||||
## Context
|
||||
- Intake notities: {intakeContent}
|
||||
- DSM-categorie: {categorie}
|
||||
- Severity: {severity}
|
||||
- Aanvullende opmerkingen: {opmerkingen}
|
||||
|
||||
## Opdracht
|
||||
Genereer een behandelplan concept met:
|
||||
|
||||
1. **SMART Doelen** (2-4 stuks)
|
||||
- Specifiek, Meetbaar, Acceptabel, Realistisch, Tijdgebonden
|
||||
- Gebaseerd op de hoofdklachten uit de intake
|
||||
|
||||
2. **Interventies**
|
||||
- Evidence-based methoden passend bij de diagnose
|
||||
- Inclusief geschat aantal sessies
|
||||
|
||||
3. **Frequentie en Duur**
|
||||
- Behandelintensiteit afgestemd op severity
|
||||
|
||||
4. **Meetmomenten**
|
||||
- Evaluatieschema voor voortgangsbewaking
|
||||
|
||||
## Output Format
|
||||
Antwoord ALLEEN met valid JSON volgens het schema.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Appendix B: UI States
|
||||
|
||||
### Behandelplan Tab States
|
||||
|
||||
| State | Weergave | Actie |
|
||||
|-------|----------|-------|
|
||||
| **Geen profiel** | "Vul eerst probleemprofiel in" | [Naar Profiel] |
|
||||
| **Generating** | Skeleton loader + "AI genereert..." | Wacht |
|
||||
| **Draft ready** | "⚡ AI Concept" badge + content | Review/Edit |
|
||||
| **Error** | "Genereren mislukt" + retry | [Probeer opnieuw] |
|
||||
| **Concept** | Oranje badge, bewerkbaar | [Publiceer] |
|
||||
| **Gepubliceerd** | Groene badge, read-only | [Nieuwe versie] |
|
||||
|
||||
---
|
||||
|
||||
*Document gegenereerd als onderdeel van AI Speedrun — Week 3*
|
||||
@@ -1,483 +0,0 @@
|
||||
# ⚙️ 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": "<p>Doorzetten naar behandeling</p>",
|
||||
"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<ClientContext>
|
||||
|
||||
// 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 |
|
||||
@@ -1,438 +0,0 @@
|
||||
# Mission Control — Bouwplan Behandelplan Module
|
||||
|
||||
**Projectnaam:** Mini-EPD Prototype - Behandelplan Module
|
||||
**Versie:** v1.0
|
||||
**Datum:** 03-12-2024
|
||||
**Auteur:** Colin Lit
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en context
|
||||
|
||||
**Doel:**
|
||||
Een werkende MVP Behandelplan module bouwen die demonstreert hoe AI:
|
||||
- **Tijdsbesparing** realiseert: van 30+ minuten naar 2-5 minuten
|
||||
- **Kwaliteitsverbetering** biedt: SMART-doelen, evidence-based interventies
|
||||
- **Transparantie** creëert: cliënt kan eigen plan begrijpen (B1-taal)
|
||||
- **Praktische workflow** ondersteunt: intake → diagnose → behandelplan
|
||||
|
||||
**Context:**
|
||||
Deze module is onderdeel van de AI Speedrun LinkedIn Serie. Het prototype demonstreert AI-toegevoegde waarde voor zorgprofessionals, product owners en developers.
|
||||
|
||||
**Gerelateerde documenten:**
|
||||
- [PRD Behandelplan v2.0](./prd-behandelplan-v2-final.md)
|
||||
- [FO Behandelplan v1.0](./fo-behandelplan-v1.md)
|
||||
- [TO Behandelplan v1.0](./to-behandelplan-v1.md)
|
||||
|
||||
---
|
||||
|
||||
## 2. Uitgangspunten
|
||||
|
||||
### 2.1 Technische Stack
|
||||
|
||||
| Component | Technologie | Status |
|
||||
|-----------|-------------|--------|
|
||||
| **Frontend** | Next.js 14.2 + TailwindCSS + shadcn/ui | ✅ Bestaand |
|
||||
| **Backend** | Next.js API Routes + Server Actions | ✅ Bestaand |
|
||||
| **Database** | Supabase PostgreSQL + RLS | ✅ Bestaand |
|
||||
| **AI/ML** | Claude 3.5 Sonnet (Anthropic) | ✅ Bestaand |
|
||||
| **Hosting** | Vercel | ✅ Bestaand |
|
||||
| **Auth** | Supabase Auth | ✅ Bestaand |
|
||||
| **Icons** | Lucide React | ✅ Bestaand |
|
||||
| **Editor** | TipTap | ✅ Bestaand |
|
||||
| **Validation** | Zod | ✅ Bestaand |
|
||||
| **Charts** | Recharts | ⏳ Stretch goal |
|
||||
|
||||
### 2.2 Projectkaders
|
||||
|
||||
| Kader | Waarde |
|
||||
|-------|--------|
|
||||
| **Tijd** | 14-19 uur bouwtijd voor MVP |
|
||||
| **Budget** | €0 extra (bestaande API keys) |
|
||||
| **Team** | 1 developer + AI assistentie |
|
||||
| **Data** | Fictieve demo-data (geen productiegegevens) |
|
||||
| **Doel** | Werkende demo voor LinkedIn serie |
|
||||
|
||||
### 2.3 Gekozen Aanpak
|
||||
|
||||
- **Foundation first**: Types en database migraties eerst, dan UI
|
||||
- **Simpele visualisatie**: Progress bars i.p.v. radar chart (stretch)
|
||||
- **Simple JSON**: Geen streaming, enkele API call met loading state
|
||||
|
||||
### 2.4 Programmeer Uitgangspunten
|
||||
|
||||
**Code Quality Principles:**
|
||||
|
||||
- **DRY (Don't Repeat Yourself)**
|
||||
- Herbruikbare leefgebieden componenten
|
||||
- Centrale types voor behandelplan structuur
|
||||
- Utility functions voor score berekeningen
|
||||
|
||||
- **KISS (Keep It Simple, Stupid)**
|
||||
- Simple JSON API (geen streaming complexity)
|
||||
- Progress bars i.p.v. radar chart
|
||||
- Bestaande UI patterns hergebruiken
|
||||
|
||||
- **SOC (Separation of Concerns)**
|
||||
- Types in `/lib/types/behandelplan.ts`
|
||||
- AI prompts in `/lib/ai/behandelplan-prompt.ts`
|
||||
- Server actions in `/app/epd/patients/[id]/behandelplan/actions.ts`
|
||||
- UI components in `/components/behandelplan/`
|
||||
|
||||
- **YAGNI (You Aren't Gonna Need It)**
|
||||
- Geen versie-diff view (stretch)
|
||||
- Geen real-time collaboration
|
||||
- Geen notificaties/reminders
|
||||
|
||||
**Development Practices:**
|
||||
|
||||
- **Error Handling**
|
||||
- Try-catch op alle AI calls
|
||||
- Fallback naar manual mode bij AI failure
|
||||
- User-friendly foutmeldingen
|
||||
|
||||
- **Security**
|
||||
- ANTHROPIC_API_KEY in environment
|
||||
- RLS policies op care_plans
|
||||
- Zod validation op alle inputs
|
||||
|
||||
- **Performance**
|
||||
- AI response < 8 seconden
|
||||
- Skeleton loaders tijdens generatie
|
||||
- Optimistic updates voor status
|
||||
|
||||
---
|
||||
|
||||
## 3. Epics & Stories Overzicht
|
||||
|
||||
| Epic ID | Titel | Doel | Status | Stories | Geschat |
|
||||
|---------|-------|------|--------|---------|---------|
|
||||
| E0 | Foundation | Types, database schema | ✅ Done | 3 | 2-3 uur |
|
||||
| E1 | Leefgebieden | Intake formulier + score weergave | ✅ Done | 3 | 3-4 uur |
|
||||
| E2 | AI Generatie | Claude API endpoint + prompts | ✅ Done | 3 | 3-4 uur |
|
||||
| E3 | Behandelplan UI | Pagina + componenten | ✅ Done | 5 | 6-8 uur |
|
||||
| E4 | Stretch | Micro-regeneratie, radar chart | ⏳ Optioneel | 3 | 3-5 uur |
|
||||
|
||||
**Totaal MVP (E0-E3):** 14-19 uur
|
||||
**Totaal met Stretch:** 17-24 uur
|
||||
|
||||
---
|
||||
|
||||
## 4. Epics & Stories (Uitwerking)
|
||||
|
||||
### Epic 0 — Foundation (Types & Database)
|
||||
|
||||
**Epic Doel:** Solide basis met TypeScript types en database schema uitbreiding.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
|
||||
|----------|--------------|---------------------|--------|------------------|----|
|
||||
| E0.S1 | Leefgebieden types maken | `lib/types/leefgebieden.ts` met LifeDomain, LifeDomainScore types | ✅ | — | 1 |
|
||||
| E0.S2 | Behandelplan types maken | `lib/types/behandelplan.ts` met SmartGoal, Intervention, GeneratedPlan types + Zod schemas | ✅ | E0.S1 | 2 |
|
||||
| E0.S3 | Database migratie | `care_plans` uitgebreid met version, behandelstructuur, evaluatiemomenten; `intakes` met life_domains | ✅ | E0.S2 | 2 |
|
||||
|
||||
**Technical Notes:**
|
||||
```typescript
|
||||
// lib/types/leefgebieden.ts
|
||||
export type LifeDomain = 'dlv' | 'wonen' | 'werk' | 'sociaal' | 'vrijetijd' | 'financien' | 'gezondheid'
|
||||
|
||||
export interface LifeDomainScore {
|
||||
domain: LifeDomain
|
||||
baseline: number // 1-5
|
||||
current: number // 1-5
|
||||
target: number // 1-5
|
||||
notes: string
|
||||
priority: 'laag' | 'middel' | 'hoog'
|
||||
}
|
||||
```
|
||||
|
||||
**Deliverables:**
|
||||
- [x] `lib/types/leefgebieden.ts`
|
||||
- [x] `lib/types/behandelplan.ts`
|
||||
- [x] Database migratie via Supabase MCP (cloud-only, geen lokale instantie)
|
||||
- [x] Gegenereerde database types via `mcp__supabase__generate_typescript_types`
|
||||
|
||||
---
|
||||
|
||||
### Epic 1 — Leefgebieden Componenten
|
||||
|
||||
**Epic Doel:** Formulier voor intake + visuele weergave van scores.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
|
||||
|----------|--------------|---------------------|--------|------------------|----|
|
||||
| E1.S1 | Leefgebieden formulier | 7 sliders (1-5), toelichting velden, prioriteit dropdowns | ✅ | E0.S3 | 3 |
|
||||
| E1.S2 | Leefgebieden scores weergave | 7 progress bars met kleuren, baseline vs current indicator | ✅ | E0.S1 | 2 |
|
||||
| E1.S3 | Leefgebieden badge component | Gekleurde tag per domein met emoji | ✅ | E0.S1 | 1 |
|
||||
|
||||
**Technical Notes:**
|
||||
```typescript
|
||||
// Kleuren per leefgebied
|
||||
const DOMAIN_COLORS = {
|
||||
dlv: '#8b5cf6', // paars
|
||||
wonen: '#ec4899', // roze
|
||||
werk: '#f59e0b', // oranje
|
||||
sociaal: '#3b82f6', // blauw
|
||||
vrijetijd: '#10b981', // groen
|
||||
financien: '#eab308', // geel
|
||||
gezondheid: '#ef4444', // rood
|
||||
}
|
||||
```
|
||||
|
||||
**Deliverables:**
|
||||
- [x] `components/behandelplan/leefgebieden-form.tsx`
|
||||
- [x] `components/behandelplan/leefgebieden-scores.tsx`
|
||||
- [x] `components/behandelplan/leefgebieden-badge.tsx`
|
||||
- [x] `components/behandelplan/index.ts` (exports)
|
||||
|
||||
---
|
||||
|
||||
### Epic 2 — AI Generatie
|
||||
|
||||
**Epic Doel:** Claude API endpoint voor behandelplan generatie.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
|
||||
|----------|--------------|---------------------|--------|------------------|----|
|
||||
| E2.S1 | Prompt engineering | System prompt + user prompt templates, evidence-based mapping | ✅ | E0.S2 | 2 |
|
||||
| E2.S2 | Generate endpoint | `POST /api/behandelplan/generate` retourneert JSON, < 8 sec response | ✅ | E2.S1 | 3 |
|
||||
| E2.S3 | AI event logging | Calls loggen naar `ai_events` tabel | ✅ | E2.S2 | 1 |
|
||||
|
||||
**Technical Notes:**
|
||||
```typescript
|
||||
// Prompt structuur
|
||||
const messages = [
|
||||
{ role: 'system', content: BEHANDELPLAN_SYSTEM_PROMPT },
|
||||
{ role: 'user', content: buildUserPrompt(context) },
|
||||
];
|
||||
|
||||
// AI settings
|
||||
const settings = {
|
||||
model: 'claude-3-5-sonnet-20240620',
|
||||
max_tokens: 4096,
|
||||
temperature: 0.3, // Consistent maar niet robotisch
|
||||
};
|
||||
```
|
||||
|
||||
**Deliverables:**
|
||||
- [x] `lib/ai/behandelplan-prompt.ts`
|
||||
- [x] `lib/ai/intervention-mapping.ts`
|
||||
- [x] `app/api/behandelplan/generate/route.ts`
|
||||
|
||||
---
|
||||
|
||||
### Epic 3 — Behandelplan UI
|
||||
|
||||
**Epic Doel:** Werkende behandelplan pagina met alle componenten.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
|
||||
|----------|--------------|---------------------|--------|------------------|----|
|
||||
| E3.S1 | Behandelplan pagina | Placeholder vervangen, data loading, status weergave | ✅ | E2.S2 | 2 |
|
||||
| E3.S2 | Generate button + flow | Button triggert AI, loading state, resultaat weergave | ✅ | E3.S1 | 2 |
|
||||
| E3.S3 | SMART doelen sectie | Goal cards met progress, status, leefgebied badge | ✅ | E3.S1, E1.S3 | 3 |
|
||||
| E3.S4 | Interventies sectie | Intervention cards met gekoppelde doelen | ✅ | E3.S3 | 2 |
|
||||
| E3.S5 | Server actions | Create, update, delete, publish behandelplan | ✅ | E3.S1 | 2 |
|
||||
|
||||
**Technical Notes:**
|
||||
```
|
||||
/app/epd/patients/[id]/behandelplan/
|
||||
├── page.tsx # Server component
|
||||
├── actions.ts # Server actions
|
||||
└── components/
|
||||
├── behandelplan-view.tsx
|
||||
├── generate-button.tsx
|
||||
├── goals-section.tsx
|
||||
├── goal-card.tsx
|
||||
└── interventions-section.tsx
|
||||
```
|
||||
|
||||
**Deliverables:**
|
||||
- [x] `app/epd/patients/[id]/behandelplan/page.tsx` (vervangen)
|
||||
- [x] `app/epd/patients/[id]/behandelplan/page-client.tsx` (nieuw - client wrapper)
|
||||
- [x] `app/epd/patients/[id]/behandelplan/actions.ts`
|
||||
- [x] `components/behandelplan/behandelplan-view.tsx` (bevat generate button, goals section, interventions inline)
|
||||
|
||||
---
|
||||
|
||||
### Epic 4 — Stretch Goals (Optioneel)
|
||||
|
||||
**Epic Doel:** Extra features indien tijd beschikbaar.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | SP |
|
||||
|----------|--------------|---------------------|--------|------------------|----|
|
||||
| E4.S1 | Micro-regeneratie | Per doel [↻] knop, modal met instructie, nieuw voorstel | ⏳ | E3.S3 | 3 |
|
||||
| E4.S2 | Radar chart | Recharts installeren, 3-lijn spindiagram | ⏳ | E1.S2 | 3 |
|
||||
| E4.S3 | Sessie-planning | Tabel met 8-12 sessies, status per sessie | ⏳ | E3.S1 | 2 |
|
||||
|
||||
**Technical Notes:**
|
||||
- Recharts: `pnpm add recharts`
|
||||
- Regenerate endpoint: `POST /api/behandelplan/regenerate-section`
|
||||
|
||||
---
|
||||
|
||||
## 5. Kwaliteit & Testplan
|
||||
|
||||
### Test Types
|
||||
|
||||
| Test Type | Scope | Tools | Status |
|
||||
|-----------|-------|-------|--------|
|
||||
| Unit Tests | Types, utilities | Vitest | ⏳ Nice to have |
|
||||
| Integration | API endpoints | Manual + curl | ✅ Required |
|
||||
| Smoke Tests | Happy flow | Manual checklist | ✅ Required |
|
||||
| Performance | AI response time | Network tab | ✅ Required |
|
||||
|
||||
### Manual Test Checklist (Demo)
|
||||
|
||||
**Pre-conditions:**
|
||||
- [ ] Patient bestaat met intake data
|
||||
- [ ] Diagnose/probleemprofiel is ingevuld
|
||||
- [ ] Leefgebieden scores zijn ingevuld
|
||||
|
||||
**Happy Flow:**
|
||||
- [ ] Behandelplan pagina laadt zonder errors
|
||||
- [ ] "Genereer Behandelplan" knop is zichtbaar
|
||||
- [ ] AI genereert plan binnen 8 seconden
|
||||
- [ ] 2-4 SMART doelen worden getoond
|
||||
- [ ] Doelen hebben leefgebied badges
|
||||
- [ ] Interventies zijn gekoppeld aan doelen
|
||||
- [ ] B1-taal versie is beschikbaar per doel
|
||||
- [ ] Plan kan worden opgeslagen
|
||||
- [ ] Status kan worden gewijzigd (concept → actief)
|
||||
|
||||
**Error Scenarios:**
|
||||
- [ ] Geen intake data → "Vul eerst intake in" melding
|
||||
- [ ] AI API error → "AI niet beschikbaar" melding + retry optie
|
||||
- [ ] Validatie error → Inline error messages
|
||||
|
||||
---
|
||||
|
||||
## 6. Demo & Presentatieplan
|
||||
|
||||
### Demo Scenario
|
||||
|
||||
**Duur:** 5-7 minuten
|
||||
**Doelgroep:** LinkedIn audience (product owners, developers, zorgprofessionals)
|
||||
|
||||
**Flow:**
|
||||
|
||||
1. **Context** (30 sec)
|
||||
- "Behandelplan schrijven kost 30+ minuten"
|
||||
- "AI kan dit reduceren naar 2-5 minuten"
|
||||
|
||||
2. **Leefgebieden invullen** (1 min)
|
||||
- Toon 7 domeinen met sliders
|
||||
- Prioriteiten instellen
|
||||
- Opslaan
|
||||
|
||||
3. **AI Generatie** (2 min)
|
||||
- Klik op "Genereer Behandelplan"
|
||||
- Toon loading state met timer
|
||||
- Resultaat verschijnt (< 5 sec)
|
||||
|
||||
4. **Resultaat bekijken** (2 min)
|
||||
- SMART doelen met leefgebied tags
|
||||
- B1-taal versie voor cliënt
|
||||
- Evidence-based interventies
|
||||
- Behandelstructuur
|
||||
|
||||
5. **Aanpassen** (1 min)
|
||||
- Doel bewerken
|
||||
- Status wijzigen
|
||||
- Publiceren
|
||||
|
||||
**Key Highlights:**
|
||||
- Tijdsbesparing: 30 min → 5 min
|
||||
- Kwaliteit: SMART-criteria automatisch
|
||||
- Transparantie: B1-taal voor cliënt
|
||||
|
||||
---
|
||||
|
||||
## 7. Risico's & Mitigatie
|
||||
|
||||
| Risico | Kans | Impact | Mitigatie | Owner |
|
||||
|--------|------|--------|-----------|-------|
|
||||
| AI genereert invalide JSON | Middel | Hoog | Zod validation, retry (2x), fallback message | Dev |
|
||||
| AI response > 8 seconden | Laag | Middel | Timeout handling, loading feedback | Dev |
|
||||
| Leefgebieden UI te complex | Middel | Middel | Simpele sliders, geen radar chart (MVP) | Dev |
|
||||
| Database migratie faalt | Laag | Hoog | Test lokaal eerst, rollback script | Dev |
|
||||
| Prompt geeft slechte output | Middel | Hoog | Itereren op prompt, few-shot examples | Dev |
|
||||
| Scope creep | Hoog | Middel | Strikte MVP scope, stretch als optioneel | Dev |
|
||||
|
||||
---
|
||||
|
||||
## 8. Implementatie Volgorde
|
||||
|
||||
```
|
||||
Week 1 (14-19 uur totaal)
|
||||
├── Dag 1: E0 - Foundation (2-3 uur)
|
||||
│ ├── E0.S1: Leefgebieden types
|
||||
│ ├── E0.S2: Behandelplan types
|
||||
│ └── E0.S3: Database migratie
|
||||
│
|
||||
├── Dag 2: E1 - Leefgebieden (3-4 uur)
|
||||
│ ├── E1.S1: Formulier component
|
||||
│ ├── E1.S2: Scores weergave
|
||||
│ └── E1.S3: Badge component
|
||||
│
|
||||
├── Dag 3: E2 - AI Generatie (3-4 uur)
|
||||
│ ├── E2.S1: Prompt engineering
|
||||
│ ├── E2.S2: Generate endpoint
|
||||
│ └── E2.S3: Event logging
|
||||
│
|
||||
└── Dag 4-5: E3 - UI (6-8 uur)
|
||||
├── E3.S1: Behandelplan pagina
|
||||
├── E3.S2: Generate button
|
||||
├── E3.S3: Doelen sectie
|
||||
├── E3.S4: Interventies sectie
|
||||
└── E3.S5: Server actions
|
||||
|
||||
Optioneel (indien tijd):
|
||||
└── E4 - Stretch Goals
|
||||
├── E4.S1: Micro-regeneratie
|
||||
├── E4.S2: Radar chart
|
||||
└── E4.S3: Sessie-planning
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Referenties
|
||||
|
||||
### Mission Control Documents
|
||||
- **PRD** — [prd-behandelplan-v2-final.md](./prd-behandelplan-v2-final.md)
|
||||
- **FO** — [fo-behandelplan-v1.md](./fo-behandelplan-v1.md)
|
||||
- **TO** — [to-behandelplan-v1.md](./to-behandelplan-v1.md)
|
||||
- **UX/UI** — [ux-stylesheet.md](../ux-stylesheet.md)
|
||||
|
||||
### Bestaande Code
|
||||
- API pattern: `/app/api/reports/classify/route.ts`
|
||||
- Server actions: `/app/epd/patients/[id]/intakes/[intakeId]/actions.ts`
|
||||
- Types pattern: `/lib/types/report.ts`
|
||||
- AI integration: `/app/api/docs/chat/route.ts`
|
||||
|
||||
### External Resources
|
||||
- Repository: `github.com/[org]/15-mini-epd-prototype`
|
||||
- Anthropic Docs: https://docs.anthropic.com/claude/reference
|
||||
- Supabase Docs: https://supabase.com/docs
|
||||
|
||||
---
|
||||
|
||||
## 10. Glossary & Abbreviations
|
||||
|
||||
| Term | Betekenis |
|
||||
|------|-----------|
|
||||
| SMART | Specifiek, Meetbaar, Acceptabel, Realistisch, Tijdgebonden |
|
||||
| B1-taal | Taalniveau begrijpelijk voor algemeen publiek |
|
||||
| Leefgebieden | 7 levensdomeinen volgens herstelgerichte zorg |
|
||||
| DSM | Diagnostic and Statistical Manual (diagnose classificatie) |
|
||||
| RLS | Row Level Security (Supabase) |
|
||||
| FHIR | Fast Healthcare Interoperability Resources |
|
||||
| Care Plan | FHIR resource voor behandelplan |
|
||||
| SP | Story Points |
|
||||
| MVP | Minimum Viable Product |
|
||||
|
||||
---
|
||||
|
||||
**Versiehistorie:**
|
||||
|
||||
| Versie | Datum | Auteur | Wijziging |
|
||||
|--------|-------|--------|-----------|
|
||||
| v1.0 | 03-12-2024 | Colin Lit | Initiële versie |
|
||||
| v1.1 | 04-12-2024 | Colin Lit | Epic 0, 1, 2 afgerond - status bijgewerkt |
|
||||
| v1.2 | 04-12-2024 | Colin Lit | Epic 3 afgerond - MVP compleet |
|
||||
@@ -1,566 +0,0 @@
|
||||
# Functioneel Ontwerp (FO) — Behandelplan Module
|
||||
|
||||
**Projectnaam:** Mini-EPD Prototype - AI Speedrun
|
||||
**Versie:** v1.0
|
||||
**Datum:** 03-12-2024
|
||||
**Auteur:** Colin Lit
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en relatie met het PRD
|
||||
|
||||
**Doel van dit document:**
|
||||
Dit Functioneel Ontwerp beschrijft **hoe** de Behandelplan module uit het PRD functioneel werkt — wat de behandelaar ziet, doet en ervaart bij het genereren en beheren van behandelplannen met AI-ondersteuning.
|
||||
|
||||
**Relatie met PRD:**
|
||||
- PRD: `prd-behandelplan-v2-final.md` — beschrijft *wat* en *waarom*
|
||||
- FO (dit document): beschrijft *hoe* dit in de praktijk werkt
|
||||
|
||||
**Scope:**
|
||||
- MVP-functionaliteit (Fase 1-4 uit implementatieplan)
|
||||
- Foundation first aanpak (types → componenten → AI → UI)
|
||||
- Simpele leefgebieden visualisatie (progress bars, geen radar chart)
|
||||
- Simple JSON API (geen streaming)
|
||||
|
||||
---
|
||||
|
||||
## 2. Overzicht van de belangrijkste onderdelen
|
||||
|
||||
De Behandelplan module bestaat uit de volgende onderdelen:
|
||||
|
||||
| # | Onderdeel | Beschrijving |
|
||||
|---|-----------|--------------|
|
||||
| 1 | **Leefgebieden Intake** | Formulier voor 7 levensdomeinen met scores en prioriteiten |
|
||||
| 2 | **AI Generatie** | Knop om behandelplan te laten genereren op basis van intake + diagnose |
|
||||
| 3 | **Behandelplan Overzicht** | Hoofdpagina met structuur, doelen, interventies |
|
||||
| 4 | **SMART Doelen** | Lijst van 2-4 behandeldoelen met voortgang |
|
||||
| 5 | **Interventies** | Evidence-based interventies gekoppeld aan doelen |
|
||||
| 6 | **Sessie-planning** | Tabel met geplande sessies (stretch) |
|
||||
| 7 | **Evaluatiemomenten** | Tussentijdse en eindevaluatie (stretch) |
|
||||
|
||||
---
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
### Primaire User Stories (MVP)
|
||||
|
||||
| ID | Rol | Doel / Actie | Verwachte waarde | Prioriteit |
|
||||
|----|-----|--------------|------------------|------------|
|
||||
| US-01 | Behandelaar | Leefgebieden scores invullen bij intake | Gestructureerd beeld van cliëntsituatie | Hoog |
|
||||
| US-02 | Behandelaar | AI behandelplan laten genereren | Van 30 min naar 2-5 min tijdsbesparing | Hoog |
|
||||
| US-03 | Behandelaar | SMART doelen bekijken en aanpassen | Kwaliteitsverbetering, passend bij cliënt | Hoog |
|
||||
| US-04 | Behandelaar | Interventies koppelen aan doelen | Evidence-based behandeling | Hoog |
|
||||
| US-05 | Behandelaar | Specifiek doel laten regenereren | Fijnafstelling zonder alles opnieuw | Middel |
|
||||
| US-06 | Behandelaar | Plan publiceren (concept → actief) | Cliënt kan plan inzien | Middel |
|
||||
|
||||
### Secundaire User Stories (Stretch)
|
||||
|
||||
| ID | Rol | Doel / Actie | Verwachte waarde | Prioriteit |
|
||||
|----|-----|--------------|------------------|------------|
|
||||
| US-07 | Behandelaar | Sessie-planning invullen | Overzicht behandeltraject | Laag |
|
||||
| US-08 | Behandelaar | Evaluatiemoment vastleggen | Voortgang meten en bijsturen | Laag |
|
||||
| US-09 | Cliënt | Eigen behandelplan bekijken (B1-taal) | Transparantie en begrip | Laag |
|
||||
|
||||
---
|
||||
|
||||
## 4. Functionele werking per onderdeel
|
||||
|
||||
### 4.1 Leefgebieden Intake
|
||||
|
||||
**Locatie:** Onderdeel van intake-flow of aparte tab binnen cliëntdossier
|
||||
|
||||
**Functionaliteit:**
|
||||
- Formulier met 7 levensdomeinen (leefgebieden)
|
||||
- Per domein:
|
||||
- **Score slider:** 1-5 (1 = zeer problematisch, 5 = goed)
|
||||
- **Toelichting:** Vrij tekstveld voor context
|
||||
- **Prioriteit:** Dropdown (Laag / Middel / Hoog)
|
||||
|
||||
**De 7 Leefgebieden:**
|
||||
|
||||
| # | Domein | Emoji | Kleur | Voorbeeldvragen |
|
||||
|---|--------|-------|-------|-----------------|
|
||||
| 1 | Dagelijkse Levensverrichtingen (DLV) | 🏠 | `#8b5cf6` | Zelfzorg, structuur, dagritme |
|
||||
| 2 | Wonen | 🏡 | `#ec4899` | Woonsituatie, veiligheid thuis |
|
||||
| 3 | Werk/Dagbesteding | 💼 | `#f59e0b` | Baan, opleiding, vrijwilligerswerk |
|
||||
| 4 | Sociaal netwerk | 👥 | `#3b82f6` | Familie, vrienden, relaties |
|
||||
| 5 | Vrijetijd/Zingeving | 🎯 | `#10b981` | Hobby's, levensdoel, spiritualiteit |
|
||||
| 6 | Financiën | 💰 | `#eab308` | Schulden, inkomen, budgettering |
|
||||
| 7 | Lichamelijke gezondheid | 🏃 | `#ef4444` | Slaap, beweging, voeding |
|
||||
|
||||
**Gedrag:**
|
||||
- Opslaan: Data wordt opgeslagen als JSONB in intake/care_plan record
|
||||
- Validatie: Alle 7 domeinen moeten een score hebben
|
||||
- Weergave: Na opslaan worden scores getoond als progress bars met kleuren
|
||||
|
||||
**States:**
|
||||
- **Leeg:** "Vul de leefgebieden in om een compleet beeld te krijgen"
|
||||
- **Gedeeltelijk:** Waarschuwing bij minder dan 7 domeinen
|
||||
- **Compleet:** Groen vinkje, klaar voor behandelplan generatie
|
||||
|
||||
---
|
||||
|
||||
### 4.2 AI Behandelplan Generatie
|
||||
|
||||
**Locatie:** Behandelplan tab binnen cliëntdossier
|
||||
|
||||
**Trigger:** Knop `[⚡ Genereer Behandelplan]`
|
||||
|
||||
**Voorwaarden:**
|
||||
- Intake notities aanwezig (uit rich text editor)
|
||||
- Diagnose/probleemprofiel ingevuld (DSM-categorie + severity)
|
||||
- Leefgebieden scores ingevuld (7 domeinen)
|
||||
|
||||
**Input naar AI:**
|
||||
```
|
||||
- Intake tekst (samenvatting of volledige notities)
|
||||
- DSM-categorie (bijv. "Angststoornissen")
|
||||
- Severity niveau (Laag / Middel / Hoog)
|
||||
- Leefgebieden scores met prioriteiten
|
||||
- Optioneel: extra instructies van behandelaar
|
||||
```
|
||||
|
||||
**AI Processing:**
|
||||
- Model: Claude 3.5 Sonnet
|
||||
- Response tijd: < 5 seconden
|
||||
- Output: Gestructureerde JSON
|
||||
|
||||
**Output van AI:**
|
||||
1. **Behandelstructuur:** Duur, frequentie, aantal sessies, vorm
|
||||
2. **SMART Doelen:** 2-4 doelen verdeeld over leefgebieden
|
||||
3. **Interventies:** Evidence-based, gekoppeld aan doelen
|
||||
4. **Sessie-planning:** Grove indeling (8-12 sessies)
|
||||
5. **Evaluatiemomenten:** Tussentijds + eind
|
||||
6. **Veiligheidsplan:** Alleen bij severity "Hoog"
|
||||
|
||||
**UI tijdens generatie:**
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ ⚡ Behandelplan wordt gegenereerd...│
|
||||
│ │
|
||||
│ [████████████░░░░░░░] 75% │
|
||||
│ │
|
||||
│ Even geduld, dit duurt ~5 seconden │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Na generatie:**
|
||||
- Plan verschijnt in bewerkbare vorm
|
||||
- Status: "Concept" (niet gepubliceerd)
|
||||
- Behandelaar kan reviewen en aanpassen
|
||||
|
||||
---
|
||||
|
||||
### 4.3 Behandelplan Overzicht (Hoofdpagina)
|
||||
|
||||
**Locatie:** `/epd/patients/[id]/behandelplan`
|
||||
|
||||
**Layout:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ HEADER │
|
||||
│ Behandelplan v1 Status: ● Concept │
|
||||
│ [Bewerken] [Publiceer] [Nieuwe Versie] │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 BEHANDELSTRUCTUUR │
|
||||
│ ┌─────────────────────────────────────────────────────────┐│
|
||||
│ │ Duur: 8 weken | Frequentie: Wekelijks | Sessies: 8 ││
|
||||
│ │ Vorm: Individueel ││
|
||||
│ └─────────────────────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ 🌐 LEEFGEBIEDEN OVERZICHT │
|
||||
│ ┌─────────────────────────────────────────────────────────┐│
|
||||
│ │ DLV ████████░░ 4/5 Baseline: 3 ││
|
||||
│ │ Wonen ████████░░ 4/5 Baseline: 4 ││
|
||||
│ │ Werk ⚠️ ████░░░░░░ 2/5 Baseline: 2 [Prioriteit] ││
|
||||
│ │ Sociaal ⚠️ ████░░░░░░ 2/5 Baseline: 2 [Prioriteit] ││
|
||||
│ │ Vrijetijd ██████░░░░ 3/5 Baseline: 3 ││
|
||||
│ │ Financiën ██████░░░░ 3/5 Baseline: 3 ││
|
||||
│ │ Gezondheid ████████░░ 4/5 Baseline: 4 ││
|
||||
│ └─────────────────────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ 🎯 SMART DOELEN (3) │
|
||||
│ [Doel cards - zie 4.4] │
|
||||
│ │
|
||||
│ 💡 INTERVENTIES (2) │
|
||||
│ [Interventie cards - zie 4.5] │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Acties:**
|
||||
- `[Bewerken]`: Opent inline editing modus
|
||||
- `[Publiceer]`: Wijzigt status naar "Actief", zichtbaar voor cliënt
|
||||
- `[Nieuwe Versie]`: Maakt v2 aan op basis van huidige versie
|
||||
|
||||
**Status indicatoren:**
|
||||
- 🔵 Concept - Bewerkbaar, niet zichtbaar voor cliënt
|
||||
- 🟢 Actief - Gepubliceerd, zichtbaar voor cliënt
|
||||
- 🟡 In evaluatie - Evaluatiemoment gepland
|
||||
- ⚫ Afgerond - Behandeling afgerond
|
||||
|
||||
---
|
||||
|
||||
### 4.4 SMART Doelen
|
||||
|
||||
**Weergave per doel:**
|
||||
```
|
||||
┌───────────────────────────────────────────────────────────┐
|
||||
│ 💼 Werk Prioriteit│
|
||||
│ [Hoog] │
|
||||
│ Terugkeer naar 4 werkdagen per week │
|
||||
│ │
|
||||
│ "Ik werk weer 4 dagen zonder paniek te krijgen" │
|
||||
│ (cliënt-versie) │
|
||||
│ │
|
||||
│ Voortgang: ██████░░░░ 60% │
|
||||
│ Status: Bezig | Deadline: 8 weken │
|
||||
│ │
|
||||
│ Meetbaarheid: Aantal werkdagen per week bijhouden │
|
||||
│ │
|
||||
│ [Bewerk] [↻ Regenereer] [Details ▼] │
|
||||
└───────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Velden per doel:**
|
||||
| Veld | Type | Beschrijving |
|
||||
|------|------|--------------|
|
||||
| Titel | Tekst | Korte beschrijving (1 zin) |
|
||||
| Beschrijving | Tekst | SMART-uitwerking (2-3 zinnen) |
|
||||
| Cliënt-versie | Tekst | B1-taal versie voor cliënt |
|
||||
| Leefgebied | Tag | DLV/Wonen/Werk/Sociaal/etc. |
|
||||
| Prioriteit | Dropdown | Hoog/Middel/Laag |
|
||||
| Meetbaarheid | Tekst | Hoe meten we vooruitgang? |
|
||||
| Tijdslijn | Getal | Binnen X weken |
|
||||
| Status | Dropdown | Niet gestart/Bezig/Gehaald/Bijgesteld |
|
||||
| Voortgang | Slider | 0-100% |
|
||||
|
||||
**Acties:**
|
||||
- `[Bewerk]`: Inline editing van alle velden
|
||||
- `[↻ Regenereer]`: AI genereert alternatief doel (zie 4.6)
|
||||
- `[Details ▼]`: Uitklappen voor SMART-details
|
||||
- `[+]`: Handmatig doel toevoegen
|
||||
- `[🗑️]`: Doel verwijderen
|
||||
|
||||
**AI-gedrag bij generatie:**
|
||||
- Focust op leefgebieden met prioriteit "Hoog"
|
||||
- Verdeelt doelen over minimaal 2 verschillende domeinen
|
||||
- Maakt concrete, meetbare doelen (geen vage termen)
|
||||
- Genereert automatisch B1-taal cliënt-versie
|
||||
|
||||
---
|
||||
|
||||
### 4.5 Interventies
|
||||
|
||||
**Weergave per interventie:**
|
||||
```
|
||||
┌───────────────────────────────────────────────────────────┐
|
||||
│ 🧠 Cognitieve Gedragstherapie (CGT) │
|
||||
│ │
|
||||
│ Beschrijving: │
|
||||
│ Identificeren en uitdagen van negatieve gedachtenpatronen │
|
||||
│ die angst en vermijding in stand houden. │
|
||||
│ │
|
||||
│ Rationale: │
|
||||
│ CGT is de eerste keuze behandeling bij angststoornissen │
|
||||
│ met sterke evidentie voor effectiviteit. │
|
||||
│ │
|
||||
│ Gekoppeld aan: [💼 Doel 1] [👥 Doel 2] │
|
||||
│ │
|
||||
│ [Bewerk] [Details ▼] │
|
||||
└───────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Velden per interventie:**
|
||||
| Veld | Type | Beschrijving |
|
||||
|------|------|--------------|
|
||||
| Naam | Tekst | CGT, Exposure, EMDR, ACT, etc. |
|
||||
| Beschrijving | Tekst | Uitleg van de interventie |
|
||||
| Rationale | Tekst | Waarom past dit bij deze cliënt? |
|
||||
| Gekoppelde doelen | Multi-select | Welke doelen worden benaderd? |
|
||||
|
||||
**AI-mapping (evidence-based):**
|
||||
| DSM-Categorie | Primaire Interventies | Sessies bij Hoog |
|
||||
|---------------|----------------------|------------------|
|
||||
| Angststoornissen | CGT, Exposure, ACT | 12-16 sessies |
|
||||
| Stemmingsklachten | CGT, IPT, Gedragsactivatie | 8-12 sessies |
|
||||
| Trauma/PTSS | EMDR, Narratieve therapie | 12+ sessies |
|
||||
| Persoonlijkheid | Schematherapie, MBT | 20+ sessies |
|
||||
|
||||
---
|
||||
|
||||
### 4.6 Micro-regeneratie (Stretch)
|
||||
|
||||
**Trigger:** Klik op `[↻ Regenereer]` bij specifiek doel of interventie
|
||||
|
||||
**Flow:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ↻ Doel regenereren [X] │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Huidige doel: │
|
||||
│ "Terugkeer naar 4 werkdagen per week" │
|
||||
│ │
|
||||
│ Extra instructie voor AI (optioneel): │
|
||||
│ ┌─────────────────────────────────────────────────────────┐│
|
||||
│ │ Maak meer gefocust op geleidelijke opbouw ││
|
||||
│ └─────────────────────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ [Annuleren] [↻ Regenereer] │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Na regeneratie:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Nieuw voorstel: │
|
||||
│ │
|
||||
│ "Stapsgewijze opbouw naar 4 werkdagen via 2→3→4 schema" │
|
||||
│ │
|
||||
│ [Behoud origineel] [✓ Accepteer nieuw voorstel] │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Gedrag:**
|
||||
- AI behoudt context van rest van plan
|
||||
- Alleen het specifieke onderdeel wordt vervangen
|
||||
- Toast notification bij succes: "Doel bijgewerkt"
|
||||
|
||||
---
|
||||
|
||||
### 4.7 Publicatie Workflow
|
||||
|
||||
**Statussen:**
|
||||
```
|
||||
Concept ──→ Actief ──→ In evaluatie ──→ Afgerond
|
||||
│ │
|
||||
└──→ Gearchiveerd ←──────────┘
|
||||
(bij nieuwe versie)
|
||||
```
|
||||
|
||||
**Validatie voor publicatie:**
|
||||
- ✓ Minimaal 1 doel ingevuld
|
||||
- ✓ Minimaal 1 interventie gekoppeld
|
||||
- ✓ Behandelstructuur compleet (duur, frequentie)
|
||||
- ✓ Evaluatiemomenten gepland (tussentijds + eind)
|
||||
|
||||
**Publicatie actie:**
|
||||
1. Behandelaar klikt `[Publiceer]`
|
||||
2. Systeem valideert compleetheid
|
||||
3. Bij succes: status → "Actief", publicatiedatum vastgelegd
|
||||
4. Toast: "Behandelplan gepubliceerd"
|
||||
5. Plan zichtbaar in cliëntportaal
|
||||
|
||||
**Versie-beheer:**
|
||||
- Nummering: v1, v2, v3, etc.
|
||||
- Bij "Nieuwe Versie": huidige → "Gearchiveerd", nieuwe kopie → "Concept"
|
||||
- Oude versies blijven zichtbaar (read-only)
|
||||
|
||||
---
|
||||
|
||||
## 5. UI-overzicht (visuele structuur)
|
||||
|
||||
### Behandelplan Pagina Layout
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ HEADER │
|
||||
│ Mini-EPD Logo [Cliëntnaam ▼] [Zoek...] [Profiel] │
|
||||
├─────────────────┬───────────────────────────────────────────────┤
|
||||
│ SIDEBAR │ MAIN CONTENT │
|
||||
│ │ │
|
||||
│ ← Cliënten │ ┌───────────────────────────────────────────┐ │
|
||||
│ ───────── │ │ Behandelplan v1 Status: Concept │ │
|
||||
│ □ Dashboard │ │ [Bewerken] [Publiceer] [Print] │ │
|
||||
│ □ Intake │ └───────────────────────────────────────────┘ │
|
||||
│ □ Diagnose │ │
|
||||
│ ■ Behandelplan │ ┌── Behandelstructuur ──────────────────────┐ │
|
||||
│ □ Rapportage │ │ Duur: 8 weken | Freq: Wekelijks | 8 sess │ │
|
||||
│ □ Agenda │ └───────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ ┌── Leefgebieden ────────────────────────────┐ │
|
||||
│ │ │ [Progress bars met scores per domein] │ │
|
||||
│ │ └───────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ ┌── SMART Doelen ────────────────────────────┐ │
|
||||
│ │ │ [Doel 1 - Werk] │ │
|
||||
│ │ │ [Doel 2 - Sociaal] │ │
|
||||
│ │ │ [Doel 3 - DLV] │ │
|
||||
│ │ │ [+ Doel toevoegen] │ │
|
||||
│ │ └───────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ ┌── Interventies ────────────────────────────┐ │
|
||||
│ │ │ [CGT] [Exposure] │ │
|
||||
│ │ └───────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
├─────────────────┴───────────────────────────────────────────────┤
|
||||
│ FOOTER: Auto-saved 2 sec ago │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Responsive (Tablet)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ [☰] Mini-EPD Cliëntnaam [Zoek] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Behandelplan v1 │
|
||||
│ Status: ● Concept │
|
||||
│ [Bewerken] [Publiceer] │
|
||||
│ │
|
||||
│ ┌── Behandelstructuur ────────────────────┐│
|
||||
│ │ Duur: 8 weken | Wekelijks | 8 sessies ││
|
||||
│ └─────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ ┌── Leefgebieden ─────────────────────────┐│
|
||||
│ │ [Compacte progress bars] ││
|
||||
│ └─────────────────────────────────────────┘│
|
||||
│ │
|
||||
│ ┌── Doelen ───────────────────────────────┐│
|
||||
│ │ [Gestapelde doel cards] ││
|
||||
│ └─────────────────────────────────────────┘│
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Interacties met AI (functionele beschrijving)
|
||||
|
||||
| Locatie | AI-actie | Trigger | Input | Output |
|
||||
|---------|----------|---------|-------|--------|
|
||||
| Behandelplan tab | Genereer plan | Klik `[⚡ Genereer]` | Intake + diagnose + leefgebieden | Compleet behandelplan (JSON) |
|
||||
| Doel card | Regenereer doel | Klik `[↻ Regenereer]` | Context plan + instructie | Alternatief doel |
|
||||
| Interventie card | Regenereer interventie | Klik `[↻ Regenereer]` | Context plan + instructie | Alternatieve interventie |
|
||||
| Doel card | Genereer cliënt-versie | Automatisch bij nieuw doel | Behandelaar-tekst | B1-taal versie |
|
||||
|
||||
### AI Response Format
|
||||
|
||||
```typescript
|
||||
interface AIGeneratedPlan {
|
||||
behandelstructuur: {
|
||||
duur: string // "8 weken"
|
||||
frequentie: string // "Wekelijks"
|
||||
aantalSessies: number // 8
|
||||
vorm: string // "Individueel"
|
||||
}
|
||||
doelen: Array<{
|
||||
id: string
|
||||
title: string
|
||||
description: string // SMART uitwerking
|
||||
clientVersion: string // B1-taal
|
||||
lifeDomain: string // "werk" | "sociaal" | etc.
|
||||
priority: string // "hoog" | "middel" | "laag"
|
||||
measurability: string
|
||||
timelineWeeks: number
|
||||
}>
|
||||
interventies: Array<{
|
||||
name: string
|
||||
description: string
|
||||
rationale: string
|
||||
linkedGoalIds: string[]
|
||||
}>
|
||||
evaluatiemomenten: Array<{
|
||||
type: string // "tussentijds" | "eind"
|
||||
weekNumber: number
|
||||
}>
|
||||
veiligheidsplan?: { // Alleen bij severity "Hoog"
|
||||
waarschuwingssignalen: string[]
|
||||
copingStrategieen: string[]
|
||||
contacten: string[]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Gebruikersrollen en rechten
|
||||
|
||||
| Rol | Toegang tot | Acties | Beperkingen |
|
||||
|-----|------------|--------|-------------|
|
||||
| Behandelaar | Eigen cliëntdossiers | Volledig CRUD, AI generatie | Alleen eigen cliënten |
|
||||
| Behandelaar (collega) | Gedeelde cliënten | Lezen, commentaar | Geen bewerken |
|
||||
| Cliënt | Eigen behandelplan | Alleen lezen | Ziet B1-versie, geen edit |
|
||||
| Demo-user | Alle fictieve data | Lezen + AI testen | Geen opslaan |
|
||||
|
||||
---
|
||||
|
||||
## 8. States en Foutafhandeling
|
||||
|
||||
### Empty States
|
||||
|
||||
**Geen behandelplan:**
|
||||
```
|
||||
┌───────────────────────────────────────────┐
|
||||
│ 📋 │
|
||||
│ │
|
||||
│ Nog geen behandelplan │
|
||||
│ │
|
||||
│ Vul eerst de intake en diagnose in, │
|
||||
│ dan kan AI een behandelplan genereren. │
|
||||
│ │
|
||||
│ [Naar Intake] [Naar Diagnose] │
|
||||
└───────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Incomplete voorwaarden:**
|
||||
```
|
||||
┌───────────────────────────────────────────┐
|
||||
│ ⚠️ Nog niet klaar voor behandelplan │
|
||||
│ │
|
||||
│ □ Intake notities ✓ │
|
||||
│ □ Diagnose/probleemprofiel ✗ │
|
||||
│ □ Leefgebieden scores ✗ │
|
||||
│ │
|
||||
│ Vul de ontbrekende onderdelen in. │
|
||||
└───────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Error States
|
||||
|
||||
| Situatie | Bericht | Actie |
|
||||
|----------|---------|-------|
|
||||
| AI niet beschikbaar | "AI tijdelijk niet beschikbaar" | Retry knop, handmatig alternatief |
|
||||
| Validatie fout | Inline error onder veld | Focus op fout veld |
|
||||
| Netwerk error | Toast: "Verbinding verloren" | Auto-retry, lokale opslag |
|
||||
| Rate limit | "Even wachten..." | Countdown timer |
|
||||
|
||||
### Loading States
|
||||
|
||||
**AI generatie:**
|
||||
```
|
||||
⚡ Behandelplan wordt gegenereerd...
|
||||
[████████████░░░░░░░] 75%
|
||||
Even geduld, dit duurt ~5 seconden
|
||||
```
|
||||
|
||||
**Auto-save:**
|
||||
- Tijdens typen: "Opslaan..."
|
||||
- Na succes: "✓ Opgeslagen 2 sec geleden"
|
||||
|
||||
---
|
||||
|
||||
## 9. Bijlagen & Referenties
|
||||
|
||||
### Interne Documenten
|
||||
- [PRD Behandelplan v2.0](./prd-behandelplan-v2-final.md) — Requirements
|
||||
- [Implementatieplan](~/.claude/plans/) — Technische aanpak
|
||||
- [UX Stylesheet](../ux-stylesheet.md) — Kleuren, typography
|
||||
|
||||
### Technische Specificaties
|
||||
- Database: `treatment_plans` tabel met JSONB structuur
|
||||
- API: `/api/behandelplan/generate` (POST, JSON response)
|
||||
- AI Model: Claude 3.5 Sonnet
|
||||
|
||||
### Externe Bronnen
|
||||
- [GGZ Richtlijnen](https://www.ggzrichtlijnen.nl/) — Evidence-based interventies
|
||||
- [WCAG 2.1 AA](https://www.w3.org/WAI/WCAG21/quickref/) — Accessibility
|
||||
|
||||
---
|
||||
|
||||
**Document Status:** v1.0 Draft
|
||||
**Volgende Review:** Na implementatie Fase 1-2
|
||||
**Eigenaar:** Colin Lit
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,719 +0,0 @@
|
||||
# Technisch Ontwerp (TO) — Behandelplan Module
|
||||
|
||||
**Projectnaam:** Mini-EPD Prototype - AI Speedrun
|
||||
**Versie:** v1.0
|
||||
**Datum:** 03-12-2024
|
||||
**Auteur:** Colin Lit
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en relatie met PRD en FO
|
||||
|
||||
**Doel van dit document:**
|
||||
Dit Technisch Ontwerp beschrijft **hoe** de Behandelplan module technisch wordt gebouwd. Het PRD beschrijft het *wat*, het FO het *hoe functioneel*, en dit TO de *technische implementatie*.
|
||||
|
||||
**Gerelateerde documenten:**
|
||||
- PRD: `prd-behandelplan-v2-final.md`
|
||||
- FO: `fo-behandelplan-v1.md`
|
||||
- Implementatieplan: `~/.claude/plans/effervescent-toasting-beaver.md`
|
||||
|
||||
**Scope:**
|
||||
- Foundation first: Types → Database → Components → AI → UI
|
||||
- Simple JSON API (geen streaming)
|
||||
- Simpele leefgebieden visualisatie (progress bars, geen radar chart)
|
||||
|
||||
---
|
||||
|
||||
## 2. Technische Architectuur Overzicht
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ FRONTEND (Next.js 14) │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────────────┐ │
|
||||
│ │ Behandelplan │ │ Leefgebieden │ │ SMART Doelen │ │
|
||||
│ │ Page │ │ Components │ │ Components │ │
|
||||
│ │ (Server Comp) │ │ (Client Comp) │ │ (Client Comp) │ │
|
||||
│ └────────┬────────┘ └────────┬────────┘ └──────────────┬──────────────┘ │
|
||||
│ │ │ │ │
|
||||
│ └────────────────────┴──────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────────▼──────────┐ │
|
||||
│ │ Server Actions │ │
|
||||
│ │ (behandelplan/ │ │
|
||||
│ │ actions.ts) │ │
|
||||
│ └──────────┬──────────┘ │
|
||||
└────────────────────────────────────┼────────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────────────────────┼────────────────────────────────────────┐
|
||||
│ API ROUTES │
|
||||
│ ┌─────────────────────────────────▼─────────────────────────────────────┐ │
|
||||
│ │ /api/behandelplan/generate │ │
|
||||
│ │ (POST - AI Generation) │ │
|
||||
│ └─────────────────────────────────┬─────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────────────────────────────────▼─────────────────────────────────────┐ │
|
||||
│ │ /api/behandelplan/regenerate-section │ │
|
||||
│ │ (POST - Micro-regeneration) │ │
|
||||
│ └─────────────────────────────────┬─────────────────────────────────────┘ │
|
||||
└────────────────────────────────────┼────────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────────────────────────┼────────────────────────────────────────┐
|
||||
│ EXTERNAL SERVICES │
|
||||
│ ┌─────────────────┐ │ ┌─────────────────────┐ │
|
||||
│ │ Supabase │◄─────────────┴──────────────► Claude API │ │
|
||||
│ │ (PostgreSQL) │ │ (Anthropic) │ │
|
||||
│ │ - care_plans │ │ - claude-sonnet │ │
|
||||
│ │ - patients │ │ - JSON response │ │
|
||||
│ │ - intakes │ │ │ │
|
||||
│ └─────────────────┘ └─────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Techstack Selectie
|
||||
|
||||
### Bestaande Stack (hergebruiken)
|
||||
|
||||
| Component | Technologie | Status | Argumentatie |
|
||||
|-----------|-------------|--------|--------------|
|
||||
| Frontend | Next.js 14.2.18 | ✅ Bestaand | React framework, SSR, App Router |
|
||||
| Backend | Next.js API Routes | ✅ Bestaand | Co-located, TypeScript |
|
||||
| Database | Supabase PostgreSQL | ✅ Bestaand | RLS, FHIR-compliant schema |
|
||||
| AI | Claude Sonnet | ✅ Bestaand | API key geconfigureerd |
|
||||
| Styling | TailwindCSS 3.4 | ✅ Bestaand | Utility-first, shadcn/ui |
|
||||
| Icons | Lucide React | ✅ Bestaand | Consistent icon set |
|
||||
| Editor | TipTap | ✅ Bestaand | Rich text editor |
|
||||
| Validation | Zod | ✅ Bestaand | Schema validation |
|
||||
|
||||
### Nieuwe Dependencies
|
||||
|
||||
| Component | Technologie | Nodig voor | Alternatief |
|
||||
|-----------|-------------|------------|-------------|
|
||||
| Charts | Recharts 2.x | Radar chart (stretch) | ❌ Later toevoegen |
|
||||
|
||||
**Conclusie:** Geen nieuwe dependencies nodig voor MVP. Recharts alleen bij stretch goal.
|
||||
|
||||
---
|
||||
|
||||
## 4. Datamodel
|
||||
|
||||
### 4.1 Bestaande Tabellen (hergebruiken)
|
||||
|
||||
```sql
|
||||
-- FHIR CarePlan (hoofdtabel voor behandelplannen)
|
||||
care_plans (
|
||||
id UUID PRIMARY KEY,
|
||||
patient_id UUID REFERENCES patients(id),
|
||||
title TEXT,
|
||||
status careplan_status, -- draft | active | completed | revoked
|
||||
intent TEXT,
|
||||
goals JSONB, -- Array van doelen
|
||||
activities JSONB, -- Array van interventies
|
||||
based_on_intake_id UUID,
|
||||
based_on_anamneses UUID[],
|
||||
based_on_examinations UUID[],
|
||||
based_on_risk_assessments UUID[],
|
||||
care_team_ids UUID[],
|
||||
author_id UUID,
|
||||
period_start DATE,
|
||||
period_end DATE,
|
||||
created_at TIMESTAMP,
|
||||
updated_at TIMESTAMP
|
||||
)
|
||||
|
||||
-- Conditions (diagnoses - input voor AI)
|
||||
conditions (
|
||||
id UUID,
|
||||
patient_id UUID,
|
||||
code TEXT, -- DSM-5 code
|
||||
code_system TEXT,
|
||||
display_text TEXT,
|
||||
category TEXT,
|
||||
clinical_status TEXT,
|
||||
severity TEXT, -- laag | middel | hoog
|
||||
encounter_id UUID
|
||||
)
|
||||
|
||||
-- Intakes (bron voor AI context)
|
||||
intakes (
|
||||
id UUID,
|
||||
patient_id UUID,
|
||||
status intake_status,
|
||||
treatment_advice JSONB,
|
||||
kindcheck_data JSONB,
|
||||
notes TEXT
|
||||
)
|
||||
```
|
||||
|
||||
### 4.2 Nieuwe Velden / Migratie
|
||||
|
||||
```sql
|
||||
-- Migratie: Leefgebieden toevoegen aan intakes
|
||||
ALTER TABLE intakes
|
||||
ADD COLUMN life_domains JSONB;
|
||||
|
||||
-- Migratie: Behandelplan specifieke velden aan care_plans
|
||||
ALTER TABLE care_plans
|
||||
ADD COLUMN version INTEGER DEFAULT 1,
|
||||
ADD COLUMN published_at TIMESTAMP,
|
||||
ADD COLUMN behandelstructuur JSONB,
|
||||
ADD COLUMN evaluatiemomenten JSONB,
|
||||
ADD COLUMN veiligheidsplan JSONB;
|
||||
|
||||
-- Constraint voor versie-beheer
|
||||
ALTER TABLE care_plans
|
||||
ADD CONSTRAINT unique_patient_version UNIQUE (patient_id, version);
|
||||
```
|
||||
|
||||
### 4.3 JSONB Structuren
|
||||
|
||||
**life_domains (in intakes):**
|
||||
```typescript
|
||||
interface LifeDomainScore {
|
||||
domain: 'dlv' | 'wonen' | 'werk' | 'sociaal' | 'vrijetijd' | 'financien' | 'gezondheid'
|
||||
baseline: number // 1-5
|
||||
current: number // 1-5
|
||||
target: number // 1-5
|
||||
notes: string
|
||||
priority: 'laag' | 'middel' | 'hoog'
|
||||
}
|
||||
|
||||
// life_domains: LifeDomainScore[]
|
||||
```
|
||||
|
||||
**goals (in care_plans):**
|
||||
```typescript
|
||||
interface SmartGoal {
|
||||
id: string
|
||||
title: string
|
||||
description: string
|
||||
clientVersion: string // B1-taal
|
||||
lifeDomain: LifeDomain
|
||||
priority: 'hoog' | 'middel' | 'laag'
|
||||
measurability: string
|
||||
timelineWeeks: number
|
||||
status: 'niet_gestart' | 'bezig' | 'gehaald' | 'bijgesteld'
|
||||
progress: number // 0-100
|
||||
}
|
||||
```
|
||||
|
||||
**activities (in care_plans):**
|
||||
```typescript
|
||||
interface Intervention {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
rationale: string
|
||||
linkedGoalIds: string[]
|
||||
}
|
||||
```
|
||||
|
||||
**behandelstructuur:**
|
||||
```typescript
|
||||
interface Behandelstructuur {
|
||||
duur: string // "8 weken"
|
||||
frequentie: string // "Wekelijks"
|
||||
aantalSessies: number // 8
|
||||
vorm: string // "Individueel"
|
||||
}
|
||||
```
|
||||
|
||||
**evaluatiemomenten:**
|
||||
```typescript
|
||||
interface Evaluatiemoment {
|
||||
id: string
|
||||
type: 'tussentijds' | 'eind' | 'crisis'
|
||||
weekNumber: number
|
||||
plannedDate: string
|
||||
actualDate?: string
|
||||
status: 'gepland' | 'afgerond' | 'overgeslagen'
|
||||
outcome?: string
|
||||
lifeDomainUpdates?: LifeDomainScore[]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 ERD
|
||||
|
||||
```
|
||||
patients ─1:N─ intakes ─1:1─ life_domains (JSONB)
|
||||
│ │
|
||||
│ └────────── anamneses ─────────┐
|
||||
│ └────────── examinations ──────┤
|
||||
│ └────────── risk_assessments ──┤
|
||||
│ │
|
||||
└─1:N─ care_plans ────────────────────────────┘
|
||||
│ (based_on_*)
|
||||
├── goals (JSONB)
|
||||
├── activities (JSONB)
|
||||
├── behandelstructuur (JSONB)
|
||||
├── evaluatiemomenten (JSONB)
|
||||
└── veiligheidsplan (JSONB)
|
||||
|
||||
└─1:N─ conditions (diagnoses - input voor AI)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. API Ontwerp
|
||||
|
||||
### 5.1 Endpoints Overzicht
|
||||
|
||||
| Endpoint | Method | Input | Output | Auth |
|
||||
|----------|--------|-------|--------|------|
|
||||
| `/api/behandelplan/generate` | POST | GenerateInput | GeneratedPlan | Required |
|
||||
| `/api/behandelplan/regenerate-section` | POST | RegenerateInput | RegeneratedSection | Required |
|
||||
|
||||
### 5.2 POST /api/behandelplan/generate
|
||||
|
||||
**Request:**
|
||||
```typescript
|
||||
interface GenerateInput {
|
||||
patientId: string // UUID
|
||||
intakeId: string // UUID
|
||||
conditionId?: string // UUID (optioneel, haalt anders laatste op)
|
||||
extraInstructions?: string // Optionele aanvullende instructies
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```typescript
|
||||
interface GeneratedPlan {
|
||||
behandelstructuur: Behandelstructuur
|
||||
doelen: SmartGoal[]
|
||||
interventies: Intervention[]
|
||||
evaluatiemomenten: Evaluatiemoment[]
|
||||
veiligheidsplan?: Veiligheidsplan // Alleen bij severity "Hoog"
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400`: Validation error (missing fields, invalid UUIDs)
|
||||
- `401`: Unauthorized
|
||||
- `404`: Patient/Intake/Condition not found
|
||||
- `422`: Insufficient data for generation (no intake notes, no diagnosis)
|
||||
- `500`: AI API error
|
||||
- `503`: AI service unavailable
|
||||
|
||||
### 5.3 POST /api/behandelplan/regenerate-section
|
||||
|
||||
**Request:**
|
||||
```typescript
|
||||
interface RegenerateInput {
|
||||
patientId: string
|
||||
carePlanId: string
|
||||
sectionType: 'goal' | 'intervention'
|
||||
sectionId: string
|
||||
instruction?: string // Extra instructie voor AI
|
||||
currentPlan: GeneratedPlan // Context van huidige plan
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```typescript
|
||||
interface RegeneratedSection {
|
||||
type: 'goal' | 'intervention'
|
||||
original: SmartGoal | Intervention
|
||||
regenerated: SmartGoal | Intervention
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 Zod Validation Schemas
|
||||
|
||||
```typescript
|
||||
// lib/types/behandelplan.ts
|
||||
|
||||
export const GenerateInputSchema = z.object({
|
||||
patientId: z.string().uuid(),
|
||||
intakeId: z.string().uuid(),
|
||||
conditionId: z.string().uuid().optional(),
|
||||
extraInstructions: z.string().max(500).optional(),
|
||||
});
|
||||
|
||||
export const RegenerateInputSchema = z.object({
|
||||
patientId: z.string().uuid(),
|
||||
carePlanId: z.string().uuid(),
|
||||
sectionType: z.enum(['goal', 'intervention']),
|
||||
sectionId: z.string().uuid(),
|
||||
instruction: z.string().max(200).optional(),
|
||||
currentPlan: GeneratedPlanSchema,
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Security & Compliance
|
||||
|
||||
### 6.1 Security Checklist
|
||||
|
||||
- [x] **Authentication:** Supabase Auth (bestaand)
|
||||
- [x] **Authorization:** Row Level Security op care_plans
|
||||
- [x] **Data Encryption:** At rest (PostgreSQL), in transit (HTTPS)
|
||||
- [x] **Input Validation:** Zod schemas op alle endpoints
|
||||
- [ ] **Rate Limiting:** Toe te voegen op AI endpoints (10 req/min)
|
||||
- [x] **CORS:** Restrictive origins (bestaand)
|
||||
- [x] **Secrets:** Environment variables (ANTHROPIC_API_KEY)
|
||||
|
||||
### 6.2 RLS Policies voor care_plans
|
||||
|
||||
```sql
|
||||
-- Bestaande RLS policy uitbreiden
|
||||
ALTER TABLE care_plans ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Behandelaars kunnen alleen eigen patiënten zien
|
||||
CREATE POLICY "Users can view care plans for their patients"
|
||||
ON care_plans FOR SELECT
|
||||
USING (
|
||||
auth.uid() IN (
|
||||
SELECT practitioner_id FROM patient_practitioners
|
||||
WHERE patient_id = care_plans.patient_id
|
||||
)
|
||||
);
|
||||
|
||||
-- Behandelaars kunnen care plans maken voor eigen patiënten
|
||||
CREATE POLICY "Users can create care plans for their patients"
|
||||
ON care_plans FOR INSERT
|
||||
WITH CHECK (
|
||||
auth.uid() = author_id
|
||||
);
|
||||
|
||||
-- Behandelaars kunnen eigen care plans updaten
|
||||
CREATE POLICY "Users can update their care plans"
|
||||
ON care_plans FOR UPDATE
|
||||
USING (auth.uid() = author_id);
|
||||
```
|
||||
|
||||
### 6.3 AVG/GDPR Overwegingen
|
||||
|
||||
- **Data minimalisatie:** Alleen noodzakelijke velden in AI prompt
|
||||
- **Geen BSN/identificerende data naar AI:** Alleen intake notities en scores
|
||||
- **Audit trail:** Bestaande `ai_events` tabel loggen van AI calls
|
||||
- **Consent:** AI-gebruik gedekt onder behandelrelatie
|
||||
|
||||
---
|
||||
|
||||
## 7. AI/LLM Integratie
|
||||
|
||||
### 7.1 AI Stack
|
||||
|
||||
| Component | Waarde |
|
||||
|-----------|--------|
|
||||
| Provider | Anthropic |
|
||||
| Model | claude-3-5-sonnet-20240620 (of claude-sonnet-4) |
|
||||
| Library | Native fetch (geen SDK nodig) |
|
||||
| Caching | Geen (elke generatie is uniek) |
|
||||
| Fallback | Error message + manual mode optie |
|
||||
|
||||
### 7.2 Prompt Template
|
||||
|
||||
```typescript
|
||||
// lib/ai/behandelplan-prompt.ts
|
||||
|
||||
export const BEHANDELPLAN_SYSTEM_PROMPT = `
|
||||
Je bent een ervaren GGZ-behandelaar die behandelplannen opstelt.
|
||||
Je maakt SMART doelen die recovery-gericht en evidence-based zijn.
|
||||
|
||||
INSTRUCTIES:
|
||||
1. Genereer 2-4 SMART doelen gebaseerd op de intake en diagnose
|
||||
2. Focus op leefgebieden met prioriteit "Hoog"
|
||||
3. Verdeel doelen over minimaal 2 verschillende leefgebieden
|
||||
4. Maak concrete, meetbare doelen (geen vage termen)
|
||||
5. Genereer voor elk doel een B1-taal versie (cliënt-vriendelijk)
|
||||
6. Kies evidence-based interventies passend bij de DSM-categorie
|
||||
7. Plan 8-12 sessies afhankelijk van severity
|
||||
8. Voeg veiligheidsplan toe alleen bij severity "Hoog"
|
||||
|
||||
OUTPUT FORMAT:
|
||||
Retourneer ALLEEN valide JSON volgens het volgende schema:
|
||||
{
|
||||
"behandelstructuur": {
|
||||
"duur": "8 weken",
|
||||
"frequentie": "Wekelijks",
|
||||
"aantalSessies": 8,
|
||||
"vorm": "Individueel"
|
||||
},
|
||||
"doelen": [...],
|
||||
"interventies": [...],
|
||||
"evaluatiemomenten": [...],
|
||||
"veiligheidsplan": null | {...}
|
||||
}
|
||||
`;
|
||||
|
||||
export function buildUserPrompt(context: PlanContext): string {
|
||||
return `
|
||||
CLIËNT CONTEXT:
|
||||
- Intake notities: ${context.intakeNotes}
|
||||
- DSM-categorie: ${context.dsmCategory}
|
||||
- Severity: ${context.severity}
|
||||
|
||||
LEEFGEBIEDEN SCORES:
|
||||
${context.lifeDomains.map(d =>
|
||||
`- ${d.domain}: ${d.baseline}/5 (prioriteit: ${d.priority})`
|
||||
).join('\n')}
|
||||
|
||||
${context.extraInstructions ? `EXTRA INSTRUCTIES:\n${context.extraInstructions}` : ''}
|
||||
|
||||
Genereer nu een behandelplan.
|
||||
`;
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 Evidence-Based Mapping
|
||||
|
||||
```typescript
|
||||
// lib/ai/intervention-mapping.ts
|
||||
|
||||
export const INTERVENTION_MAPPING: Record<string, InterventionSuggestion[]> = {
|
||||
'angststoornissen': [
|
||||
{ name: 'CGT', sessions: { laag: 8, middel: 10, hoog: 14 } },
|
||||
{ name: 'Exposure therapie', sessions: { laag: 6, middel: 8, hoog: 12 } },
|
||||
{ name: 'ACT', sessions: { laag: 8, middel: 10, hoog: 12 } },
|
||||
],
|
||||
'stemmingsklachten': [
|
||||
{ name: 'CGT', sessions: { laag: 8, middel: 10, hoog: 14 } },
|
||||
{ name: 'IPT', sessions: { laag: 8, middel: 12, hoog: 16 } },
|
||||
{ name: 'Gedragsactivatie', sessions: { laag: 6, middel: 8, hoog: 10 } },
|
||||
],
|
||||
'trauma_ptss': [
|
||||
{ name: 'EMDR', sessions: { laag: 6, middel: 10, hoog: 16 } },
|
||||
{ name: 'Narratieve therapie', sessions: { laag: 8, middel: 12, hoog: 16 } },
|
||||
],
|
||||
'persoonlijkheid': [
|
||||
{ name: 'Schematherapie', sessions: { laag: 16, middel: 24, hoog: 40 } },
|
||||
{ name: 'MBT', sessions: { laag: 16, middel: 24, hoog: 40 } },
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### 7.4 API Call Implementatie
|
||||
|
||||
```typescript
|
||||
// app/api/behandelplan/generate/route.ts
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
// 1. Validate input
|
||||
const body = await request.json();
|
||||
const input = GenerateInputSchema.parse(body);
|
||||
|
||||
// 2. Load context from database
|
||||
const context = await loadPlanContext(input);
|
||||
|
||||
// 3. Build prompt
|
||||
const messages = [
|
||||
{ role: 'system', content: BEHANDELPLAN_SYSTEM_PROMPT },
|
||||
{ role: 'user', content: buildUserPrompt(context) },
|
||||
];
|
||||
|
||||
// 4. Call Claude API
|
||||
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-api-key': process.env.ANTHROPIC_API_KEY!,
|
||||
'anthropic-version': '2023-06-01',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'claude-3-5-sonnet-20240620',
|
||||
max_tokens: 4096,
|
||||
temperature: 0.3,
|
||||
messages,
|
||||
}),
|
||||
});
|
||||
|
||||
// 5. Parse and validate response
|
||||
const result = await response.json();
|
||||
const plan = GeneratedPlanSchema.parse(
|
||||
JSON.parse(result.content[0].text)
|
||||
);
|
||||
|
||||
// 6. Log to ai_events
|
||||
await logAIEvent('behandelplan_generate', input, plan);
|
||||
|
||||
return NextResponse.json(plan);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Performance & Scalability
|
||||
|
||||
### 8.1 Performance Targets
|
||||
|
||||
| Metric | Target | Huidige Baseline |
|
||||
|--------|--------|------------------|
|
||||
| Page load (FCP) | < 1.5s | ~1s (andere pagina's) |
|
||||
| API response | < 500ms | ~300ms (intakes) |
|
||||
| AI generation | < 8s | N/A (nieuw) |
|
||||
| Auto-save | < 500ms | ~300ms (reports) |
|
||||
|
||||
### 8.2 Optimalisaties
|
||||
|
||||
**Frontend:**
|
||||
- Server Components voor initial load (geen client JS voor data)
|
||||
- Skeleton loaders tijdens AI generatie
|
||||
- Optimistic updates voor status wijzigingen
|
||||
|
||||
**Backend:**
|
||||
- Parallel database queries voor context loading
|
||||
- Geen caching van AI responses (elke generatie uniek)
|
||||
- Connection pooling via Supabase (bestaand)
|
||||
|
||||
**AI:**
|
||||
- Max tokens: 4096 (voldoende voor plan JSON)
|
||||
- Temperature: 0.3 (consistent maar niet robotisch)
|
||||
- Retry logic: 2x met exponential backoff
|
||||
|
||||
---
|
||||
|
||||
## 9. Deployment & CI/CD
|
||||
|
||||
### 9.1 Omgevingen (bestaand)
|
||||
|
||||
| Omgeving | URL | Database |
|
||||
|----------|-----|----------|
|
||||
| Development | localhost:3000 | Local Supabase |
|
||||
| Preview | Vercel preview | Supabase preview branch |
|
||||
| Production | [main domain] | Supabase production |
|
||||
|
||||
### 9.2 Migratie Workflow (Cloud-only)
|
||||
|
||||
```bash
|
||||
# Geen lokale Supabase instantie - direct naar cloud
|
||||
|
||||
# Optie 1: Via Supabase MCP tool
|
||||
mcp__supabase__apply_migration(name, query)
|
||||
|
||||
# Optie 2: Via Supabase CLI
|
||||
npx supabase db push --linked
|
||||
|
||||
# Types genereren na migratie
|
||||
mcp__supabase__generate_typescript_types
|
||||
```
|
||||
|
||||
**Let op:** Geen `supabase db reset` mogelijk - migraties zijn direct productie.
|
||||
|
||||
### 9.3 Deployment Checklist
|
||||
|
||||
- [ ] Environment variables in Vercel dashboard
|
||||
- [ ] Database migraties toegepast
|
||||
- [ ] TypeScript types gegenereerd (`supabase gen types typescript`)
|
||||
- [ ] Build succesvol (`pnpm build`)
|
||||
- [ ] Smoke test op preview environment
|
||||
|
||||
---
|
||||
|
||||
## 10. Monitoring & Logging
|
||||
|
||||
### 10.1 AI Event Logging (bestaand)
|
||||
|
||||
```sql
|
||||
-- Bestaande ai_events tabel
|
||||
ai_events (
|
||||
id UUID,
|
||||
kind TEXT, -- 'behandelplan_generate' | 'behandelplan_regenerate'
|
||||
request JSONB, -- Input parameters
|
||||
response JSONB, -- Generated plan
|
||||
duration_ms INTEGER,
|
||||
created_at TIMESTAMP
|
||||
)
|
||||
```
|
||||
|
||||
### 10.2 Metrics te Tracken
|
||||
|
||||
| Metric | Doel | Actie bij Overschrijding |
|
||||
|--------|------|--------------------------|
|
||||
| AI success rate | > 95% | Check prompts, input validation |
|
||||
| AI response time p95 | < 8s | Optimize prompt size |
|
||||
| Error rate | < 2% | Alert + investigate |
|
||||
|
||||
---
|
||||
|
||||
## 11. Risico's & Technische Mitigatie
|
||||
|
||||
| Risico | Impact | Kans | Mitigatie |
|
||||
|--------|--------|------|-----------|
|
||||
| AI genereert invalide JSON | Hoog | Middel | Zod validation, retry logic, fallback |
|
||||
| AI API down/rate limited | Hoog | Laag | Error message, manual mode optie |
|
||||
| Grote intake teksten (token limit) | Middel | Middel | Truncate/summarize intake eerst |
|
||||
| Inconsistente B1-taal kwaliteit | Middel | Middel | Post-processing, behandelaar review |
|
||||
| Performance bij grote plannen | Laag | Laag | Pagination, lazy loading |
|
||||
|
||||
---
|
||||
|
||||
## 12. Implementatie Volgorde
|
||||
|
||||
### Stap 1: Types & Database (2-3 uur)
|
||||
|
||||
**Bestanden:**
|
||||
```
|
||||
lib/types/
|
||||
├── behandelplan.ts # Nieuwe types + Zod schemas
|
||||
└── leefgebieden.ts # Life domain types
|
||||
|
||||
supabase/migrations/
|
||||
└── xxx_add_behandelplan_fields.sql
|
||||
```
|
||||
|
||||
### Stap 2: Leefgebieden Componenten (3-4 uur)
|
||||
|
||||
**Bestanden:**
|
||||
```
|
||||
components/behandelplan/
|
||||
├── leefgebieden-form.tsx # Intake formulier (7 sliders)
|
||||
├── leefgebieden-scores.tsx # Progress bar weergave
|
||||
└── leefgebieden-badge.tsx # Domain tag/badge
|
||||
```
|
||||
|
||||
### Stap 3: AI Generatie (3-4 uur)
|
||||
|
||||
**Bestanden:**
|
||||
```
|
||||
lib/ai/
|
||||
├── behandelplan-prompt.ts # System + user prompts
|
||||
└── intervention-mapping.ts # Evidence-based mapping
|
||||
|
||||
app/api/behandelplan/
|
||||
├── generate/route.ts # POST endpoint
|
||||
└── regenerate-section/route.ts # Micro-regeneratie
|
||||
```
|
||||
|
||||
### Stap 4: Behandelplan UI (6-8 uur)
|
||||
|
||||
**Bestanden:**
|
||||
```
|
||||
app/epd/patients/[id]/behandelplan/
|
||||
├── page.tsx # Server component (vervang placeholder)
|
||||
├── actions.ts # Server actions (CRUD)
|
||||
└── components/
|
||||
├── behandelplan-view.tsx
|
||||
├── goals-section.tsx
|
||||
├── goal-card.tsx
|
||||
├── interventions-section.tsx
|
||||
└── generate-button.tsx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. Bijlagen & Referenties
|
||||
|
||||
### Projectdocumenten
|
||||
- [PRD Behandelplan v2.0](./prd-behandelplan-v2-final.md)
|
||||
- [FO Behandelplan v1.0](./fo-behandelplan-v1.md)
|
||||
- [UX Stylesheet](../ux-stylesheet.md)
|
||||
|
||||
### Tech Documentatie
|
||||
- Next.js: https://nextjs.org/docs
|
||||
- Supabase: https://supabase.com/docs
|
||||
- Anthropic Claude: https://docs.anthropic.com/claude/reference
|
||||
|
||||
### Bestaande Code Referenties
|
||||
- API pattern: `/app/api/reports/classify/route.ts`
|
||||
- Server actions: `/app/epd/patients/[id]/intakes/[intakeId]/actions.ts`
|
||||
- Types pattern: `/lib/types/report.ts`
|
||||
- AI integration: `/app/api/docs/chat/route.ts`
|
||||
|
||||
---
|
||||
|
||||
**Document Status:** v1.0 Draft
|
||||
**Volgende Review:** Na implementatie Stap 1-2
|
||||
**Eigenaar:** Colin van Zeeland
|
||||
@@ -1,768 +0,0 @@
|
||||
# Mission Control — Bouwplan Diagnose Module
|
||||
|
||||
**Projectnaam:** Diagnose Module - Mini EPD
|
||||
**Versie:** v1.1
|
||||
**Datum:** 11-12-2024
|
||||
**Auteur:** Colin Lit
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en context
|
||||
|
||||
**Doel:** De bestaande diagnose-functionaliteit uitbreiden naar een volwaardige module met doorzoekbare ICD-10 classificatie, verbeterde UX en hoofd-/nevendiagnose ondersteuning.
|
||||
|
||||
**Toelichting:**
|
||||
De huidige implementatie (`diagnosis-manager.tsx`) is een basic formulier met handmatige code-invoer. Dit bouwplan beschrijft de upgrade naar:
|
||||
- Doorzoekbare **ICD-10 codelijst** (~50 GGZ-codes, client-side filtering)
|
||||
- **Modal-based invoer** (in plaats van inline formulier)
|
||||
- **Diagnose cards** met visuele status badges
|
||||
- Hoofd-/nevendiagnose markering
|
||||
- DSM-5 referentieveld (vrije tekst)
|
||||
|
||||
**Referentiedocumenten:**
|
||||
- PRD: `docs/specs/diagnose/prd-diagnose-module-v1.md` (v1.1)
|
||||
- FO: `docs/specs/diagnose/fo-diagnose-module-v1.md` (v1.1)
|
||||
- TO: `docs/specs/diagnose/to-diagnose-module-v1.md` (v1.0)
|
||||
|
||||
---
|
||||
|
||||
## 2. Uitgangspunten
|
||||
|
||||
### 2.1 Technische Stack
|
||||
- **Frontend:** Next.js 14 App Router + Tailwind CSS + shadcn/ui
|
||||
- **Database:** Supabase PostgreSQL (bestaande `conditions` tabel)
|
||||
- **UI Components:** shadcn/ui Dialog, Command (cmdk), Badge, Card
|
||||
- **Form Handling:** react-hook-form + zod
|
||||
- **Icons:** Lucide React
|
||||
|
||||
### 2.2 Projectkaders
|
||||
- **Scope:** Prototype voor demo
|
||||
- **Data:** Statische ICD-10 JSON (~50 codes), geen API call
|
||||
- **Licentie:** ICD-10 = publiek domein (WHO). DSM-5 vereist licentie.
|
||||
- **AI:** Optioneel / post-MVP
|
||||
|
||||
### 2.3 Programmeer Uitgangspunten
|
||||
|
||||
**Code Quality Principles:**
|
||||
- **DRY:** Herbruikbare ICD-10 zoekcomponent, diagnose types
|
||||
- **KISS:** Client-side filtering (geen server call voor 50 codes)
|
||||
- **SOC:** Modal logica gescheiden van lijst weergave
|
||||
- **YAGNI:** Geen AI-suggesties in v1, geen patiënt-breed overzicht
|
||||
|
||||
**Development Practices:**
|
||||
- Bestaande `conditions` tabel gebruiken (geen schema wijzigingen)
|
||||
- Server actions in bestaande `actions.ts` uitbreiden
|
||||
- shadcn/ui Command component voor autocomplete
|
||||
|
||||
---
|
||||
|
||||
## 3. Epics & Stories Overzicht
|
||||
|
||||
| Epic ID | Titel | Doel | Status | Stories | Opmerkingen |
|
||||
|---------|-------|------|--------|---------|-------------|
|
||||
| E0 | Data & Types | ICD-10 codelijst en TypeScript types | ✅ Gereed | 3 | JSON + types + schema |
|
||||
| E1 | UI Componenten | Nieuwe componenten voor diagnose UI | ⏳ To Do | 4 | Modal, Combobox, Card |
|
||||
| E2 | Integratie | Bestaande code refactoren | ⏳ To Do | 3 | Actions + Manager refactor |
|
||||
| E3 | Polish & Test | Afronding en testen | ⏳ To Do | 2 | States + handmatige tests |
|
||||
|
||||
**Belangrijk:** Voer niet in 1x het volledige plan uit. Bouw per epic en per story.
|
||||
**Belangrijk:** Installatie van `cmdk` dependency moet eerst aan Colin worden gemeld.
|
||||
|
||||
---
|
||||
|
||||
## 4. Epics & Stories (Uitwerking)
|
||||
|
||||
### Epic 0 — Data & Types
|
||||
**Epic Doel:** Statische ICD-10 codelijst en TypeScript types voor de module.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points |
|
||||
|----------|--------------|---------------------|--------|------------------|--------------|
|
||||
| E0.S1 | ICD-10 JSON codelijst maken | `lib/data/icd10-ggz-codes.json` met ~50 GGZ-codes, categorieën, keywords | ✅ | — | 3 |
|
||||
| E0.S2 | TypeScript types voor ICD-10 | `lib/types/icd10.ts` met interfaces en helper functies | ✅ | E0.S1 | 1 |
|
||||
| E0.S3 | Zod validatieschema | `lib/schemas/diagnosis.ts` voor form validatie met Nederlandse foutmeldingen | ✅ | E0.S2 | 1 |
|
||||
|
||||
**Technical Notes:**
|
||||
- ICD-10 codes: F32.x (depressie), F40.x-F41.x (angst), F43.x (trauma), F60.x (persoonlijkheid), etc.
|
||||
- Keywords toevoegen voor betere zoekresultaten
|
||||
- Code format: `/^F\d{2}(\.\d{1,2})?$/`
|
||||
|
||||
---
|
||||
|
||||
#### E0.S1 — ICD-10 JSON Codelijst
|
||||
|
||||
**Doel:** Statische JSON met ~50 GGZ-relevante ICD-10 codes voor client-side filtering.
|
||||
|
||||
**Locatie:** `lib/data/icd10-ggz-codes.json`
|
||||
|
||||
**Data structuur:**
|
||||
```json
|
||||
{
|
||||
"version": "ICD-10-GM 2024",
|
||||
"source": "WHO (publiek domein)",
|
||||
"categories": [
|
||||
{
|
||||
"name": "Depressieve stoornissen",
|
||||
"codes": [
|
||||
{ "code": "F32.0", "display": "Lichte depressieve episode", "keywords": ["depressie", "licht"] }
|
||||
]
|
||||
}
|
||||
],
|
||||
"frequentCodes": ["F32.1", "F41.1", "F43.1", "F41.0", "F60.3"]
|
||||
}
|
||||
```
|
||||
|
||||
**Categorie indeling (~55 codes):**
|
||||
| Categorie | Codes | Aantal |
|
||||
|-----------|-------|--------|
|
||||
| Depressieve stoornissen | F32.x, F33.x | 7 |
|
||||
| Angststoornissen | F40.x, F41.x | 8 |
|
||||
| Trauma/stress | F43.x | 4 |
|
||||
| OCD | F42.x | 3 |
|
||||
| Bipolaire stoornissen | F31.x | 4 |
|
||||
| Persoonlijkheidsstoornissen | F60.x | 7 |
|
||||
| ADHD | F90.x | 2 |
|
||||
| Autisme | F84.x | 2 |
|
||||
| Eetstoornissen | F50.x | 3 |
|
||||
| Schizofrenie/psychose | F20.x, F23.x | 3 |
|
||||
| Middelengebruik | F10.x-F19.x | 6 |
|
||||
| Somatoforme/dissociatief | F44.x, F45.x | 4 |
|
||||
| Slaapstoornissen | F51.x | 2 |
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] JSON is valid en parsed zonder errors
|
||||
- [ ] Alle codes hebben `code`, `display` en `keywords` velden
|
||||
- [ ] Keywords zijn in het Nederlands
|
||||
- [ ] `frequentCodes` bevat top 5 meest gebruikte GGZ-codes
|
||||
|
||||
---
|
||||
|
||||
#### E0.S2 — TypeScript Types
|
||||
|
||||
**Doel:** Type-safe interfaces voor ICD-10 data en diagnose operaties.
|
||||
|
||||
**Locatie:** `lib/types/icd10.ts`
|
||||
|
||||
**Te implementeren types:**
|
||||
```typescript
|
||||
// Data types
|
||||
interface ICD10Code {
|
||||
code: string;
|
||||
display: string;
|
||||
keywords: string[];
|
||||
}
|
||||
|
||||
interface ICD10Category {
|
||||
name: string;
|
||||
codes: ICD10Code[];
|
||||
}
|
||||
|
||||
interface ICD10CodeList {
|
||||
version: string;
|
||||
source: string;
|
||||
categories: ICD10Category[];
|
||||
frequentCodes: string[];
|
||||
}
|
||||
|
||||
// Diagnose types (FHIR compatible)
|
||||
type DiagnosisSeverity = 'licht' | 'matig' | 'ernstig';
|
||||
type DiagnosisClinicalStatus = 'active' | 'remission' | 'resolved' | ...;
|
||||
type DiagnosisType = 'primary' | 'secondary';
|
||||
|
||||
// Helper type
|
||||
type FlatICD10Code = ICD10Code & { category: string };
|
||||
```
|
||||
|
||||
**Helper functies:**
|
||||
```typescript
|
||||
flattenICD10Codes(codeList): FlatICD10Code[]
|
||||
searchICD10Codes(codes, query, maxResults): FlatICD10Code[]
|
||||
getFrequentCodes(codes, frequentIds): FlatICD10Code[]
|
||||
```
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] Alle types exporteren correct
|
||||
- [ ] Helper functies zijn type-safe
|
||||
- [ ] `searchICD10Codes` zoekt op code, display en keywords
|
||||
- [ ] `pnpm build` slaagt zonder type errors
|
||||
|
||||
---
|
||||
|
||||
#### E0.S3 — Zod Validatieschema
|
||||
|
||||
**Doel:** Form validatie met Nederlandse foutmeldingen.
|
||||
|
||||
**Locatie:** `lib/schemas/diagnosis.ts`
|
||||
|
||||
**Schema velden:**
|
||||
| Veld | Type | Verplicht | Validatie |
|
||||
|------|------|-----------|-----------|
|
||||
| `code` | string | Ja | Regex: `/^F\d{2}(\.\d{1,2})?$/` |
|
||||
| `description` | string | Ja | Min 1, max 200 tekens |
|
||||
| `severity` | enum | Ja | licht / matig / ernstig |
|
||||
| `diagnosisType` | enum | Ja | primary / secondary |
|
||||
| `status` | enum | Ja | active / remission / resolved / entered-in-error |
|
||||
| `dsm5Reference` | string | Nee | Max 100 tekens |
|
||||
| `notes` | string | Nee | Max 500 tekens |
|
||||
|
||||
**Exports:**
|
||||
```typescript
|
||||
// Constants
|
||||
export const DIAGNOSIS_SEVERITIES = ['licht', 'matig', 'ernstig'] as const;
|
||||
export const DIAGNOSIS_TYPES = ['primary', 'secondary'] as const;
|
||||
export const DIAGNOSIS_STATUSES = ['active', 'remission', 'resolved', 'entered-in-error'] as const;
|
||||
|
||||
// Schemas
|
||||
export const diagnosisSchema = z.object({...});
|
||||
export const diagnosisPayloadSchema = diagnosisSchema.extend({ patientId, intakeId });
|
||||
export const diagnosisUpdateSchema = diagnosisSchema.partial().extend({ id });
|
||||
|
||||
// Types
|
||||
export type DiagnosisFormData = z.infer<typeof diagnosisSchema>;
|
||||
export type DiagnosisPayload = z.infer<typeof diagnosisPayloadSchema>;
|
||||
|
||||
// Defaults
|
||||
export const diagnosisDefaults: DiagnosisFormData = {...};
|
||||
```
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] Alle foutmeldingen zijn in het Nederlands
|
||||
- [ ] `diagnosisDefaults` heeft correcte default waarden
|
||||
- [ ] Schema's zijn compatibel met react-hook-form
|
||||
- [ ] `pnpm build` slaagt zonder type errors
|
||||
|
||||
---
|
||||
|
||||
### Epic 1 — UI Componenten
|
||||
**Epic Doel:** Nieuwe React componenten voor de diagnose-UI.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points |
|
||||
|----------|--------------|---------------------|--------|------------------|--------------|
|
||||
| E1.S1 | ICD-10 Combobox component | Autocomplete zoeken in ICD-10 codes, debounce, max 8 resultaten | ⏳ | E0.S1, E0.S2 | 3 |
|
||||
| E1.S2 | Diagnose Modal component | Dialog met form, validatie, opslaan/bewerken | ⏳ | E0.S3, E1.S1 | 5 |
|
||||
| E1.S3 | Diagnose Card component | Weergave per diagnose met badges, expand/collapse, acties | ⏳ | — | 2 |
|
||||
| E1.S4 | cmdk dependency installeren | `pnpm add cmdk` uitvoeren (Colin) | ⏳ | — | 1 |
|
||||
|
||||
**Technical Notes:**
|
||||
- **E1.S4:** Colin moet `pnpm add cmdk` goedkeuren/uitvoeren
|
||||
- Gebruik shadcn/ui patterns voor consistentie
|
||||
- Command component voor autocomplete (cmdk based)
|
||||
|
||||
---
|
||||
|
||||
#### E1.S1 — ICD-10 Combobox Component
|
||||
|
||||
**Doel:** Autocomplete zoekcomponent voor ICD-10 codes met keyboard navigatie.
|
||||
|
||||
**Locatie:** `app/epd/patients/[id]/intakes/[intakeId]/diagnosis/components/icd10-combobox.tsx`
|
||||
|
||||
**Props interface:**
|
||||
```typescript
|
||||
interface ICD10ComboboxProps {
|
||||
value: string; // Geselecteerde code (bijv. "F32.1")
|
||||
onSelect: (code: FlatICD10Code) => void; // Callback bij selectie
|
||||
placeholder?: string; // Default: "Zoek op code of beschrijving..."
|
||||
disabled?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
**Functionaliteit:**
|
||||
| Feature | Beschrijving |
|
||||
|---------|--------------|
|
||||
| Zoeken | Filter op code (F32), display (depressie) en keywords |
|
||||
| Debounce | 200ms delay voor filtering |
|
||||
| Max resultaten | 8 items in dropdown |
|
||||
| Snelkeuze | Bij leeg veld: toon top 5 veelgebruikte codes |
|
||||
| Keyboard | Arrow keys navigatie, Enter selecteert, Escape sluit |
|
||||
| Display | Code vetgedrukt, beschrijving normaal |
|
||||
|
||||
**UI States:**
|
||||
| State | Weergave |
|
||||
|-------|----------|
|
||||
| Leeg veld | Placeholder + snelkeuze dropdown |
|
||||
| Typing | Zoekresultaten dropdown |
|
||||
| Geen resultaten | "Geen codes gevonden voor '{query}'" |
|
||||
| Geselecteerd | Geselecteerde code + beschrijving in input |
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] Zoeken werkt op code, display en keywords
|
||||
- [ ] Debounce voorkomt te veel renders
|
||||
- [ ] Max 8 resultaten worden getoond
|
||||
- [ ] Snelkeuze toont top 5 bij leeg veld
|
||||
- [ ] Keyboard navigatie werkt correct
|
||||
- [ ] Focus management correct (blur sluit dropdown)
|
||||
|
||||
---
|
||||
|
||||
#### E1.S2 — Diagnose Modal Component
|
||||
|
||||
**Doel:** Modal dialog voor toevoegen en bewerken van diagnoses.
|
||||
|
||||
**Locatie:** `app/epd/patients/[id]/intakes/[intakeId]/diagnosis/components/diagnosis-modal.tsx`
|
||||
|
||||
**Props interface:**
|
||||
```typescript
|
||||
interface DiagnosisModalProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
patientId: string;
|
||||
intakeId: string;
|
||||
diagnosis?: Condition; // undefined = nieuw, Condition = bewerk
|
||||
onSuccess: () => void; // Callback na succesvol opslaan
|
||||
}
|
||||
```
|
||||
|
||||
**Form velden:**
|
||||
| Veld | Component | Verplicht | Notes |
|
||||
|------|-----------|-----------|-------|
|
||||
| ICD-10 Code | ICD10Combobox | Ja | Autocomplete |
|
||||
| Ernst | Select | Ja | licht / matig / ernstig |
|
||||
| Diagnose type | RadioGroup | Ja | Hoofd / Neven |
|
||||
| Status | Select | Ja | Actief / In remissie / Opgelost |
|
||||
| DSM-5 referentie | Input | Nee | Vrije tekst |
|
||||
| Onderbouwing | Textarea | Nee | Max 500 tekens |
|
||||
|
||||
**Gedrag:**
|
||||
| Scenario | Actie |
|
||||
|----------|-------|
|
||||
| Nieuw | Lege form met defaults |
|
||||
| Bewerk | Form voorgevuld met bestaande data |
|
||||
| Submit | Validatie → Server action → onSuccess → Close |
|
||||
| Validatiefout | Inline errors onder velden |
|
||||
| Server error | Toast met foutmelding |
|
||||
|
||||
**UI Layout:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Nieuwe diagnose / Diagnose bewerken [✕] │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ICD-10 Code * │
|
||||
│ [Combobox: Zoek op code of beschrijving...] │
|
||||
│ │
|
||||
│ Ernst * Diagnose type * │
|
||||
│ [Select: Matig ▼] ○ Hoofddiagnose │
|
||||
│ ● Nevendiagnose │
|
||||
│ │
|
||||
│ Status * │
|
||||
│ [Select: Actief ▼] │
|
||||
│ │
|
||||
│ DSM-5 referentie (optioneel) │
|
||||
│ [Input: bijv. Major Depressive Disorder] │
|
||||
│ │
|
||||
│ Onderbouwing (optioneel) │
|
||||
│ [Textarea: Klinische redenering...] │
|
||||
│ │
|
||||
│ [Annuleren] [Opslaan] │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] Modal opent/sluit correct
|
||||
- [ ] Form validatie werkt met Nederlandse foutmeldingen
|
||||
- [ ] ICD-10 combobox integreert correct
|
||||
- [ ] Bewerk modus vult form voor met bestaande data
|
||||
- [ ] Opslaan roept juiste server action aan
|
||||
- [ ] Loading state tijdens opslaan
|
||||
- [ ] Modal sluit na succesvolle actie
|
||||
|
||||
---
|
||||
|
||||
#### E1.S3 — Diagnose Card Component
|
||||
|
||||
**Doel:** Visuele weergave van een diagnose met acties.
|
||||
|
||||
**Locatie:** `app/epd/patients/[id]/intakes/[intakeId]/diagnosis/components/diagnosis-card.tsx`
|
||||
|
||||
**Props interface:**
|
||||
```typescript
|
||||
interface DiagnosisCardProps {
|
||||
diagnosis: Condition;
|
||||
isPrimary?: boolean;
|
||||
onEdit: () => void;
|
||||
onDelete: () => void;
|
||||
isDeleting?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
**UI Layout:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ F32.1 — Matige depressieve episode HOOFD [⋮] │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Ernst: Matig │ Status: Actief │ 15 nov 2024 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ ▼ Onderbouwing │
|
||||
│ Patiënt voldoet aan 6 van de 9 criteria... │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Elementen:**
|
||||
| Element | Beschrijving |
|
||||
|---------|--------------|
|
||||
| Code + beschrijving | Vetgedrukt, altijd zichtbaar |
|
||||
| HOOFD badge | Groen, alleen bij isPrimary |
|
||||
| Status badge | Kleur per status (groen/blauw/grijs/rood) |
|
||||
| Ernst | Tekst weergave |
|
||||
| Datum | Format: d MMM yyyy (NL locale) |
|
||||
| Onderbouwing | Ingeklapt, expand via chevron |
|
||||
| Context menu | Bewerk, Verwijder |
|
||||
|
||||
**Status badge kleuren:**
|
||||
| Status | Kleur | Tekst |
|
||||
|--------|-------|-------|
|
||||
| active | Groen | Actief |
|
||||
| remission | Blauw | In remissie |
|
||||
| resolved | Grijs | Opgelost |
|
||||
| entered-in-error | Rood | Foutief |
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] Card toont alle diagnose informatie
|
||||
- [ ] HOOFD badge alleen zichtbaar bij isPrimary
|
||||
- [ ] Status badge heeft correcte kleur
|
||||
- [ ] Onderbouwing is expand/collapse
|
||||
- [ ] Context menu met Bewerk/Verwijder
|
||||
- [ ] Loading state bij verwijderen
|
||||
|
||||
---
|
||||
|
||||
#### E1.S4 — cmdk Dependency Installeren
|
||||
|
||||
**Doel:** Command menu library installeren voor autocomplete functionaliteit.
|
||||
|
||||
**Commando:**
|
||||
```bash
|
||||
pnpm add cmdk
|
||||
```
|
||||
|
||||
**Alternatief (indien cmdk niet gewenst):**
|
||||
Custom autocomplete bouwen met:
|
||||
- `@radix-ui/react-popover` (reeds aanwezig)
|
||||
- `@radix-ui/react-scroll-area`
|
||||
- Custom filtering logic
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] `pnpm add cmdk` uitgevoerd door Colin
|
||||
- [ ] Package toegevoegd aan `package.json`
|
||||
- [ ] `pnpm install` succesvol
|
||||
- [ ] `pnpm build` slaagt
|
||||
|
||||
---
|
||||
|
||||
### Epic 2 — Integratie
|
||||
**Epic Doel:** Bestaande code refactoren en nieuwe componenten integreren.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points |
|
||||
|----------|--------------|---------------------|--------|------------------|--------------|
|
||||
| E2.S1 | Server actions uitbreiden | `updateDiagnosis` functie, code_system naar ICD-10 | ⏳ | E0.S3 | 2 |
|
||||
| E2.S2 | DiagnosisManager refactoren | Vervang inline form door modal, gebruik DiagnosisCard | ⏳ | E1.S2, E1.S3 | 3 |
|
||||
| E2.S3 | Page.tsx aanpassen | Pagina tekst updaten, imports aanpassen | ⏳ | E2.S2 | 1 |
|
||||
|
||||
---
|
||||
|
||||
#### E2.S1 — Server Actions Uitbreiden
|
||||
|
||||
**Doel:** Bestaande server actions aanpassen en uitbreiden voor nieuwe functionaliteit.
|
||||
|
||||
**Locatie:** `app/epd/patients/[id]/intakes/[intakeId]/actions.ts`
|
||||
|
||||
**Wijzigingen in `createDiagnosis`:**
|
||||
```typescript
|
||||
// Huidige implementatie
|
||||
code_system: undefined // of 'DSM-5'
|
||||
|
||||
// Nieuwe implementatie
|
||||
code_system: 'ICD-10',
|
||||
category: payload.diagnosisType === 'primary' ? 'primary-diagnosis' : 'encounter-diagnosis',
|
||||
```
|
||||
|
||||
**Nieuwe functie `updateDiagnosis`:**
|
||||
```typescript
|
||||
export async function updateDiagnosis(
|
||||
diagnosisId: string,
|
||||
payload: DiagnosisUpdatePayload
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const supabase = await createClient();
|
||||
|
||||
const { error } = await supabase
|
||||
.from('conditions')
|
||||
.update({
|
||||
code_code: payload.code,
|
||||
code_display: payload.description,
|
||||
clinical_status: payload.status,
|
||||
severity_display: payload.severity,
|
||||
note: payload.notes,
|
||||
category: payload.diagnosisType === 'primary' ? 'primary-diagnosis' : 'encounter-diagnosis',
|
||||
updated_at: new Date().toISOString(),
|
||||
})
|
||||
.eq('id', diagnosisId);
|
||||
|
||||
if (error) {
|
||||
return { success: false, error: 'Diagnose bijwerken mislukt' };
|
||||
}
|
||||
|
||||
revalidatePath(`/epd/patients/[id]/intakes/[intakeId]/diagnosis`);
|
||||
return { success: true };
|
||||
}
|
||||
```
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] `createDiagnosis` zet code_system op 'ICD-10'
|
||||
- [ ] `createDiagnosis` zet category correct (primary/encounter)
|
||||
- [ ] `updateDiagnosis` functie werkt correct
|
||||
- [ ] Path revalidatie na create/update/delete
|
||||
- [ ] Foutafhandeling met Nederlandse meldingen
|
||||
|
||||
---
|
||||
|
||||
#### E2.S2 — DiagnosisManager Refactoren
|
||||
|
||||
**Doel:** Bestaande component vervangen door nieuwe UI met modal en cards.
|
||||
|
||||
**Locatie:** `app/epd/patients/[id]/intakes/[intakeId]/diagnosis/components/diagnosis-manager.tsx`
|
||||
|
||||
**Huidige structuur (te vervangen):**
|
||||
```
|
||||
- Inline diagnose lijst
|
||||
- Inline toevoeg formulier
|
||||
- Verwijder buttons
|
||||
```
|
||||
|
||||
**Nieuwe structuur:**
|
||||
```
|
||||
- DiagnosisCard lijst (met sorteer: hoofd eerst)
|
||||
- [+ Nieuwe diagnose] button → opent DiagnosisModal
|
||||
- DiagnosisModal (create/edit)
|
||||
- Verwijder bevestiging dialog
|
||||
```
|
||||
|
||||
**State management:**
|
||||
```typescript
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [editingDiagnosis, setEditingDiagnosis] = useState<Condition | undefined>();
|
||||
const [deletingId, setDeletingId] = useState<string | null>(null);
|
||||
```
|
||||
|
||||
**Gedrag:**
|
||||
| Actie | Effect |
|
||||
|-------|--------|
|
||||
| [+ Nieuwe diagnose] | `setModalOpen(true)`, `setEditingDiagnosis(undefined)` |
|
||||
| Card: Bewerk | `setModalOpen(true)`, `setEditingDiagnosis(diagnosis)` |
|
||||
| Card: Verwijder | Confirm dialog → `deleteDiagnosis()` |
|
||||
| Modal: Opslaan | `create/updateDiagnosis()` → close modal |
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] Inline form verwijderd
|
||||
- [ ] DiagnosisCard voor elke diagnose
|
||||
- [ ] Hoofddiagnoses worden eerst getoond
|
||||
- [ ] Modal opent voor nieuw/bewerk
|
||||
- [ ] Verwijderen met bevestiging
|
||||
- [ ] Loading states correct
|
||||
|
||||
---
|
||||
|
||||
#### E2.S3 — Page.tsx Aanpassen
|
||||
|
||||
**Doel:** Server component aanpassen voor nieuwe module.
|
||||
|
||||
**Locatie:** `app/epd/patients/[id]/intakes/[intakeId]/diagnosis/page.tsx`
|
||||
|
||||
**Wijzigingen:**
|
||||
```typescript
|
||||
// Huidige tekst
|
||||
<p className="text-sm text-slate-600">
|
||||
Registreer DSM-5 diagnoses gekoppeld aan deze intake.
|
||||
</p>
|
||||
|
||||
// Nieuwe tekst
|
||||
<p className="text-sm text-slate-600">
|
||||
Registreer diagnoses met ICD-10 classificatie gekoppeld aan deze intake.
|
||||
</p>
|
||||
```
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] Tekst verwijst naar ICD-10 i.p.v. DSM-5
|
||||
- [ ] Imports zijn correct
|
||||
- [ ] Pagina laadt zonder errors
|
||||
|
||||
---
|
||||
|
||||
### Epic 3 — Polish & Test
|
||||
**Epic Doel:** Afronding met correcte feedback en handmatige tests.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points |
|
||||
|----------|--------------|---------------------|--------|------------------|--------------|
|
||||
| E3.S1 | Empty states en feedback | Toast bij acties, lege staat tekst, loading indicators | ⏳ | E2.S2 | 1 |
|
||||
| E3.S2 | Handmatige tests uitvoeren | Alle test scenario's doorlopen en documenteren | ⏳ | E3.S1 | 1 |
|
||||
|
||||
---
|
||||
|
||||
#### E3.S1 — Empty States en Feedback
|
||||
|
||||
**Doel:** Consistente feedback en lege staten voor goede UX.
|
||||
|
||||
**Empty states:**
|
||||
| Context | Tekst | Actie |
|
||||
|---------|-------|-------|
|
||||
| Geen diagnoses | "Nog geen diagnoses geregistreerd." | [+ Nieuwe diagnose] button prominent |
|
||||
| Geen zoekresultaten | "Geen codes gevonden voor '{query}'" | — |
|
||||
|
||||
**Toast feedback:**
|
||||
| Actie | Type | Tekst |
|
||||
|-------|------|-------|
|
||||
| Diagnose opgeslagen | Success | "Diagnose opgeslagen" |
|
||||
| Diagnose bijgewerkt | Success | "Diagnose bijgewerkt" |
|
||||
| Diagnose verwijderd | Success | "Diagnose verwijderd" |
|
||||
| Opslaan mislukt | Error | "Opslaan mislukt: {error}" |
|
||||
|
||||
**Loading indicators:**
|
||||
| Context | Indicator |
|
||||
|---------|-----------|
|
||||
| Modal opslaan | Button disabled + spinner |
|
||||
| Verwijderen | Card disabled + spinner |
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] Lege staat toont correcte tekst en button
|
||||
- [ ] Toast feedback bij alle acties
|
||||
- [ ] Loading indicators zichtbaar
|
||||
- [ ] Geen UI jumps tijdens laden
|
||||
|
||||
---
|
||||
|
||||
#### E3.S2 — Handmatige Tests
|
||||
|
||||
**Doel:** Alle functionaliteit testen en documenteren.
|
||||
|
||||
**Test scenario's:**
|
||||
| # | Scenario | Stappen | Verwacht resultaat | Status |
|
||||
|---|----------|---------|-------------------|--------|
|
||||
| 1 | Zoek op beschrijving | Type "depressie" in combobox | Toont F32.x codes | ⏳ |
|
||||
| 2 | Zoek op code | Type "F41" in combobox | Toont angststoornissen | ⏳ |
|
||||
| 3 | Selecteer code | Klik op F32.1 in dropdown | Vult code + beschrijving | ⏳ |
|
||||
| 4 | Validatie | Opslaan zonder code | Toont foutmelding | ⏳ |
|
||||
| 5 | Nieuwe diagnose | Vul form in → Opslaan | Card verschijnt in lijst | ⏳ |
|
||||
| 6 | Bewerk diagnose | Klik Bewerk → wijzig → Opslaan | Card toont nieuwe data | ⏳ |
|
||||
| 7 | Verwijder diagnose | Klik Verwijder → Bevestig | Card verdwijnt | ⏳ |
|
||||
| 8 | Snelkeuze | Focus op lege combobox | Toont top 5 codes | ⏳ |
|
||||
| 9 | Hoofddiagnose | Selecteer "Hoofddiagnose" | HOOFD badge zichtbaar | ⏳ |
|
||||
| 10 | Build | `pnpm build` | Geen errors | ⏳ |
|
||||
|
||||
**Acceptatiecriteria:**
|
||||
- [ ] Alle scenario's doorlopen
|
||||
- [ ] Eventuele bugs gedocumenteerd
|
||||
- [ ] `pnpm build` slaagt
|
||||
- [ ] `pnpm lint` geen errors
|
||||
|
||||
---
|
||||
|
||||
## 5. Kwaliteit & Testplan
|
||||
|
||||
### Test Types
|
||||
| Test Type | Scope | Tools | Verantwoordelijke |
|
||||
|-----------|-------|-------|-------------------|
|
||||
| Type Check | Alle nieuwe files | `pnpm build` | Developer |
|
||||
| Lint | Alle nieuwe files | `pnpm lint` | Developer |
|
||||
| Manual Tests | Diagnose flows | Handmatig | Developer |
|
||||
|
||||
### Manual Test Checklist (voor demo)
|
||||
- [ ] ICD-10 zoeken werkt op code en beschrijving
|
||||
- [ ] Nieuwe diagnose toevoegen via modal
|
||||
- [ ] Bestaande diagnose bewerken
|
||||
- [ ] Diagnose verwijderen met bevestiging
|
||||
- [ ] Hoofddiagnose markeren (visuele badge)
|
||||
- [ ] Ernst en status selecteren
|
||||
- [ ] Onderbouwing toevoegen en bekijken
|
||||
- [ ] Lege staat correct weergegeven
|
||||
- [ ] Toast feedback bij opslaan/verwijderen
|
||||
- [ ] Build slaagt zonder errors
|
||||
|
||||
---
|
||||
|
||||
## 6. Bestandsstructuur (Na Implementatie)
|
||||
|
||||
```
|
||||
app/epd/patients/[id]/intakes/[intakeId]/diagnosis/
|
||||
├── page.tsx # Server component (aangepast)
|
||||
└── components/
|
||||
├── diagnosis-manager.tsx # Refactored: lijst + modal trigger
|
||||
├── diagnosis-card.tsx # Nieuw: diagnose weergave
|
||||
├── diagnosis-modal.tsx # Nieuw: invoer/bewerk modal
|
||||
└── icd10-combobox.tsx # Nieuw: autocomplete zoeken
|
||||
|
||||
lib/data/
|
||||
└── icd10-ggz-codes.json # Nieuw: statische codelijst (55 codes)
|
||||
|
||||
lib/types/
|
||||
└── icd10.ts # Nieuw: ICD-10 TypeScript types
|
||||
|
||||
lib/schemas/
|
||||
└── diagnosis.ts # Nieuw: Zod validatieschema
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Risico's & Mitigatie
|
||||
|
||||
| Risico | Kans | Impact | Mitigatie | Owner |
|
||||
|--------|------|--------|-----------|-------|
|
||||
| cmdk dependency te groot | Laag | Laag | ~10KB gzipped, acceptabel | Developer |
|
||||
| ICD-10 codes incompleet voor demo | Laag | Middel | Start met 55, uitbreiden op verzoek | Developer |
|
||||
| Bestaande diagnoses breken | Laag | Hoog | Backward compatible, DSM-5 data blijft | Developer |
|
||||
| Modal UX niet intuïtief | Middel | Middel | Volg shadcn/ui patterns | Developer |
|
||||
|
||||
---
|
||||
|
||||
## 8. Dependency Check
|
||||
|
||||
### Benodigde nieuwe dependency
|
||||
```bash
|
||||
pnpm add cmdk
|
||||
```
|
||||
|
||||
### Bestaande dependencies (geen actie)
|
||||
- `@radix-ui/react-dialog` — Dialog voor modal
|
||||
- `@radix-ui/react-select` — Dropdowns
|
||||
- `react-hook-form` — Form handling
|
||||
- `@hookform/resolvers` — Zod integration
|
||||
- `zod` — Validatie
|
||||
- `lucide-react` — Icons
|
||||
- `date-fns` — Datum formatting
|
||||
|
||||
---
|
||||
|
||||
## 9. Referenties
|
||||
|
||||
**Mission Control Documents:**
|
||||
- PRD: `docs/specs/diagnose/prd-diagnose-module-v1.md`
|
||||
- FO: `docs/specs/diagnose/fo-diagnose-module-v1.md`
|
||||
- TO: `docs/specs/diagnose/to-diagnose-module-v1.md`
|
||||
|
||||
**Bestaande Implementatie:**
|
||||
- `app/epd/patients/[id]/intakes/[intakeId]/diagnosis/` — Huidige pagina
|
||||
- `app/epd/patients/[id]/intakes/[intakeId]/actions.ts` — Server actions
|
||||
- `lib/supabase/database.types.ts` — Database types (conditions)
|
||||
|
||||
**Externe Bronnen:**
|
||||
- [WHO ICD-10 (publiek domein)](https://www.who.int/standards/classifications/classification-of-diseases)
|
||||
- [shadcn/ui Command](https://ui.shadcn.com/docs/components/command)
|
||||
- [cmdk documentation](https://cmdk.paco.me/)
|
||||
|
||||
---
|
||||
|
||||
## 10. Glossary
|
||||
|
||||
| Term | Betekenis |
|
||||
|------|-----------|
|
||||
| ICD-10 | International Classification of Diseases, 10e revisie (WHO) |
|
||||
| DSM-5 | Diagnostic and Statistical Manual of Mental Disorders (APA) |
|
||||
| GGZ | Geestelijke gezondheidszorg |
|
||||
| cmdk | Command menu library voor React (autocomplete) |
|
||||
| FHIR | Fast Healthcare Interoperability Resources (standaard) |
|
||||
|
||||
---
|
||||
|
||||
**Versiehistorie:**
|
||||
|
||||
| Versie | Datum | Auteur | Wijziging |
|
||||
|--------|-------|--------|-----------|
|
||||
| v1.0 | 11-12-2024 | Colin Lit | Initiële versie |
|
||||
| v1.1 | 11-12-2024 | Colin Lit | Uitgebreide story beschrijvingen, E0 gereed |
|
||||
@@ -1,397 +0,0 @@
|
||||
# 🧩 Functioneel Ontwerp (FO) – Diagnose Module
|
||||
|
||||
**Projectnaam:** Diagnose Module - Mini EPD
|
||||
**Versie:** v1.1
|
||||
**Datum:** 11-12-2024
|
||||
**Auteur:** Colin Lit
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en relatie met het PRD
|
||||
|
||||
🎯 **Doel van dit document:**
|
||||
Het Functioneel Ontwerp beschrijft **hoe** de diagnosemodule in de praktijk werkt voor GGZ-professionals. Dit document vertaalt de requirements uit het PRD naar concrete schermen, acties en interacties.
|
||||
|
||||
📘 **Toelichting aan de lezer:**
|
||||
Dit FO beschrijft de diagnose-functionaliteit voor het prototype met **ICD-10 classificatie** (publiek domein) als basis en optionele DSM-5 referentie. De focus ligt op een eenvoudige, werkende flow voor demo-doeleinden.
|
||||
|
||||
**Relatie met PRD:**
|
||||
Dit FO implementeert de requirements uit `prd-diagnose-module-v1.md` (v1.1), specifiek:
|
||||
- ICD-10 classificatie browser (PRD 3.1)
|
||||
- Diagnose registratie met DSM-5 referentieveld (PRD 3.2)
|
||||
- AI-ondersteuning (PRD 3.3) — optioneel voor prototype
|
||||
|
||||
> **Licentie-opmerking:** DSM-5 vereist licentie. Dit prototype gebruikt ICD-10 (publiek domein).
|
||||
|
||||
---
|
||||
|
||||
## 2. Overzicht van de belangrijkste onderdelen
|
||||
|
||||
1. **Diagnose Tab** (binnen Intake) — Hoofdlocatie voor diagnose-registratie
|
||||
2. **ICD-10 Code Zoeken** — Autocomplete met GGZ-subset (~50 codes)
|
||||
3. **Diagnose Invoer Modal** — Formulier voor nieuwe/bewerken diagnose
|
||||
4. **Diagnose Detail Card** — Weergave per geregistreerde diagnose
|
||||
5. *(Optioneel)* **AI Diagnose Assistent** — Suggesties op basis van intake
|
||||
|
||||
---
|
||||
|
||||
## 3. Userstories (Prototype)
|
||||
|
||||
| ID | Rol | Doel / Actie | Verwachte waarde | Prioriteit |
|
||||
|----|------|---------------|------------------|-------------|
|
||||
| US-01 | Psycholoog | ICD-10 code zoeken op beschrijving | Snel juiste code vinden | Hoog |
|
||||
| US-02 | Psycholoog | ICD-10 code zoeken op code (F32) | Direct navigeren bij bekende code | Hoog |
|
||||
| US-03 | Psycholoog | Hoofddiagnose markeren | Duidelijke prioritering | Hoog |
|
||||
| US-04 | Psycholoog | Nevendiagnose(s) toevoegen | Comorbiditeit vastleggen | Hoog |
|
||||
| US-05 | Psycholoog | Ernst classificeren | Behandelniveau bepalen | Hoog |
|
||||
| US-06 | Psycholoog | DSM-5 referentie toevoegen | Eigen notatie mogelijk | Middel |
|
||||
| US-07 | Psycholoog | Onderbouwing vastleggen | Klinische redenering documenteren | Middel |
|
||||
| US-08 | Psycholoog | Diagnose bewerken/verwijderen | Correcties doorvoeren | Hoog |
|
||||
| US-09 | Systeem | Diagnoses tonen in overdracht | Relevante info voor collega's | Hoog |
|
||||
|
||||
---
|
||||
|
||||
## 4. Functionele werking per onderdeel
|
||||
|
||||
### 4.1 Diagnose Tab (binnen Intake)
|
||||
|
||||
**Locatie:** `/epd/patients/[id]/intakes/[intakeId]/diagnosis`
|
||||
|
||||
**Schermopbouw:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Diagnoses │
|
||||
│ Registreer DSM-5 diagnoses gekoppeld aan deze intake. │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─ Hoofddiagnose ────────────────────────────────────────┐ │
|
||||
│ │ F32.1 — Depressieve stoornis, matig [Bewerk] │ │
|
||||
│ │ Ernst: Matig | Status: Actief | 15 nov 2024 │ │
|
||||
│ │ "Voldoet aan 6/9 criteria, significant functioneel..." │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ Nevendiagnose ────────────────────────────────────────┐ │
|
||||
│ │ F41.1 — Gegeneraliseerde angststoornis [Bewerk] │ │
|
||||
│ │ Ernst: Licht | Status: Actief | 15 nov 2024 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [+ Nieuwe diagnose] [AI › Analyseer intake] │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Functionaliteit:**
|
||||
|
||||
**Diagnoselijst:**
|
||||
- Toont alle diagnoses gekoppeld aan deze intake
|
||||
- Hoofddiagnose bovenaan met visuele markering (badge/border)
|
||||
- Per diagnose: code, beschrijving, ernst, status, datum
|
||||
- Optionele notitie ingeklapt, uitklappen via chevron
|
||||
- Acties per kaart: Bewerk, Verwijder
|
||||
|
||||
**Lege staat:**
|
||||
- Tekst: "Nog geen diagnoses geregistreerd."
|
||||
- Prominente [+ Nieuwe diagnose] knop
|
||||
|
||||
**Acties:**
|
||||
- [+ Nieuwe diagnose] → Opent diagnose-invoer modal
|
||||
- [AI › Analyseer intake] → Start AI-analyse, toont suggesties
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Diagnose Invoer Modal
|
||||
|
||||
**Trigger:** Klik op [+ Nieuwe diagnose] of [Bewerk]
|
||||
|
||||
**Schermopbouw:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Nieuwe diagnose [✕] │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ICD-10 Code * │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ 🔍 Zoek op code of beschrijving... │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ Veelgebruikt ─────────────────────────────────────────┐ │
|
||||
│ │ F32.1 Matige depressieve episode │ │
|
||||
│ │ F41.1 Gegeneraliseerde angststoornis │ │
|
||||
│ │ F43.1 Posttraumatische stressstoornis │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Ernst * Diagnose type │
|
||||
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
||||
│ │ Matig ▼ │ │ ○ Hoofddiagnose │ │
|
||||
│ └──────────────────────┘ │ ● Nevendiagnose │ │
|
||||
│ └──────────────────────┘ │
|
||||
│ │
|
||||
│ Status │
|
||||
│ ┌──────────────────────┐ │
|
||||
│ │ Actief ▼ │ │
|
||||
│ └──────────────────────┘ │
|
||||
│ │
|
||||
│ DSM-5 referentie (optioneel) │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ Major Depressive Disorder, moderate │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Onderbouwing / Notities │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ Patiënt presenteert met sombere stemming, verminderde │ │
|
||||
│ │ interesse en slaapproblemen sinds 3 maanden... │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [Annuleren] [Opslaan] │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Velden:**
|
||||
|
||||
| Veld | Type | Verplicht | Opties/Validatie |
|
||||
|------|------|-----------|------------------|
|
||||
| ICD-10 Code | Autocomplete | Ja | Zoeken in ~50 GGZ codes |
|
||||
| Ernst | Dropdown | Ja | Licht, Matig, Ernstig |
|
||||
| Diagnose type | Radio | Ja | Hoofddiagnose, Nevendiagnose |
|
||||
| Status | Dropdown | Ja | Actief, In remissie, Opgelost |
|
||||
| DSM-5 referentie | Text input | Nee | Vrije tekst voor DSM-5 equivalent |
|
||||
| Onderbouwing | Textarea | Nee | Max 500 tekens |
|
||||
|
||||
**Gedrag:**
|
||||
- Bij invoer in zoekveld: live filtering van ICD-10 codelijst
|
||||
- Selectie code: vult automatisch beschrijving in
|
||||
- Bij wijzigen bestaande: velden voorgevuld
|
||||
- Validatie: minimaal code + ernst verplicht
|
||||
- Maximaal 1 hoofddiagnose per intake (toggle andere om bij selectie)
|
||||
|
||||
---
|
||||
|
||||
### 4.3 ICD-10 Code Zoeken (Inline Autocomplete)
|
||||
|
||||
**Trigger:** Focus op code-zoekveld in modal
|
||||
|
||||
**Gedrag:**
|
||||
Voor het prototype gebruiken we een eenvoudige inline autocomplete in plaats van een aparte browser/drawer.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ICD-10 Code * │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ depre │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ F32.0 Lichte depressieve episode │ │
|
||||
│ │ F32.1 Matige depressieve episode ← │ │
|
||||
│ │ F32.2 Ernstige depressieve episode zonder psychose │ │
|
||||
│ │ F32.3 Ernstige depressieve episode met psychose │ │
|
||||
│ │ F33.0 Recidiverende depressie, lichte episode │ │
|
||||
│ │ F33.1 Recidiverende depressie, matige episode │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Functionaliteit:**
|
||||
|
||||
**Zoeken:**
|
||||
- Zoekt op code (F32, F41.1) en beschrijving (depressie, angst)
|
||||
- Client-side filtering van ~50 GGZ codes
|
||||
- Debounce 200ms
|
||||
- Max 8 resultaten in dropdown
|
||||
|
||||
**Snelkeuze (bij leeg veld):**
|
||||
- Toon top 5 veelgebruikte GGZ-diagnoses
|
||||
- Depressie (F32.1), Angst (F41.1), PTSS (F43.1), etc.
|
||||
|
||||
**Selectie:**
|
||||
- Klik of Enter: selecteert code, vult beschrijving in
|
||||
- Escape: sluit dropdown
|
||||
|
||||
---
|
||||
|
||||
### 4.4 AI Diagnose Assistent (Optioneel - Post-MVP)
|
||||
|
||||
> **Prototype scope:** AI-suggesties zijn optioneel voor de eerste versie. Focus eerst op de handmatige invoer-flow. Onderstaande specificatie is voor een latere iteratie.
|
||||
|
||||
**Trigger:** Klik op [AI › Analyseer intake]
|
||||
|
||||
**Schermopbouw (indien geïmplementeerd):**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ AI Diagnose Suggesties [✕] │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ ⚠️ Dit zijn suggesties ter ondersteuning. De clinicus │
|
||||
│ neemt altijd de eindbeslissing. │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─ Suggestie 1 ──────────────────────────────────────────┐ │
|
||||
│ │ F32.1 — Matige depressieve episode │ │
|
||||
│ │ │ │
|
||||
│ │ Onderbouwing: │ │
|
||||
│ │ • "Patiënt meldt al 3 maanden somber te zijn" │ │
|
||||
│ │ • "Verminderde interesse in dagelijkse activiteiten" │ │
|
||||
│ │ │ │
|
||||
│ │ [Overnemen] │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ Suggestie 2 ──────────────────────────────────────────┐ │
|
||||
│ │ F41.1 — Gegeneraliseerde angststoornis │ │
|
||||
│ │ ... │ │
|
||||
│ │ [Overnemen] │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Vereenvoudigde flow voor prototype:**
|
||||
- Input: intake-notities + anamnese
|
||||
- Output: 2-3 ICD-10 suggesties met onderbouwing
|
||||
- Actie: [Overnemen] opent modal met voorgevulde code
|
||||
|
||||
---
|
||||
|
||||
### 4.5 Diagnose Overzicht (Post-MVP)
|
||||
|
||||
> **Prototype scope:** Patiënt-breed diagnose-overzicht is post-MVP. Voor het prototype zijn diagnoses alleen zichtbaar binnen de intake waar ze zijn geregistreerd.
|
||||
|
||||
**Toekomstige locatie:** `/epd/patients/[id]/diagnoses`
|
||||
|
||||
Voor nu volstaat de diagnose-tab binnen de intake.
|
||||
|
||||
---
|
||||
|
||||
### 4.6 Diagnose Detail Card
|
||||
|
||||
**Component voor weergave in lijsten:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ F32.1 — Depressieve stoornis, matig HOOFD [⋮] │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Ernst: Matig Status: Actief 15 nov 2024 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ ▼ Onderbouwing │
|
||||
│ Patiënt voldoet aan 6 van de 9 DSM-5 criteria voor een │
|
||||
│ depressieve episode. Significant functioneel verlies op │
|
||||
│ werk en in sociale relaties. │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Elementen:**
|
||||
- Code + beschrijving (altijd zichtbaar)
|
||||
- Type badge: HOOFD (groen) of geen (nevendiagnose)
|
||||
- Status badge: kleurcodering per status
|
||||
- Ernst, status, datum regel
|
||||
- Onderbouwing: standaard ingeklapt, uitklappen via chevron
|
||||
- Context menu [⋮]: Bewerk, Status wijzigen, Verwijderen
|
||||
|
||||
**Status kleuren:**
|
||||
| Status | Badge kleur |
|
||||
|--------|-------------|
|
||||
| Actief | Groen |
|
||||
| In remissie | Blauw |
|
||||
| Opgelost | Grijs |
|
||||
| Ingevoerd-in-fout | Rood/doorgestreept |
|
||||
|
||||
---
|
||||
|
||||
## 5. UI-overzicht (visuele structuur)
|
||||
|
||||
### Diagnose Tab Layout (Prototype)
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ [← Terug naar intake] Jan de Vries │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ Contacts │ Kindcheck │ Risico │ Anamnese │ Onderzoek │ DIAGNOSE │ Advies │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Diagnoses │
|
||||
│ Registreer diagnoses gekoppeld aan deze intake. │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────────┐ │
|
||||
│ │ [Diagnose Card - Hoofddiagnose] │ │
|
||||
│ └────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────────┐ │
|
||||
│ │ [Diagnose Card - Nevendiagnose] │ │
|
||||
│ └────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [+ Nieuwe diagnose] │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
> **Prototype:** De [AI › Analyseer intake] knop is optioneel en kan in een latere iteratie worden toegevoegd.
|
||||
|
||||
---
|
||||
|
||||
## 6. Interacties met AI (Optioneel - Post-MVP)
|
||||
|
||||
> **Prototype scope:** AI-functionaliteit is optioneel voor de eerste versie. Onderstaande tabel beschrijft de beoogde functionaliteit voor een latere iteratie.
|
||||
|
||||
| Locatie | AI-actie | Trigger | Output |
|
||||
|---------|----------|---------|--------|
|
||||
| Diagnose Tab | Analyseer intake | Klik [AI › Analyseer] | 2-3 ICD-10 suggesties met onderbouwing |
|
||||
|
||||
**Vereenvoudigde flow:**
|
||||
1. Gebruiker klikt [AI › Analyseer intake]
|
||||
2. Systeem analyseert intake-notities + anamnese
|
||||
3. Toont 2-3 ICD-10 suggesties met citaten
|
||||
4. Gebruiker klikt [Overnemen] → opent modal met voorgevulde code
|
||||
|
||||
---
|
||||
|
||||
## 7. Gebruikersrollen en rechten (Prototype)
|
||||
|
||||
| Rol | Toegang | Acties |
|
||||
|-----|---------|--------|
|
||||
| Demo-user | Alle patiënten | Volledig CRUD |
|
||||
|
||||
> **Prototype:** Geen rollen-onderscheid. Alle gebruikers hebben volledige toegang tot demo-data.
|
||||
|
||||
---
|
||||
|
||||
## 8. States en Feedback
|
||||
|
||||
### Lege staten
|
||||
| Context | Weergave |
|
||||
|---------|----------|
|
||||
| Geen diagnoses | "Nog geen diagnoses geregistreerd." + [+ Nieuwe diagnose] |
|
||||
| Geen zoekresultaten | "Geen codes gevonden voor '{query}'" |
|
||||
|
||||
### Succes feedback
|
||||
| Actie | Feedback |
|
||||
|-------|----------|
|
||||
| Diagnose opgeslagen | Toast: "Diagnose opgeslagen" |
|
||||
| Diagnose verwijderd | Toast: "Diagnose verwijderd" |
|
||||
|
||||
### Error feedback
|
||||
| Fout | Weergave |
|
||||
|------|----------|
|
||||
| Opslaan mislukt | Inline error |
|
||||
| Validatiefout | Inline onder veld |
|
||||
|
||||
---
|
||||
|
||||
## 9. Bijlagen & Referenties
|
||||
|
||||
### Gerelateerde documenten
|
||||
- PRD Diagnose Module v1.1 (`docs/specs/diagnose/prd-diagnose-module-v1.md`)
|
||||
- FO Screening & Intake (`docs/specs/screening-intake/fo-screening-intake-v1_0.md`)
|
||||
- UX Stylesheet (`docs/specs/ux-stylesheet.md`)
|
||||
|
||||
### Bestaande implementatie
|
||||
- `app/epd/patients/[id]/intakes/[intakeId]/diagnosis/` — Huidige diagnose-tab
|
||||
- `app/epd/patients/[id]/intakes/[intakeId]/actions.ts` — Server actions
|
||||
- `lib/supabase/database.types.ts` — conditions tabel
|
||||
|
||||
### Component referenties
|
||||
- shadcn/ui: Dialog, Command (voor autocomplete), Badge, Card
|
||||
- Lucide icons: Search, Plus, ChevronDown
|
||||
|
||||
### Externe bronnen
|
||||
- [WHO-FIC Nederland - ICD-10/DSM-5 mapping](https://www.whofic.nl/dsm-5icd-10)
|
||||
- [ICD-10-GM codelijst](https://www.dimdi.de/dynamic/de/klassifikationen/icd/icd-10-gm/) (publiek domein)
|
||||
|
||||
---
|
||||
|
||||
*Document laatst bijgewerkt: 11-12-2024*
|
||||
@@ -1,291 +0,0 @@
|
||||
# 📄 Product Requirements Document (PRD) – Diagnose Module
|
||||
|
||||
**Projectnaam:** Diagnose Module - Mini EPD
|
||||
**Versie:** v1.1
|
||||
**Datum:** 11-12-2024
|
||||
**Auteur:** Colin Lit
|
||||
|
||||
---
|
||||
|
||||
## 1. Doelstelling
|
||||
|
||||
🎯 **Doel:** Een diagnosemodule bouwen voor het prototype die psychologen in staat stelt diagnoses gestructureerd vast te leggen met ICD-10 codes (publiek domein) en DSM-5 referenties.
|
||||
|
||||
📘 **Toelichting:**
|
||||
De huidige diagnose-functionaliteit is minimaal: een simpel formulier met handmatige code-invoer. Deze MVP breidt dit uit naar een werkende module met:
|
||||
- Doorzoekbare **ICD-10 classificatie** (publiek domein, geen licentie nodig)
|
||||
- DSM-5 equivalent als referentieveld (vrije tekst)
|
||||
- Meervoudige diagnoses per intake (hoofd- en nevendiagnoses)
|
||||
- Status tracking (actief, in remissie, opgelost)
|
||||
- AI-ondersteuning voor diagnose-suggesties
|
||||
|
||||
**Type:** Prototype voor demo en validatie.
|
||||
|
||||
> **Licentie-opmerking:** DSM-5 classificaties vallen onder licentie van Boom uitgevers. Voor productie is een licentie vereist. Dit prototype gebruikt ICD-10 (WHO, publiek domein) als primaire classificatie.
|
||||
|
||||
---
|
||||
|
||||
## 2. Doelgroep
|
||||
|
||||
🎯 **Primaire doelgroep:**
|
||||
- **Psychologen / Regiebehandelaren:** Stellen diagnoses en hebben behoefte aan efficiënte classificatie met onderbouwing.
|
||||
- **Psychiaters:** Valideren diagnoses, voegen specialistische classificaties toe.
|
||||
|
||||
📘 **Secundaire doelgroep:**
|
||||
- **Product Owners & Managers:** Demo van AI-potentieel in diagnostisch proces.
|
||||
- **Developers:** Referentie-implementatie voor medische classificatiesystemen.
|
||||
|
||||
**Persona's:**
|
||||
> - **Marieke (GZ-psycholoog):** Wil snel DSM-5 codes kunnen vinden zonder handboek. Wil zien welke diagnoses passen bij de intake-bevindingen.
|
||||
> - **Peter (Psychiater):** Wil comorbiditeit vastleggen met hoofd/nevendiagnose structuur. Heeft behoefte aan differentiaaldiagnostiek.
|
||||
|
||||
---
|
||||
|
||||
## 3. Kernfunctionaliteiten (MVP-scope)
|
||||
|
||||
### 3.1 ICD-10 Classificatie Browser
|
||||
1. **Doorzoekbare codelijst:** Zoeken op code (F32.1) of beschrijving ("depressieve episode").
|
||||
2. **Categorie navigatie:** Hiërarchische structuur (Hoofdgroep → Subgroep → Specifieke diagnose).
|
||||
3. **Snelkeuze:** Veelvoorkomende GGZ-diagnoses (top 30).
|
||||
|
||||
### 3.2 Diagnose Registratie
|
||||
4. **ICD-10 code:** Primaire classificatie (verplicht).
|
||||
5. **DSM-5 referentie:** Optioneel vrije-tekst veld voor DSM-5 equivalent.
|
||||
6. **Meervoudige diagnoses:** Hoofd- en nevendiagnoses (primair/secundair markering).
|
||||
7. **Ernst classificatie:** Licht / Matig / Ernstig.
|
||||
8. **Status tracking:** Actief / In remissie / Opgelost / Ingevoerd-in-fout.
|
||||
9. **Notities veld:** Onderbouwing en klinische redenering.
|
||||
|
||||
### 3.3 AI-ondersteuning
|
||||
10. **Diagnose-suggesties:** Op basis van intake-notities en anamnese (ICD-10 codes).
|
||||
11. **Differentiaal-helper:** Toon vergelijkbare diagnoses met onderscheidende kenmerken.
|
||||
|
||||
### 3.4 Integratie
|
||||
12. **Behandelplan-koppeling:** Diagnoses beschikbaar als input voor behandelplan.
|
||||
13. **Overdracht-integratie:** Actieve diagnoses in overdrachtsamenvatting.
|
||||
|
||||
### *(Stretch / Post-prototype)*
|
||||
- Volledige DSM-5 integratie (na licentie-afsluiting)
|
||||
- Diagnose-overzicht patiënt-breed
|
||||
- Versiebeheer diagnoses
|
||||
|
||||
---
|
||||
|
||||
## 4. Gebruikersflows (MVP-flows)
|
||||
|
||||
### Flow 1: Diagnose toevoegen via zoeken
|
||||
```
|
||||
1. Psycholoog opent Diagnose tab binnen intake
|
||||
2. Klikt [+ Nieuwe diagnose]
|
||||
3. Zoekt op "depressie" of "F32"
|
||||
4. Selecteert "F32.1 - Depressieve stoornis, matig"
|
||||
5. Vult ernst in (dropdown: matig)
|
||||
6. Markeert als hoofddiagnose (toggle)
|
||||
7. Voegt optionele notitie toe
|
||||
8. Klikt [Opslaan]
|
||||
```
|
||||
|
||||
### Flow 2: AI-suggestie gebruiken
|
||||
```
|
||||
1. Psycholoog opent Diagnose tab
|
||||
2. Klikt [AI › Analyseer intake]
|
||||
3. Systeem analyseert intake-notities + anamnese
|
||||
4. Toont 2-4 diagnose-suggesties met confidence score
|
||||
5. Per suggestie: onderbouwing uit intake-tekst (citaten)
|
||||
6. Psycholoog selecteert relevante suggestie(s)
|
||||
7. Past aan indien nodig → [Opslaan]
|
||||
```
|
||||
|
||||
### Flow 3: Differentiaaldiagnose bekijken
|
||||
```
|
||||
1. Bij geselecteerde diagnose (bijv. F41.1 GAD)
|
||||
2. Klikt [Differentiaal bekijken]
|
||||
3. Toont gerelateerde diagnoses:
|
||||
- F41.0 Paniekstoornis
|
||||
- F43.1 PTSS
|
||||
- F32.1 Depressie met angstkenmerken
|
||||
4. Per alternatief: kernverschillen uitgelicht
|
||||
5. Psycholoog bevestigt of past diagnose aan
|
||||
```
|
||||
|
||||
### Flow 4: Diagnose-overzicht raadplegen
|
||||
```
|
||||
1. Psycholoog opent Patiënt dossier
|
||||
2. Navigeert naar Diagnoses sectie (L2 menu)
|
||||
3. Ziet overzicht alle diagnoses (actief + historisch)
|
||||
4. Filter op status: Actief / In remissie / Alle
|
||||
5. Klik op diagnose → details + gekoppelde intake
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Niet in Scope (Prototype)
|
||||
|
||||
| Feature | Reden |
|
||||
|---------|-------|
|
||||
| Volledige DSM-5 classificatie | Licentie vereist (Boom uitgevers) |
|
||||
| DSM-5 criteria/checklists | Licentiegebonden content |
|
||||
| Multi-disciplinaire validatie workflow | Complexiteit, geen meerwaarde voor demo |
|
||||
| Automatische DBC/ZPM-koppeling | Vereist externe integraties |
|
||||
| Medicatie-diagnose interacties | Buiten scope |
|
||||
| ICD-11 ondersteuning | Nog niet gangbaar in NL GGZ |
|
||||
|
||||
---
|
||||
|
||||
## 6. Succescriteria
|
||||
|
||||
| Criterium | Meetbaar doel |
|
||||
|-----------|---------------|
|
||||
| Code-zoekfunctie | < 3 klikken van zoeken naar selectie |
|
||||
| AI-suggesties | Relevante suggestie in top-3 bij 80% van intakes |
|
||||
| Differentiaal | Toon minimaal 2 relevante alternatieven |
|
||||
| Demo-flow | Volledige diagnose-registratie in < 60 seconden |
|
||||
| Data-integriteit | Diagnoses correct gekoppeld aan intake + patiënt |
|
||||
| Overdracht | Actieve diagnoses automatisch in AI-samenvatting |
|
||||
|
||||
---
|
||||
|
||||
## 7. Risico's & Mitigatie
|
||||
|
||||
| Risico | Impact | Mitigatie |
|
||||
|--------|--------|-----------|
|
||||
| AI-suggesties onjuist/onvolledig | Hoog | Duidelijke disclaimer, suggesties als hulpmiddel niet als diagnose |
|
||||
| ICD-10 minder bekend bij GGZ | Laag | Codes zijn identiek aan DSM-5, alleen beschrijvingen verschillen |
|
||||
| Complexe classificatie UI | Middel | Focus op top 30 GGZ-diagnoses, rest via zoeken |
|
||||
| Performance bij grote codelijst | Laag | Client-side filtering + debounce |
|
||||
|
||||
---
|
||||
|
||||
## 8. Roadmap / Vervolg (Post-Prototype)
|
||||
|
||||
### Fase 2: DSM-5 Licentie
|
||||
- Licentie afsluiten met Boom uitgevers
|
||||
- DSM-5 beschrijvingen en criteria toevoegen
|
||||
- Volledige DSM-5/ICD-10 mapping
|
||||
|
||||
### Fase 3: Verdieping
|
||||
- Diagnose-overzicht patiënt-breed (over intakes)
|
||||
- Versiebeheer diagnoses (audittrail)
|
||||
- Comorbiditeit-visualisatie
|
||||
|
||||
### Fase 4: Compliance
|
||||
- DBC/ZPM declaratie-integratie
|
||||
- NEN 7510 logging
|
||||
- Multi-disciplinaire validatie workflow (MDO)
|
||||
|
||||
---
|
||||
|
||||
## 9. Bijlagen & Referenties
|
||||
|
||||
### Bestaande documentatie
|
||||
- FO Screening & Intake v1.0 (`docs/specs/screening-intake/fo-screening-intake-v1_0.md`)
|
||||
- TO Mini EPD v1.2 (`docs/specs/to-mini-ecd-v1_2.md`)
|
||||
- UX Stylesheet (`docs/specs/ux-stylesheet.md`)
|
||||
- PRD AI Prefill Behandelplan (`docs/specs/ai-integratie/prd-ai-prefill-behandelplan-v1.md`)
|
||||
|
||||
### Bestaande implementatie
|
||||
- `app/epd/patients/[id]/intakes/[intakeId]/diagnosis/` - Huidige diagnose-tab
|
||||
- `lib/supabase/database.types.ts` - `conditions` tabel definitie
|
||||
- `app/epd/patients/[id]/intakes/[intakeId]/actions.ts` - CRUD operaties
|
||||
|
||||
### Externe referenties
|
||||
- [WHO-FIC Nederland - ICD-10/DSM-5 mapping](https://www.whofic.nl/dsm-5icd-10)
|
||||
- [Zorgprestatiemodel - DSM-5 codelijst](https://www.zorgprestatiemodel.nl/aan-de-slag/downloads/)
|
||||
- [ICD-10-GM codelijst](https://www.dimdi.de/dynamic/de/klassifikationen/icd/icd-10-gm/) (publiek domein)
|
||||
- FHIR Condition Resource (R4)
|
||||
|
||||
---
|
||||
|
||||
## 10. Technische Uitgangspunten
|
||||
|
||||
### Database (bestaande `conditions` tabel)
|
||||
```typescript
|
||||
// Huidige velden (FHIR-inspired)
|
||||
- code_code: string // ICD-10 code (bijv. "F32.1")
|
||||
- code_display: string // ICD-10 beschrijving
|
||||
- code_system: string // 'ICD-10' (primair voor prototype)
|
||||
- clinical_status: enum // active | remission | resolved
|
||||
- verification_status: enum // provisional | confirmed | entered-in-error
|
||||
- severity_code: string
|
||||
- severity_display: string
|
||||
- onset_datetime: timestamp
|
||||
- recorded_date: timestamp
|
||||
- note: text
|
||||
- patient_id: uuid
|
||||
- encounter_id: uuid // Gekoppelde intake
|
||||
```
|
||||
|
||||
### Nieuwe velden (Prototype)
|
||||
```typescript
|
||||
- is_primary: boolean // Hoofd- vs nevendiagnose
|
||||
- dsm5_reference: text // Optioneel: DSM-5 equivalent (vrije tekst)
|
||||
```
|
||||
|
||||
### Statische data (JSON)
|
||||
```typescript
|
||||
// lib/data/icd10-ggz-codes.json
|
||||
// Top ~50 GGZ-relevante ICD-10 codes met Nederlandse beschrijvingen
|
||||
[
|
||||
{ "code": "F32.0", "display": "Lichte depressieve episode", "category": "Depressie" },
|
||||
{ "code": "F32.1", "display": "Matige depressieve episode", "category": "Depressie" },
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
### API Endpoints
|
||||
```
|
||||
GET /api/diagnose/codes?q={search} // Zoek ICD-10 codes (client-side fallback)
|
||||
POST /api/diagnose/suggest // AI suggesties (optioneel)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. ICD-10 GGZ Code Subset (Prototype)
|
||||
|
||||
Focus op meest voorkomende GGZ-diagnoses (~50 codes). De ICD-10 codes zijn identiek aan DSM-5, alleen de beschrijvingen komen uit de WHO-classificatie (publiek domein).
|
||||
|
||||
| Categorie | ICD-10 Codes | Voorbeelden |
|
||||
|-----------|--------------|-------------|
|
||||
| **Depressieve stoornissen** | F32.x, F33.x | Depressieve episode (licht/matig/ernstig) |
|
||||
| **Angststoornissen** | F40.x, F41.x | Sociale fobie, GAD, Paniekstoornis |
|
||||
| **Trauma/stress** | F43.x | PTSS, Aanpassingsstoornis |
|
||||
| **OCD** | F42.x | Obsessief-compulsieve stoornis |
|
||||
| **Persoonlijkheid** | F60.x | Borderline, Antisociaal, Vermijdend |
|
||||
| **Bipolair** | F31.x | Bipolaire stoornis |
|
||||
| **ADHD** | F90.x | Aandachtstekortstoornis |
|
||||
| **Autisme** | F84.x | Autismespectrumstoornis |
|
||||
| **Eetstoornissen** | F50.x | Anorexia, Boulimia |
|
||||
|
||||
> **Opmerking:** Voor productie kunnen de volledige DSM-5 beschrijvingen worden toegevoegd na licentie-afsluiting.
|
||||
|
||||
---
|
||||
|
||||
## 12. AI Prompt Strategie (Optioneel)
|
||||
|
||||
### Diagnose-suggestie prompt
|
||||
```
|
||||
Je bent een klinisch ondersteuningssysteem voor GGZ-professionals.
|
||||
|
||||
CONTEXT:
|
||||
- Intake notities: {intakeContent}
|
||||
- Anamnese: {anamneseContent}
|
||||
|
||||
OPDRACHT:
|
||||
Analyseer de informatie en geef maximaal 3 diagnose-suggesties met ICD-10 codes.
|
||||
|
||||
Per suggestie:
|
||||
1. ICD-10 code en beschrijving
|
||||
2. Onderbouwing met citaten uit de intake
|
||||
3. Ernst-indicatie (licht/matig/ernstig)
|
||||
|
||||
BELANGRIJK:
|
||||
- Dit zijn SUGGESTIES ter ondersteuning, geen diagnoses
|
||||
- De clinicus neemt altijd de eindbeslissing
|
||||
- Gebruik alleen ICD-10 codes uit de GGZ-subset (F-codes)
|
||||
```
|
||||
|
||||
> **Prototype scope:** AI-suggesties zijn optioneel voor de eerste versie. Focus eerst op de handmatige invoer-flow.
|
||||
|
||||
---
|
||||
|
||||
*Document laatst bijgewerkt: 11-12-2024*
|
||||
@@ -1,467 +0,0 @@
|
||||
# ⚙️ Technisch Ontwerp (TO) – Diagnose Module
|
||||
|
||||
**Projectnaam:** Diagnose Module - Mini EPD
|
||||
**Versie:** v1.0
|
||||
**Datum:** 11-12-2024
|
||||
**Auteur:** Colin Lit
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en relatie met PRD en FO
|
||||
|
||||
🎯 **Doel van dit document:**
|
||||
Het Technisch Ontwerp beschrijft **hoe** de diagnosemodule technisch wordt geïmplementeerd. Dit document vertaalt het FO naar concrete code-structuren, database-wijzigingen en componenten.
|
||||
|
||||
📘 **Toelichting:**
|
||||
De diagnosemodule bouwt voort op de bestaande `conditions` tabel (FHIR-inspired) en breidt de huidige basic UI uit met een doorzoekbare ICD-10 codelijst en verbeterde UX.
|
||||
|
||||
**Relatie met documenten:**
|
||||
- PRD: `docs/specs/diagnose/prd-diagnose-module-v1.md` (v1.1)
|
||||
- FO: `docs/specs/diagnose/fo-diagnose-module-v1.md` (v1.1)
|
||||
|
||||
---
|
||||
|
||||
## 2. Technische Architectuur Overzicht
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Frontend (Next.js) │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
|
||||
│ │ DiagnosisTab │───▶│ DiagnosisModal │───▶│ ICD10Search │ │
|
||||
│ │ (page.tsx) │ │ (Dialog) │ │ (Combobox) │ │
|
||||
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ Server Actions (actions.ts) │ │
|
||||
│ │ • createDiagnosis() • updateDiagnosis() • deleteDiagnosis() │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
└──────────────────────────────┼──────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Supabase (PostgreSQL) │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
|
||||
│ │ patients │◀──▶│ conditions │◀──▶│ intakes │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Statische Data (JSON) │
|
||||
│ │
|
||||
│ lib/data/icd10-ggz-codes.json (~50 codes, client-side) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Dependency Analyse
|
||||
|
||||
### Bestaande dependencies (reeds aanwezig)
|
||||
|
||||
| Dependency | Versie | Gebruik |
|
||||
|------------|--------|---------|
|
||||
| `@radix-ui/react-dialog` | ^1.1.15 | Modal voor diagnose invoer |
|
||||
| `@radix-ui/react-select` | ^2.2.6 | Dropdowns (ernst, status) |
|
||||
| `lucide-react` | ^0.553.0 | Icons (Search, Plus, Trash) |
|
||||
| `date-fns` | ^4.1.0 | Datum formatting |
|
||||
| `zod` | ^4.1.12 | Input validatie |
|
||||
| `react-hook-form` | ^7.66.1 | Form handling |
|
||||
| `@hookform/resolvers` | ^5.2.2 | Zod resolver |
|
||||
|
||||
### Nieuwe dependency (toe te voegen)
|
||||
|
||||
| Dependency | Versie | Gebruik | Alternatief |
|
||||
|------------|--------|---------|-------------|
|
||||
| `cmdk` | ^1.0.0 | Autocomplete/Combobox voor ICD-10 zoeken | Custom met Radix Popover |
|
||||
|
||||
**Aanbeveling:** Voeg `cmdk` toe voor de autocomplete functionaliteit. Dit is de standaard voor shadcn/ui Command component.
|
||||
|
||||
```bash
|
||||
pnpm add cmdk
|
||||
```
|
||||
|
||||
**Alternatief:** Bouw custom autocomplete met bestaande `@radix-ui/react-popover` + input. Minder features maar geen extra dependency.
|
||||
|
||||
---
|
||||
|
||||
## 4. Database Schema
|
||||
|
||||
### Bestaande `conditions` tabel (geen wijzigingen nodig)
|
||||
|
||||
De huidige `conditions` tabel is al FHIR-compliant en bevat alle benodigde velden:
|
||||
|
||||
```sql
|
||||
-- Bestaande tabel (lib/supabase/database.types.ts:291-369)
|
||||
conditions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
patient_id UUID NOT NULL REFERENCES patients(id),
|
||||
encounter_id UUID REFERENCES intakes(id), -- Gekoppelde intake
|
||||
|
||||
-- ICD-10/DSM-5 classificatie
|
||||
code_code TEXT NOT NULL, -- "F32.1"
|
||||
code_display TEXT NOT NULL, -- "Matige depressieve episode"
|
||||
code_system TEXT DEFAULT 'ICD-10', -- "ICD-10" of "DSM-5"
|
||||
|
||||
-- Status (FHIR enums)
|
||||
clinical_status condition_clinical_status DEFAULT 'active',
|
||||
-- active | recurrence | relapse | inactive | remission | resolved
|
||||
verification_status condition_verification_status DEFAULT 'confirmed',
|
||||
-- unconfirmed | provisional | differential | confirmed | refuted | entered-in-error
|
||||
|
||||
-- Ernst
|
||||
severity_code TEXT, -- "mild" | "moderate" | "severe"
|
||||
severity_display TEXT, -- "Licht" | "Matig" | "Ernstig"
|
||||
|
||||
-- Timing
|
||||
onset_datetime TIMESTAMPTZ,
|
||||
recorded_date DATE DEFAULT CURRENT_DATE,
|
||||
|
||||
-- Extra
|
||||
note TEXT, -- Onderbouwing
|
||||
category TEXT DEFAULT 'encounter-diagnosis',
|
||||
|
||||
-- Metadata
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
### Optionele schema-uitbreiding (later)
|
||||
|
||||
Voor de toekomst kunnen deze velden worden toegevoegd via migratie:
|
||||
|
||||
```sql
|
||||
-- Optioneel: nieuwe velden voor uitgebreide functionaliteit
|
||||
ALTER TABLE conditions ADD COLUMN IF NOT EXISTS is_primary BOOLEAN DEFAULT false;
|
||||
ALTER TABLE conditions ADD COLUMN IF NOT EXISTS dsm5_reference TEXT;
|
||||
```
|
||||
|
||||
**Besluit:** Voor het prototype gebruiken we de bestaande velden. `is_primary` kan worden afgeleid uit volgorde of in `note` worden vastgelegd.
|
||||
|
||||
---
|
||||
|
||||
## 5. Statische ICD-10 Data
|
||||
|
||||
### Bestandslocatie
|
||||
|
||||
```
|
||||
lib/data/icd10-ggz-codes.json
|
||||
```
|
||||
|
||||
### Data structuur
|
||||
|
||||
```typescript
|
||||
// lib/types/icd10.ts
|
||||
export interface ICD10Code {
|
||||
code: string; // "F32.1"
|
||||
display: string; // "Matige depressieve episode"
|
||||
category: string; // "Depressie"
|
||||
keywords?: string[]; // ["depressief", "somber", "neerslachtig"]
|
||||
}
|
||||
|
||||
export interface ICD10Category {
|
||||
name: string;
|
||||
codes: ICD10Code[];
|
||||
}
|
||||
```
|
||||
|
||||
### Voorbeeld data (~50 codes)
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "ICD-10-GM 2024",
|
||||
"source": "WHO (publiek domein)",
|
||||
"categories": [
|
||||
{
|
||||
"name": "Depressieve stoornissen",
|
||||
"codes": [
|
||||
{ "code": "F32.0", "display": "Lichte depressieve episode", "keywords": ["depressie", "licht"] },
|
||||
{ "code": "F32.1", "display": "Matige depressieve episode", "keywords": ["depressie", "matig"] },
|
||||
{ "code": "F32.2", "display": "Ernstige depressieve episode zonder psychotische kenmerken", "keywords": ["depressie", "ernstig"] },
|
||||
{ "code": "F32.3", "display": "Ernstige depressieve episode met psychotische kenmerken", "keywords": ["depressie", "psychose"] },
|
||||
{ "code": "F33.0", "display": "Recidiverende depressieve stoornis, huidige episode licht", "keywords": ["recidiverend"] },
|
||||
{ "code": "F33.1", "display": "Recidiverende depressieve stoornis, huidige episode matig", "keywords": ["recidiverend"] },
|
||||
{ "code": "F33.2", "display": "Recidiverende depressieve stoornis, huidige episode ernstig", "keywords": ["recidiverend"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Angststoornissen",
|
||||
"codes": [
|
||||
{ "code": "F40.0", "display": "Agorafobie", "keywords": ["angst", "plein", "open ruimte"] },
|
||||
{ "code": "F40.1", "display": "Sociale fobie", "keywords": ["sociaal", "angst", "vermijding"] },
|
||||
{ "code": "F40.2", "display": "Specifieke fobie", "keywords": ["fobie", "specifiek"] },
|
||||
{ "code": "F41.0", "display": "Paniekstoornis", "keywords": ["paniek", "aanval"] },
|
||||
{ "code": "F41.1", "display": "Gegeneraliseerde angststoornis", "keywords": ["gad", "piekeren", "angst"] },
|
||||
{ "code": "F41.2", "display": "Gemengde angststoornis en depressieve stoornis", "keywords": ["gemengd"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Trauma- en stressorgerelateerde stoornissen",
|
||||
"codes": [
|
||||
{ "code": "F43.0", "display": "Acute stressreactie", "keywords": ["stress", "acuut"] },
|
||||
{ "code": "F43.1", "display": "Posttraumatische stressstoornis", "keywords": ["ptss", "trauma"] },
|
||||
{ "code": "F43.2", "display": "Aanpassingsstoornis", "keywords": ["aanpassing", "stress"] }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Component Structuur
|
||||
|
||||
### Bestandsstructuur
|
||||
|
||||
```
|
||||
app/epd/patients/[id]/intakes/[intakeId]/diagnosis/
|
||||
├── page.tsx # Server component (bestaand)
|
||||
└── components/
|
||||
├── diagnosis-manager.tsx # Refactor: lijst + modal trigger
|
||||
├── diagnosis-card.tsx # Nieuwe: diagnose weergave card
|
||||
├── diagnosis-modal.tsx # Nieuwe: invoer/bewerk modal
|
||||
└── icd10-combobox.tsx # Nieuwe: autocomplete zoeken
|
||||
|
||||
lib/data/
|
||||
└── icd10-ggz-codes.json # Statische codelijst
|
||||
|
||||
lib/types/
|
||||
└── icd10.ts # TypeScript types
|
||||
```
|
||||
|
||||
### Component specificaties
|
||||
|
||||
#### 1. `DiagnosisModal` (nieuw)
|
||||
|
||||
```typescript
|
||||
// components/diagnosis-modal.tsx
|
||||
interface DiagnosisModalProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
patientId: string;
|
||||
intakeId: string;
|
||||
diagnosis?: Condition; // undefined = nieuw, anders = bewerk
|
||||
}
|
||||
|
||||
// Features:
|
||||
// - Dialog wrapper (Radix)
|
||||
// - Form met react-hook-form + zod
|
||||
// - ICD10Combobox voor code selectie
|
||||
// - Dropdowns voor ernst/status
|
||||
// - Textarea voor onderbouwing
|
||||
```
|
||||
|
||||
#### 2. `ICD10Combobox` (nieuw)
|
||||
|
||||
```typescript
|
||||
// components/icd10-combobox.tsx
|
||||
interface ICD10ComboboxProps {
|
||||
value: string;
|
||||
onSelect: (code: ICD10Code) => void;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
// Features:
|
||||
// - cmdk Command component
|
||||
// - Client-side filtering op code + display + keywords
|
||||
// - Debounce 200ms
|
||||
// - Max 8 resultaten
|
||||
// - Snelkeuze bij leeg veld (top 5)
|
||||
```
|
||||
|
||||
#### 3. `DiagnosisCard` (nieuw)
|
||||
|
||||
```typescript
|
||||
// components/diagnosis-card.tsx
|
||||
interface DiagnosisCardProps {
|
||||
diagnosis: Condition;
|
||||
isPrimary?: boolean;
|
||||
onEdit: () => void;
|
||||
onDelete: () => void;
|
||||
}
|
||||
|
||||
// Features:
|
||||
// - Code + beschrijving
|
||||
// - Ernst + status badges
|
||||
// - Datum
|
||||
// - Expand/collapse voor onderbouwing
|
||||
// - Context menu (bewerk, verwijder)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Server Actions Refactor
|
||||
|
||||
### Huidige actions (aanpassen)
|
||||
|
||||
```typescript
|
||||
// app/epd/patients/[id]/intakes/[intakeId]/actions.ts
|
||||
|
||||
// Bestaand - werkt, kleine aanpassing code_system
|
||||
export async function createDiagnosis(payload: DiagnosisPayload) {
|
||||
const supabase = await getSupabase();
|
||||
const { error } = await supabase.from('conditions').insert({
|
||||
patient_id: payload.patientId,
|
||||
encounter_id: payload.intakeId,
|
||||
code_code: payload.code,
|
||||
code_display: payload.description,
|
||||
code_system: 'ICD-10', // Wijzig van 'DSM-5' naar 'ICD-10'
|
||||
clinical_status: payload.status || 'active',
|
||||
severity_display: payload.severity || null,
|
||||
note: payload.notes,
|
||||
recorded_date: new Date().toISOString(),
|
||||
});
|
||||
// ...
|
||||
}
|
||||
|
||||
// Nieuw - update functie
|
||||
export async function updateDiagnosis(
|
||||
diagnosisId: string,
|
||||
payload: Partial<DiagnosisPayload>
|
||||
) {
|
||||
const supabase = await getSupabase();
|
||||
const { error } = await supabase
|
||||
.from('conditions')
|
||||
.update({
|
||||
code_code: payload.code,
|
||||
code_display: payload.description,
|
||||
clinical_status: payload.status,
|
||||
severity_display: payload.severity,
|
||||
note: payload.notes,
|
||||
updated_at: new Date().toISOString(),
|
||||
})
|
||||
.eq('id', diagnosisId);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Uitgebreide payload type
|
||||
|
||||
```typescript
|
||||
export interface DiagnosisPayload {
|
||||
patientId: string;
|
||||
intakeId: string;
|
||||
code: string;
|
||||
description: string;
|
||||
severity?: 'licht' | 'matig' | 'ernstig';
|
||||
status?: 'active' | 'remission' | 'resolved' | 'entered-in-error';
|
||||
notes?: string;
|
||||
dsm5Reference?: string; // Optioneel vrije tekst veld
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Zod Validatie Schema
|
||||
|
||||
```typescript
|
||||
// lib/schemas/diagnosis.ts
|
||||
import { z } from 'zod';
|
||||
|
||||
export const diagnosisSchema = z.object({
|
||||
code: z.string()
|
||||
.min(1, 'ICD-10 code is verplicht')
|
||||
.regex(/^F\d{2}(\.\d{1,2})?$/, 'Ongeldige ICD-10 code'),
|
||||
description: z.string()
|
||||
.min(1, 'Beschrijving is verplicht')
|
||||
.max(200, 'Beschrijving mag maximaal 200 tekens zijn'),
|
||||
severity: z.enum(['licht', 'matig', 'ernstig']),
|
||||
status: z.enum(['active', 'remission', 'resolved', 'entered-in-error'])
|
||||
.default('active'),
|
||||
notes: z.string()
|
||||
.max(500, 'Onderbouwing mag maximaal 500 tekens zijn')
|
||||
.optional(),
|
||||
dsm5Reference: z.string()
|
||||
.max(100, 'DSM-5 referentie mag maximaal 100 tekens zijn')
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export type DiagnosisFormData = z.infer<typeof diagnosisSchema>;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Implementatie Stappenplan
|
||||
|
||||
### Fase 1: Data & Types (1-2 uur)
|
||||
1. Creëer `lib/data/icd10-ggz-codes.json` met ~50 codes
|
||||
2. Creëer `lib/types/icd10.ts` met TypeScript types
|
||||
3. Creëer `lib/schemas/diagnosis.ts` met Zod schema
|
||||
|
||||
### Fase 2: Componenten (3-4 uur)
|
||||
4. Installeer `cmdk` dependency
|
||||
5. Creëer `ICD10Combobox` component
|
||||
6. Creëer `DiagnosisModal` component
|
||||
7. Creëer `DiagnosisCard` component
|
||||
|
||||
### Fase 3: Integratie (2 uur)
|
||||
8. Refactor `diagnosis-manager.tsx` naar nieuwe componenten
|
||||
9. Update server actions (ICD-10, update functie)
|
||||
10. Test flows: toevoegen, bewerken, verwijderen
|
||||
|
||||
### Fase 4: Polish (1 uur)
|
||||
11. Lege staten en error handling
|
||||
12. Loading states
|
||||
13. Toast feedback
|
||||
|
||||
---
|
||||
|
||||
## 10. Testen
|
||||
|
||||
### Handmatige test scenario's
|
||||
|
||||
| # | Scenario | Verwacht resultaat |
|
||||
|---|----------|-------------------|
|
||||
| 1 | Zoek "depressie" | Toont F32.x codes |
|
||||
| 2 | Zoek "F41" | Toont angststoornissen |
|
||||
| 3 | Selecteer code | Vult beschrijving automatisch |
|
||||
| 4 | Opslaan zonder code | Validatiefout |
|
||||
| 5 | Bewerk bestaande | Modal met voorgevulde waarden |
|
||||
| 6 | Verwijder diagnose | Bevestiging + toast |
|
||||
| 7 | Leeg veld | Toont top 5 snelkeuze |
|
||||
|
||||
### Build verificatie
|
||||
|
||||
```bash
|
||||
pnpm build # Moet slagen zonder type errors
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Risico's & Mitigatie
|
||||
|
||||
| Risico | Impact | Mitigatie |
|
||||
|--------|--------|-----------|
|
||||
| cmdk bundle size | Laag | ~10KB gzipped, acceptabel |
|
||||
| ICD-10 codes incompleet | Laag | Start met 50, uitbreiden op aanvraag |
|
||||
| Performance filtering | Laag | 50 codes is instant client-side |
|
||||
| Bestaande data breekt | Middel | Backward compatible, DSM-5 data blijft werken |
|
||||
|
||||
---
|
||||
|
||||
## 12. Bijlagen & Referenties
|
||||
|
||||
### Projectdocumenten
|
||||
- PRD: `docs/specs/diagnose/prd-diagnose-module-v1.md`
|
||||
- FO: `docs/specs/diagnose/fo-diagnose-module-v1.md`
|
||||
|
||||
### Bestaande code
|
||||
- `app/epd/patients/[id]/intakes/[intakeId]/diagnosis/` — Huidige implementatie
|
||||
- `app/epd/patients/[id]/intakes/[intakeId]/actions.ts` — Server actions
|
||||
- `lib/supabase/database.types.ts` — Database types
|
||||
|
||||
### Externe referenties
|
||||
- [cmdk documentation](https://cmdk.paco.me/)
|
||||
- [shadcn/ui Command](https://ui.shadcn.com/docs/components/command)
|
||||
- [ICD-10-GM 2024](https://www.dimdi.de/dynamic/de/klassifikationen/icd/icd-10-gm/)
|
||||
|
||||
---
|
||||
|
||||
*Document laatst bijgewerkt: 11-12-2024*
|
||||
@@ -1,195 +0,0 @@
|
||||
# Diagnose Module - Implementatieplan
|
||||
|
||||
## Overzicht
|
||||
Implementatie van een verbeterde diagnosemodule voor het Mini-EPD prototype met:
|
||||
- ICD-10 classificatie (publiek domein, geen licentie nodig)
|
||||
- Autocomplete zoekfunctionaliteit
|
||||
- Consistente UX/UI volgens bestaande EPD patterns
|
||||
|
||||
## Documentatie Status ✅
|
||||
- [x] PRD v1.1 - `docs/specs/diagnose/prd-diagnose-module-v1.md`
|
||||
- [x] FO v1.1 - `docs/specs/diagnose/fo-diagnose-module-v1.md`
|
||||
- [x] TO v1.0 - `docs/specs/diagnose/to-diagnose-module-v1.md`
|
||||
- [x] UX/UI Specificaties (zie hieronder)
|
||||
|
||||
---
|
||||
|
||||
## UX/UI Design Beslissingen
|
||||
|
||||
### Kleurenschema (conform ux-stylesheet.md)
|
||||
| Element | Kleur | Hex |
|
||||
|---------|-------|-----|
|
||||
| Primary action (knoppen) | Teal | `#0D9488` (teal-600) |
|
||||
| Borders | Slate | `#E2E8F0` (slate-200) |
|
||||
| Text primary | Slate | `#0F172A` (slate-900) |
|
||||
| Text secondary | Slate | `#64748B` (slate-500) |
|
||||
| Error | Red | `#DC2626` |
|
||||
| Success toast | Green | `#16A34A` |
|
||||
|
||||
### Badge Kleuren (Ernst/Status)
|
||||
| Type | Achtergrond | Tekst |
|
||||
|------|-------------|-------|
|
||||
| Ernst: Licht | `#E5E7EB` | `#374151` |
|
||||
| Ernst: Matig | `#FEF3C7` | `#92400E` |
|
||||
| Ernst: Ernstig | `#FEE2E2` | `#991B1B` |
|
||||
| Status: Actief | `#ECFDF5` | `#16A34A` |
|
||||
| Status: In remissie | `#EFF6FF` | `#3B82F6` |
|
||||
| Status: Opgelost | `#F1F5F9` | `#64748B` |
|
||||
| HOOFD badge | `#0D9488` | `#FFFFFF` |
|
||||
|
||||
### Component Patterns (hergebruik bestaande)
|
||||
- **Card layout**: Zoals `anamnese-manager.tsx` en `risk-manager.tsx`
|
||||
- **Modal/Dialog**: Zoals `appointment-modal.tsx`
|
||||
- **Form styling**: Bestaande input/select classes
|
||||
- **Empty state**: Zoals `intake-list.tsx`
|
||||
|
||||
---
|
||||
|
||||
## Implementatie Stappenplan
|
||||
|
||||
### Epic 1: Data & Types (~1 uur)
|
||||
|
||||
**Story 1.1: ICD-10 Codelijst JSON**
|
||||
```
|
||||
lib/data/icd10-ggz-codes.json
|
||||
```
|
||||
- ~50 meest voorkomende GGZ codes
|
||||
- Categorieën: Depressie, Angst, Trauma, OCD, Persoonlijkheid, etc.
|
||||
- Velden: code, display, category, keywords
|
||||
|
||||
**Story 1.2: TypeScript Types**
|
||||
```
|
||||
lib/types/icd10.ts
|
||||
```
|
||||
- ICD10Code interface
|
||||
- ICD10Category interface
|
||||
|
||||
**Story 1.3: Zod Validatie Schema**
|
||||
```
|
||||
lib/schemas/diagnosis.ts
|
||||
```
|
||||
- diagnosisSchema met code, severity, status validatie
|
||||
|
||||
---
|
||||
|
||||
### Epic 2: UI Componenten (~3-4 uur)
|
||||
|
||||
**Story 2.1: Installeer cmdk**
|
||||
```bash
|
||||
pnpm add cmdk
|
||||
```
|
||||
|
||||
**Story 2.2: ICD10Combobox Component**
|
||||
```
|
||||
app/epd/patients/[id]/intakes/[intakeId]/diagnosis/components/icd10-combobox.tsx
|
||||
```
|
||||
- Autocomplete met cmdk
|
||||
- Client-side filtering
|
||||
- Snelkeuze bij leeg veld
|
||||
- Keyboard navigatie
|
||||
|
||||
**Story 2.3: DiagnosisCard Component**
|
||||
```
|
||||
app/epd/patients/[id]/intakes/[intakeId]/diagnosis/components/diagnosis-card.tsx
|
||||
```
|
||||
- Code + beschrijving header
|
||||
- Ernst/Status/Datum badges
|
||||
- HOOFD badge voor hoofddiagnose
|
||||
- Expandable onderbouwing
|
||||
- Bewerk/Verwijder acties
|
||||
|
||||
**Story 2.4: DiagnosisModal Component**
|
||||
```
|
||||
app/epd/patients/[id]/intakes/[intakeId]/diagnosis/components/diagnosis-modal.tsx
|
||||
```
|
||||
- Dialog wrapper
|
||||
- ICD10Combobox integratie
|
||||
- Ernst dropdown (Licht/Matig/Ernstig)
|
||||
- Status dropdown (Actief/In remissie/Opgelost)
|
||||
- Type radio (Hoofd/Nevendiagnose)
|
||||
- DSM-5 referentie tekstveld (optioneel)
|
||||
- Onderbouwing textarea
|
||||
- Validatie met zod
|
||||
|
||||
---
|
||||
|
||||
### Epic 3: Integratie (~2 uur)
|
||||
|
||||
**Story 3.1: Refactor DiagnosisManager**
|
||||
```
|
||||
app/epd/patients/[id]/intakes/[intakeId]/diagnosis/components/diagnosis-manager.tsx
|
||||
```
|
||||
- Vervang inline form door modal trigger
|
||||
- Integreer DiagnosisCard voor lijst
|
||||
- Lege staat met dashed border
|
||||
- + Nieuwe diagnose knop
|
||||
|
||||
**Story 3.2: Update Server Actions**
|
||||
```
|
||||
app/epd/patients/[id]/intakes/[intakeId]/actions.ts
|
||||
```
|
||||
- Wijzig code_system naar 'ICD-10'
|
||||
- Voeg updateDiagnosis() functie toe
|
||||
- Uitbreid DiagnosisPayload type
|
||||
|
||||
**Story 3.3: Toast Integratie**
|
||||
- Succes toast bij opslaan
|
||||
- Succes toast bij verwijderen
|
||||
- Error handling
|
||||
|
||||
---
|
||||
|
||||
### Epic 4: Polish (~1 uur)
|
||||
|
||||
**Story 4.1: Empty State**
|
||||
- Dashed border container
|
||||
- Icon + tekst
|
||||
- Prominente CTA knop
|
||||
|
||||
**Story 4.2: Loading States**
|
||||
- Button spinner bij opslaan
|
||||
- Disabled state tijdens transitie
|
||||
|
||||
**Story 4.3: Validatie Feedback**
|
||||
- Inline errors onder velden
|
||||
- Focus op eerste error veld
|
||||
|
||||
---
|
||||
|
||||
## Kritieke Bestanden
|
||||
|
||||
### Te wijzigen
|
||||
- `app/epd/patients/[id]/intakes/[intakeId]/diagnosis/components/diagnosis-manager.tsx`
|
||||
- `app/epd/patients/[id]/intakes/[intakeId]/actions.ts`
|
||||
|
||||
### Nieuw aan te maken
|
||||
- `lib/data/icd10-ggz-codes.json`
|
||||
- `lib/types/icd10.ts`
|
||||
- `lib/schemas/diagnosis.ts`
|
||||
- `app/epd/.../diagnosis/components/icd10-combobox.tsx`
|
||||
- `app/epd/.../diagnosis/components/diagnosis-card.tsx`
|
||||
- `app/epd/.../diagnosis/components/diagnosis-modal.tsx`
|
||||
|
||||
### Dependencies
|
||||
- `cmdk` (toe te voegen)
|
||||
|
||||
---
|
||||
|
||||
## Acceptatiecriteria
|
||||
|
||||
1. **Zoekfunctie**: Zoeken op "depressie" toont F32.x codes binnen 200ms
|
||||
2. **Code selectie**: Selecteren vult beschrijving automatisch in
|
||||
3. **Validatie**: Opslaan zonder code toont inline error
|
||||
4. **CRUD**: Toevoegen, bewerken, verwijderen werkt correct
|
||||
5. **Badges**: Ernst en status tonen correcte kleuren
|
||||
6. **Hoofddiagnose**: Maximaal 1 per intake, duidelijk gemarkeerd
|
||||
7. **Build**: `pnpm build` slaagt zonder errors
|
||||
|
||||
---
|
||||
|
||||
## Geschatte Doorlooptijd
|
||||
- Epic 1: 1 uur
|
||||
- Epic 2: 3-4 uur
|
||||
- Epic 3: 2 uur
|
||||
- Epic 4: 1 uur
|
||||
- **Totaal: ~7-8 uur**
|
||||
@@ -1,317 +0,0 @@
|
||||
# Mission Control - Bouwplan Overdracht Dashboard
|
||||
|
||||
**Projectnaam:** Verpleegkundige Overdracht Dashboard
|
||||
**Versie:** v1.3 (Afgerond)
|
||||
**Datum:** 06-12-2024
|
||||
**Auteur:** Colin Lit
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en context
|
||||
|
||||
**Doel:** Een werkend MVP bouwen van het Overdracht Dashboard met Dagregistratie Module. Verpleegkundigen kunnen snel patiëntinformatie overzien en met AI-hulp een beknopte overdracht genereren in 30 seconden.
|
||||
|
||||
**Context:**
|
||||
- Verpleegkundigen doen gemiddeld 6 overdrachten per dag
|
||||
- Huidige workflow is tijdrovend en foutgevoelig
|
||||
- Dit dashboard bundelt vitals, rapportages, dagnotities en risico's
|
||||
- AI genereert gestructureerde samenvattingen met bronverwijzingen
|
||||
|
||||
**Relatie met andere documenten:**
|
||||
- PRD: `prd-overdracht-dashboard-v1.md` - scope en requirements
|
||||
- FO: `fo-overdracht-dashboard-v1.1.md` - functionele specificatie
|
||||
- TO: `to-overdracht-dashboard-v1.md` - technische architectuur
|
||||
|
||||
---
|
||||
|
||||
## 2. Uitgangspunten
|
||||
|
||||
### 2.1 Technische Stack
|
||||
|
||||
| Component | Technologie | Status |
|
||||
|-----------|-------------|--------|
|
||||
| Frontend | Next.js 15 (App Router) | Bestaand |
|
||||
| Backend | Next.js API Routes | Bestaand |
|
||||
| Database | Supabase (PostgreSQL) | Bestaand |
|
||||
| AI | Claude claude-sonnet-4-20250514 (Anthropic) | Bestaand |
|
||||
| Styling | TailwindCSS + shadcn/ui | Bestaand |
|
||||
| Validation | Zod | Bestaand |
|
||||
| Auth | Supabase Auth + RLS | Bestaand |
|
||||
|
||||
### 2.2 Projectkaders
|
||||
|
||||
- **Nieuwe dependencies:** Geen (alles aanwezig)
|
||||
- **Database:** 1 nieuwe tabel (`nursing_logs`)
|
||||
- **Routes:** 2 nieuwe secties (`/epd/overdracht/`, `/epd/dagregistratie/`)
|
||||
- **API endpoints:** 5 nieuwe endpoints
|
||||
- **Data:** Demo data beschikbaar (patients, encounters, reports)
|
||||
|
||||
### 2.3 Programmeer Uitgangspunten
|
||||
|
||||
**Code Quality Principles:**
|
||||
- **DRY:** Hergebruik bestaande componenten (Card, Badge, AIButton)
|
||||
- **KISS:** Eenvoudige Server Components waar mogelijk
|
||||
- **SOC:** API logic in `/api/`, UI in `/app/epd/`, types in `/lib/types/`
|
||||
- **YAGNI:** Alleen MVP features, geen "nice to have"
|
||||
|
||||
**Bestaande Patterns:**
|
||||
- AI integratie: `app/api/behandelplan/generate/route.ts`
|
||||
- CRUD API: `app/api/reports/route.ts`
|
||||
- Form components: `app/epd/patients/[id]/screening/`
|
||||
- Card layouts: `components/ui/card.tsx`
|
||||
|
||||
---
|
||||
|
||||
## 3. Epics & Stories Overzicht
|
||||
|
||||
| Epic ID | Titel | Doel | Status | Stories | Complexiteit |
|
||||
|---------|-------|------|--------|---------|--------------|
|
||||
| E0 | Database Setup | nursing_logs tabel + RLS | ✅ Done | 2 | Laag |
|
||||
| E1 | API Nursing Logs | CRUD endpoints voor dagnotities | ✅ Done | 2 | Laag |
|
||||
| E2 | API Overdracht | Endpoints voor overdracht data + AI | ✅ Done | 3 | Middel |
|
||||
| E3 | Dagregistratie UI | Quick entry module | ✅ Done | 3 | Middel |
|
||||
| E4 | Overdracht Overzicht | Patiënten grid | ✅ Done | 2 | Middel |
|
||||
| E5 | Overdracht Detail | Info blokken + AI samenvatting | ✅ Done | 4 | Middel |
|
||||
| E6 | Integratie & Polish | Sidebar, navigatie, testing | ✅ Done | 3 | Laag |
|
||||
|
||||
**Totaal:** 19 stories
|
||||
|
||||
---
|
||||
|
||||
## 4. Epics & Stories (Uitwerking)
|
||||
|
||||
### Epic 0 - Database Setup
|
||||
**Epic Doel:** nursing_logs tabel aanmaken met RLS policies en indexes.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP |
|
||||
|----------|--------------|---------------------|--------|------|----|
|
||||
| E0.S1 | nursing_logs tabel aanmaken | Tabel bestaat met alle kolommen uit TO, indexes aanwezig | ✅ | - | 2 |
|
||||
| E0.S2 | RLS policies implementeren | SELECT/INSERT/UPDATE/DELETE policies actief, alleen eigen logs muteerbaar | ✅ | E0.S1 | 2 |
|
||||
|
||||
**Technical Notes:**
|
||||
- Migratie via `npx supabase migration new create_nursing_logs`
|
||||
- Kolommen: id, patient_id, shift_date, timestamp, category, content, include_in_handover, created_by
|
||||
- Categories: medicatie, adl, gedrag, incident, observatie
|
||||
|
||||
---
|
||||
|
||||
### Epic 1 - API Nursing Logs
|
||||
**Epic Doel:** CRUD endpoints voor dagnotities.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP |
|
||||
|----------|--------------|---------------------|--------|------|----|
|
||||
| E1.S1 | GET/POST /api/nursing-logs | Ophalen per patient+date, aanmaken met Zod validatie | ✅ | E0.S2 | 3 |
|
||||
| E1.S2 | PATCH/DELETE /api/nursing-logs/[id] | Update eigen logs, hard delete | ✅ | E1.S1 | 2 |
|
||||
|
||||
**Technical Notes:**
|
||||
- Pattern volgen van `app/api/reports/route.ts`
|
||||
- Zod schema: CreateNursingLogSchema, UpdateNursingLogSchema
|
||||
- shift_date automatisch bepalen op basis van timestamp
|
||||
|
||||
---
|
||||
|
||||
### Epic 2 - API Overdracht
|
||||
**Epic Doel:** Endpoints voor overdracht overzicht, detail en AI generatie.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP |
|
||||
|----------|--------------|---------------------|--------|------|----|
|
||||
| E2.S1 | GET /api/overdracht/patients | Retourneert patiënten met encounters vandaag + alert counts | ✅ | E0.S2 | 3 |
|
||||
| E2.S2 | GET /api/overdracht/[patientId] | Retourneert patient + vitals + reports + logs + risks + conditions | ✅ | E1.S1 | 5 |
|
||||
| E2.S3 | POST /api/overdracht/generate | AI samenvatting met bronverwijzingen, logging naar ai_events | ✅ | E2.S2 | 5 |
|
||||
|
||||
**Technical Notes:**
|
||||
- E2.S2: Parallel queries via Promise.all()
|
||||
- E2.S3: Pattern van `behandelplan/generate`, nieuwe prompt in `lib/ai/overdracht-prompt.ts`
|
||||
- AI output: { samenvatting, aandachtspunten[], actiepunten[] }
|
||||
|
||||
---
|
||||
|
||||
### Epic 3 - Dagregistratie UI
|
||||
**Epic Doel:** Quick entry module voor verpleegkundige notities.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP |
|
||||
|----------|--------------|---------------------|--------|------|----|
|
||||
| E3.S1 | Dagregistratie page | Route `/epd/dagregistratie/[patientId]`, lijst van notities vandaag | ✅ | E1.S2 | 3 |
|
||||
| E3.S2 | Quick entry form | Categorie dropdown, tijd, tekst (max 500), overdracht checkbox | ✅ | E3.S1 | 5 |
|
||||
| E3.S3 | Edit/Delete functionality | Inline edit, confirm delete dialog | ✅ | E3.S2 | 3 |
|
||||
|
||||
**Technical Notes:**
|
||||
- Icons per categorie: Pill (medicatie), Utensils (adl), User (gedrag), AlertTriangle (incident), FileText (observatie)
|
||||
- Kleuren: red (incident), blue (medicatie), green (adl), purple (gedrag), gray (observatie)
|
||||
- Optimistic UI updates
|
||||
|
||||
---
|
||||
|
||||
### Epic 4 - Overdracht Overzicht
|
||||
**Epic Doel:** Grid van patiënten met alerts voor overdracht.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP |
|
||||
|----------|--------------|---------------------|--------|------|----|
|
||||
| E4.S1 | Overdracht overzicht page | Route `/epd/overdracht/`, grid van PatientCards, filter tabs | ✅ | E2.S1 | 5 |
|
||||
| E4.S2 | PatientCard component | Naam, leeftijd, alert badge (rood=hoog risico), doorklik | ✅ | E4.S1 | 3 |
|
||||
|
||||
**Technical Notes:**
|
||||
- Filter tabs: "Alle patiënten", "Met alerts"
|
||||
- Alert count = high_risk_count + abnormal_vitals_count + marked_logs_count
|
||||
- Responsive grid: 1 col mobile, 2 col tablet, 3-4 col desktop
|
||||
|
||||
---
|
||||
|
||||
### Epic 5 - Overdracht Detail
|
||||
**Epic Doel:** Patiënt detail pagina met informatieblokken en AI samenvatting.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP |
|
||||
|----------|--------------|---------------------|--------|------|----|
|
||||
| E5.S1 | Overdracht detail page | Route `/epd/overdracht/[patientId]`, patient header, 2-kolom layout | ✅ | E2.S2 | 3 |
|
||||
| E5.S2 | Info blokken: Vitals + Reports | VitalsBlock (metingen vandaag), ReportsBlock (24u) | ✅ | E5.S1 | 5 |
|
||||
| E5.S3 | Info blokken: Logs + Risks | NursingLogsBlock (gemarkeerd), RisksBlock (actief) | ✅ | E5.S2 | 5 |
|
||||
| E5.S4 | AI Samenvatting blok | AIButton "Genereer samenvatting", loading state, output met bronnen | ✅ | E2.S3, E5.S3 | 5 |
|
||||
|
||||
**Technical Notes:**
|
||||
- Linker kolom: Vitals, Reports, Logs, Risks (scrollable)
|
||||
- Rechter kolom: AI Samenvatting (sticky)
|
||||
- Bronverwijzingen klikbaar naar originele record
|
||||
- Empty states per blok
|
||||
|
||||
---
|
||||
|
||||
### Epic 6 - Integratie & Polish
|
||||
**Epic Doel:** Sidebar link, navigatie en testing.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afh. | SP |
|
||||
|----------|--------------|---------------------|--------|------|----|
|
||||
| E6.S1 | Sidebar uitbreiden | "Overdracht" link in EPD sidebar met alert badge | ✅ | E4.S1 | 1 |
|
||||
| E6.S2 | Navigatie links | Link van dagregistratie naar overdracht en vice versa | ✅ | E5.S3 | 2 |
|
||||
| E6.S3 | Smoke testing | Alle flows werken, geen console errors, performance OK | ✅ | E6.S2 | 3 |
|
||||
|
||||
**Technical Notes:**
|
||||
- Sidebar icon: ClipboardList (lucide)
|
||||
- Badge toont totaal aantal alerts
|
||||
- Test met bestaande demo patients
|
||||
|
||||
---
|
||||
|
||||
## 5. Kwaliteit & Testplan
|
||||
|
||||
### Test Types
|
||||
|
||||
| Test Type | Scope | Verantwoordelijke |
|
||||
|-----------|-------|-------------------|
|
||||
| Manual Testing | Alle flows | Developer |
|
||||
| TypeScript | Type checking | Build process |
|
||||
| RLS Testing | Database policies | Developer |
|
||||
|
||||
### Manual Test Checklist
|
||||
|
||||
**Dagregistratie:**
|
||||
- [ ] Nieuwe notitie aanmaken werkt
|
||||
- [ ] Categorie selectie werkt
|
||||
- [ ] "Opnemen in overdracht" checkbox werkt
|
||||
- [ ] Edit notitie werkt
|
||||
- [ ] Delete notitie werkt (met confirm)
|
||||
- [ ] Lijst refresht na mutatie
|
||||
|
||||
**Overdracht Overzicht:**
|
||||
- [ ] Grid toont patiënten met encounters vandaag
|
||||
- [ ] Alert badges tonen correct aantal
|
||||
- [ ] Filter "Met alerts" werkt
|
||||
- [ ] Doorklik naar detail werkt
|
||||
|
||||
**Overdracht Detail:**
|
||||
- [ ] Patient header toont naam, leeftijd, diagnose
|
||||
- [ ] Vitals blok toont metingen vandaag (of empty state)
|
||||
- [ ] Reports blok toont laatste 24u (of empty state)
|
||||
- [ ] Nursing logs blok toont gemarkeerde notities
|
||||
- [ ] Risks blok toont actieve risico's
|
||||
- [ ] AI samenvatting genereert binnen 5 sec
|
||||
- [ ] Bronverwijzingen in AI output zijn correct
|
||||
|
||||
**Performance:**
|
||||
- [ ] Overzicht laadt < 2 sec
|
||||
- [ ] Detail laadt < 1.5 sec
|
||||
- [ ] AI response < 5 sec
|
||||
|
||||
---
|
||||
|
||||
## 6. Succescriteria (uit PRD)
|
||||
|
||||
- [ ] Overzicht laadt binnen 2 seconden
|
||||
- [ ] Patiënt detail toont alle 6 informatieblokken correct (incl. dagnotities)
|
||||
- [ ] Dagregistratie form submit < 1 seconde
|
||||
- [ ] AI samenvatting genereert binnen 5 seconden
|
||||
- [ ] AI output is begrijpelijk en medisch relevant
|
||||
- [ ] AI integreert dagnotities correct in samenvatting
|
||||
- [ ] Navigatie tussen overzicht, detail en dagregistratie werkt vlot
|
||||
- [ ] Alerts (hoog risico, afwijkende vitals, gemarkeerde notities) zijn direct zichtbaar
|
||||
- [ ] Empty states bij ontbrekende data zijn informatief
|
||||
|
||||
---
|
||||
|
||||
## 7. Risico's & Mitigatie
|
||||
|
||||
| Risico | Kans | Impact | Mitigatie |
|
||||
|--------|------|--------|-----------|
|
||||
| AI samenvatting te lang/vaag | Middel | Hoog | Strikte prompt, max tokens, testen |
|
||||
| Geen vitale functies in systeem | Hoog | Laag | Graceful empty state |
|
||||
| Performance bij veel data | Laag | Middel | Indexes, parallel queries |
|
||||
| AI hallucinaties | Laag | Hoog | Bronverwijzingen verplicht |
|
||||
| VPK vergeet notities markeren | Middel | Middel | UI hint, standaard checkbox |
|
||||
|
||||
---
|
||||
|
||||
## 8. Niet in Scope (MVP)
|
||||
|
||||
| Feature | Reden |
|
||||
|---------|-------|
|
||||
| Medicatie-invoer | Alleen weergave, aparte module |
|
||||
| Historische trends | Geen grafieken |
|
||||
| PDF export | Komt later |
|
||||
| Notificaties | Geen realtime alerts |
|
||||
| Multi-afdeling | Te complex |
|
||||
| Rechten per rol | Beperkt onderscheid VPK/arts |
|
||||
|
||||
---
|
||||
|
||||
## 9. Referenties
|
||||
|
||||
### Mission Control Documents
|
||||
|
||||
| Document | Status |
|
||||
|----------|--------|
|
||||
| PRD Overdracht Dashboard v1.0 | Gereed |
|
||||
| FO Overdracht Dashboard v1.1 | Gereed |
|
||||
| TO Overdracht Dashboard v1.0 | Gereed |
|
||||
| Bouwplan v1.0 | Gereed (dit document) |
|
||||
|
||||
### Code Locaties
|
||||
|
||||
| Wat | Locatie |
|
||||
|-----|---------|
|
||||
| AI prompt pattern | `lib/ai/behandelplan-prompt.ts` |
|
||||
| API route pattern | `app/api/reports/route.ts` |
|
||||
| shadcn components | `components/ui/` |
|
||||
| EPD layout | `app/epd/layout.tsx` |
|
||||
| Sidebar | `app/epd/components/epd-sidebar.tsx` |
|
||||
|
||||
---
|
||||
|
||||
## 10. Glossary
|
||||
|
||||
| Term | Betekenis |
|
||||
|------|-----------|
|
||||
| Overdracht | Mondelinge/schriftelijke informatieoverdracht tussen diensten |
|
||||
| VPK | Verpleegkundige |
|
||||
| Dagnotitie | Korte registratie tijdens dienst (nursing_log) |
|
||||
| Alert | Signaal voor aandacht (hoog risico, afwijking, incident) |
|
||||
| Handover | Engelse term voor overdracht |
|
||||
|
||||
---
|
||||
|
||||
## Changelog
|
||||
|
||||
| Versie | Datum | Auteur | Wijziging |
|
||||
|--------|-------|--------|-----------|
|
||||
| v1.0 | 05-12-2024 | Colin | Initieel bouwplan gebaseerd op PRD, FO en TO |
|
||||
| v1.1 | 06-12-2024 | Claude | E0 + E1 afgerond: database setup + API nursing logs |
|
||||
| v1.2 | 06-12-2024 | Claude | E2 + E3 afgerond: API overdracht + dagregistratie UI |
|
||||
| v1.3 | 06-12-2024 | Claude | E4 + E5 + E6 afgerond: Overdracht UI compleet, alle 19 stories done |
|
||||
@@ -1,642 +0,0 @@
|
||||
# 🧩 Functioneel Ontwerp (FO) — Verpleegkundige Overdracht Dashboard
|
||||
|
||||
**Projectnaam:** Verpleegkundige Overdracht Dashboard
|
||||
**Versie:** v1.1 (met Dagregistratie Module)
|
||||
**Datum:** 05-12-2024
|
||||
**Auteur:** Colin Lit
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en relatie met het PRD
|
||||
|
||||
🎯 **Doel van dit document:**
|
||||
Dit Functioneel Ontwerp beschrijft **hoe** het Overdracht Dashboard uit het PRD functioneel zal werken — wat de verpleegkundige ziet, doet en ervaart. Waar het PRD uitlegt *wat en waarom*, laat dit FO zien *hoe dit in de praktijk werkt*.
|
||||
|
||||
📘 **Relatie met PRD:**
|
||||
- PRD-referentie: `prd-overdracht-dashboard-v1.md`
|
||||
- Dit FO is de functionele uitwerking van PRD secties 3 (Kernfunctionaliteiten) en 4 (Gebruikersflows)
|
||||
|
||||
**Kernprincipe:**
|
||||
> Elke getoonde informatie moet **traceerbaar** zijn naar de bron. De gebruiker moet kunnen zien waar data vandaan komt en kunnen doorklikken naar het originele record.
|
||||
|
||||
**Nieuw in v1.1:**
|
||||
> **Dagregistratie Module** - Verpleegkundigen kunnen tijdens hun dienst snelle notities maken (medicatie, ADL, gedrag, incidenten) en markeren welke relevant zijn voor overdracht. Dit scheidt operationele dagregistratie van behandelrapportages die in het decursus komen.
|
||||
|
||||
---
|
||||
|
||||
## 2. Overzicht van de belangrijkste onderdelen
|
||||
|
||||
🎯 **Doel:** Kort overzicht van schermen en componenten binnen het Overdracht Dashboard.
|
||||
|
||||
| # | Onderdeel | Beschrijving | Route |
|
||||
|---|-----------|--------------|-------|
|
||||
| 1 | **Overdracht Overzicht** | Grid van alle patiënten voor vandaag | `/epd/overdracht/` |
|
||||
| 2 | **Patiënt Detail** | Informatieblokken + AI samenvatting | `/epd/overdracht/[patientId]` |
|
||||
| 3 | **Dagregistratie Module** | Snelle verpleegkundige notities met overdracht-markering | `/epd/dagregistratie/[patientId]` |
|
||||
| 4 | **Vitale Functies Blok** | Metingen vandaag met trend indicators | Detail pagina |
|
||||
| 5 | **Rapportages Blok** | Behandelrapportages (24u) met bronlinks | Detail pagina |
|
||||
| 6 | **Dagnotities Blok** | Verpleegkundige registraties vandaag | Detail pagina |
|
||||
| 7 | **Medicatie Blok** | Huidige medicatie *(placeholder)* | Detail pagina |
|
||||
| 8 | **Risico's Blok** | Actieve risicotaxaties | Detail pagina |
|
||||
| 9 | **AI Samenvatting Blok** | Gegenereerde overdracht met bronverwijzingen | Detail pagina |
|
||||
|
||||
---
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
🎯 **Doel:** Beschrijven wat gebruikers moeten kunnen doen, vanuit hun perspectief.
|
||||
|
||||
### MVP User Stories (origineel)
|
||||
|
||||
| ID | Rol | Doel / Actie | Verwachte waarde | Prio |
|
||||
|----|-----|--------------|------------------|------|
|
||||
| **OD-US01** | Verpleegkundige | Overzicht zien van alle patiënten voor vandaag | Weet wie ik moet overdragen | 🔴 Hoog |
|
||||
| **OD-US02** | Verpleegkundige | Filteren op patiënten met alerts | Focus op urgente cases | 🔴 Hoog |
|
||||
| **OD-US03** | Verpleegkundige | Doorklikken naar patiënt detail | Zie alle relevante info | 🔴 Hoog |
|
||||
| **OD-US04** | Verpleegkundige | Vitale functies zien met afwijkingen gemarkeerd | Direct zien wat er aan de hand is | 🔴 Hoog |
|
||||
| **OD-US05** | Verpleegkundige | Recente rapportages lezen | Context voor overdracht | 🔴 Hoog |
|
||||
| **OD-US06** | Verpleegkundige | Doorklikken naar originele rapportage | Bronverificatie | 🔴 Hoog |
|
||||
| **OD-US07** | Verpleegkundige | Risico's zien met ernst-niveau | Weet wat aandacht nodig heeft | 🟡 Middel |
|
||||
| **OD-US08** | Verpleegkundige | AI-samenvatting genereren | Snelle overdracht in 30 sec | 🔴 Hoog |
|
||||
| **OD-US09** | Verpleegkundige | In AI-samenvatting bronnen zien | Weet waar info vandaan komt | 🔴 Hoog |
|
||||
| **OD-US10** | Verpleegkundige | Vanuit AI-samenvatting doorklikken naar bron | Kan details checken | 🟡 Middel |
|
||||
|
||||
### Nieuwe User Stories (Dagregistratie)
|
||||
|
||||
| ID | Rol | Doel / Actie | Verwachte waarde | Prio |
|
||||
|----|-----|--------------|------------------|------|
|
||||
| **OD-US11** | Verpleegkundige | Tijdens dienst snelle notitie toevoegen | Registreer gebeurtenis direct | 🔴 Hoog |
|
||||
| **OD-US12** | Verpleegkundige | Notitie categoriseren (medicatie/ADL/gedrag/incident) | Heldere structuur | 🔴 Hoog |
|
||||
| **OD-US13** | Verpleegkundige | Markeren welke notities relevant zijn voor overdracht | Controle over wat gedeeld wordt | 🔴 Hoog |
|
||||
| **OD-US14** | Verpleegkundige | Overzicht van dagnotities zien | Snel terugkijken wat er gebeurd is | 🔴 Hoog |
|
||||
| **OD-US15** | Verpleegkundige | Dagnotitie bewerken/verwijderen | Correctie mogelijk | 🟡 Middel |
|
||||
| **OD-US16** | Psychiater | Alleen relevante notities in overdracht zien | Geen informatie-overload | 🔴 Hoog |
|
||||
| **OD-US17** | Psychiater | AI-samenvatting inclusief dagnotities | Compleet beeld van dienst | 🔴 Hoog |
|
||||
|
||||
---
|
||||
|
||||
## 4. Functionele werking per onderdeel
|
||||
|
||||
🎯 **Doel:** Per hoofdonderdeel beschrijven wat de gebruiker kan doen en wat het systeem doet.
|
||||
|
||||
### 4.1 Dagregistratie Module (NIEUW)
|
||||
|
||||
**Route:** `/epd/dagregistratie/[patientId]`
|
||||
|
||||
**Doel:** Snelle registratie tijdens dienst van operationele gebeurtenissen die relevant kunnen zijn voor overdracht, maar niet in het behandelverloop (decursus) horen.
|
||||
|
||||
**Functionaliteit:**
|
||||
|
||||
| Actie | Beschrijving | Systeem reactie |
|
||||
|-------|--------------|-----------------|
|
||||
| **Nieuwe notitie** | Klik "+ Registratie" | Toon quick-entry form |
|
||||
| **Categorie selecteren** | Dropdown: Medicatie, ADL, Gedrag, Incident, Observatie | Icoon + kleurcodering |
|
||||
| **Tijd instellen** | Standaard: nu, Aanpasbaar | Timestamp registratie |
|
||||
| **Tekst invoeren** | Kort tekstveld (max 500 chars) | Autosave draft |
|
||||
| **Overdracht markeren** | Checkbox "Opnemen in overdracht" | Badge in lijst |
|
||||
| **Opslaan** | Submit form | Insert nursing_log, refresh lijst |
|
||||
| **Bewerken** | Klik op notitie | Inline edit mode |
|
||||
| **Verwijderen** | Trash icon | Confirm dialog → delete |
|
||||
|
||||
**UI Componenten:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Dagregistratie - Jan de Vries │
|
||||
│ Donderdag 5 december 2024 │
|
||||
├─────────────────────────────────────────┤
|
||||
│ [+ Nieuwe registratie] Filter: [Alle]│
|
||||
├─────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 14:30 🔴 Incident [Overdracht] │
|
||||
│ Verbale escalatie bij groepsactiviteit │
|
||||
│ Collega heeft de-escalatie gedaan │
|
||||
│ [Bewerken] [Verwijderen] │
|
||||
│ │
|
||||
│ 12:00 💊 Medicatie [Overdracht] │
|
||||
│ Lithium geweigerd - "Voel me goed" │
|
||||
│ [Bewerken] [Verwijderen] │
|
||||
│ │
|
||||
│ 08:00 💊 Medicatie │
|
||||
│ Olanzapine 10mg toegediend conform │
|
||||
│ [Bewerken] [Verwijderen] │
|
||||
│ │
|
||||
│ 07:30 🍽️ ADL │
|
||||
│ Ontbijt volledig genuttigd │
|
||||
│ [Bewerken] [Verwijderen] │
|
||||
│ │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Quick Entry Form:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Nieuwe registratie │
|
||||
├─────────────────────────────────────┤
|
||||
│ Categorie: [Incident ▼] │
|
||||
│ 💊 Medicatie │
|
||||
│ 🍽️ ADL/verzorging │
|
||||
│ 👤 Gedragsobservatie │
|
||||
│ 🔴 Incident │
|
||||
│ 📝 Algemene observatie │
|
||||
│ │
|
||||
│ Tijd: [14:30] [Nu] │
|
||||
│ │
|
||||
│ Omschrijving: │
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ Patiënt werd geprikkeld tijdens │ │
|
||||
│ │ groepsactiviteit, verbale │ │
|
||||
│ │ escalatie. Collega heeft... │ │
|
||||
│ └─────────────────────────────────┘ │
|
||||
│ 234 / 500 karakters │
|
||||
│ │
|
||||
│ ☑️ Opnemen in overdracht │
|
||||
│ │
|
||||
│ [Annuleren] [Opslaan] │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Data Flow:**
|
||||
|
||||
```
|
||||
User input
|
||||
↓
|
||||
nursing_logs table
|
||||
↓
|
||||
Overdracht Detail (indien marked)
|
||||
↓
|
||||
AI Samenvatting (contextueel)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Overdracht Overzicht (`/epd/overdracht/`)
|
||||
|
||||
**Context:** Level 1 - Alle patiënten voor vandaag
|
||||
|
||||
[Rest blijft hetzelfde als origineel FO]
|
||||
|
||||
**Layout:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ EPD Sidebar │ Overdracht │
|
||||
│ │ │
|
||||
│ ┌─────────┐ │ ┌──────────────────────────────────────────────┐ │
|
||||
│ │Dashboard│ │ │ Overdracht 🔴 3 alerts │ │
|
||||
│ │─────────│ │ │ Donderdag 5 december 2024 · 8 patiënten │ │
|
||||
│ │Cliënten │ │ ├──────────────────────────────────────────────┤ │
|
||||
│ │─────────│ │ │ [Alle patiënten (8)] [Met alerts (3)] │ │
|
||||
│ │Agenda │ │ ├──────────────────────────────────────────────┤ │
|
||||
│ │─────────│ │ │ │ │
|
||||
│ │►Overdracht│ │ ┌───────── ┌───────── ┌───────── │ │
|
||||
│ │─────────│ │ │ │ Jan V. │ │ Marie K.│ │ Piet B. │ │ │
|
||||
│ │Rapportage│ │ │ │ 🔴 2 │ │ OK │ │ 🟡 1 │ │ │
|
||||
│ └─────────┘ │ │ │ 67 jaar │ │ 45 jaar │ │ 52 jaar │ │ │
|
||||
│ │ │ │ [→] │ │ [→] │ │ [→] │ │ │
|
||||
│ │ │ └───────── └───────── └───────── │ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Patiënt Card Inhoud:**
|
||||
|
||||
| Element | Toelichting |
|
||||
|---------|-------------|
|
||||
| Naam | Voornaam + initiaal achternaam |
|
||||
| Alert badge | 🔴 Aantal hoog-risico items |
|
||||
| Leeftijd | Berekend uit geboortedatum |
|
||||
| Klik | → Navigeer naar detail pagina |
|
||||
|
||||
**Filter Functionaliteit:**
|
||||
|
||||
```typescript
|
||||
// Pseudo-code
|
||||
if (filter === 'met-alerts') {
|
||||
patients = patients.filter(p =>
|
||||
p.high_risk_count > 0 ||
|
||||
p.abnormal_vitals_count > 0 ||
|
||||
p.marked_nursing_logs > 0 // NIEUW
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.3 Patiënt Detail (`/epd/overdracht/[patientId]`)
|
||||
|
||||
**Context:** Level 2 - specifieke patiënt overdracht informatie
|
||||
|
||||
**Layout (uitgebreid met Dagnotities blok):**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ← Terug naar overzicht │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ Jan de Vries │
|
||||
│ ♂ 67 jaar · Depressieve stoornis, recidiverend │
|
||||
├────────────────────────────────┬────────────────────────────────┤
|
||||
│ │ │
|
||||
│ ┌─ Vitale Functies ────────┐ │ ┌─ AI Samenvatting ────────┐ │
|
||||
│ │ ... │ │ │ │ │
|
||||
│ └───────────────────────────┘ │ │ [Genereer samenvatting] │ │
|
||||
│ │ │ │ │
|
||||
│ ┌─ Rapportages ─────────────┐ │ │ Samenvatting... │ │
|
||||
│ │ Behandelverslagen (24u) │ │ │ │ │
|
||||
│ │ [3 rapportages] │ │ │ Aandachtspunten: │ │
|
||||
│ └───────────────────────────┘ │ │ • Medicatie geweigerd │ │
|
||||
│ │ │ • Incident vanmiddag │ │
|
||||
│ ┌─ Dagnotities ─────────────┐ │ │ │ │ ← NIEUW
|
||||
│ │ VPK registraties vandaag │ │ │ Actiepunten: │ │
|
||||
│ │ [5 notities, 2 relevant] │ │ │ • Bloeddruk checken │ │
|
||||
│ │ → [Dagregistratie] │ │ │ │ │
|
||||
│ └───────────────────────────┘ │ └───────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌─ Medicatie ───────────────┐ │ │
|
||||
│ │ [Placeholder] │ │ │
|
||||
│ └───────────────────────────┘ │ │
|
||||
│ │ │
|
||||
│ ┌─ Risico's ────────────────┐ │ │
|
||||
│ │ ... │ │ │
|
||||
│ └───────────────────────────┘ │ │
|
||||
│ │ │
|
||||
└────────────────────────────────┴────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.4 Dagnotities Blok (NIEUW)
|
||||
|
||||
**Doel:** Toon relevante verpleegkundige registraties in overdracht context
|
||||
|
||||
**Inhoud:**
|
||||
|
||||
```
|
||||
┌─ Dagnotities ─────────────────────────────────────┐
|
||||
│ Verpleegkundige registraties vandaag │
|
||||
│ │
|
||||
│ 14:30 🔴 Incident [Overdracht] │
|
||||
│ Verbale escalatie bij groepsactiviteit │
|
||||
│ Collega heeft de-escalatie gedaan │
|
||||
│ Bron: nursing_logs/789 │
|
||||
│ │
|
||||
│ 12:00 💊 Medicatie [Overdracht] │
|
||||
│ Lithium geweigerd - "Voel me goed" │
|
||||
│ Bron: nursing_logs/788 │
|
||||
│ │
|
||||
│ [Toon alle registraties (5)] → /dagregistratie/ │
|
||||
└────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Business Rules:**
|
||||
|
||||
| Regel | Implementatie |
|
||||
|-------|---------------|
|
||||
| Toon alleen gemarkeerde notities | `WHERE include_in_handover = true` |
|
||||
| Sorteer chronologisch (nieuw → oud) | `ORDER BY timestamp DESC` |
|
||||
| Max 5 items inline | Rest via link naar dagregistratie |
|
||||
| Urgentie kleuren | 🔴 Incident > 💊 Medicatie > 👤 Gedrag > 🍽️ ADL |
|
||||
|
||||
---
|
||||
|
||||
## 5. Interacties met AI (functionele beschrijving)
|
||||
|
||||
🎯 **Doel:** Uitleggen waar AI in de flow voorkomt en wat de gebruiker ziet.
|
||||
|
||||
### 5.1 AI Overdracht Generator (uitgebreid)
|
||||
|
||||
| Aspect | Beschrijving |
|
||||
|--------|--------------|
|
||||
| **Locatie** | AI Samenvatting blok op patiënt detail pagina |
|
||||
| **Trigger** | Klik op "Genereer samenvatting" button |
|
||||
| **Input context** | Vitals (vandaag) + Reports (24u) + **Nursing Logs (marked)** + Risks (actief) + Conditions (actief) |
|
||||
| **Processing** | ~3-5 seconden, progress indicator |
|
||||
| **Output** | Samenvatting + aandachtspunten (met bronnen) + actiepunten |
|
||||
|
||||
### 5.2 AI Prompt Strategie (aangepast)
|
||||
|
||||
**System Prompt Kernpunten:**
|
||||
- Rol: Ervaren verpleegkundige die overdrachten maakt
|
||||
- Taal: Nederlands, zakelijk, beknopt
|
||||
- Focus: Veranderingen, zorgen, actiepunten
|
||||
- **Bronvermelding:** Bij elk aandachtspunt de databron vermelden
|
||||
- **Nieuwe data:** Verwerk nursing_logs als operationele context
|
||||
|
||||
**Context Structuur voor AI (uitgebreid):**
|
||||
|
||||
```
|
||||
PATIENT: [naam], [leeftijd] jaar
|
||||
|
||||
DIAGNOSES:
|
||||
- [diagnose 1] (source: conditions/[id])
|
||||
- [diagnose 2] (source: conditions/[id])
|
||||
|
||||
VITALE FUNCTIES (vandaag):
|
||||
- Bloeddruk: 145/92 mmHg [VERHOOGD] (source: observations/[id], 14:30)
|
||||
- Hartslag: 78 bpm [NORMAAL] (source: observations/[id], 14:30)
|
||||
|
||||
RAPPORTAGES (laatste 24u):
|
||||
- [14:15] Voortgangsnotitie: "..." (source: reports/[id])
|
||||
- [09:30] Contactmoment: "..." (source: reports/[id])
|
||||
|
||||
DAGREGISTRATIES (dienst vandaag, relevant voor overdracht): ← NIEUW
|
||||
- [14:30] [INCIDENT] Verbale escalatie bij groepsactiviteit... (source: nursing_logs/789)
|
||||
- [12:00] [MEDICATIE] Lithium geweigerd - "Voel me goed" (source: nursing_logs/788)
|
||||
|
||||
RISICO'S:
|
||||
- [HOOG] Suïcidaliteit: "..." (source: risk_assessments/[id])
|
||||
- [MIDDEL] Zelfverwaarlozing: "..." (source: risk_assessments/[id])
|
||||
```
|
||||
|
||||
**Expected Output (voorbeeld):**
|
||||
|
||||
```json
|
||||
{
|
||||
"samenvatting": "67-jarige man met recidiverende depressie. Medicatie-therapietrouw problematisch vandaag (Lithium geweigerd), incident vanmiddag met verbale escalatie.",
|
||||
"aandachtspunten": [
|
||||
{
|
||||
"tekst": "Lithium medicatie geweigerd om 12:00 - patiënt geeft aan zich goed te voelen",
|
||||
"urgent": false,
|
||||
"bron": {
|
||||
"type": "dagnotitie",
|
||||
"id": "nursing-788",
|
||||
"datum": "05-12-2024 12:00",
|
||||
"label": "Medicatie registratie"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tekst": "Incident 14:30 - verbale escalatie tijdens groepsactiviteit, de-escalatie door collega",
|
||||
"urgent": true,
|
||||
"bron": {
|
||||
"type": "dagnotitie",
|
||||
"id": "nursing-789",
|
||||
"datum": "05-12-2024 14:30",
|
||||
"label": "Incident registratie"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tekst": "Bloeddruk verhoogd (145/92) - monitoring nodig",
|
||||
"urgent": false,
|
||||
"bron": {
|
||||
"type": "observatie",
|
||||
"id": "obs-456",
|
||||
"datum": "05-12-2024 14:30",
|
||||
"label": "Vitale functies"
|
||||
}
|
||||
}
|
||||
],
|
||||
"actiepunten": [
|
||||
"Overleg arts over medicatie-weigering en compliance",
|
||||
"Bloeddruk controleren over 2 uur",
|
||||
"Evalueer triggers voor incident in behandelplan"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Database Schema (NIEUW)
|
||||
|
||||
🎯 **Doel:** Duidelijk maken welke nieuwe data-structuren nodig zijn.
|
||||
|
||||
### 6.1 Nieuwe Tabel: nursing_logs
|
||||
|
||||
```sql
|
||||
CREATE TABLE nursing_logs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
patient_id UUID NOT NULL REFERENCES patients(id) ON DELETE CASCADE,
|
||||
|
||||
-- Timing
|
||||
shift_date DATE NOT NULL, -- Voor filtering per dienst
|
||||
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
|
||||
-- Content
|
||||
category TEXT NOT NULL CHECK (category IN ('medicatie', 'adl', 'gedrag', 'incident', 'observatie')),
|
||||
content TEXT NOT NULL, -- Max 500 chars in UI
|
||||
|
||||
-- Overdracht
|
||||
include_in_handover BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
-- Metadata
|
||||
created_by UUID NOT NULL REFERENCES auth.users(id),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Indexes
|
||||
CREATE INDEX idx_nursing_logs_patient ON nursing_logs(patient_id);
|
||||
CREATE INDEX idx_nursing_logs_shift ON nursing_logs(shift_date);
|
||||
CREATE INDEX idx_nursing_logs_handover ON nursing_logs(patient_id, include_in_handover);
|
||||
```
|
||||
|
||||
**Verschil met reports tabel:**
|
||||
|
||||
| Aspect | reports | nursing_logs |
|
||||
|--------|---------|--------------|
|
||||
| **Doel** | Behandelverloof (decursus) | Operationele dagregistratie |
|
||||
| **Lengte** | Lang (rich text) | Kort (max 500 chars) |
|
||||
| **Levensduur** | Jaren | Dagen/weken |
|
||||
| **In overdracht** | Soms | Frequent |
|
||||
| **Gebruiker** | Behandelaar + VPK | Voornamelijk VPK |
|
||||
|
||||
---
|
||||
|
||||
## 7. Gebruikersflows (uitgebreid)
|
||||
|
||||
🎯 **Doel:** Laten zien hoe de gebruiker stap-voor-stap door het systeem gaat.
|
||||
|
||||
### Flow 1: Dagelijkse Overdracht (aangepast)
|
||||
|
||||
```
|
||||
1. Verpleegkundige opent Overdracht pagina
|
||||
2. Ziet grid van alle patiënten voor vandaag
|
||||
3. Filtert eventueel op "Met alerts"
|
||||
4. Klikt op patiënt voor detail view
|
||||
5. Bekijkt informatieblokken:
|
||||
- Vitals
|
||||
- Behandelrapportages
|
||||
- Dagnotities (NIEUW)
|
||||
- Risico's
|
||||
6. Klikt "Genereer samenvatting"
|
||||
7. AI maakt beknopte overdracht (incl. dagnotities)
|
||||
8. Verpleegkundige gebruikt samenvatting voor overdracht aan psychiater
|
||||
```
|
||||
|
||||
### Flow 2: Registratie Tijdens Dienst (NIEUW)
|
||||
|
||||
```
|
||||
1. Verpleegkundige tijdens dienst: gebeurtenis met patiënt
|
||||
2. Opent Dagregistratie module voor die patiënt
|
||||
3. Klikt "+ Nieuwe registratie"
|
||||
4. Vult in:
|
||||
- Categorie (bijv. Incident)
|
||||
- Tijd (standaard: nu)
|
||||
- Omschrijving (kort, 2-3 zinnen)
|
||||
- ☑️ "Opnemen in overdracht"
|
||||
5. Slaat op
|
||||
6. Notitie verschijnt in lijst met [Overdracht] badge
|
||||
7. Aan eind dienst: notitie automatisch in overdracht-view
|
||||
```
|
||||
|
||||
### Flow 3: Psychiater Bekijkt Overdracht (NIEUW)
|
||||
|
||||
```
|
||||
1. Psychiater opent Overdracht dashboard
|
||||
2. Ziet lijst met patiënten waarvan VPK dienst had
|
||||
3. Opent patiënt detail
|
||||
4. Bekijkt Dagnotities blok:
|
||||
- Ziet alleen gemarkeerde items
|
||||
- Leest 2 incidenten + 1 medicatie-weigering
|
||||
5. Klikt "Genereer samenvatting"
|
||||
6. AI vat samen: "Vandaag 2 incidenten, medicatie geweigerd, verhoogde bloeddruk"
|
||||
7. Psychiater bespreekt met VPK of patiënt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Gebruikersrollen en rechten
|
||||
|
||||
🎯 **Doel:** Beschrijven welke rollen toegang hebben.
|
||||
|
||||
### MVP: Uniform toegangsmodel
|
||||
|
||||
| Rol | Dagregistratie | Overdracht Dashboard | Beperkingen |
|
||||
|-----|----------------|---------------------|-------------|
|
||||
| Verpleegkundige | Volledige CRUD | Volledige functionaliteit | Alleen eigen patiënten |
|
||||
| Psychiater | Read-only | Volledige functionaliteit | Alleen eigen patiënten |
|
||||
|
||||
### Data Scoping (uitgebreid)
|
||||
|
||||
- **Patiënten:** Gefilterd op actieve encounters vandaag
|
||||
- **Reports:** Gefilterd op `created_by` of team-toegang
|
||||
- **Nursing Logs:** Gefilterd op shift_date (vandaag) en `created_by`
|
||||
- **Risico's:** Via intake → patient relatie
|
||||
|
||||
---
|
||||
|
||||
## 9. Niet in Scope (aangepast)
|
||||
|
||||
🎯 **Doel:** Duidelijk maken wat (nog) niet wordt gebouwd.
|
||||
|
||||
| Feature | Reden exclusie |
|
||||
|---------|----------------|
|
||||
| Medicatie-invoer | Alleen weergave, CRUD is aparte module |
|
||||
| Templating dagnotities | Vrije tekst is sneller voor MVP |
|
||||
| Historische dagnotities | Alleen vandaag, archivering later |
|
||||
| Multi-afdeling view | Te complex voor MVP, alleen eigen patiënten |
|
||||
| Historische trends | Geen grafieken of lange termijn overzichten |
|
||||
| Notificaties/push | Geen realtime alerts |
|
||||
| Print/export | Geen PDF of print functionaliteit |
|
||||
| Rechten per rol | Beperkt onderscheid VPK/arts (komt later) |
|
||||
| Metingen invoer | Aparte functionaliteit, hier alleen weergave |
|
||||
| Dicteer-functie | Typen is snel genoeg voor korte notities |
|
||||
|
||||
---
|
||||
|
||||
## 10. Succescriteria (uitgebreid)
|
||||
|
||||
🎯 **Doel:** Objectieve meetlat voor een geslaagde oplevering.
|
||||
|
||||
- [ ] Overzicht laadt binnen 2 seconden
|
||||
- [ ] Patiënt detail toont alle 6 informatieblokken correct (incl. dagnotities)
|
||||
- [ ] Dagregistratie form submit < 1 seconde
|
||||
- [ ] AI samenvatting genereert binnen 5 seconden
|
||||
- [ ] AI output is begrijpelijk en medisch relevant
|
||||
- [ ] AI integreert dagnotities correct in samenvatting
|
||||
- [ ] Navigatie tussen overzicht, detail en dagregistratie werkt vlot
|
||||
- [ ] Alerts (hoog risico, afwijkende vitals, markeerde notities) zijn direct zichtbaar
|
||||
- [ ] Empty states bij ontbrekende data zijn informatief
|
||||
- [ ] Dagnotities met [Overdracht] badge zijn duidelijk herkenbaar
|
||||
|
||||
---
|
||||
|
||||
## 11. Risico's & Mitigatie (uitgebreid)
|
||||
|
||||
🎯 **Doel:** Risico's vroeg signaleren en plannen hoe ermee om te gaan.
|
||||
|
||||
| Risico | Impact | Mitigatie |
|
||||
|--------|--------|-----------|
|
||||
| AI samenvatting te lang/vaag | Hoog | Strikte prompt met max lengte, testen met echte data |
|
||||
| Geen vitale functies in systeem | Middel | Graceful empty state, instructie om metingen toe te voegen |
|
||||
| Medicatie tabel bestaat niet | Middel | Placeholder blok met "Binnenkort beschikbaar" |
|
||||
| Performance bij veel patiënten | Middel | Parallel queries, pagination indien nodig |
|
||||
| Risico's gekoppeld aan intake ipv patient | Laag | Query via intake tabel |
|
||||
| VPK vergeet notities markeren | Hoog | AI pre-selectie als backup |
|
||||
| Dubbele registratie (reports + nursing_logs) | Middel | Duidelijke UI scheiding + training |
|
||||
| Nursing_logs niet archiveren | Laag | Auto-delete na 30 dagen (fase 2) |
|
||||
|
||||
---
|
||||
|
||||
## 12. Roadmap / Vervolg (Post-MVP)
|
||||
|
||||
🎯 **Doel:** Richting geven aan toekomstige uitbreidingen.
|
||||
|
||||
| Fase | Feature | Beschrijving |
|
||||
|------|---------|--------------|
|
||||
| 2 | Medicatie module | Volledige CRUD voor medicatie, koppeling met nursing_logs |
|
||||
| 3 | Templates dagnotities | Snelle keuzes: "Medicatie conform", "Eetpatroon normaal" |
|
||||
| 4 | Archivering | Auto-delete nursing_logs > 30 dagen, export naar archief |
|
||||
| 5 | Trend grafieken | Vitale functies over tijd |
|
||||
| 6 | PDF export | Formele overdracht documenten |
|
||||
| 7 | Agenda integratie | Koppeling met encounters/afspraken |
|
||||
| 8 | Notificaties | Alerts bij kritieke waarden |
|
||||
| 9 | Multi-afdeling | Overzicht meerdere afdelingen |
|
||||
| 10 | Spraak-naar-tekst | Dicteer dagnotities (Deepgram integratie) |
|
||||
|
||||
---
|
||||
|
||||
## 13. Bijlagen & Referenties
|
||||
|
||||
🎯 **Doel:** Linken naar gerelateerde documenten.
|
||||
|
||||
### Interne Documenten
|
||||
|
||||
| Document | Status |
|
||||
|----------|--------|
|
||||
| PRD Overdracht Dashboard v1.0 | ✅ Gereed |
|
||||
| FO Overdracht Dashboard v1.1 | ✅ Gereed (dit document) |
|
||||
| TO Overdracht Dashboard | 📋 Nog te schrijven |
|
||||
| UX Stylesheet | ✅ Beschikbaar |
|
||||
|
||||
### Database Tabellen (uitgebreid)
|
||||
|
||||
| Tabel | Velden gebruikt | Nieuw? |
|
||||
|-------|-----------------|--------|
|
||||
| `nursing_logs` | id, patient_id, shift_date, timestamp, category, content, include_in_handover, created_by | ✅ Ja |
|
||||
| `observations` | id, patient_id, code_display, value_quantity_value, interpretation_code, effective_datetime | Bestaand |
|
||||
| `reports` | id, patient_id, type, content, created_at, created_by | Bestaand |
|
||||
| `risk_assessments` | id, intake_id, risk_type, risk_level, rationale, measures, assessment_date | Bestaand |
|
||||
| `conditions` | id, patient_id, code_display, clinical_status | Bestaand |
|
||||
| `patients` | id, name_given, name_family, birth_date, gender | Bestaand |
|
||||
| `encounters` | id, patient_id, period_start, type_display | Bestaand |
|
||||
|
||||
### Externe Referenties
|
||||
|
||||
| Bron | Gebruik |
|
||||
|------|---------|
|
||||
| shadcn/ui | Card, Button, Badge, Form components |
|
||||
| Lucide React | Icons (Pill, Utensils, User, AlertTriangle) |
|
||||
| Anthropic Claude API | AI samenvatting generatie |
|
||||
| Supabase RLS | Row-level security voor nursing_logs |
|
||||
|
||||
### UI Component Hergebruik
|
||||
|
||||
| Component | Locatie | Hergebruik voor |
|
||||
|-----------|---------|-----------------|
|
||||
| Quick Entry Form | Rapportage module | Nursing logs form |
|
||||
| Badge component | Risico's | Overdracht marker |
|
||||
| Card layout | Behandelplan | Informatie blokken |
|
||||
| AI Button | Behandelplan | Genereer samenvatting |
|
||||
|
||||
---
|
||||
|
||||
## Changelog
|
||||
|
||||
| Versie | Datum | Auteur | Wijziging |
|
||||
|--------|-------|--------|-----------|
|
||||
| v1.1 | 05-12-2024 | Colin | Dagregistratie module toegevoegd, nursing_logs tabel, uitgebreide flows |
|
||||
| v1.0 | 05-12-2024 | Colin | Initieel FO met focus op traceerbaarheid en bronvermelding |
|
||||
|
||||
---
|
||||
|
||||
**Einde Functioneel Ontwerp - Overdracht Dashboard v1.1**
|
||||
@@ -1,172 +0,0 @@
|
||||
# Verpleegkundige Overdracht Dashboard
|
||||
|
||||
## Implementatieplan
|
||||
|
||||
### Stap 1: PRD aanmaken
|
||||
Maak folder en PRD bestand:
|
||||
- `docs/specs/overdracht/prd-overdracht-dashboard-v1.md`
|
||||
|
||||
### Stap 2: Implementatie (na PRD)
|
||||
Zie technisch plan onderaan.
|
||||
|
||||
---
|
||||
|
||||
## PRD Content (te schrijven naar docs/specs/overdracht/prd-overdracht-dashboard-v1.md)
|
||||
|
||||
```markdown
|
||||
# 📄 Product Requirements Document (PRD) – Verpleegkundige Overdracht Dashboard
|
||||
|
||||
**Projectnaam:** Verpleegkundige Overdracht Dashboard
|
||||
**Versie:** v1.0
|
||||
**Datum:** 05-12-2024
|
||||
**Auteur:** Colin Lit
|
||||
|
||||
---
|
||||
|
||||
## 1. Doelstelling
|
||||
|
||||
Een dashboard voor verpleegkundigen die dagelijks meerdere overdrachten doen aan artsen. Het dashboard bundelt alle relevante patiëntinformatie (metingen, rapportages, medicatie, risico's) in overzichtelijke blokken en biedt een AI-functie om automatisch een beknopte overdracht-samenvatting te genereren.
|
||||
|
||||
**Focus:** Snelheid en efficiëntie - verpleegkundigen hebben weinig tijd en moeten snel de juiste informatie kunnen vinden en overdragen.
|
||||
|
||||
**Type:** MVP/Prototype met AI-integratie
|
||||
|
||||
---
|
||||
|
||||
## 2. Doelgroep
|
||||
|
||||
**Primaire gebruikers:**
|
||||
- **Verpleegkundigen (GGZ):** Doen ~6 overdrachten per dag aan artsen/collega's. Hebben behoefte aan snel overzicht van patiëntstatus, wijzigingen en aandachtspunten.
|
||||
|
||||
**Secundaire gebruikers:**
|
||||
- **Artsen:** Ontvangen de overdracht, willen beknopte maar complete informatie.
|
||||
- **Teamleiders:** Overzicht van alle patiënten en eventuele alerts.
|
||||
|
||||
**Kernbehoeften:**
|
||||
- Snel overzicht van alle patiënten die overgedragen moeten worden
|
||||
- Per patiënt: vitale functies, recente notities, medicatie, risico's
|
||||
- AI-hulp om overdracht samen te vatten in 30 seconden
|
||||
|
||||
---
|
||||
|
||||
## 3. Kernfunctionaliteiten (MVP-scope)
|
||||
|
||||
### 3.1 Niveau 1: Behandelaar Overzicht
|
||||
1. **Patiëntenlijst:** Grid van alle actieve patiënten met afspraken/encounters vandaag
|
||||
2. **Quick Stats per patiënt:** Naam, leeftijd, aantal alerts, recente activiteit
|
||||
3. **Filter op alerts:** Toon alleen patiënten met hoog risico of afwijkende metingen
|
||||
4. **Doorklik naar detail:** Navigatie naar patiënt-specifiek overdracht scherm
|
||||
|
||||
### 3.2 Niveau 2: Patiënt Detail
|
||||
5. **Informatieblokken:**
|
||||
- **Vitale functies:** Metingen van vandaag (bloeddruk, hartslag, temperatuur, O2, ademhaling)
|
||||
- **Rapportages:** Recente notities en observaties (laatste 24 uur)
|
||||
- **Medicatie:** Huidige medicatie en recente wijzigingen *(placeholder voor MVP)*
|
||||
- **Risico's:** Actieve risicotaxaties met ernst-niveau
|
||||
|
||||
6. **AI Samenvatting Blok:**
|
||||
- Eén compact blok met "Genereer samenvatting" knop
|
||||
- AI genereert beknopte overdracht op basis van alle informatieblokken
|
||||
- Output: samenvatting (max 3 zinnen) + aandachtspunten + actiepunten
|
||||
- Kan opnieuw gegenereerd worden bij nieuwe data
|
||||
|
||||
### 3.3 AI Integratie
|
||||
7. **Overdracht Generator:**
|
||||
- Input: vitals + reports + risks + diagnoses
|
||||
- Output: gestructureerde JSON met samenvatting, aandachtspunten, actiepunten
|
||||
- Taal: Nederlands, zakelijk, beknopt
|
||||
- Markering van urgente zaken met [URGENT]
|
||||
|
||||
---
|
||||
|
||||
## 4. Gebruikersflows
|
||||
|
||||
### Flow 1: Dagelijkse Overdracht
|
||||
1. Verpleegkundige opent Overdracht pagina
|
||||
2. Ziet grid van alle patiënten voor vandaag
|
||||
3. Filtert eventueel op "Met alerts"
|
||||
4. Klikt op patiënt voor detail view
|
||||
5. Bekijkt informatieblokken (vitals, reports, risico's)
|
||||
6. Klikt "Genereer samenvatting"
|
||||
7. AI maakt beknopte overdracht
|
||||
8. Verpleegkundige gebruikt samenvatting voor mondelinge/schriftelijke overdracht
|
||||
|
||||
### Flow 2: Snelle Check bij Alert
|
||||
1. Verpleegkundige ziet rode badge op patiënt-card (hoog risico)
|
||||
2. Klikt direct door naar detail
|
||||
3. Ziet welke vitale functies afwijkend zijn
|
||||
4. Checkt bijbehorende rapportages
|
||||
5. Neemt direct actie of escaleert
|
||||
|
||||
---
|
||||
|
||||
## 5. Niet in Scope
|
||||
|
||||
- **Medicatie-invoer:** Alleen weergave, geen CRUD (aparte module)
|
||||
- **Multi-afdeling view:** Alleen eigen patiënten
|
||||
- **Historische trends:** Geen grafieken of lange termijn overzichten
|
||||
- **Notificaties/push:** Geen realtime alerts
|
||||
- **Print/export:** Geen PDF of print functionaliteit
|
||||
- **Rechten per rol:** Geen onderscheid verpleegkundige/arts (komt later)
|
||||
|
||||
---
|
||||
|
||||
## 6. Succescriteria
|
||||
|
||||
- [ ] Overzicht laadt binnen 2 seconden
|
||||
- [ ] Patiënt detail toont alle 4 informatieblokken correct
|
||||
- [ ] AI samenvatting genereert binnen 5 seconden
|
||||
- [ ] AI output is begrijpelijk en medisch relevant
|
||||
- [ ] Navigatie tussen overzicht en detail werkt vlot
|
||||
- [ ] Alerts (hoog risico, afwijkende vitals) zijn direct zichtbaar
|
||||
|
||||
---
|
||||
|
||||
## 7. Risico's & Mitigatie
|
||||
|
||||
| Risico | Impact | Mitigatie |
|
||||
|--------|--------|-----------|
|
||||
| AI samenvatting te lang/vaag | Hoog | Strikte prompt met max lengte, testen met echte data |
|
||||
| Geen vitale functies in systeem | Middel | Graceful empty state, instructie om metingen toe te voegen |
|
||||
| Medicatie tabel bestaat niet | Middel | Placeholder blok met "Binnenkort beschikbaar" |
|
||||
| Performance bij veel patiënten | Middel | Parallel queries, pagination indien nodig |
|
||||
|
||||
---
|
||||
|
||||
## 8. Roadmap / Vervolg (Post-MVP)
|
||||
|
||||
- **Fase 2:** Medicatie module met volledige CRUD
|
||||
- **Fase 3:** Trend grafieken voor vitale functies over tijd
|
||||
- **Fase 4:** Export naar PDF voor formele overdracht
|
||||
- **Fase 5:** Integratie met agenda (koppeling encounters)
|
||||
- **Fase 6:** Notificaties bij kritieke waarden
|
||||
|
||||
---
|
||||
|
||||
## 9. Bijlagen & Referenties
|
||||
|
||||
- **Bestaande AI integratie:** `/app/api/behandelplan/generate/route.ts` (prompt pattern)
|
||||
- **Database schema:** `observations`, `reports`, `risk_assessments` tabellen
|
||||
- **UI componenten:** `/components/ui/ai-button.tsx`, Card components
|
||||
- **Gerelateerde docs:** `docs/specs/ai-integratie/`, `docs/design/datamodel-documentatie.md`
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Technisch Plan (na PRD goedkeuring)
|
||||
|
||||
### Route Structuur
|
||||
```
|
||||
/epd/overdracht/ → Level 1: Overzicht
|
||||
/epd/overdracht/[patientId] → Level 2: Detail
|
||||
```
|
||||
|
||||
### Te maken bestanden
|
||||
1. `docs/specs/overdracht/prd-overdracht-dashboard-v1.md` (PRD)
|
||||
2. `/lib/types/handover.ts` (types)
|
||||
3. `/app/epd/overdracht/actions.ts` (server actions)
|
||||
4. `/app/epd/overdracht/page.tsx` (overzicht)
|
||||
5. `/app/epd/overdracht/[patientId]/page.tsx` (detail)
|
||||
6. `/app/api/overdracht/generate/route.ts` (AI endpoint)
|
||||
7. `/components/overdracht/*.tsx` (UI componenten)
|
||||
8. Update `/app/epd/components/epd-sidebar.tsx` (navigatie)
|
||||
@@ -1,393 +0,0 @@
|
||||
# Overzicht Rapportage Modules
|
||||
|
||||
**Versie:** 1.0
|
||||
**Datum:** 07-12-2024
|
||||
**Status:** Actueel overzicht van de huidige implementatie
|
||||
|
||||
---
|
||||
|
||||
## 1. Drie Rapportage Modules
|
||||
|
||||
Het EPD heeft drie verschillende modules voor het vastleggen en delen van patiëntinformatie:
|
||||
|
||||
| Module | Doel | Gebruiker | Route |
|
||||
|--------|------|-----------|-------|
|
||||
| **Rapportage** | Behandelinhoudelijke verslagen (decursus) | Arts, behandelaar | `/epd/patients/[id]/rapportage` |
|
||||
| **Dagregistratie** | Operationele verpleegkundige notities | Verpleegkundige | `/epd/dagregistratie` |
|
||||
| **Overdracht** | Samenvatting voor dienstoverdracht | Verpleegkundige | `/epd/overdracht` |
|
||||
|
||||
---
|
||||
|
||||
## 2. Rapportage Module (Decursus)
|
||||
|
||||
### Doel
|
||||
Behandelinhoudelijke verslaglegging in het patiëntdossier. Dit is het "officiële" behandelverloop.
|
||||
|
||||
### Route
|
||||
`/epd/patients/[id]/rapportage`
|
||||
|
||||
### Kenmerken
|
||||
- Per patiënt (vanuit patiëntdossier)
|
||||
- Verschillende rapportage types: voortgang, observatie, evaluatie, etc.
|
||||
- Gestructureerde invoer met templates
|
||||
- Koppeling aan encounters/contactmomenten
|
||||
- Onderdeel van het medisch dossier
|
||||
- Spraak-naar-tekst ondersteuning
|
||||
|
||||
### UI Structuur
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Rapportage - [Patiëntnaam] │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ ┌─────────────────────┐ ┌─────────────────────────────────┐ │
|
||||
│ │ Quick Actions │ │ Composer │ │
|
||||
│ │ [Voortgang] │ │ Type: Voortgang │ │
|
||||
│ │ [Observatie] │ │ ┌─────────────────────────────┐ │ │
|
||||
│ │ [Evaluatie] │ │ │ Tekst invoer... │ │ │
|
||||
│ │ ... │ │ │ │ │ │
|
||||
│ └─────────────────────┘ │ └─────────────────────────────┘ │ │
|
||||
│ │ [Opslaan] │ │
|
||||
│ ┌─────────────────────┐ └─────────────────────────────────┘ │
|
||||
│ │ Timeline │ │
|
||||
│ │ ─────────────────── │ │
|
||||
│ │ 14:30 Voortgang │ │
|
||||
│ │ 10:15 Observatie │ │
|
||||
│ │ Gisteren │ │
|
||||
│ │ 16:00 Evaluatie │ │
|
||||
│ └─────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Data
|
||||
- Tabel: `reports`
|
||||
- Velden: `patient_id`, `type`, `content`, `encounter_id`, `created_at`, `created_by`
|
||||
|
||||
---
|
||||
|
||||
## 3. Dagregistratie Module (Nursing Logs)
|
||||
|
||||
### Doel
|
||||
Snelle operationele notities tijdens de dienst. Korte registraties van gebeurtenissen die niet in het behandelverloop horen maar wel relevant kunnen zijn voor overdracht.
|
||||
|
||||
### Routes
|
||||
| Route | Beschrijving |
|
||||
|-------|--------------|
|
||||
| `/epd/dagregistratie` | **Ronde-view** - Alle patiënten, snel wisselen |
|
||||
| `/epd/dagregistratie/[patientId]` | **Per patiënt** - Vanuit overdracht detail |
|
||||
|
||||
### Kenmerken
|
||||
- Korte notities (max 500 karakters)
|
||||
- Categorieën: Medicatie, ADL, Gedrag, Incident, Observatie
|
||||
- Tijdstip aanpasbaar
|
||||
- **Overdracht markering** - checkbox om te bepalen of notitie in overdracht komt
|
||||
- Periode selector (vandaag, gisteren, 3 dagen, 7 dagen)
|
||||
|
||||
### UI Structuur - Ronde View
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ [← Overdracht] [Periode: Vandaag ▼]│
|
||||
│ │
|
||||
│ Dagregistratie Ronde │
|
||||
│ Zaterdag 7 december 2024 • 3 patiënten │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ ┌───────────────────────────────────┐ ┌───────────────────┐ │
|
||||
│ │ Patiënt: [Jan de Vries (3) ▼] │ │ Ronde overzicht │ │
|
||||
│ │ │ │ ───────────────── │ │
|
||||
│ │ ┌─ Nieuwe notitie ──────────────┐ │ │ ● Jan de Vries 3 │ │
|
||||
│ │ │ [Med][ADL][Gedr][Inc][Obs] │ │ │ ○ Maria Jansen 1 │ │
|
||||
│ │ │ [09:30] [Notitie...] [+] │ │ │ ○ Piet Bakker — │ │
|
||||
│ │ │ [✓ Opnemen in overdracht] │ │ │ │ │
|
||||
│ │ └───────────────────────────────┘ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ ┌─ Notities vandaag (3) ────────┐ │ │ │ │
|
||||
│ │ │ 14:30 [Medicatie] Insuline ✓ │ │ │ │ │
|
||||
│ │ │ 12:00 [ADL] Hulp bij douchen │ │ │ │ │
|
||||
│ │ │ 09:15 [Observatie] Rustig │ │ │ │ │
|
||||
│ │ └───────────────────────────────┘ │ │ │ │
|
||||
│ └───────────────────────────────────┘ └───────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### UI Structuur - Per Patiënt
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ [← Terug naar patiënt] [Naar overdracht →] │
|
||||
│ │
|
||||
│ Dagregistratie [Periode: Vandaag ▼] │
|
||||
│ Jan de Vries (78 jaar) • zaterdag 7 december 2024 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ ┌─ Nieuwe notitie ────────────────────────────────────────┐ │
|
||||
│ │ Categorie: [Med] [ADL] [Gedrag] [Incident] [Observatie] │ │
|
||||
│ │ Tijdstip: [09:30 ▼] │ │
|
||||
│ │ Notitie: [......................................] │ │
|
||||
│ │ [✓ Opnemen in overdracht] [+ Toevoegen] │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ Samenvatting ──────────────────────────────────────────┐ │
|
||||
│ │ [3] Notities [1] Voor overdracht [0] Incidenten │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ Notities (3) ──────────────────────────────────────────┐ │
|
||||
│ │ 14:30 [Medicatie] Insuline toegediend ✓ [✎][🗑] │ │
|
||||
│ │ 12:00 [ADL] Hulp bij douchen [✎][🗑] │ │
|
||||
│ │ 09:15 [Observatie] Rustige nacht gehad [✎][🗑] │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Data
|
||||
- Tabel: `nursing_logs`
|
||||
- Velden: `patient_id`, `category`, `content`, `timestamp`, `shift_date`, `include_in_handover`, `created_by`
|
||||
|
||||
---
|
||||
|
||||
## 4. Overdracht Module
|
||||
|
||||
### Doel
|
||||
Gestructureerd overzicht voor dienstoverdracht. Combineert informatie uit verschillende bronnen tot een samenvatting.
|
||||
|
||||
### Routes
|
||||
| Route | Beschrijving |
|
||||
|-------|--------------|
|
||||
| `/epd/overdracht` | Overzicht alle patiënten met activiteit |
|
||||
| `/epd/overdracht/[patientId]` | Detail per patiënt met AI-samenvatting |
|
||||
|
||||
### Kenmerken
|
||||
- Automatisch overzicht van patiënten met recente activiteit
|
||||
- Alert badges (hoog risico, afwijkende vitals, gemarkeerde notities)
|
||||
- Informatie blokken: Vitals, Rapportages, Dagnotities, Risico's
|
||||
- **AI-gegenereerde samenvatting** met bronverwijzingen
|
||||
|
||||
### UI Structuur - Overzicht
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Overdracht [Dagregistratie →] │
|
||||
│ Zaterdag 7 december 2024 • 3 patiënten │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ Jan de Vries │ │ Maria Jansen │ │ Piet Bakker │ │
|
||||
│ │ 78 jaar, M │ │ 65 jaar, V │ │ 82 jaar, M │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ [⚠ 1 hoog] │ │ [1 notitie] │ │ [2 afwijkend] │ │
|
||||
│ │ [2 afwijkend] │ │ │ │ │ │
|
||||
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### UI Structuur - Detail
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ [← Terug naar overzicht] [Dagregistratie →]│
|
||||
│ │
|
||||
│ Jan de Vries [⚠ 1 hoog] [2 afwijkend] │
|
||||
│ 78 jaar • Man • Diabetes Mellitus │
|
||||
│ Overdracht voor zaterdag 7 december │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ ┌─────────────────────────────────┐ ┌─────────────────────┐ │
|
||||
│ │ Vitale functies │ │ AI Samenvatting │ │
|
||||
│ │ ─────────────────────────── │ │ ─────────────────── │ │
|
||||
│ │ Bloeddruk: 145/92 ⚠ Hoog │ │ [Genereer] │ │
|
||||
│ │ Pols: 78 │ │ │ │
|
||||
│ │ Temp: 37.2 │ │ Of gegenereerde │ │
|
||||
│ │ Glucose: 12.4 ⚠ Hoog │ │ samenvatting met │ │
|
||||
│ ├─────────────────────────────────┤ │ bronverwijzingen │ │
|
||||
│ │ Rapportages (24u) │ │ │ │
|
||||
│ │ ─────────────────────────── │ │ [1] Vitals │ │
|
||||
│ │ 14:00 Voortgangsrapportage │ │ [2] Rapportage │ │
|
||||
│ │ 10:30 Observatie arts │ │ [3] Dagnotitie │ │
|
||||
│ ├─────────────────────────────────┤ │ │ │
|
||||
│ │ Dagnotities (overdracht) │ │ │ │
|
||||
│ │ ─────────────────────────── │ │ │ │
|
||||
│ │ 14:30 [Med] Insuline ✓ │ │ │ │
|
||||
│ │ + 2 andere (niet gemarkeerd) │ │ │ │
|
||||
│ ├─────────────────────────────────┤ │ │ │
|
||||
│ │ Risico's │ │ │ │
|
||||
│ │ ─────────────────────────── │ │ │ │
|
||||
│ │ Valrisico: HOOG │ │ │ │
|
||||
│ │ Decubitus: Laag │ │ │ │
|
||||
│ └─────────────────────────────────┘ └─────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Data bronnen
|
||||
- `observations` (vitals)
|
||||
- `reports` (behandelrapportages)
|
||||
- `nursing_logs` (dagnotities met `include_in_handover = true`)
|
||||
- `risk_assessments` (risico's)
|
||||
- `conditions` (diagnoses)
|
||||
|
||||
---
|
||||
|
||||
## 5. Samenhang en Dataflow
|
||||
|
||||
### Hoe de modules samenwerken
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ INVOER │
|
||||
├──────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Rapportage Module Dagregistratie Module │
|
||||
│ /epd/patients/[id]/rapportage /epd/dagregistratie │
|
||||
│ ┌─────────────────────┐ ┌─────────────────────┐ │
|
||||
│ │ Behandelverslagen │ │ Operationele notities│ │
|
||||
│ │ - Voortgang │ │ - Medicatie │ │
|
||||
│ │ - Observatie │ │ - ADL │ │
|
||||
│ │ - Evaluatie │ │ - Gedrag │ │
|
||||
│ │ - Consult │ │ - Incident │ │
|
||||
│ └──────────┬──────────┘ │ - Observatie │ │
|
||||
│ │ └──────────┬───────────┘ │
|
||||
│ │ │ │
|
||||
│ │ ┌───────────────────────────┘ │
|
||||
│ │ │ [✓ Opnemen in overdracht] │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
├──────────────────────────────────────────────────────────────────┤
|
||||
│ UITVOER │
|
||||
├──────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Overdracht Module │
|
||||
│ /epd/overdracht/[patientId] │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
||||
│ │ │ Vitals │ │ Rapportages │ │ Dagnotities │ │ │
|
||||
│ │ │ (24u) │ │ (24u) │ │ (gemarkeerd)│ │ │
|
||||
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│ │ └───────────────┼───────────────┘ │ │
|
||||
│ │ ▼ │ │
|
||||
│ │ ┌─────────────────────┐ │ │
|
||||
│ │ │ AI Samenvatting │ │ │
|
||||
│ │ │ met bronnen [1-n] │ │ │
|
||||
│ │ └─────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Verschil Rapportage vs Dagregistratie
|
||||
|
||||
| Aspect | Rapportage | Dagregistratie |
|
||||
|--------|------------|----------------|
|
||||
| **Doel** | Behandelverloop (decursus) | Operationele registratie |
|
||||
| **Lengte** | Lang, gedetailleerd | Kort (max 500 chars) |
|
||||
| **Invoer** | Per patiënt | Per patiënt of ronde |
|
||||
| **Structuur** | Rapportage types | Categorieën |
|
||||
| **In overdracht** | Automatisch (24u) | Alleen als gemarkeerd |
|
||||
| **Medisch dossier** | Ja | Nee (operationeel) |
|
||||
| **Spraak-invoer** | Ja | Nee |
|
||||
|
||||
### Navigatie tussen modules
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ /epd/overdracht │
|
||||
│ (Patiëntenlijst) │
|
||||
└─────────┬───────────┘
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────────┐ ┌─────────────┐ ┌─────────────────┐
|
||||
│ /epd/overdracht │ │ /epd/dag- │ │ /epd/patients/ │
|
||||
│ /[patientId] │ │ registratie │ │ [id]/rapportage │
|
||||
│ (Detail) │ │ (Ronde) │ │ (Decursus) │
|
||||
└────────┬────────┘ └──────┬──────┘ └─────────────────┘
|
||||
│ │
|
||||
│ ┌────────────┘
|
||||
▼ ▼
|
||||
┌─────────────────────┐
|
||||
│ /epd/dagregistratie │
|
||||
│ /[patientId] │
|
||||
│ (Per patiënt) │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Componenten Overzicht
|
||||
|
||||
### Rapportage Module
|
||||
| Component | Bestand | Functie |
|
||||
|-----------|---------|---------|
|
||||
| `RapportageWorkspaceV2` | `rapportage-workspace-v2.tsx` | Hoofdcontainer met panels |
|
||||
| `ReportComposer` | `report-composer.tsx` | Invoer nieuwe rapportage |
|
||||
| `QuickActions` | `quick-actions.tsx` | Type selectie knoppen |
|
||||
| `ReportTimeline` | `report-timeline.tsx` | Tijdlijn van rapportages |
|
||||
| `ReportViewEditModal` | `report-view-edit-modal.tsx` | Bekijk/bewerk modal |
|
||||
|
||||
### Dagregistratie Module
|
||||
| Component | Bestand | Functie |
|
||||
|-----------|---------|---------|
|
||||
| `DagregistratieWorkspace` | `dagregistratie-workspace.tsx` | Ronde-view container |
|
||||
| `PatientSelector` | `patient-selector.tsx` | Patiënt dropdown |
|
||||
| `RondeOverview` | `ronde-overview.tsx` | Overzicht sidebar |
|
||||
| `LogForm` | `log-form.tsx` | Notitie invoer |
|
||||
| `LogList` | `log-list.tsx` | Notities lijst |
|
||||
| `PeriodSelector` | `period-selector.tsx` | Periode dropdown |
|
||||
|
||||
### Overdracht Module
|
||||
| Component | Bestand | Functie |
|
||||
|-----------|---------|---------|
|
||||
| `PatientGrid` | `patient-grid.tsx` | Patiënten kaarten grid |
|
||||
| `PatientCard` | `patient-card.tsx` | Individuele patiënt kaart |
|
||||
| `VitalsBlock` | `vitals-block.tsx` | Vitale functies blok |
|
||||
| `ReportsBlock` | `reports-block.tsx` | Rapportages blok |
|
||||
| `NursingLogsBlock` | `nursing-logs-block.tsx` | Dagnotities blok |
|
||||
| `RisksBlock` | `risks-block.tsx` | Risico's blok |
|
||||
| `AISummaryBlock` | `ai-summary-block.tsx` | AI samenvatting |
|
||||
|
||||
---
|
||||
|
||||
## 7. API Endpoints
|
||||
|
||||
| Endpoint | Methode | Module | Functie |
|
||||
|----------|---------|--------|---------|
|
||||
| `/api/reports` | GET, POST | Rapportage | CRUD rapportages |
|
||||
| `/api/reports/[id]` | GET, PATCH, DELETE | Rapportage | Specifieke rapportage |
|
||||
| `/api/nursing-logs` | GET, POST | Dagregistratie | CRUD nursing logs |
|
||||
| `/api/nursing-logs/[id]` | PATCH, DELETE | Dagregistratie | Specifieke log |
|
||||
| `/api/overdracht/patients` | GET | Overdracht | Patiënten met activiteit |
|
||||
| `/api/overdracht/[patientId]` | GET | Overdracht | Detail data |
|
||||
| `/api/overdracht/generate` | POST | Overdracht | AI samenvatting |
|
||||
|
||||
---
|
||||
|
||||
## 8. Database Tabellen
|
||||
|
||||
### reports
|
||||
```sql
|
||||
- id: uuid
|
||||
- patient_id: uuid (FK)
|
||||
- encounter_id: uuid (FK, nullable)
|
||||
- type: text (voortgang, observatie, evaluatie, etc.)
|
||||
- content: text
|
||||
- created_at: timestamptz
|
||||
- created_by: uuid (FK)
|
||||
- deleted_at: timestamptz (soft delete)
|
||||
```
|
||||
|
||||
### nursing_logs
|
||||
```sql
|
||||
- id: uuid
|
||||
- patient_id: uuid (FK)
|
||||
- category: text (medicatie, adl, gedrag, incident, observatie)
|
||||
- content: text (max 500)
|
||||
- timestamp: timestamptz
|
||||
- shift_date: date (voor filtering)
|
||||
- include_in_handover: boolean
|
||||
- created_by: uuid (FK)
|
||||
- created_at: timestamptz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Openstaande Punten
|
||||
|
||||
1. **Ronde/caseload**: Geen mechanisme om "mijn patiënten" te definiëren
|
||||
2. **Autorisatie**: Alle gebruikers zien alle patiënten
|
||||
3. **Afdelingen**: Geen afdeling/groep structuur
|
||||
4. **Archivering**: Geen archivering van oude nursing logs
|
||||
5. **Spraak-invoer**: Alleen bij rapportage, niet bij dagregistratie
|
||||
@@ -1,197 +0,0 @@
|
||||
# 📄 Product Requirements Document (PRD) – Verpleegkundige Overdracht Dashboard
|
||||
|
||||
**Projectnaam:** Verpleegkundige Overdracht Dashboard
|
||||
**Versie:** v1.0
|
||||
**Datum:** 05-12-2024
|
||||
**Auteur:** Colin Lit
|
||||
|
||||
---
|
||||
|
||||
## 1. Doelstelling
|
||||
|
||||
🎯 **Doel:** Een dashboard voor verpleegkundigen die dagelijks meerdere overdrachten doen aan artsen. Het dashboard bundelt alle relevante patiëntinformatie (metingen, rapportages, medicatie, risico's) in overzichtelijke blokken en biedt een AI-functie om automatisch een beknopte overdracht-samenvatting te genereren.
|
||||
|
||||
**Focus:** Snelheid en efficiëntie - verpleegkundigen hebben weinig tijd en moeten snel de juiste informatie kunnen vinden en overdragen.
|
||||
|
||||
**Type:** MVP/Prototype met AI-integratie
|
||||
|
||||
> Een verpleegkundige doet gemiddeld 6 overdrachten per dag aan artsen. Met dit dashboard kan zij in 30 seconden een complete overdracht genereren, inclusief AI-samenvatting met aandachtspunten en actiepunten.
|
||||
|
||||
---
|
||||
|
||||
## 2. Doelgroep
|
||||
|
||||
🎯 **Doel:** Schets wie de eindgebruikers, stakeholders en testers zijn.
|
||||
|
||||
**Primaire gebruikers:**
|
||||
- **Verpleegkundigen (GGZ):** Doen ~6 overdrachten per dag aan artsen/collega's. Hebben behoefte aan snel overzicht van patiëntstatus, wijzigingen en aandachtspunten.
|
||||
|
||||
**Secundaire gebruikers:**
|
||||
- **Artsen:** Ontvangen de overdracht, willen beknopte maar complete informatie.
|
||||
- **Teamleiders:** Overzicht van alle patiënten en eventuele alerts.
|
||||
|
||||
**Kernbehoeften:**
|
||||
- Snel overzicht van alle patiënten die overgedragen moeten worden
|
||||
- Per patiënt: vitale functies, recente notities, medicatie, risico's
|
||||
- AI-hulp om overdracht samen te vatten in 30 seconden
|
||||
|
||||
---
|
||||
|
||||
## 3. Kernfunctionaliteiten (MVP-scope)
|
||||
|
||||
🎯 **Doel:** Afbakenen van de minimale werkende functies.
|
||||
|
||||
### 3.1 Niveau 1: Behandelaar Overzicht (`/epd/overdracht/`)
|
||||
|
||||
| # | Functie | Beschrijving |
|
||||
|---|---------|--------------|
|
||||
| 1 | **Patiëntenlijst** | Grid van alle actieve patiënten met afspraken/encounters vandaag |
|
||||
| 2 | **Quick Stats per patiënt** | Naam, leeftijd, aantal alerts, recente activiteit |
|
||||
| 3 | **Filter op alerts** | Toon alleen patiënten met hoog risico of afwijkende metingen |
|
||||
| 4 | **Doorklik naar detail** | Navigatie naar patiënt-specifiek overdracht scherm |
|
||||
|
||||
### 3.2 Niveau 2: Patiënt Detail (`/epd/overdracht/[patientId]`)
|
||||
|
||||
| # | Functie | Beschrijving |
|
||||
|---|---------|--------------|
|
||||
| 5 | **Vitale functies blok** | Metingen van vandaag (bloeddruk, hartslag, temperatuur, O2, ademhaling) |
|
||||
| 6 | **Rapportages blok** | Recente notities en observaties (laatste 24 uur) |
|
||||
| 7 | **Medicatie blok** | Huidige medicatie en recente wijzigingen *(placeholder voor MVP)* |
|
||||
| 8 | **Risico's blok** | Actieve risicotaxaties met ernst-niveau |
|
||||
| 9 | **AI Samenvatting blok** | Compact blok met "Genereer samenvatting" knop |
|
||||
|
||||
### 3.3 AI Integratie
|
||||
|
||||
| # | Functie | Beschrijving |
|
||||
|---|---------|--------------|
|
||||
| 10 | **Overdracht Generator** | AI genereert beknopte overdracht op basis van alle informatieblokken |
|
||||
| 11 | **Gestructureerde output** | Samenvatting (max 3 zinnen) + aandachtspunten + actiepunten |
|
||||
| 12 | **Urgentie markering** | Urgente zaken gemarkeerd met [URGENT] |
|
||||
|
||||
---
|
||||
|
||||
## 4. Gebruikersflows (Demo- of MVP-flows)
|
||||
|
||||
🎯 **Doel:** Laten zien hoe de gebruiker stap-voor-stap door het systeem gaat.
|
||||
|
||||
### Flow 1: Dagelijkse Overdracht
|
||||
|
||||
```
|
||||
1. Verpleegkundige opent Overdracht pagina
|
||||
2. Ziet grid van alle patiënten voor vandaag
|
||||
3. Filtert eventueel op "Met alerts"
|
||||
4. Klikt op patiënt voor detail view
|
||||
5. Bekijkt informatieblokken (vitals, reports, risico's)
|
||||
6. Klikt "Genereer samenvatting"
|
||||
7. AI maakt beknopte overdracht
|
||||
8. Verpleegkundige gebruikt samenvatting voor mondelinge/schriftelijke overdracht
|
||||
```
|
||||
|
||||
### Flow 2: Snelle Check bij Alert
|
||||
|
||||
```
|
||||
1. Verpleegkundige ziet rode badge op patiënt-card (hoog risico)
|
||||
2. Klikt direct door naar detail
|
||||
3. Ziet welke vitale functies afwijkend zijn
|
||||
4. Checkt bijbehorende rapportages
|
||||
5. Neemt direct actie of escaleert
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Niet in Scope
|
||||
|
||||
🎯 **Doel:** Duidelijk maken wat (nog) niet wordt gebouwd.
|
||||
|
||||
| Feature | Reden exclusie |
|
||||
|---------|----------------|
|
||||
| Medicatie-invoer | Alleen weergave, CRUD is aparte module |
|
||||
| Multi-afdeling view | Te complex voor MVP, alleen eigen patiënten |
|
||||
| Historische trends | Geen grafieken of lange termijn overzichten |
|
||||
| Notificaties/push | Geen realtime alerts |
|
||||
| Print/export | Geen PDF of print functionaliteit |
|
||||
| Rechten per rol | Geen onderscheid verpleegkundige/arts (komt later) |
|
||||
| Metingen invoer | Aparte functionaliteit, hier alleen weergave |
|
||||
|
||||
---
|
||||
|
||||
## 6. Succescriteria
|
||||
|
||||
🎯 **Doel:** Objectieve meetlat voor een geslaagde oplevering.
|
||||
|
||||
- [ ] Overzicht laadt binnen 2 seconden
|
||||
- [ ] Patiënt detail toont alle 4 informatieblokken correct
|
||||
- [ ] AI samenvatting genereert binnen 5 seconden
|
||||
- [ ] AI output is begrijpelijk en medisch relevant
|
||||
- [ ] Navigatie tussen overzicht en detail werkt vlot
|
||||
- [ ] Alerts (hoog risico, afwijkende vitals) zijn direct zichtbaar
|
||||
- [ ] Empty states bij ontbrekende data zijn informatief
|
||||
|
||||
---
|
||||
|
||||
## 7. Risico's & Mitigatie
|
||||
|
||||
🎯 **Doel:** Risico's vroeg signaleren en plannen hoe ermee om te gaan.
|
||||
|
||||
| Risico | Impact | Mitigatie |
|
||||
|--------|--------|-----------|
|
||||
| AI samenvatting te lang/vaag | Hoog | Strikte prompt met max lengte, testen met echte data |
|
||||
| Geen vitale functies in systeem | Middel | Graceful empty state, instructie om metingen toe te voegen |
|
||||
| Medicatie tabel bestaat niet | Middel | Placeholder blok met "Binnenkort beschikbaar" |
|
||||
| Performance bij veel patiënten | Middel | Parallel queries, pagination indien nodig |
|
||||
| Risico's gekoppeld aan intake ipv patient | Laag | Query via intake tabel |
|
||||
|
||||
---
|
||||
|
||||
## 8. Roadmap / Vervolg (Post-MVP)
|
||||
|
||||
🎯 **Doel:** Richting geven aan toekomstige uitbreidingen.
|
||||
|
||||
| Fase | Feature | Beschrijving |
|
||||
|------|---------|--------------|
|
||||
| 2 | Medicatie module | Volledige CRUD voor medicatie |
|
||||
| 3 | Trend grafieken | Vitale functies over tijd |
|
||||
| 4 | PDF export | Formele overdracht documenten |
|
||||
| 5 | Agenda integratie | Koppeling met encounters/afspraken |
|
||||
| 6 | Notificaties | Alerts bij kritieke waarden |
|
||||
| 7 | Multi-afdeling | Overzicht meerdere afdelingen |
|
||||
|
||||
---
|
||||
|
||||
## 9. Bijlagen & Referenties
|
||||
|
||||
🎯 **Doel:** Bronnen koppelen voor context en consistentie.
|
||||
|
||||
### Bestaande Code Patterns
|
||||
|
||||
| Pattern | Locatie | Hergebruik voor |
|
||||
|---------|---------|-----------------|
|
||||
| AI integratie | `/app/api/behandelplan/generate/route.ts` | Overdracht generator |
|
||||
| Server actions | `/app/epd/patients/[id]/behandelplan/actions.ts` | Data fetching |
|
||||
| Card components | `/components/ui/card.tsx` | Informatieblokken |
|
||||
| AI Button | `/components/ui/ai-button.tsx` | Genereer knop |
|
||||
|
||||
### Database Tabellen
|
||||
|
||||
| Tabel | Gebruik |
|
||||
|-------|---------|
|
||||
| `observations` | Vitale functies (FHIR-compliant) |
|
||||
| `reports` | Rapportages/notities |
|
||||
| `risk_assessments` | Risico's (via intakes) |
|
||||
| `conditions` | Diagnoses |
|
||||
| `patients`, `encounters` | Basis data |
|
||||
|
||||
### Gerelateerde Documentatie
|
||||
|
||||
- FO (Functioneel Ontwerp) – *nog te schrijven*
|
||||
- TO (Technisch Ontwerp) – *nog te schrijven*
|
||||
- `docs/specs/ai-integratie/` – AI prompt patterns
|
||||
- `docs/design/datamodel-documentatie.md` – Database schema
|
||||
|
||||
---
|
||||
|
||||
## Changelog
|
||||
|
||||
| Versie | Datum | Auteur | Wijziging |
|
||||
|--------|-------|--------|-----------|
|
||||
| v1.0 | 05-12-2024 | Colin | Initieel PRD |
|
||||
@@ -1,806 +0,0 @@
|
||||
# Technisch Ontwerp (TO) - Verpleegkundige Overdracht Dashboard
|
||||
|
||||
**Projectnaam:** Verpleegkundige Overdracht Dashboard
|
||||
**Versie:** v1.0
|
||||
**Datum:** 05-12-2024
|
||||
**Auteur:** Claude (AI-assisted)
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en relatie met PRD en FO
|
||||
|
||||
**Doel van dit document:**
|
||||
Dit Technisch Ontwerp beschrijft **hoe** het Overdracht Dashboard technisch wordt gebouwd. Het vertaalt de functionele specificaties uit FO v1.1 naar concrete technische implementatie.
|
||||
|
||||
**Relatie met andere documenten:**
|
||||
- PRD: `prd-overdracht-dashboard-v1.md` - wat en waarom
|
||||
- FO: `fo-overdracht-dashboard-v1.1.md` - hoe functioneel
|
||||
- TO: dit document - hoe technisch
|
||||
|
||||
**Technische haalbaarheidsanalyse:**
|
||||
| Aspect | Status | Toelichting |
|
||||
|--------|--------|-------------|
|
||||
| Database tabellen | Deels aanwezig | patients, encounters, observations, reports, risk_assessments, conditions aanwezig. nursing_logs moet worden toegevoegd |
|
||||
| Frontend framework | Aanwezig | Next.js 15 App Router met EPD layout |
|
||||
| UI componenten | Aanwezig | shadcn/ui (Card, Button, Badge, Dialog, etc.) |
|
||||
| AI integratie | Aanwezig | Claude API via behandelplan/generate pattern |
|
||||
| Authentication | Aanwezig | Supabase Auth met RLS |
|
||||
|
||||
---
|
||||
|
||||
## 2. Technische Architectuur Overzicht
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ Frontend (Next.js 15) │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ /epd/overdracht/ /epd/dagregistratie/[patientId] │
|
||||
│ ├── page.tsx ├── page.tsx │
|
||||
│ │ (Overzicht Grid) │ (Dagregistratie Module) │
|
||||
│ │ │ │
|
||||
│ └── [patientId]/ └── components/ │
|
||||
│ └── page.tsx ├── log-list.tsx │
|
||||
│ (Patiënt Detail) ├── log-form.tsx │
|
||||
│ └── log-card.tsx │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ API Routes (Next.js) │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ /api/overdracht/ │
|
||||
│ ├── patients/route.ts GET - Patiënten voor vandaag │
|
||||
│ ├── [patientId]/route.ts GET - Detail data voor patiënt │
|
||||
│ └── generate/route.ts POST - AI samenvatting genereren │
|
||||
│ │
|
||||
│ /api/nursing-logs/ │
|
||||
│ ├── route.ts GET/POST - CRUD nursing logs │
|
||||
│ └── [logId]/route.ts PATCH/DELETE - Update/delete log │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ Database (Supabase) │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Bestaand: Nieuw: │
|
||||
│ ├── patients ├── nursing_logs │
|
||||
│ ├── encounters │ │
|
||||
│ ├── observations │ │
|
||||
│ ├── reports │ │
|
||||
│ ├── risk_assessments │ │
|
||||
│ ├── conditions │ │
|
||||
│ ├── intakes │ │
|
||||
│ └── ai_events │ │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ External Services │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Claude API (Anthropic) AI samenvatting generatie │
|
||||
│ Supabase Auth Session-based authentication │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Techstack Selectie
|
||||
|
||||
| Component | Technologie | Argumentatie | Bestaand |
|
||||
|-----------|-------------|--------------|----------|
|
||||
| Frontend | Next.js 15 (App Router) | Bestaande codebase, SSR, TypeScript | Ja |
|
||||
| Backend | Next.js API Routes | Co-located met frontend | Ja |
|
||||
| Database | Supabase (PostgreSQL) | Realtime, auth included, RLS | Ja |
|
||||
| AI | Claude claude-sonnet-4-20250514 | Bestaande integratie, Nederlands | Ja |
|
||||
| Styling | TailwindCSS + shadcn/ui | Bestaande componenten | Ja |
|
||||
| Validation | Zod | Type-safe validatie, bestaand pattern | Ja |
|
||||
| State | React Server Components + Client | Minimale client state | Ja |
|
||||
|
||||
---
|
||||
|
||||
## 4. Datamodel
|
||||
|
||||
### 4.1 Nieuwe Tabel: nursing_logs
|
||||
|
||||
```sql
|
||||
-- Migratie: create_nursing_logs_table
|
||||
CREATE TABLE public.nursing_logs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
patient_id UUID NOT NULL REFERENCES patients(id) ON DELETE CASCADE,
|
||||
|
||||
-- Timing
|
||||
shift_date DATE NOT NULL,
|
||||
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
|
||||
-- Content
|
||||
category TEXT NOT NULL CHECK (category IN (
|
||||
'medicatie', 'adl', 'gedrag', 'incident', 'observatie'
|
||||
)),
|
||||
content TEXT NOT NULL CHECK (char_length(content) <= 500),
|
||||
|
||||
-- Overdracht markering
|
||||
include_in_handover BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
-- Metadata
|
||||
created_by UUID NOT NULL REFERENCES auth.users(id),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Indexes voor performance
|
||||
CREATE INDEX idx_nursing_logs_patient ON nursing_logs(patient_id);
|
||||
CREATE INDEX idx_nursing_logs_shift ON nursing_logs(shift_date);
|
||||
CREATE INDEX idx_nursing_logs_handover ON nursing_logs(patient_id, include_in_handover)
|
||||
WHERE include_in_handover = true;
|
||||
CREATE INDEX idx_nursing_logs_timestamp ON nursing_logs(patient_id, timestamp DESC);
|
||||
|
||||
-- Updated_at trigger
|
||||
CREATE OR REPLACE FUNCTION update_nursing_logs_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER nursing_logs_updated_at
|
||||
BEFORE UPDATE ON nursing_logs
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_nursing_logs_updated_at();
|
||||
|
||||
-- Comments
|
||||
COMMENT ON TABLE nursing_logs IS
|
||||
'Operationele verpleegkundige dagregistraties - kort, snel, met overdracht-markering';
|
||||
COMMENT ON COLUMN nursing_logs.shift_date IS
|
||||
'Datum van de dienst (voor filtering per dag)';
|
||||
COMMENT ON COLUMN nursing_logs.include_in_handover IS
|
||||
'True als deze notitie relevant is voor overdracht';
|
||||
```
|
||||
|
||||
### 4.2 RLS Policies voor nursing_logs
|
||||
|
||||
```sql
|
||||
-- Enable RLS
|
||||
ALTER TABLE nursing_logs ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Policy: Authenticated users kunnen lezen
|
||||
CREATE POLICY "nursing_logs_select_authenticated" ON nursing_logs
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (true);
|
||||
|
||||
-- Policy: Authenticated users kunnen inserten
|
||||
CREATE POLICY "nursing_logs_insert_authenticated" ON nursing_logs
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (created_by = auth.uid());
|
||||
|
||||
-- Policy: Eigen logs kunnen updaten
|
||||
CREATE POLICY "nursing_logs_update_own" ON nursing_logs
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (created_by = auth.uid())
|
||||
WITH CHECK (created_by = auth.uid());
|
||||
|
||||
-- Policy: Eigen logs kunnen deleten
|
||||
CREATE POLICY "nursing_logs_delete_own" ON nursing_logs
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (created_by = auth.uid());
|
||||
```
|
||||
|
||||
### 4.3 TypeScript Types
|
||||
|
||||
```typescript
|
||||
// lib/types/nursing-log.ts
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
export const NursingLogCategory = z.enum([
|
||||
'medicatie',
|
||||
'adl',
|
||||
'gedrag',
|
||||
'incident',
|
||||
'observatie'
|
||||
]);
|
||||
|
||||
export type NursingLogCategory = z.infer<typeof NursingLogCategory>;
|
||||
|
||||
export const NursingLogSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
patient_id: z.string().uuid(),
|
||||
shift_date: z.string(), // ISO date
|
||||
timestamp: z.string(), // ISO datetime
|
||||
category: NursingLogCategory,
|
||||
content: z.string().min(1).max(500),
|
||||
include_in_handover: z.boolean(),
|
||||
created_by: z.string().uuid(),
|
||||
created_at: z.string(),
|
||||
updated_at: z.string(),
|
||||
});
|
||||
|
||||
export type NursingLog = z.infer<typeof NursingLogSchema>;
|
||||
|
||||
export const CreateNursingLogSchema = z.object({
|
||||
patient_id: z.string().uuid(),
|
||||
category: NursingLogCategory,
|
||||
content: z.string().min(1).max(500),
|
||||
timestamp: z.string().optional(), // Default: now
|
||||
include_in_handover: z.boolean().default(false),
|
||||
});
|
||||
|
||||
export type CreateNursingLog = z.infer<typeof CreateNursingLogSchema>;
|
||||
|
||||
export const UpdateNursingLogSchema = z.object({
|
||||
category: NursingLogCategory.optional(),
|
||||
content: z.string().min(1).max(500).optional(),
|
||||
timestamp: z.string().optional(),
|
||||
include_in_handover: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type UpdateNursingLog = z.infer<typeof UpdateNursingLogSchema>;
|
||||
|
||||
// Category display mapping
|
||||
export const CATEGORY_CONFIG: Record<NursingLogCategory, {
|
||||
label: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
}> = {
|
||||
medicatie: { label: 'Medicatie', icon: 'Pill', color: 'blue' },
|
||||
adl: { label: 'ADL/verzorging', icon: 'Utensils', color: 'green' },
|
||||
gedrag: { label: 'Gedragsobservatie', icon: 'User', color: 'purple' },
|
||||
incident: { label: 'Incident', icon: 'AlertTriangle', color: 'red' },
|
||||
observatie: { label: 'Algemene observatie', icon: 'FileText', color: 'gray' },
|
||||
};
|
||||
```
|
||||
|
||||
### 4.4 Bestaande Tabellen (queries)
|
||||
|
||||
```typescript
|
||||
// Overdracht context queries
|
||||
|
||||
// 1. Patiënten voor vandaag (via actieve encounters)
|
||||
const patientsToday = supabase
|
||||
.from('encounters')
|
||||
.select(`
|
||||
patient_id,
|
||||
patients!inner (
|
||||
id, name_given, name_family, birth_date, gender
|
||||
)
|
||||
`)
|
||||
.gte('period_start', todayStart)
|
||||
.lte('period_start', todayEnd)
|
||||
.in('status', ['planned', 'in-progress']);
|
||||
|
||||
// 2. Vitale functies (observations) vandaag
|
||||
const vitalsToday = supabase
|
||||
.from('observations')
|
||||
.select('*')
|
||||
.eq('patient_id', patientId)
|
||||
.eq('category', 'vital-signs')
|
||||
.gte('effective_datetime', todayStart)
|
||||
.order('effective_datetime', { ascending: false });
|
||||
|
||||
// 3. Rapportages laatste 24 uur
|
||||
const reportsLast24h = supabase
|
||||
.from('reports')
|
||||
.select('*')
|
||||
.eq('patient_id', patientId)
|
||||
.gte('created_at', last24h)
|
||||
.is('deleted_at', null)
|
||||
.order('created_at', { ascending: false });
|
||||
|
||||
// 4. Actieve risico's (via intake)
|
||||
const activeRisks = supabase
|
||||
.from('risk_assessments')
|
||||
.select(`
|
||||
*,
|
||||
intakes!inner (patient_id)
|
||||
`)
|
||||
.eq('intakes.patient_id', patientId)
|
||||
.in('risk_level', ['hoog', 'zeer_hoog', 'gemiddeld']);
|
||||
|
||||
// 5. Actieve diagnoses
|
||||
const activeConditions = supabase
|
||||
.from('conditions')
|
||||
.select('*')
|
||||
.eq('patient_id', patientId)
|
||||
.eq('clinical_status', 'active');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. API Ontwerp
|
||||
|
||||
### 5.1 Overdracht Endpoints
|
||||
|
||||
| Endpoint | Method | Input | Output | Auth |
|
||||
|----------|--------|-------|--------|------|
|
||||
| `/api/overdracht/patients` | GET | `?date=YYYY-MM-DD` | `PatientOverzicht[]` | Required |
|
||||
| `/api/overdracht/[patientId]` | GET | - | `PatientDetail` | Required |
|
||||
| `/api/overdracht/generate` | POST | `{ patientId }` | `AISamenvatting` | Required |
|
||||
|
||||
### 5.2 Nursing Logs Endpoints
|
||||
|
||||
| Endpoint | Method | Input | Output | Auth |
|
||||
|----------|--------|-------|--------|------|
|
||||
| `/api/nursing-logs` | GET | `?patientId&date` | `NursingLog[]` | Required |
|
||||
| `/api/nursing-logs` | POST | `CreateNursingLog` | `NursingLog` | Required |
|
||||
| `/api/nursing-logs/[logId]` | PATCH | `UpdateNursingLog` | `NursingLog` | Required |
|
||||
| `/api/nursing-logs/[logId]` | DELETE | - | `204` | Required |
|
||||
|
||||
### 5.3 Response Types
|
||||
|
||||
```typescript
|
||||
// lib/types/overdracht.ts
|
||||
|
||||
// Patiënt overzicht (lijst view)
|
||||
export interface PatientOverzicht {
|
||||
id: string;
|
||||
name_given: string[];
|
||||
name_family: string;
|
||||
birth_date: string;
|
||||
gender: string;
|
||||
alerts: {
|
||||
high_risk_count: number;
|
||||
abnormal_vitals_count: number;
|
||||
marked_logs_count: number;
|
||||
};
|
||||
}
|
||||
|
||||
// Patiënt detail (detail view)
|
||||
export interface PatientDetail {
|
||||
patient: {
|
||||
id: string;
|
||||
name_given: string[];
|
||||
name_family: string;
|
||||
name_prefix?: string;
|
||||
birth_date: string;
|
||||
gender: string;
|
||||
};
|
||||
vitals: VitalSign[];
|
||||
reports: Report[];
|
||||
nursingLogs: NursingLog[];
|
||||
risks: RiskAssessment[];
|
||||
conditions: Condition[];
|
||||
}
|
||||
|
||||
// Vitale functie met interpretatie
|
||||
export interface VitalSign {
|
||||
id: string;
|
||||
code_display: string;
|
||||
value_quantity_value: number;
|
||||
value_quantity_unit: string;
|
||||
interpretation_code?: string; // 'H' | 'L' | 'N'
|
||||
effective_datetime: string;
|
||||
source_id: string;
|
||||
}
|
||||
|
||||
// AI Samenvatting output
|
||||
export interface AISamenvatting {
|
||||
samenvatting: string;
|
||||
aandachtspunten: Aandachtspunt[];
|
||||
actiepunten: string[];
|
||||
generatedAt: string;
|
||||
durationMs: number;
|
||||
}
|
||||
|
||||
export interface Aandachtspunt {
|
||||
tekst: string;
|
||||
urgent: boolean;
|
||||
bron: {
|
||||
type: 'observatie' | 'rapportage' | 'dagnotitie' | 'risico';
|
||||
id: string;
|
||||
datum: string;
|
||||
label: string;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. AI Integratie
|
||||
|
||||
### 6.1 AI Overdracht Generator
|
||||
|
||||
**Locatie:** `/api/overdracht/generate/route.ts`
|
||||
|
||||
**Pattern:** Gebaseerd op bestaande `behandelplan/generate` implementatie.
|
||||
|
||||
```typescript
|
||||
// lib/ai/overdracht-prompt.ts
|
||||
|
||||
export const OVERDRACHT_SYSTEM_PROMPT = `Je bent een ervaren verpleegkundige die overdrachten maakt in een GGZ-instelling.
|
||||
|
||||
Je taak: Maak een beknopte, relevante overdracht voor de opvolgende dienst.
|
||||
|
||||
## Outputformaat (JSON)
|
||||
{
|
||||
"samenvatting": "1-2 zinnen over de patiënt en wat er speelt",
|
||||
"aandachtspunten": [
|
||||
{
|
||||
"tekst": "Beschrijving van het aandachtspunt",
|
||||
"urgent": true/false,
|
||||
"bron": {
|
||||
"type": "observatie|rapportage|dagnotitie|risico",
|
||||
"id": "source-id",
|
||||
"datum": "DD-MM-YYYY HH:mm",
|
||||
"label": "Korte beschrijving bron"
|
||||
}
|
||||
}
|
||||
],
|
||||
"actiepunten": [
|
||||
"Concrete actie voor opvolgende dienst"
|
||||
]
|
||||
}
|
||||
|
||||
## Regels
|
||||
1. Taal: Nederlands, zakelijk, beknopt
|
||||
2. Focus op: veranderingen, afwijkingen, aandachtspunten
|
||||
3. Elke aandachtspunt MOET een bronverwijzing hebben
|
||||
4. Maximum 5 aandachtspunten, 3 actiepunten
|
||||
5. Markeer urgent=true voor:
|
||||
- Medicatie-weigering
|
||||
- Incidenten
|
||||
- Sterk afwijkende vitals
|
||||
- Hoog-risico situaties
|
||||
`;
|
||||
|
||||
export function buildOverdrachtUserPrompt(context: OverdrachtContext): string {
|
||||
const lines: string[] = [
|
||||
`PATIENT: ${context.patientName}, ${context.age} jaar, ${context.gender}`,
|
||||
'',
|
||||
'DIAGNOSES:',
|
||||
...context.conditions.map(c =>
|
||||
`- ${c.code_display} (source: conditions/${c.id})`
|
||||
),
|
||||
'',
|
||||
'VITALE FUNCTIES (vandaag):',
|
||||
...context.vitals.map(v =>
|
||||
`- ${v.code_display}: ${v.value_quantity_value} ${v.value_quantity_unit} ` +
|
||||
`[${interpretationLabel(v.interpretation_code)}] ` +
|
||||
`(source: observations/${v.id}, ${formatTime(v.effective_datetime)})`
|
||||
),
|
||||
'',
|
||||
'RAPPORTAGES (laatste 24u):',
|
||||
...context.reports.map(r =>
|
||||
`- [${formatTime(r.created_at)}] ${r.type}: "${truncate(r.content, 200)}" ` +
|
||||
`(source: reports/${r.id})`
|
||||
),
|
||||
'',
|
||||
'DAGREGISTRATIES (relevant voor overdracht):',
|
||||
...context.nursingLogs.map(l =>
|
||||
`- [${formatTime(l.timestamp)}] [${l.category.toUpperCase()}] ${l.content} ` +
|
||||
`(source: nursing_logs/${l.id})`
|
||||
),
|
||||
'',
|
||||
'RISICOS:',
|
||||
...context.risks.map(r =>
|
||||
`- [${r.risk_level.toUpperCase()}] ${r.risk_type}: "${truncate(r.rationale, 150)}" ` +
|
||||
`(source: risk_assessments/${r.id})`
|
||||
),
|
||||
];
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 AI Event Logging
|
||||
|
||||
```typescript
|
||||
// Uitbreiding ai_events.kind enum
|
||||
// Voeg toe: 'overdracht_generate'
|
||||
|
||||
await supabase.from('ai_events').insert({
|
||||
kind: 'overdracht_generate',
|
||||
patient_id: patientId,
|
||||
request: {
|
||||
vitalCount: context.vitals.length,
|
||||
reportCount: context.reports.length,
|
||||
logCount: context.nursingLogs.length,
|
||||
riskCount: context.risks.length,
|
||||
},
|
||||
response: {
|
||||
aandachtspuntenCount: result.aandachtspunten.length,
|
||||
actiepuntenCount: result.actiepunten.length,
|
||||
urgentCount: result.aandachtspunten.filter(a => a.urgent).length,
|
||||
},
|
||||
duration_ms: durationMs,
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Frontend Componenten
|
||||
|
||||
### 7.1 Nieuwe Routes
|
||||
|
||||
```
|
||||
app/epd/
|
||||
├── overdracht/
|
||||
│ ├── page.tsx # Overzicht grid
|
||||
│ ├── [patientId]/
|
||||
│ │ └── page.tsx # Patiënt detail
|
||||
│ └── components/
|
||||
│ ├── patient-card.tsx # Card in overzicht grid
|
||||
│ ├── vitals-block.tsx # Vitale functies blok
|
||||
│ ├── reports-block.tsx # Rapportages blok
|
||||
│ ├── nursing-logs-block.tsx # Dagnotities blok
|
||||
│ ├── risks-block.tsx # Risico's blok
|
||||
│ └── ai-summary-block.tsx # AI samenvatting blok
|
||||
│
|
||||
└── dagregistratie/
|
||||
└── [patientId]/
|
||||
├── page.tsx # Dagregistratie module
|
||||
└── components/
|
||||
├── log-list.tsx # Lijst van notities
|
||||
├── log-form.tsx # Quick entry form
|
||||
└── log-card.tsx # Individuele notitie card
|
||||
```
|
||||
|
||||
### 7.2 Component Hergebruik
|
||||
|
||||
| Nieuw Component | Hergebruik van | Locatie |
|
||||
|-----------------|----------------|---------|
|
||||
| patient-card.tsx | Card (shadcn), Badge | components/ui/ |
|
||||
| ai-summary-block.tsx | AIButton pattern | behandelplan/ |
|
||||
| log-form.tsx | Form patterns | screening/activity-log.tsx |
|
||||
| risks-block.tsx | Card, Badge | intakes/risk/ |
|
||||
|
||||
### 7.3 Sidebar Uitbreiding
|
||||
|
||||
```typescript
|
||||
// app/epd/components/epd-sidebar.tsx
|
||||
// Voeg toe aan navigatie items:
|
||||
|
||||
{
|
||||
title: 'Overdracht',
|
||||
href: '/epd/overdracht',
|
||||
icon: ClipboardList,
|
||||
badge: alertCount > 0 ? alertCount : undefined,
|
||||
},
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Security & Compliance
|
||||
|
||||
### 8.1 Authentication Flow
|
||||
|
||||
```
|
||||
User Request
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ Supabase Auth │ ← Session cookie
|
||||
│ (JWT validation)│
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ RLS Policies │ ← auth.uid() check
|
||||
│ (Row filtering) │
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ API Response │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
### 8.2 Security Checklist
|
||||
|
||||
- [x] **Authentication:** Supabase Auth (bestaand)
|
||||
- [x] **Authorization:** RLS policies op nursing_logs
|
||||
- [x] **Data Encryption:** PostgreSQL at rest, HTTPS in transit
|
||||
- [x] **Input Validation:** Zod schemas op alle endpoints
|
||||
- [x] **CORS:** Via Next.js middleware (bestaand)
|
||||
- [x] **Audit Trail:** ai_events tabel voor AI calls
|
||||
|
||||
### 8.3 AVG/GDPR Compliance
|
||||
|
||||
- **Data minimalisatie:** nursing_logs max 500 chars
|
||||
- **Retention:** nursing_logs cleanup na 30 dagen (fase 2)
|
||||
- **Audit:** created_by tracking op alle records
|
||||
- **Access logging:** Via Supabase logs
|
||||
|
||||
---
|
||||
|
||||
## 9. Performance & Scalability
|
||||
|
||||
### 9.1 Performance Targets
|
||||
|
||||
| Metric | Target | Implementatie |
|
||||
|--------|--------|---------------|
|
||||
| Overzicht load | < 2s | Parallel queries, index op encounters |
|
||||
| Detail load | < 1.5s | Batch queries via Promise.all() |
|
||||
| Log submit | < 500ms | Direct insert, optimistic UI |
|
||||
| AI response | < 5s | Claude claude-sonnet-4-20250514, max_tokens=2048 |
|
||||
|
||||
### 9.2 Database Indexes
|
||||
|
||||
```sql
|
||||
-- Bestaande indexes (verificatie)
|
||||
CREATE INDEX IF NOT EXISTS idx_encounters_period ON encounters(period_start);
|
||||
CREATE INDEX IF NOT EXISTS idx_observations_patient_datetime ON observations(patient_id, effective_datetime DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_reports_patient_created ON reports(patient_id, created_at DESC);
|
||||
|
||||
-- Nieuwe indexes voor overdracht
|
||||
CREATE INDEX idx_nursing_logs_patient ON nursing_logs(patient_id);
|
||||
CREATE INDEX idx_nursing_logs_shift ON nursing_logs(shift_date);
|
||||
CREATE INDEX idx_nursing_logs_handover ON nursing_logs(patient_id, include_in_handover)
|
||||
WHERE include_in_handover = true;
|
||||
```
|
||||
|
||||
### 9.3 Query Optimalisatie
|
||||
|
||||
```typescript
|
||||
// Parallelle queries voor detail pagina
|
||||
export async function getPatientDetail(patientId: string) {
|
||||
const supabase = await createClient();
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const last24h = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
|
||||
|
||||
const [
|
||||
{ data: patient },
|
||||
{ data: vitals },
|
||||
{ data: reports },
|
||||
{ data: nursingLogs },
|
||||
{ data: risks },
|
||||
{ data: conditions },
|
||||
] = await Promise.all([
|
||||
supabase.from('patients').select('*').eq('id', patientId).single(),
|
||||
supabase.from('observations')
|
||||
.select('*')
|
||||
.eq('patient_id', patientId)
|
||||
.eq('category', 'vital-signs')
|
||||
.gte('effective_datetime', today)
|
||||
.order('effective_datetime', { ascending: false }),
|
||||
supabase.from('reports')
|
||||
.select('*')
|
||||
.eq('patient_id', patientId)
|
||||
.gte('created_at', last24h)
|
||||
.is('deleted_at', null)
|
||||
.order('created_at', { ascending: false }),
|
||||
supabase.from('nursing_logs')
|
||||
.select('*')
|
||||
.eq('patient_id', patientId)
|
||||
.eq('shift_date', today)
|
||||
.order('timestamp', { ascending: false }),
|
||||
// Risks via intakes join
|
||||
supabase.from('risk_assessments')
|
||||
.select('*, intakes!inner(patient_id)')
|
||||
.eq('intakes.patient_id', patientId),
|
||||
supabase.from('conditions')
|
||||
.select('*')
|
||||
.eq('patient_id', patientId)
|
||||
.eq('clinical_status', 'active'),
|
||||
]);
|
||||
|
||||
return { patient, vitals, reports, nursingLogs, risks, conditions };
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Deployment & Implementatie
|
||||
|
||||
### 10.1 Implementatie Volgorde
|
||||
|
||||
```
|
||||
Fase 1: Database (1 migratie)
|
||||
├── nursing_logs tabel
|
||||
├── RLS policies
|
||||
└── Indexes
|
||||
|
||||
Fase 2: API Routes
|
||||
├── /api/nursing-logs (CRUD)
|
||||
├── /api/overdracht/patients
|
||||
├── /api/overdracht/[patientId]
|
||||
└── /api/overdracht/generate
|
||||
|
||||
Fase 3: Frontend - Dagregistratie
|
||||
├── /epd/dagregistratie/[patientId]/page.tsx
|
||||
├── Log form component
|
||||
└── Log list component
|
||||
|
||||
Fase 4: Frontend - Overdracht
|
||||
├── /epd/overdracht/page.tsx
|
||||
├── /epd/overdracht/[patientId]/page.tsx
|
||||
├── Info blokken (vitals, reports, logs, risks)
|
||||
└── AI samenvatting blok
|
||||
|
||||
Fase 5: Integratie
|
||||
├── Sidebar link toevoegen
|
||||
├── AI prompt refinement
|
||||
└── Testing & polish
|
||||
```
|
||||
|
||||
### 10.2 Migratie Commands
|
||||
|
||||
```bash
|
||||
# Database migratie
|
||||
npx supabase migration new create_nursing_logs_table
|
||||
|
||||
# TypeScript types regenereren
|
||||
npx supabase gen types typescript --linked > lib/supabase/database.types.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Monitoring & Logging
|
||||
|
||||
### 11.1 Key Metrics
|
||||
|
||||
| Metric | Doel | Bron |
|
||||
|--------|------|------|
|
||||
| AI success rate | > 95% | ai_events.kind = 'overdracht_generate' |
|
||||
| Avg AI duration | < 5s | ai_events.duration_ms |
|
||||
| Log creations/day | Tracking | nursing_logs.created_at |
|
||||
| Handover marks % | Tracking | nursing_logs.include_in_handover |
|
||||
|
||||
### 11.2 Error Tracking
|
||||
|
||||
```typescript
|
||||
// Sentry error context (bestaand pattern)
|
||||
Sentry.setContext('overdracht', {
|
||||
patientId,
|
||||
vitalCount: vitals.length,
|
||||
reportCount: reports.length,
|
||||
logCount: nursingLogs.length,
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Risico's & Technische Mitigatie
|
||||
|
||||
| Risico | Impact | Waarschijnlijkheid | Mitigatie |
|
||||
|--------|--------|-------------------|-----------|
|
||||
| Claude API down | Hoog | Laag | Graceful error, toon data zonder AI |
|
||||
| Veel patiënten (>50) | Middel | Middel | Pagination in overzicht, lazy loading |
|
||||
| Lege data (geen vitals) | Laag | Hoog | Empty states per blok, instructieve tekst |
|
||||
| AI hallucinaties | Hoog | Laag | Bronverwijzingen verplicht, validatie |
|
||||
| Performance nursing_logs | Middel | Laag | Indexes, 30-dagen cleanup (fase 2) |
|
||||
|
||||
---
|
||||
|
||||
## 13. Bijlagen & Referenties
|
||||
|
||||
### 13.1 Projectdocumenten
|
||||
|
||||
| Document | Status |
|
||||
|----------|--------|
|
||||
| PRD Overdracht Dashboard v1.0 | Gereed |
|
||||
| FO Overdracht Dashboard v1.1 | Gereed |
|
||||
| TO Overdracht Dashboard v1.0 | Gereed (dit document) |
|
||||
|
||||
### 13.2 Code Locaties
|
||||
|
||||
| Wat | Locatie |
|
||||
|-----|---------|
|
||||
| AI prompt pattern | `lib/ai/behandelplan-prompt.ts` |
|
||||
| API route pattern | `app/api/reports/route.ts` |
|
||||
| shadcn components | `components/ui/` |
|
||||
| Supabase client | `lib/auth/server.ts` |
|
||||
| Database types | `lib/supabase/database.types.ts` |
|
||||
|
||||
### 13.3 Externe Documentatie
|
||||
|
||||
| Bron | URL |
|
||||
|------|-----|
|
||||
| Next.js App Router | https://nextjs.org/docs/app |
|
||||
| Supabase RLS | https://supabase.com/docs/guides/auth/row-level-security |
|
||||
| Claude API | https://docs.anthropic.com/en/api |
|
||||
| shadcn/ui | https://ui.shadcn.com |
|
||||
|
||||
---
|
||||
|
||||
## Changelog
|
||||
|
||||
| Versie | Datum | Auteur | Wijziging |
|
||||
|--------|-------|--------|-----------|
|
||||
| v1.0 | 05-12-2024 | Claude | Initieel TO gebaseerd op FO v1.1 |
|
||||
|
||||
---
|
||||
|
||||
**Einde Technisch Ontwerp - Overdracht Dashboard v1.0**
|
||||
@@ -1,146 +0,0 @@
|
||||
# 🚀 Mission Control — Bouwplan Screening & Intake
|
||||
|
||||
💡 **Tip:** Dit document is opgesteld op basis van `fo-screening-intake-v1_0.md`.
|
||||
|
||||
---
|
||||
|
||||
**Projectnaam:** AI Speedrun - Mini EPD v1.2
|
||||
**Versie:** v1.0
|
||||
**Datum:** 22-11-2025
|
||||
**Auteur:** Antigravity (i.s.m. Colin)
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en context
|
||||
🎯 **Doel:** Het realiseren van de volledige screening- en intakeflow voor GGZ-professionals, van aanmelding tot behandeladvies.
|
||||
📘 **Toelichting:** Dit bouwplan vertaalt het Functioneel Ontwerp (FO) naar concrete ontwikkelstappen. De focus ligt op het bouwen van de fundering (zonder AI in eerste instantie) zodat cliënten kunnen worden geregistreerd, gescreend en geïntaked volgens de specificaties.
|
||||
|
||||
---
|
||||
|
||||
## 2. Uitgangspunten
|
||||
|
||||
### 2.1 Technische Stack
|
||||
- **Frontend:** Next.js (App Router) + Tailwind CSS + Lucide Icons
|
||||
- **Backend:** Supabase (PostgreSQL + Auth)
|
||||
- **State Management:** React Query / Server Actions
|
||||
- **UI Library:** shadcn/ui (of vergelijkbaar)
|
||||
|
||||
### 2.2 Projectkaders
|
||||
- **Scope:** Zoals beschreven in FO v1.0 (MVP).
|
||||
- **Data:** Gebruik van Supabase voor persistentie.
|
||||
- **AI:** Nog niet in scope voor deze fase (komt in latere iteratie).
|
||||
|
||||
### 2.3 Programmeer Uitgangspunten
|
||||
- **DRY & SOC:** Strikte scheiding tussen UI en data-fetching (Server Actions / Services).
|
||||
- **Types:** Volledig getypeerd met TypeScript (Database types genereren uit Supabase).
|
||||
- **Componenten:** Herbruikbare componenten voor veelvoorkomende patronen (bijv. `SectionCard`, `StatusBadge`).
|
||||
|
||||
---
|
||||
|
||||
## 3. Epics & Stories Overzicht
|
||||
|
||||
| Epic ID | Titel | Doel | Status | Stories | Progress |
|
||||
|---------|-------|------|--------|---------|----------|
|
||||
| E1 | Database & Types | Datamodel implementeren in Supabase | ✅ Done | 3 | 3/3 ✅ |
|
||||
| E2 | Cliëntenbeheer | Lijstweergave en aanmaken cliënten | ✅ Done | 3 | 3/3 ✅ |
|
||||
| E3 | Screening Module | Screening tab en functionaliteit | ⏳ To Do | 4 | 0/4 ⏳ |
|
||||
| E4 | Intake Core | Intake overzicht en navigatie | ✅ Done | 3 | 3/3 ✅ |
|
||||
| E5 | Intake Details | Specifieke tabbladen (Contact, Risico, etc.) | ✅ Done | 5 | 5/5 ✅ |
|
||||
| E6 | Diagnose & Advies | Diagnose stelling en behandeladvies | ⏳ To Do | 3 | 0/3 ⏳ |
|
||||
|
||||
---
|
||||
|
||||
## 4. Epics & Stories (Uitwerking)
|
||||
|
||||
### Epic 1 — Database & Types ✅
|
||||
**Doel:** Een solide datamodel in Supabase dat voldoet aan de eisen uit het FO.
|
||||
**Status:** Done - Alle stories voltooid op 22-11-2025
|
||||
|
||||
| Story ID | Status | Beschrijving | Acceptatiecriteria |
|
||||
|----------|--------|--------------|---------------------|
|
||||
| E1.S1 | ✅ Done | Tabellen aanmaken | Migration `20251122_screening_intake_schema.sql` aangemaakt met:<br>- Patient status kolom (`episode_status` enum)<br>- Screening module (3 tabellen: `screenings`, `screening_activities`, `screening_documents`)<br>- Intake module (4 tabellen: `intakes`, `anamneses`, `examinations`, `risk_assessments`)<br>- `encounters` tabel uitgebreid met `intake_id` kolom<br>- `care_plans` uitgebreid met intake referenties |
|
||||
| E1.S2 | ✅ Done | Migration toepassen | Migration succesvol toegepast op Supabase database met:<br>- Foreign keys en constraints<br>- RLS policies voor alle nieuwe tabellen<br>- Indexes voor performance<br>- Triggers voor `updated_at` timestamps |
|
||||
| E1.S3 | ✅ Done | TypeScript Types genereren | Types gegenereerd met `supabase gen types` en geëxporteerd naar `lib/supabase/database.types.ts`<br>- 2148+ regels TypeScript types<br>- Alle nieuwe tabellen en enums geëxporteerd |
|
||||
|
||||
### Epic 2 — Cliëntenbeheer (Level 1) ✅
|
||||
**Doel:** Behandelaars kunnen cliënten vinden en nieuwe cliënten aanmaken.
|
||||
**Status:** Done - Alle stories voltooid op 22-11-2025
|
||||
|
||||
| Story ID | Status | Beschrijving | Acceptatiecriteria |
|
||||
|----------|--------|--------------|---------------------|
|
||||
| E2.S1 | ✅ Done | Cliëntenlijst | Tabel met zoekfunctie, filters en status badges:<br>- `patient-list.tsx` geüpdatet met client-side search bar<br>- Status filter dropdown (alle/screening/actief/afgerond/afgemeld)<br>- StatusBadge component met color-coded badges<br>- Tabel kolommen: Status, Naam, BSN, Laatst gewijzigd<br>- API route `/api/fhir/Patient` ondersteunt status filtering<br>- FHIR transform aangepast voor status extension |
|
||||
| E2.S2 | ✅ Done | Nieuwe Cliënt Flow | Formulier voor aanmaken cliënt met John Doe logica:<br>- `patient-form.tsx` compleet herschreven met alle FO velden<br>- John Doe checkbox met conditional BSN requirement<br>- BSN validatie met Modulo-11 check<br>- Alle velden: naam, BSN, geboortedatum, geslacht, adres (straat, postcode, plaats), contact (telefoon, email), verzekering (verzekeraar, polisnummer)<br>- Warning messages voor John Doe patiënten<br>- Status altijd 'planned' voor nieuwe patiënten<br>- Redirect naar patient detail page na aanmaken<br>- FHIR transform ondersteunt insurance extension (bidirectioneel) |
|
||||
| E2.S3 | ✅ Done | Cliënt Header & Nav | Context-aware header en sidebar navigatie (Level 2):<br>- `ClientHeader` component met naam, status badge, laatst gewijzigd en John Doe indicator<br>- `ClientSidebar` component met navigatie naar alle tabs<br>- Patient detail layout met header en sidebar<br>- Dashboard pagina met quick actions en volgende stappen<br>- Basisgegevens pagina met patient form en John Doe warning<br>- Placeholder paginas voor alle tabs: Screening, Intake, Diagnose, Behandelplan, Rapportage<br>- Alle tabs altijd zichtbaar, ongeacht status |
|
||||
|
||||
### Epic 3 — Screening Module (Level 2)
|
||||
**Doel:** Faciliteren van het screeningsproces.
|
||||
**Status:** ⏳ To Do - Database schema voltooid (E1), UI functionaliteit nog te implementeren
|
||||
|
||||
| Story ID | Status | Beschrijving | Acceptatiecriteria |
|
||||
|----------|--------|--------------|---------------------|
|
||||
| E3.S1 | ✅ Done | Activiteitenlog | Tijdlijn component met activiteiten (datum, type, beschrijving):<br>- Chronologische weergave van screeningsactiviteiten<br>- Formulier om nieuwe activiteit toe te voegen<br>- Server Action `addScreeningActivity` voor persistentie<br>- Activity types: Telefoongesprek, Email, Consult, Overig<br>- Integratie met `screening_activities` tabel |
|
||||
| E3.S2 | ✅ Done | Documenten & Hulpvraag | Upload functionaliteit en hulpvraag registratie:<br>- Document upload component met file preview<br>- Opslag in Supabase Storage (`screening-documents` bucket)<br>- Metadata opslag in `screening_documents` tabel<br>- Hulpvraag tekstveld (rich text) opgeslagen in `screenings.help_request`<br>- Server Actions voor upload en opslaan |
|
||||
| E3.S3 | ✅ Done | Screeningsbesluit | Formulier voor screeningsbesluit met status update + verwijsbrief-warning:<br>- Besluit opties: Geschikt / Niet geschikt<br>- Motivation textbox + afdeling selectie<br>- Status update logica naar `screenings.decision` + patiënstatus<br>- Warning bij ontbrekende verwijsbrief |
|
||||
| E3.S4 | ⏳ To Do | Basisgegevens Tab | Read-only weergave met edit-modus voor NAW:<br>- Display mode toont alle patient basisgegevens<br>- Edit knop voor wijzigingsmodus<br>- Inline editing of modal voor NAW gegevens<br>- Hergebruik van `PatientForm` component<br>- Save changes via `updatePatient` action<br>- Cancel/Reset functionaliteit |
|
||||
|
||||
**Database Dependencies (✅ Voltooid in E1):**
|
||||
- `screenings` tabel met decision en help_request velden
|
||||
- `screening_activities` tabel voor activiteitenlog
|
||||
- `screening_documents` tabel voor document metadata
|
||||
|
||||
### Epic 4 — Intake Core (Level 2) ✅
|
||||
**Doel:** Beheer van intakes (meerdere per cliënt mogelijk).
|
||||
**Status:** Done - Alle stories voltooid op 22-11-2025
|
||||
|
||||
| Story ID | Status | Beschrijving | Acceptatiecriteria |
|
||||
|----------|--------|--------------|---------------------|
|
||||
| E4.S1 | ✅ Done | Intake Overzicht | Kaartweergave van alle intakes per cliënt:<br>- `IntakeCard` component met status badges<br>- `IntakeList` component voor grid weergave<br>- Server Action `getIntakesByClientId` voor data fetching<br>- Geïntegreerd in `IntakeTab` op cliënt detail pagina |
|
||||
| E4.S2 | ✅ Done | Nieuwe Intake | Modal/page voor starten nieuwe intake:<br>- `NewIntakeForm` met Zod validatie<br>- Velden: Titel, Afdeling, Startdatum<br>- Server Action `createIntake` voor aanmaken record<br>- Redirect naar intake lijst na succes |
|
||||
| E4.S3 | ✅ Done | Intake Layout | Sub-navigatie (tabs) binnen een specifieke intake:<br>- `IntakeLayout` met `IntakeHeader` en `IntakeTabs`<br>- Header toont titel, status, en datums<br>- Tabs voor navigatie naar sub-onderdelen (Algemeen, Contact, etc.)<br>- Server Action `getIntakeById` voor ophalen details |
|
||||
|
||||
### Epic 5 — Intake Details (Tabs)
|
||||
**Doel:** Inhoudelijke registratie van de intake.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria |
|
||||
|----------|--------------|---------------------|
|
||||
| E5.S1 | ✅ Done | Tab Algemeen (read-only hulpvraag/besluit + notities). |
|
||||
| E5.S2 | ✅ Done | Tab Contactmomenten (lijst + CRUD via `encounters`). |
|
||||
| E5.S3 | ✅ Done | Tab Kindcheck (JSON-editing + alerts). |
|
||||
| E5.S4 | ✅ Done | Tab Risicotaxatie (`risk_assessments` CRUD). |
|
||||
| E5.S5 | ✅ Done | Tabs Anamnese, Onderzoek, ROM (gedeelde component met Supabase opslag). |
|
||||
|
||||
### Epic 6 — Diagnose & Advies
|
||||
**Doel:** Afronding van de intake met diagnose en advies.
|
||||
|
||||
| Story ID | Beschrijving | Acceptatiecriteria |
|
||||
|----------|--------------|---------------------|
|
||||
| E6.S1 | Diagnose Tab | Toevoegen DSM-5 diagnoses (code, ernst, toelichting). |
|
||||
| E6.S2 | Behandeladvies Tab | Rich text editor voor advies + doorzet-logica. |
|
||||
| E6.S3 | Intake Afronding | Status transitie naar 'Afgerond' en update cliënt status. |
|
||||
|
||||
---
|
||||
|
||||
## 5. Kwaliteit & Testplan
|
||||
|
||||
### Test Types
|
||||
- **Unit Tests:** Voor complexe validatielogica (bijv. BSN check).
|
||||
- **Manual Testing:** Doorlopen van de volledige flow van 'Nieuwe Cliënt' tot 'Intake Afgerond'.
|
||||
|
||||
### Manual Test Checklist
|
||||
- [ ] Nieuwe cliënt aanmaken (John Doe & Regulier).
|
||||
- [ ] Screening doorlopen en besluit nemen.
|
||||
- [ ] Intake starten en contactmoment toevoegen.
|
||||
- [ ] Diagnose toevoegen en behandeladvies opstellen.
|
||||
- [ ] Intake afronden en controleren of status update.
|
||||
|
||||
---
|
||||
|
||||
## 6. Risico's & Mitigatie
|
||||
|
||||
| Risico | Mitigatie |
|
||||
|--------|-----------|
|
||||
| Complexiteit datamodel | Starten met strikte types en ERD validatie. |
|
||||
| Navigatie diepte (Level 3?) | Duidelijke breadcrumbs en 'terug' knoppen implementeren. |
|
||||
| Performance bij veel data | Paginering op lijsten en lazy loading van tabs. |
|
||||
|
||||
---
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,69 +0,0 @@
|
||||
# 📆 Gefaseerd Implementatieplan — Screening & Intake
|
||||
|
||||
Dit plan bouwt voort op het Functioneel Ontwerp (`fo-screening-intake-v1_0.md`) en het bouwplan (`bouwplan-screening-intake-v1.0.md`). Elk faseblok beschrijft scope, deliverables, afhankelijkheden en validatie zodat duidelijk is wanneer een epic “Done” mag worden verklaard.
|
||||
|
||||
---
|
||||
|
||||
## Fase 0 — Schema & Migratie Align (Week 0) 🟡 _(plan klaar, uitvoering wacht op Supabase maintenance)_
|
||||
**Scope:** Repo en Supabase in sync brengen met de documentatie.
|
||||
- 🟢 Migreer `docs/archive/migrations/20251122-supabase-scheme.sql` naar echte SQL-migraties in `supabase/migrations/`.
|
||||
- 🟡 Voer migraties uit op alle omgevingen; documenteer eventuele datafixes (oude `clients` → `patients`).
|
||||
- 🟢 Update `docs/migratie-clients-naar-patients.md` met runbook + status (RLS tests, API-doc, console-checks).
|
||||
- 🟡 Valideer met `supabase db diff` en korte CRUD smoke-test op `/api/intakes` zodra maintenance voorbij is.
|
||||
|
||||
✅ **DoD:** Schone installaties krijgen identiek schema, API’s werken lokaal, documentatie verwijst naar juiste migratiebestanden.
|
||||
|
||||
---
|
||||
|
||||
## Fase 1 — Screening Module (E3) (Week 1) 🟢 _(document upload + warning actief)_
|
||||
**Scope:** UI + opslag voor activiteitenlog, documentbeheer, hulpvraag en screeningsbesluit.
|
||||
- 🟢 Backend: CRUD server actions + `/api/screenings` endpoints volgens FO §4.3 en data model FO §10.2–10.4.
|
||||
- 🟢 Frontend: activiteitenlog, hulpvraag en document upload/delete live.
|
||||
- 🟢 Statuskoppeling van screeningsbesluit naar `patients.status` geïmplementeerd.
|
||||
- 🟢 UX-warning bij ontbrekende verwijsbrief vóór besluit.
|
||||
|
||||
✅ **DoD:** Alle vier secties functioneel, bestanden worden opgeslagen, statusbadge in header verandert correct, manual test checklist items “Screening doorlopen” en “Besluit nemen” afgevinkt.
|
||||
|
||||
---
|
||||
|
||||
## Fase 2 — Intake Details (E5) (Week 2–3) 🟢 _(routing + CRUD opgezet)_
|
||||
**Scope:** Alle intake-subtabs uit FO §4.4.4–4.4.10 inclusief nieuwe tabroutes.
|
||||
- 🟢 Routing child routes (`/contacts`, `/kindcheck`, `/risk`, `/anamnese`, `/onderzoeken`, `/rom`, `/diagnose`, `/behandeladvies`).
|
||||
- 🟢 Contactmomenten UI/CRUD op `encounters`.
|
||||
- 🟢 Kindcheck & Risicotaxaties formulieren (JSONB + `risk_assessments`).
|
||||
- 🟢 Anamnese/Onderzoeken/ROM tabfunctionaliteit (gedeelde component + Supabase mutaties).
|
||||
- 🟢 Diagnoses (`conditions`) en Behandeladvies (`intakes.treatment_advice`).
|
||||
- 🟡 Intakekaart metrics (#contactmomenten, diagnoses, status “bezig/afgerond”).
|
||||
|
||||
✅ **DoD:** Alle tabs renderen data uit DB, formulieren schrijven terug, status `bezig/afgerond` sluit aan op FO §8.3, manual checklist items “Intake starten”, “Contactmoment toevoegen” en “Intake afronden” geslaagd.
|
||||
|
||||
---
|
||||
|
||||
## Fase 3 — Diagnose & Behandeladvies (E6) (Week 4) 🟡 _(metadata + tiptap live, diagnose nog te doen)_
|
||||
**Scope:** DSM-5 diagnose registratie, behandeladvies en statuskoppeling.
|
||||
- 🔧 Diagnose tab: CRUD op `conditions`/`diagnoses` tabel met validatie (code + omschrijving + ernst). Ondersteun sortering/primair/secundair.
|
||||
- 🟢 Behandeladvies tab: TipTap editor + metadata-paneel (datum, psycholoog, afdeling, zorgprogramma, behandelaar).
|
||||
- 🟡 Afrondingsworkflow: checkbox “Intake afronden” + vervolgkeuze (in zorg / doorverwijzen / extra diagnostiek), automatisch einddatum zetten en intake-status -> `afgerond`.
|
||||
- 🟢 Koppeling naar behandelplan: button/link om advies door te zetten naar tab “Behandelplan”.
|
||||
- 🟢 Voorbereiding spraak-naar-tekst: editor accepteert vrije tekst + placeholders.
|
||||
|
||||
✅ **DoD:** Diagnoses zichtbaar in intake-overzicht + diagnose tab, behandeladvies opslaan + locking, status-flow getest inclusief notifications/toasts.
|
||||
|
||||
---
|
||||
|
||||
## Fase 4 — QA, Documentatie & Roll-out (Week 5) 🔵 _(Nog te doen)_
|
||||
**Scope:** Validatie, handover en support.
|
||||
- Testmatrix: volledige regressie over cliëntenlijst, screening, intake tabs, diagnose & advies; documenteer in `docs/testing/screening-intake-regressie.md`.
|
||||
- Accessibility & contrast check via `scripts/test-contrast.ts` (voor nieuwe UI-blokken).
|
||||
- Bijwerken van FO/bouwplan/changelog met “v1.1” status + screenshots.
|
||||
- Training/handover: korte Loom of stappenplan voor behandelaars/secretaresses.
|
||||
|
||||
✅ **DoD:** Alle open checkboxen in `docs/migratie-clients-naar-patients.md` en bouwplan test checklist afgevinkt; release notes vermeld live datum en bekende risico’s.
|
||||
|
||||
---
|
||||
|
||||
## Overkoepelende aandachtspunten
|
||||
- **Data consistentie:** Reuse Supabase RLS policies; voer `supabase tests` of handmatige RLS-checks per fase.
|
||||
- **Roles & rechten (prototype):** Houd basisrolstatus aan (secretaresse vult screening, psycholoog intake), maar focus op UX-flows; fijnmazige autorisatie volgt later.
|
||||
- **Status uniformiteit:** Gebruik overal dezelfde enumeraties (`planned/active/finished/cancelled` voor patiënten, `bezig/afgerond` voor intakes). Update UI-badges en API’s in Fase 1.
|
||||
- **DX:** Houd server actions/API’s symmetrisch (FHIR vs Custom) en documenteer nieuwe endpoints onder `docs/api/`.
|
||||
@@ -1,34 +0,0 @@
|
||||
# 📋 Screening & Intake – Fasenplan
|
||||
|
||||
Dit document geeft een beknopt overzicht van de resterende werkpakketten, opgesplitst in fasen en subfasen. Het vult het bestaande implementatieplan aan met een snel te scannen roadmap.
|
||||
|
||||
## Fase 0 – Schema & Deploy (on hold)
|
||||
- 0.1: Supabase migration repair (wacht tot maintenance klaar is)
|
||||
- 0.2: `supabase db pull/push` + seeds
|
||||
- 0.3: Smoke-tests (`curl /api/fhir` en `/api/intakes`)
|
||||
|
||||
## Fase 1 – Screening (afgerond)
|
||||
- 1.1: Activiteitenlog + hulpvraag (gereed)
|
||||
- 1.2: Document upload/store (gereed)
|
||||
- 1.3: Screeningsbesluit + status sync + verwijsbrief-warning (gereed)
|
||||
|
||||
## Fase 2 – Intake Details (huidige focus)
|
||||
- 2.1: Routing + tab shells (gereed)
|
||||
- 2.2: Contactmomenten (CRUD op `encounters`)
|
||||
- 2.3: Kindcheck JSONB editor
|
||||
- 2.4: Risicotaxaties (`risk_assessments`)
|
||||
- 2.5: Anamnese, Onderzoeken, ROM editors
|
||||
- 2.6: Diagnoses & behandeladvies (TipTap, metadata)
|
||||
- 2.7: Intake kaarten uitbreiden met contactcount/diagnose/status
|
||||
|
||||
## Fase 3 – Diagnose & Advies verdieping
|
||||
- 3.1: Validaties + DSM-code helpers
|
||||
- 3.2: Workflow “intake afronden” (checkbox + status change)
|
||||
- 3.3: Koppeling naar behandelplan-tab
|
||||
|
||||
## Fase 4 – QA & Roll-out
|
||||
- 4.1: Regressietests + documentatie update
|
||||
- 4.2: Accessibility/contrast check
|
||||
- 4.3: Release notes, training, screenshot-updates
|
||||
|
||||
Gebruik dit document als snelle referentie; details en acceptatiecriteria blijven in `implementatieplan-screening-intake.md` staan.
|
||||
@@ -1,93 +0,0 @@
|
||||
# Universele Rapportage — Split Timeline Composer
|
||||
|
||||
Context: gesprek met behandelaren/psychiaters toonde dat rapportages schrijven en overzicht houden tegelijk nodig is. Deze mock beschrijft een layout waarbij timeline en composer gelijktijdig zichtbaar blijven.
|
||||
|
||||
## UX Principes
|
||||
|
||||
1. **Context behouden** – timeline altijd zichtbaar; geen modal die context blokkeert.
|
||||
2. **Snelle wissel** – klik op entry synchroniseert composer en toont referenties.
|
||||
3. **Mobiele pariteit** – tabs/drawer zodat schrijven en lezen in één flow blijft.
|
||||
4. **State veilig** – concepten autosaven; switching verliest content niet.
|
||||
|
||||
## Desktop Mock
|
||||
|
||||
```
|
||||
┌───────────────────────────────┬───────────────────────────────┐
|
||||
│ Timeline kolom (40%) │ Composer kolom (60%) │
|
||||
│ ┌────────── Rapportage filter │ ┌──────────── Nieuwe rapportage│
|
||||
│ │ Zoeken [🔍___________] │ │ Emma de Vries • Vrije notitie│
|
||||
│ │ Type [• Alle ▼] │ │ --------------------------- │
|
||||
│ └──────────────────────────── │ │ [textarea................] │
|
||||
│ ┌── Entry ─────────────────── │ │ AI badge + dropdown │
|
||||
│ │ 09:12 • Sophie (AI 92%) │ │ Rapportagetype [▼] │
|
||||
│ │ Behandeladvies snippet │ │ Speech recorder + attach │
|
||||
│ └──────────────────────────── │ │ Footer: Opslaan • Analyseer │
|
||||
│ Scrollbare lijst met badges │ │ Sticky action bar │
|
||||
└───────────────────────────────┴───────────────────────────────┘
|
||||
```
|
||||
- Clicking an entry previews full text in a slide-out panel or inline expansion.
|
||||
- Filters (type, author, date) pin to top of timeline.
|
||||
- Composer sticky footer shows save status + autosave timestamp.
|
||||
|
||||
## Mobile Mock
|
||||
|
||||
```
|
||||
┌──────────────┐
|
||||
│ Tabs │
|
||||
│ [Timeline] [Rapportage+] │
|
||||
├──────────────┤
|
||||
│ Timeline tab │
|
||||
│ cards stack │
|
||||
└────┬─────────┘
|
||||
▼ swipe up opens composer drawer
|
||||
┌──────────────┐
|
||||
│ Rapportage │
|
||||
│ textarea │
|
||||
│ AI panel │
|
||||
│ Save / AI btn│
|
||||
└──────────────┘
|
||||
```
|
||||
- Drawer covers 75% height so top timeline remains slightly visible.
|
||||
- Swipe down or "Terug naar timeline" button closes drawer without losing draft.
|
||||
|
||||
## Interacties
|
||||
|
||||
- **Select entry → composer reference**: clicking "Referentie toevoegen" inserts a quote block with metadata (author, time).
|
||||
- **Autosave badge**: top-right of composer shows "Automatisch opgeslagen 13:42".
|
||||
- **AI context chips**: timeline entries show AI confidence badges; clicking them filters timeline by type.
|
||||
|
||||
## Open vragen
|
||||
|
||||
1. Hoeveel entries tonen we per pagina? (voorstel: 50 + virtuele scroll)
|
||||
2. Benodigd? inline edit van bestaande rapportages? (nu read-only)
|
||||
3. Notificatie bij gelijktijdig schrijven door meerdere behandelaren?
|
||||
|
||||
Deze mock dient als richting voor UI implementatie; visuele uitwerking kan in Figma plaatsvinden met shadcn/ui componenten.
|
||||
|
||||
## Actieplan
|
||||
|
||||
1. **UX refinement**
|
||||
- Bouw Figma-variant voor desktop split view en mobiele drawer.
|
||||
- Valideer met 2 behandelaren of de voorgestelde flows voldoen.
|
||||
|
||||
2. **Component architectuur**
|
||||
- Refactor rapportage route naar layout met `TimelinePane` + `ComposerPane`.
|
||||
- Introduceer context/state voor draft + selectie (bijv. `useReportDraft`).
|
||||
|
||||
3. **Timeline functionaliteit**
|
||||
- Implement filters (zoek, type, auteur, datum).
|
||||
- Voeg inline preview/slide-out voor entries toe.
|
||||
- Onderzoek virtualized list (React Virtual) voor >50 items.
|
||||
|
||||
4. **Composer upgrades**
|
||||
- Sticky footer met status + autosave indicator.
|
||||
- "Referentie toevoegen" waarmee geselecteerde entry als quote block wordt ingevoegd.
|
||||
- Drawer/tab ervaring op mobiel.
|
||||
|
||||
5. **State & autosave**
|
||||
- Drafts opslaan in localStorage of Supabase temp table.
|
||||
- Toon laatste autosave + unsaved changes waarschuwing bij navigeren.
|
||||
|
||||
6. **Testing & rollout**
|
||||
- Schrijf QA checklist (desktop/mobile).
|
||||
- Monitor gebruikersfeedback tijdens pilot, focus op contextswitch-snelheid.
|
||||
@@ -1,196 +0,0 @@
|
||||
# Analyse: Migratie naar Deepgram SDK
|
||||
|
||||
## Huidige situatie
|
||||
|
||||
### Huidige implementatie
|
||||
|
||||
- REST API via directe `fetch()` naar `https://api.deepgram.com/v1/listen`
|
||||
- Audio wordt opgenomen met `MediaRecorder`, opgeslagen als Blob
|
||||
- Na opname wordt het hele bestand geüpload via FormData
|
||||
- Server-side route handler (`app/api/deepgram/transcribe/route.ts`) verwerkt de upload
|
||||
- Geen streaming; alles gebeurt na de opname
|
||||
|
||||
### Componenten betrokken
|
||||
|
||||
- `components/speech-recorder.tsx` - Client-side opname component
|
||||
- `app/api/deepgram/transcribe/route.ts` - Server-side API route
|
||||
|
||||
---
|
||||
|
||||
## Impact van Deepgram SDK
|
||||
|
||||
### 1. Architectuurwijziging: REST → WebSocket streaming
|
||||
|
||||
**Huidige flow:**
|
||||
```
|
||||
Browser → MediaRecorder → Blob → FormData → POST /api/deepgram/transcribe → Deepgram REST API → Transcript
|
||||
```
|
||||
|
||||
**Nieuwe flow met SDK:**
|
||||
```
|
||||
Browser → Microfoon stream → Deepgram SDK (WebSocket) → Real-time transcript chunks → UI update
|
||||
```
|
||||
|
||||
**Impact:**
|
||||
- Streaming vereist een WebSocket-verbinding
|
||||
- Real-time updates tijdens opname (niet alleen na opname)
|
||||
- Client-side SDK nodig (niet alleen server-side)
|
||||
- Server route kan worden vereenvoudigd of verwijderd
|
||||
|
||||
### 2. Client-side SDK vereist
|
||||
|
||||
**Wat er moet gebeuren:**
|
||||
- Deepgram SDK installeren: `@deepgram/sdk` of `@deepgram/browser-sdk`
|
||||
- Client-side WebSocket-verbinding opzetten
|
||||
- Audio stream direct naar Deepgram sturen (niet via server)
|
||||
- Real-time transcript chunks ontvangen en verwerken
|
||||
|
||||
**Overwegingen:**
|
||||
- **API key:** moet client-side beschikbaar zijn (met `NEXT_PUBLIC_` prefix) of via een proxy/token endpoint
|
||||
- **Security:** API key niet direct in client code plaatsen; gebruik een proxy endpoint die tokens uitreikt
|
||||
|
||||
### 3. Component herstructurering
|
||||
|
||||
**`speech-recorder.tsx` wijzigingen:**
|
||||
- Verwijder `MediaRecorder` blob-opslag (of behoud voor lokale backup)
|
||||
- Verwijder FormData upload naar `/api/deepgram/transcribe`
|
||||
- Voeg Deepgram SDK WebSocket-verbinding toe
|
||||
- Implementeer real-time transcript updates tijdens opname
|
||||
- Update state management voor streaming chunks
|
||||
- Voeg error handling toe voor WebSocket-verbindingen
|
||||
|
||||
**Nieuwe functionaliteit:**
|
||||
- Real-time transcript updates tijdens opname
|
||||
- Mogelijkheid tot pauzeren/hervatten zonder verbinding te verbreken
|
||||
- Endpointing (automatische detectie van spraakpauzes)
|
||||
- Betere error handling voor netwerkproblemen
|
||||
|
||||
### 4. Server-side route aanpassing
|
||||
|
||||
**Opties voor `/api/deepgram/transcribe/route.ts`:**
|
||||
|
||||
**Optie A: Verwijderen**
|
||||
- Als alles client-side gebeurt, is deze route niet meer nodig
|
||||
- Vereist client-side API key exposure (niet aanbevolen)
|
||||
|
||||
**Optie B: Proxy voor API key security**
|
||||
- Route wordt een proxy die tokens uitreikt of de verbinding proxyt
|
||||
- Client maakt verbinding via deze proxy
|
||||
- API key blijft server-side
|
||||
|
||||
**Optie C: Hybride**
|
||||
- Streaming via client-side SDK
|
||||
- Fallback naar REST API voor batch-verwerking
|
||||
- Route behouden voor backward compatibility
|
||||
|
||||
### 5. State management wijzigingen
|
||||
|
||||
**Huidige state:**
|
||||
- `isRecording` - boolean
|
||||
- `isUploading` - boolean
|
||||
- `error` - string
|
||||
- `chunksRef` - Blob array
|
||||
|
||||
**Nieuwe state nodig:**
|
||||
- `isStreaming` - WebSocket verbinding status
|
||||
- `transcriptChunks` - Array van real-time transcript delen
|
||||
- `connectionStatus` - 'connecting', 'connected', 'disconnected', 'error'
|
||||
- `partialTranscript` - Huidige incomplete transcript
|
||||
- `finalTranscript` - Voltooide transcripties
|
||||
|
||||
### 6. Error handling uitbreiding
|
||||
|
||||
**Nieuwe error scenarios:**
|
||||
- WebSocket verbindingsfouten
|
||||
- Netwerk onderbrekingen tijdens streaming
|
||||
- Deepgram quota/rate limiting tijdens live sessie
|
||||
- Microfoon toegang tijdens actieve stream
|
||||
- Herverbindingslogica nodig
|
||||
|
||||
### 7. UX verbeteringen mogelijk
|
||||
|
||||
**Met streaming beschikbaar:**
|
||||
- Real-time tekst tijdens spreken
|
||||
- Visual feedback per woord/chunk
|
||||
- Lagere latency (<500ms per chunk vs 2+ seconden voor hele opname)
|
||||
- Mogelijkheid tot directe correcties tijdens opname
|
||||
- Pauzeren/hervatten zonder opnieuw opnemen
|
||||
|
||||
### 8. Dependencies
|
||||
|
||||
**Te installeren:**
|
||||
```json
|
||||
"@deepgram/sdk": "^latest" // of "@deepgram/browser-sdk"
|
||||
```
|
||||
|
||||
**Mogelijk te verwijderen:**
|
||||
- Geen directe fetch naar Deepgram REST API meer nodig
|
||||
- FormData handling kan worden vereenvoudigd
|
||||
|
||||
### 9. Configuratie wijzigingen
|
||||
|
||||
**Environment variables:**
|
||||
- `DEEPGRAM_API_KEY` blijft nodig
|
||||
- Overweeg `NEXT_PUBLIC_DEEPGRAM_API_KEY` alleen als je client-side direct verbindt (niet aanbevolen)
|
||||
- Beter: proxy endpoint die tokens uitreikt
|
||||
|
||||
**Deepgram configuratie:**
|
||||
- Model: `nova-2` (blijft hetzelfde)
|
||||
- Language: `nl` (blijft hetzelfde)
|
||||
- Nieuwe opties: `endpointing`, `interim_results`, `punctuate`, `smart_format`
|
||||
|
||||
### 10. Backward compatibility
|
||||
|
||||
**Overwegingen:**
|
||||
- Bestaande code die `/api/deepgram/transcribe` gebruikt
|
||||
- Migratiepad voor andere componenten
|
||||
- Fallback mechanisme als streaming faalt
|
||||
|
||||
---
|
||||
|
||||
## Aanbevolen migratiepad
|
||||
|
||||
### Fase 1: Voorbereiding
|
||||
1. Deepgram SDK installeren
|
||||
2. Proxy endpoint maken voor secure token/key management
|
||||
3. Test implementatie maken naast bestaande REST implementatie
|
||||
|
||||
### Fase 2: Core streaming
|
||||
1. WebSocket verbinding opzetten in `speech-recorder.tsx`
|
||||
2. Real-time transcript updates implementeren
|
||||
3. Basis error handling toevoegen
|
||||
|
||||
### Fase 3: UX verbeteringen
|
||||
1. Visual feedback voor real-time updates
|
||||
2. Pauzeren/hervatten functionaliteit
|
||||
3. Endpointing configureren
|
||||
|
||||
### Fase 4: Cleanup
|
||||
1. Oude REST API route verwijderen of deprecaten
|
||||
2. Code cleanup
|
||||
3. Documentatie updaten
|
||||
|
||||
---
|
||||
|
||||
## Risico's en aandachtspunten
|
||||
|
||||
1. **Security:** API key niet direct in client code
|
||||
2. **Kosten:** Streaming kan meer API calls genereren
|
||||
3. **Netwerk:** WebSocket vereist stabiele verbinding
|
||||
4. **Browser compatibiliteit:** WebSocket en MediaStream API support
|
||||
5. **Testing:** Complexer dan REST (real-time flows)
|
||||
|
||||
---
|
||||
|
||||
## Conclusie
|
||||
|
||||
De migratie vereist:
|
||||
- Architectuurwijziging van REST naar WebSocket streaming
|
||||
- Client-side SDK integratie
|
||||
- Herstructurering van `speech-recorder.tsx`
|
||||
- Aanpassing/verwijdering van server route
|
||||
- Uitgebreidere state management
|
||||
- Betere error handling
|
||||
- Security overwegingen voor API key management
|
||||
|
||||
**De belangrijkste winst:** real-time transcriptie tijdens opname in plaats van alleen na opname, wat beter aansluit bij de live transcriptie-vereisten in de documentatie.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,177 +0,0 @@
|
||||
# 🧪 Test Checklist - Epic 6: Integration & Testing
|
||||
|
||||
**Datum:** 24-11-2025
|
||||
**Tester:** [Naam]
|
||||
|
||||
---
|
||||
|
||||
## E6.S1 - Component Integration Tests
|
||||
|
||||
### Speech Recorder in Editor (report-composer.tsx)
|
||||
|
||||
| Test | Verwacht | ✅/❌ | Opmerkingen |
|
||||
|------|----------|-------|-------------|
|
||||
| Start opname → Cursor naar einde | Cursor springt naar einde van textarea | | |
|
||||
| Start opname → Groene border | Textarea krijgt emerald border + shadow | | |
|
||||
| Interim tekst → Grijs italic onder textarea | Live preview tijdens spreken | | |
|
||||
| Stop opname → Border reset | Normale border keert terug | | |
|
||||
| Transcript → Append aan content | Tekst wordt toegevoegd aan einde | | |
|
||||
|
||||
### Speech Recorder in Modal (report-view-edit-modal.tsx)
|
||||
|
||||
| Test | Verwacht | ✅/❌ | Opmerkingen |
|
||||
|------|----------|-------|-------------|
|
||||
| Edit mode → Speech recorder zichtbaar | Recorder verschijnt in bg-slate-50 sectie | | |
|
||||
| Start opname → Groene border op textarea | Modal textarea krijgt emerald border | | |
|
||||
| Transcript → Append aan content | Tekst wordt toegevoegd | | |
|
||||
| Stop → Unsaved indicator verschijnt | Amber bolletje + tekst | | |
|
||||
|
||||
### State Synchronization
|
||||
|
||||
| Test | Verwacht | ✅/❌ | Opmerkingen |
|
||||
|------|----------|-------|-------------|
|
||||
| Nieuwe rapportage → Verschijnt in timeline | Report toegevoegd bovenaan lijst | | |
|
||||
| Edit rapport → Timeline card update | Content preview update na save | | |
|
||||
| Delete rapport → Verdwijnt uit timeline | Card verwijderd uit lijst | | |
|
||||
| Duplicate → Content naar editor | Inhoud gekopieerd naar composer | | |
|
||||
|
||||
---
|
||||
|
||||
## E6.S2 - Dutch Medical Terms Test
|
||||
|
||||
### GGZ Terminologie Test
|
||||
|
||||
Spreek elk woord/zin in en controleer transcriptie:
|
||||
|
||||
| Term | Correct? | Confidence | Opmerkingen |
|
||||
|------|----------|------------|-------------|
|
||||
| "gegeneraliseerde angststoornis" | | | |
|
||||
| "SSRI medicatie" | | | |
|
||||
| "DSM-5 classificatie" | | | |
|
||||
| "cognitieve gedragstherapie" | | | |
|
||||
| "EMDR behandeling" | | | |
|
||||
| "traumaverwerking" | | | |
|
||||
| "depressieve episode" | | | |
|
||||
| "bipolaire stoornis" | | | |
|
||||
| "schizofrenie" | | | |
|
||||
| "persoonlijkheidsstoornis" | | | |
|
||||
| "dissociatieve identiteitsstoornis" | | | |
|
||||
| "borderline persoonlijkheidsstoornis" | | | |
|
||||
| "obsessief-compulsieve stoornis" | | | |
|
||||
| "PTSS post-traumatische stressstoornis" | | | |
|
||||
| "anorexia nervosa" | | | |
|
||||
|
||||
### Medische Zinnen Test
|
||||
|
||||
| Zin | Correct? | Issues |
|
||||
|----|----------|--------|
|
||||
| "De patiënt presenteert zich met klachten van angst en depressie" | | |
|
||||
| "Behandeladvies: cognitieve gedragstherapie, 12 sessies" | | |
|
||||
| "Diagnose volgens DSM-5: gegeneraliseerde angststoornis (F41.1)" | | |
|
||||
| "Patiënt is gestart met SSRI medicatie (sertraline 50mg)" | | |
|
||||
| "Verwijzing naar EMDR therapeut voor traumaverwerking" | | |
|
||||
|
||||
---
|
||||
|
||||
## E6.S3 - Browser Compatibility
|
||||
|
||||
### Desktop Browsers
|
||||
|
||||
| Browser | Versie | WebSocket | Web Audio | MediaRecorder | Streaming | Opmerkingen |
|
||||
|---------|--------|-----------|-----------|---------------|-----------|-------------|
|
||||
| Chrome | | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | |
|
||||
| Firefox | | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | |
|
||||
| Safari | | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | |
|
||||
| Edge | | ✅/❌ | ✅/❌ | ✅/❌ | ✅/❌ | |
|
||||
|
||||
### Mobile Browsers
|
||||
|
||||
| Browser | Versie | Mic Access | Streaming | UI Responsive | Opmerkingen |
|
||||
|---------|--------|------------|-----------|---------------|-------------|
|
||||
| Chrome Mobile | | ✅/❌ | ✅/❌ | ✅/❌ | |
|
||||
| Safari iOS | | ✅/❌ | ✅/❌ | ✅/❌ | |
|
||||
|
||||
---
|
||||
|
||||
## E6.S4 - Bug Bash & Polish
|
||||
|
||||
### Happy Flow Tests
|
||||
|
||||
**Test 1: Nieuwe Rapportage**
|
||||
- [ ] Pagina laadt met editor full-width
|
||||
- [ ] Quick action buttons zichtbaar
|
||||
- [ ] Klik [+ Vrije notitie] → Type geselecteerd
|
||||
- [ ] Start opname → Verbinding binnen 2 sec
|
||||
- [ ] Spreek → Real-time tekst verschijnt
|
||||
- [ ] Interim tekst is grijs italic
|
||||
- [ ] Final tekst is zwart
|
||||
- [ ] Stop → Transcript compleet
|
||||
- [ ] Klik Opslaan → Toast verschijnt
|
||||
- [ ] Rapportage in timeline (na refresh of real-time)
|
||||
|
||||
**Test 2: Bestaande Bewerken**
|
||||
- [ ] Klik [Tijdlijn] → Sidebar slides in (smooth)
|
||||
- [ ] Rapportages zichtbaar met preview
|
||||
- [ ] Klik [Bekijk rapport] → Modal opent (read mode)
|
||||
- [ ] Klik [✏️ Bewerken] → Edit mode (smooth transitie)
|
||||
- [ ] Speech recorder verschijnt
|
||||
- [ ] Dicteer → Tekst append aan einde
|
||||
- [ ] Klik [Opslaan] → Toast + modal blijft open
|
||||
- [ ] Klik [✕] → Modal sluit
|
||||
|
||||
**Test 3: Unsaved Changes**
|
||||
- [ ] Edit rapport → Type tekst
|
||||
- [ ] Klik [✕] → Dialog verschijnt
|
||||
- [ ] Klik [Terug] → Modal blijft open, tekst intact
|
||||
- [ ] Klik [Opslaan en sluiten] → Saved + modal sluit
|
||||
- [ ] OF Klik [Wijzigingen verwijderen] → Discard + modal sluit
|
||||
|
||||
**Test 4: Network Resilience**
|
||||
- [ ] Start opname
|
||||
- [ ] Spreek 5 seconden
|
||||
- [ ] Disconnect wifi (of throttle in DevTools)
|
||||
- [ ] Status indicator wordt oranje "Herverbinden..."
|
||||
- [ ] Partial transcript blijft zichtbaar
|
||||
- [ ] Reconnect → Groen "Verbonden"
|
||||
- [ ] Kan verder dicteren
|
||||
|
||||
### Known Issues / Bugs
|
||||
|
||||
| # | Beschrijving | Prioriteit | Status |
|
||||
|---|--------------|------------|--------|
|
||||
| 1 | | | |
|
||||
| 2 | | | |
|
||||
| 3 | | | |
|
||||
|
||||
### UI Polish Items
|
||||
|
||||
| # | Item | Status |
|
||||
|---|------|--------|
|
||||
| 1 | Loading states consistent | |
|
||||
| 2 | Error messages user-friendly | |
|
||||
| 3 | Animations smooth (300ms) | |
|
||||
| 4 | Keyboard navigation (Escape) | |
|
||||
| 5 | Focus management correct | |
|
||||
|
||||
---
|
||||
|
||||
## Test Summary
|
||||
|
||||
| Category | Pass | Fail | Blocked |
|
||||
|----------|------|------|---------|
|
||||
| E6.S1 Component Integration | | | |
|
||||
| E6.S2 Dutch Medical Terms | | | |
|
||||
| E6.S3 Browser Compatibility | | | |
|
||||
| E6.S4 Bug Bash & Polish | | | |
|
||||
|
||||
**Overall Status:** ⏳ In Progress / ✅ Pass / ❌ Fail
|
||||
|
||||
**Notes:**
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Sign-off:**
|
||||
- Developer:
|
||||
- Date:
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"timestamp": "2025-11-10T08:34:00Z",
|
||||
"source_folder_id": "11Vm70rVxj01gIbJzN6Kk1x_8yTbFxSg2",
|
||||
"source_folder_name": "01-project-epd-prototype",
|
||||
"destination": "./docs/specs/",
|
||||
"sync_method": "git-restore",
|
||||
"projects": [
|
||||
{
|
||||
"name": "mini-epd-prototype",
|
||||
"files_synced": 5,
|
||||
"files_failed": 0,
|
||||
"status": "success",
|
||||
"files": [
|
||||
"api-acces-mini-ecd.md",
|
||||
"fo-mini-ecd.md",
|
||||
"prd-mini-ecd.md",
|
||||
"to-mini-ecd.md",
|
||||
"ux-stylesheet.md"
|
||||
]
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"total_projects": 1,
|
||||
"total_files": 5,
|
||||
"total_failures": 0,
|
||||
"sync_status": "success"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,194 +0,0 @@
|
||||
# 🎨 Kleur Stylesheet – Mini‑ECD (v2, UX‑geoptimaliseerd)
|
||||
|
||||
> Doel: consistente, toegankelijke kleuren met **lage cognitieve belasting**. Accentpalet teruggebracht tot **3 modules** (Afspraken, Medicatie/Herinneringen, Lab/Resultaten). Inclusief duidelijke states en contrastrichtlijnen.
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Basiskleuren
|
||||
|
||||
* **App‑achtergrond**: `#F8FAFC`
|
||||
* **Oppervlak (kaarten/modals)**: `#FFFFFF`
|
||||
* **Sub‑oppervlak** (sekundair paneel/right‑rail): `#F1F5F9`
|
||||
* **Tekst primair**: `#0F172A`
|
||||
* **Tekst secundair**: `#475569`
|
||||
* **Borders/Dividers**: `#E2E8F0`
|
||||
|
||||
**WCAG tip:** tekst op witte of zachte pastelfondsen ≥ `#0F172A` / `#1E293B` voor AA‑contrast.
|
||||
|
||||
---
|
||||
|
||||
## 🔹 Merk & Primaire UI
|
||||
|
||||
* **Primary / Brand**: `#3B82F6`
|
||||
|
||||
* Hover: `#2563EB`
|
||||
* Active: `#1D4ED8`
|
||||
* Subtle bg (chips, empty‑states): `#EFF6FF`
|
||||
* On‑Primary text/icon: `#FFFFFF`
|
||||
|
||||
* **Neutral CTA (secundair/terug)**: `#334155`
|
||||
|
||||
* Hover: `#1F2937`
|
||||
* On‑Neutral: `#FFFFFF`
|
||||
|
||||
---
|
||||
|
||||
## 📊 Module‑accenten (gereduceerd)
|
||||
|
||||
Gebruik **max. drie** accentfamilies. Pastel voor kaarten + een verzadigd accent voor iconen/teksten.
|
||||
|
||||
1. **Afspraken**
|
||||
|
||||
* Card bg: `#E8F8EF`
|
||||
* Accent (icon/label): `#16A34A`
|
||||
* Border: `#CDECDC`
|
||||
|
||||
2. **Medicatie / Herinneringen**
|
||||
|
||||
* Card bg: `#FEF6DC`
|
||||
* Accent: `#F59E0B`
|
||||
* Border: `#F6E7B6`
|
||||
|
||||
3. **Lab / Resultaten**
|
||||
|
||||
* Card bg: `#FFEBDC`
|
||||
* Accent: `#F97316`
|
||||
* Border: `#FFD2B8`
|
||||
|
||||
> **Toegankelijkheid:** tekst op pastelkaarten in **donkergrijs `#0F172A`**. Accentkleur enkel voor iconen/badges/kleine headings.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Status & Feedback
|
||||
|
||||
* **Success**: `#16A34A`
|
||||
* **Warning**: `#EAB308`
|
||||
* **Error**: `#DC2626`
|
||||
* **Info**: `#3B82F6`
|
||||
|
||||
**Subtle backgrounds**
|
||||
|
||||
* Success subtle: `#ECFDF5`
|
||||
* Warning subtle: `#FEFCE8`
|
||||
* Error subtle: `#FEF2F2`
|
||||
* Info subtle: `#EFF6FF`
|
||||
|
||||
**Toasts/alerts**
|
||||
|
||||
* Tekst: `#0F172A`
|
||||
* Icon: statuskleur
|
||||
* Border: statuskleur op 30% (bijv. mix met wit)
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ Badges & Labels (Severity DSM‑light)
|
||||
|
||||
* **Laag**: bg `#E5E7EB`, text `#374151`
|
||||
* **Middel**: bg `#FEF3C7`, text `#92400E`
|
||||
* **Hoog**: bg `#FEE2E2`, text `#991B1B`
|
||||
|
||||
---
|
||||
|
||||
## ✍️ Formulieren & Invoervelden
|
||||
|
||||
* **Input bg**: `#FFFFFF`
|
||||
* **Input text**: `#0F172A`
|
||||
* **Placeholder**: `#94A3B8`
|
||||
* **Border default**: `#CBD5E1`
|
||||
* **Border hover**: `#94A3B8`
|
||||
* **Focus**: 2px ring `#3B82F6` + 1px inset border `#2563EB`
|
||||
* **Disabled**: bg `#F1F5F9`, text `#94A3B8`, border `#E2E8F0`
|
||||
* **Invalid**: border `#DC2626`, help‑text `#B91C1C`
|
||||
|
||||
**Select/Dropdown**
|
||||
|
||||
* Menu bg: `#FFFFFF`
|
||||
* Hover option: `#F1F5F9`
|
||||
* Active/selected: left bar `#3B82F6`
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Component‑states (Buttons/Links/Cards)
|
||||
|
||||
**Primary button**
|
||||
|
||||
* Default: bg `#3B82F6`, text `#FFFFFF`
|
||||
* Hover: bg `#2563EB`
|
||||
* Active: bg `#1D4ED8`
|
||||
* Disabled: bg `#BFDBFE`, text `#FFFFFF` @ 70%
|
||||
|
||||
**Secondary button**
|
||||
|
||||
* Default: bg `#334155`, text `#FFFFFF`
|
||||
* Hover: bg `#1F2937`
|
||||
* Disabled: bg `#CBD5E1`, text `#FFFFFF` @ 60%
|
||||
|
||||
**Ghost button**
|
||||
|
||||
* Text: `#334155`; hover bg: `#F1F5F9`
|
||||
|
||||
**Links**
|
||||
|
||||
* Default: `#2563EB`
|
||||
* Hover/Focus: underline + `#1D4ED8`
|
||||
* Visited: `#4F46E5`
|
||||
|
||||
**Cards**
|
||||
|
||||
* Default: bg `#FFFFFF`, border `#E2E8F0`, shadow sm
|
||||
* Hoverable variant: shadow md + translateY(‑1px)
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Navigatie
|
||||
|
||||
* **Sidebar item**
|
||||
|
||||
* Default text: `#334155`
|
||||
* Active: text `#0F172A`, bg `#E2E8F0`, left accent bar `#3B82F6`
|
||||
* Disabled: text `#94A3B8`
|
||||
|
||||
* **Topbar**
|
||||
|
||||
* Bg: `#FFFFFF`, border‑bottom: `#E2E8F0`
|
||||
|
||||
---
|
||||
|
||||
## 🌫️ Elevation & Focus
|
||||
|
||||
* **Shadows**
|
||||
|
||||
* sm: `0 1px 2px rgba(15,23,42,0.06)`
|
||||
* md: `0 2px 6px rgba(15,23,42,0.08)`
|
||||
* lg: `0 8px 20px rgba(15,23,42,0.10)`
|
||||
|
||||
* **Focus ring (universeel)**: 2px `#3B82F6` buiten het element + 1px contrast‑border.
|
||||
|
||||
---
|
||||
|
||||
## ♿ Toegankelijkheidsrichtlijnen
|
||||
|
||||
* Minimale contrastverhouding **AA**:
|
||||
|
||||
* Body‑tekst op wit ≥ 4.5:1 (gebruik `#0F172A`/`#1E293B`)
|
||||
* Tekst op gekleurde knoppen altijd **wit** (`#FFFFFF`) en check contrast.
|
||||
* Gebruik niet alleen kleur: combineer status met **icoon**, **label** of **shape**.
|
||||
* Focus is altijd zichtbaar (geen `outline: none`).
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Semantische tokens (aliasing)
|
||||
|
||||
Gebruik semantische namen in code i.p.v. ruwe HEX‑waarden:
|
||||
|
||||
* `--color-bg`, `--color-surface`, `--color-text`, `--color-border`
|
||||
* `--color-brand`, `--color-brand-hover`, `--color-info`, `--color-success`, `--color-warning`, `--color-error`
|
||||
* `--color-module-appointments`, `--color-module-meds`, `--color-module-labs`
|
||||
|
||||
---
|
||||
|
||||
## 📌 Notities
|
||||
|
||||
* Accentpalet bewust klein gehouden → minder visuele ruis, sneller scannen.
|
||||
* Kaarten tonen **accent** alleen in icoon/badge of kleine titel; content blijft donker op licht voor leesbaarheid.
|
||||
* Voor donker thema kunnen bovenstaande waarden gespiegeld worden met lichtere teksten en donkerder oppervlakken.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 108 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 127 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 84 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 146 KiB |
@@ -1,255 +0,0 @@
|
||||
# Webpack Module Resolution Error
|
||||
|
||||
**Error:** `Cannot read properties of undefined (reading 'call')`
|
||||
|
||||
## Root Cause
|
||||
|
||||
Dit is een **bekend probleem in Next.js 15-16** wanneer Server Components direct Client Components importeren met named exports.
|
||||
|
||||
### Wat gebeurt er technisch?
|
||||
|
||||
1. **Server Component** (bijv. `layout.tsx`) importeert een **Client Component** (met `'use client'` directive)
|
||||
2. Webpack bundelt de Client Component in een aparte chunk voor client-side hydration
|
||||
3. Next.js maakt een proxy module op de Server/Client boundary
|
||||
4. Bij het laden van de webpack chunk verwacht de loader een functie export
|
||||
5. Door timing/caching issues is de export soms `undefined`
|
||||
6. Dit geeft: `TypeError: Cannot read properties of undefined (reading 'call')`
|
||||
|
||||
## Wanneer treedt dit op?
|
||||
|
||||
### Situaties die dit veroorzaken:
|
||||
|
||||
1. **Direct import van Client Component in Server Component**
|
||||
```tsx
|
||||
// layout.tsx (Server Component)
|
||||
import { ClientComponent } from './client-component' // ❌ PROBLEEM
|
||||
```
|
||||
|
||||
2. **Named exports met 'use client'**
|
||||
```tsx
|
||||
// client-component.tsx
|
||||
'use client'
|
||||
export function ClientComponent() { ... } // ❌ Kan problemen geven
|
||||
```
|
||||
|
||||
3. **Webpack caching issues** na HMR (Hot Module Reload)
|
||||
|
||||
4. **Type imports die conflicteren**
|
||||
```tsx
|
||||
import type { Props } from './client-component' // Kan webpack verwarren
|
||||
import { ClientComponent } from './client-component'
|
||||
```
|
||||
|
||||
## Oplossingen
|
||||
|
||||
### Optie 1: Wrapper Component (GEKOZEN)
|
||||
|
||||
Maak een tussenlaag die de import isoleert:
|
||||
|
||||
```tsx
|
||||
// client-component-wrapper.tsx
|
||||
import { ClientComponent } from './client-component'
|
||||
|
||||
export default function ClientComponentWrapper(props) {
|
||||
return <ClientComponent {...props} />
|
||||
}
|
||||
|
||||
// layout.tsx (Server Component)
|
||||
import ClientComponent from './client-component-wrapper' // ✅ WERKT
|
||||
```
|
||||
|
||||
**Voordelen:**
|
||||
- Eenvoudig
|
||||
- Geen code wijzigingen in originele component
|
||||
- Isoleert webpack module boundary
|
||||
|
||||
**Nadelen:**
|
||||
- Extra bestand nodig
|
||||
- Iets meer boilerplate
|
||||
|
||||
### Optie 2: Default Export
|
||||
|
||||
Wijzig Client Component naar default export:
|
||||
|
||||
```tsx
|
||||
// client-component.tsx
|
||||
'use client'
|
||||
|
||||
function ClientComponent() { ... }
|
||||
|
||||
export default ClientComponent // ✅ Default export
|
||||
|
||||
// layout.tsx
|
||||
import ClientComponent from './client-component' // ✅ WERKT
|
||||
```
|
||||
|
||||
**Voordelen:**
|
||||
- Geen extra bestanden
|
||||
- Webpack handelt default exports beter af
|
||||
|
||||
**Nadelen:**
|
||||
- Originele component moet aangepast worden
|
||||
- Inconsistent als je meerdere exports nodig hebt
|
||||
|
||||
### Optie 3: Dynamic Import (NIET AANBEVOLEN voor layouts)
|
||||
|
||||
```tsx
|
||||
// layout.tsx
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
const ClientComponent = dynamic(
|
||||
() => import('./client-component').then(mod => mod.ClientComponent)
|
||||
)
|
||||
// Note: SSR false kan NIET in Server Components
|
||||
```
|
||||
|
||||
**Nadelen:**
|
||||
- Kan niet `ssr: false` gebruiken in Server Components
|
||||
- Loading state issues
|
||||
- Niet geschikt voor kritieke UI componenten
|
||||
|
||||
### Optie 4: Clean Cache en Rebuild
|
||||
|
||||
Soms is het gewoon cache corruptie:
|
||||
|
||||
```bash
|
||||
rm -rf .next node_modules
|
||||
pnpm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Preventie: Best Practices
|
||||
|
||||
### 1. Gebruik default exports voor Client Components
|
||||
|
||||
```tsx
|
||||
// ✅ GOED
|
||||
'use client'
|
||||
export default function MyClientComponent() { ... }
|
||||
|
||||
// ❌ VERMIJD
|
||||
'use client'
|
||||
export function MyClientComponent() { ... }
|
||||
```
|
||||
|
||||
### 2. Maak wrapper components voor complexe imports
|
||||
|
||||
Als je een Client Component in een Server Component layout nodig hebt:
|
||||
|
||||
```
|
||||
app/
|
||||
layout.tsx (Server)
|
||||
components/
|
||||
client-sidebar.tsx ('use client')
|
||||
client-sidebar-wrapper.tsx (wrapper)
|
||||
```
|
||||
|
||||
### 3. Splits type imports
|
||||
|
||||
```tsx
|
||||
// ✅ GOED
|
||||
import type { Props } from './types'
|
||||
import ClientComponent from './client-component'
|
||||
|
||||
// ❌ VERMIJD mixed imports
|
||||
import { type Props, ClientComponent } from './client-component'
|
||||
```
|
||||
|
||||
### 4. Clear cache bij persistente errors
|
||||
|
||||
```bash
|
||||
rm -rf .next
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 5. Check webpack chunks
|
||||
|
||||
Als de error blijft terugkomen, check webpack output:
|
||||
|
||||
```bash
|
||||
# In terminal met dev server
|
||||
# Kijk naar compile output voor errors
|
||||
```
|
||||
|
||||
## Specifieke Case: Release Sidebar
|
||||
|
||||
**Probleem:**
|
||||
- `app/(marketing)/releases/layout.tsx` (Server) importeerde direct `ReleaseSidebar` (Client)
|
||||
- Named export + 'use client' combinatie
|
||||
- Webpack module 356 resolution failure
|
||||
|
||||
**Oplossing:**
|
||||
Wrapper component gemaakt: `release-sidebar-wrapper.tsx`
|
||||
|
||||
**Bestanden:**
|
||||
```
|
||||
app/(marketing)/releases/
|
||||
├── layout.tsx # Server Component
|
||||
├── components/
|
||||
│ ├── release-sidebar.tsx # Client Component (named export)
|
||||
│ └── release-sidebar-wrapper.tsx # Wrapper (default export)
|
||||
```
|
||||
|
||||
**Code:**
|
||||
```tsx
|
||||
// layout.tsx
|
||||
import ReleaseSidebar from './components/release-sidebar-wrapper' // ✅
|
||||
|
||||
// release-sidebar-wrapper.tsx
|
||||
import { ReleaseSidebar } from './release-sidebar'
|
||||
export default function ReleaseSidebarWrapper(props) {
|
||||
return <ReleaseSidebar {...props} />
|
||||
}
|
||||
```
|
||||
|
||||
## Gerelateerde Issues
|
||||
|
||||
- Next.js issue: https://github.com/vercel/next.js/issues/...
|
||||
- Webpack module federation issues met RSC
|
||||
- Fast Refresh compatibility met Server/Client boundaries
|
||||
|
||||
## Andere Plekken in Codebase
|
||||
|
||||
Deze Client Components gebruiken momenteel named exports en kunnen hetzelfde probleem geven:
|
||||
|
||||
```
|
||||
app/(marketing)/components/
|
||||
- auth-code-handler.tsx
|
||||
- hero-section-client.tsx
|
||||
- reading-progress.tsx
|
||||
- marketing-shader.tsx
|
||||
- minimal-nav.tsx
|
||||
|
||||
app/epd/clients/components/
|
||||
- client-form.tsx
|
||||
- client-list.tsx
|
||||
|
||||
app/epd/clients/[id]/components/
|
||||
- client-tabs.tsx
|
||||
- intake-tab.tsx
|
||||
- plan-tab.tsx
|
||||
- profile-tab.tsx
|
||||
```
|
||||
|
||||
**Actie:** Check of deze geïmporteerd worden in Server Components. Zo ja, overweeg wrappers of default exports.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Symptom | Likely Cause | Solution |
|
||||
|---------|--------------|----------|
|
||||
| `undefined reading 'call'` | Named export Client in Server | Use wrapper or default export |
|
||||
| Intermittent/disappears on refresh | Webpack cache | Clear .next, restart |
|
||||
| Only in production build | SSR/hydration mismatch | Check dynamic imports |
|
||||
| After HMR (file save) | Fast Refresh issue | Full reload or restart dev |
|
||||
|
||||
## Samenvatting
|
||||
|
||||
**Root cause:** Next.js Server/Client Component boundary + webpack module chunking + named exports = module resolution failure
|
||||
|
||||
**Best fix:** Wrapper component met default export
|
||||
|
||||
**Prevention:**
|
||||
1. Default exports voor Client Components
|
||||
2. Wrappers voor Server → Client imports in layouts
|
||||
3. Clean cache bij persistente problemen
|
||||
4. Vermijd mixed type/component imports
|
||||
Reference in New Issue
Block a user