cpatpa builds retention that deletes on a timer but gives you a way back

A new auto-deletion system clears out aged documents, chats, and review tables on schedule - with a grace period so nothing vanishes the instant the clock runs out.

complianceworkflow

cpatpa added an automatic data-retention enforcer to this self-hosted fork. Once a document, chat, or review table passes its retention horizon, it gets flagged and disappears from everyone's view straight away - but it isn't actually destroyed until it has sat in a holding state past a configurable grace window (a week by default). That two-step design is the whole point: an admin can step in and restore a flagged item before the hard delete fires, which a single-pass purge would never allow.

Retention periods can be set per workspace and fall back to an organisation-wide default, with an option to keep certain records forever. There's also a small admin screen listing everything currently flagged, where admins can rescue individual items or kick off a retention run on demand. Every flag and deletion is written to an audit trail.

So what Worth a look for any legal or compliance lead who needs defensible, configurable data-retention on a self-hosted tool without losing the ability to undo a deletion in time.

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