feat(realtime): live admin user list (LC-175, admin-user surface) #220
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-175-live-admin-lists"
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?
First surface of LC-175 (audit gap C1). The admin user list was static-on-load: when one admin banned / muted / role-changed / re-quotaed / deleted a user, other admins' open lists (and the actor's other tabs) showed stale rows until reload.
Changes
AdminUserChanged { user_id, removed }event, broadcast on theadmintopic (only admins can subscribe, pertopic_subscribe_allowed).render_user_rowfires it on every row-changing mutation (ban / unban / mute / unmute / role / quota all route through it);post_delete_userfires it withremoved = true.admin_layout.htmlsubscribes every admin page to theadmintopic viadata-lc-live-topic. The WS send task renders the matching#user-{id}row OOB (UserRowFragmentgains anoobflag) or anhx-swap-oob="delete"tombstone (user_row_delete.html) for removals. Admin pages without that row id drop the swap.build_admin_user_viewis factored out ofrender_user_rowand shared with the WS renderer.Feature gating
routes::admin(and its row builder) is#[cfg(standalone)], so the WS arm +render_admin_user_roware gated to standalone; in saas the event is never broadcast and falls through torender_event(None). This fixes the feature-gate drift that broke the saas build on the first cut (caught byjust test-saas).Out of scope (spun out)
admintopic, mechanically symmetric./saved,/inbox,/activity-user:{id}topic.Verification
just testandjust test-saasboth green (106test result: okeach; the oneroutes_uploadsfailure seen mid-run is the documented concurrent-load flake, 12/12 isolated, unrelated to this change).cargo clippy/cargo fmtclean. Regression test (routes_quotas::admin_user_list_is_wired_for_live_row_updates) asserts the admin topic subscription, the OOB-targetable row id, and that page-rendered rows are not themselves OOB.First surface of LC-175 (audit gap C1). The admin user list was static-on-load: when one admin banned / muted / role-changed / re-quotaed / deleted a user, other admins' open lists (and the actor's other tabs) showed stale rows until reload. - New AdminUserChanged { user_id, removed } event, broadcast on the `admin` topic (only admins can subscribe per topic_subscribe_allowed). render_user_row now fires it on every row-changing mutation (ban/unban/mute/unmute/role/quota all route through it); post_delete_user fires it with removed=true. - admin_layout.html subscribes every admin page to the `admin` topic via data-lc-live-topic; the WS send task renders the matching #user-{id} row OOB (UserRowFragment with a new oob flag) or an hx-swap-oob="delete" tombstone (user_row_delete.html) for removals. Admin pages without that row id drop the swap. - The user row is identical for all admins, so one render per event serves every recipient. build_admin_user_view is factored out of render_user_row and shared with the WS renderer. Standalone-only: routes::admin (and its row builder) is #[cfg(standalone)], so the WS arm + render_admin_user_row are gated to standalone; in saas the event is never broadcast and falls through to render_event (None). This avoids the feature-gate drift that broke the saas build on the first cut. Out of scope (spun out): admin ROOM list (archive/edit, same admin topic, symmetric), and the per-user surfaces /saved, /inbox, /activity (user:{id} topic). New-user-appears-on-registration live-append is also deferred (registration is not an admin action and OOB-by-id cannot append). Regression test asserts the admin user list subscribes to the admin topic, renders the OOB-targetable row id, and that page-rendered rows are not themselves OOB. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>