@@ -17,11 +17,13 @@ Toelichting: dit bouwt voort op het Swift conversatie‑ model en hergebruikt de
### 2.1 Technische Stack
- Frontend: Next.js App Router + React + TypeScript
- Styling: Tailwind CSS
- State: Zustand (Swift store)
- Backend: Next.js route handlers + Supabase (encounters)
- AI/Intent: Local regex + Claude Haiku fallback
- Auth: Supabase Auth (server-side guard )
- Styling: Tailwind CSS + shadcn/ui components
- State: Zustand (Swift store) + React Query for data caching
- Backend: Next.js route handlers + Supabase (encounters table )
- AI/Intent: Two-tier system ( Local regex <50ms + Claude Haiku fallback ~400ms)
- Date/Time: date-fns library (al aanwezig )
- Auth: Supabase Auth (server-side guard via `lib/auth/server.ts` )
- Voice: Deepgram (existing integration voor voice input)
### 2.2 Projectkaders
- Scope (MVP): agenda_query, create_appointment, cancel_appointment, reschedule_appointment + AgendaBlock.
@@ -31,18 +33,36 @@ Toelichting: dit bouwt voort op het Swift conversatie‑ model en hergebruikt de
- Reuse bestaande agenda actions waar mogelijk.
### 2.3 Programmeer uitgangspunten
- DRY: hergebruik `app/epd/agenda/actions.ts` .
- DRY: hergebruik `app/epd/agenda/actions.ts` (getEncounters, createEncounter, cancelEncounter, rescheduleEncounter) .
- KISS: snelle API routes + simpele AgendaBlock UI.
- SOC: intent parsing, data fetching en UI gescheiden.
- YAGNI: alleen P1/P2 uit FO, geen extra planner features.
### 2.4 Performance Targets
| Metric | Target | Actual (Expected) |
|--------|--------|-------------------|
| Local pattern match | <50ms | ~10-15ms |
| Local + entity extraction | <100ms | ~30-50ms |
| AI fallback (cold) | <800ms | ~400-600ms |
| AI fallback (warm) | <500ms | ~200-400ms |
| Total (local path) | <150ms | ~50-80ms |
| Total (AI path) | <1000ms | ~500-700ms |
### 2.5 Confidence Thresholds
| Confidence | Actie | Voorbeeld |
|------------|-------|-----------|
| * * >0.9** | Direct artifact openen met prefill | "afspraken vandaag" |
| **0.7-0.9 ** | Artifact + bevestigingsvraag | "maak afspraak jan morgen" (tijd ontbreekt) |
| **0.5-0.7 ** | Verduidelijkingsvraag in chat | "maak afspraak" (patient/tijd ontbreekt) |
| * * <0.5** | Fallback: "Ik begrijp het niet" | Gibberish input |
---
## 3. Epics & Stories Overzicht
| Epic ID | Titel | Doel | Status | Stories | Opmerkingen |
|---------|-------|------|--------|---------|-------------|
| E0 | Alignment & scope | MVP afbakenen en keuzes vastleggen | Done | 2 | FO‑ based |
| E1 | Intent & entity layer | Agenda intents + entities toevoegen | To Do | 4 | Swift intent stack |
| E1 | Intent & entity layer | Agenda intents + entities toevoegen | Done | 4 | Swift intent stack |
| E2 | Date/time parsing | NLP‑ helpers voor datum/tijd | To Do | 3 | Geen nieuwe deps |
| E3 | Backend integratie | Agenda data APIs + reuse actions | To Do | 4 | Auth vereist |
| E4 | AgendaBlock UI | List/create/cancel/reschedule views | To Do | 5 | Swift artifact |
@@ -76,13 +96,95 @@ Epic doel: agenda intent types en entities toevoegen aan Swift.
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points |
|----------|--------------|---------------------|--------|------------------|--------------|
| E1.S1 | SwiftIntent uitbreiden | Nieuwe a genda intents toegevoegd in types/store | To Do | E0.S1 | 2 |
| E1.S2 | Local intent patterns | Regex patterns voor agenda intents in `intent-classifier.ts` | To Do | E1.S1 | 3 |
| E1.S3 | AI fallback prompt | Prompt in `intent-classifier-ai.ts` uitgebreid met agenda intents | To Do | E1.S1 | 3 |
| E1.S4 | Entities schema | `ExtractedEntities` uitgebreid met date/time/identifier | To Do | E1.S1 | 2 |
| E1.S1 | SwiftIntent uitbreiden | A genda intent name s toegevoegd in types/store | Done | E0.S1 | 2 |
| E1.S2 | Local intent patterns | Regex patterns voor agenda intents in `intent-classifier.ts` | Done | E1.S1 | 3 |
| E1.S3 | AI fallback prompt | Prompt in `intent-classifier-ai.ts` uitgebreid met agenda intents | Done | E1.S1 | 3 |
| E1.S4 | Entities schema | `ExtractedEntities` uitgebreid met date/time/identifier | Done | E1.S1 | 2 |
Technical notes:
** Technical notes:**
**E1.S1 - SwiftIntent type uitbreiding: **
- File: `lib/swift/types.ts`
- Houd `SwiftIntent` single source of truth (voorkom duplicatie).
- SwiftIntent (na uitbreiding):
```ts
type SwiftIntent =
| 'dagnotitie'
| 'zoeken'
| 'overdracht'
| 'agenda_query' // 🆕
| 'create_appointment' // 🆕
| 'cancel_appointment' // 🆕
| 'reschedule_appointment'// 🆕
| 'unknown';
` ``
**E1.S2 - Local pattern examples:**
- File: ` lib/swift/intent-classifier.ts`
- Toevoegen aan ` INTENT_PATTERNS`:
` ``ts
agenda_query: [
{ pattern: /^afspraken?\\b/i, weight: 1.0 },
{ pattern: /^agenda\\b/i, weight: 1.0 },
{ pattern: /^(wat|wanneer)\\s+is\\s+(mijn\\s+)?volgende\\s+afspraak/i, weight: 1.0 },
],
create_appointment: [
{ pattern: /^maak\\s+afspraak\\b/i, weight: 1.0 },
{ pattern: /^plan\\s+(een\\s+)?(intake|afspraak)\\b/i, weight: 1.0 },
],
cancel_appointment: [
{ pattern: /^annuleer\\s+(de\\s+)?afspraak/i, weight: 1.0 },
],
reschedule_appointment: [
{ pattern: /^verzet\\s+(de\\s+)?afspraak/i, weight: 1.0 },
{ pattern: /^\\d{1,2}:\\d{2}\\s+naar\\s+\\d{1,2}:\\d{2}/i, weight: 0.9 },
],
` ``
**E1.S3 - AI System Prompt addition:**
- File: ` lib/swift/intent-classifier-ai.ts`
- Toevoegen aan ` INTENT_CLASSIFIER_SYSTEM_PROMPT`:
- Agenda intent descriptions + voorbeelden
- Entity extraction instructies (patientName, dateRange, datetime, type, identifier, newDatetime)
- Response format met nieuwe entities
**E1.S4 - ExtractedEntities uitbreiding:**
- File: ` lib/swift/types.ts`
- Toevoegen:
` ``ts
interface ExtractedEntities {
// Bestaande entities
patientName?: string;
category?: VerpleegkundigCategory;
content?: string;
// 🆕 Agenda entities
dateRange?: {
start: Date;
end: Date;
label: 'vandaag' | 'morgen' | 'deze week' | 'volgende week' | 'custom';
};
datetime?: {
date: Date;
time: string; // "HH:mm" format
};
appointmentType?: 'intake' | 'behandeling' | 'follow-up' | 'telefonisch' |
'huisbezoek' | 'online' | 'crisis' | 'overig';
location?: 'praktijk' | 'online' | 'thuis';
identifier?: {
type: 'patient' | 'time' | 'both';
patientName?: string;
patientId?: string;
time?: string;
date?: Date;
encounterId?: string;
};
newDatetime?: {
date: Date;
time: string;
};
}
` ``
---
@@ -95,6 +197,34 @@ Epic doel: datum/tijd interpretatie uit natuurlijke taal.
| E2.S2 | Time parser utility | Tijd normalisatie (14:00, half drie) | To Do | E2.S1 | 2 |
| E2.S3 | Entity extraction hook | Entity extractor gebruikt parser output | To Do | E2.S2 | 2 |
**Technical notes:**
**E2.S1 - Date parser implementation:**
- File: ` lib/swift/date-time-parser.ts`
- Functie: ` parseRelativeDate(input: string): Date | DateRange | null`
- Ondersteunt:
- "vandaag", "morgen", "overmorgen"
- "maandag", "dinsdag", ... (next weekday)
- "deze week", "volgende week" (returns DateRange)
- Fallback naar date-fns ` parse()` voor "30 december", "28-12-2024"
- Gebruik ` date-fns` helpers: ` addDays()`, ` startOfWeek()`, ` endOfWeek()`, ` addWeeks()`
**E2.S2 - Time parser implementation:**
- Functie: ` parseTime(input: string): string | null`
- Ondersteunt:
- "14:00" → "14:00"
- "14" → "14:00"
- "twee uur" → "14:00"
- "half drie" → "14:30"
- "kwart voor drie" → "14:45"
- Returns ` HH:mm` format string
**E2.S3 - Integration:**
- Parser functies worden aangeroepen in entity extraction flow
- Local pattern matching extraheert ruwe strings ("morgen", "14:00")
- Parser functies normaliseren naar Date/time formats
- AI fallback gebruikt parser voor validation
---
### Epic 3 — Backend integratie
@@ -107,9 +237,42 @@ Epic doel: agenda data ontsluiten voor Swift blocks.
| E3.S3 | Cancel/reschedule API | Endpoints die ` cancelEncounter`/` rescheduleEncounter` aanroepen | To Do | E3.S1 | 3 |
| E3.S4 | Patient match API | Fuzzy patiënt matching + disambiguation lijst | To Do | E1.S4 | 2 |
Technical notes:
- Reuse `app/epd/agenda/actions.ts` voor database logic.
- Auth guard via `createClient()` en `supabase.auth.getUser()` .
** Technical notes:**
**E3.S1 - Agenda query endpoint:**
- Route: ` GET /api/swift/agenda?start=2024-12-27&end=2024-12-27`
- Auth: via ` createClient()` from ` lib/auth/server.ts`
- Hergebruik: ` getEncounters()` from ` app/epd/agenda/actions.ts`
- Response: ` { appointments: Encounter[] }`
- Filters: practitioner_id = current user, status = 'planned', period_start in range
- Order: chronological (period_start ASC)
**E3.S2 - Create appointment endpoint:**
- Route: ` POST /api/swift/agenda/create`
- Body: ` { patientId, datetime: { date, time }, type, location, notes? }`
- Validation: Zod schema, Dutch error messages
- Hergebruik: ` createEncounter()` from ` app/epd/agenda/actions.ts`
- Mapping:
- type → typeCode (FHIR encounter type)
- location → classCode ('AMB' = praktijk, 'VR' = online, 'HH' = thuis)
- datetime → periodStart/periodEnd (1 hour duration default)
- Response: ` { encounterId, success: true }`
**E3.S3 - Cancel/Reschedule endpoints:**
- Route: ` POST /api/swift/agenda/cancel`
- Body: ` { encounterId }`
- Hergebruik: ` cancelEncounter(encounterId)` (soft delete: status → 'cancelled')
- Route: ` POST /api/swift/agenda/reschedule`
- Body: ` { encounterId, newDatetime: { date, time } }`
- Hergebruik: ` rescheduleEncounter(encounterId, periodStart, periodEnd)`
**E3.S4 - Patient search endpoint:**
- Route: ` GET /api/swift/patients/search?q=jan`
- Fuzzy match op patient name (ILIKE %query%)
- Response: ` { patients: Array<{ id, name, bsn }> }`
- Limit: 10 resultaten
- Used voor: disambiguation bij meerdere matches
---
@@ -124,6 +287,85 @@ Epic doel: Swift artifact voor agenda flows.
| E4.S4 | Cancel view | Disambiguation + confirm flow | To Do | E4.S1 | 3 |
| E4.S5 | Reschedule view | Edit form met nieuwe tijd | To Do | E4.S1 | 3 |
**Technical notes:**
**E4.S1 - AgendaBlock component structure:**
- File: ` components/swift/artifacts/blocks/agenda-block.tsx`
- Props interface:
` ``ts
interface AgendaBlockProps {
mode: 'list' | 'create' | 'cancel' | 'reschedule';
appointments?: Encounter[];
dateRange?: { start: Date; end: Date; label: string };
prefillData?: {
patient?: { id: string; name: string };
datetime?: { date: Date; time: string };
type?: EncounterType;
location?: EncounterLocation;
};
disambiguationOptions?: Encounter[];
onClose?: () => void;
}
` ``
- Architecture: switch statement op mode → render juiste sub-component
- Styling: max-width 600px, max-height 80vh, overflow-y auto
**E4.S2 - List view:**
- Component: ` <AgendaListView />`
- Layout:
- Header: Datum label (e.g., "Afspraken Vandaag - 27 december") + close button
- Body: Scrollable lijst van appointment cards
- Footer: Link naar ` /epd/agenda` ("📅 Open volledige agenda →")
- Appointment card bevat:
- Tijd (09:00 - 10:00)
- Patient naam (klikbaar → opens PatientContextCard)
- Type badge met color coding (intake=blauw, behandeling=groen, crisis=rood)
- Locatie icon (📍 Praktijk, 🌐 Online, 🏠 Thuis)
- Actions: [Details] [Annuleren]
- Empty state: "📭 Geen afspraken gevonden" + [Maak nieuwe afspraak] button
**E4.S3 - Create form:**
- Component: ` <AgendaCreateForm />`
- Fields:
- Patiënt* (autocomplete, pre-filled)
- Datum* (date picker, pre-filled)
- Tijd* (time picker 07:00-20:00, pre-filled)
- Type* (radio buttons: Intake, Behandeling, Vervolg, Telefonisch, Huisbezoek, Crisis)
- Locatie* (radio buttons: Praktijk, Online, Thuis)
- Notities (textarea, optioneel, max 500 chars)
- Validation:
- Patient required
- Date cannot be in past
- Time within 07:00-20:00
- Conflict warning: "⚠️ Conflict: Je hebt al een afspraak om 14:00 met Marie" (optional feature)
- Submit: [Annuleren] [✓ Afspraak maken]
- States: initial → validating → submitting → success/error
**E4.S4 - Cancel view:**
- Component: ` <AgendaCancelView />`
- Submode 1: Disambiguation (multiple matches)
- Radio list met opties: "○ 28-12-2024 09:00 - Jan de Vries (Intake)"
- [Annuleren] [Volgende →] buttons
- Submode 2: Confirmation (single match or after disambiguation)
- Appointment details card
- Warning: "⚠️ Deze actie kan niet ongedaan worden gemaakt."
- [Terug] [✓ Annuleren] buttons
**E4.S5 - Reschedule view:**
- Component: ` <AgendaRescheduleForm />`
- Layout:
- Afspraak details (readonly)
- Huidige datum/tijd (readonly, strikethrough styling)
- Nieuwe datum/tijd* (editable date + time pickers, pre-filled)
- Conflict check: "✅ Geen conflicten gevonden" or warning
- [Annuleren] [✓ Verzetten] buttons
**Styling specs:**
- Colors: Teal-700 primary, appointment type badges (zie FO sectie 13.3)
- Animations: slide-in from right 200ms, fade-out on close
- Typography: text-sm voor body, text-base voor headers
- Spacing: 16px padding, 12px card gaps
---
### Epic 5 — Chat orchestration
@@ -135,6 +377,75 @@ Epic doel: agenda intents laten landen in juiste artifact.
| E5.S2 | Chat prompt update | ` /api/swift/chat` prompt bevat agenda sectie + action format | To Do | E1.S3 | 2 |
| E5.S3 | Error states | User-friendly errors + link naar ` /epd/agenda` | To Do | E3.S1 | 2 |
**Technical notes:**
**E5.S1 - Intent router implementation:**
- Location: Swift store of artifact manager
- Functie: ` openArtifactForIntent(intent, entities, confidence)`
- Logic:
` ``ts
if (confidence < 0.7) return null; // Trigger verduidelijkingsvraag
switch (intent) {
case 'agenda_query':
return { type: 'AgendaBlock', mode: 'list', prefill: { dateRange } };
case 'create_appointment':
if (!entities.patientName) return null; // Need patient
return { type: 'AgendaBlock', mode: 'create', prefill: { patient, datetime, type, location } };
case 'cancel_appointment':
return { type: 'AgendaBlock', mode: 'cancel', prefill: { identifier } };
case 'reschedule_appointment':
if (!entities.identifier) return null; // Need to know which appointment
return { type: 'AgendaBlock', mode: 'reschedule', prefill: { identifier, newDatetime } };
}
` ``
**E5.S2 - Chat API system prompt addition:**
- File: ` app/api/swift/chat/route.ts`
- Toevoegen aan system prompt:
` ``markdown
## Agenda & Afspraken Beheer
Je helpt gebruikers met agenda-gerelateerde taken.
### Intents die je herkent:
1. **agenda_query** - Afspraken opvragen
Voorbeelden: "afspraken vandaag", "wat is volgende", "agenda morgen"
Actie: Toon lijst van afspraken in AgendaBlock
2. **create_appointment** - Nieuwe afspraak maken
Voorbeelden: "maak afspraak met Jan morgen 14:00", "plan intake"
Required: patient, date, time
Optional: type (default: behandeling), location (default: praktijk)
3. **cancel_appointment** - Afspraak annuleren
Voorbeelden: "annuleer afspraak Jan", "cancel 14:00"
Actie: Toon confirmation dialog
4. **reschedule_appointment** - Afspraak verzetten
Voorbeelden: "verzet 14:00 naar 15:00", "verzet Jan naar dinsdag"
Actie: Toon edit form met oude + nieuwe tijd
### Entity Extraction:
- Patient: extraheer volledige naam, gebruik activePatient als user zegt "deze patiënt"
- Date/Time: parse relatieve datums ("morgen", "dinsdag"), validate geen verleden
- Type: intake, behandeling, follow-up, telefonisch (default: behandeling)
- Location: praktijk, online, thuis (default: praktijk)
### Verduidelijkingsvragen:
Stel vragen bij:
- Meerdere patiënten met zelfde naam
- Onduidelijke datum
- Ontbrekende tijd bij create
- Meerdere matches bij cancel/reschedule
` ``
**E5.S3 - Error handling:**
- Server errors: "Er ging iets mis bij het ophalen van je afspraken. Probeer het opnieuw of [open de volledige agenda](/epd/agenda)."
- Auth errors: Redirect naar ` /login`
- Validation errors: Dutch messages ("Datum kan niet in het verleden liggen")
- Network errors: Retry logic + user-friendly message
---
### Epic 6 — QA & docs
@@ -154,30 +465,129 @@ Test types:
| Test Type | Scope | Tools | Verantwoordelijke |
|-----------|-------|-------|-------------------|
| Lint | App code | pnpm lint | Developer |
| Smoke tests | Agenda intents + artifact flows | Manual checklist | Developer/UX |
| Type check | TypeScript | pnpm build | Developer |
| Smoke tests | Agenda intents + artifact flows | Manual checklist (20 scenarios) | Developer/UX |
| Regression | /epd/agenda klassiek | Manual checklist | Developer |
Manual t est c hecklist (MVP ):
- "afspraken vandaag" → AgendaBlock list view
- "maak afspraak Jan morgen 14:00" → create form met prefill
- "annuleer afspraak Jan" → disambiguation indien nodig
- "verzet 14:00 naar 15:00" → reschedule form
- Link naar `/epd/agenda` werkt
- Geen auth → redirect naar `/login`
### Manual T est C hecklist (uit FO, 20 scenarios ):
| # | Scenario | Expected Result | Priority | Status |
|---|----------|-----------------|----------|--------|
| 1 | "afspraken vandaag" | AgendaBlock list view, toont vandaag's afspraken | P1 | ⬜ |
| 2 | "wat is volgende afspraak" | Chat response met eerstvolgende, AgendaBlock toont details | P1 | ⬜ |
| 3 | "maak afspraak jan morgen 14:00" | Create form met prefill, patient gevonden | P1 | ⬜ |
| 4 | Voice: "maak intake marie vrijdag 10:00" | Transcript correct, create form opent | P2 | ⬜ |
| 5 | "maak afspraak" (incomplete) | Verduidelijkingsvraag: "Met welke patiënt?" | P1 | ⬜ |
| 6 | "maak afspraak onbekende patient" | Patient search fallback, suggesties | P2 | ⬜ |
| 7 | Create form submit → success | Toast, chat confirmation, artifact sluit | P1 | ⬜ |
| 8 | "annuleer afspraak jan" (1 match) | Confirmation dialog, direct match | P1 | ⬜ |
| 9 | "annuleer afspraak jan" (3 matches) | Disambiguation radio list | P1 | ⬜ |
| 10 | Cancel confirm → success | Afspraak status=cancelled, toast | P1 | ⬜ |
| 11 | "verzet 14:00 naar 15:00" | Reschedule form, tijd pre-filled | P1 | ⬜ |
| 12 | Reschedule submit → success | Tijd updated, toast confirmation | P1 | ⬜ |
| 13 | Conflict warning (overlapping) | Warning banner in create form | P2 | ⬜ |
| 14 | Click patient name in list | PatientContextCard opent | P2 | ⬜ |
| 15 | Click "Details" button | Navigates to /epd/agenda with filter | P2 | ⬜ |
| 16 | Empty state (geen afspraken) | Placeholder met "Maak nieuwe afspraak" | P1 | ⬜ |
| 17 | Server error tijdens query | Error in chat, geen artifact | P1 | ⬜ |
| 18 | Date in past validation | "Kan geen afspraken in verleden maken" | P1 | ⬜ |
| 19 | Context-aware: "maak afspraak deze patient" | Gebruikt active patient uit context | P2 | ⬜ |
| 20 | Multiple artifacts (3 max) | Agenda + Dagnotitie + Context card, tabs | P2 | ⬜ |
### Regression Test Checklist:
| # | Test | Expected Result | Status |
|---|------|-----------------|--------|
| R1 | Klassieke agenda ` /epd/agenda` werkt nog | Kan afspraken zien/maken/wijzigen | ⬜ |
| R2 | Swift dagnotitie intent ongewijzigd | "dagnotitie jan medicatie" opent DagnotatieBlock | ⬜ |
| R3 | Swift zoeken intent ongewijzigd | "zoek jan" opent ZoekenBlock | ⬜ |
| R4 | Swift overdracht intent ongewijzigd | "overdracht" opent OverdrachtBlock | ⬜ |
| R5 | Auth guard op alle endpoints | Geen auth → 401/redirect | ⬜ |
### Performance Test Targets:
| Metric | Target | Test Method |
|--------|--------|-------------|
| Local pattern match | <50ms | Browser DevTools Network tab |
| Create form open | <150ms total | Lighthouse/manual timing |
| AI fallback | <1000ms | DevTools, onduidelijke input |
| List view render (10 items) | <100ms | React DevTools Profiler |
---
## 6. Demo & Presentatieplan
Doel: korte demo van agenda planning via Swift.
## 6. User Stories (uit FO)
Flow :
1) "afspraken vandaag" → lijst
2) "maak afspraak met Jan morgen 14:00" → cre ate form → submit
3) "annuleer afspraak Jan" → confirm
### Primaire User Stories (P1 - MVP) :
| ID | Als | Wil ik | Zodat | Accept ati e |
|----|-----|--------|-------|------------|
| US-24 | Verpleegkundige | Snel overzicht afspraken vandaag | Ik weet waar ik moet zijn | "afspraken vandaag" → lijst in AgendaBlock, <3 sec |
| US-25 | Verpleegkundige | Check volgende afspraak tijdens werk | Ik op tijd ben | "wat is mijn volgende afspraak?" → directe info |
| US-27 | Verpleegkundige | Snelle afspraak tijdens telefoongesprek | Ik direct kan plannen | "maak afspraak jan morgen 14:00" → prefilled form, <15 sec |
| US-28 | Verpleegkundige | Context-aware planning | Ik niet steeds naam hoef te typen | "maak afspraak met deze patiënt" → gebruikt actieve patiënt |
| US-29 | Verpleegkundige | Voice input tijdens consult | Ik hands-free kan werken | Spraak → afspraak maken |
| US-30 | Verpleegkundige | Annuleren via chat | Ik snel kan annuleren | "annuleer afspraak jan" → confirmation → done |
| US-31 | Verpleegkundige | Snel verzetten | Ik afspraken flexibel kan aanpassen | "verzet 14:00 naar 15:00" → tijd update |
### Secundaire User Stories (P2 - Nice to Have):
| ID | Als | Wil ik | Zodat | Acceptatie |
|----|-----|--------|-------|------------|
| US-26 | Verpleegkundige | Weekoverzicht bekijken | Ik kan plannen | "agenda deze week" → gefilterde lijst |
| US-32 | Verpleegkundige | Disambiguation bij meerdere matches | Systeem helpt kiezen | Systeem vraagt "Welke Jan?" → lijst opties |
---
## 7. Risico's & Mitig atie
## 7. File Structuur (na implement atie)
` ``
lib/swift/
├── types.ts # SwiftIntent + ExtractedEntities uitbreidingen
├── intent-classifier.ts # Local patterns voor agenda intents
├── intent-classifier-ai.ts # AI prompt uitbreidingen
└── date-time-parser.ts # 🆕 Date/time parsing utilities
app/api/swift/
├── agenda/
│ ├── route.ts # 🆕 GET agenda query endpoint
│ ├── create/route.ts # 🆕 POST create appointment
│ ├── cancel/route.ts # 🆕 POST cancel appointment
│ └── reschedule/route.ts # 🆕 POST reschedule appointment
├── patients/
│ └── search/route.ts # 🆕 GET fuzzy patient search
└── chat/route.ts # Updated: agenda system prompt
components/swift/artifacts/blocks/
├── agenda-block.tsx # 🆕 Main AgendaBlock component
├── agenda-list-view.tsx # 🆕 List mode
├── agenda-create-form.tsx # 🆕 Create mode
├── agenda-cancel-view.tsx # 🆕 Cancel mode
└── agenda-reschedule-form.tsx # 🆕 Reschedule mode
app/epd/agenda/
└── actions.ts # ♻️ Hergebruikt (getEncounters, createEncounter, etc.)
` ``
---
## 8. Demo & Presentatieplan
Doel: korte demo van agenda planning via Swift (5 minuten).
**Demo Flow:**
1. **Agenda query**: "afspraken vandaag" → lijst met 3 afspraken
2. **Quick create**: "maak afspraak met Jan morgen 14:00" → create form → submit → success toast
3. **Cancel flow**: "annuleer afspraak Jan" → disambiguation (3 matches) → select → confirm → success
4. **Reschedule**: "verzet de 14:00 naar 15:00" → edit form → submit → success
5. **Fallback**: Link naar klassieke agenda tonen via footer
**Key Messaging:**
- Swift = snelle queries en actions (10-15 sec)
- Klassieke agenda = visuele planning en overzicht
- Voice input = hands-free werken tijdens consult
---
## 9. Risico's & Mitigatie
| Risico | Kans | Impact | Mitigatie | Owner |
|--------|------|--------|-----------|-------|
| Intent ambigu | Hoog | Middel | Disambiguation + fallback prompt | UX |
@@ -187,7 +597,58 @@ Flow:
---
## 8. Evaluatie & Lessons Learned
## 10. Sprint Planning & Implementatie Volgorde
### Voorgestelde Sprint Indeling (3 sprints):
**Sprint 1: Foundation (E1 + E2)**
- Focus: Intent layer + date/time parsing
- Stories: E1.S1, E1.S2, E1.S3, E1.S4, E2.S1, E2.S2, E2.S3
- Total: 17 SP
- Oplevering: Intent detection + entity extraction werkend, nog geen UI
- Test: Console log check van extracted entities
**Sprint 2: Backend + UI Foundation (E3 + E4.S1-S2)**
- Focus: API endpoints + AgendaBlock basis
- Stories: E3.S1, E3.S2, E3.S3, E3.S4, E4.S1, E4.S2
- Total: 14 SP
- Oplevering: Agenda query werkend met list view
- Test: "afspraken vandaag" end-to-end
**Sprint 3: UI Completion + Integration (E4.S3-S5 + E5 + E6)**
- Focus: Create/cancel/reschedule forms + orchestration
- Stories: E4.S3, E4.S4, E4.S5, E5.S1, E5.S2, E5.S3, E6.S1, E6.S2, E6.S3
- Total: 20 SP
- Oplevering: MVP compleet
- Test: Alle 20 test scenarios
**Total MVP: 51 SP (~3 sprints à 2 weken = 6 weken)**
### Implementatie Volgorde (binnen stories):
Voor elke story, volg deze volgorde:
1. **Types first**: Definieer interfaces/types
2. **Backend**: API endpoints + server actions
3. **Frontend**: UI components
4. **Integration**: Wire backend ↔ frontend
5. **Test**: Manual test scenario's
### Critical Path:
` ``
E1.S1 (types) → E1.S2 (patterns) → E1.S4 (entities) → E2 (parsers) →
E3.S1 (query API) → E4.S1 (skeleton) → E4.S2 (list view) →
E5.S1 (routing) → Milestone: Basic Query Werkend
E3.S2 (create API) → E4.S3 (create form) → Milestone: Create Werkend
E3.S3 (cancel API) → E4.S4 (cancel view) → Milestone: Cancel Werkend
E4.S5 (reschedule) → E5.S2 (prompt) → E6 (QA) → MVP Done
` ``
---
## 11. Evaluatie & Lessons Learned
Te documenteren na oplevering:
- Welke intents vaak misclassificeren?
- Hoe snel users afspraken kunnen plannen?
@@ -195,27 +656,102 @@ Te documenteren na oplevering:
---
## 9 . Referenties
- FO: `docs/swift/fo-swift-agenda-planning.md`
- Swift FO v3: `docs/swift/fo-swift-medical-scribe-v3.md`
- Agenda module: `app/epd/agenda`
- Swift chat: `app/api/swift/chat/route.ts`
- Intent classifier: `lib/swift/intent-classifier.ts`
## 12 . Referenties & Documentatie
### Primaire Documenten:
- **FO Agenda Afspraken**: ` docs/swift/fo-agenda-afspraken.md` - Gebruikersgericht FO
- **FO Agenda Planning**: ` docs/swift/fo-swift-agenda-planning.md` - Technisch FO met detailed specs
- **Swift FO v3**: ` docs/swift/fo-swift-medical-scribe-v3.md` - Basis conversational interface
- **Swift Bouwplan Core**: ` docs/swift/bouwplan-swift-standalone-module.md` - Development roadmap
### Code Referenties:
- **Bestaande Agenda**: ` app/epd/agenda` - Klassieke kalender (wordt hergebruikt)
- **Agenda Actions**: ` app/epd/agenda/actions.ts` - Server actions (getEncounters, createEncounter, etc.)
- **Swift Chat API**: ` app/api/swift/chat/route.ts` - Conversational endpoint
- **Intent Classifier**: ` lib/swift/intent-classifier.ts` - Local pattern matching
- **AI Classifier**: ` lib/swift/intent-classifier-ai.ts` - Claude Haiku fallback
- **Swift Types**: ` lib/swift/types.ts` - SwiftIntent & ExtractedEntities
### Libraries & Dependencies:
- **date-fns**: Date/time utilities (already installed)
- **Zod**: API validation schemas (already installed)
- **React Query**: Data caching (already installed)
- **shadcn/ui**: UI components (already installed)
- **Deepgram**: Voice input (already integrated)
### External References:
- [FHIR Encounter Resource](https://www.hl7.org/fhir/encounter.html) - Encounter data model
- [date-fns Documentation](https://date-fns.org/) - Date manipulation
- [React Query Best Practices](https://tanstack.com/query/latest) - Caching patterns
---
## 10 . Glossary & Abbreviations
## 13 . Glossary & Abbreviations
| Term | Betekenis |
|------|-----------|
| Epic | Grote feature of fase |
| Story | Kleine uitvoerbare taak |
| MVP | Minimum Viable Produc t |
| FO | Functioneel Ontwerp |
| SSE | Server-Sent Events |
| ** Epic** | Grote feature of fase, bevat meerdere stories |
| ** Story** | Kleine uitvoerbare taak (user story) |
| **SP** | Story Points - schatting van complexitei t |
| **MVP** | Minimum Viable Product |
| **FO** | Functioneel Ontwerp |
| **P1/P2** | Priority 1 (must have) / Priority 2 (nice to have) |
| **SSE** | Server-Sent Events |
| **RLS** | Row Level Security (Supabase) |
| **NLP** | Natural Language Processing |
| **Artifact** | Swift UI component (AgendaBlock, DagnotatieBlock, etc.) |
| **Intent** | Gebruikersintentie (agenda_query, create_appointment, etc.) |
| **Entity** | Geëxtraheerde data uit user input (patient, date, time) |
| **Disambiguation** | Verduidelijking bij meerdere matches |
| **Confidence** | Zekerheid van intent classificatie (0.0-1.0) |
| **Two-tier** | Local pattern matching + AI fallback systeem |
| **FHIR** | Fast Healthcare Interoperability Resources |
| **Encounter** | Afspraak/contact in FHIR terminologie |
### Domain-Specific Terms:
| Term | Betekenis |
|------|-----------|
| **Klassieke Agenda** | Bestaande visuele kalender in ` /epd/agenda` |
| **Swift Agenda ** | Nieuwe conversational agenda interface |
| **AgendaBlock ** | Swift artifact voor agenda functionaliteit |
| **Verpleegkundige ** | Primaire gebruikersrol (nurse/healthcare provider) |
| **Practitioner ** | FHIR term voor zorgverlener |
| **Quick Create ** | Snel afspraak maken via natuurlijke taal |
| **Hands-free ** | Werken met voice input (geen typen nodig) |
---
Versiehistorie:
## Versiehistorie
| Versie | Datum | Auteur | Wijziging |
|--------|-------|--------|-----------|
| v1.0 | 27-12-2025 | Colin Lit | Initiele versie |
| v1.0 | 27-12-2025 | Colin Lit | Initiele versie - basis epics en stories |
| v1.1 | 27-12-2025 | Claude Code | Uitgebreid met technische details uit FO's: patterns, entities, API specs, UI components, test scenarios, sprint planning, file structuur |
---
## Quick Reference Card
**Voor Developers - Start Here: **
1. Lees Epic 0 voor scope
2. Begin met E1.S1 (types uitbreiden)
3. Volg implementatie volgorde (sectie 10)
4. Check test scenarios (sectie 5)
5. Zie file structuur (sectie 7) voor waar code moet komen
**Voor Product Owners: **
- MVP scope: sectie 2.2
- User stories: sectie 6
- Demo plan: sectie 8
- Risico's: sectie 9
**Voor QA: **
- Test checklist: sectie 5 (20 scenarios)
- Regression tests: sectie 5
- Performance targets: sectie 2.4
**Voor Designers: **
- UI components: Epic 4 technical notes
- Styling specs: E4.S1-E4.S5
- User flows: FO documenten (zie sectie 12)