cpatpa builds a safety net into document deletion

PIP now treats retention as a two-stage process so accidental purges are recoverable for a week.

complianceworkflow

Most legal platforms enforce retention with a hard switch: the clock runs out, the document is gone. cpatpa's fork does it in two beats. When a document, chat, or tabular review crosses its retention horizon, it gets flagged rather than deleted. A grace window - seven days by default - has to elapse before the row and its underlying file are actually removed. Retention windows are set at the workspace level, with the org-wide setting as a fallback, and a zero means keep forever.

Admins get a dedicated retention dashboard showing every flagged item across documents, chats, and reviews, with the date it was created and how long it's been sitting in the grace window. From there they can restore an individual row with a click, or run the cleanup job on demand. Every flag and every hard delete writes an audit event with row counts.

So what Worth a look for any legal-ops lead who's ever had to explain to a partner why a document vanished on schedule - this is retention with an undo button.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

2 commits from cpatpa/PIP, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
490f8271 Phase 10: document retention enforcement Claude 2026-05-15 ↗ GitHub
commit body
Two-phase retention so accidental data loss is recoverable:

  1. Flag    rows past the effective retention horizon
             (workspace.retention_days, falling through to
             org_settings.retention_days; 0 = keep forever) are
             marked with pending_deletion_at.
  2. Hard delete rows still flagged after
             org_settings.retention_grace_days (default 7) are
             removed; document storage objects unlinked then.

Schema (0017_retention.sql) adds pending_deletion_at to documents,
chats, tabular_reviews and a retention_grace_days column on
org_settings. Both phases write audit events
(retention.flag / retention.hard_delete) with row counts.

backend/src/lib/retention.ts owns the SQL and a setInterval(24h)
boot scheduler, disable with RETENTION_DISABLED=true. The user
list/get surfaces (single-docs, project docs, chats, project chats,
tabular review list) hide pending-deletion rows so the UI reflects
the flag immediately.

Admin endpoints for visibility and recovery:
  GET  /admin/retention/pending
  POST /admin/retention/restore  { kind, id }
  POST /admin/retention/run
c91262ac Retention admin UI + drop legacy shared_with JSONB Claude 2026-05-15 ↗ GitHub
commit body
New /admin/retention tab visualises every row currently flagged for
deletion (documents, chats, tabular reviews) with created-at,
flagged-at, and days-since-flag. Admins can restore individual rows
inside the grace window via POST /admin/retention/restore or kick
the job immediately with POST /admin/retention/run.

Migration 0018 drops projects.shared_with and
tabular_reviews.shared_with JSONB columns. No app code reads or
writes them any more; project_members and review_members have been
the source of truth since Phase 3. The companion GIN indexes drop
implicitly. API responses still surface a shared_with array
derived from the members tables, so the frontend wire shape is
unchanged.

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-371.md from inside the repo you want the changes in.

⬇ Download capture-thread-371.md