feat: migrate clients module to patients + add docs
This commit is contained in:
379
docs/release/E3.S3-patient-crud.md
Normal file
379
docs/release/E3.S3-patient-crud.md
Normal file
@@ -0,0 +1,379 @@
|
||||
# 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
|
||||
|
||||
- [x] **Create:** Nieuwe patiënt aanmaken met validatie
|
||||
- [x] **Read:** Patiënt gegevens ophalen en tonen
|
||||
- [x] **Update:** Bestaande patiënt bijwerken
|
||||
- [x] **Delete:** Patiënt verwijderen met confirmatie
|
||||
- [x] BSN 11-proef validatie
|
||||
- [x] Alle verplichte velden (volgens bouwplan)
|
||||
- [x] John Doe support (crisis opname zonder BSN)
|
||||
|
||||
## Implementatie
|
||||
|
||||
### 1. Server Actions (actions.ts)
|
||||
|
||||
📁 **Locatie:** `app/epd/patients/actions.ts`
|
||||
|
||||
**CRUD Functies:**
|
||||
|
||||
```typescript
|
||||
// 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:**
|
||||
```typescript
|
||||
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:**
|
||||
```typescript
|
||||
{
|
||||
"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:**
|
||||
- `required` attribute voor verplichte velden
|
||||
- `type="email"` voor email validatie
|
||||
- `type="tel"` voor telefoonnummer
|
||||
- `type="date"` met `max` voor geboortedatum
|
||||
- `maxLength` en `pattern` voor BSN/AGB
|
||||
- `pattern="[0-9]{9}"` voor BSN
|
||||
- `pattern="[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
|
||||
|
||||
1. **FHIR API Afhankelijkheid:**
|
||||
- Alle CRUD werkt via `/api/fhir/Patient`
|
||||
- API moet volledig geïmplementeerd zijn
|
||||
- Cascade delete moet in API geregeld zijn
|
||||
|
||||
2. **Validatie:**
|
||||
- Momenteel alleen HTML5 + BSN check
|
||||
- Geen Zod schema validatie (toekomstige verbetering)
|
||||
- Server-side validatie in FHIR API
|
||||
|
||||
3. **Multi-step Wizard:**
|
||||
- Bouwplan suggereert wizard
|
||||
- Huidige implementatie: single page form
|
||||
- Werkt goed, maar kan verbeterd naar wizard UX
|
||||
|
||||
4. **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)
|
||||
Reference in New Issue
Block a user