Skip to content

Audit Logs

Every mutation in oikapi is recorded in an immutable, append-only audit log. This includes record changes, schema modifications, permission changes, and authentication events.

OperationDetails tracked
Record createUser, table, new values
Record updateUser, table, before/after diff
Record deleteUser, table, deleted values
Schema changesTable/field creation, modification, deletion
Auth eventsLogin, logout, credential access
Permission changesGrants, revocations, role assignments

Audit history is read through dedicated, permission-aware endpoints rather than generic record queries:

GET /api/apps/{app}/tables/{table}/records/{record_id}/history
GET /api/apps/{app}/tables/{table}/activity

The first returns the change history for a single record; the second returns recent activity across the whole table. Both use cursor-based pagination.

Each log entry contains:

FieldDescription
idUnique identifier for this audit entry
operationcreate, update, or delete for record history; CREATE, UPDATE, DELETE, or other action codes for table activity
userObject with id, name, and email of the actor
changesStructured change record (see below)
timestampWhen the change occurred
versionMonotonic version counter; only populated on table-activity entries (/activity endpoint) — always 0 in record history (/history) responses

The changes field carries a structured change record. Each key is a field name, and each value is a two-element array [old_value, new_value]. For create operations the old value is null; for delete operations the prior record is captured under a _deleted_ key.

{
"status": ["draft", "active"],
"budget": ["10000.00", "15000.00"]
}

System and auto-generated fields (such as created_at, updated_at, created_by, updated_by) are excluded from change records, so diffs focus on meaningful business changes.

Audit log diffs are filtered based on the requesting user’s field-level permissions. If a user cannot read the salary field, they won’t see salary changes in audit logs either. Admins see complete, unfiltered diffs.

Fields can be marked as PII (pii: true) or sensitive (sensitive: true) when creating or adding fields to a table. PII and sensitive field values are excluded from full-text search indexes. Note that field-level PII redaction inside audit log diffs (record history) is not yet implemented — raw values are visible to users who have read access to the record. For audit trail exports (the download endpoints), the actor’s email address and IP address are redacted via the oikapi/redaction module (on by default in production, off in development).

Permission and role changes are tracked in a separate, append-only audit trail with these change types:

  • permission_created, permission_updated, permission_deleted – Permission grant changes
  • role_created, role_updated, role_deleted – Role definition changes
  • role_assigned, role_revoked – Role assigned to or removed from a user

Nothing is ever permanently deleted in oikapi. Deleted records, tables, and fields are deactivated rather than destroyed. The audit trail is always preserved.