diff --git a/docs/datamodel/datamodel-discovery.md b/docs/datamodel/datamodel-discovery.md new file mode 100644 index 0000000..0009113 --- /dev/null +++ b/docs/datamodel/datamodel-discovery.md @@ -0,0 +1,136 @@ +# Datamodel Discovery — ECD + +**Status:** verkenning, geen ontwerp +**Datum:** 16 juli 2026 +**Werkwijze:** FCO-IM-geïnspireerd (feitzinnen eerst), visualisaties in HTML op verzoek +**Kader:** ECD bevat ECD-data (proces-state blijft in TIP) · FHIR is niet heilig · huidig prototype-schema is géén vertrekpunt + +--- + +## 1. Waarom deze discovery + +Het prototype-datamodel is de bron van vrijwel alle gevonden gebreken: labels vs. codes, twee modules op één tabel, schema niet reproduceerbaar, regels die alleen in de UI leven. We bouwen het ECD opnieuw op een eigen model. Dit document verkent de uitgangspunten en de werkvorm — er wordt nog niets gebouwd. + +## 2. Methode: feiten eerst (FCO-IM) + +We modelleren niet met tabellen als startpunt, maar met **feitzinnen in natuurlijke taal**, uitgesproken door de domeinexpert (Colin). Uit die zinnen leiden we elementaire feiten af, en dááruit het model. Dit is de kern van FCO-IM: het model legt de *communicatie* over het domein vast, en daarmee blijft de betekenis (semantiek) bewaard — leesbaar voor behandelaar én ontwikkelaar. Vanuit een elementair feitenmodel zijn ER-diagrammen, relationele schema's en zelfs graph-modellen af te leiden. + +**Werkvorm per flow:** +1. Claude stelt een startlijst feitzinnen op vanuit de bestaande schermen en use-cases +2. Colin corrigeert, schrapt en vult aan ("zo zeggen wij dat niet", "dit feit ontbreekt") +3. Samen benoemen we per feit: uniciteit (kan dit feit maar één keer waar zijn?), verplichtheid, wie het feit mag vastleggen/wijzigen +4. Claude leidt er de entiteitenkaart uit af (HTML-visualisatie) → review → pas daarna SQL + +## 3. Uitgangspunten voor het datamodel + +### 3.1 Harde spelregels +1. **Waardelijsten op één plek** — types, statussen, afdelingen als data (referentietabellen), UI en database delen dezelfde bron. Directe les uit de kapotte intake-tabs. +2. **Herkomst (provenance) op elk klinisch record** — auteur (mens/AI), bij AI: model + bronverwijzingen; content-hash zodat gewijzigde tekst automatisch her-embedding triggert. +3. **Append-only audit** — geen UPDATE/DELETE op audit; hash-chaining (elk event hasht het vorige) maakt manipulatie detecteerbaar; NEN 7510: 5 jaar bewaren. +4. **Soft delete overal** — `deleted_at`, nooit hard delete; definitieve verwijdering na wettelijke termijn via batchjob. +5. **Stabiele UUID's** — één identiteit per record; vector-hits en (later) graph-nodes wijzen altijd terug naar hetzelfde PostgreSQL-record. +6. **BSN: opslaan, maar afgeschermd** — zorgaanbieders zijn wettelijk verplicht het BSN te gebruiken (Wabvpz: declaraties, Vecozo, verwijzingen), dus het ECD slaat het op — versleuteld in de database, toegang op need-to-know, elke inzage gelogd. De echte regel: het BSN komt **nooit** in AI-prompts, embeddings, logs of events richting TIP. (Wijkt bewust af van het architectuurdocument v0.1 — "alleen bsn_hash" past bij een AI-laag boven een bestaand EPD, niet bij een zelfstandig ECD; correctie meenemen in v0.2.) +7. **Regels in het model, niet alleen in de UI** — "max één hoofddiagnose per traject" is een database-constraint. +8. **Reproduceerbaar schema** — alles in migrations vanaf een verse baseline; de `conditions`-tabel-zonder-migration mag nooit meer gebeuren. +9. **Statusmachines expliciet** — per entiteit: welke statussen, welke overgangen, wie mag ze zetten. In een referentietabel of check-constraint, niet impliciet in schermcode. + +### 3.2 AI-voorbereiding (vector + graph) +- **Tekst en structuur in hetzelfde record** — elk verslag heeft gestructureerde velden (voor regels/filters) én vrije tekst (voor embeddings). +- **pgvector vanaf dag één** — extensie in dezelfde PostgreSQL; embeddings in een aparte tabel (`record_id`, `chunk_index`, `embedding`, `model`, `content_hash`) zodat her-embedden en modelwissel geen schemawijziging zijn. Productie-les uit het veld: event-driven her-embedding (trigger bij mutatie) boven periodieke batch. +- **Neo4j: ontwerpen, niet aanzetten** — de graph-vragen (ZPM: diagnose → prestatiecode → bevoegdheid) komen uit dezelfde bron-records; zolang ID's stabiel zijn kan de graaf later zonder migratie worden opgebouwd. + +### 3.3 Grensvlak met TIP +- ECD = klinische feiten (bron van waarheid voor het dossier). TIP = proces-state en beslislogica. +- Per entiteit leggen we in de discovery een kolom **eigenaarschap** vast: leidend in ECD, en welke gebeurtenissen als event naar TIP gaan. + +**Afstemming Joshua (17 juli 2026):** +1. **TIP-eigen beslis-state** (workspaces, intents, taken) heeft geen ECD-tegenhanger — per definitie geen dubbeling. Brondata hoort bij de bron; het ECD is leidend. +2. **Auditkopie**: TIP maakt een snapshot van de data waarop een intentie/nudge/actie is gebaseerd — doelgebonden, met herkomst erop. Zonder snapshot is niet herleidbaar waarop een besluit rustte; dit is juist het onderscheidend vermogen. +3. **Longitudinale IE's**: voor trendmeting houdt TIP relevante informatie-elementen door de tijd vast. Bewuste, minimale dubbeling — TIP slaat alleen de IE's op die nodig zijn om tot intenties/nudges/acties te komen. +4. **Koppelafspraak nodig**: hoe valt een wijziging in het ECD (correctie, soft delete) door naar TIP zodat de kopie niet veroudert? Het ECD-model levert hiervoor de bouwstenen die er al in zitten: stabiele UUID's, content-hash per record en mutatie-events (zelfde mechanisme als event-driven her-embedding, §3.2). + +Kortom: wel een bewuste, minimale, herleidbare kopie waar nodig; geen schaduwadministratie. + +## 4. Context: standaarden en koppelvlakken (geen datamodel-regels) + +Het datamodel ontwerpen we volledig op eigen termen, vanuit de feitzinnen. FHIR, zibs en openEHR zijn koppelvlak- en uitwisselingszaken; uitwisseling loopt via onze eigen API's. Deze learnings zijn relevant als achtergrond, maar stellen geen eisen aan het model: + +- **FHIR**: puur uitwisselformaat. Komt alleen ooit terug in een adapter of export (deployment model B richting bestaande EPD's). +- **zibs (Nictiz)**: semantische definities van klinische begrippen. Bruikbaar als gratis checklist per entiteit ("welke velden hoort een verwijzing te hebben?", Wvggz-registratie-eisen) — het model blijft van ons. +- **openEHR**: nemen we niet over; alleen de ontwerples "stabiele kern als schema, veranderlijke inhoud als data" — die al in het Triqura-architectuurdocument stond (ADR-03). +- **Aandachtspunt** (geen regel): drijf semantisch niet nodeloos af van wat de Nederlandse zorg onder een begrip verstaat — dat houdt een eventuele adapter later goedkoop. + +## 5. Scope ronde 1: instroomflow + +### 5.0 Besluiten basis (sessie 16 juli, Colin) + +1. **Terminologie: "cliënt"** — overal, ook in tabelnamen. (Prototype mixte patients/cliënten.) +2. **Persoon ≠ patiënt-zijn**: één CLIËNT-record per persoon; zorg is episodisch via AANMELDING (1 cliënt → meerdere aanmeldingen door de tijd). +3. **Verwijzer is een eigen begrip** met type uit een waardelijst: huisarts, medisch specialist, GGZ-instelling, bedrijfsarts, gemeente, zelfaanmelding, crisis. Routes niet hardcoden. +4. **Wettelijk kader hoort bij de aanmelding** (Zvw, Jeugdwet, Wmo, Wlz, forensisch) — bepaalt ook de financierings-/declaratiekant. Jeugd loopt onder de huidige wetgeving indirect via de gemeente. +5. **Parallelle aanmeldingen**: nog geen besluit. Structuur ondersteunt meerdere; "max één actief" wordt een aan/uit-zetbare bedrijfsregel, geen schemabeperking. + +### 5.1 Feitzinnen basis (herzien na besluiten) + +1. *Persoon Jan de Vries is geboren op 12-03-1988.* +2. *Jan de Vries is sinds 14 juli 2026 cliënt bij de instelling, onder cliëntnummer 427.* +3. *Jan de Vries heeft zich op 14 juli 2026 aangemeld bij de instelling.* +4. *Verwijzer P. Pietersen is van het type huisarts.* +5. *Verwijzer P. Pietersen is verbonden aan praktijk/instelling "Huisartsenpraktijk De Vries & Pietersen".* +6. *Praktijk/instelling "Huisartsenpraktijk De Vries & Pietersen" heeft AGB-code 12345678.* +7. *Verwijzer P. Pietersen heeft zelf ook AGB-code 87654321 (persoonlijk, naast de praktijk-AGB).* +8. *De aanmelding van 14 juli 2026 is ontvangen via verwijzer P. Pietersen.* +9. *De aanmelding van 14 juli 2026 valt onder wettelijk kader Zvw.* +10. *De aanmelding van 14 juli 2026 heeft als hulpvraag "somberheidsklachten, slaapproblemen".* +11. *De aanmelding van 14 juli 2026 heeft status "nieuw".* +12. *Bij de aanmelding van 14 juli 2026 is verwijsdocument document-812 (type: verwijsbrief) ontvangen.* +13. *Cliënt Jan de Vries heeft toegang tot het cliëntportaal.* + +**Besluiten (sessie 17 juli 2026, Colin):** +1. **PERSOON en CLIENT gesplitst.** PERSOON draagt de identiteit (naam, geboortedatum, BSN) en blijft bestaan onafhankelijk van zorg. CLIENT is een rol/koppeltabel op PERSOON (cliëntnummer, cliënt-sinds-datum), niet meer één platte entiteit. Reden: dezelfde persoon kan later ook een andere rol hebben (contactpersoon, wettelijk vertegenwoordiger van iemand anders' dossier, medewerker) zonder een dubbel persoonsrecord. Dit verfijnt besluit 5.0.2 ("persoon ≠ patiënt-zijn") — die tekst benoemde het onderscheid al, maar modelleerde nog één CLIENT-record; nu krijgt PERSOON zijn eigen entiteit. + - **BSN is optioneel op PERSOON.** Niet elke persoon heeft een BSN nodig in het systeem — een medewerker is ook een persoon. De verplichting hoort bij de rol: voor de cliëntrol is het BSN nodig (Wabvpz: declaraties, Vecozo, verwijzingen — zie spelregel 3.1 #6), voor andere rollen niet. Of dat een nudge wordt ("cliënt zonder BSN") of een rolgebonden eis, bepalen we bij de rollenronde. +2. **VERWIJZER en PRAKTIJK_INSTELLING zijn twee losse entiteiten** — een verwijzer kan zonder praktijk bestaan (bijv. gemeente-ambtenaar), een praktijk kan meerdere verwijzers hebben. +3. **AGB-verplichting hangt aan verwijzertype**, niet hardcoded per type in de applicatie: waardelijst `verwijzertype` krijgt attribuut `agb_verplicht (ja/nee)`. Huisarts/medisch specialist → ja, gemeente → nee. Zowel verwijzer als praktijk/instelling kunnen een eigen AGB-code hebben. +4. **Geen AGB-validatie tegen Vecozo nu** — vrije invoer, validatie tegen een echte AGB-tabel parkeren we tot de declaratie-ronde. +5. **Aanmelding-status is flexibel** — geen eenrichtingsflow, een besloten aanmelding kan terug naar "in screening" bij heropening. Basisstatussen: `nieuw → in screening → besloten`. Uitkomst bij `besloten`: `intake` / `afgewezen` / `doorverwezen` / `wachtlijst`. +6. **Wie de status mag zetten blijft open** — rollen/disciplines zijn nog niet gemodelleerd; komt terug in die ronde. +7. **Verwijsbrief blijft een nudge, geen harde schema-eis.** Ontbrekende verwijzing wordt een protocolregel (Nudge Engine), met severity die kan verschillen per financieringtype/regelgeving (bijv. `blokkade` bij Zvw-huisartsroute, `signaal` bij Wmo/Jeugdwet). Een beschikking telt ook als verwijzing: waardelijst `verwijsdocument_type` (verwijsbrief, beschikking, ...) i.p.v. één vast veld. +8. **Cliëntportaaltoegang als losse entiteit `CLIENTPORTAAL_ACCOUNT`**, 1-op-0..1 op CLIENT (niet elke cliënt heeft portaaltoegang; een persoon zonder cliëntrol kan sowieso geen portaalaccount hebben). Authenticatiedetails (e-mail, provider-koppeling, status uitgenodigd/actief/geblokkeerd) werken we pas uit in de auth/ADM-ronde — hier alleen de relatie vastgelegd zodat de entiteitenkaart klopt. + +**Open idee, nog geen besluit:** mogelijk krijgt ook een verwijzer toegang tot de status van zijn verwijzingen (verwijzersportaal, analoog aan `CLIENTPORTAAL_ACCOUNT` maar dan op VERWIJZER). Nog niet uitgewerkt en niet in de entiteitenkaart opgenomen — apart onderwerp voor een volgende ronde als dit een echte behoefte blijkt. + +Aanmelding → screening → intake. Dit is de eerste rebuild-module én de TIP-proefflow. Latere rondes: diagnose & behandeltraject, agenda, rapportage & overdracht. + +### 5.2 Feitzinnen screening & intake (volgende ronde — nog te bespreken) + +1. *Voor de aanmelding van Jan de Vries is op 15 juli 2026 een screening gestart.* +2. *Screeningsactiviteit "telefonisch contact" is op 16 juli 2026 uitgevoerd door verpleegkundige K. Jansen.* +3. *Het screeningsbesluit voor de aanmelding van Jan de Vries luidt "geschikt voor afdeling Volwassenen".* +4. *Voor cliënt Jan de Vries is op 20 juli 2026 een intake gestart op afdeling Volwassenen.* +5. *De intake van Jan de Vries heeft status "bezig".* +6. *Het intakegesprek van 22 juli 2026 is gevoerd door psycholoog M. de Boer.* +7. *De kindcheck voor de intake van Jan de Vries is uitgevoerd met uitkomst "geen minderjarige kinderen".* +8. *Verslag X is op 22 juli 2026 geschreven door M. de Boer.* / *Verslag Y is gegenereerd door AI-model Z op basis van bronnen A en B, en bevestigd door M. de Boer.* + +Vragen voor die ronde: +- Is een screening verplicht vóór elke intake, of kan die worden overgeslagen (bijv. bij crisis)? +- Wat maakt een intake "afgerond" — en wie mag dat besluiten? +- Welke afdelingen bestaan er echt (screening bood er 5, intake accepteerde er 3)? + +## 6. Vervolg + +| Stap | Wat | Wie | +|---|---|---| +| 1 | Feitzinnen instroom corrigeren en aanvullen | Colin | +| 2 | Entiteitenkaart instroom (HTML-visualisatie) | Claude | +| 3 | Statussen + eigenaarschap (ECD/TIP) per entiteit | samen | +| 4 | Zelfde cyclus voor diagnose/traject, agenda, rapportage | samen | +| 5 | Pas daarna: schema-baseline (migrations) + `lib/dat/` | Claude | + +## Bronnen + +- [FCO-IM (Wikipedia)](https://en.wikipedia.org/wiki/FCO-IM) · [CaseTalk — About FCO-IM](https://www.casetalk.com/articles/introduction) · [Zwart e.a., Fact Oriented Modeling with FCO-IM](https://www.goodreads.com/book/show/27818248-fact-oriented-modeling-with-fco-im) +- [Nictiz — Zorginformatiebouwstenen (zibs)](https://www.nictiz.nl/wat-we-doen/activiteiten/zibs/) · [Registratie aan de bron — zibs](https://www.registratieaandebron.nl/zorginformatiebouwstenen) +- [openEHR — Design Principles](https://specifications.openehr.org/releases/1.0.1/html/architecture/overview/Output/design_principles.html) · [Archetype relational mapping (PMC)](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4636072/) +- [dbi services — Embedding versioning met pgvector / event-driven her-embedding](https://www.dbi-services.com/blog/rag-series-embedding-versioning-with-pgvector-why-event-driven-architecture-is-a-precondition-to-ai-data-workflows/) · [pgvector RAG op managed PostgreSQL (2026)](https://danubedata.ro/blog/pgvector-rag-managed-postgres-2026) +- [Append-only audit trails — designgurus](https://www.designgurus.io/answers/detail/how-do-you-enforce-immutability-and-appendonly-audit-trails) · [EHR audit trail — compliance & best practices](https://www.accountablehq.com/post/ehr-audit-trail-explained-what-it-is-compliance-requirements-and-best-practices) diff --git a/docs/datamodel/entiteitenkaart-instroom.html b/docs/datamodel/entiteitenkaart-instroom.html new file mode 100644 index 0000000..0a4ed41 --- /dev/null +++ b/docs/datamodel/entiteitenkaart-instroom.html @@ -0,0 +1,477 @@ + + +
+ + ECD · datamodel discovery +

