Skip to content

The Activity Log and Its Sources

The activity log is a chronological list of all history of the dialog. The history is derived from different sources, consolidated and collected in one timeline.

SourceComes fromContributes
Activitiesdialog.activities on the dialog itselfOne sentence per activity
Transmissionsdialog.transmissions on the dialog itselfAn expandable card, or one sentence, depending on visibility
Notification lognotificationLogs(dialogId), a separate queryOne sentence per correlated dispatch
Label assignment loglabelAssignmentLog(dialogId), a separate queryOne sentence per label change worth reporting

They are combined in getActivityHistory and sorted by date, newest first. The two newest sources are behind feature flags — dialogDetails.enableNotificationLogs and dialogDetails.enableLabelAssignmentLogs, both off by default — so the log degrades to activities and transmissions when either is unavailable.

  • One list, not sections. Nothing gets its own heading or its own component. A new source earns a line in the existing log or it does not ship.
  • One entry, one sentence. The only exception is a fully visible transmission, which is a card because it has expandable content.
  • Active voice, actor first, actor emphasised. “Kari Nordmann flyttet meldingen til arkivet.” This is what makes four unrelated sources read as one log rather than as interleaved voices. A sentence with no actor — a notification, a transmission the user cannot open — says what happened to the thing itself rather than inventing someone to do it.
  • It is a melding, never a dialog. Dialog is the data model; the sentence uses the word the user knows it by.
  • One actor resolution. Every source runs performedBy through the same getActorProps, so person-name flipping (dialogporten.disableFlipNamesPatch), system-user and organisation detection from the actorId URN, and the service-owner fallback to senderName or the organisation name behave identically everywhere. A service owner arrives with no actorId and no actorName and resolves to the dialog’s sender name when one is given, otherwise the organisation name.
  • The timestamp is the sort key and the byline. Entries with the same timestamp keep the order their source returned them in.

The most direct source: each DialogActivityFragment maps by its type to one sentence.

ActivityTypeBokmål
DialogCreated{actor} opprettet meldingen.
DialogOpened{actor} åpnet meldingen.
DialogClosed{actor} lukket meldingen.
DialogDeleted / DialogRestored{actor} slettet / gjenopprettet meldingen.
Information{actor}: {description}
TransmissionOpened{actor} åpnet «{transmission}».
FormSaved / FormSubmitted{actor} lagret / sendte inn skjemaet.
PaymentMade{actor} betalte.
SignatureProvided{actor} signerte.
SentTo…{actor} sendte meldingen til skjemautfylling / betaling / innsending / signering.
CorrespondenceOpened / CorrespondenceConfirmed{actor} åpnet / bekreftet meldingen.

Information is the only type carrying service-owner-authored text; the rest are fixed sentences. The transmission title is free text in the middle of a sentence, so it is quoted.

Same event, same sentence; different event, different verb. DialogOpened and CorrespondenceOpened both read åpnet meldingen, because to the user they are the same thing. DialogRestored keeps gjenopprettet: it undoes a deletion, which is not the same as bringing a message back from the bin — that is a label change, and reads flyttet meldingen til innboksen.

Unknown types are printed raw. An ActivityType with no case falls through to rendering the enum value itself. See Where the sources disagree.

A transmission is classified before it is rendered, and the classification decides whether the user gets a card or a sentence. The order of the checks matters — the first match wins.

#ConditionOutcome
AHas attachments, none GUI-consumable, no summary and no content referencefilter — dropped from the timeline, shown in the log as “Forsendelse kun med maskinlesbart vedlegg”
BisAuthorized is falsedisabled — card stays in the timeline but cannot expand; in the log it reads “Forsendelse du ikke har tilgang til”
CAuthorized, but no summary, no content reference and no GUI attachmentempty — expands to an empty-state explanation; in the log only the title is shown
DAnything elsevisible — a normal expandable card

Only D becomes a card in the log. A, B and C become plain sentences, because there is nothing worth expanding. The sentence for B ends in a preposition, so tilgang til (and access to) is joined by a non-breaking space: on a narrow screen the line would otherwise break before til, and the first line reads as a complete sentence without it.

Related transmissions are grouped into one segment via relatedTransmissionId, resolved as a bidirectional graph so a chain of replies collapses into a single entry rather than several.

This source is an MVP, and its rules are mostly about not flooding the log.

