Gå til innhold

Domenemodell⚓︎

Tre views av samme modell, alle avgrenset til Enova.Kai.Domain pluss de to policyene i Enova.Kai.Application som bærer ekte domeneregler. Ingen infrastruktur, ingen hosts — det bildet ligger i Runtime-arkitektur.

Språket er hentet fra CONTEXT.md og ADR-015: domenebegreper på norsk med æøå, teknisk stillas på engelsk.

Aggregater og verdiobjekter⚓︎

Åpne i fullskjerm

Tre ting er verdt å merke seg:

  • Bare Sak, Regel og Regelresultat er aggregatrøtter — de arver Aggregate<TId>. Beslutning, Stadiegjennomgang, RegelGjennomgang, Arbeidsmarkering, ErsStatus, Søknadskostnad, VirkemiddelMasterdata og Vurdering er vanlige entiteter uten egen rot.
  • Invariantene er ujevnt fordelt. Regelresultat.Create() avviser et resultat uten regelutfall og krever facts-hash, schema- og engine-versjon. Sak har ingen invarianter: FraReplika/OppdaterFraReplika kopierer felter, og OppdaterProjeksjon setter de utledede kolonnene.
  • Domain events driver sak-projeksjonen. SakStatusEndret, RegelresultatOpprettet, BeslutningRegistrert og StadiegjennomgangEndret arver DomainEvent, reises med Aggregate.Raise() og plukkes opp av DomainEventDispatchingInterceptor ved SaveChanges. Håndtererne i Enova.Kai.Application/Cases/Projection/ skriver de utledede kolonnene på Sak, slik at GET /cases slipper å regne dem ut per kall — se ADR-021.

Hvem eier hvilke begreper⚓︎

Åpne i fullskjerm

Skillet som forklarer mest i modellen er hva Kai eier og hva Kai bare låner:

  • Sak, ErsStatus, Vurdering, VirkemiddelMasterdata og Søknadskostnad er ERS sine begreper. Kai holder en replika, leser den fra Mimir gold, og skriver aldri tilbake. Det er grunnen til at Sak er en ren projeksjon uten oppførsel.
  • Regelresultat, Beslutning, gjennomgang-entitetene og regel-/workflow-config finnes ikke oppstrøms. De oppstår i Kai og har ingen annen kilde.
  • Alle gold-kall går gjennom kilde-adaptere som oversetter gold-skjema til domenetyper, slik at kolonnenavn fra gold ikke lekker inn i modellen. Se Kildesystemer.

Fra sak i gold til beslutning⚓︎

Åpne i fullskjerm

Hvert steg i Kai-lanen er en egen TickerQ-jobb i kai-worker. Saksbehandleren er eneste kilde til beslutning; alt annet i historien er systemgenerert.

To ting historien ikke viser

  • Dokumenter som gir opp. Et dokument som feiler permanent etter retries blir ikke stille borte — det varsles på regelresultatet. Steget er utelatt fordi en egen avviks-lane gjorde diagrammet for høyt for å være lesbart på én skjerm.
  • Ny kjøring etter beslutning. En Beslutning overstyrer ett regelutfall, og resultatet regnes på nytt. Sløyfen tilbake til regelkjøringen er utelatt fordi en backward edge tvang ruter på kryss av lanene.

Slik oppdaterer du diagrammene⚓︎

Alle tre genereres fra typede specs i docs/sourcefiles/arkitektur/ — ikke rediger HTML-filene direkte.

Diagram Spec Type
Aggregater kai-domenemodell.arch.json architecture
Eierskap kai-kontekstkart.arch.json architecture
Historie kai-domenehistorie.workflow.json workflow
Bash
node .claude/skills/archify/bin/archify.mjs deliver architecture docs/sourcefiles/arkitektur/kai-domenemodell.arch.json docs/publisert/arkitektur/diagrammer/kai-domenemodell.html --quality showcase

Merk at architecture- og workflow-typene ikke har egne node-typer for aggregat, entitet eller verdiobjekt. Taksonomien ligger i meta.legend-etiketter og per-node tag, altså en konvensjon — ikke noe skjemaet håndhever. Endrer du hva en form betyr, må legenden endres i samme slengen.