Skip to content

SCRUM-251 — AdminUI audit trail table and release diff

Plan ref: UI-6 (docs/11-admin-plane-plan.md). Stacked on SCRUM-250. Reads the Dashboard's merged /audit (SCRUM-238) and Config's release list.

What exists

Piece Notes
Audit page table of time, source, actor, action, target, expandable details JSON; filters (source, actor, from, to) in the URL; "Load older entries" via next_cursor; a notice naming a source the Dashboard could not read
"View changes" on release.publish and release.rollback rows; opens /config/releases/:channel/:releaseId?base=…
Release diff page release header (channel, id, message, author/time, min client version change, base); namespaces added / removed / changed (version a → b, linking to the namespace) with unchanged ones collapsed; packs added / removed / changed
diffManifests pure, unit-tested; packs are identified by hash, and one removal plus one addition under the same name reads as "changed" (old hash → new hash)
Config client getRelease(channel, id) over the release list (before=id+1&limit=1, id checked)

Config has no release-diff endpoint (only per-namespace version diffs), so the diff is computed in the browser from the two releases' manifests.

How to verify

cd services/adminui
npm run typecheck && npm run lint && npm run format:check && npx vitest run && npm run build
npx playwright test

Results at time of writing

  • typecheck, lint, prettier, vitest (310 tests), build: pass; Playwright 15/15 incl. "clicking a publish entry opens the matching diff" and back keeping the filters.
  • Screenshots checked: audit table and the diff of a rollback.

How it was built

DeepSeek run scoped (Landlock) to services/adminui (479 s, ~55k output tokens, reasoning effort low). Claude review (screenshots): a pack re-uploaded under the same name showed as an unrelated "added" and "removed" pair; they are now one "changed" row (hash identity kept), with tests for both cases.