Audit-log

Hvad logges, hvorfor det logges, og hvor længe det gemmes.

Audit-loggen er Ressourcifys svar på "hvem gjorde hvad hvornår?". Hver mutation til kritiske entiteter giver en uforanderlig række i AuditLog.

Hvad logges

Alle handlinger med actor er kandidat — i praksis skrives audit ved alle CREATE/UPDATE/DELETE på følgende entiteter:

EntitetHvorfor logges
UserRolle- og status-ændringer påvirker adgang
UserRoleAdgangskontrol — kritisk for compliance
ProjectHvem ændrede projekt-data hvornår
AssignmentAllokeringer er kontraktlige forpligtelser
LeaveFravær-godkendelser sporbarhed
ForecastPlanPlanlægnings-ændringer over tid
EntraConfigSSO-konfigurations-ændringer
LeaveType, ForecastSizeKonfigurationsdata påvirker beregninger

Login og logout logges også (AuditAction.LOGIN, LOGOUT), samt eksport-handlinger (EXPORT).

Felter

FeltEksempelNote
organizationIdUUIDTenant-isolation
performedByUUID?null ved system-handlinger (autoprune, cron)
actionUPDATEEnum: CREATE/UPDATE/DELETE/LOGIN/LOGOUT/EXPORT
entityType"Assignment"Modelnavn (string, ikke FK)
entityIdUUIDID på påvirket række
oldValues{value: 50}Snapshot før (kun ved UPDATE/DELETE)
newValues{value: 75}Snapshot efter (kun ved CREATE/UPDATE)
createdAttimestampUTC

Audit-flow

Audit-skrivning sker i samme transaktion som mutationen — enten lykkes begge eller ingen. Hvis audit-INSERT fejler, rulles mutationen tilbage.

Hvad logges ikke

  • Reads — for støjende; ville fylde 99% af loggen
  • Bulk-batches — én linje per genereret/slettet Assignment, ikke én per batch
  • Auto-prunet data — efter retention slettes rækken; vi logger ikke "vi slettede audit-linjer"
  • Følsomme felterUser.passwordHash, EntraConfig.clientSecretEncrypted redactes til "<redacted>" i oldValues/newValues

Retention

Audit-loggen er ikke uendelig. Hver organisation har en retention-periode (standard 365 dage), som kan ændres af ORG_ADMIN:

Indstillinger → Sikkerhed → Audit-retention — vælg mellem 90, 180, 365, 730 eller 1825 dage.

Autoprune-jobbet

Én gang om dagen pr. organisation kører runAuditAutoprune():

  1. Læs lastRunDate fra AppConfig
  2. Hvis allerede kørt i dag → spring over
  3. Skriv today til lastRunDate (optimistisk lock)
  4. Beregn cutoff = now − retentionDays
  5. DELETE FROM AuditLog WHERE createdAt < cutoff

Idempotent: kører jobbet to gange samme dag, går runde 2 ud uden at slette noget.

Når en audit-linje først er autoprunet, kan den ikke genskabes. Eksportér til CSV før retention-grænsen hvis du har behov for længere opbevaring (fx revisions-formål).

Tilgang til audit

HandlingKrævet rolle
Læs audit-sideORG_ADMIN
Eksportér til CSVORG_ADMIN
Ændre retentionORG_ADMIN
Slet manueltIkke muligt — kun via autoprune

DEPT_ADMIN og COORDINATOR har ingen adgang til audit-loggen, heller ikke for egen afdeling. Begrundelsen er compliance: kun én rolle skal kunne se hele billedet.

Hvor finder du audit-siden

I sidemenuen under Org & System → Audit.

Filtre:

  • Periode (default seneste 30 dage)
  • Entity-type (User, Assignment, …)
  • Performer (drop-down med brugere)
  • Action (CREATE/UPDATE/DELETE/…)

Klik på en række for at se oldValues og newValues som JSON-diff.

Eksport til CSV

På audit-siden: filter → Eksportér CSV. Den downloades med felterne:

timestamp,performer,action,entityType,entityId,changedFields
2026-05-14T10:23:45Z,alice@acme.dk,UPDATE,Assignment,abc-…,value

Eksport-handlingen logger selv et EXPORT-audit-event — så "hvem eksporterede hele audit-loggen?" kan også besvares.

Hvor logikken bor

StiFunktion
lib/api/audit.tswriteAudit() — skriver én række
lib/audit/autoprune.tsrunAuditAutoprune() — daglig oprydning
lib/audit/config.server.tsLæser per-org retention fra AppConfig
app/api/v1/admin/audit/route.tsListe-endpoint med filtre

On this page