Files
triqura-ecd/docs/datamodel/diagrammen/model-behandelplan-erd.html
colinislit 0db3ec2ce1 docs(datamodel): Mermaid ER-diagrammen voor alle actuele deelmodellen
Voegt docs/datamodel/diagrammen/ toe: één self-contained HTML per
deelmodel (instroom, aanmelding, behandelplan, diagnose,
intake-behandeladvies, rapportage, screening, wachtlijst), elk met een
Mermaid erDiagram, blueprint-vormgeving en sleep/scroll pan-zoom
(mermaid.js + svg-pan-zoom via CDN, geen serverside build nodig).

Per diagram alleen sleutel-/FK-attributen en de kernrelaties uit de §2/§3
entiteiten-/cardinaliteitensecties van het bijbehorende deelmodel, niet elk
veld — bedoeld als navigeerbaar overzicht naast de tabelvorm, niet als
vervanging ervan.

Scope-keuzes:
- model-intake.md en datamodel-discovery.md zijn overgeslagen: eerstgenoemde
  is volledig vervangen door model-intake-behandeladvies.md, laatstgenoemde
  is een prosedocument zonder entiteitenstructuur.
- model-aanmelding.md toont alleen de nog geldige PERSOON/CLIENT-kern;
  AANMELDING/VERWIJZING/ZORGEPISODE zijn vervangen door model-instroom.md
  en daar al gediagrammeerd.
- model-screening.md krijgt een expliciete waarschuwing in titel en
  bronregel: het losse screeningsbesluit is achterhaald door besluit B21
  (screeningsbesluit = acceptatiebesluit, nu care_acceptance_decision in
  model-instroom.md).
- model-behandelplan.md, model-rapportage.md en model-wachtlijst.md tonen
  een statusnotitie (in herziening resp. deels herzien resp. voorlopig
  onderzoeksmodel) conform hun documentstatus.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 08:01:38 +02:00

337 lines
9.4 KiB
HTML

