Skip to content

Add searchable Content Trash and scoped recovery - #4608

Draft
3mdistal wants to merge 4 commits into
mainfrom
codex/content-trash-recovery
Draft

3mdistal wants to merge 4 commits into
mainfrom
codex/content-trash-recovery

Conversation

@3mdistal

@3mdistal 3mdistal commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Problem

People recovering deleted Content Pages and Databases need to identify the right object, inspect it, and restore only the intended subtree. The old sidebar Trash list did not provide a searchable recovery surface, and recovery operations needed a precise authorization and scope contract for independently deleted descendants.

Changes

Adds one searchable Trash browser for Pages and Databases, bounded pagination and filters, deletion attribution, selection, and read-only previews at existing Page URLs. Previews use the native editor for ordinary rich content, including tables, toggles, images and math, and expose authorized Database properties, comments and saved versions. Active embedded components remain inert source previews.

Recovery plans bind confirmation to the selected object, its affected descendants, destination and surviving children. Restore preserves identity and memberships, supports a selected child subtree and an explicit destination in the same space, and checks access again under transaction locks. Permanent deletion reports its scope and any surviving children before confirmation; changed plans fail instead of silently widening. Legacy Database-only trash remains restorable through its canonical binding.

Includes overlapping prerequisites from the deletion work: canonical Page lifecycle and membership-independent Database reads (see #4605), plus the typed unavailable-editor integration (see #4607). These overlaps need coordination with the companion editor PR before integration. Adds nullable deletion metadata and indexes through additive migration 91. Also fixes the product-doc validator to read LF and CRLF identically, without weakening required-section validation.

Verification

  • 143 tests pass across 11 targeted query, recovery, preview, UI, localization and Database lifecycle suites. Content TypeScript check and formatting pass.
  • Product-doc validator passes all 163 records; its LF/CRLF regression suite passed 16 tests.
  • Real local browser checks exercised search, duplicate Page/Database titles, pagination, query error/Retry, inaccessible URLs, viewer-only preview and access revocation, child destination recovery, independent descendants, overlapping selection, confirmation Cancel, keyboard focus, and 390/768/1280 layouts.
  • A shared Page retained separate values in two Databases after restore, verified in Table and List. Native rich preview renders math and an image. Comment pagination (100 + 3), history groups (20 + 3), and nested checkpoints (20 + 2) passed Next/Previous and end-boundary checks, including opening an old checkpoint. A second browser client restored one selected Page before bulk confirmation; the original dialog reported one restored item and one explicit stale-item failure without false full success.
  • Independent recovery review findings about survivor authorization/locking, destination ancestry and original-parent grant locking were fixed and rechecked.

Open before acceptance

This is a draft, not an acceptance-complete change. Browser execution of permanent deletion awaits exact-fixture approval. Second-client permanent-delete stale-plan rejection still needs browser evidence. A supported mock-source Database was soft-trashed and restored through the UI while its independent member stayed live; strict readback confirmed unchanged source binding, row provenance, member body and membership. No real provider or upstream deletion was exercised. Two-client stale restoration and independent bulk partial outcomes have been exercised. Active embedded components intentionally have source previews rather than full renderer parity. Transaction tests use isolated PGlite; PostgreSQL CI remains pending.

The full local guard runner cannot start child commands on this Windows host (spawn EINVAL). The local i18n catalog guard reports 2,537 platform-related findings and no Trash findings; the Linux CI catalog guard passes. No baseline was changed. Initial CI found unused imports and two unscoped reads; these are repaired in 1e9e9ea with destination authorization before ancestry traversal, ownership-scoped ancestry, and regression coverage. At 23044a6, Linux CI passed lint, typecheck, build, security guards, PGlite migrations, and core integration tests. Remaining failures were stale fixtures/assertions and missing parity entries. Commit 6d80ab5 adds action-backed Trash parity coverage, updates the sidebar and typed access-error assertions, and aligns PostgreSQL fixtures with independent membership and scope-token rejection. The repaired parity/sidebar/Trash suites pass 127 tests; revoked-access seeding passes 26 tests; the critical-coverage check passes 2 tests. Replacement CI is pending. PostgreSQL tests could not execute locally because no isolated PostgreSQL server is available; all 15 skipped, so locking proof remains open. Changed-copy exits successfully but reports zero surfaces, so it is not claimed as coverage. The app changelog command is disabled by current configuration and was not enabled. No merge or deployment is authorized.

content_product_impact:
  lane: contract_fulfillment
  features: []
  capabilities:
    - content.object.page
    - content.history.queryable
  record_change: included
  proof:
    - Focused Trash query, preview, recovery, and lifecycle tests
    - Content parity and sidebar regression tests
    - Reversible local browser recovery and source-preservation checks
  rationale: Adds scoped Trash inspection and recovery while preserving identity and access; irreversible browser acceptance and PostgreSQL CI remain open.

Current integration gate

At head 6d80ab5e6, GitHub reports conflicts with main; no main CI workflow has started for this head. A read-only merge preview identifies six files: create-content-database.ts, delete-content-database.ts, restore-content-database.ts, DocumentEditor.tsx, content-action-refresh.ts, and server/plugins/db.ts (all under templates/content). The working tree and branch were not merged or rebased. CI monitoring is paused because branch reconciliation needs explicit authorization under the current no-merge boundary. Permanent-delete browser approval also remains pending.

@netlify

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant