From bd7b3256fce7ee3fb47c31e071774cd928e41ab1 Mon Sep 17 00:00:00 2001 From: mrhid6 Date: Mon, 10 Aug 2026 15:25:48 +0100 Subject: [PATCH] feat(audit): server-side paging, search and category filter; one event format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The page rendered a map of eleven event types to labels and seven to colours. The server emits forty-seven. Everything unmapped fell through to its raw string, so "Key Assigned" in green sat above "workflow.schedule_updated" in grey — the same kind of fact in two formats, which made the column look like it carried a meaning it did not. Presentation is now derived rather than enumerated. Event types are named . by every call site, so the category becomes a chip, the action is humanised, and the tone comes from the verb. A type added to the server tomorrow gets a sensible label and colour with no second list to update; the override table holds only the dozen the rule reads badly for. Every row is one treatment, and colour never carries meaning alone — the sentence beside it says the same thing in words. Paging and filtering are server-side, unlike the fleet lists that answer with everything and slice in the browser. audit_retention_days is a licensed entitlement measured in months, and this log is read to answer questions about the past, so a browser filtering the most recent page would report "no results" for events that exist. GET /api/audit now takes q, category, limit and skip and answers {events, total} — a short page is not evidence of the end of the log, which is why the total is counted rather than inferred. audit_logs had no indexes at all: every read was a collection scan with an in-memory sort over an append-only collection. Adds (instance_id, created_at) and warns rather than failing, matching EnsureSecretIndexes. Two bugs found by running the deriver over all forty-seven real types rather than eyeballing it: the tone rules matched only past-tense verbs, leaving auth_provider.delete drawn as neutral beside key.deleted in red; and "unaccepted" matched "accepted", so withdrawing an acceptance read as the same caution as granting one. --- docs/vantage/audit-log.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/vantage/audit-log.md b/docs/vantage/audit-log.md index e4e753f..46d9a74 100644 --- a/docs/vantage/audit-log.md +++ b/docs/vantage/audit-log.md @@ -47,5 +47,16 @@ for accountability. ## Getting events out -`GET /api/audit` returns recent events as JSON and accepts a `limit`. There is -no streaming or push export; if you need events in a SIEM, poll that endpoint. +`GET /api/audit` returns one page of events as JSON: + +```json +{ "events": [ ... ], "total": 3214 } +``` + +It accepts `limit` (default 50, maximum 200), `skip`, `q` to search actor, +details and event type, and `category` to match the part of an event type +before the dot — `workflow`, `key`, `server`. `total` counts everything +matching the filter, not the page, so a short page is not the end of the log. + +There is no streaming or push export; if you need events in a SIEM, poll that +endpoint, walking `skip` until you have `total`.