Реалізація права на експорт даних (Data Portability) у мобільному додатку
GDPR Article 20 та App Store Review Guideline 5.1.1 вимагають надати користувачу копію своїх даних у машиночитаємому форматі. Apple з 2022 року активно перевіряє це при ревю додатків, що працюють з персональними даними. Відсутність функції експорту — реальна причина відмови.
Що включати в експорт
Мінімальний набір за GDPR: всі дані, які користувач надав напрямку (профіль, настройки, контент), та дані, створені в результаті використання сервісу (історія дій, трансакції, переваги).
Не обов'язково: похідні дані (analytics aggregates, ML-моделі), технічні логи (server access logs), дані інших користувачів.
Формати: JSON переважний для машиночитаємості, CSV — для користувачів, що хочуть відкрити в Excel. ZIP архів з кількома файлами — стандартна практика (як Google Takeout).
Серверна реалізація експорту
Експорт — потенційно важка операція. Не робіть синхронну відповідь на HTTP-запит:
POST /api/user/export-request
→ 202 Accepted { "job_id": "exp_xxxx", "estimated_minutes": 5 }
GET /api/user/export-request/exp_xxxx
→ 200 { "status": "processing" | "ready", "download_url": "...", "expires_at": "..." }
Фонова задача (Celery, Sidekiq, Laravel Queue) збирає дані з усіх таблиць, формує архів, завантажує в S3/сховище з presigned URL на 24–72 години. Після завершення — push-сповіщення або email.
Presigned URL з TTL критичен: не відавайте прямих посилань на S3 без авторизації — це витік даних.
Клієнтський флоу
// iOS — запит експорту та polling статусу
class DataExportViewModel: ObservableObject {
@Published var exportState: ExportState = .idle
func requestExport() async {
exportState = .requesting
let job = try await api.requestDataExport()
exportState = .processing(jobID: job.id)
await pollStatus(jobID: job.id)
}
private func pollStatus(jobID: String) async {
while true {
try? await Task.sleep(nanoseconds: 30_000_000_000) // 30 секунд
let status = try await api.getExportStatus(jobID: jobID)
if status.isReady {
exportState = .ready(downloadURL: status.downloadURL!)
return
}
}
}
}
При отримання ready — пропонуємо користувачу зберегти файл через UIDocumentPickerViewController (iOS) або ActivityResultContracts.CreateDocument (Android). Не зберігаємо в Documents автоматично без згоди.
Обмеження частоти запитів
Користувач не повинен мати можливість запитувати експорт кожні 5 хвилин — це навантаження на БД. Розумний ліміт: один запит на 24–48 годин. Показуємо дату останнього експорту та час до наступної можливості.
Терміни — 1–3 дні: серверна черга експорту, збір даних з усіх джерел, формування архіву, клієнтський UI з polling та скачуванням.







