feat(core-shared): grace-purge soft-deleted rows + boot registration
The retention purge job gated its whole body on activeRetention while every collection declares only postDeletion, and no app ever called registerRetentionPurgeJobs — retention was dead end to end (audit findings A2 + A3). The DSR soft delete now stamps a deletedAt tombstone on postDeletion collections (kept distinct from processingRestrictedAt so an Art. 18 restriction never feeds the purge), the job grace-purges tombstoned rows past postDeletion.duration with the declared action, core-cms injects the tombstone field + Payload task definitions, and bindAllProduction enqueues the first purge cycle at boot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,10 @@ import {
|
||||
NoopRateLimit,
|
||||
type RateLimitBudget,
|
||||
} from "@repo/core-shared/rate-limit";
|
||||
import {
|
||||
registerRetentionPurgeJobs,
|
||||
type GetPayloadFn,
|
||||
} from "@repo/core-shared/payload";
|
||||
import { bindAudit, type IAuditLog } from "@repo/core-audit";
|
||||
import {
|
||||
bindProductionConsent,
|
||||
@@ -192,6 +196,17 @@ export async function bindAllProduction(): Promise<void> {
|
||||
bindProductionMarketingPages(ctx);
|
||||
bindProductionNavigation(ctx);
|
||||
bindProductionMedia(ctx);
|
||||
|
||||
// Kick off the retention purge cycle (audit finding A3): enqueue the first
|
||||
// `retention-purge--<slug>` job for every collection declaring a
|
||||
// custom.retention.purgeSchedule. The task definitions live in the Payload
|
||||
// config (core-cms jobs.tasks); each run re-enqueues the next cycle.
|
||||
await registerRetentionPurgeJobs({
|
||||
queue,
|
||||
config: resolvedConfig,
|
||||
getPayload: getPayload as unknown as GetPayloadFn,
|
||||
auditLog,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user