What is recorded
The audit trail holds who changed what about the system, and when. It is not a second set of books for your production data; it is the trace of interventions: configuration, rights, plugins, corrections.
The basic rule
Section titled “The basic rule”A new record produces no entry. It already carries its author and its time; mirroring that would be the same information twice. What is recorded instead:
| Case | Entry? | Why |
|---|---|---|
| capturing a record | no | the row carries author and time itself |
| correcting or deleting a record | yes | the previous state disappears from the row |
| changing how the system behaves (tag, right, plugin) | yes | it lives in no business table |
| an action by the AI | yes | required by the EU AI Act |
Cyclic machine values never reach the trail. They are measurements, not interventions.
What an entry consists of
Section titled “What an entry consists of”| Field | Content |
|---|---|
| Time | when it happened |
| Actor | the kind of actor (user, ai, machine, operator) and their identifier |
| Action | the act itself, for example tag.update |
| Target | what it happened to |
| Detail | the circumstances, different per action |
A machine entry is normal, not an anomaly: a connector writing a value because a telegram
arrived acts with no person behind it. An ai entry likewise — that the AI builds and acts
is part of the product, and precisely why it is written down.
What produces entries
Section titled “What produces entries”| Area | Actions |
|---|---|
| Data model | record_type.create, record_type.rename, record_type.delete, field.create, field.update, field.change-type, field.delete |
| Tags | tag.create, tag.update, tag.rename, tag.move, tag.copy, tag.delete, tag.deleteFolder |
| Connections | connection.create, connection.update, connection.delete |
| Scripts | script.create, script.update, script.move, script.copy, script.delete |
| Navigation | navigation.node.create, navigation.node.update, navigation.node.move, navigation.node.delete, navigation.reorder, navigation.tree.save |
| Roles | role.create, role.delete |
| Users | tenant-user.create, tenant-user.deactivate, tenant-user.reactivate, tenant-user.assignRole, tenant-user.unassignRole, tenant-user.setSecurityRole, tenant-user.delete |
| Plugins | plugin.install, plugin.install.rejected, plugin.enable, plugin.disable, plugin.uninstall, plugin.net.request |
| Trust anchors | trust_anchor.create, trust_anchor.revoke |
| Templates | configuration.load |
| Access | display-token.issue, display-token.revoke, offline-token.issue, offline-token.revoke |
| Records | record.update |
Refusals are in there too. A rejected plugin upload, a blocked user action, a plugin’s outbound network attempt that was denied — each leaves an entry carrying the reason in its detail. A trail that knows only the successes withholds exactly what somebody later goes looking for.
For record.update the detail names the fields that were written, never their values.
The trail is the trace of a change, not a second copy of your data.
Immutable, and for how long
Section titled “Immutable, and for how long”Entries can neither be changed nor deleted. The database itself enforces that: no role is granted the right, and a second bar refuses any attempt. Even loading a template, which otherwise empties the tenant, leaves the trail untouched.
There is no expiry today: nothing removes old entries. How long a trail has to be kept is deliberately still open and will be decided against the EU AI Act.
The audit trail is not logging
Section titled “The audit trail is not logging”The application’s operational log is a different thing: it helps with troubleshooting, it is short-lived, and it does not belong in the audit trail. The two are never mixed.