Retention Policy
90-Day Rolling Cleanup
This policy covers removable logs and operational audit rows that are not needed for active product operation, billing, legal obligations, or security investigations.
Cleanup Scope
- `usage_logs` rows older than 90 days, using `coalesce(completed_at, started_at)` as the age reference.
- `pivot_target_audit_logs` rows older than 90 days.
- `mcp_invocation_audit_logs` rows older than 90 days.
Excluded State
- `accounts`
- `users`
- `monday_tokens`
- `saved_pivots`
- `scheduled_syncs`
- `mcp_service_identities` and `mcp_service_account_allowlist`
Implementation Path
- Config: `RETENTION_CLEANUP_DAYS=90` in backend settings.
- Task: `backend/app/workers/retention_cleanup.py`.
- Schedule: Taskiq cron job `jobs.retention_cleanup` running daily at `03:17` UTC.
- Verification: SQL delete counts plus runtime logs/observability event `monday_retention_cleanup_complete`.
Operational Notes
Transient Redis keys use TTL and are not purged by this SQL task. Job status data expires automatically, and prefetch data uses a short-lived cache window with account-scoped eviction rules.
Uninstall handling is separate: the lifecycle webhook deletes the account state immediately and cascades the remaining account-scoped records.
Proof Targets
- Code path: `backend/app/workers/retention_cleanup.py`.
- Tests: `backend/tests/test_retention_cleanup.py`.
- Database proof: run a query selecting rows older than 90 days in the audit tables and confirm the cleanup task deletes them.