- Add architecture overview, implementation plan, and intent overview - Add intake intent process specs (gap analyse, bouwplan, testplan) - Add swift architecture specs and visualization prompts - Remove obsolete aispeedrun-manifesto template Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
472 lines
19 KiB
Markdown
472 lines
19 KiB
Markdown
# Mini-EPD Prototype - Architectuur
|
|
|
|
## Executive Summary (C-Level)
|
|
|
|
**Mini-EPD** is een moderne, AI-gestuurde elektronische patiëntendossier (EPD) oplossing voor de Nederlandse zorgsector. Het systeem combineert spraakherkenning met intelligente intentieherkenning, waardoor zorgverleners hands-free kunnen rapporteren en navigeren.
|
|
|
|
### Kernwaarden
|
|
|
|
| Aspect | Waarde |
|
|
|--------|--------|
|
|
| **Tijdsbesparing** | 70% van commando's verwerkt in <20ms door lokale AI |
|
|
| **Gebruiksgemak** | Natuurlijke taal en spraak als primaire input |
|
|
| **Compliance** | GDPR-vriendelijk met soft deletes en audit trail |
|
|
| **Schaalbaarheid** | Serverless architectuur, horizontaal schaalbaar |
|
|
| **Integratie** | FHIR-geïnspireerd datamodel voor interoperabiliteit |
|
|
|
|
### Strategische Voordelen
|
|
|
|
1. **Lagere administratielast** - Zorgverleners dicteren notities in natuurlijke taal; AI classificeert en structureert automatisch
|
|
2. **Proactieve ondersteuning** - Systeem suggereert vervolgacties op basis van klinische protocollen
|
|
3. **Snelle implementatie** - Cloud-native stack (Vercel + Supabase) zonder on-premise infrastructuur
|
|
4. **Toekomstbestendig** - Modulaire opzet maakt toevoeging van nieuwe functionaliteit eenvoudig
|
|
|
|
### Risico's & Mitigatie
|
|
|
|
| Risico | Mitigatie |
|
|
|--------|-----------|
|
|
| AI-hallucinaties | Drie-lagen architectuur met confidence scoring; fallback naar menselijke verificatie |
|
|
| Data privacy | Row Level Security op database niveau; geen PII in logs |
|
|
| Vendor lock-in | Open standaarden (FHIR, PostgreSQL); migratiepaden beschikbaar |
|
|
|
|
---
|
|
|
|
## Technische Architectuur
|
|
|
|
### Tech Stack
|
|
|
|
| Component | Technologie | Motivatie |
|
|
|-----------|-------------|-----------|
|
|
| Frontend | Next.js 14 (App Router) | Server-side rendering, optimale SEO, moderne DX |
|
|
| Database | Supabase (PostgreSQL) | Managed database met ingebouwde auth en RLS |
|
|
| Auth | Supabase Auth + JWT | Industrie-standaard, SSR-compatibel |
|
|
| AI Classification | Claude API (Anthropic) | State-of-the-art NLP voor Nederlands |
|
|
| Speech-to-Text | Deepgram | Lage latency, hoge nauwkeurigheid |
|
|
| State Management | Zustand | Lightweight, TypeScript-native |
|
|
| Styling | Tailwind CSS + shadcn/ui | Consistente UI, snelle ontwikkeling |
|
|
|
|
---
|
|
|
|
### Cortex: Drie-Lagen AI Architectuur
|
|
|
|
Het hart van het systeem is **Cortex**, een intelligent command center dat natuurlijke taal omzet naar gestructureerde acties.
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ GEBRUIKER INPUT │
|
|
│ "Maak een dagnotitie voor Jan Bakker" │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ LAYER 1: REFLEX ARC │
|
|
│ Latency: <20ms │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ • Regex-gebaseerde pattern matching │
|
|
│ • Weighted confidence scoring │
|
|
│ • Verwerkt 70%+ van alle commando's lokaal │
|
|
│ • Escaleert bij: confidence <0.7, multi-intent, ambiguïteit │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
↓ (indien nodig)
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ LAYER 2: ORCHESTRATOR │
|
|
│ Model: Claude 3.5 Haiku │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ • Multi-intent detectie ("annuleer afspraak en maak notitie") │
|
|
│ • Pronoun resolutie met actieve patiënt context │
|
|
│ • Relatieve tijd parsing ("morgen", "volgende week") │
|
|
│ • Context-aware entity extraction │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ LAYER 3: NUDGE │
|
|
│ Proactieve Suggesties │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ • Post-actie aanbevelingen op basis van V&VN protocollen │
|
|
│ • Voorbeeld: Na wondnotitie → suggestie voor controle-interval │
|
|
│ • Niet-intrusief: toast notifications met dismiss optie │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ UI ARTIFACT BLOCKS │
|
|
│ DagnotatieBlock / ZoekenBlock / OverdrachtBlock │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Intent Types
|
|
|
|
| Intent | Beschrijving | Voorbeeld |
|
|
|--------|--------------|-----------|
|
|
| `dagnotitie` | Dagelijkse rapportage aanmaken | "Noteer dat mevrouw Jansen goed geslapen heeft" |
|
|
| `zoeken` | Patiënt opzoeken | "Zoek Jan Bakker" |
|
|
| `overdracht` | Handover bekijken | "Toon overdracht van gisteren" |
|
|
| `agenda_query` | Agenda raadplegen | "Wat staat er vandaag gepland?" |
|
|
| `create_appointment` | Afspraak inplannen | "Plan een intake voor morgen 14:00" |
|
|
| `cancel_appointment` | Afspraak annuleren | "Annuleer de afspraak van vrijdag" |
|
|
| `reschedule_appointment` | Afspraak verzetten | "Verzet de afspraak naar volgende week" |
|
|
|
|
---
|
|
|
|
### Directory Structuur
|
|
|
|
```
|
|
mini-epd-prototype/
|
|
├── app/ # Next.js App Router
|
|
│ ├── api/ # Backend API Routes
|
|
│ │ ├── cortex/ # AI Command Center
|
|
│ │ │ ├── classify/ # Intent classificatie
|
|
│ │ │ ├── chat/ # Streaming conversatie
|
|
│ │ │ ├── patients/ # Patiënt context
|
|
│ │ │ └── agenda/ # Agenda operaties
|
|
│ │ ├── reports/ # Rapportage CRUD
|
|
│ │ ├── overdracht/ # Handover + AI summaries
|
|
│ │ ├── patients/ # Patiënt data
|
|
│ │ ├── deepgram/ # Speech-to-text
|
|
│ │ └── fhir/ # FHIR endpoints
|
|
│ │
|
|
│ ├── epd/ # EPD Modules (Protected)
|
|
│ │ ├── dashboard/ # Cortex Command Center
|
|
│ │ ├── verpleegrapportage/ # Nursing reports
|
|
│ │ │ └── rapportage/ # Timeline invoer
|
|
│ │ ├── patients/[id]/ # Patiënt dossier
|
|
│ │ ├── agenda/ # Kalender (FullCalendar)
|
|
│ │ └── clients/ # Cliëntenbeheer
|
|
│ │
|
|
│ └── auth/ # Authenticatie
|
|
│ ├── login/
|
|
│ └── reset-password/
|
|
│
|
|
├── lib/ # Shared Business Logic
|
|
│ ├── cortex/ # Drie-lagen AI systeem
|
|
│ │ ├── types.ts # Type definities
|
|
│ │ ├── reflex-classifier.ts # Layer 1: Pattern matching
|
|
│ │ ├── orchestrator.ts # Layer 2: Claude classificatie
|
|
│ │ ├── nudge.ts # Layer 3: Suggesties
|
|
│ │ ├── entity-extractor.ts # Entity extraction
|
|
│ │ ├── date-time-parser.ts # Datum/tijd parsing
|
|
│ │ └── hooks/ # React hooks
|
|
│ │
|
|
│ ├── auth/ # Auth utilities
|
|
│ │ ├── server.ts # Server-side (API routes)
|
|
│ │ └── client.ts # Client-side
|
|
│ │
|
|
│ ├── supabase/ # Database layer
|
|
│ │ ├── database.types.ts # Auto-generated types
|
|
│ │ ├── client.ts # Browser client
|
|
│ │ └── server.ts # SSR client
|
|
│ │
|
|
│ └── types/ # Domain types
|
|
│ ├── report.ts # Rapportage types
|
|
│ └── overdracht.ts # Handover types
|
|
│
|
|
├── components/ # React Components
|
|
│ ├── cortex/ # Cortex UI
|
|
│ │ ├── command-center/ # Main container
|
|
│ │ │ ├── command-center.tsx
|
|
│ │ │ ├── command-input.tsx # Voice/text input
|
|
│ │ │ ├── context-bar.tsx # Actieve patiënt
|
|
│ │ │ ├── canvas-area.tsx # Artifact rendering
|
|
│ │ │ └── offline-banner.tsx
|
|
│ │ ├── blocks/ # Intent-specifieke UI
|
|
│ │ │ ├── dagnotitie-block.tsx
|
|
│ │ │ ├── zoeken-block.tsx
|
|
│ │ │ └── overdracht-block.tsx
|
|
│ │ └── chat/ # Chat componenten
|
|
│ │
|
|
│ └── ui/ # shadcn/ui (29 componenten)
|
|
│ ├── button.tsx
|
|
│ ├── dialog.tsx
|
|
│ └── ...
|
|
│
|
|
├── stores/ # State Management
|
|
│ └── cortex-store.ts # Zustand store
|
|
│
|
|
├── supabase/ # Database
|
|
│ └── migrations/ # SQL migrations
|
|
│
|
|
└── docs/ # Documentatie
|
|
└── swift/ # Cortex specificaties
|
|
```
|
|
|
|
---
|
|
|
|
### Data Model
|
|
|
|
#### Reports Table (Unified)
|
|
|
|
Alle rapportages worden opgeslagen in één tabel met type-discriminatie:
|
|
|
|
```sql
|
|
CREATE TABLE reports (
|
|
id UUID PRIMARY KEY,
|
|
patient_id UUID REFERENCES patients(id),
|
|
type report_type NOT NULL, -- enum
|
|
content TEXT,
|
|
structured_data JSONB, -- type-specifieke velden
|
|
created_at TIMESTAMPTZ,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
shift_date DATE, -- berekend: vóór 07:00 = vorige dag
|
|
deleted_at TIMESTAMPTZ, -- soft delete
|
|
ai_confidence FLOAT,
|
|
ai_reasoning TEXT
|
|
);
|
|
```
|
|
|
|
**Report Types:**
|
|
- `voortgang` - Voortgangsrapportage
|
|
- `observatie` - Klinische observatie
|
|
- `incident` - Incident melding
|
|
- `medicatie` - Medicatie gerelateerd
|
|
- `contact` - Contact met derden
|
|
- `crisis` - Crisis interventie
|
|
- `intake` - Intake notities
|
|
- `behandeladvies` - Behandeladvies
|
|
- `vrije_notitie` - Vrije tekst
|
|
- `verpleegkundig` - Verpleegkundige notitie (met categorie)
|
|
|
|
**Verpleegkundig Categories:**
|
|
- `medicatie`, `adl`, `gedrag`, `incident`, `observatie`
|
|
|
|
#### Shift Logic
|
|
|
|
Rapporten aangemaakt vóór 07:00 worden toegewezen aan de vorige dag (nachtdienst handover):
|
|
|
|
```typescript
|
|
function calculateShiftDate(createdAt: Date): Date {
|
|
const hour = createdAt.getHours();
|
|
if (hour < 7) {
|
|
return subDays(createdAt, 1);
|
|
}
|
|
return createdAt;
|
|
}
|
|
```
|
|
|
|
**Diensten:**
|
|
| Dienst | Tijdvak |
|
|
|--------|---------|
|
|
| Nacht | 00:00 - 07:00 |
|
|
| Ochtend | 07:00 - 12:00 |
|
|
| Middag | 12:00 - 17:00 |
|
|
| Avond | 17:00 - 24:00 |
|
|
|
|
---
|
|
|
|
### API Endpoints
|
|
|
|
#### Cortex APIs
|
|
|
|
| Method | Endpoint | Beschrijving |
|
|
|--------|----------|--------------|
|
|
| POST | `/api/cortex/classify` | Intent classificatie (Reflex + Orchestrator) |
|
|
| POST | `/api/cortex/chat` | Streaming chat (SSE) |
|
|
| GET | `/api/cortex/context` | Huidige gebruikerscontext |
|
|
| GET | `/api/cortex/patients/search` | Patiënt zoeken voor context |
|
|
| GET | `/api/cortex/agenda` | Dagagenda ophalen |
|
|
| POST | `/api/cortex/agenda/create` | Afspraak aanmaken |
|
|
| POST | `/api/cortex/agenda/cancel` | Afspraak annuleren |
|
|
| POST | `/api/cortex/agenda/reschedule` | Afspraak verzetten |
|
|
|
|
#### Report APIs
|
|
|
|
| Method | Endpoint | Beschrijving |
|
|
|--------|----------|--------------|
|
|
| GET | `/api/reports` | Lijst rapporten (filters: type, datum, patiënt) |
|
|
| POST | `/api/reports` | Rapport aanmaken |
|
|
| GET | `/api/reports/[id]` | Enkel rapport ophalen |
|
|
| PUT | `/api/reports/[id]` | Rapport bijwerken |
|
|
| DELETE | `/api/reports/[id]` | Soft delete |
|
|
|
|
#### Overdracht APIs
|
|
|
|
| Method | Endpoint | Beschrijving |
|
|
|--------|----------|--------------|
|
|
| GET | `/api/overdracht/patients` | Patiënten voor handover |
|
|
| GET | `/api/overdracht/[patientId]` | Handover data per patiënt |
|
|
| POST | `/api/overdracht/generate` | AI-gegenereerde samenvatting |
|
|
|
|
---
|
|
|
|
### State Management
|
|
|
|
**Zustand Store** (`stores/cortex-store.ts`):
|
|
|
|
```typescript
|
|
interface CortexStore {
|
|
// Chat state
|
|
messages: ChatMessage[];
|
|
pendingAction: IntentAction | null;
|
|
|
|
// Context
|
|
activePatient: Patient | null;
|
|
currentShift: 'nacht' | 'ochtend' | 'middag' | 'avond';
|
|
|
|
// UI
|
|
openArtifacts: ArtifactInstance[];
|
|
suggestions: NudgeSuggestion[];
|
|
patientSidebarOpen: boolean;
|
|
|
|
// Actions
|
|
addMessage(msg: ChatMessage): void;
|
|
setActivePatient(patient: Patient): void;
|
|
openArtifact(artifact: ArtifactInstance): void;
|
|
acceptSuggestion(id: string): void;
|
|
dismissSuggestion(id: string): void;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Security
|
|
|
|
#### Row Level Security (RLS)
|
|
|
|
Alle tabellen hebben RLS policies die data toegang beperken tot geautoriseerde gebruikers:
|
|
|
|
```sql
|
|
-- Voorbeeld: users kunnen alleen hun eigen patiënten zien
|
|
CREATE POLICY "Users can view assigned patients"
|
|
ON patients FOR SELECT
|
|
USING (auth.uid() IN (
|
|
SELECT user_id FROM patient_assignments
|
|
WHERE patient_id = patients.id
|
|
));
|
|
```
|
|
|
|
#### Authentication Flow
|
|
|
|
```
|
|
1. Login via /auth/login
|
|
2. Supabase Auth valideert credentials
|
|
3. JWT token in httpOnly cookie
|
|
4. Middleware refresht sessie bij elk request
|
|
5. API routes valideren via createClient()
|
|
6. RLS filtert data op database niveau
|
|
```
|
|
|
|
#### Input Validation
|
|
|
|
Alle API endpoints gebruiken Zod schemas:
|
|
|
|
```typescript
|
|
const CreateReportSchema = z.object({
|
|
patient_id: z.string().uuid(),
|
|
type: z.enum(['voortgang', 'observatie', ...]),
|
|
content: z.string().min(20).max(5000),
|
|
structured_data: z.object({...}).optional()
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
### Performance
|
|
|
|
| Aspect | Implementatie | Target |
|
|
|--------|---------------|--------|
|
|
| Intent classificatie | Layer 1 Reflex | <20ms voor 70%+ requests |
|
|
| Chat responses | SSE streaming | First token <500ms |
|
|
| Patient search | Debounced input | 300ms debounce |
|
|
| Build optimization | Code splitting | Three.js in apart chunk |
|
|
| Database queries | Selective columns | Geen overbodige data |
|
|
|
|
---
|
|
|
|
### Monitoring & Audit
|
|
|
|
**AI Events Table:**
|
|
|
|
```sql
|
|
CREATE TABLE ai_events (
|
|
id UUID PRIMARY KEY,
|
|
kind TEXT, -- 'classify', 'summarize', 'chat'
|
|
request JSONB,
|
|
response JSONB,
|
|
duration_ms INTEGER,
|
|
created_at TIMESTAMPTZ,
|
|
user_id UUID
|
|
);
|
|
```
|
|
|
|
Elk AI-verzoek wordt gelogd voor:
|
|
- Compliance en audit trail
|
|
- Performance monitoring
|
|
- Model fine-tuning data
|
|
|
|
---
|
|
|
|
### Feature Flags
|
|
|
|
```typescript
|
|
// lib/config/feature-flags.ts
|
|
CORTEX_V2_ENABLED // Drie-lagen architectuur
|
|
CORTEX_MULTI_INTENT // Multi-intent detectie
|
|
CORTEX_NUDGE // Proactieve suggesties
|
|
CORTEX_LOGGING // Debug logging (dev only)
|
|
```
|
|
|
|
---
|
|
|
|
## Deployment
|
|
|
|
### Infrastructuur
|
|
|
|
```
|
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
│ Vercel │────▶│ Supabase │────▶│ PostgreSQL │
|
|
│ (Frontend + │ │ (Auth) │ │ (Database) │
|
|
│ API Routes) │ └─────────────────┘ └─────────────────┘
|
|
└─────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────┐ ┌─────────────────┐
|
|
│ Claude API │ │ Deepgram │
|
|
│ (Anthropic) │ │ (Speech-to-Text)│
|
|
└─────────────────┘ └─────────────────┘
|
|
```
|
|
|
|
### Environment Variables
|
|
|
|
```bash
|
|
# Supabase
|
|
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
|
|
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
|
|
|
|
# AI Services
|
|
ANTHROPIC_API_KEY=sk-ant-...
|
|
DEEPGRAM_API_KEY=...
|
|
|
|
# Feature Flags
|
|
NEXT_PUBLIC_CORTEX_V2=true
|
|
```
|
|
|
|
---
|
|
|
|
## Extensibility
|
|
|
|
### Nieuw Intent Toevoegen
|
|
|
|
1. Voeg toe aan `CortexIntent` type in `lib/cortex/types.ts`
|
|
2. Voeg Reflex patterns toe in `lib/cortex/reflex-classifier.ts`
|
|
3. Maak artifact block in `components/cortex/blocks/`
|
|
4. Update Orchestrator prompt (indien AI-driven)
|
|
5. Maak API endpoint (indien nodig)
|
|
|
|
### Nieuw Report Type Toevoegen
|
|
|
|
1. Voeg toe aan `REPORT_TYPES` enum in `lib/types/report.ts`
|
|
2. Voeg Zod schema toe voor validatie
|
|
3. Update UI componenten voor nieuw type
|
|
4. Voeg database migration toe indien nodig
|
|
|
|
---
|
|
|
|
## Conclusie
|
|
|
|
De Mini-EPD architectuur is ontworpen voor:
|
|
|
|
- **Snelheid**: Drie-lagen AI met <20ms lokale verwerking
|
|
- **Schaalbaarheid**: Serverless, horizontaal schaalbaar
|
|
- **Veiligheid**: RLS, JWT, Zod validatie op alle lagen
|
|
- **Uitbreidbaarheid**: Modulaire opzet met duidelijke interfaces
|
|
- **Compliance**: Audit trail, soft deletes, Nederlandse foutmeldingen
|
|
|
|
Het systeem is production-ready voor MVP deployment met duidelijke paden voor doorontwikkeling.
|