<!doctype html>
<html lang="nl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Behandelplan — entiteit-relatiediagram</title>
<style>
:root {
--bg: #F5FAF9;
--surface: #FFFFFF;
--surface-2: #EAF3F1;
--border: #CFE1DE;
--text: #12211F;
--text-muted: #4C6B66;
--accent: #0F766E;
--font-sans: -apple-system, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
--font-mono: ui-monospace, "SFMono-Regular", "Cascadia Code", "Roboto Mono", Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0A1615;
--surface: #10201E;
--surface-2: #15302C;
--border: #1F3A36;
--text: #E6F5F2;
--text-muted: #8FB6B0;
--accent: #34D6C4;
}
}
* { box-sizing: border-box; }
html, body {
margin: 0;
height: 100%;
overscroll-behavior: none;
}
body {
background: var(--bg);
color: var(--text);
font-family: var(--font-sans);
}
.app {
display: flex;
flex-direction: column;
height: 100vh;
}
/* Toolbar */
.toolbar {
flex: 0 0 auto;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 10px 16px;
background: var(--surface);
border-bottom: 1px solid var(--border);
}
.title-group {
display: flex;
align-items: baseline;
gap: 10px;
min-width: 0;
}
.title-group h1 {
font-size: 0.95rem;
margin: 0;
font-weight: 700;
white-space: nowrap;
}
.title-group .source {
font-family: var(--font-mono);
font-size: 11px;
color: var(--text-muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.controls {
display: flex;
gap: 6px;
flex: 0 0 auto;
}
.controls button {
width: 32px;
height: 32px;
border-radius: 6px;
border: 1px solid var(--border);
background: var(--surface-2);
color: var(--text);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
padding: 0;
}
.controls button:hover { border-color: var(--accent); color: var(--accent); }
.controls button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: no-preference) {
.controls button { transition: border-color 120ms, color 120ms; }
}
/* Diagram canvas */
.canvas-wrap {
flex: 1 1 auto;
position: relative;
overflow: hidden;
background:
repeating-linear-gradient(0deg, rgba(87,216,198,0.07) 0 1px, transparent 1px 28px),
repeating-linear-gradient(90deg, rgba(87,216,198,0.07) 0 1px, transparent 1px 28px),
#08211D;
}
.canvas-wrap .hint {
position: absolute;
left: 16px;
bottom: 14px;
font-family: var(--font-mono);
font-size: 11px;
color: #6FBFB2;
z-index: 2;
pointer-events: none;
}
#diagram {
width: 100%;
height: 100%;
}
#diagram svg {
width: 100%;
height: 100%;
display: block;
}
.loading {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
color: #6FBFB2;
font-family: var(--font-mono);
font-size: 13px;
}
</style>
</head>
<body>
<div class="app">
<div class="toolbar">
<div class="title-group">
<h1>Behandelplan — entiteit-relatiediagram</h1>
<span class="source">model-behandelplan.md §2 · 12 entiteiten · 20 relaties · in structurele herziening — zie besluitenlog §5 B11 (één levend behandelplan met formele snapshots i.p.v. losse versie-records)</span>
</div>
<div class="controls">
<button id="zoom-out" title="Uitzoomen" aria-label="Uitzoomen">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><line x1="3" y1="8" x2="13" y2="8" stroke="currentColor" stroke-width="2"/></svg>
</button>
<button id="zoom-in" title="Inzoomen" aria-label="Inzoomen">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><line x1="8" y1="3" x2="8" y2="13" stroke="currentColor" stroke-width="2"/><line x1="3" y1="8" x2="13" y2="8" stroke="currentColor" stroke-width="2"/></svg>
</button>
<button id="zoom-fit" title="Passend maken" aria-label="Passend maken">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M2 6V2h4M14 6V2h-4M2 10v4h4M14 10v4h-4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<button id="zoom-reset" title="Reset (100%)" aria-label="Reset naar 100%">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M8 2a6 6 0 1 1-4.24 1.76" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
<path d="M2 2v3h3" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
</div>
<div class="canvas-wrap">
<div class="loading" id="loading">Diagram wordt geladen…</div>
<div id="diagram" class="mermaid">
erDiagram
ZORGEPISODE {
uuid id PK
}
DIAGNOSE {
uuid id PK
}
INTAKE {
uuid id PK
}
MEDEWERKER {
uuid id PK
}
PERSOON {
uuid id PK
}
BEHANDELPLAN {
uuid id PK
uuid zorgepisode_id FK
uuid vervangt_plan_id FK
uuid gebaseerd_op_intake_id FK
uuid opgesteld_door FK
uuid regiebehandelaar_id FK
uuid vastgesteld_door FK
integer versienummer
string status
date vastgesteld_op
}
BEHANDELPLAN_DIAGNOSE {
uuid behandelplan_id FK
uuid diagnose_id FK
}
BEHANDELDOEL {
uuid id PK
uuid behandelplan_id FK
uuid diagnose_id FK
uuid overgenomen_van_doel_id FK
string omschrijving
string prioriteit
string status
}
INTERVENTIE {
uuid id PK
uuid behandelplan_id FK
uuid uitvoerder_id FK
string interventietype
string extern_systeem
string extern_kenmerk
}
INTERVENTIE_DOEL {
uuid interventie_id FK
uuid behandeldoel_id FK
}
EVALUATIEMOMENT {
uuid id PK
uuid behandelplan_id FK
uuid uitgevoerd_door FK
string evaluatietype
date gepland_op
string uitkomst
}
BEHANDELPLAN_AKKOORD {
uuid id PK
uuid behandelplan_id FK
uuid gegeven_door_persoon_id FK
uuid vastgelegd_door FK
date datum
string wijze
string gegeven_door_type
}
ZORGEPISODE ||--o{ BEHANDELPLAN : "zorgepisode_id"
BEHANDELPLAN |o--o| BEHANDELPLAN : "vervangt_plan_id (self)"
INTAKE |o--o{ BEHANDELPLAN : "gebaseerd_op_intake_id (0..1)"
BEHANDELPLAN ||--o{ BEHANDELPLAN_DIAGNOSE : "diagnoses"
DIAGNOSE ||--o{ BEHANDELPLAN_DIAGNOSE : "plannen"
BEHANDELPLAN ||--o{ BEHANDELDOEL : "doelen"
DIAGNOSE |o--o{ BEHANDELDOEL : "diagnose_id (optioneel)"
BEHANDELDOEL |o--o{ BEHANDELDOEL : "overgenomen_van_doel_id (self)"
BEHANDELPLAN ||--o{ INTERVENTIE : "interventies"
INTERVENTIE ||--o{ INTERVENTIE_DOEL : "doelkoppelingen"
BEHANDELDOEL ||--o{ INTERVENTIE_DOEL : "interventiekoppelingen"
BEHANDELPLAN ||--o{ EVALUATIEMOMENT : "evaluatiemomenten"
BEHANDELPLAN ||--o{ BEHANDELPLAN_AKKOORD : "akkoorden"
MEDEWERKER ||--o{ BEHANDELPLAN : "opgesteld_door"
MEDEWERKER |o--o{ BEHANDELPLAN : "regiebehandelaar_id"
MEDEWERKER |o--o{ BEHANDELPLAN : "vastgesteld_door"
MEDEWERKER |o--o{ INTERVENTIE : "uitvoerder_id"
MEDEWERKER |o--o{ EVALUATIEMOMENT : "uitgevoerd_door"
MEDEWERKER ||--o{ BEHANDELPLAN_AKKOORD : "vastgelegd_door"
PERSOON |o--o{ BEHANDELPLAN_AKKOORD : "gegeven_door_persoon_id"
</div>
<div class="hint">sleep om te pannen · scroll om te zoomen</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/svg-pan-zoom@3.6.1/dist/svg-pan-zoom.min.js"></script>
<script>
mermaid.initialize({
startOnLoad: false,
theme: "base",
themeVariables: {
background: "#08211D",
primaryColor: "#0E2E29",
primaryBorderColor: "#57D8C6",
primaryTextColor: "#EAFBF7",
lineColor: "#57D8C6",
textColor: "#EAFBF7",
tertiaryColor: "#123B35",
attributeBackgroundColorOdd: "#0E2E29",
attributeBackgroundColorEven: "#123B35",
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
fontSize: "13px"
}
});
(async () => {
await mermaid.run({ querySelector: "#diagram" });
document.getElementById("loading").remove();
const svgEl = document.querySelector("#diagram svg");
svgEl.removeAttribute("style");
const panZoom = svgPanZoom(svgEl, {
panEnabled: true,
zoomEnabled: true,
controlIconsEnabled: false,
fit: true,
center: true,
minZoom: 0.15,
maxZoom: 8,
zoomScaleSensitivity: 0.35
});
document.getElementById("zoom-in").addEventListener("click", () => panZoom.zoomIn());
document.getElementById("zoom-out").addEventListener("click", () => panZoom.zoomOut());
document.getElementById("zoom-fit").addEventListener("click", () => { panZoom.fit(); panZoom.center(); });
document.getElementById("zoom-reset").addEventListener("click", () => { panZoom.reset(); });
window.addEventListener("resize", () => { panZoom.resize(); panZoom.fit(); panZoom.center(); });
})();
</script>
</body>
</html>