Multiple features and improvements: Reports/Rapportage API: - Created REST API endpoints: /api/reports (GET/POST), /api/reports/[id] (GET/PATCH/DELETE) - Added /api/reports/classify endpoint for AI classification - Supabase migrations: reports table + RLS policies - Server utilities: api-client.ts for DRY fetch logic - Type definitions: lib/types/report.ts with Zod schemas - Removed old rapportage-modal component (replaced by split-view) Speech Recorder Refactor: - Moved speech-recorder from intake-specific to shared components/ - Updated treatment-advice-form to use new location - Updated intake actions for speech functionality UI Components (shadcn): - Added dialog, dropdown-menu, toast, toaster components - Added use-toast hook for toast notifications Documentation: - Reorganized docs/release/ → docs/reports/ for better structure - Archived old specs to docs/specs/archive/ - Added screening-system.mdx documentation - Added rapportage-split-view-design.md - Added UI screenshots for troubleshooting Dependencies: - Updated package.json and pnpm-lock.yaml - Regenerated database.types.ts from Supabase 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
9.7 KiB
E3.S3 - Patient CRUD
Epic: E3 - Patients & Organizations Story: E3.S3 - Patient CRUD Story Points: 6 Status: ✅ Compleet
Doel
Volledige CRUD operaties voor patiënten met validatie.
Acceptatiecriteria
- Create: Nieuwe patiënt aanmaken met validatie
- Read: Patiënt gegevens ophalen en tonen
- Update: Bestaande patiënt bijwerken
- Delete: Patiënt verwijderen met confirmatie
- BSN 11-proef validatie
- Alle verplichte velden (volgens bouwplan)
- John Doe support (crisis opname zonder BSN)
Implementatie
1. Server Actions (actions.ts)
📁 Locatie: app/epd/patients/actions.ts
CRUD Functies:
// Create
export async function createPatient(fhirPatient: FHIRPatient): Promise<FHIRPatient>
// Read
export async function getPatient(id: string): Promise<FHIRPatient>
export async function getPatients(filters): Promise<{ patients, total, page, pageSize }>
// Update
export async function updatePatient(id: string, fhirPatient: FHIRPatient): Promise<FHIRPatient>
// Delete
export async function deletePatient(id: string): Promise<{ success: boolean }>
FHIR API Integration:
- POST
/api/fhir/Patient- Create - GET
/api/fhir/Patient/:id- Read one - GET
/api/fhir/Patient?params- Read many (met paginatie) - PUT
/api/fhir/Patient/:id- Update - DELETE
/api/fhir/Patient/:id- Delete
2. Patient Form Component
📁 Locatie: app/epd/patients/components/patient-form.tsx
Features:
A. BSN Validatie
11-proef Check:
function validateBSN(bsn: string): boolean {
if (!bsn || bsn.length !== 9) return false;
const digits = bsn.split('').map(Number);
if (digits.some(isNaN)) return false;
// Modulo-11 check
const sum = digits.reduce((acc, digit, index) => {
if (index < 8) {
return acc + digit * (9 - index);
}
return acc - digit;
}, 0);
return sum % 11 === 0;
}
Validatie regels:
- 9 cijfers verplicht
- Alleen numerieke karakters
- Modulo-11 proef moet kloppen
- Optioneel bij John Doe registratie
B. Form Secties
Stap 1: Persoonlijke gegevens
- ✅ Voorvoegsel (optioneel)
- ✅ Voornaam (verplicht)
- ✅ Achternaam (verplicht)
- ✅ BSN (9 cijfers, 11-proef) - verplicht tenzij John Doe
- ✅ Geboortedatum (verplicht, max vandaag)
- ✅ Geslacht (verplicht): Man, Vrouw, Anders, Onbekend
Stap 2: Adresgegevens
- ✅ Straat + huisnummer (optioneel)
- ✅ Postcode (optioneel)
- ✅ Woonplaats (optioneel)
Stap 3: Contactgegevens
- ✅ Telefoonnummer (optioneel)
- ✅ E-mail (optioneel, email validatie)
Stap 4: Verzekering
- ✅ Verzekeraar (optioneel)
- ✅ Polisnummer (optioneel)
- ✅ Huisarts naam (optioneel)
- ✅ Huisarts AGB-code (optioneel, 8 cijfers)
Stap 5: Noodcontact
- ✅ Naam contactpersoon (optioneel)
- ✅ Relatie (optioneel)
- ✅ Telefoonnummer (optioneel)
C. John Doe Support
Features:
- Checkbox om John Doe aan te geven
- BSN wordt optioneel bij John Doe
- Warning indicator voor incomplete gegevens
- Mogelijkheid om later BSN aan te vullen
- Custom FHIR extension:
john-doe
Use case:
- Crisis opnames waarbij identiteit niet direct bekend is
- Patiënt kan later worden geüpdatet met volledige gegevens
D. FHIR Mapping
Extensions gebruikt:
{
"extension": [
// Episode status
{
"url": "http://mini-epd.local/fhir/StructureDefinition/episode-status",
"valueCode": "planned" | "active" | "finished" | "cancelled"
},
// John Doe flag
{
"url": "http://mini-epd.local/fhir/StructureDefinition/john-doe",
"valueBoolean": true | false
},
// Insurance (custom)
{
"url": "http://mini-epd.local/fhir/StructureDefinition/insurance",
"valueString": "{\"company\":\"...\",\"number\":\"...\"}"
},
// General Practitioner (custom)
{
"url": "http://mini-epd.local/fhir/StructureDefinition/general-practitioner",
"valueString": "{\"name\":\"...\",\"agb\":\"...\"}"
}
],
"contact": [
// Emergency contact (FHIR standard)
{
"relationship": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v2-0131",
"code": "C",
"display": "Emergency Contact"
}],
"text": "Partner" | "Ouder" | "Kind" | etc.
}],
"name": { "text": "..." },
"telecom": [{ "system": "phone", "value": "...", "use": "home" }]
}
]
}
3. Delete Patient Component
📁 Locatie: app/epd/patients/components/delete-patient-button.tsx
Features:
A. Two-Step Confirmation
Step 1: Initial Warning
- Rode "Gevaarlijke zone" sectie
- Waarschuwing dat actie niet ongedaan gemaakt kan worden
- "Patiënt verwijderen" button
Step 2: Final Confirmation
- Gedetailleerde lijst van wat wordt verwijderd:
- Alle persoonlijke gegevens
- Alle screening en intake informatie
- Alle diagnoses en observaties
- Alle behandelplannen en doelen
- Alle documenten en rapportages
- Patiëntnaam wordt getoond
- "Ja, verwijder permanent" button
- Annuleren button
B. Safety Features
- Disabled state tijdens verwijderen
- Loading indicator
- Error handling met feedback
- Redirect naar overzichtspagina na succes
- Cache revalidation
4. Page Implementations
Create Page:
- 📁
app/epd/patients/new/page.tsx - Gebruikt PatientForm zonder patient prop
- "Terug naar patiënten" link
- Clear page title en beschrijving
Read Page:
- 📁
app/epd/patients/[id]/page.tsx - Toont patiënt detail met tabs
- Basisgegevens tab voor view/edit
Update Page:
- 📁
app/epd/patients/[id]/basisgegevens/page.tsx - Gebruikt PatientForm met patient prop
- John Doe warning indien van toepassing
- Missing BSN warning
- Delete button onderaan
List Page:
- 📁
app/epd/patients/page.tsx - Tabel met alle patiënten (zie E3.S2)
- "Nieuwe patiënt" button
Validatie
Client-side (HTML5)
Built-in validatie:
requiredattribute voor verplichte veldentype="email"voor email validatietype="tel"voor telefoonnummertype="date"metmaxvoor geboortedatummaxLengthenpatternvoor BSN/AGBpattern="[0-9]{9}"voor BSNpattern="[0-9]{8}"voor AGB
Server-side (Actions)
Validatie in handleSubmit:
- BSN 11-proef check (tenzij John Doe)
- Error throwing bij ongeldige data
- FHIR API valideert ook server-side
Error handling:
- Try-catch om alle errors
- User-friendly error messages
- Error state in UI
UI/UX Details
Form Layout
Desktop (md+):
- Grid layouts: 2-3 kolommen voor gerelateerde velden
- Grouped sections met headers
- Visual separation met borders
Mobile:
- Stack layout (1 kolom)
- Responsive grid → stack
- Touch-friendly input sizes
Visual Feedback
States:
- Focus ring (teal) op inputs
- Hover states op buttons
- Loading states tijdens submit/delete
- Disabled states
- Error states (red border + message)
Colors:
- Teal: Primary actions, focus
- Red: Danger (delete), errors
- Amber: Warnings (John Doe)
- Orange: Info (incomplete BSN)
- Slate: Neutral elements
Accessibility
Features:
- Label voor alle inputs
- Aria-labels waar nodig
- Keyboard navigation (Tab, Enter)
- Clear error messages
- Confirmation voor destructieve acties
Testing Checklist
Create
- Nieuwe patiënt aanmaken met alle velden
- Nieuwe patiënt aanmaken met minimale velden
- BSN validatie werkt (reject invalid)
- John Doe aanmaken zonder BSN
- Form validatie toont errors
- Redirect naar detail pagina na succes
Read
- Patiënt detail pagina toont alle gegevens
- Lijst pagina toont alle patiënten
- Missing gegevens worden correct getoond (-)
- John Doe indicator zichtbaar
Update
- Bestaande patiënt bewerken werkt
- Velden pre-filled met huidige waarden
- John Doe → regulier (BSN toevoegen)
- Update success toont correcte data
- John Doe warning verdwijnt na BSN toevoegen
Delete
- Delete button zichtbaar op basisgegevens
- First confirmation shows warning
- Second confirmation toont details
- Annuleren werkt op beide stappen
- Delete success redirect naar lijst
- Patiënt is echt verwijderd
Validation
- BSN 11-proef reject: 123456789
- BSN 11-proef accept: 111222333 (example valid)
- Email validatie werkt
- Geboortedatum niet in toekomst
- Required velden kunnen niet leeg
- AGB moet 8 cijfers zijn
Bekende Beperkingen
-
FHIR API Afhankelijkheid:
- Alle CRUD werkt via
/api/fhir/Patient - API moet volledig geïmplementeerd zijn
- Cascade delete moet in API geregeld zijn
- Alle CRUD werkt via
-
Validatie:
- Momenteel alleen HTML5 + BSN check
- Geen Zod schema validatie (toekomstige verbetering)
- Server-side validatie in FHIR API
-
Multi-step Wizard:
- Bouwplan suggereert wizard
- Huidige implementatie: single page form
- Werkt goed, maar kan verbeterd naar wizard UX
-
Soft Delete:
- Momenteel hard delete
- Toekomstige verbetering: soft delete met archivering
Volgende Stappen
Na E3.S3:
- E4.S1 - Encounter tijdlijn
- Eventueel: Zod validation schema
- Eventueel: Multi-step wizard UX
- Eventueel: Soft delete / archivering
- Eventueel: Audit trail (wie/wanneer gewijzigd)
Referenties
- Bouwplan:
docs/bouwplan-mini-epd.md(regel 356, E3.S3) - Patient Form:
app/epd/patients/components/patient-form.tsx - Delete Button:
app/epd/patients/components/delete-patient-button.tsx - Actions:
app/epd/patients/actions.ts - New Page:
app/epd/patients/new/page.tsx - Edit Page:
app/epd/patients/[id]/basisgegevens/page.tsx - FHIR Types:
lib/fhir/index.ts
Datum voltooid: 2025-11-22 Status: ✅ Compleet Dependencies voltooid: E3.S2 (Patients lijst) Blokkeert: E4.S1 (Encounter tijdlijn)