feat(webapp): Admin's Recording & retention, Backup, Import and Audit log (lane 9 page 4b) — stacked on #864 #873
Loading…
Reference in a new issue
No description provided.
Delete branch "build/lane9-4b-pages"
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?
Lane 9 (#735), page 4b. Stacked on the second merge train, on top of #864. This is frontend only: the server work (A, B2, C and D179's retention) is already underneath it.
What's rebuilt
GET /admin/settings/retention/preview, which lists the campaigns a new cap would cut;credentials_set;ImportCampaignFormwith the New Campaign page's import (D46).Coverage
ADMIN-5 (AD-077–AD-084, IS-311), ADMIN-6 (AD-084–AD-088), ADMIN-7 (AD-089–AD-098, IS-081, IS-396), ADMIN-9 (AD-129–AD-133), ADMIN-10 (AD-134–AD-141).
coverage/lane7.pyreports "unclassified: none".Departures
Admin.jsxsections stay until page 4d deletes the old page.The render check
There was no seeded stack, so the four pages were mounted against realistic fixture data and screenshotted with Playwright:
The only fault found is shared with 4a's tables: they wrap at 390 instead of scrolling. That's filed as #872.
Tests
changelog.d/fragment is included.🤖 Generated with Claude Code
The page at /campaigns/:id/safety (CAMP-18): lines and veils for everyone; for a GM, Edit, Remove with Undo (D12), "+ Add", and the waiting queue with Add as a veil / Add as a line (in the GM's wording) and Dismiss. A player gets the anonymous suggest card with the drawn words (T3(a)) and every GM named (T10(a)), and IS-017's Sent card. The flag dialog, "Flag something to Dana", behind four doors: This week's card (IS-205, about no session), the foot of a live or played session's page (T2(a), IS-210), and Table mode's players' face ("Flag something quietly"). The GM's Table-mode face gets the quiet "N waiting in Table rules & safety" in its place, polled from GET …/safety/waiting (T4(a)). The Contents gains the Table rules & safety entry, with the GM's count (IS-204, IS-212); a player is never asked for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"Make it canon" on a party thread wrote the answer, unblocked, into a wiki page the whole table reads, so members outside the party read it there (found by the lane 8 survey). CANON_AUDIENCES is ("table",) until lane 8's party and visibility blocks (IS-148) can carry the thread's audience into the article; a party answer is now a 422, like a narrower one. The thread page follows: no "Make it canon" on a party thread. Tests hold both sides; API.md and the CHANGELOG say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>The bot's half is tested: /record/test announces "Recording a test" before it captures (and records anyway if the post fails, D171), captures with the same sink into audio_temp/tests/{id}/ with absolute placement intact, hands over through POST /api/bot/recording-tests/{id}/audio, deletes the audio if the handoff does not land (D150), and crash recovery and the startup sweep never take tests/ for a session. The session page's SSE keys a test's "other" by its own id. API.md documents the routes; the changelog says it. Closes #824. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Server and bot halves together; no pages. - Discord DMs (D152): `notification_dm` on the durable stream, claimed before publish, the bell's line + link + time for session news only; sent only to a bot whose GET /identity lists "dm" in its new `features`. The bot's handler is exempt from the channel check and reports refusals to the new POST /api/bot/users/discord/{id}/dm-status (closed | no_shared_server | ok); the settings carry a `warning` beside the DM column until the next DM lands. - The GM's warnings (D151): session_at_risk and audio_deletion_pending are GM-only bell rows, DM'd per the GM's grid (GM tasks x DM on by default), and posted to the channel only when no GM is reachable by DM. The at-risk poller runs for campaigns without a guild. - A group without Discord (D153, #840): session news is emailed to every member unless Sessions email is explicitly off; the from-address email backends are retired. Reminders are `session_reminder` rows per member (only the last in the bell), reading the reader's RSVP. - The reader's time: users.timezone, else the campaign's, else UTC, with the abbreviation, in notification emails and calendar invites. - One star, one wish (D161): `feedback_requested`, written on completion for the players Home asks, never in the bell. - D159: campaigns.voice_channel_id, stored and shown to GMs. - PUT notification-settings writes only cells that change and never refuses an unchanged echo, so the page's whole-grid save keeps the defaults. - Migration 10a1b2c3d4e5 on c4e6a8b0d2f1: the kind CHECK is the union with lane 9 A's and lane 7's kinds; notifications.in_bell; platform_links dm_failed_at/dm_failed_reason; campaigns.voice_channel_id. Bot contract unchanged (additive). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Admin becomes a place with sections in Home's Contents rather than a page of ten tabs, reusing the same shape lane 3 gave Settings: - adminSections.js (16 sections, the survey's addresses); ADMIN_SECTIONS' `built` flag follows settingsSections.js's own rollout rule — three sections with no legacy screen at all (Content notices, Instance health, Plans & entitlements) stay unmounted for their own PR (4c/4d). - /admin/* routes; `?tab=` redirects to the new address (paths are contracts, R1-8); `bot` (ambiguous) goes to AI models. - Home's Contents "This instance" group, the crumb ("Admin › <section>"), and IS-377's Stop for a non-administrator (AdminDoc.jsx). - The index (GET /admin/overview, already on this branch from lane 9 A): grouped status lines, D142's quiet leftovers box, and D141's accept/ decline banner for an offered server. - ADMIN-15 About this server: the admin GET/PUT this lane's server work added, now with a form. - ADMIN-1 Users: the owner's chip, "Hand the server on…" (an offer, D68), Make/Remove administrator (a dialog, then an undo), delete with the typed name and the blocked-by-campaigns state, and D56's search-scope radio cards (new GET endpoint — the setter existed, nothing read it back). - ADMIN-2 Campaigns: the instance-wide list, and an immediate (never an offer) hand-on for a campaign whose owner is unreachable or just moved on — the admin's own recovery path either way. - D141's server-scoped attention item: AttentionItem.campaign_id/ campaign_name become optional for the one kind that isn't a campaign's (server_owner_offer), checked ahead of the membership scope so it reaches an administrator with no campaigns of their own. - Every other built section keeps working at its new address by mounting pages/Admin.jsx's existing component unchanged (the tab bar is gone); AI models and Discord share one interim mount until page 4c splits BotSettings along the new addresses — a documented departure. - J1's Admin leg walked for real: the leftovers list, Backup's own heading and Contents-current row, a whole-page axe scan (no longer scoped to [role="alert"]), the desktop project settling the step, and the keyboard project reaching Admin through the account menu and its Contents sub-list. A new IS-377 journey test (Priya, stopped, axed). Backend: GET /api/admin/settings/member-search-scope (D56's setter has existed since #855; nothing read it back before this). Not in this PR (see the survey's §7 row 4a and the file's own notes): AI models/AI usage & speed/Discord's real split, Recording & retention, Backup, Content packs, Content notices, Audit log's names/categories, and Plans & entitlements — pages 4b/4c/4d. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>ADMIN-5/6 gets the default/cap split (D24) with IS-311's confirm against GET /admin/settings/retention/preview before a tighter cap catches a campaign's sessions, and says D179's now-fixed retention promises correctly (D179 itself shipped server-side in lane 9 B2). ADMIN-7 queues a backup without asking first (D12), polls the last runs while one is in progress, and drops the now-false "uploaded images are not in the backup" line since D143 already put them in. ADMIN-9 shares its form (ImportCampaignForm.jsx) with Home's New campaign -> Import a file (D46), gaining "Open its Members" since an administrator need not be a member of what they import. ADMIN-10 filters by name and category (server support already in main), and reads a row's detail as labelled lines with the record as stored one click further. Departures, each recorded in the page's own docstring: - the on-disk detail lines needing per-recording expiry/progress fields the server doesn't return are left as plainer wording rather than adding new backend fields; - the audit log's description column shows the server's own `description` string verbatim rather than reconstructing bespoke per-event sentences from `context`; - Admin.jsx's legacy RetentionSection/RecordingsSection/BackupSection/ AuditLogSection/AdminImportSection are left in place rather than deleted, since the legacy default-exported page and its own test still use them and deleting the whole file is page 4d's job. Coverage: docs/design/redesign-surfaces/coverage/lane7.py reports {'replaced': 19, 'drawn': 165, 'elsewhere': 9} total 193 - unclassified: none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>