audit PK: id 6 required 1 unique

Description

An immutable, append-only record of significant system events — authentication events, data access, approval decisions, role changes, and sensitive data operations. Supports compliance requirements for GDPR and Bufdir grant auditing. No update or delete operations are permitted on this table.

15
Attributes
9
Indexes
8
Validation Rules
13
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Immutable primary key generated server-side at insert time. Never client-provided.
PKrequiredunique
actor_id uuid Foreign key to users.id — the authenticated user who triggered the event. May be null only for system-initiated events (cron jobs, scheduled tasks).
-
organization_id uuid Foreign key to organizations.id — the top-level organization context for tenant scoping. Required for all non-global events.
-
association_id uuid Foreign key to local_associations.id — the local association context when the event is scoped below the organization level. Null for org-level and global events.
-
event_type enum Classification of the event that occurred. Drives querying, alerting, and compliance report generation.
required
resource_type string The type of entity affected by this event. Combined with resource_id to identify the specific record. Examples: 'user', 'activity', 'reimbursement', 'assignment', 'certification', 'role', 'organization'.
required
resource_id string The identifier of the affected resource. Stored as string to accommodate UUIDs and composite keys across all entity types without FK constraint (avoids cross-table coupling).
-
action string Human-readable description of the specific action taken, e.g. 'approved reimbursement', 'changed role from peer_mentor to coordinator', 'exported bufdir report Q1-2025'. Supplements event_type for audit display.
required
previous_state json Snapshot of the relevant resource state before the action. Null for create and access events. Must not include raw encryption keys or raw biometric data. Sensitive fields (personnummer, medical data) must be masked before storage.
-
new_state json Snapshot of the relevant resource state after the action. Null for delete and access events. Same masking rules as previous_state apply.
-
metadata json Flexible bag of contextual data specific to the event_type. For auth events: ip_address, user_agent, provider. For approval events: notes, threshold_evaluated, rule_name. For bulk operations: affected_ids array, count. For export events: format, period, record_count.
-
ip_address string IPv4 or IPv6 address of the client at the time of the event. Populated for authentication and sensitive data access events. May be null for system-initiated background events.
-
session_id uuid Reference to the sessions.id value active at the time of the event. Allows grouping all events within a single authenticated session. Null for system events.
-
severity enum Risk classification of the event for monitoring and alerting thresholds. Used by compliance dashboards to surface high-severity events.
required
created_at datetime Server-side UTC timestamp set automatically at insert. Never provided by the client. Indexed for time-range queries and retention policy enforcement.
required

Database Indexes

idx_audit_log_actor_id
btree

Columns: actor_id

idx_audit_log_organization_id
btree

Columns: organization_id

idx_audit_log_event_type
btree

Columns: event_type

idx_audit_log_resource
btree

Columns: resource_type, resource_id

idx_audit_log_created_at
btree

Columns: created_at

idx_audit_log_org_created_at
btree

Columns: organization_id, created_at

idx_audit_log_actor_created_at
btree

Columns: actor_id, created_at

idx_audit_log_association_id
btree

Columns: association_id

idx_audit_log_severity
btree

Columns: severity, created_at

Validation Rules

event_type_valid_enum error

Validation failed

resource_type_non_empty error

Validation failed

action_description_non_empty error

Validation failed

metadata_valid_json error

Validation failed

previous_and_new_state_valid_json error

Validation failed

ip_address_format error

Validation failed

severity_default_info warning

Validation failed

no_duplicate_rapid_fire_inserts warning

Validation failed

Business Rules

append_only_immutability
always

No UPDATE or DELETE statements may be executed against the audit_logs table under any circumstances. The table must be enforced as append-only at both the application layer (no update/delete methods in AuditLogRepository) and the database layer (a PostgreSQL row-level security policy or trigger that rejects all UPDATE and DELETE operations).

Enforced by: Audit Log Repository
server_side_timestamp
on_create

created_at must always be set by the server using NOW() at insert time. Client-provided timestamps must never be accepted. This ensures the audit trail cannot be forged or backdated.

Enforced by: Audit Log Repository
sensitive_field_masking
on_create

Before writing previous_state or new_state snapshots, components must mask sensitive personal data fields — personnummer, full medical data (epikrise contents), encryption keys, and raw biometric payloads. Masked values are stored as '[REDACTED]' strings. This satisfies GDPR Article 25 data minimisation in audit storage.

system_event_actor_null_allowed
on_create

For scheduled background jobs (certification expiry, badge evaluation, annual summary aggregation) the actor_id may be null and a system_event event_type must be used. All user-initiated events must include a non-null actor_id.

Enforced by: Audit Log Repository
mandatory_approval_logging
on_create

Every reimbursement approval, rejection, or clarification action — whether automated or manual — must produce an audit log entry before the status change is committed. The audit write and the status update must be within the same database transaction.

mandatory_role_change_logging
on_create

Every user role assignment, removal, or modification must produce an audit log entry capturing the previous role and new role. This is required for GDPR accountability and Bufdir grant compliance.

org_scoping_required_for_non_global
on_create

All events that are not of event_type 'system_event' or global admin actions must include a non-null organization_id. Events below the org level (coordinator actions, local association operations) must also include association_id.

Enforced by: Audit Log Repository
no_cross_tenant_reads
always

Read queries against audit_logs must always include an organization_id filter matching the requesting user's organization. Coordinators are further restricted to entries where association_id matches their association membership. Global Administrators may query across all organizations.

critical_severity_for_auth_failures
on_create

Authentication failure events (auth_login_failed, auth_biometric_failed) must be recorded with severity='critical'. Repeated failures for the same actor within a 15-minute window should be flagged in metadata for monitoring systems.

Enforced by: Audit Log Repository

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
by_date
Retention
Permanent Storage