Audit and Events
Each write through TotalBase does three things in the same PostgreSQL transaction:
the write + an audit entry + an event = one transaction
If any part fails, all of it rolls back. You'll never find a change without its audit entry, or an event for a change that didn't commit.
The audit log
The audit log, totalbase.logs, records:
| Entry | When |
|---|---|
| Creates, updates and deletes through the Data API | always, successful or not |
| Function calls | always |
| Sign-ins and access changes: roles, permissions, tokens, settings | always |
| Schema changes, SQL Console statements, maintenance | always |
| Imports, exports and prints from a DataView grid | one entry per operation |
| Reads | only for resources where you turn read auditing on |
Each entry says who acted (a user, or a token), from where (api, app, admin, workflow), on which resource, with which result (EXECUTED, DENIED or FAILED), and how long it took. Refused and failed writes are recorded too, with PostgreSQL's error.
What a write records
A create or delete stores the row. An update also stores, for each column it changed, the old and the new value:
{ "status": { "old": "IN_PROGRESS", "new": "COMPLETED" },
"resolution": { "old": null, "new": "Replaced the compressor capacitor." } }
That is how a work order's View history shows who moved it to Completed, and what they wrote, three weeks later. Password columns, token hashes and similar secrets are never recorded. You can also exclude columns per table (in the table's Auditing section) for values that must not reach the log or are too large to keep twice.


Reading it
Administrators read the full log in Logs: filters by user, resource, action and status, one row's history, a workflow run's entries, and sign-in insights. A user's own activity appears in My account, through an ordinary permission (read the log where principal = $USER.id), which Apply default permissions grants.
Entries are kept for 365 days by default (audit.retention_days).
Events
Alongside its audit entry, each written row produces an event in the outbox, totalbase.outbox. Events are written in the same transaction as the change, so they exist only for changes that committed. An event carries the row, and for an update, the row before and the columns that changed.
After the commit, TotalBase hands each event to the workflows listening for it. This is how Acme's Order completed workflow starts when a work order's status changes to COMPLETED:
UPDATE work_orders … status = 'COMPLETED' ── commit ──▶ event ──▶ workflow: invoice, PDF, email
Delivery happens after the commit, never inside your transaction. A slow email server or a failing webhook can't slow down or roll back the write that triggered it. If the process stops between commit and delivery, a background poller picks up the waiting events. Failed deliveries are retried with backoff.
Outgoing webhooks work the same way: a workflow triggered by a data change, with an HTTP request step. See Integration steps.
The queue lives in PostgreSQL, so there's no message broker to run.
Next steps
- Database event trigger: reacting to data events.
- HTTP request: notifying another system of a change.
- Settings › Audit and Executions: retention of logs and events.