Rework the admin Overview tab into a full-width vertical list of
per-section summary cards (System, Crawler, Analysis, Mangas, Users,
Settings), each linking to its tab. Crawler and Analysis cards update
live over the existing SSE streams; System/Mangas/Users poll; the
Settings strip reflects daemon state. The disk/memory/CPU boxes move
into the System card.
Add a composed GET /admin/overview endpoint returning Users, Mangas and
Analysis aggregates (user counts + newest, manga sync-state counts +
chapter/page totals + newest, library analysis coverage), reusing the
existing MANGA_SYNC_STATE_CASE and the storage handler's try_join fan-out.
Extend the System tab with hardware sensors: CPU load average and
per-core usage (sysinfo), plus temperatures via sysinfo's Components API
(enabled the `component` feature). Sensors degrade to an "unavailable"
state when not exposed (e.g. inside containers without /sys access), and
a temperature at/above its critical threshold raises a warning alert.
Tests: integration tests for /admin/overview and the extended /admin/system
shape; vitest coverage for the new client types and getOverviewStats.
Bump to 0.85.0 (minor) in lockstep.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses the security-audit findings on top of the admin feature stack:
M1: /admin/mangas/:id/chapters now paginates (default limit 200, max 500).
A long-runner with thousands of chapters would otherwise produce a multi-MB
response with that many scalar subqueries per row — admin-only but a real
stall risk on one expand-click. Adds explicit pagination tests for the cap
and offset; frontend renders a "Showing first N of M" hint when the cap
clips the result.
L1: repo::user::set_is_admin renamed to set_is_admin_unchecked with a
doc-comment pointing at admin_safe_set_is_admin for production use. The
short name was a footgun — a future contributor reaching for it would
silently bypass self-protection, the last-admin invariant, and the audit
log. Used only by integration-test setup; production code goes through
the admin_safe_* paths.
CSRF posture: build_session_cookie carries a comment that the
SameSite=Lax default is the project's CSRF defense for state-changing
mutations and breaks the instant anyone adds a side-effecting GET under
/admin/*. Spells out what to do then (Strict + explicit token check).
Test counts: 43 backend admin tests + 12 vitest admin tests all green;
svelte-check 0/0 across 446 files.
Adds GET /api/v1/admin/system returning disk (scoped to storage_dir
via statvfs), memory, CPU, and a server-side alerts array that fires
at >90% disk or memory.
Disk uses nix::sys::statvfs directly rather than sysinfo's Disks API
to avoid mountpoint-matching gymnastics for the storage_dir. A new
`Storage::local_root() -> Option<&Path>` trait method exposes the
root; the default returns None so a future S3Storage gets `disk:
null` in the response instead of fabricated numbers.
CPU is sampled inline (refresh → 250ms sleep → refresh → read) so the
endpoint adds 250ms of latency per call. No background-cache yet —
admin traffic is low-volume and the moving parts aren't worth it
until polling shows up.
Alerts are evaluated server-side so the frontend can render them
without re-implementing the thresholds.