Audit log
Append-only record of state-changing admin actions — who did what, when, against what target.
The audit log captures every state-changing call to /api/v1/admin/* —
settings updates, hook saves, admin invites, backup triggers, and so on —
every collection write at /api/v1/collections, every record restore, and
every MCP tool call. One row per request, append-only, designed for
compliance and forensic lookups.
What gets recorded
Section titled “What gets recorded”A row is written for every POST / PUT / PATCH / DELETE to
/api/v1/admin/* and to /api/v1/collections (create, update, delete a
collection). GET is not audited — read traffic is high-volume and
already covered by the request log.
Skip-list (intentionally not audited):
/api/v1/admin/auth/login,/api/v1/admin/auth/logout— auth attempts already log via the request log/api/v1/admin/setup— fresh-install bootstrap/api/v1/admin/migrations/diff— read-only despite being POST- Any path matching
/api/v1/admin/preview-*or/api/v1/admin/.*/preview$
Each row is immutable. The application never updates audit rows, and
deletes them only through the opt-in audit.retention_days setting (entries
older than that many days are removed by the daily cleanup; 0, the default,
keeps them forever). Operators can also DELETE directly from the
vaultbase_audit_log table.
Schema
Section titled “Schema”CREATE TABLE vaultbase_audit_log ( id TEXT PRIMARY KEY, actor_id TEXT, -- admin id from the JWT actor_email TEXT, -- email cached at the time of action method TEXT NOT NULL, path TEXT NOT NULL, action TEXT NOT NULL, -- logical label, e.g. "collections.create" target TEXT, -- best-effort id or name from the path status INTEGER NOT NULL, ip TEXT, -- client IP (see IP capture); null for MCP rows summary TEXT, -- optional human / JSON at INTEGER NOT NULL, -- unix-seconds token_id TEXT, -- API token of an MCP call; null otherwise token_name TEXT -- that token's name at the time);Indexes on (actor_id, at), (at), (action, at), (token_id, at).
token_id and token_name are filled since 0.40.0; older MCP rows name the
token in summary only.
Action labels
Section titled “Action labels”action is derived from the path + method. Examples:
| Method | Path | action |
|---|---|---|
| POST | /api/v1/collections | collections.create |
| PATCH | /api/v1/collections/<id> | collections.update (target = the id) |
| PATCH | /api/v1/admin/settings | settings.update |
| POST | /api/v1/admin/hooks | hooks.create |
| POST | /api/v1/admin/admins | admins.create |
| POST | /api/v1/admin/sql/run | sql.create (target = run; the SQL text is not stored) |
Uncategorised paths fall back to <METHOD> <path>.
MCP tool calls are entries with action mcp.tool, method MCP and the
tool name as path; run_sql writes mcp.sql.read / mcp.sql.write. See
MCP audit trail. A call on a record has
collection=<name> id=<id> as its target.
A record restore is record.restore,
with the record as target and the restored version in summary.
Read API
Section titled “Read API”GET /api/v1/admin/audit-log ?page=1&perPage=50 &actorId=<id> &tokenId=<api-token-id> &actionPrefix=collections. &from=<unix-seconds>&to=<unix-seconds>Returns:
{ "data": { "data": [ { "id": "...", "actor_email": "ops@acme", "action": "collections.delete", ... } ], "page": 1, "perPage": 50, "totalItems": 1234, "totalPages": 25 }}GET /api/v1/admin/audit-log/tokens lists the API tokens that appear in the
log (id, name, number of calls, last call), newest first, deleted tokens
included.
Admin UI
Section titled “Admin UI”Sidebar → System → Audit log. Filter by actor id, API token, action prefix, and date range; click a row to see the full entry (path, status, target, token, IP, timestamp, summary). From an entry, Only this token filters to that token’s calls, and Record history opens the record it names with its history, so you can restore an earlier version or undo a delete. The table paginates server-side; default page size 50.
IP capture
Section titled “IP capture”The audit row’s ip field is the connecting peer’s address.
X-Forwarded-For is used only when the peer is a trusted proxy
(VAULTBASE_TRUSTED_PROXIES or security.trusted_proxies). Without that, a
client can’t put a fake address in the column by sending the header. MCP tool
calls have no request to read from, so their ip is null.
Environment=VAULTBASE_TRUSTED_PROXIES=10.0.0.0/8,127.0.0.1/32Same env var the rate-limiter uses for its real-IP resolution.