Entiteitenkaart — instroomflow

+

+ Afgeleid uit de feitzinnen in datamodel-discovery.md §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. +

+ +
+

Diagram

+

Rechthoeken met een sleutel (PK) zijn entiteiten met een eigen identiteit; entiteiten met alleen een code-sleutel zijn waardelijsten (referentiedata, geen eigen levenscyclus).

+
+
+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
+    }
+
+
+

+ Niet in het diagram, maar op elke entiteit hierboven van toepassing (spelregels §3.1): id (uuid), + created_at/updated_at, deleted_at (soft delete), en een append-only + audit-event per mutatie. Weggelaten voor leesbaarheid, niet omdat ze niet gelden. +

+
+ +
+

Waardelijsten

+

De daadwerkelijke waarden per referentietabel, zodat je kunt controleren of de lijst klopt en compleet is.

+
+ +
+

VERWIJZERTYPE

+ + + + + + + + + + + +
CodeAGB verplicht
huisartsja
medisch_specialistte bevestigen
ggz_instellingte bevestigen
bedrijfsartste bevestigen
gemeentenee
zelfaanmeldingnee
crisiste bevestigen
+
+ +
+

WETTELIJK_KADER

+ + + + + + + + + +
Code
zvw
jeugdwet
wmo
wlz
forensisch
+
+ +
+

