8. Tvärgående koncept
8.1 Domänmodell#
Kärnan i domänen följer TestVioras informationsmodell (Figur 4 i uppsatsen). Den använder de 24 begreppen i verksamhetsmodellen (ADR 0009). Den är utbyggd för GVR, ListOn, kontroll och flera regioner. Klassdiagrammen visar varje del. ER-diagrammen visar hur delarna lagras per schema. Tabellen visar vem som äger varje mängd data och om den har personuppgifter. Den visar också hur skyddad den är, var den lagras och om den ska sparas eller gallras (tas bort efter en tid).
| Informationsmängd (TestViora) | Ägare | Personuppgifter | Klassning | Schema | Bevarande |
|---|---|---|---|---|---|
| 1 Överenskommelser | Avtalsansvarig på HSF | Nej | Intern | overenskommelse |
Bevaras |
| 2 Vårdhändelser | HSF | Känsliga | Skyddad | vardhandelser, vantande |
Gallras enligt dokumenthanteringsplanen |
| 3 Listning | HSF | Ja | Skyddad | listning |
Gallras enligt dokumenthanteringsplanen |
| 4 Kodverk och masterdata | Systemförvaltningen | Nej | Öppen | kodverk, masterdata |
Bevaras |
| 5 Ersättningsregelverk | Controller på HSF | Nej | Intern | regelverk |
Bevaras |
| 6 Ersättningsunderlag | Controller på HSF | Nej (pseudonym) | Intern | berakning, granskning |
Bevaras |
| 7 Kvalitetsdata och ansökningar | Controller på HSF | Nej | Intern | malrelaterad |
Bevaras |
| 8 Fakturaunderlag och utbetalningar | Ekonomifunktionen | Nej | Intern | fakturering |
Gallras efter 10 år (bokföringslagen) |
| 9 Avstämningsinformation | HSF | Känsliga (via vårdhändelsenummer) | Skyddad | avstamning |
Gallras enligt dokumenthanteringsplanen |
| 10 Loggar | Systemförvaltningen | Ja | Skyddad | drift |
Gallras enligt dokumenthanteringsplanen |
Överenskommelse, vårdgivare och vårdenhet#
Huvudman (tenant, den region som äger datat) har överenskommelser genom en Bestallarnamnd. Overenskommelse är abstrakt. Den är antingen ett Avtal (avtalsnummer, vårdval, LfU-avtalsområde, lagrum LOV/LOU) eller ett Uppdrag (beslutsreferens, egen regi). Den gäller en Vardgivare (organisationsnummer, driftform) med Vardenheter. Den har ett Vardutbud och använder en eller flera Ersattningsgrunder. Typen är en av Kapitering, Uppdrag, Produktion och Målrelaterad, med legacyModellnummer mot ERSMO. Huvudman, vårdgivare och vårdenhet är typer av NIM:s Organisation.
Id-modell (ADR 0011, kontroll 3 Ä5). Ersvias egna id ändras aldrig och är primärnycklar: vg- (vårdgivare), ve- (vårdenhet), ok- (överenskommelse), eg- (ersättningsgrund), bn- (beställarnämnd) och fm- (fakturamottagare). HSA-id och Avtalat uppdrags-id (NVID) är de viktigaste externa id. De lagras som alias med versioner och två tidsaxlar (bitemporalt) i masterdata.alias_version. Där finns också vårdgivarnummer och kombika. Kombika används bara för kompatibilitetsfasaden och historiken, och den ska bort. GET /vardenheter/sok-alias slår upp ett internt id från ett alias, så som det var vid en viss tid (as-of). HSA-id valideras mot ^SE[0-9]{10}-[A-Za-z0-9]{1,24}$. Fakturamottagare tas fram ur län, basområde och hemvist.
Vårdhändelse#
Vardhandelse (termbankens vårdkontakt, TestVioras Rapport om utförd vård) är abstrakt med underklasserna Besok, Inskrivning/Vardtillfalle, Aktivitet, Vardperiod och Kontakt. Varje ändring blir en ny VardhandelseVersion. Patienten refereras med Patientreferens (personnummer, samordningsnummer eller reservnummer), som utanför patientdatazonen bara är en Pseudonym.
Listning#
Regelverk#
Beräkning och ersättningsrad#
Berakningskorning har ett Manifest och ett Underlagssnapshot och producerar EkonomiskErsattning per vårdgivare, period och ersättningsslag, uppdelad i Ersattningsrader med Traceposter. Justeringar är egna rader. Differensunderlag refererar den ursprungliga körningen.
Fakturering och utbetalning#
Mål och vite#
Kontroll och ärende#
Databasscheman#
Varje modul har ett eget schema med egen historik för migreringar. Den har också tabellerna outbox och dokument. Data med versioner lagras i en tabell per bitemporal entitetstyp (<entitet>_version). Tabellen har giltig daterange, registrerad tstzrange, data jsonb och en hashkedja per nyckel. SchemaSql.BitemporalTabell skapar den (ADR 0011). Alla tabeller har huvudman och säkerhet på radnivå. Diagrammet e04 visar de byggda schemana med det allmänna mönstret (F2–F5). Vårdhändelser (F4) har i stället en egen tabell med partitioner, för att klara volymen (e01, ADR 0012). e01 visar det som är byggt i patientdatazonen, och e02 visar regelverk och identitet. e05 visar beräkning, simulering, FUMS/FUL, kompatibilitet och rapportering (F6 och F9a). e03 visar malrelaterad och granskning (F7) och uppfoljning, migrering och drift (F10). Fakturering och avstämning (F8) finns också i e03.
8.2 Bitemporal versionering och manifest#
Vad som versioneras: allt som påverkar ett belopp. Det omfattar ersättningsmodeller och regler, parametertabeller (ACG, CNI, DRG-viktlista och poängpris, utomlänsprislista, taxekoder, glesbygdszoner, prisbasbelopp, LPIK), överenskommelser, kodverk, masterdata (vårdenheter, kombika och HSA-giltighet), faktureringskalendrar och källdokumenten själva med SHA-256 (ADR 0004).
Två tidsaxlar:
| Axel | Fält i koden | Kolumn | Betydelse |
|---|---|---|---|
| Giltighetstid (valid time) | Giltighet.GiltigFran, Giltighet.GiltigTill (halvöppet, null = tills vidare) |
giltig |
När versionen gäller i verksamheten |
| Registreringstid (transaction time) | Bitemporal<T>.RegistreradTid, Bitemporal<T>.ErsattTid |
registrerad |
När Ersvia kände till versionen |
Bitemporal<T>.GallerAsOf(giltigVid, kandVid) svarar på frågan för en version, och BitemporalHistorik<T> garanterar att högst en version gäller för varje par (giltigVid, kandVid). GiltighetsAnalys hittar luckor och överlapp. IBitemporalLager<T> har två implementationer med samma semantik: in-memory (InMemoryBitemporalLager) och PostgreSQL (PostgresBitemporalLager, EF Core med NpgsqlRange och rådgivande lås per nyckel). Samma FsCheck-modell körs mot båda. I PostgreSQL förhindrar en exclusion constraint (EXCLUDE USING gist (huvudman WITH =, nyckel WITH =, giltig WITH &&) WHERE (upper_inf(registrerad)), btree_gist) överlappande giltighet bland aktuella versioner, och triggern skydda_version gör raderna oföränderliga: bara ersattTid får sättas, en gång, och DELETE är förbjudet (ADR 0011).
Känd svaghet (kontroll 3 R1): en rättelse som bara täcker en del av en tidigare giltighet kräver att den gamla versionen stängs i transaktionstid och att resterna läggs in på nytt, och ersattTid omfattas inte av hashkedjan. Åtgärd: rättelsen görs som en enda operation i lagret (Minus på Giltighet), och stängningen kedjas som en egen händelse.
Prestanda (kontroll 3 R2): manifestet kompileras vid körningens start till en oföränderlig ögonblicksbild i minnet. Motorn läser aldrig bitemporala tabeller per vårdhändelse.
Regler:
- En publicerad version ändras aldrig. En ändring skapar en ny version.
- Ett fel rättas med en ny version med samma giltighet och senare registreringstid. Den gamla får
ErsattTidoch finns kvar. - Versionerna kedjas med hash (
Hashkedja<T>). - Varje version har beslutsreferens, källdokument med hash, skapare och godkännare, status och ändringsbeskrivning med diff.
Portalens sida Vad gällde när? (F11a) visar samma fråga för användare, med tidslinje per ersättningsgrund:
Exempel (kapitering 75+ och 85+):
| Version | Värde | Giltighet | Registrerad | Ersatt |
|---|---|---|---|---|
| A | 75+ 1 535 kr/år | [2025-01-01, 2026-03-01) | 2024-12 | |
| B | 75+ 2 100 kr/år | [2026-03-01, tills vidare) | 2026-02 | |
| C | 85+ 3 100 kr/år | [2026-07-01, tills vidare) | 2026-06 | |
| D (rättelse) | retroaktiv rättelse efter nämndbeslut | samma som rättad version | 2026-08-20 | ersätter tidigare version från 2026-08-20 |
- "Vad gällde för vård utförd 2026-05-15?" →
giltigVid=2026-05-15,kandVid=nu→ version B (eller D efter rättelsen). - "Vad trodde vi gällde för maj när vi räknade 2026-06-03?" →
giltigVid=2026-05-15,kandVid=2026-06-03→ version B. - Majkörningen 2026-06-03 reproduceras exakt ur sitt manifest. Omräkningen 2026-08-25 får ett nytt manifest och ett differensunderlag.
Manifest (ADR 0005): Manifest.Skapa(motorversion, underlagSnapshot, poster) sorterar posterna ordinalt på nyckel och beräknar SHA-256 över kanonisk JSON (KanoniskJson: sorterade nycklar, inga blanksteg, normaliserade tal). Hashen är oberoende av i vilken ordning posterna lades till. Manifest.Id = mf- + de första 16 hexadecimala tecknen och följer med varje ersättningsrad, fakturaunderlag och avstämningsrad. Nycklarna i Beräkningens manifest (F6) är regel/{ersattningsgrund}/{giltigFrån}, parametertabell/{id}, masterdata/vardgivare/{id}, masterdata/vardenhet/{id}, kodverk/{kodverk}, overenskommelse/{id}, konfiguration/berakning, underlag/vardhandelser/{period}, underlag/listning/…, underlag/fums/{period}, underlag/ful/{period}, tidigareKorning/{period} och motor/version. Varje post har versions-id eller referens och hash.
API: alla läs-API:er för versionerad data tar ?giltigVid=<datum>&kandVid=<tidpunkt>. Historik: GET /regelverk/ersattningsgrunder/{id}/historik. Jämförelse: GET /regelverk/jamfor?fran=&till=. MCP: vad_gallde(ersattningsgrund, datum, kand_vid?).
Tester: egenskapsbaserade tester (BitemporalEgenskaper) visar att det inte finns luckor eller överlapp och att as-of-frågan ger högst en version. Ett golden-test kör maj 2026, gör en retroaktiv ändring, kör igen och reproducerar den första körningen bit för bit.
8.3 Regelmotorns primitiver och mallar#
Motorn byggs av primitiver (åtta grundprimitiver nedan, elva i den byggda motorn). De 42 regeltyperna i katalogen (docs/underlag/modeller/00-katalog.md) blir mallar som sätts samman av primitiver. Regionpaketen innehåller bara parametrar och sammansättningar (ADR 0003, ADR 0010). En ny ersättningsform byggs alltså av befintliga primitiver i stället för ny kod (mål 2).
| Primitiv | Signatur (förenklad) | Exempel |
|---|---|---|
Urval |
mängd × predikat → delmängd | Listade sista dagen och folkbokförda i länet; besök med yrkeskategori läkare |
Tabelluppslag |
nyckel(ar) × tabell → värde | Åldersklass → belopp; produktkod × yrke × kanal → pris |
Trappa |
värde × intervall → utfall | CNI 1,0–1,199 → 10 kr; volym 100–104 % → 50 % |
Tak |
belopp eller volym × gräns → begränsat värde | 1 125 000 kr per fysioterapeut och år; tak 1 i LOL |
Andel |
belopp × procent → belopp | Momskompensation 6 %; delat kostnadsansvar 20 %; 75 % över 12 000 kr |
Tidsfonster |
händelser × fönster → delmängd | 90 dagars förfall; reoperation inom 2 år; ACG 18/36 månader; 2 omlistningar per 12 månader |
Aggregering |
mängd × gruppering × funktion → värde | Antal listade per vårdenhet; kvot besök/listade |
Fordelning |
belopp × nyckel → delbelopp | Tolftedelar; 1/365; sjättedelar; fördelning efter kapacitetsandel |
Byggt i F3 (ADR 0013). Regelschemat (contracts/schemas/regel/) och Ersvia.Regelmotor har elva primitiver: de åtta ovan plus villkor, schablon och episod (tillstånd över händelser, tillagd i primitiver.schema.json). Det finns 34 mallar (33 ur schemat plus körsteget clearing för clearing mellan vårdgivare). Alla 42 regeltyper är uttryckta som mall eller variant av mall, utan kodad specialmall; mappningen med facit per typ finns i docs/plan/regelmappning.yaml, och facitfilerna (51 st.) i tests/Golden. Nya ersättningsformer byggs med sammansatt (kedja av primitiver).
Körfaser och beroenden (kontroll 3 Ä11 och R10). Motorn har nio körfaser i ordning – urval, klassificering, prissättning, tillägg/avdrag, tak/målvolym, periodavstämning, pooler/clearing, justering och resultat – grupperade i fyra körnivåer: händelse, vårdgivare och period, pool över vårdgivare och avstämning. Varje mall planeras till namngivna steg, och beroendena bildar en DAG som sorteras topologiskt med fas, regelordning och stegordning som deterministisk prioritet. Ett steg får inte bero på ett steg i en senare fas. Avrundning sker bara med avrunda och en explicit metod (halvUpp, bankavrundning, nedåt, uppåt), per rad eller per summa (nar: perSumma). Belopp är kronor som decimal i motorn och öre i gränssnitten. Varje primitivanrop skriver en tracepost, och resultatet har en SHA-256 över rader, flaggor och trace (KRAV-36). Se f03.
Beslutstabeller med explicit träffpolicy (planen 4k). Varje beslutstabell anger träffpolicy enligt DMN: unik (UNIQUE), forsta (FIRST), prioritet (PRIORITY), alla (COLLECT) och summa (COLLECT-SUM). Överlapp är fel vid publicering för UNIQUE och för PRIORITY med samma prioritet, och luckor är fel när tabellen saknar standardutfall. Uttryck kan skrivas som JSON-träd eller som formel ({"formel": "max(0, x - $troskel) * 0.75"}). Bevis vid publicering: Regelverk kräver minst ett godkänt facitfall och sparar ett hashat testbevis (regelhash, motorversion, fallens utfall) med versionen.
Uttrycken körs i en sandlåda utan I/O, klocka eller slump. Belopp räknas med Belopp och avrundas bara med en explicit Avrundningsregel.
Mallar (42 regeltyper)#
| # | Mall | Primitiver |
|---|---|---|
| 1 | Pris per produktkod | Urval, Tabelluppslag |
| 2 | Tilläggsersättning ovanpå bas | Urval, Tabelluppslag |
| 3 | Åldersviktad kapitering per listad | Urval, Tabelluppslag, Aggregering, Fordelning |
| 4 | Indexjusterad kapitering eller fast ersättning (CNI/ACG) | Tabelluppslag, Andel, Fordelning |
| 5 | Indextrappa per besök | Tabelluppslag, Trappa |
| 6 | Geografiskt tillägg (zoner) | Tabelluppslag |
| 7 | Avståndstrappa | Trappa |
| 8 | DRG × poängpris | Tabelluppslag, Andel |
| 9 | Målvolym med reducerat pris eller trappa | Aggregering, Trappa, Andel |
| 10 | Avdragstrappa vid underproduktion | Aggregering, Trappa, Andel |
| 11 | Fast uppdrag i tolftedelar | Fordelning |
| 12 | Fast ersättning med villkor och återkrav | Aggregering, Trappa, Fordelning |
| 13 | Bemanningsavdrag | Andel, Fordelning |
| 14 | Episod- och periodersättning | Tidsfonster, Tabelluppslag |
| 15 | Vårdtillfälle med vårddygnstrappa | Trappa, Tak |
| 16 | Dagersättning per patient | Aggregering, Tabelluppslag |
| 17 | Ersättningstak i kronor | Aggregering, Tak, Fordelning |
| 18 | Volymtak och kvottak | Aggregering, Trappa, Andel |
| 19 | Andelsgolv och andelstak per delmängd | Urval, Aggregering, Tak |
| 20 | Kostnadsgräns med vidarefakturering | Trappa, Andel |
| 21 | Bonus per mål | Tabelluppslag, Fordelning |
| 22 | Kvalitetsandel innehållen ur pris | Andel |
| 23 | Indikatorformel (resultat − min)/(mål − min) | Aggregering, Trappa, Andel |
| 24 | Bonus och vite i procent av årsersättning | Aggregering, Andel |
| 25 | Vite per händelse | Urval, Tabelluppslag |
| 26 | Avtalsvite på vitesgrundande belopp | Tidsfonster, Aggregering, Andel, Tak |
| 27 | Innehållande och återbetalning | Andel, Tidsfonster |
| 28 | Patientavgiftsavdrag | Tabelluppslag, Urval |
| 29 | Schablonavdrag för ej folkbokförda | Urval, Tabelluppslag |
| 30 | Delat kostnadsansvar i procent | Andel |
| 31 | Undantagslista med kostnadsersättning | Urval, Tabelluppslag |
| 32 | Prisindexering | Tabelluppslag, Andel |
| 33 | Prisbrytpunkt | Tabelluppslag (nyckel = styrande datum) |
| 34 | Preskription och frister | Tidsfonster |
| 35 | Patientkategori styr prislista och mottagare | Urval, Tabelluppslag |
| 36 | Frekvensregler per patient och period | Tidsfonster, Aggregering |
| 37 | Förhandsbedömning eller ansökan som villkor | Urval |
| 38 | Kapitering per vårdbehovsområde | Tabelluppslag, Aggregering, Fordelning |
| 39 | Nationell taxa med takbelopp | Tabelluppslag, Aggregering, Tak, Trappa |
| 40 | Tillfällig fast ersättning fördelad efter andel | Fordelning |
| 41 | Moms- och engångsbelopp | Andel |
| 42 | Momentan avräkning (kvittning) | Aggregering |
Det finns också mallar för de regeltyper som finns i ersättningsbilagorna:
- tillägg för uppdrag med villkor och kontroll per period
- fast och rörligt led
- ersättning efter tid
- beslut om ersättning varje halvår, i sjättedelar
- tillägg som gäller en viss tid
- volymtrappor som höjer den fasta delen
- pris efter triage (bedömning av hur brådskande vården är)
- målvolym i flera steg
- ersättning i proportion till hur väl målet nås, med villkor om täckning
- mätning vid flera tidpunkter
- viten enligt klausul 10.1, 10.2 och 10.4.2
- egen regi med budget för uppdraget.
Varje mall har ett facittest med ett verkligt exempel ur katalogen. Ett facittest jämför resultatet med ett känt rätt svar.
8.4 Säkerhet#
Zoner#
| Zon | Data | Åtkomst | Skydd |
|---|---|---|---|
| Patientdatazon | Personnummer, samordningsnummer, reservnummer i klartext | Bara modulerna Vardhandelser, Vantande, Listning, Rapportering, Kompatibilitet, Personuppgifter (värd Ersvia.Patientdata) |
Egen process och deploybar enhet, egen namnrymd, egen databasinstans och DB-roll utan grants mellan zonerna, nätpolicy, arkitekturtest, åtkomstloggning, återidentifiering och utlämningsexport bara här |
| Ersättningszon | Pseudonym, ålder, kön, län, kommun, basområde | Övriga moduler, Portal, MCP | RLS per huvudman, behörighet per roll och vårdgivare |
| AI-zon | Pseudonymiserade eller aggregerade data | Bara från ersättningszonen | Egen namnrymd, ingen utgående trafik som standard |
Zonbrygga, personnummervakt och nycklar (byggt i F12a, ADR 0020)#
| Skydd | Hur det fungerar |
|---|---|
| Zonbrygga | Portar som går över zongränsen ersätts av proxyer som anropar POST /intern/zon/v1/{port}/{metod} hos den andra zonen över HTTPS med ömsesidig TLS. Klientcertifikatet (cert-manager, zonernas interna CA) valideras mot tillåtna namn. Bara portar på vitlistan (Zonkopplingar) exponeras: patientdatazonen ger pseudonym och härledda fält, ersättningszonen referensdata. Arkitekturtester kontrollerar att portarna saknar personnummerfält och att ersättningszonen inte beror på patientdatazonen. |
| Personnummervakt | Svar från patientdatazonen kontrolleras på båda sidor av bryggan. Allt som liknar ett personnummer (giltigt datum och kontrollsiffra) stoppas och loggas som säkerhetshändelse, och mätvärdet ersvia.zon.personnummerstopp ska alltid vara 0. Loggarna tvättas dessutom från personnummer, samordningsnummer och reservnummer (Personnummertvatt). |
| Databasroller | Applikations- och gallringsroll per zon, grants bara till zonens scheman, uttryckligt nekande av andra zoners scheman, inget för PUBLIC (Zonroller). |
| Nycklar | Pseudonymnyckeln per huvudman och ändamål läses via INyckelkalla: konfiguration (utveckling), Kubernetes Secret som volym eller KMS via IKmsKlient (HashiCorp Vault KV v2 eller stubbe). Bara patientdatazonen har nyckeln. |
| CSP | Portalen skickar Content-Security-Policy med nonce per svar; axe kördes om mot CSP-värdarna med 0 överträdelser. |
| Hastighetsbegränsning | AddErsviaWebbskydd (Ersvia.Hosting/Webbskydd): fast fönster per minut och anropare, 600 anrop för användare och 6 000 för system med certifikat (konfigurerbart under Ratebegransning); hälsokontroller undantas; 429 vid överskridande loggas som säkerhetshändelse. |
| Säkerhetsloggar | Varje HTTP-anrop, nekade anrop, zonanrop, hastighetsbegränsningar och driftåtgärder loggas som säkerhetshändelser till en separat sink med minst 5 års bevarande (HSLF-FS 2016:40). |
Autentisering#
| Part | Mekanism |
|---|---|
| System-till-system (journalsystem, Inera, leverantörer) | mTLS med SITHS funktionscertifikat (byggt i F9a för GVR-fasaden): ASP.NET Core-certifikatautentisering mot regionens rot, HSA-id ur certifikatets SERIALNUMBER (2.5.4.5) mappas till vårdgivare via Identitet eller Kompatibilitet:Systemkonton. TLS kan termineras i ingressen med vidarebefordrat certifikat (kap. 7.2). Spärrkontroll kan slås på. SNOD: HTTPS och Basic auth. |
| Regionens användare (Avtalsansvarig, Controller, Attestant, Ekonomifunktionen, Systemförvaltare) | OIDC/SAML mot regionens identitetstjänst (SLL IDP), med SITHS-kort eller e-legitimation. Flerfaktor krävs (HSLF-FS 2016:40) och tillitsnivå 3 för kritiska system (RS 2025-0418). |
| Vårdgivarens användare | OIDC med e-legitimation (BankID, Freja) eller SITHS. Behörigheten kopplas till vårdgivare via HSA-uppdrag eller regionens behörighetsadministration. |
| AI-klienter | OIDC-token med samma roller. MCP-verktygen filtreras på roll. |
| Dev och test | Keycloak och en dev-CA |
Behörighet#
Behörigheten har tre delar. Den första är roll (TestVioras sex roller). Den andra är vårdgivare, alltså vilka av dem som användaren får se. Den tredje är beloppsgräns (för attest). Identitet översätter claims (uppgifter i inloggningen) till behörigheter. Varje endpoint (adress i API:et) har en policy, en regel för vem som får anropa den. Tabellen över behörigheter följer TestVioras roller:
| Roll | Läsa | Skapa och ändra | Godkänna |
|---|---|---|---|
| Avtalsansvarig | Överenskommelser, ersättningsunderlag, kodverk | Överenskommelser | |
| Controller | Allt i ersättningszonen | Regelverk, indikatorer, justeringar, simuleringar | Regelversioner som någon annan har skapat |
| Attestant | Ersättningsunderlag, fakturaunderlag | Attest steg 2 upp till beloppsgränsen | |
| Vårdgivare | Egna överenskommelser, avstämning, fakturaunderlag | Vårdhändelser, invändningar, ansökningar | Eget fakturaunderlag |
| Ekonomifunktionen | Fakturaunderlag och utbetalningar | Kvittens | |
| Systemförvaltare | Integrationsstatus, loggar, kodverk och masterdata | Kodverk och masterdata, behörigheter |
Delegations- och attestmatris#
Beslutsrätten är konfigurerbar per regionpaket och versionerad bitemporalt, och Identitet kontrollerar den vid varje beslut (planen 4j). Systemet kontrollerar både vem (roll och delegation) och hur mycket (beloppsnivå).
Delegationsmatris (Region Stockholm, gällande delegationer HSN 2026-0052 och PVN 2026-0005):
| Beslut | Beslutsfattare | Gräns |
|---|---|---|
| Avtal om vård | Avdelningschef | Under 25 mnkr |
| Avtal om övrigt | Avdelningschef | Under 5 mnkr |
| Avtal | HS-direktören | Under 50 mnkr |
| Upphandling | Nämnden | Över 50 mnkr |
| Avtal inom psykiatri | Psykiatriutskottet | Under 1 500 mnkr per år |
| Godkännande och uppsägning enligt LOV | HSN:s avtalsutskott (primärvård: PVN) | |
| Rapporteringsanvisningar som påverkar ersättningen | Avdelningschef | |
| Avskrivning av fordringar | Avdelningschef / direktören | Upp till 30 000 kr / upp till 100 000 kr |
Attestmatris: beloppsnivåer, utanordnare och attestanter. Egenattest spärras, och över en konfigurerad gräns krävs två personer (GR-5002). Inget attestreglemente är publicerat, så regionen fyller i värdena från HSN:s beslutsordning 2024-0105 och ekonomihandboken. Ändringar i attestanter rapporteras till nämnden varje kvartal. Behörigheter tilldelas utifrån en dokumenterad behovs- och riskanalys per roll och följs upp årligen (NK20, RS 2025-0418).
Pseudonymisering och dataminimering#
- Pseudonym (ett ersättningsnamn i stället för personnummer) = HMAC-SHA-256 av person-id med en nyckel. Nyckeln är unik per tenant och ändamål och ligger i KMS eller HSM (i F2 per huvudman i konfigurationen). Den finns bara i patientdatazonen.
- Återidentifiering, att ta fram personnumret igen, sker bara i patientdatazonen. Ändamålet kontrolleras och allt loggas (NK19). Det behövs för drill-down och utlämningsexport.
- Data med pseudonym är ändå personuppgifter, till exempel vid små celler och ovanliga diagnoser. Därför görs en DPIA (en analys av hur integriteten påverkas). Data slås ihop med k-anonymitet innan de går till AI, så att ingen kan pekas ut (kontroll 3 R5).
- Ersättningszonen får bara ålder på mätdagen, kön, län, kommun och basområde (KRAV-18).
- Inga personnummer i fakturaunderlag till vårdgivare eller i interna fakturor. De använder vårdhändelsenummer eller pseudonym. Vissa utlämnanden kräver identitet enligt regelverk (riksavtalet 8.9, Försäkringskassan EU/EES, Migrationsverket). De skapas av utlämningsexporten i patientdatazonen. Skyddad identitet sköts av sig själv.
- VAL (rättat krav, ADR 0020 tillägg): VAL gör pseudonymer själv och får därför vårdhändelser och listning med personnummer i klartext.
Valexporttjansti patientdatazonen gör leveransen (POST /api/uppfoljning/v1/val/leveranser, som ingressen skickar dit). Ändamålet kontrolleras mot regionpaketetsuppfoljning/exporter.json(annarsUP-5005). Varje person läses via Personuppgifter med ändamålet. Varje uttag loggas i revisionsloggen och säkerhetsloggen. Leveransen har ett manifest medpseudonymiserad: false. Kontrollen av personnummer,UP-5003, är en uttrycklig inställning per export. Den är avslagen bara förval-vardhandelserochval-listningoch påslagen för allt annat. Utfallsexporten innehåller inga personer och ligger kvar i Uppföljning. - Väntetidsdatabasen, KPP, patientregistret och statsbidragen får underlag med pseudonym, och underlagen kontrolleras mot personnummer. Patientregistret får personnumret när underlaget lämnas in. Det är utlämningsexporten som kopplar på det.
Loggning#
IRevisionsloggloggarLasningAvPersonuppgifter,Skapad,Andrad,Godkand,Avslagen,Publicerad,Justerad,AttesteradochInloggning(KRAV-67).- Loggen är append-only och hashkedjad per tenant (
Hashkedja<Revisionspost>).VerifieraAsynchittar den första trasiga posten. - Loggen lagras per schema i
<schema>.revisionslogg(huvudman, sekvens, tid, aktor, handling, objekt, detalj, foregaende_hash, hash)med triggernendast_tillaggoch RLS (ADR 0011).Personuppgifterloggar varje läsning med pseudonym, aldrig personnummer i klartext. - Säkerhets- och åtkomstloggar sparas i minst 5 år (HSLF-FS 2016:40, BG-plan). Stickprov i loggarna dokumenteras.
- Loggarna kan levereras till regionens SIEM och e-arkiv. Säkerhetshändelser tidsstämplas så att regionen kan lämna tidig varning inom 24 timmar, incidentanmälan inom 72 timmar och slutrapport inom 1 månad (NIS 2, NK24).
Säkerhetsdrift och NIS 2#
Ersvia omfattas som del av regionens verksamhet av cybersäkerhetslagen (2025:1506). En leverantör som driver Ersvia som tjänst blir själv verksamhetsutövare (förvaltade tjänster). Arkitekturen stöder därför: SBOM per release (CycloneDX i CI, byggt i F12a), Trivy-skanning per image, signerade images, SIEM-export (separat säkerhetslogg-sink), incidentflöde med tidsstämplar (nis2-incidentrutin.md), säkerhetskopiering varje dygn med återläsningstest, revisionsrätt och NIS 2-ansvar i leverantörsavtalet, och säkerhetsskyddsanalys före upphandling (NK25). En ADR om säkerhetsdrift tas fram i F12 (kontroll 3 R7).
8.5 Multi-tenant och regionpaket#
Huvudman är tenant (ADR 0010). ITenantKontext.Huvudman (HuvudmanId, t.ex. exempel eller stockholm) sätts per anrop från token eller certifikat, eller per jobb. Alla tabeller har kolumnen huvudman och RLS-policyer (ENABLE + FORCE) som jämför med current_setting('app.huvudman'). En interceptor sätter värdet med set_config på varje anslutning. Applikationsrollen saknar BYPASSRLS och superanvändare, och lagren filtrerar dessutom explicit på huvudman som försvar på djupet (ADR 0011). Integrationstesterna visar att stockholm och exempel inte ser varandras data. Kvarstående risk (kontroll 3 R9): läckage via poolade anslutningar, bakgrundsjobb och outbox utan tenant. Åtgärd: SET LOCAL per transaktion och ett test som misslyckas om tenant saknas. KSON (kommunalförbund) passar inte modellen "huvudman = region" och modelleras som beställare inom regionens tenant tills vidare. Nycklar för pseudonymisering och kryptering är separata per tenant.
Regionpaketen för stockholm och exempel finns som seed i packages/region-stockholm/ och packages/region-exempel/ från F2.
| Driftform | Beskrivning |
|---|---|
| En installation per region | Vanligast i offentlig sektor. FastTenantKontext. |
| Multi-tenant SaaS | Flera regioner i samma kluster, med RLS och nycklar per tenant. |
Regionpaket (packages/region-<namn>/) innehåller allt som är unikt för en region, som versionerad och bitemporal data: regelsammansättningar och parametrar, Kodserver-tabeller, faktureringskalendrar, roller, fakturamottagare med Peppol-adresser, ekonomisystemsadapter, portaltexter och profil (white-label) och begreppsalias. Paketen kan exporteras och importeras i öppet format (KRAV-79). Ett startpaket med nationellt gemensamma regler ingår: riksavtalet, patientavgifter, LOL/LOF-taxan, asyl och EU.
Variation som paketen ska kunna uttrycka: viktlistor med 2–101 åldersgrupper med eller utan kön, ACG-fönster på 15, 18 eller 24 månader, CNI med tröskel och avstämningsrytm, mätdag (1:a, 15:e, 28:e, sista dagen eller dag för dag), utbetalningsdag (5:e, 15:e, 19:e, 20:e eller sista vardagen, ibland förskott) och momskompensation (3,5, 5 eller 6 %).
Verifiering: arkitekturtestet söker efter regionspecifika namn ("Stockholm", "SLL", "HSF") i src/ utanför src/Integrations/. E2E-scenariot körs också mot det fiktiva paketet "Region Exempel". Varje paket levereras med ett körbart scenariobibliotek, eftersom upphandlingar utvärderar på scenarier (till exempel Örebro och Västernorrland med 12 scenarier).
8.6 AI-arkitektur och skydd#
Ersvia är AI-först, men AI påverkar aldrig belopp och ser aldrig personuppgifter (ADR 0007).
| Förmåga | Var | Indata | Utdata | Mål eller krav |
|---|---|---|---|---|
| Regelassistent | Ersvia.Ai via Ersvia.Mcp och Portal |
Avtalsbilaga eller rapporteringsanvisning (källdokument med hash), gällande regel | Regelutkast i regel-JSON-schemat, diff, simulering | Mål 2, KRAV-20 |
| "Förklara min ersättning" | Portal | Trace för en ersättningsrad (pseudonymiserad) | Förklaring med hänvisning till regelrader. Beloppen kommer från motorn. | Mål 4, KRAV-59 |
| Avvisningshjälp | Vardhandelser → Ersvia.Ai |
Felkod, fält och regel, utan personuppgifter | Förklaring och rättningsförslag | KRAV-7, B4 |
| Avvikelseanalys | Granskning |
Aggregerade avvikelser och kontrollflaggor | Hypoteser, prioritering och förslag på stickprov | KRAV-47 |
| Handläggningsstöd för ansökningar | Malrelaterad |
Ansökan om målrelaterad ersättning | Sammanfattning och bedömningsstöd | KRAV-45 |
| Förklaring av skillnader vid parallellkörning | Migrering |
Skillnader per vårdgivare | Förklaringar | KRAV-72, risk 1 |
MCP-verktyg (byggda i F11a, officiella C#-SDK:t ModelContextProtocol 2.4): vad_gallde, sok_overenskommelse, hamta_regelversion, vardhandelsestatus, listning_ogonblicksbild och forklara_felkod (läsande) samt skapa_regelutkast (skapar bara utkast med status utkast). Autentisering per huvudman med SHA-256-lagrade nycklar; alla svar maskeras mot personnummer, och listning ges bara som aggregat.
Skydd:
- All AI går via
Microsoft.Extensions.AI.IChatClient. Standard i regionpaketet är en lokal eller svensk modell. Anthropics C#-SDK (claude-opus-5-5) eller en annan extern leverantör kräver explicit aktivering per miljö.FakeChatClientanvänds i CI. - AI körs bara i AI-zonen och får bara pseudonymiserade eller aggregerade data. En utgående filter-mellanvara avvisar anrop som innehåller mönster för personnummer.
- AI räknar aldrig belopp. Allt AI-genererat är utkast, märks "AI-genererat" och kräver mänskligt godkännande.
- Varje anrop loggas med modell, prompt-hash, verktyg, användare och resultat.
- AI kan stängas av per miljö och per förmåga.
- En eval-svit (
tests/Evals) mäter schematräffsäkerhet, korrekthet mot facit och läckage. Den körs vid byte av modell. - Structured outputs valideras mot regel-JSON-schemat innan utkastet sparas (
RV-5002vid fel). - En extern LLM klassas som tredjelandsöverföring och biträde och är avstängd tills beslut finns (kontroll 3 R5).
AI-register och klassning enligt AI-förordningen#
AI-registret är byggt i F11a och ligger i docs/plan/ai-register.yaml (version 1.0.0, uppdaterad 2026-11-11). Filen bäddas in i Ersvia.Ai och serveras av AI-tjänsten (GET /ai/register) och portalens sida /ai-register. Ersvia.Ai stänger av en funktion som saknas i registret eller är avstängd, och en högriskfunktion kan inte slås på utan FRIA-referens (art. 27). Förordning: (EU) 2024/1689, ändrad genom (EU) 2026/1744; högriskkraven gäller från 2027-12-02. Regelbaserad beräkning är inte AI, och AI fastställer aldrig belopp eller rätt (NK40).
Riskklasserna är minimal (AI-kunnighet enligt art. 4), transparens (upplysning enligt art. 50) och hög (bilaga III p. 5 a: bedömer fysiska personers rätt till vård eller förmån eller profilerar fysiska personer; kräver FRIA, mänsklig kontroll, loggning och dokumenterad bedömning; avstängd som standard).
| Id | AI-funktion | Riskklass | Artiklar | Mänsklig kontroll | Standard |
|---|---|---|---|---|---|
regelassistent |
Regelassistent | transparens | 4, 50 | Utkast → granskning av controller → publicering av annan person (fyra ögon). Ingen automatisk publicering. | på |
forklara-vardhandelsestatus |
Förklara vårdhändelsestatus | transparens | 4, 50 | Förklaringen är information; status sätts av valideringen och kan bara ändras genom rättelse. | på |
forklara-ersattningsrad |
Förklara ersättningsrad | transparens | 4, 50 | Förklaringen är information; invändningar hanteras av handläggare. | på |
avvisningshjalp |
Avvisningshjälp | transparens | 4, 50 | Vårdgivaren rättar själv och skickar in på nytt; valideringen avgör. | på |
avvikelseanalys |
Avvikelseanalys och granskningsurval | transparens | 4, 50 | Handläggare beslutar om granskning och återkrav. | av |
riskpoang-enskild-naringsidkare |
Riskpoäng för enskilda näringsidkare (LOL/LOF) | hög | 6, 26, 27, 50 | Krävs men är inte utformad; funktionen är avstängd. | av |
bedomning-patientavgift-och-ratt-till-vard |
AI-bedömning av patientavgift, frikort eller rätt till vård | hög | 6, 26, 27, 50 | Krävs men är inte utformad; funktionen är avstängd. | av |
Varje svar bär upplysningen: "AI-genererad förklaring (art. 50 AI-förordningen). Kontrollera mot regelrad och orsakskod; belopp och beslut kommer alltid från Ersvias regelmotor och handläggare."
Skydd i varje anrop (F11a): registret, pseudonymiseringsfiltret (personnummer blockerar anropet, namn, e-post och telefon maskeras), beloppsvakten (belopp som inte finns i underlaget tas bort), art. 50-upplysningen och en hashkedjad AI-revisionslogg med prompt, svar, modell, syfte och användare. Loggen är en JSON Lines-fil tills Drift (F12) flyttar den till revisionsloggen i PostgreSQL. Adaptrar: Anthropic (claude-opus-5-5, structured outputs, server-side fallback), lokal OpenAI-kompatibel (svensk drift) och FakeChatClient (CI). Profilen per regionpaket (packages/region-*/ai/ai-profil.json) är av som standard; paketen väljer lokal drift, och extern LLM kräver dessutom Ersvia:Ai:TillatExtern i miljön. Anthropic-adaptern är ännu inte testad mot API:t.
Avvikelseanalys (avvikelseanalys) är registrerad men avstängd; Granskningens deterministiska kontrollregler och riskpoäng (F7) är inte AI.
8.7 Felkodskatalog och kompatibilitet#
Fel returneras som ProblemDetails (RFC 9457) med Ersvias stabila felkod felkod (<PREFIX>-<nnnn>) och legacyFelkod (system, kod), så att vårdgivare och servicedesk känner igen felen (ADR 0002). Katalogen ligger i contracts/legacy/felkoder.yaml.
| Prefix | Modul | Prefix | Modul |
|---|---|---|---|
| GEN | Generella (400, 401, 403, 404, 409, 500) | GR | Granskning |
| MD | Masterdata | FA | Fakturering |
| KV | Kodverk | AV | Avstamning |
| OK | Overenskommelse | UP | Uppfoljning |
| VH | Vardhandelser | MS | MedicinskService |
| VA | Vantande | LM | Lakemedel |
| LI | Listning | DR | Drift |
| RA | Rapportering | SI | Simulering |
| RV | Regelverk | MR | Malrelaterad |
| BE | Berakning |
| Legacysystem | Dagens koder | Mappning |
|---|---|---|
| GVR (AF v1.4) | 0000–0950 | VH-* med legacyFelkod.system = GVR |
| GVR REST v2 | 147 errorCode i intervallet 0–1099 |
GvrProblemDetail.errorCode i fasaden |
| ERSMO | AF100–AF330 | BE-* |
| HEJ | H0xx–H1xx | BE-* |
| VF | 0000–4225 och 9999 | FA-* |
| CVR, ListOn, RAPP | Respektive specifikation | VA-*, LI-*, RA-* |
Katalogen contracts/legacy/felkoder.yaml (F1) har 438 koder och följer numreringen: 0000–1099 har samma nummer som GVR errorCode (GEN, VH, VA), BE-0100–BE-0330 motsvarar ERSMO AFnnn, BE-1000–BE-1999 HEJ Hnnn, FA-0001–FA-0046 VF:s statuskoder, AV-0000/1111/2222/9999 avstämningsstatus OK, Prel, Mak och BeEj, och 5000 och uppåt är Ersvias egna koder.
Felkoderna i SAD:ens körningsvy är synkade mot katalogen:
| Felkod | Titel i felkoder.yaml |
Används i | Status |
|---|---|---|---|
GEN-0409 |
Konflikt (idempotensnyckel med annat innehåll) | s01, 8.9 | Finns |
GEN-0010 |
Pseudonymiseringsnyckel saknas för huvudmannen | Personuppgifter (F2) | Finns, används i koden |
VH-0202 |
Personnummer/reservnummer saknas i CFU/SPAR (GVR errorCode 202) | s01, s02 | Finns, används i F4 |
VH-0313 |
Dubblett av X-Resource-Id/externtId |
s01 | Finns, används i F4 |
VH-5001 |
Rapporterad efter brytpunkt (KRAV-9) | s04 | Finns |
VH-5002 |
Rätten till ersättning har förfallit (KRAV-10) | t01 | Finns |
VH-5003 |
Vårdhändelsen är för gammal för att bearbetas (30 månader) | t01 | Finns |
LI-5001 |
Omlistning inte tillåten | s03 | Finns (tidigare LI-2001 i SAD v1) |
LI-5002 |
Listningstaket är nått | s03 | Finns |
RV-5001 |
Godkännande kräver en annan person (KRAV-21) | s06 | Finns (tidigare RV-2001) |
RV-5002 |
Regeldokumentet är ogiltigt (mot regelschemat) | s10 | Finns (tidigare RV-2101) |
RV-5003 |
Överlappande giltighet | s06 | Finns |
GR-5001 |
Justering kräver motivering (KRAV-48) | s08 | Finns |
GR-5002 |
Attest kräver en annan person med attesträtt (KRAV-49) | s07 | Finns (tidigare GR-3001) |
FA-5002 |
Invändningsfristen har passerat (KRAV-51) | s08 | Finns |
FA-5003 |
Beslut om tillägg kan inte ändras (KRAV-52) | s08 | Finns |
FA-5006 |
LMA- eller dossiernummer saknas (KRAV-38) | s07, t03 | Finns, används i F8 |
FA-5018, FA-5019, FA-5021 |
Självfakturering kräver godkännande; egenattest spärrad; utomlänskrav bestrids efter fristen | s07, s09 | Finns, används i F8 |
KP-5003, KP-5004 |
Ogiltigt billing:claim-underlag; ändamål saknas för utlämning | s09, s15 | Finns, används i F8 |
UP-5003, UP-5004, UP-5005 |
Personnummer i nationell fil; VAL-typer levereras från patientdatazonen; ändamål saknas för VAL-uttag | s15 | Finns, används i F10/F12a |
AV-5001 |
Avstämning | 5.3 | Finns, används i F8 |
FA-5101 |
Utomlänsunderlag äldre än 6 månader (riksavtalet) | s09 | Planerad, läggs in i katalogen i F8 |
BE-5004 |
Stängd period: torrkörning krävs, och genomförandet måste ha samma manifesthash | s05 | Finns, används i F6 |
RA-5002–RA-5012, KP-5001–KP-5002 |
Rapportering och kompatibilitetsfasaden | 5.2 | Finns, används i F9a |
Orsakskoder (planen 4k): katalogen byggs ut till en publik och versionerad katalog över orsakskoder, i stil med CARC/RARC. Varje kod anger vem som bär beloppet (vårdgivaren, regionen, annan huvudman), vilken åtgärd som krävs (rätta, komplettera, ingen) och är kopplad till den regelrad som gav anmärkningen. Katalogen publiceras tillsammans med kontrakten och versioneras bitemporalt.
Kompatibilitetsregler för kontrakt: OpenAPI-diff i CI. Brytande ändringar kräver ny version (/api/<modul>/v2). Händelsetyper har versionssuffix (.v1). Gamla versioner stöds i minst 12 månader. Legacykontrakten (GVR v1.9.5 och v2.0.0, SNOD-XML, CVR, VF) testas med paritetstester som genereras direkt ur specifikationerna.
8.8 Händelser och outbox#
- Integrationshändelser (
IIntegrationshandelse.HandelseTyp) namngesersvia.<Handelse>.v<n>(t.ex.ersvia.VardenhetRegistrerad.v1) enligt AsyncAPI-kontraktetcontracts/asyncapi/ersvia-events.yaml(23 händelser i F1). Kanalerna heterersvia.{huvudman}.<modul>.v1. ADR 0006 är reviderad och anger nu samma form. Interna jobb som inte lämnar modulen har prefixetersvia.intern.(t.ex.ersvia.intern.ValideringBegard.v1). Händelserna skrivs till modulensoutboxi samma transaktion som domänändringen (IOutbox.LaggTillAsync). OutboxBearbetarepublicerar viaIHandelsePubliceraremed minst en gång-leverans. Mottagarna är idempotenta, med händelse-id som dedupliceringsnyckel.- I MVP sker publiceringen in-process. Publiceraren kan bytas mot Kafka eller regionens integrationstjänst utan att modulerna ändras.
- Händelser från patientdatazonen till ersättningszonen pseudonymiseras innan de lämnar zonen.
- Outboxen är persistent per schema (
<schema>.outbox) från F2, och händelsen skrivs i samma transaktion som versionen (ADR 0011). - Händelser som saknas i AsyncAPI-kontraktet och är planerade:
ersvia.InsamlingsperiodStangd.v1,ersvia.FolkbokforingAndrad.v1,ersvia.DifferensunderlagSkapat.v1,ersvia.AvvikelseFlaggad.v1,ersvia.KontrollarendeOppnat.v1,ersvia.AterkravBeslutat.v1,ersvia.FakturaunderlagSkapat.v1ochersvia.AvstamningsfilKlar.v1. De läggs in i kontraktet i den fas som bygger utgivaren.
| Händelse | Utgivare | Mottagare |
|---|---|---|
ersvia.VardgivareRegistrerad.v1, ersvia.VardenhetRegistrerad.v1 (byggda F2) |
Masterdata | Vardhandelser, Listning, Overenskommelse |
ersvia.KodverksversionPublicerad.v1 (byggd F2) |
Kodverk | Vardhandelser, Berakning |
ersvia.OverenskommelseAndrad.v1 (byggd F2) |
Overenskommelse | Vardhandelser, Berakning |
ersvia.VardhandelseMottagen.v1, …Avvisad.v1, …Rattad.v1, …Makulerad.v1, …StatusAndrad.v1 (byggda F4) |
Vardhandelser | Berakning, Avstamning, Uppfoljning, Granskning |
ersvia.VantandeRapporterat.v1 (byggd F4) |
Vantande | Uppfoljning |
ersvia.ListningAndrad.v1 (byggd F5) |
Listning | Malrelaterad, Uppfoljning |
ersvia.InsamlingsperiodStangd.v1 |
Vardhandelser | Berakning |
ersvia.ListningsunderlagFaststallt.v1 (byggd F5) |
Listning | Berakning, Malrelaterad, Uppfoljning |
ersvia.RegelversionPublicerad.v1, ersvia.ParametertabellPublicerad.v1 (byggda F3) |
Regelverk | Berakning (retroaktiv kontroll), Simulering |
ersvia.BerakningKlar.v1 (byggd F6, bara ordinarie körning) |
Berakning | Granskning, Avstamning |
ersvia.SimuleringKlar.v1 (byggd F6) |
Simulering | Portal |
ersvia.DifferensunderlagSkapat.v1 |
Berakning | Fakturering |
ersvia.UnderlagAttesterat.v1 |
Granskning | Fakturering |
ersvia.AterkravBeslutat.v1 |
Granskning | Fakturering |
ersvia.FakturaforslagSkapat.v1, ersvia.UnderlagGodkant.v1, ersvia.UnderlagInvandning.v1, ersvia.FakturaSkickad.v1, ersvia.BudgetjusteringBokford.v1 (byggda F8) |
Fakturering | Avstamning, Portal (aviseringar), Uppfoljning |
ersvia.UtbetalningKvitterad.v1 (byggd F8) |
Fakturering | Avstamning, Uppfoljning, Portal |
8.9 API-konventioner#
- REST under
/api/<modul>/v1/...(t.ex./api/masterdata/v1/vardgivare), med en OpenAPI-fil och en server-URL per modul, och svenska resursnamn utan å/ä/ö. JSON i camelCase. ?giltigVid=&kandVid=på alla läs-API:er för versionerad data.- Offsetpaginering med
offsetochgrans(högst 1000), samtX-Totalt-Antal. - Idempotens med headern
Idempotens-Nyckel(UUID) för skrivningar. Samma nyckel och samma innehåll ger samma svar, och samma nyckel med annat innehåll ger409(GEN-0409). - Optimistisk låsning med
ETagochIf-Match. X-Korrelations-Idföljer med genom hela kedjan och i OpenTelemetry.- Långa körningar returnerar
202 Acceptedmed enJobb-resurs. - OpenAPI publiceras på
/openapi/v1.jsonoch i regionens API-portal (Anypoint Exchange eller motsvarande).
8.10 Observability#
| Signal | Innehåll | Mål |
|---|---|---|
| Spår (OpenTelemetry traces) | Anrop från gateway genom modul, outbox och adapter, med X-Korrelations-Id och huvudman |
Felsökning över modulgränser |
| Mått | Kölängd och ålder på äldsta meddelande per kö (validering ≤ 1 h), körningstid per beräkning (≤ 4 h), antal avvisade per felkod, outbox-eftersläpning, integrationsstatus | Larm och kapacitetsplanering |
| Loggar | Strukturerade loggar utan personuppgifter. Personuppgifter loggas bara i revisionsloggen. | Drift |
| Integrationsstatus | GET /drift/integrationer: senaste lyckade körning, antal poster och fel per integration (drift.integrationskorning) |
KRAV-68 |
| Datakvalitet | Andel LF och RF per vårdgivare och felkod, sena rättelser | Risk 4 |
Telemetrin skickas med OTLP till regionens observabilitetsplattform. Lokalt visas den i Aspire-dashboarden.
8.11 Arkiv, gallring och export#
Byggt i F10 och F12a (ADR 0018, 0020). Detaljerna finns i docs/drift/earkiv-och-gallring.md.
E-arkiv enligt FGS Paketstruktur 2.0#
Jobbet --jobb earkiv --period <år|månad> (CronJob den 15 januari för föregående år) bygger ett informationspaket (SIP) med Ersvia.Arkiv.FgsPaket enligt E-ARK CSIP:
| Del i paketet | Innehåll |
|---|---|
METS.xml (rot) |
CSIP-profil, OBJID, TYPE, innehållstyp, metsHdr med SIP, agenter (ARCHIVIST, CREATOR, OTHER), altRecordID (leveransöverenskommelse, start- och slutdatum, åtkomstbegränsning, gallringsinformation), dmdSec, amdSec/digiprovMD, fileSec och structMap |
metadata/descriptive/arkivbeskrivning.xml |
Arkivbildare, arkiv, period, informationsmängder |
metadata/preservation/premis.xml |
PREMIS 3: objekt med SHA-256 och storlek, skapandehändelse, agent |
representations/rep1/ |
Representationens METS och data i öppna format (JSON, CSV) med manifest.json |
schemas/, documentation/gallringsinformation.json |
JSON Schema för manifestet och gällande gallringsfrister |
Inte validerat ännu: paketet har inte körts genom Riksarkivets eller E-ARK:s valideringsverktyg. METS- och PREMIS-XSD bäddas inte in, och arkivbeskrivningen är en förenklad XML i stället för EAD. Detta stäms av med Regionarkivet.
Gallring per regionpaket#
Gallringsfristerna ligger versionerade per informationsmängd i packages/region-*/drift/gallring.json med värden ur Regionarkivets BG-planer:
| Informationsmängd | Frist (Region Stockholm, förslag) |
|---|---|
| Verifikationer, filöverföringar till ekonomisystem, reskontra och momsunderlag | 7 år (LKBR, t.o.m. sjunde året efter räkenskapsåret) |
| Fakturaunderlag | 7 år om obligatoriska uppgifter ingår, annars 2 år |
| Transaktions- och ändringsloggar i ärendesystem | 10 år |
| Behandlingshistorik för redovisning, ersättningsunderlag och manifest | Bevaras eller 10 år |
| Säkerhets- och åtkomstloggar | Minst 5 år (kortare frist avvisas) |
| Regelversioner, beslut, källdokument, överenskommelser, godkända LOV-ansökningar, viten | Bevaras |
| Ej godkända LOV-ansökningar | 2 år |
Gallringsjobbet (--jobb gallring [--torr], CronJob per zon) följer fyra regler:
- Arkivbevarande går först. En källa som ingår i en informationsmängd som ska bevaras spärras helt, och finns den i flera mängder gäller den längsta fristen.
- Bitemporal gallring. En nyckels versioner gallras bara tillsammans: när alla gällande versioner har upphört att gälla före gränsen och ingen version registrerades eller ersattes efter gränsen. Det som finns kvar har därför alltid hel historik och obruten hashkedja, så att "vad gällde när" fortsatt kan besvaras.
- Egen roll. Jobbet kör som zonens gallringsroll med DELETE-behörighet; skyddstriggern tillåter DELETE bara när
ersvia.gallring = 'pagar'är satt i transaktionen och rollen är medlem. Applikationsrollen kan aldrig radera versionerad data. - Spårbarhet. Varje åtgärd loggas som säkerhetshändelse med informationsmängd, frist, fristversion, beslutsreferens, gräns och antal.
Samråd med Regionarkivet krävs före införandet; kopplingen mellan källor och tabeller i gallring.json är ett förslag till det samrådet.
Full export (KRAV-79)#
--jobb export och POST /api/drift/v1/exporter skriver varje informationsmängd som JSON och CSV (RFC 4180, semikolon, UTF-8 utan BOM) med manifest.json (SHA-256, storlek och antal poster per fil). Portalen visar 15 månaders historik; resten finns i arkivet.
8.12 Test och kravspårning#
| Testnivå | Katalog | Exempel |
|---|---|---|
| Enhet och egenskaper | tests/Ersvia.Tests.Unit |
BitemporalEgenskaper, BeloppTester, IntegritetTester (manifest, hashkedja) |
| Arkitektur | tests/Ersvia.Tests.Architecture |
ModulgransTester (KRAV-71, KRAV-78), RegionoberoendeTester (KRAV-76) |
| Kontrakt | tests/Ersvia.Tests.Kontrakt |
OpenAPI, AsyncAPI, regelschema och legacykontrakt; alla OpenAPI-exempel valideras mot sina scheman; route-test jämför endpoints med kontraktens operationer |
| Integration | tests/Ersvia.Tests.Integration |
Testcontainers med PostgreSQL: as-of, rättelse, exclusion constraint, triggrar, RLS mellan stockholm och exempel, outbox, åtkomstlogg (F2) |
| Golden (facit) | tests/Golden |
En golden file per mall, majkörningen 2026 |
| Kompatibilitet | tests/Compatibility |
Paritet mot GVR v2.0.0/v1.9.5, CVR, VF-fil, AF-rapport, paritetsmatris |
| E2E | tests/E2E |
Månadsscenariot i planen avsnitt 9, även mot "Region Exempel" |
| Tillgänglighet | tests/Accessibility |
axe mot Portal (KRAV-69) |
| Last | tests/Load |
NBomber: validering ≤ 1 h, månadsberäkning ≤ 4 h |
| AI-eval | tests/Evals |
Regelassistent mot facit, läckagetest |
Tester taggas med [Krav("KRAV-n")]. CI exporterar JUnit-resultat som laddas upp till TestViora, så att kravtäckningen syns där.
8.13 Användbarhet och tillgänglighet#
Portalen (se kapitel 5.5) är en Blazor Web App med server-rendering och följer WCAG 2.2 AA (KRAV-69): tangentbordsnavigering, synlig fokus, kontrast, skärmläsarstöd och felmeddelanden i klartext. Automatiska axe-tester körs i CI, och manuella tester görs med skärmläsare. Användartest före driftstart visar att controllers och vårdgivare klarar en regeländring och en månadsgranskning efter högst en dags utbildning (KRAV-77). Portalen kan märkas med regionens profil (white-label) och har svenska som grundspråk.
8.14 Begrepp och informationsmodell (NIM, VOK och termbanken)#
Planen avsnitt 4h styr hur Ersvias domänmodell förhåller sig till nationella begrepps- och informationsmodeller.
Termbanken som referensdata. Socialstyrelsens termbank 4.3.6 (TBX, CC0) importeras som referensdata i Kodverk. Varje begrepp i domänen har ett termbankTid med stabil länk, och mappningen underhålls i begreppsmappning.csv. Begreppen delas in i fyra grupper (se kapitel 12):
| Grupp | Begrepp | Hantering |
|---|---|---|
| Används direkt | vårdgivare, vårdenhet, vårdkontakt, vårdtillfälle, patient, reservnummer | Termbankens definition och termbankTid |
| Avviker eller avråds | "sjukvårdsinrättning" (avrådd term) används inte. "Hälso- och sjukvårdsutbud" betyder i termbanken själva utbudet, inte överenskommelsen. | Vardutbud används bara om utbudet. Överenskommelsen heter Overenskommelse. |
| Ersvias egna definitioner | patientavgift, frikort, högkostnadsskydd | Termbankens versioner gäller läkemedel eller är föråldrade. Definieras utifrån HSL 17 kap. |
| Egna begrepp som saknas i termbanken | huvudman, avtal, uppdrag, DRG, kapitering och ekonomibegreppen | Ersvias ordlista är källan och markerar dem som "egna" |
Informationsmodellen följer NIM (E-hälsomyndighetens nationella informationsmodell, informationsstruktur.ehalsomyndigheten.se, JSON-API) och VOK (informationsspecifikationen Organisation och verksamhet):
| NIM/VOK-begrepp | Ersvia | Kommentar |
|---|---|---|
| Organisation | Huvudman, Vardgivare och Vardenhet är typer av en gemensam Organisation |
Påverkar d01 och masterdata |
| Avtal, Uppdrag (VOK) | Avtal och Uppdrag (i egen regi) med VOK-attribut |
Mappas mot FHIR-profilerna HVOContract och HVOOrganizationAffiliation |
| Vårdkontakt, aktiviteter, diagnoser, deltagande | Vardhandelse är en sammanställning av dessa |
Patientregistrets variabel AVTAL och DRG, MDC och RTC ingår, så att Ersvia kan leverera till patientregistret (HSLF-FS 2023:33 och 2026:27) |
| Aktivitet | Aktivitet (åtgärd) ersätter "Hälso- och sjukvårdsåtgärd" |
Byter inte status och lagras oföränderlig |
| (saknas) | Ersattningsprodukt ersätter "Produktkod" |
|
| Nya begrepp | DrgResultat (med RTC och versioner), väntetid som två separata mått, Vardepisod, KostnadsansvarigHuvudman, Listningsko |
Läggs in i klassdiagrammen d02, d03 och d05 när F3–F7 byggs |
| Vårdkontakt och Vårdbegäran (utkast i NIM) | Följs, men mappningen versioneras | Ändringar i NIM blir nya mappningsversioner |
Diagrammen d01–d08 visar F0/F1-läget. Ändringarna ovan förs in i diagrammen efter F2 och F3 (öppen punkt C.4).
8.15 Förädlingar efter benchmark (planen 4k)#
Benchmarken jämförde Ersvia med 13 lösningar (bland andra NitCore, Privera, Vera Asyl, LOGEX, KUHR, LUNA, KBV Prüfmodul, SUS+, LAMDA/T2A och CMS PRICER) på 33 förmågor. Ingen av dem har bitemporal versionering med transaktionstid, så Ersvia behåller sin egen motor och lånar DMN:s semantik. Följande läggs in i MVP:n:
| # | Förädling | Förebild | Arkitektur i Ersvia | Fas |
|---|---|---|---|---|
| 1 | Inskickets livscykel: mottagen → kontrollerad → beslutad → utbetald, asynkron och idempotent, med anmärkningskoder per rad, webhooks och tre statusdimensioner (teknisk, kontroll, ekonomisk) | KUHR | Vardhandelser och Rapportering (status), Avstamning (vy), webhooks från outboxen. Diagram t05. |
F4, F8 |
| 2 | Publik och versionerad katalog över orsakskoder: vem som bär beloppet, vilken åtgärd som krävs, koppling till regelraden | CARC/RARC | Utbyggnad av contracts/legacy/felkoder.yaml (kap. 8.7) |
F4–F8 |
| 3 | Torrkörning före inskick: POST /…/validera validerar utan att spara. I R2 ett inbäddbart valideringspaket med certifieringssvit. |
KBV Prüfmodul | Vardhandelser (/vardhandelser/{id}/validering och torrkörning), samma Valideringskedja |
F4 |
| 4 | Konsultationsversion av nästa års regelpaket, som vårdgivare och nämnd kan simulera mot | NPK, IHACPA | Regelpaket med status konsultation och egen giltighet, körs i Simulering |
F7 |
| 5 | Frysdatum och namngivna ögonblicksbilder: aktuell, avstämd och slutlig per period | SUS+ | Berakning (underlagssnapshot med namn och frysdatum i faktureringskalendern). Manifestet refererar ögonblicksbildens hash. |
F6 |
| 6 | Riskbaserad efterkontroll med regler, riskpoäng och ärenden. AI-stöd och spårbar ROI i R2. | Granskning (kap. 5.4, s11) |
F7 | |
| 7 | Beslutstabeller med explicit hit policy och kontroll av luckor och överlapp | DMN | Regelverk (kap. 8.3) |
F3 |
| 8 | Skuggkörning: en ny regelversion och ERSMO/HEJ körs mot samma underlag, och skillnader förklaras | Simulering och Migrering. Legacyutfall importeras som legacy-manifest med källsystem och hash (kontroll 3 R11). |
F7, F10 | |
| 9 | KPI-jämförelse av simuleringar som underlag för nämnden | Simulering, Uppfoljning |
F7 | |
| 10 | Portal med drill-down och export. Rättelse per rad med frist, och ostridiga belopp betalas ut även när andra rader är bestridda. | Portal, Fakturering (delbetalning av ostridiga rader), Avstamning |
F8, F11 | |
| 11 | Korrigering av stängda perioder: rättelsen värderas som skillnaden mot tidigare utfall och torrkörs innan den genomförs | LAMDA | Berakning (Differensberaknare) och Fakturering (differensunderlag), s05 |
F6, F8 |
| 12 | Bevis vid publicering: testkörningen mot facit hashas och sparas med regelversionen | Regelverk (Facittestkorare) |
F3 |
R2 och senare: vårdgivarprognos ("vad får jag?"), inbäddbar validering, DMN-export med Drools som testorakel, en publik referenskalkylator per region och en förvaltningsmodell för flera regioner.
Positionering: modulpaket som kan offereras för 4–6 MSEK (till exempel utbetalning till privata vårdgivare, där Ersvia konkurrerar med NitCore och Privera), en asylmodul (Vera Asyl är i praktiken ensam, och Migrationsverket ställer om sin e-tjänst 2026) och ett körbart scenariobibliotek per anbud. Avtal att bevaka: NitCore Örebro 2028-10-31, Vera Asyl Skåne 2027-12-17 och VGR asyl 2028-04-22.