16 KiB
status, playbook-section, title, gdpr-articles, last-reviewed
| status | playbook-section | title | gdpr-articles | last-reviewed | |||||
|---|---|---|---|---|---|---|---|---|---|
| template | 10 | Data Subject Rights (DSR) Fulfilment Procedure |
|
[FILL IN: YYYY-MM-DD] |
Data Subject Rights (DSR) Fulfilment Procedure
Template status — fill every
[FILL IN: …]marker before use. Cross-references below point to shipped interfaces, endpoints, and ADRs; do not change them.
1. Purpose & Scope
This procedure governs how [FILL IN: organisation name] receives, validates, fulfils, and records requests from data subjects exercising rights under GDPR Articles 15–20.
Covered rights:
| GDPR Article | Right | Shipped interface |
|---|---|---|
| Art. 15 + 20 | Access + Portability | IDataExport (dsr.export) |
| Art. 16 | Rectification | IDataRectify (dsr.rectify) |
| Art. 17 | Erasure ("right to be forgotten") | IDataDelete (dsr.delete) |
| Art. 18 | Restriction of processing | IProcessingRestriction (dsr.restrict) |
See docs/guides/dsr.md for the engineering cookbook and docs/decisions/adr-025-eu-compliance-baseline.md § Epic B for the design rationale.
2. Roles & Contacts
| Role | Name | Contact |
|---|---|---|
| Data Protection Officer | [FILL IN: name / DPO provider] | [FILL IN: contact] |
| DSR Coordinator | [FILL IN: name] | [FILL IN: contact] |
| Engineering contact (fulfilment) | [FILL IN: name] | [FILL IN: contact] |
Intake channel: [FILL IN: e.g. privacy@example.com / online form URL]
3. Statutory Deadlines
| Stage | Deadline | Extension |
|---|---|---|
| Acknowledge receipt | [FILL IN: e.g. 5 business days] |
— |
| Fulfil or refuse | 1 calendar month from receipt (GDPR Art. 12(3)) | Up to 2 further months for complex/numerous requests; notify subject within the first month |
| Notify subject of refusal | 1 month | — |
Deadline clock starts when the organisation receives the request — not when identity is verified.
4. Phase 1 — Receipt & Intake
4.1 Intake channels
Accept DSR requests via:
[FILL IN: primary channel, e.g. privacy form at https://example.com/privacy/request][FILL IN: secondary channel, e.g. email to privacy@example.com]- Any written format (GDPR does not mandate a specific form)
4.2 Logging the request
Log each incoming request immediately in [FILL IN: DSR register / issue tracker] with:
| Field | Value |
|---|---|
| Reference ID | DSR-YYYY-NNN (sequential) |
| Right requested | Art. 15 / 16 / 17 / 18 / 20 |
| Channel | email / form / letter |
| Received at | ISO 8601 timestamp |
| Deadline | received + 1 month |
| Status | pending-verification |
4.3 Acknowledgement
Send acknowledgement to the requester within [FILL IN: e.g. 5 business days] confirming:
- Receipt of the request
- Reference ID
- Identity verification requirement (§ 5)
- Statutory deadline
Template: [FILL IN: path to acknowledgement email template]
5. Phase 2 — Identity Validation
5.1 Verification requirement
GDPR Art. 12(6) permits identity verification when there is reasonable doubt. Always verify for Art. 17 (erasure) and Art. 18 (restriction). For Art. 15 (access) of clearly authenticated users, verification may be satisfied by existing session.
5.2 Verification methods
| Method | Acceptable for |
|---|---|
| Authenticated session in the app | Art. 15, Art. 16 (low-risk fields) |
| Email confirmation to registered address | All rights |
[FILL IN: government ID / identity provider] |
Art. 17 cascade-hard, Art. 18 |
5.3 Rejected or suspicious requests
If identity cannot be verified after [FILL IN: e.g. 14 days]:
- Close the request with status
identity-unverified. - Notify the requester in writing of the outcome.
- Log closure in the DSR register.
6. Phase 3 — Fulfilment
6.1 Identify the subject record
Map the verified identity to the system subjectId (Payload users.id or equivalent auth collection primary key). Cross-reference compliance/data-map.yml (generated by pnpm compliance:data-map) to enumerate which collections hold personal data for this subject.
# Regenerate data map to ensure it reflects current schema
pnpm compliance:data-map
Review compliance/data-map.yml fields tagged exportable: true (Art. 15/20) and restrictable: true (Art. 18).
6.2 Art. 15 + 20 — Access and Portability
Interface: IDataExport.exportSubjectData(subjectId, format)
tRPC procedure: dsr.export (query — no mutation)
GDPR deadline: respond within 1 month; provide data without charge for first copy.
Invoke via the admin tRPC client or the REST endpoint wired in apps/web-next:
GET /api/gdpr/export?subjectId=<id>&format=json
GET /api/gdpr/export?subjectId=<id>&format=json-ld # machine-readable JSON-LD
The response is a UserDataBundle:
data— keyed by Payload collection slug; each bucket containsasSelf(rows the subject owns) andasReference(rows merely referencing the subject)auditLog— the subject's audit trail (optional; include for transparency)exportedAt— ISO 8601 export timestamp for the certificate of fulfilment
Audit entry emitted: EXPORT action, resource.type: "data-subject", resource.id: subjectId.
Deliver the export to the subject via [FILL IN: secure delivery method, e.g. encrypted download link / secure email].
6.3 Art. 16 — Rectification
Interface: IDataRectify.updateSubjectField(subjectId, collection, field, value)
tRPC procedure: dsr.rectify (mutation)
Scope: only fields tagged custom.pii in the Payload collection config (i.e. fields indexed in compliance/data-map.yml).
POST /api/gdpr/rectify
Body: { subjectId, collection, field, value }
Steps:
- Confirm the field is
custom.pii-tagged incompliance/data-map.yml. - Confirm the new value passes Payload field validation.
- Invoke the procedure; the implementation emits a
RESTRICTaudit entry withreason: "art-16-request". - Notify the subject that rectification is complete and, if data was shared with third parties, notify them per Art. 19.
Third-party notification log: [FILL IN: log location]
6.4 Art. 17 — Erasure
Interface: IDataDelete.deleteSubjectData(subjectId, mode)
tRPC procedure: dsr.delete (mutation — requires authenticated admin session for cascade-hard)
Returned: DeletionCertificate — retain this as evidence of fulfilment.
Mode selection:
| Mode | Effect | Who can invoke |
|---|---|---|
"soft" |
Redacts PII fields in owned rows; NULLs reference fields; row structure preserved | Standard authenticated user or DSR coordinator |
"cascade-hard" |
Hard-deletes owned rows where postDeletion.action === "hard-delete" per retention policy; NULLs reference fields |
Admin role required |
POST /api/gdpr/delete
Body: { subjectId, mode: "soft" | "cascade-hard" }
Exemptions (GDPR Art. 17(3)) — erasure must be refused if data is required for:
- Legal obligation compliance (document refusal in the DSR register)
- Establishment, exercise, or defence of legal claims
Audit trail pseudonymization: after deletion, invoke IAuditLog.eraseSubject(actorId, "pseudonymize") via the admin tRPC to replace the subject identifier in the audit log with erased-{hash[0:16]} (sha256-salted pseudonym per ADR-018). This preserves the event record for regulatory purposes while removing the identifier.
Retention-policy overrides: check compliance/retention-policy.yml for postDeletion rules — some collections may have a grace period (postDeletion.duration: P30D) before hard deletion executes.
# View current retention policy
cat compliance/retention-policy.yml
# Regenerate from Payload field tags
pnpm compliance:retention-policy
DeletionCertificate fields to retain:
subjectId(or pseudonymized form)mode,timestamp,reason: "art-17-request"affected[]— collections and rows modifiedauditEntryId— links to the audit log
6.5 Art. 18 — Restriction of Processing
Interface: IProcessingRestriction.setRestriction(subjectId, granted: true)
tRPC procedure: dsr.restrict (mutation)
POST /api/gdpr/restrict
Body: { subjectId, granted: true }
The implementation sets processingRestrictedAt on the user record. Downstream use cases check isRestricted(subjectId) before processing personal data. The audit channel records a RESTRICT audit entry on every state change.
Grounds for restriction (Art. 18(1)):
- Accuracy of data is contested (pending Art. 16 rectification)
- Processing is unlawful but erasure is opposed by the subject
- Organisation no longer needs the data but subject requires it for legal claims
- Subject has objected (pending verification of legitimate grounds)
Notify the subject when restriction is lifted: invoke dsr.restrict with granted: false and send written notice per Art. 18(3).
Audit entry emitted: RESTRICT (on restriction) / UNRESTRICT (on lift).
7. Phase 4 — Recording & Closure
7.1 DSR register update
Update the DSR register entry (§ 4.2) with:
| Field | Value |
|---|---|
| Fulfilled at | ISO 8601 timestamp |
| Outcome | fulfilled / refused / partially-fulfilled |
| Evidence | DeletionCertificate ID or export reference |
| Audit entry ID | From AuditEntry.correlationId or auditEntryId |
| Status | closed |
7.2 Subject notification
Notify the data subject of the outcome within the Art. 12(3) deadline:
- Fulfilment: summary of actions taken, delivery method for exports.
- Refusal: grounds for refusal (Art. 12(4)), right to lodge complaint with SA, right to seek judicial remedy.
Template: [FILL IN: path to outcome notification template]
7.3 Third-party notification log (Art. 19)
If the corrected, erased, or restricted data was previously shared with third parties (sub-processors listed in compliance/sub-processors.yml), notify each processor of the subject's request. Record each notification in [FILL IN: third-party notification log].
8. Consent-Related DSR Interactions
Consent grant and withdrawal are distinct from Art. 17 erasure but often accompany DSR requests. The consent channel (docs/guides/consent.md) records:
| Audit action | Trigger |
|---|---|
CONSENT_GRANT |
Subject grants consent for a category (e.g. marketing) |
CONSENT_WITHDRAW |
Subject withdraws consent |
RESTRICT |
Art. 18 restriction set |
UNRESTRICT |
Art. 18 restriction lifted |
If a DSR request also includes consent withdrawal, invoke IConsent.withdraw(subjectId, categories) in addition to the relevant DSR procedure. Consent withdrawal does not automatically trigger erasure — only an explicit Art. 17 request does.
9. Appendix — Command Reference
# Regenerate PII data map (enumerate affected collections and fields)
pnpm compliance:data-map
# Regenerate retention policy (check postDeletion rules before Art. 17)
pnpm compliance:retention-policy
# Regenerate sub-processor list (for Art. 19 third-party notification)
pnpm compliance:sub-processors
# Regenerate all compliance artifacts in one pass
pnpm compliance:emit-all
# Run fallow audit before closing a DSR-related PR
pnpm fallow:audit
10. Document Control
| Field | Value |
|---|---|
| Owner | [FILL IN: DPO or DSR Coordinator] |
| Review cycle | [FILL IN: e.g. annual or on schema change] |
| Next review date | [FILL IN: YYYY-MM-DD] |
| Cross-references | docs/decisions/adr-025-eu-compliance-baseline.md, docs/decisions/adr-018-audit-and-compliance.md, docs/guides/dsr.md, docs/guides/audit-and-compliance.md, docs/guides/consent.md, ../data-map.example.yml |