Slik fungerer det
Pipelinen: oppdag, filtrer, hent, lever, registrer
Den headless workeren behandler alle tenantens organisasjonsnumre i én enkelt seriell løkke, med én pipeline-kjøring per org-nr per syklus (det kjører én worker per tenant). Altinn (Dialogporten) er den autoritative arbeidskøen. Hver kjøring gjenoppdager fra Altinn; workeren holder ingen lokal innbokstilstandsmaskin.
Som standard kjøres pipelinen på et fast intervall, med henting hver fjerde time; hyppigere
henting kan avtales særskilt. I tillegg finnes en hendelsesdrevet modus (eksperimentell)
der workeren poller Altinn Events-feeden for de overvåkede tjenesteressursene og bare
kjører full oppdagelse når det faktisk har skjedd noe. Feeden filtreres på hendelsestyper som betyr
nytt eller endret innhold, slik at for eksempel lest-kvitteringer ikke utløser kjøringer. Posisjonen i
feeden lagres i leveringsloggen, så en omstart fortsetter der den slapp. Et planlagt sikkerhetsnett
kjører uansett pipelinen med jevne mellomrom, slik at ingenting går tapt om en hendelse skulle utebli.
Modusen krever scopet altinn:events.subscribe på tenantens innloggingsklient.
Hendelsesmodusen kan i tillegg settes opp med push-vekking: innloggings-appen registrerer da abonnementer i Altinn Events som peker på dens eget webhook-endepunkt, og en levering derfra vekker workeren fra null via en intern vekkekø. Selve varselet inneholder bare metadata (hendelses-id, ressurs og part), aldri innholdet i posten; workeren henter uansett alt gjennom den autentiserte pull-flyten fra sist lagrede posisjon. Slik kan workeren skaleres helt ned når det ikke er aktivitet, uten at noe går tapt om et varsel skulle utebli.
- Oppdag: spør Dialogporten search API for tenantens org, filtrert til nye/uleste elementer og relevante avsendere. Oppdagingen kjører på en fast tidsplan (tidsplanlagt polling).
- Filtrer: bruk avsender-, vedleggsutvidelse- og hent-etter-dato-filtrene. Filtrerte elementer får ingen logg-skriving og re-evalueres billig hver kjøring.
- Hent: for hver ny dialog, hent korrespondansedetaljer for å liste opp vedlegg, og strøm deretter hvert vedlegg fra dets endepunkt med et gyldig access-token og korrekt scope.
- Lever: skriv vedlegget til Blob-droppsonen. Se Droppsone for navnekonvensjon og format.
- Registrer: skriv utfallet til leveringsloggen (idempotens + dead-letter), re-assert
MarkedAsUnopenedpå dialogen slik at tenantens innbokstilstand bevares (eller arkiver dialogen, hvis dere har valgt arkivering etter levering, se nedenfor), og emit telemetri til driftspartnerens sentrale overvåkingsmiljø. Telemetrien er avgrenset til tekniske driftsdata, uten innhold og uten filnavn, se Personvern og datahåndtering.
Hvorfor vi re-asserterer MarkedAsUnopened
Dialogporten regner en dialog som «sett» hvis den er hentet etter siste innholds-oppdatering
og ikke har systemetiketten MarkedAsUnopened. Vår listing flytter «sist hentet»-tidspunktet,
så uten et mottiltak ville pipelinen indirekte flippe dialogen fra ulest til lest i sluttbrukerens
Altinn-innboks. Etter hver behandlet dialog re-setter tjenesten derfor MarkedAsUnopened,
og en mislykket re-assertion logges men avbryter ikke leveringen.
Effekt: sluttbrukeren ser dialogen som ulest i Altinn-innboksen etter at vi har behandlet den, og kan selv markere den som lest når de faktisk åpner den.
Valgfri arkivering etter levering
Som tilvalg per tenant kan tjenesten i stedet arkivere dialogen i Altinn etter fullført
levering, slik at Altinn-innboksen viser hva mailroomen allerede har håndtert. Når alle vedlegg
i en dialog har fått et endelig utfall i leveringsloggen og minst ett av dem faktisk ble levert
til droppsonen, settes systemetiketten Archive og dialogen flyttes til arkivmappen. Den
markeres da ikke som ulest, en arkivert dialog er per definisjon håndtert.
Merk presiseringene:
- Dialoger der ingenting ble levert (alt filtrert ut, eller levering ga opp etter gjentatte feil) blir stående urørt i innboksen som ulest, akkurat som i standardoppførselen. Arkivet skal aldri skjule post dere ikke har fått i droppsonen.
- Arkiveringen skjer først etter at leveringsloggen har registrert leveransen. En feil under arkiveringen logges, men feiler aldri selve leveringen; dialogen blir da liggende ulest i innboksen og filene er uansett trygt levert.
- Angring trenger ingen egen funksjon: dere kan når som helst flytte dialogen tilbake fra arkivmappen i Altinn-innboksen.
Standard er av, altså oppførselen beskrevet ovenfor der innbokstilstanden bevares. Tilvalget aktiveres av driftspartneren for deres utrulling.
Manuelle systemetikett-operasjoner
For operatør-initierte korrigeringer kan tjenesten utføre fire systemetikett-operasjoner
mot en dialog via Dialogportens systemlabels-endepunkt
(PUT /api/v1/enduser/dialogs/{id}/context/systemlabels): markere som lest/ulest og
arkivere/av-arkivere.
| Operasjon | Effekt |
|---|---|
| Marker som lest | Fjerner MarkedAsUnopened. |
| Marker som ulest | Setter MarkedAsUnopened. |
| Arkiver | Flytter dialogen til Archive (fjerner Default/Bin). |
| Av-arkiver | Flytter dialogen tilbake til Default (fjerner Archive/Bin). |
Default/Bin/Archive er gjensidig utelukkende på Dialogporten-siden; arkiv-operasjonene
sender med begge andre i removeLabels slik at kallet er idempotent uavhengig av dialogens
nåværende mappe. Sent settes kun av Dialogporten selv og kan ikke endres av oss.
Av disse er arkivering den eneste pipelinen selv utfører, og bare når tilvalget ovenfor er
aktivert. Ellers er den eneste automatiske systemetikett-handlingen re-assertion av
MarkedAsUnopened.
Leveringsloggen
Loggen er en liten, holdbar oversikt over vedlegg vi har allerede fullført: en idempotens-
og dead-letter-vakt, ikke en arbeidskø. Én post per (correspondenceId, attachmentId),
skrevet etter at et utfall er kjent.
| Tilstand | Betydning |
|---|---|
Delivered | Terminal. Hoppes over på alle fremtidige kjøringer, selv etter at bloben er slettet. |
Retrying | Et leveringsforsøk mislyktes; attempts < MaxDeliveryAttempts. |
Abandoned | Terminal poison-melding: attempts == MaxDeliveryAttempts. Varslet én gang; aldri prøvd igjen. |
Delivered-posten overlever vedlegget: droppsonen har kort GDPR-oppbevaring og vedlegg
slettes når de er samlet inn. "Blob eksisterer" kan ikke være idempotens-nøkkel, for da ville
et slettet element lastes ned på nytt og hente persondata vi bevisst slettet.
Autentisering: ID-porten + BankID nivå 4
Et rent maskin-til-maskin-token (Maskinporten med en systembruker) kan fastslå hvilken organisasjon som representeres, men det kan ikke bære et personlig høyt sikkerhetsnivå. Sensitiv korrespondanse (NAV, Namsmannen) er sperret ved sikkerhetsnivå 4 (BankID / Buypass / Commfides), som kun en personlig ID-porten-innlogging kan oppfylle. Kjøretiden er derfor menneskebakket, ikke M2M.
acr_values=idporten-loa-highlåser nivå 4, og nivået kontrolleres iid_token-et etterpå. Tokenet valideres kryptografisk mot ID-portens egne signeringsnøkler, så kravene i det er bevist, ikke bare lest.- Scope inkluderer
offline_accessfor å få et refresh-token: den langvarige legitimasjonen innloggings-appen bruker til å prege kortvarige access-tokens som workeren leser. - Klienten autentiserer med
private_key_jwt; ID-porten krever klientautentisering på token- og refresh-grants for en konfidensiell klient.
Token-livssyklus og re-autentiseringsflyt
- En autorisert ansatt besøker innloggings-siden og logger inn via ID-porten + BankID nivå 4.
- Det resulterende tokensettet (id-, access- og refresh-token) skrives til tenantens Key Vault og passerer aldri gjennom Managed Service Providers infrastruktur. Id-tokenet bærer identiteten til medarbeideren som logget inn; se Personvern og datahåndtering.
- Innloggings-appen eier fornyelsen: en bakgrunnstjeneste fornyer access-tokenet før det utløper og skriver det tilbake til Key Vault. Den er den eneste skriveren mot det roterende refresh-tokenet — flere uavhengige fornyere ville ugyldiggjort hverandre — så fornyelsen er sentralisert her, og innloggings-appen holdes alltid varm (skalerer ikke til null).
- Ved hver kjøring leser workeren det gjeldende access-tokenet fra Key Vault (kun lesetilgang), bytter det mot et Altinn-plattform-token og kaller Dialogporten og attachment-endepunktene. Workeren fornyer aldri selv.
- Refresh-tokenet utløper etter ~90 dager (eller en fornyelse feiler); et Azure Monitor-varsel utløses og en ansatt re-autentiserer.
Autorisasjon: én innlogging dekker tenantens org-numre
Et ID-porten-token virker bare for organisasjonene der den innloggede personen har Altinn-roller
(samme virkelighet som CORR-04001: en ikke-rollehaver får
ikke hente korrespondansen). Workeren bruker ett delt token for alle organisasjonsnumrene den
behandler, så den som logger inn må holde de nødvendige Altinn-rollene for hvert
organisasjonsnummer tenanten behandler. I praksis er dette én utpekt person (typisk DAGL) som dekker alle org-numrene.
Lageret holder ett token om gangen — logger en annen person inn, overskrives det forrige (siste innlogging vinner). Modellen er altså én aktiv innlogging: flere personer kan bytte på å re-autentisere, men ikke bære hvert sitt token samtidig. Genuint samtidige per-person-tokens (ulike personer for ulike org-numre på én gang) ville krevd per-org nøkkeldelte hemmeligheter i stedet for det delte tokenet — bevisst utenfor scope her, der ett delt token gir lavest kompleksitet og angrepsflate.
Systemoversikt
Høynivå arkitektur for Digital Mailroom med komponenter, de to planene og teknologivalg.
Droppsone
Droppsonen er standard leveringsmål og grensesnittet mellom Digital Mailroom og tenantens øvrige systemer. Tjenesten leverer vedlegg hit og gjør ingenting annet. Videre prosessering er tenantens ansvar. For nedstrøms systemer som leser fra et lokalt Windows-filsystem finnes et alternativt leveringsmål med samme navnekonvensjon og metadata: levering til filshare.