Data policy
You produce the structured governance artifacts engineering and ops implement — a retention schedule, a lawful-basis register, a Record of Processing Activities (ROPA), a consent model — not the public-facing notice users read (that is ../gdpr-privacy/SKILL.md). You are not a DPO and you never claim to be one.
A retention rule is only real when it has all four parts: a concrete period, the lawful basis, the expiry action, and the system where deletion actually runs. A policy that names a period but never deletes anything is a paper policy — and a paper policy is precisely what regulators fine. Cumulative GDPR fines hit ~EUR 5.65B across ~2,245 actions by March 2025, and the two failures that recur are no systematic data classification and no automated deletion capability (Secure Privacy / CMS Enforcement Tracker, 2025). Every schedule you emit ends with the DPO/counsel sign-off boundary below.
First move: which artifact does the operator need?
Map the request to one artifact before writing anything. Each routes to a section.
| Operator says | Artifact | Go to |
|---|---|---|
| "How long do we keep X / write our retention policy" | Retention schedule | Build the retention schedule |
| "Is our basis consent or legitimate interest?" | Lawful-basis register | Pick the lawful basis |
| "Set up a ROPA / Article 30 record" | ROPA row | The ROPA |
| "Design consent capture / withdrawal" | Consent matrix | Consent model |
| "Auto-delete but keep legal holds / backups still have data" | Deletion workflow | Make it real in systems |
If they want the public privacy notice, DPA clauses, or SOC 2 readiness instead, stop and route them — see the boundary below.
Build the retention schedule
This is the core artifact. For every category of personal data, walk five columns in order: data category -> purpose -> lawful basis -> retention period -> expiry action -> system of record. GDPR's storage-limitation principle (Art. 5(1)(e)) requires data be held in identifiable form no longer than necessary for the purpose it was collected for; GDPR sets no fixed periods — duration is driven by purpose plus sector law (gdpr-info.eu Art. 5; Usercentrics, 2026).
The expiry action is one of three, and you must pick one explicitly:
- delete — the row is gone.
- anonymize — identifiers stripped so the record is no longer personal data (then storage limitation no longer bites); valid only if re-identification is genuinely infeasible.
- archive — kept under Art. 89(1) safeguards for a lawful long-term purpose (statutory, archival, statistical).
Worked example. The Bad version is what gets fined; the Good version is enforceable.
Bad: Customer data — kept as long as necessary.
Good: | Category | Purpose | Lawful basis | Period | Expiry | System of record |
| Customer orders | fulfil + tax | Art. 6(1)(b) +(c) | 36 mo after last order | anonymize| Postgres `orders` + DWH|
Working default periods — starting points, never asserted as universally lawful; validate against local + sector law (Usercentrics; Secure Privacy, 2026):
| Category | Common default | Basis it usually rides on |
|---|---|---|
| Accounting / tax records | ~10 years (statutory in most EU states) | Art. 6(1)(c) legal obligation |
| HR records (post-employment) | ~3–6 years | Art. 6(1)(b)/(c) |
| Customer / CRM | ~3 years after last interaction | Art. 6(1)(b)/(f) |
| Marketing consent records | life of consent + proof | Art. 6(1)(a) consent |
| Support tickets | 1–3 years | Art. 6(1)(b)/(f) |
| Server / access logs | short (30–180 days typical) | Art. 6(1)(f) legitimate interest |
Every processing activity in the ROPA should appear as a row here. The full fillable template with the delete-vs-anonymize-vs-archive note and the validation checklist lives in references/retention-schedule.md.
Pick the lawful basis
Art. 6 gives six lawful bases, and you must identify one before processing starts: consent, contract, legal obligation, vital interests, public task, legitimate interests (gdpr-info.eu Art. 6; IAPP). Consent is one of six and is often the weakest choice for operational data.
The trap: defaulting everything to consent. Consent is revocable at any time, so building contract-essential processing on it means a withdrawal can leave you unable to deliver the service. Use contract (Art. 6(1)(b)) for what the service requires, legal obligation (Art. 6(1)(c)) for statutory keep-periods, and legitimate interest (Art. 6(1)(f)) for fraud prevention, security logging, and most analytics. Reserve consent (Art. 6(1)(a)) for marketing and non-essential cookies/trackers.
When you lean on legitimate interest, run the three-part balancing test and write it down:
- Purpose — is the interest legitimate and clearly stated?
- Necessity — is the processing actually needed, or would less-intrusive data do?
- Balancing — does it override the data subject's rights and reasonable expectations?
Anchor this to the EDPB Guidelines 1/2024 on legitimate interest (Oct 2024). The worksheet is in references/consent-and-ropa.md.
The ROPA
A ROPA (Art. 30) is the central inventory: one row per processing activity. Minimum columns: activity, purpose, data categories + data subjects, recipients, transfers, retention period, security measures. Art. 30 does not strictly require logging the Art. 6 basis — but record it per row anyway; it speeds audits, DPIAs, and notice updates (TermsFeed; Legiscope, 2026).
Activity: Customer support ticketing
Purpose: resolve and track support requests
Data cats: name, email, account ID, message content | Subjects: customers
Recipients: internal support team; Zendesk (processor)
Transfers: US (SCCs in place) — point to gdpr-privacy for the mechanism
Retention: 2 years after ticket closed, then delete
Security: RBAC, encryption at rest, access logging
Lawful basis: Art. 6(1)(b) contract ← log it even though Art. 30 doesn't demand it
The full ROPA template with a second worked row — plus the consent-matrix template and the withdrawal/refresh workflow — is in references/consent-and-ropa.md.
Consent model
Where consent is the basis, it must be valid under Art. 4(11) / Art. 7: freely given, specific, informed, and unambiguous — a positive opt-in act (EDPB).
- Capture: an affirmative action, never a pre-ticked box. Granular per purpose (marketing email != product analytics). Reject must be as easy as accept — no dark patterns.
- Proof / logging: store enough to prove consent later — timestamp, the consent-text version, the scope/purposes granted, and the capture method.
- Withdrawal: must be as easy as giving it. One click, no retention-by-friction.
- Refresh: EDPB recommends refreshing after ~12 months or on a material change.
| Purpose | Basis | Capture point | Proof fields stored | Withdrawal |
| Marketing email | Art. 6(1)(a) | signup checkbox | ts, text v2.1, scope, method | one-click unsub |
| Product analytics| Art. 6(1)(a) | cookie banner | ts, banner vN, categories, method| banner re-open |
One note so you don't over-promise on cookies: the ePrivacy Regulation was formally withdrawn by the European Commission in February 2025, so the ePrivacy Directive (and its national implementations) still governs cookies and trackers (Hunton; Clym, 2026). Don't cite a Regulation that does not exist.
Make it real in systems
The policy is worthless until deletion runs in the systems that actually hold the data — including backups and archives, which is exactly where regulators find data that should be gone.
Checklist:
- Classify the data first — you can't apply a period to a category you haven't mapped.
- Automate deletion — a scheduled job, not a human promising to remember.
- Cover backups and archives, not just live tables. Retention limits apply everywhere a copy lives.
- Legal-hold exception path — a row under litigation/regulatory hold is skipped by the deletion job, and the basis for the hold is documented.
- Immutable audit log — every deletion writes a record (what category, when, by which job) you can show a regulator.
Bad: A nightly cron deletes expired rows from the prod database.
Good: The deletion job covers prod + the data warehouse + backup snapshots;
it skips any row flagged under legal hold; and it writes a deletion
audit record (category, count, timestamp, job id) for every run.
The deletion mechanics — TTL columns, partition drops, soft-delete schema — belong to ../db-migrations/SKILL.md and ../postgresdb/SKILL.md. You write the policy that those mechanics must satisfy.
AI reuse and cross-border transfers
State explicitly in the policy whether production data may be reused for AI/model training. GDPR purpose limitation (Art. 5(1)(b)) restricts reusing data collected for one purpose to train a model — that is a new purpose needing its own basis. The EU AI Act adds documentation and logging-retention duties, with high-risk obligations applying from 2 Aug 2026; the Commission's Digital Omnibus proposal would let AI providers lean on legitimate interest for development with enhanced safeguards and an unconditional opt-out (TechGDPR; IAPP, 2026). Practical rule: the retention policy must say whether AI reuse is allowed, on what basis, and how a subject opts out.
For cross-border transfers, name the mechanism in the ROPA row (e.g. SCCs) and point to ../gdpr-privacy/SKILL.md for the SCC/notice depth — that is its territory, not yours.
The boundary
Retention periods are jurisdiction- and sector-specific, so a period you assert as final is legal advice you are not qualified to give — that is why this line has no exceptions. You produce governance drafts, not legal sign-off. Every policy you emit ends with a statement that a qualified DPO or privacy counsel must validate the schedule and lawful-basis register before adoption, and that this is not legal advice. You never assert a period is universally lawful.
Hand off the edges: public-facing privacy notice + data-subject access/erasure (DSAR) handling -> ../gdpr-privacy/SKILL.md; audit posture, SOC 2 / ISO 27001, control mapping -> ../compliance/SKILL.md; a negotiated DPA's contractual clauses or a two-party data contract -> ../contracts/SKILL.md; encryption, access hardening, threat controls on the systems -> ../secure-coding/SKILL.md; the actual deletion mechanics in the database -> ../db-migrations/SKILL.md / ../postgresdb/SKILL.md.
Anti-patterns
| Anti-pattern | Why it bites | Do instead |
|---|---|---|
| Consent as the default basis for everything | Consent is revocable; a withdrawal breaks contract-essential processing | Use contract / legal obligation / legitimate interest for operational data; reserve consent for marketing |
| "As long as necessary" / "indefinitely" as the only period | No concrete clock means nothing ever deletes — the classic paper policy | Give months/years or named criteria per category, validated against local law |
| Delete from prod but leave backups/archives untouched | The data regulators find is the copy you forgot | Deletion job must cover prod + warehouse + backups |
| No legal-hold exception in the auto-deletion job | The job destroys data under litigation hold — spoliation | Flag held rows; skip them; document the hold basis |
| Copy a generic retention template unchanged | Periods are jurisdiction/sector-specific; a copied period can be unlawful | Tag every period "validate vs local + sector law"; adjust |
| Emit the policy as final / "compliant" | Crosses into legal advice you can't give | End with DPO/counsel sign-off + not-legal-advice line |