Audit log
riverbase_core::logstore records what every command and query did. Writes on the command path are
part of the command's transaction, so the audit trail always matches the state.
Channels
| Channel | Table purpose | Written by | Default |
|---|---|---|---|
context | Request context: actor, profile, tenant, correlation | Command and query engines | on |
command | Each command and its terminal status | Command engine | on |
event | One row per successful #[domain_action] | Aggregate session | on |
message | Integration messages | emit_message | on |
activity | Human-readable audit entries | emit_activity, reports | on |
response | The response returned to the caller | Command engine | on |
query | Query executions | Query engine | off |
Idempotency records (idempotency, on by default) and outbox rows are written alongside.
Configuration
[riverbase.audit_log]
command = true
event = true
message = true
activity = true
response = true
query = false
Each key has an env override: RIVERBASE_AUDIT_LOG_COMMAND, …_EVENT, …_MESSAGE, …_ACTIVITY,
…_RESPONSE, …_QUERY, …_CONTEXT. A disabled channel is backed by NoOpLogStore. Turning off
idempotency disables response replay for retried requests.
Building the bundle
DomainRuntime::from_config builds it for you. To build it by hand, for example in a worker:
use riverbase_core::logstore::PostgresDomainLogStore;
let logs = PostgresDomainLogStore::new(pool.clone())
.into_bundle_with_config(&config.audit_log);
DomainLogStore exposes each channel (logs.activities, …) as a LogStore you can append to
outside a command. For example, ActivityEmitter records activities from a custom route.
Command status
A command row starts as Created and moves to a terminal success or error status
(CommandLogStatus) when its unit of work completes. A row stuck in Created means the process
died mid-command. Nothing else committed with it.
Idempotency
Clients send an idempotency key with a command. The engine stores the response under that key in the
same transaction, and a retry returns the stored response. The response header that echoes the key
is configured by resp_header_idempotency in [riverbase.auth].
Outbox
emit_message writes an OutboxStore row in the command transaction. The publisher started by
DomainRuntime::from_config (or by spawn_outbox_publisher) delivers rows to the MessageBus
after commit, retrying failures. Delivery is at least once.
Retention
purge_audit_logs with an AuditRetentionConfig deletes audit rows past their retention window.
Run it from a scheduled job; it is never called implicitly.
Where it lives
On Postgres, the tables are in the riverbase_audit schema and are created by the framework
migrations in establish_dbpool.