docs: architectuurdocs, styleguides en release notes intake/behandelplan
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1734
docs/architecture/enterprise-componenten-uitbreiding.md
Normal file
1734
docs/architecture/enterprise-componenten-uitbreiding.md
Normal file
File diff suppressed because it is too large
Load Diff
1619
docs/architecture/enterprise-epd-architectuur.md
Normal file
1619
docs/architecture/enterprise-epd-architectuur.md
Normal file
File diff suppressed because it is too large
Load Diff
1073
docs/architecture/intent-system-architecture.md
Normal file
1073
docs/architecture/intent-system-architecture.md
Normal file
File diff suppressed because it is too large
Load Diff
1101
docs/architecture/intent-system-architectuur-nl.md
Normal file
1101
docs/architecture/intent-system-architectuur-nl.md
Normal file
File diff suppressed because it is too large
Load Diff
287
docs/architecture/overzicht-po-pm.html
Normal file
287
docs/architecture/overzicht-po-pm.html
Normal file
@@ -0,0 +1,287 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="nl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Mini-EPD — Architectuur & Datacomponenten (PO/PM)</title>
|
||||
<style>
|
||||
:root{
|
||||
--bg:#0f172a; --panel:#ffffff; --ink:#1e293b; --muted:#64748b;
|
||||
--line:#e2e8f0; --brand:#4f46e5; --brand-soft:#eef2ff;
|
||||
--teal:#0d9488; --teal-soft:#ecfdf5; --amber:#d97706; --amber-soft:#fffbeb;
|
||||
--rose:#e11d48; --rose-soft:#fff1f2; --sky:#0284c7; --sky-soft:#f0f9ff;
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||
background:linear-gradient(160deg,#0f172a 0%,#1e1b4b 100%);color:var(--ink);line-height:1.5;padding:32px 16px;}
|
||||
.wrap{max-width:1080px;margin:0 auto;}
|
||||
header{text-align:center;color:#fff;margin-bottom:32px;}
|
||||
header h1{font-size:30px;margin:0 0 8px;letter-spacing:-.5px;}
|
||||
header p{color:#c7d2fe;margin:0;font-size:15px;}
|
||||
.badge{display:inline-block;background:rgba(255,255,255,.12);color:#e0e7ff;
|
||||
padding:4px 12px;border-radius:999px;font-size:12px;margin-top:12px;}
|
||||
.card{background:var(--panel);border-radius:18px;padding:26px 28px;margin-bottom:22px;
|
||||
box-shadow:0 10px 40px rgba(0,0,0,.18);}
|
||||
.card h2{font-size:13px;text-transform:uppercase;letter-spacing:1.5px;color:var(--brand);
|
||||
margin:0 0 4px;font-weight:700;}
|
||||
.card h2 .num{background:var(--brand);color:#fff;border-radius:8px;padding:2px 9px;margin-right:8px;font-size:13px;}
|
||||
.card .lead{color:var(--muted);font-size:14px;margin:0 0 20px;}
|
||||
|
||||
/* layers stack */
|
||||
.stack{display:flex;flex-direction:column;gap:10px;}
|
||||
.layer{border-radius:14px;padding:16px 20px;border:1px solid var(--line);}
|
||||
.layer .tag{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;opacity:.7;}
|
||||
.layer .title{font-size:16px;font-weight:700;margin:2px 0 6px;}
|
||||
.layer .desc{font-size:13px;color:var(--muted);}
|
||||
.l1{background:var(--sky-soft);border-color:#bae6fd;}
|
||||
.l2{background:var(--brand-soft);border-color:#c7d2fe;}
|
||||
.l3{background:var(--teal-soft);border-color:#a7f3d0;}
|
||||
.chev{text-align:center;color:#94a3b8;font-size:18px;line-height:1;}
|
||||
|
||||
/* modules grid */
|
||||
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;}
|
||||
.mod{border:1px solid var(--line);border-radius:14px;padding:16px;}
|
||||
.mod .ic{font-size:22px;}
|
||||
.mod .nm{font-weight:700;margin:8px 0 4px;font-size:15px;}
|
||||
.mod .tx{font-size:13px;color:var(--muted);}
|
||||
|
||||
/* cortex flow */
|
||||
.flow{display:flex;flex-direction:column;gap:8px;}
|
||||
.step{display:flex;align-items:center;gap:14px;border:1px solid var(--line);border-radius:12px;padding:12px 16px;}
|
||||
.step .badgeN{flex:0 0 34px;height:34px;border-radius:50%;display:flex;align-items:center;justify-content:center;
|
||||
font-weight:800;color:#fff;font-size:14px;}
|
||||
.step .body{flex:1;}
|
||||
.step .t{font-weight:700;font-size:14px;}
|
||||
.step .d{font-size:12.5px;color:var(--muted);}
|
||||
.n1{background:var(--sky);} .n2{background:var(--brand);} .n3{background:var(--teal);} .nA{background:#475569;}
|
||||
|
||||
.intents{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px;}
|
||||
.intent{background:var(--brand-soft);color:var(--brand);border-radius:999px;padding:5px 13px;font-size:12.5px;font-weight:600;}
|
||||
|
||||
/* services */
|
||||
.svc{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px;}
|
||||
.svcbox{border:1px solid var(--line);border-radius:14px;padding:16px;}
|
||||
.svcbox .h{font-weight:700;font-size:15px;display:flex;align-items:center;gap:8px;}
|
||||
.svcbox .role{font-size:12px;color:var(--muted);margin:6px 0;}
|
||||
.svcbox .why{font-size:12.5px;background:#f8fafc;border-radius:8px;padding:8px 10px;color:var(--ink);}
|
||||
|
||||
/* data model diagram */
|
||||
.dm{display:flex;flex-direction:column;align-items:center;gap:0;}
|
||||
.entity{border-radius:12px;padding:12px 18px;text-align:center;border:2px solid;min-width:150px;}
|
||||
.entity .e-nm{font-weight:800;font-size:14px;}
|
||||
.entity .e-tx{font-size:11.5px;color:var(--muted);}
|
||||
.epatient{background:var(--brand-soft);border-color:var(--brand);}
|
||||
.erow{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;margin-top:12px;}
|
||||
.echild{background:#f8fafc;border-color:var(--line);}
|
||||
.echild .e-nm{font-size:13px;}
|
||||
.pipe{width:2px;height:18px;background:#cbd5e1;}
|
||||
|
||||
/* journey */
|
||||
.journey{display:flex;flex-wrap:wrap;align-items:stretch;gap:0;}
|
||||
.jstep{flex:1;min-width:120px;background:#f8fafc;border:1px solid var(--line);padding:12px;text-align:center;position:relative;}
|
||||
.jstep:first-child{border-radius:12px 0 0 12px;}
|
||||
.jstep:last-child{border-radius:0 12px 12px 0;}
|
||||
.jstep .jt{font-weight:700;font-size:13px;}
|
||||
.jstep .jd{font-size:11px;color:var(--muted);margin-top:3px;}
|
||||
.jstep .arrow{position:absolute;right:-9px;top:50%;transform:translateY(-50%);color:#cbd5e1;font-size:18px;z-index:2;}
|
||||
|
||||
/* tables */
|
||||
table{width:100%;border-collapse:collapse;font-size:13px;}
|
||||
th,td{text-align:left;padding:10px 12px;border-bottom:1px solid var(--line);vertical-align:top;}
|
||||
th{font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);}
|
||||
td:first-child{font-weight:600;white-space:nowrap;}
|
||||
|
||||
/* rules / warnings */
|
||||
.rules{display:grid;gap:10px;}
|
||||
.rule{display:flex;gap:12px;border:1px solid var(--line);border-radius:12px;padding:12px 14px;}
|
||||
.rule .ic{font-size:18px;}
|
||||
.rule .rt{font-weight:700;font-size:13.5px;}
|
||||
.rule .rd{font-size:12.5px;color:var(--muted);}
|
||||
.warns{display:grid;gap:10px;}
|
||||
.warn{display:flex;gap:12px;background:var(--amber-soft);border:1px solid #fde68a;border-radius:12px;padding:12px 14px;}
|
||||
.warn .rt{font-weight:700;font-size:13.5px;color:#92400e;}
|
||||
.warn .rd{font-size:12.5px;color:#78350f;}
|
||||
footer{text-align:center;color:#94a3b8;font-size:12px;margin-top:8px;}
|
||||
.tags{margin-top:14px;}
|
||||
.pill{display:inline-block;font-size:11px;padding:3px 9px;border-radius:6px;margin:2px;font-weight:600;}
|
||||
.pill-type{background:var(--sky-soft);color:var(--sky);}
|
||||
.pill-cat{background:var(--teal-soft);color:var(--teal);}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
|
||||
<header>
|
||||
<h1>Mini-EPD — Architectuur & Datacomponenten</h1>
|
||||
<p>Eén begrijpelijk overzicht voor Product Owners & Project Managers</p>
|
||||
<span class="badge">GGZ Elektronisch Patiëntdossier · Prototype</span>
|
||||
</header>
|
||||
|
||||
<!-- IN ÉÉN ALINEA -->
|
||||
<div class="card">
|
||||
<h2><span class="num">1</span>In het kort</h2>
|
||||
<p style="font-size:15px;margin:0;">Het Mini-EPD is een <strong>elektronisch patiëntdossier voor de GGZ</strong>. Een zorgverlener meldt patiënten aan, doet intake, maakt behandelplannen, schrijft dagrapportages en draagt diensten over. Het hart is de <strong>Cortex AI Command Center</strong>: een natuurlijke-taal-interface (typen of inspreken) waarmee je acties uitvoert in gewone zinnen — <em>"maak een notitie voor Jan: medicatie ingenomen"</em> of <em>"plan een afspraak morgen om 14:00"</em>.</p>
|
||||
</div>
|
||||
|
||||
<!-- DRIE LAGEN -->
|
||||
<div class="card">
|
||||
<h2><span class="num">2</span>De drie lagen van het systeem</h2>
|
||||
<p class="lead">Van wat de gebruiker ziet tot waar de gegevens staan.</p>
|
||||
<div class="stack">
|
||||
<div class="layer l1">
|
||||
<div class="tag">Laag 1 · Schermen</div>
|
||||
<div class="title">Wat de gebruiker ziet</div>
|
||||
<div class="desc">Dashboard · Patiëntdossier · Intake · Behandelplan · Verpleegrapportage · Agenda · Cortex AI Command Center</div>
|
||||
</div>
|
||||
<div class="chev">▼</div>
|
||||
<div class="layer l2">
|
||||
<div class="tag">Laag 2 · Logica</div>
|
||||
<div class="title">De verwerking (API's)</div>
|
||||
<div class="desc">Rapportage · Overdracht · Behandelplan · Intake · Cortex (intentherkenning + chat) · Spraak-naar-tekst</div>
|
||||
</div>
|
||||
<div class="chev">▼</div>
|
||||
<div class="layer l3">
|
||||
<div class="tag">Laag 3 · Gegevens</div>
|
||||
<div class="title">Database & externe diensten</div>
|
||||
<div class="desc">Supabase database · Claude AI (Anthropic) · Deepgram (spraak)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODULES -->
|
||||
<div class="card">
|
||||
<h2><span class="num">3</span>De modules (wat de gebruiker ziet)</h2>
|
||||
<p class="lead">De schermen waarmee de zorgverlener werkt.</p>
|
||||
<div class="grid">
|
||||
<div class="mod"><div class="ic">🏠</div><div class="nm">Dashboard</div><div class="tx">Startscherm met het Cortex AI Command Center. Hier begint elke actie.</div></div>
|
||||
<div class="mod"><div class="ic">📋</div><div class="nm">Patiëntdossier</div><div class="tx">Basisgegevens (incl. BSN), diagnoses, observaties en intakes per patiënt.</div></div>
|
||||
<div class="mod"><div class="ic">📝</div><div class="nm">Intake</div><div class="tx">Stapsgewijs: contactpersonen, risicotaxatie, anamnese, onderzoek, diagnose, advies.</div></div>
|
||||
<div class="mod"><div class="ic">🎯</div><div class="nm">Behandelplan</div><div class="tx">Doelen en interventies per leefgebied vastleggen en beheren.</div></div>
|
||||
<div class="mod"><div class="ic">🔄</div><div class="nm">Verpleegrapportage</div><div class="tx">Dagnotities in tijdlijn + overdracht met AI-samenvatting voor de volgende dienst.</div></div>
|
||||
<div class="mod"><div class="ic">📅</div><div class="nm">Agenda</div><div class="tx">Kalender met afspraken; inplannen, verzetten of annuleren.</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CORTEX -->
|
||||
<div class="card">
|
||||
<h2><span class="num">4</span>Het hart: Cortex AI Command Center</h2>
|
||||
<p class="lead">De gebruiker typt of spreekt een opdracht. Het systeem begrijpt de bedoeling en handelt — in drie slimme lagen die snelheid én begrip combineren.</p>
|
||||
<div class="flow">
|
||||
<div class="step"><div class="badgeN nA">🗣</div><div class="body"><div class="t">Gebruiker zegt of typt iets</div><div class="d">"Maak een notitie voor Jan: medicatie ingenomen"</div></div></div>
|
||||
<div class="chev">▼</div>
|
||||
<div class="step"><div class="badgeN n1">1</div><div class="body"><div class="t">Reflex (lokaal) — snel & gratis</div><div class="d">Herkent veelvoorkomende opdrachten direct via patronen (<20ms). Twijfel of complex? → door naar laag 2.</div></div></div>
|
||||
<div class="chev">▼</div>
|
||||
<div class="step"><div class="badgeN n2">2</div><div class="body"><div class="t">Orchestrator (AI) — voor lastige gevallen</div><div class="d">Claude lost op: meerdere opdrachten tegelijk, "hem/haar", "morgen", onduidelijke zinnen.</div></div></div>
|
||||
<div class="chev">▼</div>
|
||||
<div class="step"><div class="badgeN nA">✓</div><div class="body"><div class="t">Actie uitgevoerd</div><div class="d">Notitie opgeslagen · afspraak gemaakt · patiënt gevonden …</div></div></div>
|
||||
<div class="chev">▼</div>
|
||||
<div class="step"><div class="badgeN n3">3</div><div class="body"><div class="t">Nudge — proactieve suggestie achteraf</div><div class="d">"Wil je hier ook een observatie bij maken?" — verhoogt de zorgkwaliteit op het juiste moment.</div></div></div>
|
||||
</div>
|
||||
<p class="lead" style="margin:18px 0 6px;"><strong>Waarom drie lagen?</strong> De goedkope lokale laag vangt het gros af zonder AI-kosten of vertraging. Alleen echt lastige zinnen gaan naar de betaalde AI.</p>
|
||||
<p class="lead" style="margin:14px 0 4px;"><strong>Wat Cortex begrijpt (de "intents"):</strong></p>
|
||||
<div class="intents">
|
||||
<span class="intent">Dagnotitie maken</span>
|
||||
<span class="intent">Patiënt zoeken</span>
|
||||
<span class="intent">Overdracht bekijken</span>
|
||||
<span class="intent">Agenda opvragen</span>
|
||||
<span class="intent">Afspraak inplannen</span>
|
||||
<span class="intent">Afspraak annuleren</span>
|
||||
<span class="intent">Afspraak verzetten</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- EXTERNE DIENSTEN -->
|
||||
<div class="card">
|
||||
<h2><span class="num">5</span>De externe diensten (afhankelijkheden)</h2>
|
||||
<p class="lead">Waar het product op leunt buiten de eigen code.</p>
|
||||
<div class="svc">
|
||||
<div class="svcbox">
|
||||
<div class="h">🗄️ Supabase</div>
|
||||
<div class="role">Database + inloggen (authenticatie)</div>
|
||||
<div class="why">De plek waar alle patiëntgegevens veilig staan.</div>
|
||||
</div>
|
||||
<div class="svcbox">
|
||||
<div class="h">🤖 Claude (Anthropic)</div>
|
||||
<div class="role">Intentherkenning · chat · overdrachtssamenvatting · behandelplan</div>
|
||||
<div class="why">De "intelligentie" achter Cortex en de samenvattingen. <strong>Betaalde API → gebruik = kosten.</strong></div>
|
||||
</div>
|
||||
<div class="svcbox">
|
||||
<div class="h">🎙️ Deepgram</div>
|
||||
<div class="role">Spraak omzetten naar tekst</div>
|
||||
<div class="why">Maakt het inspreken van notities mogelijk. <strong>Betaalde API → gebruik = kosten.</strong></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DATAMODEL -->
|
||||
<div class="card">
|
||||
<h2><span class="num">6</span>De gegevens (datacomponenten)</h2>
|
||||
<p class="lead">Het datamodel is <strong>FHIR-geïnspireerd</strong> — de internationale standaard voor zorggegevens, pragmatisch vereenvoudigd. Alles draait om de patiënt.</p>
|
||||
|
||||
<div class="dm">
|
||||
<div class="entity epatient">
|
||||
<div class="e-nm">PATIËNT</div>
|
||||
<div class="e-tx">naam · BSN · geboortedatum · status</div>
|
||||
</div>
|
||||
<div class="pipe"></div>
|
||||
<div class="erow">
|
||||
<div class="entity echild"><div class="e-nm">Screening</div><div class="e-tx">aanmelding & besluit</div></div>
|
||||
<div class="entity echild"><div class="e-nm">Intake</div><div class="e-tx">+ risico, anamnese, onderzoek</div></div>
|
||||
<div class="entity echild"><div class="e-nm">Diagnose</div><div class="e-tx">DSM-5 / ICD-10</div></div>
|
||||
<div class="entity echild"><div class="e-nm">Observatie</div><div class="e-tx">metingen & scores</div></div>
|
||||
<div class="entity echild"><div class="e-nm">Behandelplan</div><div class="e-tx">doelen & interventies</div></div>
|
||||
</div>
|
||||
<div class="pipe"></div>
|
||||
<div class="entity echild" style="min-width:200px;"><div class="e-nm">Contactmoment → Rapportage</div><div class="e-tx">sessies & dagnotities</div></div>
|
||||
</div>
|
||||
|
||||
<div class="tags">
|
||||
<p class="lead" style="margin:18px 0 6px;"><strong>Soorten rapportage (type):</strong></p>
|
||||
<span class="pill pill-type">voortgang</span><span class="pill pill-type">observatie</span><span class="pill pill-type">incident</span><span class="pill pill-type">medicatie</span><span class="pill pill-type">contact</span><span class="pill pill-type">crisis</span><span class="pill pill-type">verpleegkundig</span><span class="pill pill-type">behandeladvies</span>
|
||||
<p class="lead" style="margin:14px 0 6px;"><strong>Categorieën (verpleegkundig):</strong></p>
|
||||
<span class="pill pill-cat">medicatie</span><span class="pill pill-cat">ADL</span><span class="pill pill-cat">gedrag</span><span class="pill pill-cat">incident</span><span class="pill pill-cat">observatie</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PATIENTREIS -->
|
||||
<div class="card">
|
||||
<h2><span class="num">7</span>De patiëntreis door de data</h2>
|
||||
<p class="lead">Hoe een patiënt door het systeem stroomt.</p>
|
||||
<div class="journey">
|
||||
<div class="jstep"><div class="jt">Aangemeld</div><div class="jd">status: planned</div><span class="arrow">›</span></div>
|
||||
<div class="jstep"><div class="jt">Screening</div><div class="jd">geschikt?</div><span class="arrow">›</span></div>
|
||||
<div class="jstep"><div class="jt">Intake</div><div class="jd">anamnese, risico</div><span class="arrow">›</span></div>
|
||||
<div class="jstep"><div class="jt">In zorg</div><div class="jd">plan + rapportages</div><span class="arrow">›</span></div>
|
||||
<div class="jstep"><div class="jt">Overdracht</div><div class="jd">samenvatting collega</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- REGELS -->
|
||||
<div class="card">
|
||||
<h2><span class="num">8</span>Belangrijke regels in de data</h2>
|
||||
<p class="lead">Goed om te weten als PO/PM.</p>
|
||||
<div class="rules">
|
||||
<div class="rule"><div class="ic">♻️</div><div><div class="rt">Soft delete</div><div class="rd">Verwijderen markeert alleen; data blijft staan. Niets gaat echt verloren — belangrijk voor zorgdossiers en herstel.</div></div></div>
|
||||
<div class="rule"><div class="ic">🌙</div><div><div class="rt">Shift-logica</div><div class="rd">Notities vóór 07:00 horen bij de dienst van de vórige dag. Zorgt dat nachtdiensten correct in de overdracht vallen.</div></div></div>
|
||||
<div class="rule"><div class="ic">✅</div><div><div class="rt">Overdrachtsfilter</div><div class="rd">Alleen notities met "meenemen in overdracht" verschijnen in de samenvatting. De zorgverlener bepaalt wat relevant is.</div></div></div>
|
||||
<div class="rule"><div class="ic">🔒</div><div><div class="rt">Row Level Security (RLS)</div><div class="rd">De database dwingt af wie welke gegevens mag zien — fundament voor privacy/AVG. In deze fase nog ruim ingesteld.</div></div></div>
|
||||
<div class="rule"><div class="ic">🧠</div><div><div class="rt">AI-herkomst</div><div class="rd">Bij AI-gegenereerde inhoud worden zekerheid en redenering bewaard — transparant en controleerbaar.</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AANDACHTSPUNTEN -->
|
||||
<div class="card">
|
||||
<h2><span class="num">9</span>Aandachtspunten & status (eerlijk beeld)</h2>
|
||||
<div class="warns">
|
||||
<div class="warn"><div class="ic">⚠️</div><div><div class="rt">Prototype-status</div><div class="rd">Geen productiesysteem. Beveiligingsregels (RLS) zijn nog ruim; verfijning per team/organisatie is nog niet gebouwd.</div></div></div>
|
||||
<div class="warn"><div class="ic">⚠️</div><div><div class="rt">Twee-sporen datamodel</div><div class="rd">Naast het nieuwe FHIR-model bestaat nog een ouder model. Het nieuwe is leidend; het oude is nog niet opgeruimd — technische schuld om te bewaken.</div></div></div>
|
||||
<div class="warn"><div class="ic">⚠️</div><div><div class="rt">Externe AI-kosten</div><div class="rd">Schaalbaarheid van Cortex hangt samen met de gebruikskosten van Claude en Deepgram.</div></div></div>
|
||||
<div class="warn"><div class="ic">⚠️</div><div><div class="rt">Nog geen echte interoperabiliteit</div><div class="rd">Het model is FHIR-geïnspireerd; volledige FHIR-uitwisseling met externe systemen is nog niet geïmplementeerd.</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>Bron: codebase mini-epd-prototype · modules in <code>app/</code> · logica in <code>app/api/</code> · Cortex in <code>lib/cortex/</code> · datamodel in <code>supabase/migrations/</code></footer>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
170
docs/architecture/overzicht-po-pm.md
Normal file
170
docs/architecture/overzicht-po-pm.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# Mini-EPD — Architectuur & Datacomponenten (PO/PM-overzicht)
|
||||
|
||||
> Doel van dit document: één begrijpelijk overzicht van **wat het systeem doet**, **uit welke bouwblokken het bestaat** en **welke gegevens het beheert** — zonder dat je code hoeft te lezen. Bedoeld voor product owners en project managers.
|
||||
|
||||
---
|
||||
|
||||
## 1. In één alinea
|
||||
|
||||
Het Mini-EPD is een **elektronisch patiëntdossier voor de GGZ**. Een zorgverlener kan patiënten aanmelden, intake doen, behandelplannen maken, dagelijkse rapportages schrijven en diensten overdragen aan een collega. Het bijzondere is de **Cortex AI Command Center**: een natuurlijke-taal-interface (typen of inspreken) waarmee de zorgverlener acties uitvoert in gewone zinnen, zoals *"maak een notitie voor Jan: medicatie ingenomen"* of *"plan een afspraak morgen om 14:00"*.
|
||||
|
||||
---
|
||||
|
||||
## 2. De drie lagen van het systeem
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ 1. WAT DE GEBRUIKER ZIET (de modules / schermen) │
|
||||
│ Dashboard · Patiëntdossier · Intake · Behandelplan · │
|
||||
│ Verpleegrapportage · Agenda · Cortex AI Command Center │
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ 2. DE LOGICA (de API's / verwerking) │
|
||||
│ Rapportage · Overdracht · Behandelplan · Intake · │
|
||||
│ Cortex (intentherkenning + chat) · Spraak-naar-tekst │
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ 3. DE GEGEVENS (de database + externe diensten) │
|
||||
│ Supabase database · Claude AI · Deepgram (spraak) │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. De modules (wat de gebruiker ziet)
|
||||
|
||||
| Module | Wat de zorgverlener ermee doet |
|
||||
|---|---|
|
||||
| **Dashboard** | Startscherm met het Cortex AI Command Center. Hier begint elke actie. |
|
||||
| **Patiëntdossier** | Volledig dossier per patiënt: basisgegevens (incl. BSN), diagnoses, observaties, intakes. |
|
||||
| **Intake** | Stapsgewijze intakeprocedure voor een nieuwe patiënt: contactpersonen, risicotaxatie, anamnese, onderzoek, diagnose, behandeladvies. |
|
||||
| **Behandelplan** | Behandeldoelen en interventies per leefgebied vastleggen en beheren. |
|
||||
| **Verpleegrapportage** | Dagelijkse notities in een tijdlijn (nacht/ochtend/middag/avond) + **overdracht** met AI-samenvatting voor de collega van de volgende dienst. |
|
||||
| **Agenda** | Kalender met alle afspraken; afspraken inplannen, verzetten of annuleren. |
|
||||
|
||||
---
|
||||
|
||||
## 4. Het hart: Cortex AI Command Center
|
||||
|
||||
De zorgverlener typt of spreekt een opdracht in. Het systeem begrijpt de bedoeling ("intent") en voert de juiste actie uit. Dit gebeurt in **drie slimme lagen** die samen snelheid én begrip combineren:
|
||||
|
||||
```
|
||||
Gebruiker zegt/typt iets
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐ Snel & gratis. Herkent veelvoorkomende
|
||||
│ 1. REFLEX (lokaal) │ opdrachten direct via patronen (<20ms).
|
||||
└─────────┬───────────┘ Twijfel of complex? → door naar laag 2.
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐ AI (Claude) lost lastige gevallen op:
|
||||
│ 2. ORCHESTRATOR (AI)│ meerdere opdrachten tegelijk, "hem/haar",
|
||||
└─────────┬───────────┘ "morgen", onduidelijke zinnen.
|
||||
│
|
||||
▼
|
||||
Actie wordt uitgevoerd (notitie opgeslagen, afspraak gemaakt...)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐ Proactieve suggestie achteraf, bijv.
|
||||
│ 3. NUDGE │ "Wil je hier ook een observatie bij maken?"
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
**Waarom drie lagen?** De Reflex-laag handelt het gros af zonder AI-kosten en zonder vertraging. Alleen echt lastige zinnen gaan naar de (betaalde, iets tragere) AI. De Nudge-laag verhoogt de zorgkwaliteit door op het juiste moment iets te suggereren.
|
||||
|
||||
**Wat begrijpt Cortex (de "intents"):**
|
||||
- Dagnotitie maken · Patiënt zoeken · Overdracht bekijken
|
||||
- Agenda opvragen · Afspraak inplannen / annuleren / verzetten
|
||||
|
||||
**Chat & artifacts:** Het scherm is gesplitst — links een **chatpaneel** (gesprek met de assistent), rechts een **werkblok** ("artifact") dat past bij de opdracht: een notitieformulier, een overdrachtssamenvatting, een zoekresultaat, enzovoort.
|
||||
|
||||
---
|
||||
|
||||
## 5. De externe diensten (afhankelijkheden)
|
||||
|
||||
| Dienst | Waarvoor | Belang voor het product |
|
||||
|---|---|---|
|
||||
| **Supabase** | Database + inloggen (authenticatie) | De plek waar alle patiëntgegevens veilig staan. |
|
||||
| **Claude (Anthropic)** | AI: intentherkenning, chat, overdrachtssamenvatting, behandelplan genereren | De "intelligentie" achter Cortex en de samenvattingen. |
|
||||
| **Deepgram** | Spraak omzetten naar tekst | Maakt inspreken van notities mogelijk. |
|
||||
|
||||
> **Aandachtspunt PO/PM:** Claude en Deepgram zijn betaalde externe API's. Gebruik = kosten. Cortex is bewust zo ontworpen dat de goedkope lokale laag het meeste afvangt.
|
||||
|
||||
---
|
||||
|
||||
## 6. De gegevens (datacomponenten)
|
||||
|
||||
Het datamodel is **FHIR-geïnspireerd**. FHIR is de internationale standaard voor gestructureerde zorggegevens. "Geïnspireerd" betekent: we volgen de standaard waar het helpt voor uitwisselbaarheid met andere systemen (denk ICD-10/DSM-5 diagnosecodes, BIG/AGB-nummers), maar pragmatisch vereenvoudigd waar dat sneller bouwt.
|
||||
|
||||
### De kerngegevens en hoe ze samenhangen
|
||||
|
||||
```
|
||||
┌──────────────┐
|
||||
│ PATIËNT │ (naam, BSN, geboortedatum, status)
|
||||
└──────┬───────┘
|
||||
┌──────────────┬───────┼───────────┬──────────────┐
|
||||
▼ ▼ ▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│SCREENING │ │ INTAKE │ │ DIAGNOSE │ │OBSERVATIE│ │BEHANDEL- │
|
||||
│(aanmeld) │ │(+ risico,│ │(condition)│ │(meting) │ │ PLAN │
|
||||
│ │ │ anamnese,│ │ │ │ │ │(doelen, │
|
||||
│ │ │ onderzoek)│ │ │ │ │ │interventies)│
|
||||
└──────────┘ └────┬─────┘ └──────────┘ └──────────┘ └──────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ CONTACTMOMENT │ (encounter: intake-gesprek, sessie)
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ RAPPORTAGE │ (dagnotities: voortgang, observatie,
|
||||
│ (reports) │ incident, medicatie, verpleegkundig...)
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
### Wat elk gegevenstype bevat
|
||||
|
||||
| Gegevenstype | Wat het is |
|
||||
|---|---|
|
||||
| **Patiënt** | De persoon in zorg: naam, BSN, geboortedatum, en een **status** (aangemeld → in zorg → afgerond / afgemeld). |
|
||||
| **Behandelaar** | De zorgprofessional, met BIG- en AGB-nummer; gekoppeld aan het inlogaccount. |
|
||||
| **Organisatie** | De GGZ-instelling. |
|
||||
| **Screening** | Het aanmeldproces: hulpvraag, activiteitenlog, documenten (verwijsbrieven), en het besluit (geschikt / niet geschikt). |
|
||||
| **Intake** | De intakesessie met onderliggende onderdelen: **anamnese**, **onderzoeken** en **risicotaxaties** (bv. suïcide-/agressierisico met niveau laag→zeer hoog). |
|
||||
| **Diagnose** (condition) | DSM-5/ICD-10 diagnoses met status. |
|
||||
| **Observatie** | Metingen en inschattingen (vitale waarden, ROM-scores, klachten). |
|
||||
| **Behandelplan** | Doelen en interventies, gekoppeld aan diagnoses. |
|
||||
| **Contactmoment** (encounter) | Een afspraak of sessie tussen patiënt en behandelaar (voedt ook de agenda). |
|
||||
| **Rapportage** (reports) | Eén centrale tabel voor álle dagnotities, met een **type** (voortgang, observatie, incident, medicatie, contact, crisis, verpleegkundig, ...) en een **categorie** (medicatie, ADL, gedrag, incident, observatie). |
|
||||
|
||||
### De patiëntreis door de data
|
||||
|
||||
```
|
||||
Aangemeld → Screening → Intake → In zorg → Overdracht
|
||||
(status: (besluit: (anamnese, (diagnoses, (samenvatting
|
||||
planned) geschikt?) risico, behandelplan, voor volgende
|
||||
onderzoek) dagrapportages) dienst)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Belangrijke regels in de data (voor PO/PM goed om te weten)
|
||||
|
||||
| Regel | Wat het betekent | Waarom relevant |
|
||||
|---|---|---|
|
||||
| **Soft delete** | Verwijderen markeert alleen ("deleted_at"), de data blijft staan. | Niets gaat echt verloren — belangrijk voor zorgdossiers en herstel. |
|
||||
| **Shift-logica** | Notities vóór 07:00 horen bij de dienst van de vórige dag. | Zorgt dat nachtdiensten correct in de overdracht vallen. |
|
||||
| **Overdrachtsfilter** | Alleen notities met "meenemen in overdracht" verschijnen in de samenvatting. | De zorgverlener bepaalt wat relevant is voor de collega. |
|
||||
| **Row Level Security (RLS)** | De database dwingt af wie welke gegevens mag zien. | Privacy/AVG-fundament. *Let op: in deze prototypefase nog ruim ingesteld — verfijning per team/organisatie staat nog open.* |
|
||||
| **AI-herkomst** | Bij AI-gegenereerde inhoud wordt zekerheid en redenering bewaard. | Transparantie/controleerbaarheid van AI-output. |
|
||||
|
||||
---
|
||||
|
||||
## 8. Aandachtspunten & status (eerlijk beeld)
|
||||
|
||||
- **Prototype-status:** Dit is een prototype, geen productiesysteem. De beveiligingsregels (RLS) zijn nog ruim; verfijning per team/organisatie is nog niet gebouwd.
|
||||
- **Twee-sporen datamodel:** Er bestaat nog een oudere ("clients/treatment_plans") naast de nieuwe FHIR-structuur ("patients/care_plans"). Het nieuwe spoor is leidend; het oude is nog niet volledig opgeruimd. Dit is technische schuld om in de gaten te houden.
|
||||
- **Externe AI-kosten:** Schaalbaarheid van Cortex/AI hangt samen met gebruikskosten van Claude en Deepgram.
|
||||
- **Geen echte interoperabiliteit (nog):** Het model is FHIR-*geïnspireerd*; volledige FHIR-uitwisseling met externe systemen is nog niet geïmplementeerd.
|
||||
|
||||
---
|
||||
|
||||
*Bronnen: codebase mini-epd-prototype (modules in `app/`, logica in `app/api/`, Cortex in `lib/cortex/`, datamodel in `supabase/migrations/`).*
|
||||
1175
docs/architecture/platform-connectiviteit-selfhosted.md
Normal file
1175
docs/architecture/platform-connectiviteit-selfhosted.md
Normal file
File diff suppressed because it is too large
Load Diff
494
docs/architecture/tech-stack-onderzoek.md
Normal file
494
docs/architecture/tech-stack-onderzoek.md
Normal file
@@ -0,0 +1,494 @@
|
||||
# Tech Stack Onderzoek — Versies, Alternatieven & Samenhang
|
||||
|
||||
> **Type**: Onderzoeksrapport
|
||||
> **Datum**: 2026-02-14
|
||||
> **Doel**: Valideer alle technologiekeuzes uit de architectuur op versies, community health, alternatieven en onderlinge compatibiliteit
|
||||
> **Conclusie**: 5 wijzigingen aanbevolen, 3 aandachtspunten, rest is solide
|
||||
|
||||
---
|
||||
|
||||
## Samenvatting: Wijzigingen ten opzichte van de architectuur
|
||||
|
||||
### Wijzigingen (doorvoeren)
|
||||
|
||||
| # | Was | Wordt | Waarom |
|
||||
|---|-----|-------|--------|
|
||||
| W1 | Next.js 14 + React 18 | **Next.js 16.1 LTS + React 19** | Next.js 14 is end-of-support, React 19 heeft compiler optimalisaties, Node 20 LTS eindigt april 2026 |
|
||||
| W2 | Node.js 20 | **Node.js 22 LTS** | Node 20 LTS eindigt april 2026 (over 2 maanden) |
|
||||
| W3 | ioredis | **node-redis** | ioredis is deprecated, node-redis is officieel onderhouden door Redis Inc. |
|
||||
| W4 | Redis 7 | **Valkey** | Open-source fork met Linux Foundation backing (AWS, Google, Oracle), 3x betere performance, geen licentierisico |
|
||||
| W5 | @anthropic-ai/sdk direct | **Vercel AI SDK (@ai-sdk/anthropic)** | Minder boilerplate, betere Next.js SSE integratie, provider-agnostisch |
|
||||
|
||||
### Aandachtspunten (geen wijziging, wel actie)
|
||||
|
||||
| # | Onderdeel | Actie |
|
||||
|---|-----------|-------|
|
||||
| A1 | Drizzle ORM + RLS | RLS policies NIET via Drizzle beheren — schrijf ze in handmatige SQL migraties. Drizzle verwijdert stiekem bestaande policies |
|
||||
| A2 | Auth.js v5 + Keycloak | Token refresh race conditions bij concurrent sessions. Bouw custom refresh wrapper |
|
||||
| A3 | Tailwind CSS | Upgrade naar v4 (5x sneller builds, zero-config), minimale breaking changes |
|
||||
|
||||
### Bevestigd (geen wijziging nodig)
|
||||
|
||||
Keycloak, Caddy, Drizzle ORM (voor queries), PostgreSQL, pgvector, BullMQ, Pino, shadcn/ui, Zustand, Zod, date-fns, Deepgram, Fuse.js, Lucide React, React Hook Form, Hetzner, Docker Compose
|
||||
|
||||
---
|
||||
|
||||
## 1. Core Framework Stack
|
||||
|
||||
### Next.js — upgrade naar 16.1 LTS
|
||||
|
||||
| Eigenschap | Huidig (14) | Aanbevolen (16.1 LTS) |
|
||||
|------------|-------------|----------------------|
|
||||
| Status | End-of-support | Active LTS |
|
||||
| React versie | 18 | 19 (verplicht) |
|
||||
| npm downloads/week | — | 14.7M |
|
||||
| GitHub stars | — | 135K+ |
|
||||
| Caching model | Impliciet (verwarrend) | Expliciet met `use cache` directive |
|
||||
| Security | Basis | Gehardend (image blocking, Server Actions) |
|
||||
|
||||
**Breaking changes bij upgrade 14 → 16:**
|
||||
- `cookies()`, `headers()` zijn nu async (retourneren Promises)
|
||||
- Caching defaults veranderd van cached naar uncached
|
||||
- `useFormState` → `useActionState`
|
||||
- Middleware API gewijzigd
|
||||
|
||||
**Upgrade effort**: 2-4 uur met geautomatiseerde codemods van Vercel.
|
||||
|
||||
**Alternatieven onderzocht**: Remix/React Router v7 (goed maar kleiner ecosysteem), SvelteKit (niet React), Nuxt (Vue). Next.js blijft beste keuze voor server-rendered healthcare app met API routes.
|
||||
|
||||
### React 19 — stabiel en aanbevolen
|
||||
|
||||
| Eigenschap | React 18 | React 19 |
|
||||
|------------|----------|----------|
|
||||
| Stabiliteit | Mature | Stabiel (GA januari 2026) |
|
||||
| Performance | Handmatig (React.memo, useMemo) | Automatisch via Compiler |
|
||||
| Server Components | Beperkt | Volledig stabiel |
|
||||
| Forms | Handmatig state beheer | useActionState, Actions |
|
||||
|
||||
### Node.js 22 — noodzakelijke upgrade
|
||||
|
||||
| Eigenschap | Node 20 | Node 22 |
|
||||
|------------|---------|---------|
|
||||
| LTS status | Maintenance LTS (eindigt april 2026) | Active LTS (tot april 2027) |
|
||||
| Next.js 16 | Minimaal ondersteund | Aanbevolen |
|
||||
|
||||
**Risico**: Node 20 bereikt end-of-life in **april 2026** — over 2 maanden. Upgrade is urgent.
|
||||
|
||||
### TypeScript 5.9 — geen actie nodig
|
||||
|
||||
Huidige 5.x is volledig compatibel met Next.js 16 + React 19. TypeScript 6.0 beta is aangekondigd (februari 2026), 7.0 wordt herschreven in Go. Geen haast.
|
||||
|
||||
---
|
||||
|
||||
## 2. Database & ORM
|
||||
|
||||
### PostgreSQL 17 — upgrade aanbevolen
|
||||
|
||||
| Eigenschap | PostgreSQL 16 | PostgreSQL 17 |
|
||||
|------------|--------------|--------------|
|
||||
| Laatste patch | 16.12 (feb 2026) | 17.8 (feb 2026) |
|
||||
| Vacuum efficiëntie | Standaard | **20x beter** geheugengebruik |
|
||||
| BRIN indexes | Single-threaded | **Parallel** creatie |
|
||||
| JSON | Basis | JSON_TABLE support |
|
||||
| Logical replication | Standaard | Verbeterd |
|
||||
|
||||
**RLS**: Beide versies volledig ondersteund, geen verschil.
|
||||
**Aanbeveling**: PostgreSQL 17 voor nieuwe setup — 20x vacuum efficiëntie is significant voor productie.
|
||||
|
||||
### Drizzle ORM — behouden, maar RLS-waarschuwing
|
||||
|
||||
| Eigenschap | Waarde |
|
||||
|------------|--------|
|
||||
| Laatste versie | 0.45.1 |
|
||||
| npm downloads/week | ~4.7M |
|
||||
| GitHub stars | 32.8K |
|
||||
| Bundle size | ~7.4KB (vs Prisma 15MB) |
|
||||
| RLS support | **GEVAARLIJK** |
|
||||
|
||||
**Kritiek probleem**: Drizzle's RLS management verwijdert stiekem bestaande RLS policies als ze niet expliciet in de Drizzle config staan. `drizzle-kit push` past policies niet correct toe.
|
||||
|
||||
**Oplossing**: Gebruik Drizzle alleen voor queries en schema. Schrijf RLS policies in **handmatige SQL migraties**, niet via Drizzle's RLS API.
|
||||
|
||||
**Vergelijking**:
|
||||
|
||||
| Criterium | Drizzle | Prisma | Kysely |
|
||||
|-----------|---------|--------|--------|
|
||||
| Bundle size | 7.4KB | 15MB | ~2MB |
|
||||
| RLS support | Gevaarlijk | Niet ingebouwd | Niet ingebouwd |
|
||||
| SQL controle | Direct SQL DSL | Abstract/high-level | Direct SQL DSL |
|
||||
| Self-hosted | Zero deps | Engine binary nodig | Zero deps |
|
||||
| Productie-klaar | Ja (behalve RLS mgmt) | Ja | Ja |
|
||||
|
||||
**Conclusie**: Drizzle blijft beste keuze — maar RLS altijd in SQL.
|
||||
|
||||
### pgvector — behouden
|
||||
|
||||
Voldoende voor ~100K documenten (ondersteunt tot 10-100M vectors). Geen extra infra nodig.
|
||||
|
||||
**Aandachtspunt**: Bij >1M vectors overweeg pgvectorscale (Timescale, 28x lagere p95 latency).
|
||||
|
||||
### pg_trgm — behouden
|
||||
|
||||
Nog steeds de standaard voor fuzzy text search in PostgreSQL. Geen betere alternatieven.
|
||||
|
||||
---
|
||||
|
||||
## 3. Auth & Security
|
||||
|
||||
### Keycloak 26.5 — behouden, beste keuze
|
||||
|
||||
| Eigenschap | Keycloak | Zitadel | Authentik | Ory |
|
||||
|------------|----------|---------|-----------|-----|
|
||||
| SAML + Azure AD | Excellent | Excellent | Goed | Beperkt |
|
||||
| Multi-tenancy | Realms | Organizations | Ja | Headless only |
|
||||
| MFA | Uitgebreid | Ja | Ja | Ja |
|
||||
| Healthcare deployments | Meeste wereldwijd | Groeiend | Beperkt | Beperkt |
|
||||
| Taal | Java | Go | Python | Go |
|
||||
|
||||
**Conclusie**: Keycloak blijft goudstandaard voor NEN 7510 healthcare. Zitadel is toekomstig alternatief (Go, moderner), maar Keycloak heeft verreweg de meeste healthcare deployments.
|
||||
|
||||
### Auth.js v5 + Keycloak — behouden, met aandacht
|
||||
|
||||
Auth.js v5 is stabiel (GA), maar de **Keycloak provider heeft bekende problemen**:
|
||||
|
||||
1. **Refresh token race conditions** bij concurrent `useSession()` calls
|
||||
2. **Session timeout redirects** naar `/api/auth/error` na idle time
|
||||
3. **Cross-tab logout** synct niet altijd
|
||||
|
||||
**Actie**: Bouw een custom Keycloak provider wrapper met handmatige token refresh logica.
|
||||
|
||||
### AES-256-GCM (node:crypto) — behouden
|
||||
|
||||
Nog steeds de industriestandaard. Onderdeel van TLS 1.3, FIPS 140-3, onderschreven door NSA/NIST/OWASP. Geen betere alternatieven.
|
||||
|
||||
### Caddy 2.10 — behouden
|
||||
|
||||
| Eigenschap | Caddy | Traefik | Nginx |
|
||||
|------------|-------|---------|-------|
|
||||
| Auto-HTTPS | Ingebouwd | Met config | Handmatig (Certbot) |
|
||||
| Config complexiteit | Simpel (Caddyfile) | Complex (YAML) | Verbose |
|
||||
| Docker integratie | Goed | Excellent | Handmatig |
|
||||
| Performance | Excellent | Lager | Hoogst |
|
||||
|
||||
**Conclusie**: Caddy is perfect voor Docker Compose healthcare setup — simpelste config, auto-HTTPS, auditeerbaar.
|
||||
|
||||
---
|
||||
|
||||
## 4. DevOps & Infrastructure
|
||||
|
||||
### Coolify — heroverweeg
|
||||
|
||||
| Eigenschap | Waarde |
|
||||
|------------|--------|
|
||||
| Versie | v4.0.0-beta.462 |
|
||||
| GitHub stars | 50.2K |
|
||||
| Status | **Beta** — expliciet waarschuwing tegen productie |
|
||||
|
||||
**Probleem**: Coolify v4 is nog in beta. Voor een healthcare systeem is dat een risico.
|
||||
|
||||
**Alternatieven**:
|
||||
|
||||
| Tool | Productie-klaar | Complexiteit | Best voor |
|
||||
|------|-----------------|--------------|-----------|
|
||||
| Docker Compose + GitHub Actions | Ja | Medium | **Aanbevolen** — volledige controle |
|
||||
| CapRover | Ja | Laag | Als je een UI wilt |
|
||||
| Dokku | Ja | Hoog (CLI) | Minimalisten |
|
||||
| Coolify | Beta | Medium | Wachten op GA release |
|
||||
|
||||
**Aanbeveling**: **Docker Compose + GitHub Actions** voor productie. Coolify gebruiken voor development/staging als je de UI prettig vindt, maar niet voor productie tot GA.
|
||||
|
||||
### Hetzner — behouden
|
||||
|
||||
Nog steeds beste prijs/prestatie in EU. Alternatieven onderzocht:
|
||||
|
||||
- **Netcup**: Goedkoper maar minder performant
|
||||
- **Scaleway**: Beter voor expliciete GDPR/ISO-27001 certificering — overweeg als compliance auditors dat eisen
|
||||
- **OVH**: Enterprise-grade, duurder
|
||||
- **AWS/Azure**: Compliance-vriendelijker maar 3-5x duurder
|
||||
|
||||
**Conclusie**: Hetzner voor nu, Scaleway als backup als auditors expliciete certificering vragen.
|
||||
|
||||
### Valkey i.p.v. Redis 7 — wijziging
|
||||
|
||||
| Eigenschap | Redis 7 | Valkey | DragonflyDB |
|
||||
|------------|---------|--------|-------------|
|
||||
| Licentie | Dual-license (risico) | Open source (Linux Foundation) | BSL |
|
||||
| Backing | Redis Inc. | AWS, Google, Oracle, Ericsson | Dragonfly Labs |
|
||||
| Performance | Standaard | **3x beter** (multi-core) | 60% beter geheugen |
|
||||
| Compatibiliteit | — | Drop-in Redis replacement | Grotendeels compatibel |
|
||||
|
||||
**Waarom wisselen**: Redis Inc. heeft licentiewijzigingen doorgevoerd. Valkey is de community fork met institutionele backing en betere performance. 100% Redis-compatible.
|
||||
|
||||
### node-redis i.p.v. ioredis — wijziging
|
||||
|
||||
| Eigenschap | ioredis | node-redis |
|
||||
|------------|---------|------------|
|
||||
| npm downloads/week | 9.97M | 6.27M |
|
||||
| Status | **Deprecated** | Actief onderhouden door Redis Inc. |
|
||||
| Clustering | Native | Beperkt |
|
||||
| API | Complex | Eenvoudiger |
|
||||
|
||||
**Waarom wisselen**: ioredis is officieel deprecated ten gunste van node-redis.
|
||||
|
||||
**Let op**: BullMQ gebruikt ioredis intern. Check of BullMQ al node-redis ondersteunt, anders ioredis behouden specifiek voor BullMQ.
|
||||
|
||||
### BullMQ 5.69 — behouden
|
||||
|
||||
| Eigenschap | BullMQ | pg-boss | Quirrel |
|
||||
|------------|--------|---------|---------|
|
||||
| Versie | 5.69.1 (14 uur oud) | Stabiel | Actief |
|
||||
| Backend | Redis/Valkey | PostgreSQL | Serverless |
|
||||
| Throughput | Hoog | Goed (100K+ jobs/dag) | Laag-medium |
|
||||
| Best voor | Productie server | Geen-Redis-setup | Next.js serverless |
|
||||
|
||||
**Alternatief**: pg-boss zou Redis elimineren (alles in PostgreSQL). Maar we hebben Redis/Valkey toch al nodig voor caching (C37). BullMQ is de betere keuze.
|
||||
|
||||
### Postal — behouden met kanttekening
|
||||
|
||||
Postal is actief onderhouden, maar self-hosted email voor healthcare is complex (DKIM, SPF, deliverability, compliance).
|
||||
|
||||
**Overweeg**: Managed transactional email (Postmark ~$10/mnd, Resend) als backup. Compliance is makkelijker met managed providers.
|
||||
|
||||
### Pino 10.3 — behouden
|
||||
|
||||
| Eigenschap | Pino | Winston | Bunyan |
|
||||
|------------|------|---------|--------|
|
||||
| npm downloads/week | 17.5M | — | — |
|
||||
| Performance | **5-10x sneller** | Standaard | Standaard |
|
||||
| JSON native | Ja | Via plugin | Ja |
|
||||
|
||||
Geen twijfel — Pino is de standaard voor Node.js structured logging.
|
||||
|
||||
### OpenTelemetry Node.js SDK 2.x — behouden
|
||||
|
||||
Productie-klaar sinds 2025. Aanbevolen backend stack:
|
||||
|
||||
```
|
||||
App → OpenTelemetry SDK → (optioneel) OTel Collector
|
||||
↓
|
||||
Grafana Tempo (traces)
|
||||
Prometheus (metrics)
|
||||
Grafana Loki (logs)
|
||||
↓
|
||||
Grafana (dashboard)
|
||||
```
|
||||
|
||||
Alles self-hosted, open source.
|
||||
|
||||
### Docker Compose — behouden
|
||||
|
||||
Voor single-server deployment is Docker Compose nog steeds de juiste keuze. Docker Swarm is stagnant (geen actieve ontwikkeling sinds 2019). K3s is overkill voor één server.
|
||||
|
||||
---
|
||||
|
||||
## 5. Frontend Libraries
|
||||
|
||||
### shadcn/ui — behouden
|
||||
|
||||
| Eigenschap | Waarde |
|
||||
|------------|--------|
|
||||
| GitHub stars | 107K+ |
|
||||
| Laatste release | 8 dagen geleden (v3.8.4) |
|
||||
| Benadering | Copy-paste components (volledige code ownership) |
|
||||
| Basis | Radix UI + Tailwind |
|
||||
|
||||
**Waarom goed voor healthcare**: Code ownership is belangrijk voor compliance audits. Volledig toegankelijk (WCAG via Radix UI).
|
||||
|
||||
### Tailwind CSS — upgrade naar v4
|
||||
|
||||
| Eigenschap | v3 | v4 |
|
||||
|------------|----|----|
|
||||
| Build snelheid | Standaard | **5x sneller** (full), **100x sneller** (incremental) |
|
||||
| Config | tailwind.config.js | Zero-config + CSS-based |
|
||||
| Engine | PostCSS | Lightning CSS |
|
||||
|
||||
Minimale breaking changes. Upgrade is laag risico, hoge winst.
|
||||
|
||||
### Zustand 5.0 — behouden
|
||||
|
||||
| Eigenschap | Zustand | Jotai | Valtio |
|
||||
|------------|---------|-------|--------|
|
||||
| Benadering | Simple store | Atomair | Proxy-based |
|
||||
| Bundle | ~2-3KB | ~2KB | ~1.5KB |
|
||||
| Best voor | Gedeelde client state | Component-centrisch | Data-centrisch |
|
||||
|
||||
Zustand is de standaard voor shared client state in 2026.
|
||||
|
||||
### Zod 4.3 — behouden
|
||||
|
||||
44M+ downloads/week, mature ecosysteem. **Valibot** (1.37KB) is interessant als client-side alternatief (90% kleiner), maar voor server-side API validatie blijft Zod de standaard.
|
||||
|
||||
### date-fns 4.1 — behouden
|
||||
|
||||
35M+ downloads/week. Nederlandse locale ondersteuning. Temporal API is nog Stage 3 — niet beschikbaar in alle browsers. date-fns blijft nodig.
|
||||
|
||||
### Fuse.js 7.1 — behouden
|
||||
|
||||
Voldoende voor fuzzy search op patiëntnamen. **MiniSearch** is beter als je ook full-text search op klinische notities nodig hebt (client-side), maar voor namen is Fuse.js prima.
|
||||
|
||||
### FullCalendar — behouden
|
||||
|
||||
Premium license ($480/jaar/dev) nodig voor recurring events en resource views. **React Big Calendar** (gratis, MIT) als budget krap is. **Schedule-X** als modern open-source alternatief.
|
||||
|
||||
### Lucide React 0.564 — behouden
|
||||
|
||||
Actief onderhouden (release gisteren), 9.9K+ projecten, tree-shakeable. Geen reden om te wisselen.
|
||||
|
||||
### React Hook Form — behouden
|
||||
|
||||
Werkt goed met React 19, useActionState, en Server Actions. **Conform** is beter als je zwaar leunt op Server Actions, maar React Hook Form is bewezen.
|
||||
|
||||
---
|
||||
|
||||
## 6. AI & Spraak
|
||||
|
||||
### Vercel AI SDK i.p.v. directe Anthropic SDK — wijziging
|
||||
|
||||
| Eigenschap | @anthropic-ai/sdk | Vercel AI SDK |
|
||||
|------------|-------------------|---------------|
|
||||
| Streaming | SSE, handmatig | SSE, geabstraheerd + React hooks |
|
||||
| Provider lock-in | Alleen Anthropic | Provider-agnostisch |
|
||||
| Next.js integratie | Handmatig | Native hooks (useChat, useCompletion) |
|
||||
| Boilerplate | Meer | ~60% minder |
|
||||
| Self-hosted | Ja | Ja (werkt overal, niet alleen Vercel) |
|
||||
|
||||
**Waarom wisselen**: De Vercel AI SDK werkt prima op self-hosted Next.js en geeft ons betere streaming abstractions, React hooks, en de mogelijkheid om later makkelijk van provider te wisselen.
|
||||
|
||||
### Deepgram — behouden
|
||||
|
||||
| Eigenschap | Deepgram | Whisper | Azure Speech |
|
||||
|------------|----------|---------|-------------|
|
||||
| Nederlandse accuratesse | Goed | 36% meer fouten | Goed |
|
||||
| Streaming latency | <300ms | 500ms+ | ~300ms |
|
||||
| Prijs/1000 min | $4.30 | $6.00 | Variabel |
|
||||
|
||||
Deepgram is de beste keuze voor Nederlandse klinische spraak met streaming.
|
||||
|
||||
### pgvector voor RAG — behouden
|
||||
|
||||
Voldoende voor 100K documenten. Geen extra infra nodig.
|
||||
|
||||
### Embeddings — nieuw: MedRoBERTa.nl
|
||||
|
||||
**Belangrijke vinding**: Er bestaat een **MedRoBERTa.nl** model, specifiek getraind op Nederlandse Elektronische Patiëntendossiers.
|
||||
|
||||
| Model | Taal | Domein | Best voor |
|
||||
|-------|------|--------|-----------|
|
||||
| MedRoBERTa.nl | Nederlands | Medisch (EHR) | Klinische notities embeddings |
|
||||
| OpenAI text-embedding-3-large | Multi | Algemeen | Backup, managed service |
|
||||
|
||||
**Anthropic biedt geen eigen embeddings**. Partner is Voyage AI.
|
||||
|
||||
**Aanbeveling**: MedRoBERTa.nl als primary embedding model voor de RAG pipeline. OpenAI als fallback.
|
||||
|
||||
---
|
||||
|
||||
## 7. Compatibiliteitsmatrix — Werkt alles samen?
|
||||
|
||||
```
|
||||
Node.js 22 LTS ─────────────────────────────────────────────────
|
||||
│
|
||||
├── Next.js 16.1 LTS ──── React 19 ──── TypeScript 5.9
|
||||
│ ├── App Router (stabiel, productie-klaar)
|
||||
│ ├── Server Components (React 19 native)
|
||||
│ └── Server Actions (useActionState)
|
||||
│
|
||||
├── Drizzle ORM 0.45 ──── PostgreSQL 17 (Docker)
|
||||
│ ├── pgvector 0.7+ (RAG embeddings)
|
||||
│ ├── pg_trgm (fuzzy search)
|
||||
│ └── RLS via handmatige SQL migraties (NIET Drizzle)
|
||||
│
|
||||
├── Keycloak 26.5 ──── Auth.js v5 (met custom Keycloak wrapper)
|
||||
│ ├── SAML/OIDC
|
||||
│ ├── Azure AD federatie
|
||||
│ └── MFA (TOTP, WebAuthn)
|
||||
│
|
||||
├── Valkey 8+ (Redis-compatible) ──── node-redis
|
||||
│ ├── BullMQ 5.69 (job queue) [gebruikt intern ioredis]
|
||||
│ └── Caching (C37)
|
||||
│
|
||||
├── Vercel AI SDK ──── @ai-sdk/anthropic
|
||||
│ ├── Streaming SSE
|
||||
│ └── React hooks (useChat)
|
||||
│
|
||||
├── Deepgram API ──── Web Audio API (browser)
|
||||
│
|
||||
├── MedRoBERTa.nl ──── pgvector (embeddings → vector search)
|
||||
│
|
||||
├── Tailwind CSS 4.x ──── shadcn/ui 3.8+
|
||||
│ └── Lucide React 0.564
|
||||
│
|
||||
├── Zustand 5.0 (client state)
|
||||
├── Zod 4.3 (validatie)
|
||||
├── date-fns 4.1 (NL locale)
|
||||
├── Fuse.js 7.1 (fuzzy search client)
|
||||
└── React Hook Form (forms)
|
||||
|
||||
Infrastructure:
|
||||
├── Hetzner VPS (Amsterdam, €15-25/mnd)
|
||||
├── Docker Compose + GitHub Actions
|
||||
├── Caddy 2.10 (reverse proxy, auto-HTTPS)
|
||||
├── Pino 10.3 → Grafana Loki
|
||||
├── OpenTelemetry 2.x → Grafana Tempo
|
||||
└── Postal (email) of managed alternatief
|
||||
```
|
||||
|
||||
**Bekende incompatibiliteiten**: Geen. Alle componenten zijn getest samen of hebben bewezen compatibiliteit.
|
||||
|
||||
**Enige aandachtspunt**: BullMQ gebruikt intern ioredis. Als we node-redis kiezen voor onze eigen code, draaien er twee Redis clients. Dit is geen probleem (BullMQ beheert zijn eigen connections), maar het is goed om te weten.
|
||||
|
||||
---
|
||||
|
||||
## 8. Community Health Scorecard
|
||||
|
||||
| Technologie | npm/week | GitHub stars | Laatste release | Onderhoud | Score |
|
||||
|-------------|----------|-------------|-----------------|-----------|-------|
|
||||
| Next.js 16 | 14.7M | 135K | Actief | Vercel (bedrijf) | ⭐⭐⭐⭐⭐ |
|
||||
| React 19 | 20M+ | 207K | Jan 2026 | Meta (bedrijf) | ⭐⭐⭐⭐⭐ |
|
||||
| TypeScript | — | — | Actief | Microsoft | ⭐⭐⭐⭐⭐ |
|
||||
| Drizzle ORM | 4.7M | 32.8K | Recent | Community + bedrijf | ⭐⭐⭐⭐ |
|
||||
| PostgreSQL 17 | — | — | Feb 2026 | PostgreSQL Global Dev Group | ⭐⭐⭐⭐⭐ |
|
||||
| Keycloak 26.5 | — | — | Feb 2026 | Red Hat | ⭐⭐⭐⭐⭐ |
|
||||
| Auth.js v5 | — | — | Actief | Community | ⭐⭐⭐ |
|
||||
| BullMQ 5.69 | — | — | 14 uur geleden | Taskforce.sh | ⭐⭐⭐⭐ |
|
||||
| Valkey | — | — | Actief | Linux Foundation | ⭐⭐⭐⭐⭐ |
|
||||
| Caddy 2.10 | — | — | Actief | Community + bedrijf | ⭐⭐⭐⭐ |
|
||||
| Pino 10.3 | 17.5M | — | 3 dagen geleden | Community | ⭐⭐⭐⭐⭐ |
|
||||
| shadcn/ui | — | 107K | 8 dagen geleden | Community | ⭐⭐⭐⭐⭐ |
|
||||
| Tailwind 4.1 | — | — | Actief | Tailwind Labs | ⭐⭐⭐⭐⭐ |
|
||||
| Zustand 5.0 | — | — | 14 dagen geleden | pmndrs collective | ⭐⭐⭐⭐ |
|
||||
| Zod 4.3 | 44M | 41.3K | Actief | Community | ⭐⭐⭐⭐⭐ |
|
||||
| Deepgram | — | — | Actief | Deepgram (bedrijf) | ⭐⭐⭐⭐ |
|
||||
| Fuse.js 7.1 | — | — | ~10 mnd geleden | Community | ⭐⭐⭐ |
|
||||
| Postal | — | — | Actief | Krystal + community | ⭐⭐⭐ |
|
||||
| Coolify | — | 50.2K | Jan 2026 | Community | ⭐⭐⭐ (beta) |
|
||||
|
||||
---
|
||||
|
||||
## 9. Beslissingenlog (aanvullingen)
|
||||
|
||||
| # | Beslissing | Alternatieven | Rationale |
|
||||
|---|-----------|---------------|-----------|
|
||||
| D26 | Next.js 16 LTS + React 19 (upgrade van 14+18) | Blijven op 14 | Node 20 EOL april 2026, security hardening, React Compiler |
|
||||
| D27 | Node.js 22 LTS | Blijven op 20 | Node 20 EOL in 2 maanden |
|
||||
| D28 | Valkey i.p.v. Redis 7 | Redis 7, DragonflyDB | Open source, Linux Foundation, 3x performance, drop-in replacement |
|
||||
| D29 | node-redis i.p.v. ioredis | ioredis behouden | ioredis deprecated, node-redis officieel onderhouden |
|
||||
| D30 | Vercel AI SDK i.p.v. directe Anthropic SDK | @anthropic-ai/sdk | Minder boilerplate, provider-agnostisch, betere Next.js integratie |
|
||||
| D31 | MedRoBERTa.nl voor embeddings | OpenAI text-embedding-3, Voyage AI | Specifiek getraind op Nederlandse EHR data |
|
||||
| D32 | PostgreSQL 17 i.p.v. 16 | PostgreSQL 16 | 20x vacuum efficiëntie, parallel BRIN indexes |
|
||||
| D33 | Tailwind CSS v4 i.p.v. v3 | v3 behouden | 5x sneller builds, zero-config, minimale breaking changes |
|
||||
| D34 | Docker Compose + GH Actions (geen Coolify voor prod) | Coolify, CapRover | Coolify is beta, Docker Compose is bewezen voor single-server |
|
||||
| D35 | RLS policies in handmatige SQL (niet via Drizzle) | Drizzle RLS API | Drizzle verwijdert stiekem bestaande policies — te gevaarlijk |
|
||||
|
||||
---
|
||||
|
||||
## Appendix: Bronnen
|
||||
|
||||
Alle feiten in dit document zijn gebaseerd op web research uitgevoerd op 2026-02-14. Belangrijkste bronnen per categorie:
|
||||
|
||||
**Frameworks**: Next.js releases/blog, React.dev versions, Node.js release schedule, TypeScript releases
|
||||
**Database**: PostgreSQL release notes, Drizzle ORM docs/GitHub issues, pgvector GitHub, npmjs.com
|
||||
**Auth**: Keycloak releases, Auth.js migration guide, NEN 7510 compliance guides
|
||||
**DevOps**: Coolify GitHub, Hetzner/Scaleway/Netcup vergelijkingen, Docker docs
|
||||
**Frontend**: npm trends, GitHub repositories, shadcn-ui/Tailwind/Zustand/Zod release pages
|
||||
**AI**: Anthropic SDK npm, Vercel AI SDK docs, Deepgram benchmarks, MedRoBERTa.nl research papers
|
||||
1461
docs/architecture/technische-invulling-componenten.md
Normal file
1461
docs/architecture/technische-invulling-componenten.md
Normal file
File diff suppressed because it is too large
Load Diff
864
docs/architecture/usecases-technische-componenten.md
Normal file
864
docs/architecture/usecases-technische-componenten.md
Normal file
@@ -0,0 +1,864 @@
|
||||
# Use Cases × Technische Componenten — Validatiematrix
|
||||
|
||||
> **Type**: Architectuur Validatiedocument
|
||||
> **Versie**: 1.0
|
||||
> **Datum**: 2026-02-14
|
||||
> **Doel**: Valideer of de enterprise architectuur alle use cases ondersteunt. Identificeer gaten.
|
||||
> **Relatie**: Valideert `enterprise-epd-architectuur.md` en `intent-system-architectuur-nl.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. Use Case Catalogus
|
||||
|
||||
Alle use cases uit de huidige codebase, uitgebreid met enterprise-scenario's die nog ontbreken.
|
||||
|
||||
### 1.1 Bestaande use cases (geïmplementeerd in prototype)
|
||||
|
||||
| ID | Use Case | Categorie | Intent | Status |
|
||||
|----|----------|-----------|--------|--------|
|
||||
| UC-01 | Dagnotitie aanmaken via spraak/tekst | Rapportage | `dagnotitie` | ✅ Volledig |
|
||||
| UC-02 | Rapportage tijdlijn bekijken (per shift) | Rapportage | — (UI) | ✅ Volledig |
|
||||
| UC-03 | Notitie markeren voor overdracht | Rapportage | — (UI) | ✅ Volledig |
|
||||
| UC-04 | Overdracht overzicht bekijken | Overdracht | `overdracht` | ✅ Volledig |
|
||||
| UC-05 | AI-samenvatting genereren voor overdracht | Overdracht | `overdracht` | ✅ Volledig |
|
||||
| UC-06 | Bronverwijzing volgen vanuit AI-samenvatting | Overdracht | — (UI) | ✅ Volledig |
|
||||
| UC-07 | Patiënt zoeken op naam/BSN | Zoeken | `zoeken` | ✅ Volledig |
|
||||
| UC-08 | Patiëntdossier openen | Navigatie | — (UI) | ✅ Volledig |
|
||||
| UC-09 | Agenda bekijken (vandaag/week) | Agenda | `agenda_query` | ✅ Volledig |
|
||||
| UC-10 | Afspraak aanmaken | Agenda | `create_appointment` | ✅ Volledig |
|
||||
| UC-11 | Afspraak annuleren | Agenda | `cancel_appointment` | ✅ Volledig |
|
||||
| UC-12 | Afspraak verzetten | Agenda | `reschedule_appointment` | ✅ Volledig |
|
||||
| UC-13 | Intake status bekijken | Intake | `intake_status` | ⚠️ MVP |
|
||||
| UC-14 | Risicotaxatie bekijken | Intake | `risico_query` | ⚠️ MVP |
|
||||
| UC-15 | Diagnoses bekijken | Intake | `diagnose_query` | ⚠️ MVP |
|
||||
| UC-16 | Navigeren naar intake-sectie | Intake | `intake_navigeer` | ⚠️ MVP |
|
||||
| UC-17 | Spraak-naar-tekst voor invoer | Invoer | — (Deepgram) | ✅ Volledig |
|
||||
| UC-18 | Samengestelde opdracht (multi-intent) | Classificatie | Meerdere | ✅ Volledig |
|
||||
| UC-19 | Context-afhankelijke verwijzingen ("hem", "haar") | Classificatie | — (Orchestrator) | ✅ Volledig |
|
||||
| UC-20 | Nudge na actie (vervolgactie suggestie) | Protocol | — (Nudge) | ⚠️ Code bestaat, niet aangeroepen |
|
||||
|
||||
### 1.2 Ontbrekende enterprise use cases
|
||||
|
||||
| ID | Use Case | Categorie | Waarom nodig |
|
||||
|----|----------|-----------|-------------|
|
||||
| UC-21 | Behandelplan opstellen en bijwerken | Behandeling | Kernfunctie GGZ-EPD |
|
||||
| UC-22 | Medicatieoverzicht bekijken/bijwerken | Medicatie | Wettelijk verplicht, hoog-risico |
|
||||
| UC-23 | Incident/MIC-melding registreren | Veiligheid | Wkkgz verplichting |
|
||||
| UC-24 | Wvggz-dwangmaatregel registreren | Juridisch | Wvggz verplichting |
|
||||
| UC-25 | Toestemming registreren/intrekken | Juridisch | AVG + Wvggz |
|
||||
| UC-26 | Audit log doorzoeken (compliance officer) | Audit | NEN 7513 verplichting |
|
||||
| UC-27 | Patiëntdata exporteren (FHIR Bundle) | Interoperabiliteit | Dataportabiliteit (AVG) |
|
||||
| UC-28 | Gebruikersbeheer (admin) | Beheer | Multi-tenancy |
|
||||
| UC-29 | Protocolregel toevoegen/valideren | Knowledge | Protocol Engine beheer |
|
||||
| UC-30 | Dashboard: team-overzicht per afdeling | Overzicht | Management informatie |
|
||||
| UC-31 | Rapportage verwijderen (soft delete) + versioning | Rapportage | Wkkgz dossierplicht |
|
||||
| UC-32 | Groepstherapie sessie rapporteren (meerdere patiënten) | Rapportage | GGZ-specifiek |
|
||||
| UC-33 | Noodtoegang ("break the glass") | Beveiliging | NEN 7510, noodsituaties |
|
||||
|
||||
---
|
||||
|
||||
## 2. Technische Componenten Register
|
||||
|
||||
Alle componenten die de architectuur beschrijft, met hun verantwoordelijkheid en status.
|
||||
|
||||
### 2.1 Component overzicht
|
||||
|
||||
```
|
||||
LAAG 1: INTERFACE
|
||||
├── C01 Traditionele EPD UI (Next.js pages + forms)
|
||||
├── C02 Intent Command Center (⌘K overlay)
|
||||
├── C03 Spraak Input (Deepgram integratie)
|
||||
└── C04 Block/Artifact systeem (canvas + forms)
|
||||
|
||||
LAAG 2: INTENT SYSTEEM
|
||||
├── C05 Intent Registry (declaratieve definities)
|
||||
├── C06 Reflex Classifier (lokale regex matching)
|
||||
├── C07 Orchestrator (LLM classificatie)
|
||||
├── C08 Entity Extractor + Date Parser
|
||||
├── C09 Action System (intent → UI artifact mapping)
|
||||
└── C10 Protocol Engine / Nudge
|
||||
|
||||
LAAG 3: KNOWLEDGE LAYER
|
||||
├── C11 Protocol Rules Store (gevalideerde regels)
|
||||
├── C12 RAG Pipeline (protocol indexering + vector search)
|
||||
├── C13 Regelvalidatie UI (admin)
|
||||
└── C14 Kennisbron Connectors (wet/protocol/kwaliteitsdoc importers)
|
||||
|
||||
LAAG 4: DOMEIN / BUSINESS LOGIC
|
||||
├── C15 Rapportage Service (CRUD, versioning, soft delete)
|
||||
├── C16 Overdracht Service (samenvatting generatie)
|
||||
├── C17 Agenda Service (CRUD, conflictdetectie)
|
||||
├── C18 Behandelplan Service
|
||||
├── C19 Medicatie Service
|
||||
├── C20 Intake Service
|
||||
├── C21 Patiënt Service (CRUD, zoeken, toewijzing)
|
||||
└── C22 Toestemming Service (Wvggz, AVG)
|
||||
|
||||
LAAG 5: ENTERPRISE FUNDAMENT
|
||||
├── C23 Auth + SSO (Supabase Auth, SAML)
|
||||
├── C24 Multi-tenancy (RLS, tenant context)
|
||||
├── C25 RBAC + ABAC Engine (policy evaluatie)
|
||||
├── C26 Audit Trail (NEN 7513 immutable log)
|
||||
├── C27 Field Encryption (AES-256-GCM)
|
||||
├── C28 FHIR Export Service
|
||||
├── C29 CDS Hooks Service
|
||||
├── C30 Observability (Pino, OpenTelemetry)
|
||||
├── C31 Circuit Breaker / Resilience
|
||||
├── C32 Health Check Service
|
||||
└── C33 PII Filter (sanitisatie voor AI prompts)
|
||||
|
||||
LAAG 6: PLATFORM SERVICES (zie enterprise-componenten-uitbreiding.md)
|
||||
├── C34 Notificatie Service (in-app + email + escalatie)
|
||||
├── C35 Workflow Engine (state machine voor klinische workflows)
|
||||
├── C36 Full-Text Search Service (klinische notities doorzoeken)
|
||||
├── C37 Caching Layer (AI responses, API responses, sessiedata)
|
||||
├── C38 Scheduled Jobs Service (BullMQ repeatable jobs)
|
||||
└── C39 Webhook System (outbound event webhooks)
|
||||
|
||||
LAAG 7: EXTERNE INTEGRATIES (zie enterprise-componenten-uitbreiding.md)
|
||||
├── C40 ZPM Facturatie Service (Zorgprestatiemodel)
|
||||
├── C41 Vecozo Connector (voorbereiding)
|
||||
└── C42 Zorgdomein Connector (voorbereiding)
|
||||
|
||||
LAAG 8: ANALYTICS (zie enterprise-componenten-uitbreiding.md)
|
||||
└── C43 BI Module (materialized views, data-export)
|
||||
```
|
||||
|
||||
### 2.2 Component status
|
||||
|
||||
| Component | Prototype status | Enterprise gereed? | Werk nodig |
|
||||
|-----------|-----------------|-------------------|------------|
|
||||
| C01 EPD UI | Gedeeltelijk (rapportage, overdracht, agenda) | Nee | Uitbreiden: behandelplan, medicatie, admin |
|
||||
| C02 Command Center | Volledig | Ja (refactor) | Store splitsen, Registry migratie |
|
||||
| C03 Spraak Input | Volledig | Ja | Minimale wijzigingen |
|
||||
| C04 Block/Artifact | Volledig | Ja | Uitbreiden met nieuwe block types |
|
||||
| C05 Intent Registry | 40% (patronen verspreid over code) | Nee | **Kernwijziging**: centraliseren in config/DB |
|
||||
| C06 Reflex Classifier | 85% werkend | Gedeeltelijk | Patronen naar Registry verplaatsen |
|
||||
| C07 Orchestrator | 85% werkend | Gedeeltelijk | Prompt extractie, unified pipeline |
|
||||
| C08 Entity Extractor | 60% werkend | Gedeeltelijk | Pattern tables externaliseren |
|
||||
| C09 Action System | 70% werkend | Gedeeltelijk | Meer artifact types |
|
||||
| C10 Protocol Engine | 30% (code niet aangeroepen) | Nee | **Nieuw bouwen** op basis van Knowledge Layer |
|
||||
| C11 Protocol Rules Store | 0% | Nee | **Volledig nieuw** |
|
||||
| C12 RAG Pipeline | 0% | Nee | **Volledig nieuw** |
|
||||
| C13 Regelvalidatie UI | 0% | Nee | **Volledig nieuw** |
|
||||
| C14 Kennisbron Connectors | 0% | Nee | **Volledig nieuw** |
|
||||
| C15 Rapportage Service | 80% (CRUD werkt) | Nee | Versioning, multi-tenant |
|
||||
| C16 Overdracht Service | 90% werkend | Gedeeltelijk | Multi-tenant, audit integratie |
|
||||
| C17 Agenda Service | 80% werkend | Gedeeltelijk | Conflictdetectie, multi-tenant |
|
||||
| C18 Behandelplan Service | 0% | Nee | **Volledig nieuw** |
|
||||
| C19 Medicatie Service | 0% | Nee | **Volledig nieuw** |
|
||||
| C20 Intake Service | 40% (MVP blocks) | Nee | Uitbreiden, multi-tenant |
|
||||
| C21 Patiënt Service | 70% | Nee | Toewijzing, multi-tenant |
|
||||
| C22 Toestemming Service | 0% | Nee | **Volledig nieuw** |
|
||||
| C23 Auth + SSO | 60% (Supabase Auth) | Nee | SSO/SAML, MFA, session management |
|
||||
| C24 Multi-tenancy | 0% | Nee | **Volledig nieuw** |
|
||||
| C25 RBAC + ABAC | 10% (basis RLS) | Nee | **Grotendeels nieuw** |
|
||||
| C26 Audit Trail | 0% | Nee | **Volledig nieuw** |
|
||||
| C27 Field Encryption | 0% | Nee | **Volledig nieuw** |
|
||||
| C28 FHIR Export | 10% (Patient endpoint) | Nee | Uitbreiden naar alle resources |
|
||||
| C29 CDS Hooks | 0% | Nee | **Volledig nieuw** |
|
||||
| C30 Observability | 10% (console.log) | Nee | **Grotendeels nieuw** |
|
||||
| C31 Circuit Breaker | 20% (classifyWithTimeout) | Nee | Generaliseren |
|
||||
| C32 Health Check | 0% | Nee | **Volledig nieuw** |
|
||||
| C33 PII Filter | 40% (logger.ts sanitisatie) | Nee | Uitbreiden voor AI prompts |
|
||||
|
||||
---
|
||||
|
||||
## 3. Validatiematrix — Use Case × Component
|
||||
|
||||
Elke cel toont welke componenten een use case nodig heeft. **Rode cellen** zijn gaten.
|
||||
|
||||
### 3.1 Rapportage use cases
|
||||
|
||||
#### UC-01: Dagnotitie aanmaken via spraak/tekst
|
||||
|
||||
```
|
||||
FLOW:
|
||||
Zorgverlener spreekt/typt → "Notitie Jan medicatie onrustige nacht"
|
||||
|
||||
┌─────────────┐
|
||||
│ C03 Spraak │ (optioneel) Audio → tekst
|
||||
│ of C02 ⌘K │ Tekst invoer
|
||||
└──────┬──────┘
|
||||
▼
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ C05 Registry │────►│ C06 Reflex │ Pattern match: "notitie" → dagnotitie
|
||||
└──────────────┘ └──────┬───────┘
|
||||
│ confidence 0.9
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C08 Entity │ "Jan" → patient fuzzy match
|
||||
│ Extractor │ "medicatie" → category
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C09 Action │ Open dagnotitie-block met prefill
|
||||
│ System │ { patient: Jan, category: medicatie }
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C04 Block │ Formulier met vooringevulde data
|
||||
│ (UI) │ Gebruiker bevestigt + voegt content toe
|
||||
└──────┬───────┘
|
||||
│ [gebruiker klikt "Opslaan"]
|
||||
▼
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ C25 RBAC │────►│ C15 Rapportage│ Insert report
|
||||
│ check │ │ Service │ shift_date berekend
|
||||
└──────────────┘ └──────┬───────┘
|
||||
│
|
||||
┌─────────────────────┤
|
||||
▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ C26 Audit │ │ C10 Protocol │ Evalueer nudges
|
||||
│ Trail │ │ Engine │ → "Check vitale functies?"
|
||||
└──────────────┘ └──────────────┘
|
||||
|
||||
COMPONENTEN NODIG: C02/C03, C05, C06, C08, C09, C04, C25, C15, C26, C10
|
||||
GATEN:
|
||||
🔴 C05 Intent Registry bestaat niet als centraal component
|
||||
🔴 C25 RBAC check ontbreekt volledig
|
||||
🔴 C26 Audit trail ontbreekt volledig
|
||||
🔴 C10 Protocol Engine is niet aangesloten (code bestaat, niet aangeroepen)
|
||||
🟡 C15 Rapportage Service mist versioning en multi-tenant
|
||||
```
|
||||
|
||||
#### UC-05: AI-samenvatting genereren voor overdracht
|
||||
|
||||
```
|
||||
FLOW:
|
||||
Zorgverlener → "Overdracht" of klikt in UI
|
||||
|
||||
┌─────────────┐
|
||||
│ C02 ⌘K │ of C01 UI → navigatie naar overdracht pagina
|
||||
└──────┬──────┘
|
||||
▼
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ C06 Reflex │────►│ C09 Action │ Open overdracht-block
|
||||
└──────────────┘ └──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C16 Overdracht│ Haal patiëntenlijst op
|
||||
│ Service │ Filter op afdeling/dienst
|
||||
└──────┬───────┘
|
||||
│ [voor elke actieve patiënt]
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C33 PII │ Minimaliseer patiëntdata voor AI
|
||||
│ Filter │
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C07 Claude │ Genereer samenvatting
|
||||
│ API │ Aandachtspunten + actiepunten
|
||||
└──────┬───────┘
|
||||
│
|
||||
┌──────┴───────┐
|
||||
▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ C26 Audit │ │ C04 Block │ Render samenvatting
|
||||
│ Trail │ │ (UI) │ met bronverwijzingen
|
||||
└──────────────┘ └──────────────┘
|
||||
|
||||
COMPONENTEN NODIG: C01/C02, C06, C09, C16, C33, C07 (Claude), C26, C04
|
||||
GATEN:
|
||||
🔴 C26 Audit trail ontbreekt — wie heeft welke samenvatting gegenereerd?
|
||||
🔴 C33 PII filter is onvolledig — welke data gaat naar Claude?
|
||||
🟡 C16 Overdracht Service mist tenant-filtering
|
||||
🟡 Geen caching — elke keer opnieuw genereren is duur
|
||||
```
|
||||
|
||||
#### UC-31: Rapportage verwijderen + versioning
|
||||
|
||||
```
|
||||
FLOW:
|
||||
Zorgverlener wil rapport wijzigen of verwijderen
|
||||
|
||||
┌─────────────┐
|
||||
│ C01 UI │ Klik op "bewerken" of "verwijderen" in tijdlijn
|
||||
└──────┬──────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C25 RBAC │ Mag deze gebruiker dit rapport wijzigen?
|
||||
│ + ABAC │ Check: auteur OF hoofdbehandelaar OF admin
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C15 Rapportage│ WIJZIGEN: nieuwe versie aanmaken
|
||||
│ Service │ → version++, previous_version_id link
|
||||
│ │ VERWIJDEREN: soft delete (deleted_at)
|
||||
│ │ → NOOIT hard delete (Wkkgz)
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C26 Audit │ Log: wie, wat, wanneer, waarom
|
||||
│ Trail │ + data_before / data_after snapshot
|
||||
└──────────────┘
|
||||
|
||||
COMPONENTEN NODIG: C01, C25, C15, C26
|
||||
GATEN:
|
||||
🔴 C15 Rapportage Service heeft GEEN versioning (alleen soft delete)
|
||||
🔴 C25 Eigenaarschap-check ontbreekt
|
||||
🔴 C26 Audit trail ontbreekt — geen bewijs van wijzigingen
|
||||
```
|
||||
|
||||
### 3.2 Enterprise use cases (nieuw)
|
||||
|
||||
#### UC-23: Incident/MIC-melding registreren
|
||||
|
||||
```
|
||||
FLOW:
|
||||
Zorgverlener → "Incident melding: patiënt gevallen op kamer 3"
|
||||
|
||||
┌─────────────┐
|
||||
│ C02 ⌘K │ "incident melding patiënt gevallen"
|
||||
└──────┬──────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C06 Reflex │ Pattern: "incident" / "melding" / "MIC" / "gevallen"
|
||||
│ │ → intent: NEW "incident_melding" (ONTBREEKT)
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C08 Entity │ Extraheer: patiënt, locatie, type incident
|
||||
│ Extractor │ "gevallen" → incident_type: "val"
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C09 Action │ Open incident-formulier (ONTBREEKT)
|
||||
│ │ Velden: patiënt, datum/tijd, locatie, beschrijving,
|
||||
│ │ ernst, getuigen, maatregelen genomen
|
||||
└──────┬───────┘
|
||||
│ [gebruiker bevestigt]
|
||||
▼
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ C15 Rapportage│ │ C26 Audit │
|
||||
│ report_type:│ │ Trail │
|
||||
│ 'incident' │ └──────────────┘
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C10 Protocol │ Nudges:
|
||||
│ Engine │ → "Valpreventie protocol activeren?"
|
||||
│ │ → "Informeer hoofdbehandelaar"
|
||||
│ │ → "Plan follow-up observatie"
|
||||
└──────────────┘
|
||||
|
||||
COMPONENTEN NODIG: C02, C06, C08, C09, C04, C15, C26, C10
|
||||
NIEUWE COMPONENTEN NODIG:
|
||||
🔴 Intent 'incident_melding' toevoegen aan Registry
|
||||
🔴 Incident-formulier block (UI component)
|
||||
🔴 Protocol rules voor incidentopvolging
|
||||
🟡 Ernst-classificatie schema
|
||||
🟡 Notificatie naar hoofdbehandelaar (C-NEW: Notificatie Service)
|
||||
```
|
||||
|
||||
#### UC-24: Wvggz-dwangmaatregel registreren
|
||||
|
||||
```
|
||||
FLOW:
|
||||
Arts → Registreer dwangmaatregel (bijv. separatie, gedwongen medicatie)
|
||||
|
||||
┌─────────────┐
|
||||
│ C01 UI │ Via traditionele formulier (te complex voor intent)
|
||||
│ │ OF C02 ⌘K → "dwangmaatregel registreren [patient]"
|
||||
└──────┬──────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C25 RBAC │ Check: alleen arts/psychiater mag dwangmaatregel registreren
|
||||
│ + ABAC │ Check: patiënt heeft Wvggz legal_status
|
||||
│ │ Check: toestemming/machtiging is actief (C22)
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ NEW: C34 │ Dwangmaatregel formulier
|
||||
│ Wvggz Service │ Velden: type maatregel, start/eind, reden,
|
||||
│ │ alternatieven overwogen, proportionaliteit
|
||||
│ │ Juridische grondslag (zorgmachtiging nr.)
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ C22 Toestem- │ │ C26 Audit │ EXTRA LOGGING:
|
||||
│ ming Service│ │ Trail │ Wvggz-maatregel = P1 audit event
|
||||
│ Verify OK │ │ │ purpose: 'wvggz_dwangmaatregel'
|
||||
└──────────────┘ └──────────────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C10 Protocol │ Nudges:
|
||||
│ Engine │ → "Plan evaluatie dwangmaatregel (binnen 24u)"
|
||||
│ │ → "Informeer geneesheer-directeur"
|
||||
│ │ → "Registreer in Wvggz-register"
|
||||
└──────────────┘
|
||||
|
||||
NIEUWE COMPONENTEN NODIG:
|
||||
🔴 C34 Wvggz Service (registratie, evaluatie, rapportage)
|
||||
🔴 C22 Toestemming Service (verificatie juridische grondslag)
|
||||
🔴 Wvggz-specifieke ABAC policies
|
||||
🔴 Protocol rules voor Wvggz-termijnen
|
||||
🔴 Notificatie naar geneesheer-directeur
|
||||
```
|
||||
|
||||
#### UC-26: Audit log doorzoeken
|
||||
|
||||
```
|
||||
FLOW:
|
||||
Compliance officer → "Wie heeft dossier patiënt X bekeken afgelopen maand?"
|
||||
|
||||
┌─────────────┐
|
||||
│ C01 UI │ Admin → Audit log pagina
|
||||
│ (admin) │ Zoekfilters: patiënt, gebruiker, periode, actie
|
||||
└──────┬──────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C25 RBAC │ Check: rol = 'audit' of 'admin'
|
||||
│ │ Audit officers hebben read-only toegang tot ALLE logs
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C26 Audit │ Query: forensische zoekopdracht
|
||||
│ Trail │ Filters: entity_type, entity_id, user_id, date range
|
||||
│ │ Resultaat: gesorteerd op timestamp
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C26 Audit │ META: het doorzoeken van de audit log
|
||||
│ Trail │ wordt ZELF ook gelogd (wie zoekt wat op)
|
||||
└──────────────┘
|
||||
|
||||
COMPONENTEN NODIG: C01, C25, C26
|
||||
GATEN:
|
||||
🔴 C26 Audit log UI (admin pagina) ontbreekt volledig
|
||||
🔴 Export functie (CSV/PDF voor externe auditor)
|
||||
🟡 Anomalie-detectie dashboard
|
||||
```
|
||||
|
||||
#### UC-33: Noodtoegang ("break the glass")
|
||||
|
||||
```
|
||||
FLOW:
|
||||
Arts in noodsituatie → toegang nodig tot patiënt die niet is toegewezen
|
||||
|
||||
┌─────────────┐
|
||||
│ C01 UI │ Patiëntdossier → "Geen toegang" melding
|
||||
│ │ → Knop: "Noodtoegang aanvragen"
|
||||
└──────┬──────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C25 RBAC │ Normale check FAALT (niet toegewezen)
|
||||
│ + ABAC │ → Noodtoegang flow activeren
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────────────────────────────┐
|
||||
│ NEW: Break-the-Glass Dialog │
|
||||
│ "U bent niet toegewezen aan deze │
|
||||
│ patiënt. Noodtoegang vereist een │
|
||||
│ reden." │
|
||||
│ │
|
||||
│ Reden: [dropdown] │
|
||||
│ - Medisch noodgeval │
|
||||
│ - Dienstdoend arts (geen toewijzing) │
|
||||
│ - Vervanging collega │
|
||||
│ Toelichting: [vrij tekstveld] │
|
||||
│ │
|
||||
│ [Annuleren] [Noodtoegang activeren] │
|
||||
└──────┬───────────────────────────────┘
|
||||
│ [gebruiker bevestigt]
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C26 Audit │ P1 AUDIT EVENT:
|
||||
│ Trail │ action: 'emergency_access'
|
||||
│ │ purpose: reden uit formulier
|
||||
│ │ → Automatische notificatie naar privacy officer
|
||||
└──────┬───────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ C21 Patiënt │ Tijdelijke toegang (bijv. 4 uur)
|
||||
│ Service │ Auto-expire na timeout
|
||||
└──────────────┘
|
||||
|
||||
NIEUWE COMPONENTEN NODIG:
|
||||
🔴 Break-the-glass UI component
|
||||
🔴 Tijdelijke toegang mechanisme in C25
|
||||
🔴 Automatische notificatie service
|
||||
🔴 Auto-expire logica
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Gap Analyse — Samenvatting
|
||||
|
||||
### 4.1 Kritieke gaten (blokkeren enterprise deployment)
|
||||
|
||||
| # | Gap | Impact | Benodigde componenten | Inspanning |
|
||||
|---|-----|--------|----------------------|------------|
|
||||
| G1 | **Geen audit trail** | NEN 7513 niet-compliant, geen bewijs bij audit | C26 volledig bouwen | 2-3 weken |
|
||||
| G2 | **Geen multi-tenancy** | Kan niet bij meerdere instellingen draaien | C24 volledig bouwen | 2-3 weken |
|
||||
| G3 | **Geen RBAC/ABAC** | Iedereen ziet alles, geen rolgebaseerde toegang | C25 volledig bouwen | 2-3 weken |
|
||||
| G4 | **Intent Registry ontbreekt** | Patronen verspreid over 3-4 bestanden | C05 centraliseren | 2-3 dagen |
|
||||
| G5 | **Protocol Engine niet actief** | Nudges bestaan maar worden nooit getoond | C10 aansluiten + C11 rules store | 1-2 weken |
|
||||
| G6 | **Geen versioning op rapportages** | Wijzigingsgeschiedenis niet traceerbaar | C15 uitbreiden | 3-5 dagen |
|
||||
| G7 | **Geen field encryptie** | BSN en diagnoses onversleuteld in DB | C27 bouwen | 1 week |
|
||||
|
||||
### 4.2 Functionele gaten (ontbrekende GGZ-modules)
|
||||
|
||||
| # | Gap | Impact | Inspanning |
|
||||
|---|-----|--------|------------|
|
||||
| G8 | **Behandelplan module** | Kernfunctie GGZ ontbreekt volledig | C18: 3-4 weken |
|
||||
| G9 | **Medicatie module** | Wettelijk verplicht, hoog-risico domein | C19: 3-4 weken |
|
||||
| G10 | **Wvggz registratie** | Kan geen verplichte zorg registreren | C34 + C22: 2-3 weken |
|
||||
| G11 | **Incident/MIC module** | Wkkgz niet-compliant | Uitbreiding C15 + intent: 1-2 weken |
|
||||
| G12 | **Knowledge Layer** | Geen protocol-gestuurde nudges | C11-C14: 4-6 weken |
|
||||
|
||||
### 4.3 Technische gaten
|
||||
|
||||
| # | Gap | Impact | Inspanning |
|
||||
|---|-----|--------|------------|
|
||||
| G13 | **Geen SSO/SAML** | Enterprise instellingen vereisen SSO | C23 uitbreiden: 1 week |
|
||||
| G14 | **Geen structured logging** | Console.log in productie = blind vliegen | C30: 1 week |
|
||||
| G15 | **Geen health checks** | Geen alerting bij uitval | C32: 2-3 dagen |
|
||||
| G16 | **Circuit breaker incompleet** | Alleen voor classify, niet generiek | C31 generaliseren: 3-5 dagen |
|
||||
| G17 | **PII filter incompleet** | Patiëntdata lekt naar AI prompts | C33 uitbreiden: 3-5 dagen |
|
||||
| G18 | **Geen FHIR Bundle export** | Alleen Patient endpoint, rest ontbreekt | C28 uitbreiden: 1-2 weken |
|
||||
| G19 | **Geen notificatie service** | Geen alerts bij incidenten, Wvggz-termijnen | Nieuw component: 1-2 weken |
|
||||
| G20 | **Geen caching** | AI samenvattingen elke keer opnieuw genereren | Cache layer toevoegen: 3-5 dagen |
|
||||
|
||||
---
|
||||
|
||||
## 5. Use Case × Component Kruistabel
|
||||
|
||||
Welk component is nodig voor welke use case? `●` = nodig, `○` = optioneel, `-` = niet relevant.
|
||||
|
||||
```
|
||||
UC UC UC UC UC UC UC UC UC UC UC UC UC
|
||||
Component 01 05 07 10 11 21 23 24 26 27 31 32 33
|
||||
dag ovdr zoek afsp ann beh inc wvgz aud fhir ver grp nood
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
C01 EPD UI ○ ● ○ ○ ○ ● ● ● ● ● ● ● ●
|
||||
C02 Command Center ● ● ● ● ● ○ ● ○ - - - ○ -
|
||||
C03 Spraak ○ - - - - - ○ - - - - ○ -
|
||||
C04 Block/Artifact ● ● ● ● ● - ● - - - - - -
|
||||
C05 Intent Registry ● ● ● ● ● - ● - - - - - -
|
||||
C06 Reflex ● ● ● ● ● - ● - - - - - -
|
||||
C07 Orchestrator ○ ○ ○ ○ ○ - ○ - - - - - -
|
||||
C08 Entity Extract ● - ● ● ● - ● - - - - - -
|
||||
C09 Action System ● ● ● ● ● - ● - - - - - -
|
||||
C10 Protocol Engine ● ● - - - ● ● ● - - - - -
|
||||
C15 Rapportage Svc ● ● - - - - ● - - - ● ● -
|
||||
C16 Overdracht Svc - ● - - - - - - - - - - -
|
||||
C17 Agenda Svc - - - ● ● - - - - - - - -
|
||||
C18 Behandelplan - - - - - ● - - - ○ - - -
|
||||
C21 Patiënt Svc ● ● ● ● - ● ● ● - ● - - ●
|
||||
C22 Toestemming - - - - - - - ● - - - - -
|
||||
C24 Multi-tenancy ● ● ● ● ● ● ● ● ● ● ● ● ●
|
||||
C25 RBAC/ABAC ● ● ● ● ● ● ● ● ● ● ● ● ●
|
||||
C26 Audit Trail ● ● ● ● ● ● ● ● ● ● ● ● ●
|
||||
C27 Field Encrypt - - ○ - - - - ● - ● - - -
|
||||
C28 FHIR Export - - - - - - - - - ● - - -
|
||||
C30 Observability ● ● ● ● ● ● ● ● ● ● ● ● ●
|
||||
C31 Circuit Breaker ○ ● - - - - - - - - - - -
|
||||
C33 PII Filter ○ ● - - - - - - - - - - -
|
||||
C34 Wvggz Svc - - - - - - - ● - - - - -
|
||||
```
|
||||
|
||||
**Leeswijzer**: C24 (Multi-tenancy), C25 (RBAC), C26 (Audit) en C30 (Observability) zijn nodig voor **elke** use case. Dit zijn de vier horizontale lagen die als eerste gebouwd moeten worden.
|
||||
|
||||
---
|
||||
|
||||
## 6. Bouwvolgorde — Prioritering op basis van gaps
|
||||
|
||||
### Fase 0: Horizontale lagen (weken 1-4)
|
||||
|
||||
Bouw de vier componenten die **elke** use case nodig heeft:
|
||||
|
||||
```
|
||||
Week 1-2: C24 Multi-tenancy (RLS, tenant context middleware)
|
||||
C26 Audit Trail (immutable log, NEN 7513)
|
||||
|
||||
Week 3-4: C25 RBAC + ABAC Engine (rollen, policies, evaluatie)
|
||||
C30 Observability (Pino structured logging)
|
||||
```
|
||||
|
||||
**Waarom eerst**: Zonder deze vier werkt geen enkele enterprise use case. Retrofit is exponentieel duurder.
|
||||
|
||||
### Fase 1: Intent systeem solide maken (weken 5-6)
|
||||
|
||||
```
|
||||
Week 5: C05 Intent Registry (centraliseer patronen uit reflex-classifier)
|
||||
C06 Reflex refactor (lees uit Registry)
|
||||
C07 Orchestrator refactor (unified pipeline met Classify)
|
||||
|
||||
Week 6: C10 Protocol Engine activeren (nudge.ts aansluiten)
|
||||
C15 Rapportage versioning + soft delete (G6)
|
||||
C33 PII Filter uitbreiden
|
||||
```
|
||||
|
||||
**Na deze fase**: UC-01 t/m UC-20 werken enterprise-grade.
|
||||
|
||||
### Fase 2: Ontbrekende GGZ-modules (weken 7-12)
|
||||
|
||||
```
|
||||
Week 7-8: C18 Behandelplan Service (UC-21)
|
||||
C19 Medicatie Service (UC-22)
|
||||
|
||||
Week 9-10: C22 Toestemming Service (UC-25)
|
||||
C34 Wvggz Service (UC-24)
|
||||
UC-23 Incident/MIC formulier
|
||||
|
||||
Week 11-12: C27 Field Encryption (BSN, diagnoses)
|
||||
C23 Auth uitbreiden (SSO/SAML, MFA)
|
||||
UC-33 Break-the-glass noodtoegang
|
||||
```
|
||||
|
||||
### Fase 3: Knowledge Layer + interoperabiliteit (weken 13-18)
|
||||
|
||||
```
|
||||
Week 13-14: C11 Protocol Rules Store (database)
|
||||
C13 Regelvalidatie UI (admin)
|
||||
|
||||
Week 15-16: C12 RAG Pipeline (pgvector, protocol indexering)
|
||||
C14 Kennisbron Connectors (eerste protocollen inladen)
|
||||
|
||||
Week 17-18: C28 FHIR Export (alle resources)
|
||||
C29 CDS Hooks Service
|
||||
C32 Health Check + C31 Circuit Breaker generaliseren
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Technische Specificaties per Component
|
||||
|
||||
### 7.1 C24 Multi-tenancy — Specificatie
|
||||
|
||||
**Verantwoordelijkheid**: Isoleer data per instelling/tenant.
|
||||
|
||||
**Database wijzigingen**:
|
||||
- `tenant_id UUID NOT NULL` kolom op ELKE tabel met patiëntdata
|
||||
- RLS policy per tabel: `USING (tenant_id = get_current_tenant())`
|
||||
- Helper function: `get_current_tenant()` leest uit `app.current_tenant_id` setting
|
||||
|
||||
**Middleware**:
|
||||
```typescript
|
||||
// Elke request:
|
||||
// 1. Haal user op uit Supabase Auth
|
||||
// 2. Lees tenant_id uit user metadata
|
||||
// 3. Zet als header voor Server Components
|
||||
// 4. Zet als PostgreSQL setting voor RLS
|
||||
```
|
||||
|
||||
**Bestanden**:
|
||||
- `lib/auth/tenant-context.ts` — Helper om tenant te zetten/lezen
|
||||
- `middleware.ts` — Injecteer tenant in elke request
|
||||
- Migratie: `add_tenant_id_to_all_tables.sql`
|
||||
- Migratie: `create_rls_policies.sql`
|
||||
|
||||
**Test**: Maak twee tenants, voeg patiënt toe aan tenant A, verifieer dat tenant B de patiënt NIET kan zien.
|
||||
|
||||
---
|
||||
|
||||
### 7.2 C26 Audit Trail — Specificatie
|
||||
|
||||
**Verantwoordelijkheid**: Onwijzigbare log van alle toegang en wijzigingen aan patiëntdata.
|
||||
|
||||
**Database**:
|
||||
- Tabel `audit_logs` (zie enterprise-epd-architectuur.md §5.2)
|
||||
- Partitionering per maand
|
||||
- Triggers die UPDATE/DELETE blokkeren
|
||||
- Hash chain voor integriteitsverificatie
|
||||
|
||||
**API**:
|
||||
```typescript
|
||||
// lib/audit/logger.ts
|
||||
logAuditEvent({ entityType, entityId, action, purpose, cortexIntent?, metadata? })
|
||||
|
||||
// Automatisch:
|
||||
// - user_id, user_role, user_name uit auth context
|
||||
// - tenant_id uit tenant context
|
||||
// - timestamp server-side
|
||||
// - data_hash berekend
|
||||
// - previous_hash opgehaald
|
||||
```
|
||||
|
||||
**Integratiepunten**: Elke API route roept `logAuditEvent()` aan na succesvolle actie. Dit is een **hard requirement** — geen route zonder audit log.
|
||||
|
||||
**Bestanden**:
|
||||
- `lib/audit/logger.ts` — Core logging functie
|
||||
- `lib/audit/hash.ts` — Hash chain berekening
|
||||
- `app/api/audit/route.ts` — Query endpoint (admin only)
|
||||
- Migratie: `create_audit_logs.sql`
|
||||
|
||||
---
|
||||
|
||||
### 7.3 C25 RBAC + ABAC — Specificatie
|
||||
|
||||
**Verantwoordelijkheid**: Bepaal of een gebruiker een actie mag uitvoeren op een resource.
|
||||
|
||||
**Twee lagen**:
|
||||
1. **RBAC** (snel): Rol → vaste permissions set
|
||||
2. **ABAC** (verfijnd): Context-afhankelijke policies (toewijzing, toestemming, tijdvenster)
|
||||
|
||||
**API**:
|
||||
```typescript
|
||||
// lib/access-control/evaluator.ts
|
||||
const { allowed, reason } = await evaluateAccess({
|
||||
userId, action, resource, resourceId, tenantId
|
||||
});
|
||||
|
||||
if (!allowed) {
|
||||
return Response.json({ error: 'Geen toegang', reason }, { status: 403 });
|
||||
}
|
||||
```
|
||||
|
||||
**Bestanden**:
|
||||
- `lib/access-control/roles.ts` — Rol definities en basis permissions
|
||||
- `lib/access-control/policies.ts` — ABAC policy definities
|
||||
- `lib/access-control/evaluator.ts` — Policy evaluatie engine
|
||||
- Migratie: `create_access_policies.sql`
|
||||
|
||||
---
|
||||
|
||||
### 7.4 C05 Intent Registry — Specificatie
|
||||
|
||||
**Verantwoordelijkheid**: Single source of truth voor alle intent definities.
|
||||
|
||||
**Structuur per intent**:
|
||||
```typescript
|
||||
interface IntentDefinition {
|
||||
id: CortexIntent; // 'dagnotitie', 'zoeken', etc.
|
||||
label: { nl: string; en: string }; // Mensleesbare labels
|
||||
description: string; // Voor LLM context
|
||||
priority: 'P1' | 'P2' | 'P3';
|
||||
|
||||
// Reflex patterns
|
||||
reflexPatterns: Array<{
|
||||
pattern: RegExp;
|
||||
weight: number;
|
||||
extractHints?: string[]; // Welke entities te extracten
|
||||
}>;
|
||||
|
||||
// Orchestrator hints
|
||||
aiExamples: Array<{
|
||||
input: string;
|
||||
expectedIntent: CortexIntent;
|
||||
expectedEntities: Record<string, string>;
|
||||
}>;
|
||||
|
||||
// Entity configuratie
|
||||
entities: {
|
||||
required: string[]; // Welke entities verplicht
|
||||
optional: string[];
|
||||
};
|
||||
|
||||
// Action mapping
|
||||
artifactType: string; // Welk block/formulier openen
|
||||
requiresConfirmation: boolean; // Destructieve actie?
|
||||
|
||||
// Access control
|
||||
allowedRoles?: string[]; // Welke rollen mogen dit intent gebruiken
|
||||
featureFlag?: string; // Feature flag voor geleidelijke uitrol
|
||||
enabled: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
**Opslag**: TypeScript config file (fase 1), migreerbaar naar database (fase 3).
|
||||
|
||||
**Bestanden**:
|
||||
- `lib/cortex/registry/intent-registry.ts` — Registry class
|
||||
- `lib/cortex/registry/definitions/dagnotitie.ts` — Per intent een definitie
|
||||
- `lib/cortex/registry/definitions/zoeken.ts`
|
||||
- `lib/cortex/registry/definitions/index.ts` — Barrel export
|
||||
- `lib/cortex/registry/types.ts` — IntentDefinition interface
|
||||
|
||||
---
|
||||
|
||||
### 7.5 C10 Protocol Engine — Specificatie
|
||||
|
||||
**Verantwoordelijkheid**: Evalueer klinische regels na afgeronde acties. Stel vervolgacties voor.
|
||||
|
||||
**Pure function**: `(completedAction, patientContext, rules) → suggestions[]`
|
||||
|
||||
**Regel evaluatie**:
|
||||
```typescript
|
||||
// lib/cortex/protocol-engine/evaluator.ts
|
||||
|
||||
async function evaluateRules(
|
||||
completedAction: CompletedAction,
|
||||
patientContext: PatientContext,
|
||||
rules: ProtocolRule[]
|
||||
): Promise<NudgeSuggestion[]> {
|
||||
|
||||
const applicableRules = rules.filter(rule =>
|
||||
rule.status === 'actief' &&
|
||||
rule.trigger.afterIntent?.includes(completedAction.intent)
|
||||
);
|
||||
|
||||
const suggestions: NudgeSuggestion[] = [];
|
||||
|
||||
for (const rule of applicableRules) {
|
||||
const conditionMet = await evaluateCondition(rule.condition, patientContext);
|
||||
if (conditionMet) {
|
||||
suggestions.push({
|
||||
ruleId: rule.id,
|
||||
message: rule.suggestion.message,
|
||||
priority: rule.suggestion.priority,
|
||||
evidence: rule.suggestion.evidence,
|
||||
suggestedIntent: rule.suggestion.suggestedIntent,
|
||||
source: rule.source,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return suggestions.sort((a, b) =>
|
||||
a.priority.localeCompare(b.priority) // P1 eerst
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Bestanden**:
|
||||
- `lib/cortex/protocol-engine/evaluator.ts` — Rule evaluatie
|
||||
- `lib/cortex/protocol-engine/conditions.ts` — Conditie evaluatie (static + query)
|
||||
- `lib/cortex/protocol-engine/rules/` — Gevalideerde regels per domein
|
||||
- `app/api/cortex/nudge/route.ts` — API endpoint
|
||||
|
||||
---
|
||||
|
||||
## 8. Validatie Conclusie
|
||||
|
||||
### De architectuur ondersteunt alle use cases MITS:
|
||||
|
||||
1. **De vier horizontale lagen eerst gebouwd worden** (G1-G3 + G14): multi-tenancy, audit, RBAC, logging
|
||||
2. **Het intent systeem gecentraliseerd wordt** (G4): Intent Registry als single source of truth
|
||||
3. **De Protocol Engine aangesloten wordt** (G5): nudge.ts → protocol-engine met rules store
|
||||
4. **Ontbrekende GGZ-modules gebouwd worden** (G8-G12): behandelplan, medicatie, Wvggz, incidenten
|
||||
|
||||
### Wat de architectuur GOED doet:
|
||||
|
||||
- Dual interface (traditioneel + intent) ondersteunt alle use cases via twee paden
|
||||
- De pipeline (Registry → Classify → Resolve → Action → Protocol) is generiek genoeg voor nieuwe intents
|
||||
- Multi-tenancy via RLS is pragmatisch en past bij Supabase
|
||||
- Audit trail als horizontale laag dekt alle use cases zonder per-module implementatie
|
||||
|
||||
### Wat nog aandacht nodig heeft:
|
||||
|
||||
- ~~**Notificatie service** (niet in architectuur): incidenten, Wvggz-termijnen, break-the-glass alerts~~ → **Opgelost: C34** (zie `enterprise-componenten-uitbreiding.md`)
|
||||
- **Groepstherapie** (UC-32): één rapportage voor meerdere patiënten — huidige datamodel is 1:1
|
||||
- ~~**Caching strategie**: AI-samenvattingen zijn duur, caching ontbreekt in architectuur~~ → **Opgelost: C37** (zie `enterprise-componenten-uitbreiding.md`)
|
||||
- **Offline support**: niet besproken, maar relevant voor mobiele zorgverleners
|
||||
|
||||
### Uitbreiding: 10 nieuwe componenten (C34–C43)
|
||||
|
||||
Na de initiële gap analyse zijn 10 aanvullende enterprise componenten geïdentificeerd en gespecificeerd. Deze zijn gedocumenteerd in **`enterprise-componenten-uitbreiding.md`** en omvatten:
|
||||
|
||||
| Component | Laag | Status |
|
||||
|-----------|------|--------|
|
||||
| C34 Notificatie Service | Platform Services | Interface gedefinieerd |
|
||||
| C35 Workflow Engine (State Machine) | Platform Services | Interface + voorbeeldworkflows |
|
||||
| C36 Full-Text Search | Platform Services | Interface + PostgreSQL tsvector schema |
|
||||
| C37 Caching Layer | Platform Services | Interface + TTL strategie |
|
||||
| C38 Scheduled Jobs | Platform Services | Interface + job definities |
|
||||
| C39 Webhook System | Platform Services | Interface + security (HMAC) |
|
||||
| C40 ZPM Facturatie | Externe Integraties | Interface + database schema |
|
||||
| C41 Vecozo Connector | Externe Integraties | Interface + mock (voorbereiding) |
|
||||
| C42 Zorgdomein Connector | Externe Integraties | Interface + mock (voorbereiding) |
|
||||
| C43 BI Module | Analytics | Materialized views gedefinieerd |
|
||||
|
||||
De gap items G19 (notificatie) en G20 (caching) uit §4.3 zijn hiermee opgelost. Zie het uitbreidingsdocument voor volledige interface definities, database schemas en integratiepunten.
|
||||
Reference in New Issue
Block a user