Maintenance-jobs admin panel and audit-log viewer #86
Labels
No Label
area:auth
area:docs
area:export
area:ops
area:storage
area:supply-chain
auth
backend
blocked
collab
deployment
docs
effort:L
effort:M
effort:S
frontend
plugins
qa
vs-nfd
vs-nfd:blocker
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: stwaidele/dorfteich#86
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Operators need one glance for instance health: job outcomes and the audit trail (operations.md).
Scope
Admin area 'System': maintenance job list (name, cadence, last run, outcome, duration; manual trigger button per job), backup status card (from status.json via API), audit-log viewer (filterable by actor/action/time, paginated — reading the structured audit entries written since M1/M5), storage overview (per-pond usage top list).
Acceptance criteria
Technical notes
Dependencies
Depends on #31, #83, #52.
Size: ~1.5 days
Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add
deanden), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.Implemented in
c8aac13(pipeline green, 8/8 contexts; migration verified live on Test + Int).New Site-Admin panel
/admin/system(linked from the admin settings page), four sections:jobsrow: cadence, last run, duration (newJob.lastDurationMs, recorded by the scheduler on every completion), outcome badge with the error on hover, and a manual trigger per job. The trigger (POST /admin/system/jobs/:name/run) skips the due-check but never the run-mutex (already_runninginstead of doubling up) and is itself audit-logged (job.triggered). A leftover DB row whose job no longer registers in the build is flagged instead of hidden.status.json(read through the api's ro-mount from #85) including the freshness verdict with the same 26 h bound as readyz: fresh/stale badge, last success with backup id and sizes, last run outcome with the error, retention. Missing status.json → explicit "not available" state.pond_usage.storageBytesUsed, linked.Persistent audit trail (the substrate the viewer needed): audit events existed only as pino stdout lines — unqueryable. New
audit_logtable (migration20260711180000; actor FKSET NULL, indexes on at/actor/action) + centralAuditService.record()which writes the row and keeps emitting the establishedaudit: …log line; persisting failures are swallowed so auditing can never break the audited operation. Converted call sites — the security.md audit trail: grants (created/deleted), members (added/role_changed/removed), user admin (disable, resend, delete, site-admin, pseudonymized), quota admin (set/cleared), plugins (installed/mode/uninstalled/pond-toggle — actor threaded through the controllers; dropzone installs record without an actor), instance settings (key only, values stay out of the trail), setup (4 steps), auth (signup, verified, login success/failure, password reset). Content activity (pages, files, exports, labels) deliberately stays log-only. Action ids are stable dot-namespaced strings; the UI localizes them (de+en, newsystemnamespace).Acceptance criteria
job.triggeredentry attributed to the admin; e2e: button click in the panel, row shows date + duration, audit table finds the entry.available: true, fresh: false; fresh fixture →fresh: true; e2e renders the card in both worlds.grant.created→ entry with pond target and role; a different actor filter returns nothing.Tests:
system-admin.e2e.db.test.ts(7) in the checks job, Playwrightsystem.spec.ts(4) as a new CI step; the full api suite stays green with the retrofits. Live:audit_log+jobs.last_duration_msconfirmed on Test and Int after the deploy (migrations auto-applied), endpoints up and guarded.