Data retention
Leatsmap does not delete your data automatically. Retention is a policy decision; the platform exposes the mechanism (and a few sensible defaults) but you control the timeline.
Defaults
Section titled “Defaults”| Table | Default retention | Configurable via |
|---|---|---|
events | Forever | Operator SQL / cron |
sessions | Forever | Operator SQL / cron |
user_profiles | Until GDPR delete | API call |
identity_links | Until GDPR delete | API call |
audit_log | Forever (append-only) | Trigger-enforced |
dlq | 30 days | DLQ_RETENTION_DAYS env on collector |
quota_counters | 13 months | Operator SQL / cron |
Why “forever” on events
Section titled “Why “forever” on events”The platform is designed for analytics — historical trends, year-over-year comparisons, retention curves. A short retention window defeats the use case. If you want short retention, the right move is:
- Roll up to aggregate tables (v1.1 will add materialized views for this).
- Periodically
DELETE FROM events WHERE ts < NOW() - INTERVAL '13 months'.
A scheduled cron + the standard Postgres DELETE is the v1.0 answer. The
platform deliberately does not ship an “event TTL” feature that would
silently delete data — it would conflict with operators who do want
forever retention.
DLQ retention
Section titled “DLQ retention”DLQ rows are pruned by a maintenance job that runs daily inside the
collector. It deletes rows where received_at < NOW() - INTERVAL '$DLQ_RETENTION_DAYS days'. The default of 30 is enough to find
producer bugs in normal release cadence; tune up if your release cycle is
slower.
audit_log retention
Section titled “audit_log retention”Audit rows are append-only. There is a database trigger that refuses
DELETE and UPDATE against the table. To purge for storage reasons,
operators can:
- Archive:
COPY audit_log TO …and rotate to cold storage. - Drop and recreate: requires a deliberate migration step and breaks the “append-only” guarantee for that retention period.
The append-only guarantee is what makes the audit log usable as a compliance artifact.
quota_counters
Section titled “quota_counters”Per-workspace monthly counters. The platform retains 13 months so year-over-year quota math is possible. Older rows can be pruned by an operator cron.
Backup retention
Section titled “Backup retention”Backups are operator-managed and not coupled to the application. Standard Postgres practice: at least one backup per day, retained for as long as your DPIA / compliance posture requires (often 30–90 days for warm backups, longer for cold).
Sample cron for events rollup
Section titled “Sample cron for events rollup”For operators who want 13-month event retention:
-- Run nightly:DELETE FROM eventsWHERE ts < EXTRACT(EPOCH FROM (NOW() - INTERVAL '13 months')) * 1000;(Note: events.ts is unix epoch milliseconds, not a TIMESTAMPTZ.)
What about the events.raw JSONB column?
Section titled “What about the events.raw JSONB column?”The events.raw column carries the verbatim wire payload — including any
operator-defined custom props. It is the versioning safety net
that lets future migrations backfill new typed columns without re-ingesting
from the SDK.
If your retention policy is “delete after N months”, the raw column is deleted with the row — the safety net does not change the retention math.
What does NOT respect retention
Section titled “What does NOT respect retention”- GDPR deletes are unconditional — they purge the affected subject immediately, regardless of retention windows. Retention rules are about storage cost and compliance posture; GDPR is about data-subject rights.
- DLQ replay is unconditional — replaying an entry re-creates a fresh
eventsrow (Path A by design; see Validation). If retention has elapsed since the original, the replay’seventsrow inherits the replay timestamp by default unless you supplyevent.tsexplicitly.