Audit

Immutable trail of every data operation

The audit block records who did what, to which record, and when. When enabled, a database audit transport is attached to the logger and writes structured rows to the audit_logs table — capturing the entity name, entity id, acting user, operation and outcome.

Because it hangs off the central logger, audit coverage spans both generated entity routes (create/update/delete) and the auth routes (login, logout, password change, session revocation), giving you one coherent security timeline.

You control the cost/coverage trade-off per operation type: log every read, or only the writes that mutate state.

Enabling audit#

A single switch attaches the database audit transport. Without it, audit entries are not persisted.

enabledbooleanOptional

Turn on persistent audit logging. On startup the framework wires a DatabaseAuditTransport to the audit_logs table; every audited operation then writes a row with entity_name, entity_id, user_id, action and timestamp.

Defaultfalse

Per-operation toggles#

Choose exactly which operation types are recorded. Reads (GET) are high-volume and often left off; mutations are usually all on. Omit actions entirely to accept the framework defaults.

config.nucleus.json — audit
1{2  "audit": {3    "enabled": true,4    "actions": {5      "GET": false,6      "INSERT": true,7      "UPDATE": true,8      "DELETE": true,9      "TOGGLE": true,10      "VERIFICATION": true11    }12  }13}
actionsobjectOptional

Boolean switch per operation type.

GETbooleanOptional

Record read access. High volume — enable only when you need read auditing (e.g. sensitive data access).

INSERTbooleanOptional

Record row creation.

UPDATEbooleanOptional

Record row updates.

DELETEbooleanOptional

Record row deletions.

TOGGLEbooleanOptional

Record soft enable/disable (is_active) toggles.

VERIFICATIONbooleanOptional

Record verification decisions (approve/reject) from the approval flows.

Under the hood — what a row captures#

Audit isn't a separate subsystem — it's the logger's audit path. logger.audit() (and trace() when auditEnabled) builds an entry and the DatabaseAuditTransport writes it, so audit and logs share one component and one correlation id.

captured columnsaudit_logs rowOptional

Each row records id, entity_name, entity_id, operation_type, user_id, ip_address, user_agent, a human summary, the before/after old_values and new_values, plus the request path and query — a complete forensic record, not just 'who and when'.

old / new valuesstructured diffOptional

Writes capture the prior and resulting field values, so an audit row is also a diff: you can see exactly what changed, which is what makes the trail useful for compliance reviews and incident forensics.

correlationshared with logsOptional

Because the same Logger writes both, an audit row and the request's log lines carry the same correlation id — you can pivot from 'this record changed' to the full request trace that changed it.

Related sections