Security
Retention policy
How long Matter retains each data class. Per-table policy enforced by nightly cron. Audit chain retained forever; idempotency records purged at 30 days; event delivery logs at 90 days. GDPR Article 17 erasure is the customer-controlled escape hatch.
Last updated
This document is the authoritative retention policy for every Matter table. Retention rules apply per-row and run nightly via apps/api/app/api/cron/apply-retention/route.ts. The cron is owned by the Platform context and audited quarterly.
A table's retention rule is not negotiable per customer. The single exception is GDPR Article 17 erasure (P0.D4) which acts on Restricted and Highly Restricted PII regardless of the table's standard retention.
Per-table retention table
| Table | Retention | Rationale | Cold tier? |
|---|---|---|---|
AuditEntry | Forever (1 year hot, then cold) | Tamper-evident chain; regulatory; customer trust. Anchored to Sigstore Rekor (effectively immutable). | Cold tier at 1 year (S3 object-lock). |
Event | 7 years hot, then cold | Canonical state log; CQRS replay; customer-facing trace context. | Cold tier at 90 days. |
EventDelivery | 90 days hot, then aggregate-only | Per-delivery attempt log; 30-day replay window requires the recent ones. | Aggregate stats retained 7 years; per-attempt rows purged. |
IdempotencyRecord | 30 days hot, then purge | Beyond the 24h TTL plus a buffer for forensics; no long-term value. | None (purged outright). |
BackgroundJob | 90 days hot, then aggregate | Terminal job rows retained for forensics; aggregate stats for capacity planning. | Aggregate retained 1 year; per-job rows purged. |
SagaInstance | 1 year hot | Recoverable from Event log; saga state itself is for in-flight orchestration. | None. |
Request | 7 years hot | Customer-facing async record; appears in customer dashboards. | Cold at 90 days. |
Entity and all aggregate root tables | Indefinite (active resources) / 7 years (dissolved entities) | Customer's own data. Dissolution retains 7 years for regulatory tail. | Dissolved entities cold at 1 year post-dissolution. |
Document + DocumentVersion | Indefinite (executed) / 7 years (void or superseded) | Legal artefacts; tail retention for litigation hold. | Cold at 1 year for non-current versions. |
Mail | 7 years hot, then cold | Regulatory mail; tail for litigation hold. | Cold at 1 year. |
Token (revoked / expired) | 7 years hot | Auditable token lifecycle; principal attribution back-reference. | None. |
AuthAttempt (failed auth log) | 90 days hot, then aggregate | Anomaly detection corpus; per-attempt purged after 90 days. | Aggregate stats retained. |
Consent (ESRA, acknowledgements) | Forever | Compliance proof that ESRA / acknowledgements were signed. Required for legal validity of downstream Documents. | Cold at 1 year. |
ApiTraffic (traffic capture) | 90 days hot, 1 year warm, then aggregate | Customer-facing request inspector (last 50 calls; from this table). | Warm tier at 90 days; aggregate stats at 1 year. |
Usage (metering) | 7 years hot | Billing audit trail. | Cold at 1 year. |
Invoice | Forever | Tax / accounting. | Cold at 1 year. |
How retention executes
Nightly cron at apps/api/app/api/cron/apply-retention/route.ts:
- Loads the per-table retention rules from
packages/database/src/retention.ts. - For each table, computes the cutoff timestamps for hot → warm, warm → cold, and cold → purge transitions.
- Runs each transition as a typed BackgroundJob:
- hot → warm: move rows to a warm-tier table (same DB, different partition / table).
- warm → cold: export rows to S3 object-lock storage; delete from warm tier.
- cold → purge: for tables where outright deletion is allowed (per the table above), delete from cold storage.
- Emits
retention.appliedevents for observability + dashboards.
The cron is monitored: failure to apply retention is a SEV3 alert; failure across multiple consecutive nights escalates to SEV2.
What we do not delete
Per the table above, the following are retained forever (or 7 years minimum):
- Audit chain. The hash-chained record of every state transition. Required for tamper-evidence; required for SOC 2; required for customer trust. Anchored to Sigstore Rekor (public WORM log) so even our deletion would not erase the historical witness.
- Event log. The canonical state-transition record. Replay-from-zero requires it; future debugging requires it.
- Consents. Proof that ESRA or acknowledgements were signed at execution time. Legal validity of downstream Documents depends on the consent record being available.
- Invoices. Tax / accounting requirement.
GDPR Article 17 erasure
A customer (or a stakeholder named in a customer's data) may exercise the right to erasure via POST /v1/stakeholders/{id}/erase. The erasure flow (P0.D4):
- Tombstones every PII column on the Stakeholder row (Restricted and Highly Restricted fields).
- Destroys the per-row DEK via KMS, rendering any backup of the encrypted columns unrecoverable.
- Cascades to dependent rows (e.g., Grant rows referencing the stakeholder) — PII is tombstoned; non-PII (
grant_id,entity_id) remains for cap-table integrity. - Writes a sealed audit entry:
stakeholder.erased. The audit chain remains intact. - Notifies the customer via webhook + dashboard.
Erasure of customer-owned data — i.e., the customer themselves leaving Matter — follows the standard offboarding flow with a 90-day reversal window after which the customer's data is purged per the per-table rules.
What changes when we add a new table
A new table is added via:
- Prisma schema PR.
- Retention rule added to
packages/database/src/retention.tsin the same PR. - CI gate fails if a new table appears in the schema without a retention rule.
- The new rule is added to the table above (this docs page).
The default for a new tenant-scoped table is 7 years hot, then aggregate-only unless otherwise justified.
Why retention is a published commitment
Published retention is part of the SOC 2 + ISO 27001 evidence pack. Customers in regulated industries (healthcare, finance) need it for their own audits. The data-processing addendum (DPA) at apps/docs/content/docs/customer-contracts/dpa.mdx (lands P11) references this page.
See also
- Data classification — which fields are Restricted vs Highly Restricted vs others.
- Threat model — T15 covers GDPR erasure.
- Customer SLA — the data-handling commitments.