The OSS plan rationale: most operators don’t need the regulatory tier;
turning it on commits to a multi-year retention obligation that’s
expensive + GDPR-tense (longer retention = more rows the user can
demand redaction on). The default is off; operators in jurisdictions
that require it (US FinCEN, EU AMLD) flip it on per entity.
Implementation status
Theretention-tier-sweep function is scheduled daily at 03:00 UTC, but returns status: 'skipped' with reason: 'retention_enforcement_not_deployed'. It does not archive, delete or mark rows as transitioned.
The age bands above describe configuration targets. The previous count-and-timestamp implementation was removed because it suggested that retention had occurred. Do not treat the schedule, configured thresholds or old sweep timestamps as evidence of archival or deletion.
Configuring per entity
Admins use the/admin/retention UI:
hot < warm < cold is required;
regulatory > cold if regulatoryEnabled = true. Stored sweep timestamps do not establish that retention enforcement ran.
DSAR + retention interaction
Retention configuration expresses intended age bands; enforcement is currently disabled. The DSAR redaction workflow (/admin/dsar) is the lower bound — a
right-to-redaction request can flag fields as [REDACTED] regardless
of which tier the row is in. The append-only-trigger pattern guarantees
the row’s existence stays for audit-log integrity even after redaction.
See DSAR redaction workflow
for the full picture.
Reading list
- Money-safety contracts —
the F-rules around append-only
activity_log. - Receipt schema — what’s in each row.
- Source:
apps/web/drizzle/0048_retention_tier_config.sql+apps/web/src/inngest/functions/retention-tier-sweep.ts.