Audit reference

Config

KeyDefault
databaseDBThe D1 binding the table and its migrations target
basePath/auditWhere the control-plane read routes mount

The shape below is the event model as columns. What each field means, and which of them the emitter cannot set, is on that page.

The row

ColumnNullable
idAutoincrement surrogate. Internal, never exposed
eventIdA UUID minted before the insert — the idempotency key
occurredAtMs-epoch in SQLite, a Date in app code. Indexed
actiondomain/reason. Indexed
outcome
severity
actorType
actorId✓Indexed
sessionId✓
resourceType, resourceId✓
ip, userAgent, requestId✓Correlation
metadata✓A JSON object, validated both ways
project, environment, worker✓Stamped by the recorder
version✓
tenant✓Supplied by the emitter

Enums

Outcome — success · failure · denied

Severity — info · warning · critical. Defaults to info.

Actor type — user · service · system · anonymous · control-plane

Scopes

ScopeGrants
audit:events:readThe listing. No ip, no userAgent, no metadata
audit:events:read_detailOne event in full

Matched exactly. Holding one does not imply the other.

Routes

GET /audit/eventsKeyset paged. Returns nextCursor
GET /audit/events/:eventId

Both are reads. There is no third route. Querying the trail covers the scopes, the keyset pages and the filter; the shape these two share with every other route in the kit is on HTTP routes.

Actions this capability emits about itself

Action
audit/trail_readThe filter, and how much came back
audit/event_readWhich event was asked for

Recorded including the reads that found nothing.

Error codes

Each is domain/reason, and they read the way every error code in the kit does.

Code
audit/invalid_eventThe event did not validate
audit/write_failedThe insert failed. The audited action still succeeded

Not implemented

Retention and pruning. Tamper-evidence (a hash chain). A dedicated database by default. All deferred — see Retention.

License

ESC