OrgModel Versioning
Concept
Een OrgModel-versie legt een genummerde momentopname vast van alle gebruikersattributen die bij een tenant horen. Per tenant bestaan er op elk moment maximaal twee versies tegelijk:
Actieve versie (
IsActive = true,IsDraft = false) — de snapshot die downstream systemen als bron van waarheid gebruiken.Concept (
IsDraft = true,IsActive = false) — een bewerkbare werkversie waaraan attributen worden toegevoegd, hernoemd of verwijderd.
Wijzigingen worden incrementeel opgeslagen als changerecords in het concept. Zodra het concept wordt geactiveerd, promoot de service het atomisch naar actief: de vorige actieve versie wordt gedeactiveerd, de changerecords worden geconsolideerd tot een volledige snapshot en downstream systemen kunnen de nieuwe versie inlezen.
Er is altijd hooguit één open concept tegelijk. Een tweede CreateDraft-aanroep terwijl er al een concept bestaat, retourneert 409 DraftAlreadyExists.
Lifecycle-toestandsdiagram
Endpoints overzicht
Alle paden zijn relatief aan de basisroute GET /usertypes/org-model/versions. De tenant-ID wordt altijd uit de X-Tenant-Id header gehaald via de MultiTenantService.
Methode | Pad | Beschrijving | Succesrespons |
|---|---|---|---|
|
| Geeft alle attributen van de huidige actieve versie-snapshot terug. |
|
|
| Geeft de openstaande changerecords van het huidige concept terug. |
|
|
| Geeft de changerecords van een specifieke (historische) versie terug. |
|
|
| Evalueert de downstreamimpact van activatie van het huidige concept. |
|
|
| Activeert het huidige concept (hervoert impact; blokkeert bij openstaande issues). |
|
|
| Dient resolutiekeuzes in voor blokkerende impactproblemen. |
|
|
| Reset (gooit weg) het huidige concept. |
|
Draft wijzigingen
Elke mutatie op een attribuut terwijl een concept open is, schrijft een changerecord met een van de volgende typen:
ChangeType | Betekenis |
|---|---|
| Een nieuw attribuut is aangemaakt en wacht op activatie. |
| Een bestaand attribuut is verwijderd uit het model. |
| Een attribuut heeft een nieuwe naam gekregen ( |
GetDraftChangesAsync vs GetVersionChangesAsync
Beide methoden lezen uit dezelfde changerecordstabel maar richten zich op een andere versie:
GetDraftChangesAsync— zoekt eerst het openstaande concept op voor de huidige tenant en leest de changerecords van dat concept. Geeft een lege lijst terug als er geen concept bestaat.GetVersionChangesAsync(versionId)— leest de changerecords van een willekeurige (historische) versie op basis van ID. Geeftnullterug als de versie niet bestaat of niet bij de tenant hoort.
Het DTO dat beide methoden teruggeven is identiek (OrgModelVersionChangeDto):
Actieve attributen
GetActiveAttributesAsync bepaalt welke actieve versie bij de huidige tenant hoort, haalt de bijbehorende versie-snapshot op en geeft alle attributen terug als OrgModelAttributeDto. Als er nog geen actieve versie bestaat, geeft de methode een lege collectie terug — nooit een fout.
Impact evaluatie
EvaluateDraftImpactAsync voert een pipeline uit van alle geregistreerde IOrgModelImpactEvaluator-implementaties. Dit maakt het mogelijk om downstream effecten van attributenwijzigingen te beoordelen voordat activatie plaatsvindt.
Werking
De service haalt het openstaande concept op voor de huidige tenant.
Alle changerecords van het concept worden geladen.
De service laadt de completed resolution keys uit de database: een verzameling sleutels in het formaat
"{IssueCode}:{AffectedEntityId ?? string.Empty}"voor problemen die al succesvol zijn opgelost.Een
OrgModelImpactContext-object wordt aangemaakt met de concept- en changedata plus de completed keys.Elke evaluator roept
EvaluateAsync(context, ct)aan en voegt eventuele bevindingen toe aan de context.Na afloop worden openstaande blokkerende problemen verrijkt met hun ingeleverde resolutierecord (indien aanwezig).
Het eindresultaat is een
DraftImpactResult.
OrgModelImpactContext
Eigenschap | Type | Beschrijving |
|---|---|---|
|
| Tenant waarvoor de evaluatie wordt uitgevoerd. |
|
| Het huidige conceptrecord. |
|
| Alle openstaande changerecords. |
|
| Sleutels van problemen met een |
|
| Problemen die activatie blokkeren (evaluators voegen hier aan toe). |
|
| Informatieve problemen die activatie niet blokkeren. |
|
| Downstream systemen die door activatie worden geraakt. |
Evaluators gebruiken context.IsResolved(code, entityId) om te controleren of een probleem al is opgelost en kunnen het in dat geval overslaan:
OrgModelImpactIssue
Eigenschap | Type | Beschrijving |
|---|---|---|
|
| Machine-leesbare code, bijv. |
|
| Mensleesbare uitleg die in de UI wordt getoond. |
|
| Optioneel ID van het betrokken object (bijv. persona-ID). |
|
| Beschikbare resolutieacties voor dit probleem. |
|
| Ingeleverde resolutie (gevuld door de service, niet door evaluators). |
DraftImpactResult
Eigenschap | Type | Beschrijving |
|---|---|---|
|
|
|
|
| Aantal openstaande changerecords in het concept. |
|
| Problemen die activatie blokkeren. |
|
| Informatieve problemen. |
|
| Betrokken downstream systemen. |
Als er geen concept bestaat, retourneert de methode altijd CanActivate = false met een enkel blokkerend probleem orgmodel.version.no_draft_to_evaluate. Zie OrgModel-Draft-Resolutions.md voor details over hoe resoluties blokkerende problemen onderdrukken.
Activatie guard
ActivateDraftAsync voert de impact-evaluatie altijd opnieuw uit, ook als de aanroeper GET /draft/impact al eerder heeft gebruikt. Dit voorkomt race conditions waarbij de toestand verandert tussen evaluatie en activatie.
Als CanActivate = false, gooit de service een OrgModelDomainException met foutcode orgmodel.version.blocking_issues_not_resolved en HTTP-status 422.
Draft resetten
ResetDraftAsync gooit het huidige concept weg zonder het te activeren:
Controleer of er een open concept bestaat; zo niet, gooi
422 NoDraftToReset.Haal alle attribuut-ID's op van changerecords van het type
Addin dit concept (attributen die nog nooit actief zijn geweest).Verwijder deze attributen soft uit de attributentabel (
SoftDeleteBatchAsync), zodat ze niet als "wees"-records achterblijven.Reset het conceptrecord in de versietabel (
ResetDraftAsyncin de repository): het concept blijft in de database staan voor auditdoeleinden maar is niet langer bewerkbaar.
Na de reset kan een nieuw concept worden aangemaakt via POST /versions/draft.
Foutcodes
Foutcode | HTTP-status | Situatie |
|---|---|---|
| 409 | Er bestaat al een open concept voor deze tenant. |
| 422 | Er is geen open concept om te activeren. |
| 422 | Er is geen open concept om te resetten. |
| n.v.t. | Geen concept aanwezig bij impact-evaluatie (in response-body). |
| 422 | Activatie geblokkeerd omdat er nog blokkerende problemen zijn. |
| 422 | Er is geen open concept waaraan resoluties gekoppeld kunnen worden. |
| 409 | Een attribuut kan niet worden verwijderd omdat het aan een versie gekoppeld is. |
| 422 | Het opgegeven type-ID bestaat niet. |
| 422 | Attribuutnaam is verplicht. |
| 422 | Attribuutnaam overschrijdt de maximumlengte. |
| 422 | Het opgegeven attribuut-ID is ongeldig. |
Nieuwe impact evaluator toevoegen
Een evaluator is een klasse die IOrgModelImpactEvaluator implementeert:
Stap 1: Evaluator implementeren
Stap 2: Registreer in DI
De OrgModelVersionsService ontvangt via constructor-injectie een IEnumerable<IOrgModelImpactEvaluator> en roept elke evaluator aan. Er zijn geen andere wijzigingen nodig.
Gerelateerde pagina's
OrgModel-Draft-Resolutions.md — Hoe resolutiekeuzes worden ingediend, verwerkt als Hangfire-jobs en geblokkeerde activatie deblokkeren.
OrgModel-Portal-UI.md — Paginabeheer, paginavergrendeling (SignalR), attribuutbeheer en conceptbeheer in de ManagementPortal.