AANMELDING_STATUS

+ + + + + + + +
Code
nieuw
in_screening
besloten
+

+ Overgangen zijn vrij — een besloten aanmelding kan terug naar in_screening bij heropening. Geen eenrichtingsflow. +

+
+ +
+

AANMELDING_UITKOMST

+ + + + + + + + +
Code
intake
afgewezen
doorverwezen
wachtlijst
+

+ Alleen gezet zodra status = besloten. +

+
+ +
+

VERWIJSDOCUMENT_TYPE

+ + + + + + +
Code
verwijsbrief
beschikking
+

+ Lijst waarschijnlijk niet compleet — open voor aanvulling. +

+
+ +
+
+ +
+

Openstaand / geparkeerd

+
    +
  1. + AGB-validatie tegen een echte Vecozo-tabel — nu vrije invoer, geen validatie. +
    Geparkeerd tot de declaratie-ronde.
    +
  2. +
  3. + Wie mag de aanmelding-status zetten — nog geen rollen/disciplines gemodelleerd. +
    Komt terug zodra die ronde wordt gedaan.
    +
  4. +
  5. + AGB-verplichting per verwijzertype — alleen huisarts (ja) en gemeente (nee) zijn expliciet besproken; de overige vier staan als "te bevestigen" in de tabel hierboven. +
  6. +
  7. + Verwijsbrief/beschikking is een nudge, geen schema-constraint — leeft in de Protocol Rules Registry (Nudge Engine), niet zichtbaar als FK-verplichting in dit diagram. +
  8. +
  9. + CLIENTPORTAAL_ACCOUNT is nog een lege huls — alleen de relatie (1-op-0..1 op CLIENT) staat vast. +
    Authenticatiedetails (e-mail, provider-koppeling, status) volgen in de auth/ADM-ronde.
    +
  10. +
  11. + Verwijzersportaal — nog geen besluit, alleen een idee. Mogelijk krijgt een verwijzer ook toegang tot de status van zijn verwijzingen, analoog aan CLIENTPORTAAL_ACCOUNT. +
    Niet in dit diagram opgenomen — apart onderwerp voor een volgende ronde als het een echte behoefte blijkt.
    +
  12. +
  13. + BSN is optioneel op PERSOON — een medewerker is ook een persoon en heeft geen BSN in het systeem nodig. De verplichting hoort bij de rol (voor cliënten: Wabvpz). +
    Nudge ("cliënt zonder BSN") of rolgebonden eis — te bepalen in de rollenronde.
    +
  14. +
+
+ + + +