288 lines
18 KiB
HTML
288 lines
18 KiB
HTML
<!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>
|