Deleted files 2/3: manual purge surface in the admin topic (#278) #280

Closed
opened 2026-08-19 18:44:04 +00:00 by Cordy · 1 comment
Owner

Part of epic #278. Especially load-bearing when trashFinalDeletionDisabled is set (#279) — manual purge is then the only deletion path.

Backend

  • Admin-gated endpoints to list trash contents instance-wide (not just the caller's own trash: per-user trash entries with owner, original path, deleted-at, expires/eligible-at, size) and to purge selected entries permanently.
  • Purge is refuse-on-conflict with legal holds: any hold covering an entry's original path blocks that entry with a per-item error, never a silent skip.
  • Every manual purge appends the purge-log record (#281) and an audit event (trash-purge, actor = the admin).
  • Purging retires associated custody material where the entry is the last content under a retired scope (ties into #268 space purge; do not over-engineer — space-level key retirement arrives with the #268 implementation).

UI (mockup-first)

Deleted files → Manual purge tab:

  • Filterable list (by user, by path substring, by expired-eligibility) rendered in the established row style (Transfers-look rows, not card-in-card — the v0.6.46 lesson).
  • Per-row Purge (danger, askConfirm) and bulk select + "Purge selected" with a type-to-confirm summary ("Permanently delete N items — this cannot be undone").
  • Hold-blocked rows visibly marked and excluded from bulk selection.
  • Empty state and a hint linking the Retention tab when final deletion is disabled.

Acceptance

  1. An admin can find and permanently delete specific trash entries; recipients of hold-covered entries get an explicit refusal.
  2. Bulk purge summarizes and confirms before acting; partial failures report per item.
  3. Every purge lands in the purge log and audit log.
  4. No purge path exists that bypasses the hold check (shared chokepoint with auto-purge).
  5. Mockup proposed and signed off before implementation ships.
Part of epic #278. Especially load-bearing when `trashFinalDeletionDisabled` is set (#279) — manual purge is then the only deletion path. ## Backend - Admin-gated endpoints to list trash contents instance-wide (not just the caller's own trash: per-user trash entries with owner, original path, deleted-at, expires/eligible-at, size) and to purge selected entries permanently. - Purge is refuse-on-conflict with legal holds: any hold covering an entry's original path blocks that entry with a per-item error, never a silent skip. - Every manual purge appends the purge-log record (#281) and an audit event (`trash-purge`, actor = the admin). - Purging retires associated custody material where the entry is the last content under a retired scope (ties into #268 space purge; do not over-engineer — space-level key retirement arrives with the #268 implementation). ## UI (mockup-first) **Deleted files → Manual purge** tab: - Filterable list (by user, by path substring, by expired-eligibility) rendered in the established row style (Transfers-look rows, not card-in-card — the v0.6.46 lesson). - Per-row Purge (danger, `askConfirm`) and bulk select + "Purge selected" with a type-to-confirm summary ("Permanently delete N items — this cannot be undone"). - Hold-blocked rows visibly marked and excluded from bulk selection. - Empty state and a hint linking the Retention tab when final deletion is disabled. ## Acceptance 1. An admin can find and permanently delete specific trash entries; recipients of hold-covered entries get an explicit refusal. 2. Bulk purge summarizes and confirms before acting; partial failures report per item. 3. Every purge lands in the purge log and audit log. 4. No purge path exists that bypasses the hold check (shared chokepoint with auto-purge). 5. Mockup proposed and signed off before implementation ships.
Author
Owner

Shipped as v0.6.49 (PR #283), live on both dogfoods. Includes the slot-leak fix from the v0.6.48 finding (adm-slot-trash was missing from the shell's explicit hide-all ID list).

As built (per the signed-off mockup):

  • GET /api/v1/admin/trash — every user's personal trash + every space trash, annotated server-side with eligible / hold / keepUntil
  • POST /api/v1/admin/trash/purge — owner-aware; held or retained entries are refused with the retention error; every purge audited as manual-purge (the #281 feed)
  • UI: summary bar with "Purge all eligible (n)" (two-step: first click arms, second executes), rows with mono original path + owner/space + deleted-by + date, badges for legal hold / retention-until with the Purge button disabled, inline per-row confirm strip
  • Driver tests: non-admin refusal, hold and retention blocks, personal + space purge round trips — green in CI

Dogfood checklist (fresh login after the roll):

  • Deleted files no longer leaks into Retention & holds or any other topic
  • #admin/trash/purge lists your existing trash (there should be some from the delete tests); summary counts look right
  • Purge one throwaway entry: inline confirm appears, purge removes it, entry lands in the audit log as manual-purge
  • Set a legal hold on a path with a trashed file → row shows the badge, button disabled
  • A held/retained "Purge all" run skips the protected entries
Shipped as **v0.6.49** (PR #283), live on both dogfoods. Includes the slot-leak fix from the v0.6.48 finding (adm-slot-trash was missing from the shell's explicit hide-all ID list). As built (per the signed-off mockup): - `GET /api/v1/admin/trash` — every user's personal trash + every space trash, annotated server-side with `eligible` / `hold` / `keepUntil` - `POST /api/v1/admin/trash/purge` — owner-aware; held or retained entries are refused with the retention error; every purge audited as `manual-purge` (the #281 feed) - UI: summary bar with "Purge all eligible (n)" (two-step: first click arms, second executes), rows with mono original path + owner/space + deleted-by + date, badges for legal hold / retention-until with the Purge button disabled, inline per-row confirm strip - Driver tests: non-admin refusal, hold and retention blocks, personal + space purge round trips — green in CI Dogfood checklist (fresh login after the roll): - Deleted files no longer leaks into Retention & holds or any other topic - `#admin/trash/purge` lists your existing trash (there should be some from the delete tests); summary counts look right - Purge one throwaway entry: inline confirm appears, purge removes it, entry lands in the audit log as `manual-purge` - Set a legal hold on a path with a trashed file → row shows the badge, button disabled - A held/retained "Purge all" run skips the protected entries
Cordy closed this issue 2026-08-20 05:12:23 +00:00
Sign in to join this conversation.
No labels
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#280
No description provided.