- datamodel-discovery.md: FCO-IM-werkwijze, spelregels, feitzinnen §5.1 afgerond met besluiten 17 juli (persoon/cliënt-splitsing, verwijzer + praktijk als eigen entiteiten, AGB per verwijzertype, flexibele statussen, verwijsbrief als nudge, cliëntportaal-account, BSN optioneel op persoon) - entiteitenkaart-instroom.html: ER-diagram + waardelijsten instroomflow, gepubliceerd als artifact ter review Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
478 lines
13 KiB
HTML
478 lines
13 KiB
HTML
<style>
|
|
:root {
|
|
--bg: #F5F7F6;
|
|
--surface: #FFFFFF;
|
|
--text: #172420;
|
|
--muted: #5B6D68;
|
|
--line: #DCE3E0;
|
|
--accent: #0F766E;
|
|
--accent-strong: #0B5C56;
|
|
--accent-soft: #E1F0EE;
|
|
--warn: #B45309;
|
|
--warn-soft: #FCEEDC;
|
|
--warn-line: #F0D3A8;
|
|
}
|
|
@media (prefers-color-scheme: dark) {
|
|
:root {
|
|
--bg: #0D1512;
|
|
--surface: #12201C;
|
|
--text: #E6EEEB;
|
|
--muted: #96A9A4;
|
|
--line: #223330;
|
|
--accent: #35D6C4;
|
|
--accent-strong: #6EE7D9;
|
|
--accent-soft: #163430;
|
|
--warn: #F0A94E;
|
|
--warn-soft: #2A1F10;
|
|
--warn-line: #4A3419;
|
|
}
|
|
}
|
|
:root[data-theme="dark"] {
|
|
--bg: #0D1512;
|
|
--surface: #12201C;
|
|
--text: #E6EEEB;
|
|
--muted: #96A9A4;
|
|
--line: #223330;
|
|
--accent: #35D6C4;
|
|
--accent-strong: #6EE7D9;
|
|
--accent-soft: #163430;
|
|
--warn: #F0A94E;
|
|
--warn-soft: #2A1F10;
|
|
--warn-line: #4A3419;
|
|
}
|
|
:root[data-theme="light"] {
|
|
--bg: #F5F7F6;
|
|
--surface: #FFFFFF;
|
|
--text: #172420;
|
|
--muted: #5B6D68;
|
|
--line: #DCE3E0;
|
|
--accent: #0F766E;
|
|
--accent-strong: #0B5C56;
|
|
--accent-soft: #E1F0EE;
|
|
--warn: #B45309;
|
|
--warn-soft: #FCEEDC;
|
|
--warn-line: #F0D3A8;
|
|
}
|
|
|
|
* { box-sizing: border-box; }
|
|
|
|
body {
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
}
|
|
|
|
.page {
|
|
max-width: 900px;
|
|
margin: 0 auto;
|
|
padding: 3rem 1.5rem 5rem;
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
line-height: 1.55;
|
|
}
|
|
|
|
.eyebrow {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.4em;
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
font-size: 0.72rem;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
color: var(--accent-strong);
|
|
background: var(--accent-soft);
|
|
border-radius: 999px;
|
|
padding: 0.3em 0.8em;
|
|
margin-bottom: 1.1rem;
|
|
}
|
|
|
|
h1 {
|
|
font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, serif;
|
|
font-size: clamp(1.7rem, 3.2vw, 2.3rem);
|
|
font-weight: 600;
|
|
line-height: 1.2;
|
|
text-wrap: balance;
|
|
margin: 0 0 0.4rem;
|
|
}
|
|
|
|
.subtitle {
|
|
color: var(--muted);
|
|
font-size: 1.02rem;
|
|
max-width: 62ch;
|
|
margin: 0 0 2.6rem;
|
|
}
|
|
|
|
h2 {
|
|
font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, serif;
|
|
font-size: 1.28rem;
|
|
font-weight: 600;
|
|
margin: 0 0 0.9rem;
|
|
padding-top: 0.2rem;
|
|
}
|
|
|
|
h3 {
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
font-size: 0.86rem;
|
|
letter-spacing: 0.02em;
|
|
color: var(--accent-strong);
|
|
margin: 0 0 0.6rem;
|
|
}
|
|
|
|
section {
|
|
margin-bottom: 3rem;
|
|
}
|
|
|
|
section > p {
|
|
color: var(--muted);
|
|
max-width: 68ch;
|
|
margin: 0 0 1.2rem;
|
|
}
|
|
|
|
.panel {
|
|
background: var(--surface);
|
|
border: 1px solid var(--line);
|
|
border-radius: 10px;
|
|
padding: 1.4rem;
|
|
}
|
|
|
|
.diagram-panel {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.diagram-panel pre.mermaid {
|
|
margin: 0;
|
|
min-width: 640px;
|
|
}
|
|
|
|
.legend-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 1.4rem;
|
|
margin-top: 1.1rem;
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
font-size: 0.78rem;
|
|
color: var(--muted);
|
|
}
|
|
|
|
.legend-row span {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.45em;
|
|
}
|
|
|
|
.legend-swatch {
|
|
width: 0.85em;
|
|
height: 0.85em;
|
|
border-radius: 3px;
|
|
border: 1px solid var(--line);
|
|
}
|
|
|
|
.waardelijsten-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 1.2rem;
|
|
}
|
|
|
|
@media (max-width: 620px) {
|
|
.waardelijsten-grid { grid-template-columns: 1fr; }
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 0.88rem;
|
|
}
|
|
|
|
caption {
|
|
caption-side: top;
|
|
text-align: left;
|
|
margin-bottom: 0.1rem;
|
|
}
|
|
|
|
th, td {
|
|
text-align: left;
|
|
padding: 0.45rem 0.5rem;
|
|
border-bottom: 1px solid var(--line);
|
|
vertical-align: top;
|
|
}
|
|
|
|
th {
|
|
font-weight: 600;
|
|
color: var(--muted);
|
|
font-size: 0.74rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
}
|
|
|
|
td.code {
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
font-size: 0.82rem;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.tag {
|
|
display: inline-block;
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
font-size: 0.72rem;
|
|
padding: 0.1em 0.5em;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
.tag-ja { background: var(--accent-soft); color: var(--accent-strong); }
|
|
.tag-nee { background: var(--line); color: var(--muted); }
|
|
.tag-tbc { background: var(--warn-soft); color: var(--warn); }
|
|
|
|
.callout {
|
|
background: var(--warn-soft);
|
|
border: 1px solid var(--warn-line);
|
|
border-radius: 10px;
|
|
padding: 1.3rem 1.4rem;
|
|
}
|
|
|
|
.callout h2 { color: var(--warn); margin-bottom: 0.8rem; }
|
|
|
|
.callout ol {
|
|
margin: 0;
|
|
padding-left: 1.2rem;
|
|
color: var(--text);
|
|
}
|
|
|
|
.callout li { margin-bottom: 0.7rem; }
|
|
.callout li:last-child { margin-bottom: 0; }
|
|
.callout li b { font-weight: 600; }
|
|
.callout li .why { color: var(--muted); font-size: 0.92rem; }
|
|
|
|
.baseline-note {
|
|
font-size: 0.86rem;
|
|
color: var(--muted);
|
|
border-top: 1px dashed var(--line);
|
|
margin-top: 1.2rem;
|
|
padding-top: 1rem;
|
|
}
|
|
|
|
footer {
|
|
border-top: 1px solid var(--line);
|
|
padding-top: 1.5rem;
|
|
color: var(--muted);
|
|
font-size: 0.88rem;
|
|
}
|
|
|
|
footer a { color: var(--accent-strong); }
|
|
</style>
|
|
|
|
<div class="page">
|
|
|
|
<span class="eyebrow">ECD · datamodel discovery</span>
|
|
<h1>Entiteitenkaart — instroomflow</h1>
|
|
<p class="subtitle">
|
|
Afgeleid uit de feitzinnen in <code>datamodel-discovery.md</code> §5.1. Persoon, cliëntrol, aanmelding,
|
|
verwijzer en de bijbehorende waardelijsten. Status: concept, ter review — vóór dit naar SQL gaat, checkt
|
|
Colin de entiteiten, kardinaliteiten en waardelijst-waarden.
|
|
</p>
|
|
|
|
<section>
|
|
<h2>Diagram</h2>
|
|
<p>Rechthoeken met een sleutel (<code>PK</code>) zijn entiteiten met een eigen identiteit; entiteiten met alleen een <code>code</code>-sleutel zijn waardelijsten (referentiedata, geen eigen levenscyclus).</p>
|
|
<div class="panel diagram-panel">
|
|
<pre class="mermaid">
|
|
erDiagram
|
|
PERSOON ||--o| CLIENT : "is cliënt sinds"
|
|
CLIENT ||--o{ AANMELDING : "meldt zich aan"
|
|
CLIENT ||--o| CLIENTPORTAAL_ACCOUNT : "heeft toegang via"
|
|
AANMELDING }o--|| WETTELIJK_KADER : "valt onder"
|
|
AANMELDING }o--|| AANMELDING_STATUS : "heeft"
|
|
AANMELDING }o--o| AANMELDING_UITKOMST : "heeft, bij besloten"
|
|
AANMELDING }o--o| VERWIJZER : "komt binnen via"
|
|
AANMELDING ||--o{ VERWIJSDOCUMENT : "ontvangt"
|
|
VERWIJSDOCUMENT }o--|| VERWIJSDOCUMENT_TYPE : "is van type"
|
|
VERWIJZER }o--|| VERWIJZERTYPE : "is van type"
|
|
VERWIJZER }o--o| PRAKTIJK_INSTELLING : "verbonden aan"
|
|
|
|
PERSOON {
|
|
uuid id PK
|
|
string naam
|
|
date geboortedatum
|
|
string bsn_encrypted "optioneel"
|
|
}
|
|
CLIENT {
|
|
uuid id PK
|
|
uuid persoon_id FK
|
|
string clientnummer UK
|
|
date sinds
|
|
}
|
|
CLIENTPORTAAL_ACCOUNT {
|
|
uuid id PK
|
|
uuid client_id FK
|
|
string status
|
|
}
|
|
AANMELDING {
|
|
uuid id PK
|
|
uuid client_id FK
|
|
date datum
|
|
string hulpvraag
|
|
}
|
|
VERWIJZER {
|
|
uuid id PK
|
|
string naam
|
|
string agb_code
|
|
}
|
|
PRAKTIJK_INSTELLING {
|
|
uuid id PK
|
|
string naam
|
|
string agb_code
|
|
}
|
|
VERWIJSDOCUMENT {
|
|
uuid id PK
|
|
uuid aanmelding_id FK
|
|
date ontvangen_datum
|
|
}
|
|
VERWIJZERTYPE {
|
|
string code PK
|
|
string label
|
|
boolean agb_verplicht
|
|
}
|
|
WETTELIJK_KADER {
|
|
string code PK
|
|
string label
|
|
}
|
|
AANMELDING_STATUS {
|
|
string code PK
|
|
string label
|
|
}
|
|
AANMELDING_UITKOMST {
|
|
string code PK
|
|
string label
|
|
}
|
|
VERWIJSDOCUMENT_TYPE {
|
|
string code PK
|
|
string label
|
|
}
|
|
</pre>
|
|
</div>
|
|
<p class="baseline-note">
|
|
Niet in het diagram, maar op elke entiteit hierboven van toepassing (spelregels §3.1): <code>id</code> (uuid),
|
|
<code>created_at</code>/<code>updated_at</code>, <code>deleted_at</code> (soft delete), en een append-only
|
|
audit-event per mutatie. Weggelaten voor leesbaarheid, niet omdat ze niet gelden.
|
|
</p>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Waardelijsten</h2>
|
|
<p>De daadwerkelijke waarden per referentietabel, zodat je kunt controleren of de lijst klopt en compleet is.</p>
|
|
<div class="waardelijsten-grid">
|
|
|
|
<div class="panel">
|
|
<h3>VERWIJZERTYPE</h3>
|
|
<table>
|
|
<thead><tr><th>Code</th><th>AGB verplicht</th></tr></thead>
|
|
<tbody>
|
|
<tr><td class="code">huisarts</td><td><span class="tag tag-ja">ja</span></td></tr>
|
|
<tr><td class="code">medisch_specialist</td><td><span class="tag tag-tbc">te bevestigen</span></td></tr>
|
|
<tr><td class="code">ggz_instelling</td><td><span class="tag tag-tbc">te bevestigen</span></td></tr>
|
|
<tr><td class="code">bedrijfsarts</td><td><span class="tag tag-tbc">te bevestigen</span></td></tr>
|
|
<tr><td class="code">gemeente</td><td><span class="tag tag-nee">nee</span></td></tr>
|
|
<tr><td class="code">zelfaanmelding</td><td><span class="tag tag-nee">nee</span></td></tr>
|
|
<tr><td class="code">crisis</td><td><span class="tag tag-tbc">te bevestigen</span></td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<h3>WETTELIJK_KADER</h3>
|
|
<table>
|
|
<thead><tr><th>Code</th></tr></thead>
|
|
<tbody>
|
|
<tr><td class="code">zvw</td></tr>
|
|
<tr><td class="code">jeugdwet</td></tr>
|
|
<tr><td class="code">wmo</td></tr>
|
|
<tr><td class="code">wlz</td></tr>
|
|
<tr><td class="code">forensisch</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<h3>AANMELDING_STATUS</h3>
|
|
<table>
|
|
<thead><tr><th>Code</th></tr></thead>
|
|
<tbody>
|
|
<tr><td class="code">nieuw</td></tr>
|
|
<tr><td class="code">in_screening</td></tr>
|
|
<tr><td class="code">besloten</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<p class="baseline-note" style="margin-top: 0.9rem; padding-top: 0.7rem;">
|
|
Overgangen zijn vrij — een <code>besloten</code> aanmelding kan terug naar <code>in_screening</code> bij heropening. Geen eenrichtingsflow.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<h3>AANMELDING_UITKOMST</h3>
|
|
<table>
|
|
<thead><tr><th>Code</th></tr></thead>
|
|
<tbody>
|
|
<tr><td class="code">intake</td></tr>
|
|
<tr><td class="code">afgewezen</td></tr>
|
|
<tr><td class="code">doorverwezen</td></tr>
|
|
<tr><td class="code">wachtlijst</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<p class="baseline-note" style="margin-top: 0.9rem; padding-top: 0.7rem;">
|
|
Alleen gezet zodra status = <code>besloten</code>.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<h3>VERWIJSDOCUMENT_TYPE</h3>
|
|
<table>
|
|
<thead><tr><th>Code</th></tr></thead>
|
|
<tbody>
|
|
<tr><td class="code">verwijsbrief</td></tr>
|
|
<tr><td class="code">beschikking</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<p class="baseline-note" style="margin-top: 0.9rem; padding-top: 0.7rem;">
|
|
Lijst waarschijnlijk niet compleet — open voor aanvulling.
|
|
</p>
|
|
</div>
|
|
|
|
</div>
|
|
</section>
|
|
|
|
<section class="callout">
|
|
<h2>Openstaand / geparkeerd</h2>
|
|
<ol>
|
|
<li>
|
|
<b>AGB-validatie tegen een echte Vecozo-tabel</b> — nu vrije invoer, geen validatie.
|
|
<div class="why">Geparkeerd tot de declaratie-ronde.</div>
|
|
</li>
|
|
<li>
|
|
<b>Wie mag de aanmelding-status zetten</b> — nog geen rollen/disciplines gemodelleerd.
|
|
<div class="why">Komt terug zodra die ronde wordt gedaan.</div>
|
|
</li>
|
|
<li>
|
|
<b>AGB-verplichting per verwijzertype</b> — alleen huisarts (ja) en gemeente (nee) zijn expliciet besproken; de overige vier staan als "te bevestigen" in de tabel hierboven.
|
|
</li>
|
|
<li>
|
|
<b>Verwijsbrief/beschikking is een nudge, geen schema-constraint</b> — leeft in de Protocol Rules Registry (Nudge Engine), niet zichtbaar als FK-verplichting in dit diagram.
|
|
</li>
|
|
<li>
|
|
<b>CLIENTPORTAAL_ACCOUNT is nog een lege huls</b> — alleen de relatie (1-op-0..1 op CLIENT) staat vast.
|
|
<div class="why">Authenticatiedetails (e-mail, provider-koppeling, status) volgen in de auth/ADM-ronde.</div>
|
|
</li>
|
|
<li>
|
|
<b>Verwijzersportaal — nog geen besluit, alleen een idee.</b> Mogelijk krijgt een verwijzer ook toegang tot de status van zijn verwijzingen, analoog aan <code>CLIENTPORTAAL_ACCOUNT</code>.
|
|
<div class="why">Niet in dit diagram opgenomen — apart onderwerp voor een volgende ronde als het een echte behoefte blijkt.</div>
|
|
</li>
|
|
<li>
|
|
<b>BSN is optioneel op PERSOON</b> — een medewerker is ook een persoon en heeft geen BSN in het systeem nodig. De verplichting hoort bij de rol (voor cliënten: Wabvpz).
|
|
<div class="why">Nudge ("cliënt zonder BSN") of rolgebonden eis — te bepalen in de rollenronde.</div>
|
|
</li>
|
|
</ol>
|
|
</section>
|
|
|
|
<footer>
|
|
Bron: <code>docs/datamodel/datamodel-discovery.md</code> §5.1 · volgende stap (§6): dit diagram reviewen,
|
|
daarna statussen + eigenaarschap ECD/TIP vastleggen, vervolgens dezelfde cyclus voor screening & intake (§5.2).
|
|
</footer>
|
|
|
|
</div>
|