OrgModel Draft Resoluties
Waarom resoluties?
De impact-evaluatie kan blokkerende problemen vinden — situaties waarbij het activeren van een concept ongewenste bijwerkingen heeft op downstream systemen. Een voorbeeld: een persona-filter verwijst naar een attribuut dat in het concept wordt hernoemd of verwijderd. Zonder tussenkomst zou activatie die filter ongeldig maken.
In plaats van activatie hard te blokkeren tot een beheerder handmatig ingrijpt, biedt het resolutiemechanisme een begeleide keuzeflow: de evaluator beschrijft welke acties beschikbaar zijn om het probleem op te lossen, de gebruiker kiest een actie, en de API voert die actie asynchroon uit als een Hangfire-job. Zodra een resolutie de status Completed bereikt, onderdrukt de impact-evaluatie het bijbehorende probleem en is CanActivate niet langer geblokkeerd door dat specifieke probleem.
Volledige flow
Resolutie statussen
Status | Betekenis voor activatie |
|---|---|
| Job is ingepland maar nog niet gestart. Het bijbehorende probleem blokkeert activatie nog. |
| Job is gestart door een Hangfire-worker. Blokkeert activatie nog. |
| Handler heeft de actie succesvol uitgevoerd. De evaluator slaat dit probleem voortaan over. |
| Handler heeft een fout gegooid na alle retries. Blokkeert activatie. Zie het |
Alleen Completed onderdrukt een blokkerend probleem. Een Failed resolutie kan opnieuw worden ingediend via POST /draft/resolutions; dit overschrijft het vorige record en plant een nieuwe job in.
OrgModelDraftResolutionRecord
Dit is het database-entiteitsmodel voor een resolutierecord (OrgModel_DraftResolutions):
Kolom | Type | Nullable | Beschrijving |
|---|---|---|---|
|
| Nee | Primaire sleutel. Nieuw GUID bij aanmaak; behouden bij upsert. |
|
| Nee | Verwijst naar het concept waarop de resolutie van toepassing is. |
|
| Nee | Tenant waarvoor de resolutie geldt. |
|
| Nee | Machine-leesbare probleemcode, bijv. |
|
| Ja | ID van het betrokken object (bijv. persona-ID). |
|
| Nee | Gekozen actietype, bijv. |
|
| Ja | JSON-string met actie-specifieke parameters, opgeslagen als vrije tekst. |
|
| Nee | Huidige status: |
|
| Ja | ID van de ingeplande Hangfire-job. Ingevuld na enqueue. |
|
| Nee | Tijdstip van indiening (UTC). |
|
| Ja | Tijdstip waarop de job is voltooid of mislukt (UTC). |
|
| Ja | Foutmelding bij |
OrgModelResolutionJob
OrgModelResolutionJob is de Hangfire-job die een ingediende resolutie uitvoert. De klasse is gedecoreerd met [AutomaticRetry(Attempts = 3, OnAttemptsExceeded = AttemptsExceededAction.Fail)], wat betekent dat Hangfire de job automatisch tot drie keer opnieuw probeert bij een fout.
Stappenplan
Record ophalen — de job laadt het
OrgModelDraftResolutionRecordop basis van het meegegevenresolutionId. Als het record ontbreekt, gooit de job eenInvalidOperationException(Hangfire zal ook dit als een mislukte poging tellen en opnieuw proberen).Status naar
Processing— het record wordt bijgewerkt zodat de UI de voortgang kan tonen.Handler opzoeken — alle geregistreerde
IOrgModelResolutionHandler-implementaties worden doorzocht opActionType == resolution.ChosenActionType. Als er geen handler is gevonden, gooit de job eenInvalidOperationException.Handler aanroepen —
handler.ExecuteAsync(resolution, ct)voert de feitelijke resolutielogica uit.Status naar
Completed— bij succes wordt het record bijgewerkt metExecutedAt = DateTime.UtcNow.Foutafhandeling — bij een uitzondering wordt het record bijgewerkt met
Status = Faileden de foutmelding inError, waarna de uitzondering opnieuw wordt gegooid. Hangfire ziet de re-throw en plant de volgende retry in.
De displaynaam "OrgModel Draft Resolution [{0}]" maakt jobs goed herkenbaar in het Hangfire-dashboard.
IOrgModelResolutionHandler
Elke resolutieactie wordt uitgevoerd door een implementatie van IOrgModelResolutionHandler:
Handlers worden via DI geregistreerd. OrgModelResolutionJob zoekt at runtime de juiste handler op via ActionType. Er is geen centrale registratie van actietypen nodig.
Nieuwe resolution handler implementeren
Stap 1: Handler-klasse aanmaken
Stap 2: Registreer in DI
Er zijn verder geen wijzigingen nodig. De job vindt de handler automatisch op basis van ActionType.
Resolutie-bewuste impact context
OrgModelImpactContext bevat de property CompletedResolutionKeys — een IReadOnlySet<string> met sleutels in het formaat "{IssueCode}:{AffectedEntityId ?? string.Empty}". Evaluators gebruiken de helpermethode IsResolved om te bepalen of een probleem al is afgehandeld:
Een evaluator past dit als volgt toe:
De service laadt de completed keys via IOrgModelDraftResolutionsRepository.GetCompletedResolutionKeysAsync en vult de context voor de evaluatorpipeline wordt gestart.
POST /draft/resolutions endpoint
Request
Het veld actionPayload is een vrije JSON-structuur. De inhoud wordt als raw JSON-string opgeslagen en later doorgegeven aan de handler. De handler is verantwoordelijk voor deserialisatie.
Response
Upsert-gedrag
Het endpoint werkt met een upsert op de sleutel (DraftVersionId, IssueCode, AffectedEntityId). Als een resolutie opnieuw wordt ingediend voor hetzelfde probleem:
Het bestaande record wordt bijgewerkt met de nieuwe
ChosenActionTypeenActionPayload.De status wordt teruggezet naar
Pending.HangfireJobIdenExecutedAtworden gewist.Een nieuwe Hangfire-job wordt ingepland.
Dit maakt het mogelijk om een Failed resolutie te corrigeren door dezelfde of een andere actie opnieuw in te dienen.
Database tabel
De tabel OrgModel_DraftResolutions wordt aangemaakt via FluentMigrator-migratie 069:
Kolom | SQL-type | Nullable | Constraint |
|---|---|---|---|
|
| Nee |
|
|
| Nee | |
|
| Nee | |
|
| Nee | |
|
| Ja | |
|
| Nee | |
|
| Ja | |
|
| Nee | Default: |
|
| Ja | |
|
| Nee | |
|
| Ja | |
|
| Ja |
Upsert-sleutel: (DraftVersionId, IssueCode, AffectedEntityId) — de MERGE-query gebruikt deze drie kolommen om te bepalen of een record wordt aangemaakt of bijgewerkt.
Index: IX_odr_DraftVersionId_IssueCode op (DraftVersionId ASC, IssueCode ASC, AffectedEntityId ASC) versnelt de lookups door de resolutiepipeline.
Foutcodes
Foutcode | HTTP-status | Situatie |
|---|---|---|
| 422 | Er is geen open concept om resoluties aan te koppelen. |
| 422 | Activatie geblokkeerd; er zijn nog blokkerende problemen zonder |
Observeerbaarheid
Hangfire-dashboard
Elke resolutie-job is zichtbaar in het Hangfire-dashboard onder de displaynaam "OrgModel Draft Resolution [{resolutionId}]". Vanuit het dashboard zijn de volgende zaken te inzien:
De huidige status van de job (
Enqueued,Processing,Succeeded,Failed).Het aantal uitgevoerde pogingen en de volgende geplande retry.
De volledige stack trace bij een mislukte poging.
Databasekolom Error
Bij een mislukte resolutie slaat de job de uitzonderingsboodschap op in de kolom Error van OrgModel_DraftResolutions. Dit maakt directe diagnose mogelijk zonder het Hangfire-dashboard te raadplegen:
Gerelateerde pagina's
OrgModel-Versioning.md — Versielifecycle, impact-evaluatie en activatielogica in detail.