Audit Log
Data Entity
Description
Immutable, append-only chronological record of all significant actions performed within the Meander platform. Captures actor identity, action type, affected entity, outcome, and contextual metadata for every write operation. Serves as the tamper-evident compliance trail required under GDPR and Norwegian data protection law, and as the primary data source for the Security Dashboard, session monitoring, and activity approval audit trails.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Immutable primary key generated server-side at insert time. Never reused. | PKrequiredunique |
organization_id |
uuid |
FK to organizations. Scopes the entry to a specific tenant. NULL for platform-level system events performed by global admins or internal services with no org context. | - |
actor_id |
uuid |
FK to users. The authenticated user who triggered the action. NULL for automated system actions (e.g., auto-approval rule engine, scheduled jobs, sync orchestration). | - |
actor_role |
enum |
The role the actor was acting under at the time of the event. Captured at write time because roles can change. NULL for system actors. | - |
action |
string |
Dot-namespaced action identifier describing what occurred. Format: <entity_type>.<verb> (e.g., 'activity.approved', 'user.deactivated', 'expense.rejected', 'session.revoked', 'role.assigned', 'export.generated', 'login.failed', 'login.succeeded', 'bulk_operation.executed', 'assignment.dispatched'). | required |
entity_type |
string |
Type of the primary domain entity affected by the action (e.g., 'activity', 'user', 'expense', 'session', 'assignment', 'organization', 'role', 'export'). Used with entity_id to reconstruct the full audit trail for a specific record. | - |
entity_id |
string |
The UUID or identifier of the entity affected. Stored as string to accommodate composite or non-UUID keys. Must be present when entity_type is set. | - |
outcome |
enum |
Result of the action. 'success' = completed as intended. 'failure' = rejected or unauthorized. 'error' = unexpected system-level exception. | required |
severity |
enum |
Severity classification used by the Security Dashboard and alert evaluator for threshold-based alerting. | required |
source |
enum |
Origin of the action. 'user' = explicit user interaction. 'system' = automated background process (cron, event listener). 'api' = external API call (integrations, webhooks). 'auto' = auto-approval or rule engine. | required |
metadata |
json |
Structured contextual payload. Contains before/after state snapshots for mutations, filter parameters for queries, rejection reasons, correction diffs, batch size for bulk operations, rule ID for auto-approval events. Schema is action-specific. Must never contain PII beyond the actor/entity IDs already captured in dedicated columns. | - |
ip_address |
string |
IPv4 or IPv6 address of the originating request. Captured for authentication events and sensitive data access. NULL for server-initiated background actions. | - |
user_agent |
string |
HTTP User-Agent header from the originating request. Used for session fingerprinting and anomaly detection on the Security Dashboard. NULL for background jobs. | - |
session_id |
uuid |
FK to sessions. Links the audit event to the active session that triggered it. NULL for system-initiated actions with no user session context. | - |
correlation_id |
string |
Distributed trace ID propagated through a multi-step operation (e.g., a bulk export that writes multiple audit entries). Allows all related events to be retrieved together for incident investigation. | - |
created_at |
datetime |
UTC timestamp set by the database server at insert time using now(). Never provided by the client. The primary ordering column for all audit log queries. | required |
Database Indexes
idx_audit_log_org_created
Columns: organization_id, created_at
idx_audit_log_actor_created
Columns: actor_id, created_at
idx_audit_log_entity
Columns: entity_type, entity_id
idx_audit_log_action_created
Columns: action, created_at
idx_audit_log_org_action_created
Columns: organization_id, action, created_at
idx_audit_log_session
Columns: session_id
idx_audit_log_correlation
Columns: correlation_id
idx_audit_log_created_at
Columns: created_at
Validation Rules
entity_type_and_id_pair
error
Validation failed
action_format
error
Validation failed
created_at_server_only
error
Validation failed
actor_or_source_present
error
Validation failed
metadata_no_raw_pii
error
Validation failed
organization_id_matches_actor_org
error
Validation failed
Business Rules
append_only
Audit log records are immutable. No UPDATE or DELETE operations are permitted under any circumstance, including administrative correction workflows. Corrections are achieved by inserting a new correction event referencing the original entry ID in metadata.
write_within_transaction
Audit events for data-mutating operations (approve, reject, deactivate, role change, bulk action) must be inserted within the same database transaction as the primary mutation. If the primary write fails and rolls back, the audit entry must also be rolled back. This ensures the audit log reflects only committed state changes.
tenant_isolation_on_read
All read queries against audit_logs must include an organization_id WHERE clause unless the caller is a Global Admin. Global Admins may query across all organizations. Org Admins and Coordinators are restricted to their own organization's records.
authentication_events_always_logged
Every login attempt (success or failure), logout, token refresh, and session revocation must produce an audit entry regardless of outcome. Failed authentication events must be logged even before a session exists.
sensitive_data_access_logged
Access to encrypted assignments, personal health data, and bulk export operations must produce audit entries with entity_type, entity_id, and actor details. This supports GDPR Article 30 records of processing activities.
system_actions_use_null_actor
Automated system actions (auto-approval rule engine, scheduled sync jobs, background notification dispatch) must set actor_id to NULL and source to 'auto' or 'system'. They must never be attributed to the last authenticated user.
global_admin_cross_org_entries_use_null_org
Audit entries created by Global Admin actions that are not scoped to a specific organization (e.g., system-wide configuration changes, cross-org session revocation) must use NULL for organization_id to prevent false inclusion in org-scoped tenant queries.
bulk_operations_use_correlation_id
Bulk actions (bulk user deactivation, bulk activity approval, bulk export) must populate correlation_id with a shared identifier across all individual audit entries generated by the same bulk operation. Enables reconstruction of the full batch scope during incident investigation.