Skip to content

SCRUM-250 — AdminUI log explorer and live tail

Plan ref: UI-5 (docs/11-admin-plane-plan.md). Stacked on SCRUM-249. Reads the Dashboard's /logs and /logs/tail from SCRUM-237.

What exists

Piece Notes
Filters service (free text with suggestions), level, contains (debounced), request id, time range — all in the URL
Virtualised list @tanstack/vue-virtual 3.13.39 (new dependency, lockfile hand-merged); time, level, service, message; click to expand full message + pretty fields JSON; a request_id in fields is a link that filters by it
Load more walks back from the oldest line held (inclusive, deduplicated by identity), up to 10 000 lines
Live tail Start/Stop; newest on top; ring buffer capped at 5 000 lines, batched per animation frame; auto-scroll pins the top unless you scrolled away ("N new lines — jump to latest"); paused on hidden tabs; aborted on Stop / leave; a 429 shows "Too many live tails open (limit 2 per person)" instead of retrying
Mock filters honoured; tail at otomo.mock.tailRate lines/s; 10 000 lines with otomo.mock.logs = 'many'

How to verify

cd services/adminui
npm ci
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 (291 tests), build: pass; Playwright 14/14 incl. 10 000 lines scrolled with < 200 row elements in the DOM, a 200 lines/s tail for 10 s staying ≤ 5 000 lines, the new-lines pill, and Stop ending the stream.

How it was built

DeepSeek run scoped (Landlock) to services/adminui (705 s, ~73k output tokens, reasoning effort low); Claude installed TanStack Virtual beforehand. Claude review: "load more" asked for lines older than the oldest held minus one millisecond, which skipped every line in that last millisecond that had not fit on the previous page (logs arrive in bursts; timestamps are nanosecond-precise). It now asks inclusively from the oldest line's exact timestamp and drops lines already held; a full page that adds nothing stops the paging. Regression test: a 30-line same-millisecond group straddling the page boundary — 500 of 510 lines before, 510 after.