Client SaaS
TypeScript
Pull Request Merged
PR #203 merged: fix: GDPR/PECR compliance — consent, unsubscribe, erasure, retention
Summary
Compliance fixes from the audit, in rough order of legal urgency:
- Marketing consent is no longer pre-ticked. Pre-ticked boxes are invalid consent under UK GDPR (Planet49/ICO guidance). The registration checkbox now defaults to unchecked and the DB column default flips to
false(the application layer already defaulted to false for headless requests).- ⚠️ Open decision for you, Stu: the original
marketing_opt_inmigration defaulted the entire existing user base totrueas a deliberate soft opt-in. This PR does not change existing users' values — soft opt-in for existing customers is arguable under PECR reg 22(3), but it's your call whether to keep relying on it or reset pre-migration users to false. Happy to do the reset in a follow-up if you want it.
- ⚠️ Open decision for you, Stu: the original
- Launch announcement emails can now be unsubscribed from. They previously had no opt-out at all (PECR reg 22(3)(c) violation).
email_signupsgetsunsubscribed_at, the mailable gets a signed unsubscribe link + footer + RFC 8058 one-click headers, and the signed GET-confirm/POST-act routes mirror the existing user unsubscribe flow. - Erased users are no longer re-targeted. Previously a deleted account's email dropped out of the users-match and became an "unconverted" marketing prospect again. The scope now treats soft-deleted users as converted, and
DeleteUserDataremoves the person'semail_signupsandemail_eventsrows and anonymises their support requests. - Hard delete no longer destroys financial records.
paymentsFKs (quote/client/cleaner) andpayouts.stripe_connect_account_idswitch fromcascadeOnDeletetonullOnDelete— HMRC requires 6 years of transaction records and GDPR Art 17(3)(b) permits retention under legal obligation. - Right to erasure actually works for clients now.
client_profiles.user_idhad no ON DELETE action, so the 30-day hard delete hit an FK violation for any client with a profile (only the cleaner path was tested). Now cascades likecleaner_profiles.
Tests
- Client hard-delete end-to-end (previously only cleaners were covered)
- Payments survive user hard-delete with the user reference nulled
- Erasure removes signups/email events and anonymises support requests
- Signup unsubscribe flow: signed GET confirm, POST act, unsigned rejected, idempotent timestamp, scope exclusion
- Launch announcement: unsubscribed + erased recipients excluded, unsubscribe link + headers rendered
Not in this PR (follow-ups needing retention-policy decisions)
- Scheduled purge for old
email_events/email_signups(needs a chosen retention period) - ID/RTW/DBS document deletion after verification approval (needs a retention rule)
- Privacy policy rewrite (retention table, processor list, ICO complaint right)
+549
additions
-17
deletions
17
files changed