Реализация права на удаление данных (Right to Erasure) в мобильном приложении
Кнопка «Удалить аккаунт» — одно из самых недооценённых требований. App Store с 2022 года обязывает все приложения с аккаунтами предоставлять возможность удаления прямо из приложения (не через форму на сайте). Google Play — аналогично. И GDPR, и CCPA дают пользователю право на это удаление.
Технически «удалить аккаунт» — это не одна SQL-команда. Это каскадный процесс, который при неправильной реализации либо удаляет не всё, либо удаляет то, что удалять нельзя.
Что нужно удалить, а что нельзя
Данные делятся на три категории:
Удалить немедленно: профиль пользователя (имя, email, фото), история действий, контент созданный пользователем, токены аутентификации, push-токены, данные аналитических систем (через API этих систем).
Анонимизировать, не удалять: агрегированные метрики (количество покупок влияет на бизнес-статистику), контент с которым взаимодействовали другие пользователи (комментарии можно заменить на «Удалённый пользователь»).
Хранить вопреки запросу: финансовые транзакции (требования налогового законодательства, обычно 5–7 лет), данные по судебным удержаниям, данные необходимые для расследования мошенничества.
Архитектура процесса удаления
Удаление не должно быть синхронным — особенно если данные разбросаны по нескольким сервисам. Правильная схема: запрос → очередь → асинхронное выполнение → подтверждение.
class AccountDeletionService(
private val deletionQueue: DeletionQueue,
private val notificationService: NotificationService
) {
suspend fun requestDeletion(userId: String, reason: DeletionReason?) {
// 1. Немедленно блокируем аккаунт — никаких новых данных
userRepository.setStatus(userId, UserStatus.PENDING_DELETION)
// 2. Отзываем все активные токены
authTokenRepository.revokeAll(userId)
// 3. Ставим в очередь удаление по сервисам
deletionQueue.enqueue(
DeletionJob(
userId = userId,
requestedAt = System.currentTimeMillis(),
scheduledFor = System.currentTimeMillis() + GRACE_PERIOD_MS, // 30 дней
steps = listOf(
DeletionStep.PROFILE_DATA,
DeletionStep.ANALYTICS_EVENTS,
DeletionStep.THIRD_PARTY_SDKS,
DeletionStep.BACKUP_ANONYMIZATION,
DeletionStep.AUDIT_LOGS_RETENTION
)
)
)
// 4. Уведомляем пользователя
notificationService.sendDeletionConfirmation(userId)
}
}
Grace period (30 дней) — это возможность восстановить аккаунт, если пользователь передумал. В течение этого периода данные заморожены, но не удалены. По истечении — автоматическое удаление.
Удаление из сторонних систем
Каждый SDK, который получал данные пользователя, должен их удалить:
class ThirdPartyDeletionStep(private val userId: String) : DeletionStep {
override suspend fun execute(): DeletionResult {
val results = coroutineScope {
listOf(
async { deleteFromAmplitude(userId) },
async { deleteFromBraze(userId) },
async { deleteFromFirebaseAnalytics(userId) },
async { deleteFromIntercom(userId) }
).awaitAll()
}
return if (results.all { it.success }) {
DeletionResult.Success
} else {
DeletionResult.PartialFailure(results.filter { !it.success })
}
}
private suspend fun deleteFromAmplitude(userId: String): ServiceDeletionResult {
// Amplitude GDPR API
val response = amplitudeApi.deleteUser(
AmplitudeDeletionRequest(userId = userId, requesterEmail = "[email protected]")
)
return ServiceDeletionResult("amplitude", response.isSuccessful)
}
}
Важно: у Firebase нет прямого API для удаления Analytics данных конкретного пользователя — только через resetAnalyticsData() на устройстве + запрос через Firebase Console/API для серверных данных. Это ограничение нужно учитывать при GDPR оценке Firebase как субпроцессора.
Мобильный клиент: что происходит на устройстве
При подтверждении удаления — немедленная очистка на устройстве, не ждать серверного grace period:
func performLocalDeletion() {
// Keychain
let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword]
SecItemDelete(query as CFDictionary)
// UserDefaults
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
// Core Data / SQLite
try? FileManager.default.removeItem(at: coreDataURL)
try? FileManager.default.removeItem(at: sqliteURL)
// Кеши
URLCache.shared.removeAllCachedResponses()
// Выходим на экран логина
coordinator.navigateToLanding()
}
После локального удаления приложение ведёт себя как при первой установке. Данные на сервере будут удалены по расписанию.
Верификация перед удалением
Нельзя допустить, что злоумышленник удалит данные чужого аккаунта через перехваченный запрос. Перед выполнением:
- Re-аутентификация (пароль или биометрия)
- Подтверждение намерения (не pop-up с двумя кнопками одинакового размера)
- Email с кодом подтверждения для чувствительных аккаунтов
Подтверждение завершения
По GDPR: ответ на запрос на удаление — в течение 30 дней. Пользователь должен получить подтверждение, что удаление выполнено. Если полное удаление невозможно по юридическим основаниям — объяснение, что именно и почему сохраняется.
Сроки: базовая реализация (UI + локальное удаление + серверная очередь): 1–2 дня. С удалением из всех субпроцессоров и документированным процессом для GDPR: 2–3 дня.







