feat: GDPR-compliant user self-deletion (anonymization)#928
Open
socksprox wants to merge 3 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
User Self-Deletion (GDPR Art. 17 – Right to Erasure)
Users currently have no way to delete their own accounts. This PR adds a self-service account deletion endpoint that satisfies the GDPR right to erasure via anonymization — not hard deletion. Records that serve a legitimate legal or financial purpose are retained, but all personal identifiers are scrubbed from the user record itself.
What is anonymization deletion?
Unlike a hard delete, anonymization deletion replaces all PII on the user row with placeholder values and soft-deletes the record. The user identity is gone, but historical records that reference them remain intact and consistent.
What gets scrubbed
email→deleted_{id}@deleted.invalidpassword→ random hashpassword_algo,password_salt,last_login_ip,telegram_id→ nulluuid,token→ regenerated (subscribe URL immediately invalidated)plan_id,group_idnulled;bannedset to trueWhat is retained
These records keep their
user_idFK but the row they point to contains no personal data.Changes
deleted_atinteger column onv2_user(integer to matchdateFormat = 'U')SoftDeletestrait — deleted users automatically excluded from all queries including broadcast/reminder emailsPOST /api/v1/user/destroy: new endpoint, requires password confirmation, blocks admin accountsTicket.user(),Order.user(),Order.invite_user()usewithTrashed()so admins can still see historical records tied to deleted userstransformUserData(): null-safe for soft-deleted user referencesdestroy+clear:user: updated toforceDelete()to preserve existing hard-delete behaviour