Видалення акаунта з періодом заперечення (м’яке видалення + анонімізація)
Коротко: Замість того щоб одразу безповоротно видаляти акаунт за запитом на видалення, спершу фіксується лише момент часу (pending_deletion_at) — акаунт фактично анонімізується лише після закінчення строку.
Докладніше: Негайне жорстке видалення ризиковане: випадковий клік, зламаний акаунт чи відкликання запиту на видалення інакше вже не можна було б скасувати. Строк залишає місце для «скасування», не суперечачи праву на видалення (ст. 17 GDPR) — після закінчення строку персональні дані видаляються/анонімізуються (anonymizedAt фіксує, КОЛИ це сталося).
Наш контекст: В Emzett db/migrations/add_v27_session_version_deletion.sql додає users.pending_deletion_at і users.anonymized_at — 7-денний період заперечення перед фактичною анонімізацією.
Подробиці
Не юридична консультація, а технічна класифікація. Право на видалення (ст. 17 GDPR) не обов’язково вимагає негайного жорсткого видалення — воно вимагає, щоб персональні дані були видалені без невиправданої затримки, коли мета зберігання відпала. Короткий, чітко повідомлений період заперечення з чіткою вказівкою, як можна відкликати запит на видалення, як правило, вважається припустимим, якщо він не використовується для фактичного затягування видалення.
Технічно розрізняють два етапи: м’яке видалення (запис повністю зберігається, лише прапорець/мітка часу позначає його як «заплановане до видалення» — оборотно) і анонімізація (персональні поля замінюються замінниками, які вже не можна відстежити — необоротно). Важливо для справжньої анонімізації: недостатньо видалити лише очевидні поля на кшталт імені/електронної пошти — непрямі ідентифікатори (унікальна комбінація дати народження + поштового індексу, пов’язана, інакше порожня історія замовлень) теж можуть зробити людину повторно ідентифікованою, якщо їх залишити.
-- Запланувати (оборотно)
UPDATE users SET pending_deletion_at = now() + interval '7 days' WHERE id = $1;
-- Після закінчення строку (необоротно, через cron-завдання)
UPDATE users SET email = 'deleted-' || id || '@anon.local', name = 'Deleted user', anonymized_at = now()
WHERE pending_deletion_at < now() AND anonymized_at IS NULL;Див. також: Експорт даних за GDPR (ст. 15/20), GDPR