The BFF filters the upstream log before it answers notificationLogs, so everything the frontend receives is worth a line:

  • Only delivered notifications. Delivered passes. Every other status — in flight, handed off but not confirmed, or failed — is dropped. The log reports what the user actually received.
  • Statuses carry no channel prefix. The log returns Delivered, not the Email_Delivered / SMS_Delivered shown in Altinn’s status reference. The channel is in its own field.
  • Instant and Composed dispatches are dropped. Notification, Reminder and any type we do not recognise pass through.
  • lastUpdateTime decides placement. For a delivered notification it is when the provider reported the delivery, so the entry sits where the user actually got it.
  • A dispatch to several recipients sits at the latest of their delivery times, because only then is ”… til A, B og C ble levert” true.
  • When no delivery time was reported, the requested send time is used instead. With neither, the entry has no position and is dropped.

The API has no correlation id, so Arbeidsflate derives one: type + channel + transmissionId + requestedSendTime. The recipients of one dispatch share its requested send time, while each has a delivery time of its own — which is why grouping and placement use different timestamps.

  • The same dispatch to several recipients becomes one entry.
  • When no send time was reported, the last update time stands in for it in the key.

The sentence is {type} på {channel} til {recipients} ble levert. Only delivered notifications reach the frontend, so the outcome is part of the sentence rather than a slot of its own.

  • The notification is the subject. There is no actor to put first, so the sentence says what happened to the dispatch.
  • The channel is named once, in its own slot. Delivery reads “ble levert” whether it went by email or SMS.
  • Only Reminder gets its own word, because “påminnelse” tells the user something real. Everything else is “Varsel”.
  • At most three recipients are listed, the rest are counted. Without the cap, one dispatch to many organisation addresses fills the log with addresses.
  • An unknown value degrades, it does not hide. An unknown type becomes “Varsel” and an unknown channel “ukjent kanal”. Hiding a notification the user actually received is worse than describing it generically — and the gap would be invisible to us.

End-user system label changes: where the dialog sits for this user. The operations are set and remove; the labels are DEFAULT, ARCHIVE, BIN, SENT and MARKED_AS_UNOPENED.

Names arrive prefixed — systemlabel:MarkedAsUnopened. Parsing ignores the prefix, the casing and any underscores, so the API’s PascalCase and the GraphQL enum’s SCREAMING_SNAKE_CASE land on the same label. Removals are accepted as both remove and removed.

  • SENT is never shown. It is logged as set by the service owner after the dialog was created, which makes it an attempt to put the dialog in a desired state rather than something a user did. Future labels should be judged by the same test: is this a user operation?
  • An entry that cannot become a sentence is dropped, never printed raw. This is safe because a unit test requires every value of the SystemLabel enum to have both a set and a remove sentence in nb, nn and en — a new label upstream fails the build instead of silently disappearing.
  • DEFAULT is never set. The platform expresses “in the inbox” as the absence of the other two folder labels, so moving a dialog back to the inbox is a remove of ARCHIVE or BIN, never a set of DEFAULT. The set of DEFAULT has a sentence, but it is not reachable with current API behaviour.
  • A move says where the message went, in the words of the buttons. Flytt til arkivet, Flytt til papirkurven and Flytt til innboksen are logged as flyttet meldingen til arkivet, til papirkurven and til innboksen. So the remove of ARCHIVE or BIN reads flyttet meldingen til innboksen, and where the message came from is usually the entry below it. Like the button, it says innboksen even when the message also carries SENT and so lands in Sendt.
  • One move, one sentence. The folders are mutually exclusive, so a move writes a set of the destination and a remove of the origin at the same instant. Entries are grouped by (timestamp, actor), and a remove of a folder label is dropped when the same group holds a folder set. Moving from the bin to the archive says the dialog was archived — not that it first lost its bin label.
  • A remove that arrives alone is still shown. This is not an edge case: it is how the return to the inbox appears, and it is what happens when the dialog is updated — the platform clears the archive or bin label so the dialog resurfaces, and seeing why it reappeared is the useful part.
  • Read and unread are never collapsed. MARKED_AS_UNOPENED sits outside the folder logic, so both directions say something. ”… markerte meldingen som lest” is what a reader sees when a dialog they had marked unread is opened again.
  • Different actors never collapse into each other. The actor is part of the grouping key, so a set by a user and a remove by the service owner in the same instant are two events by two parties, and both are reported.

All eight follow the shared form, {actor} … meldingen ….

Labelsetremove
BINflyttet meldingen til papirkurvenflyttet meldingen til innboksen
ARCHIVEflyttet meldingen til arkivetflyttet meldingen til innboksen
DEFAULTflyttet meldingen til innboksen (unreachable)flyttet meldingen ut av innboksen
MARKED_AS_UNOPENEDmarkerte meldingen som ulestmarkerte meldingen som lest

Nynorsk and English carry the same meaning.