Skip to content

Edit validation & the audit trail (admin)

In the admin: Audit — the screen this page documents (opens in the running app).

What/why: Admin governance — what this screen manages and why it exists.

Every admin edit to the knowledge base is validated before it is written and recorded after it is written. This page explains both guarantees and the Audit trail screen at /admin/audit.

Validation (safe edits)

All admin writes are validated server-side, in the form action, before any database write happens:

  • Core fields (systems, attributes, factors, options) go through a validate* function that checks required fields and the kebab-case key format, returning field-keyed errors. An invalid submission is rejected with fail(400) and a clear per-field message — nothing is written.
  • Typed attribute values go through buildTypedValue, which parses and validates the value against its declared type; an unparseable value is rejected with a message and never stored.

Because each write is a single statement, a rejected edit is never partially applied — validation happens first, and only a fully valid edit reaches D1. The UI never gates on its own; authorization and validation are always decided server-side.

The audit trail (/admin/audit)

Every create, edit, retire/restore, removal, value change, and factor→attribute mapping is recorded in an append-only audit log. Each entry captures:

  • Actor — the verified Cloudflare Access identity that made the change (email + display name). Locally, the dev-bypass identity is used.
  • Entity — the kind (system · attribute · factor · option · mapping · value) and its id.
  • Actioncreate · update · retire · restore · remove · set-value · clear-value · map · unmap.
  • Summary — a human-readable one-line description, plus optional structured before/after detail.
  • Timestamp — when the change happened.

The screen lists the most recent changes (newest first) and can filter by entity type and/or actor via the dropdowns (the filter is a plain query string, so a filtered view is linkable). It is visible to anyone with the view_audit capability — granted to every admin role, since the trail spans both data and rules changes.

Append-only by design

The audit trail is tamper-evident by construction: the write layer (src/lib/server/admin/audit.ts) exposes only recordAudit (an insert) and read functions — there is no update or delete path, and the screen offers no way to edit or remove an entry. History can only grow.

What this maps to

  • Validation → the validate* helpers in src/lib/server/admin/{systems,attributes,factors}.ts and buildTypedValue in src/lib/server/admin/value-input.ts.
  • Audit recording → recordAudit in src/lib/server/admin/audit.ts, called by every write action under src/routes/admin/**.
  • Audit view → src/routes/admin/audit/ (read-only; gated on view_audit).