Як реалізується мультиплатформова синхронізація
1) Що таке мультиплатформова синхронізація і навіщо вона потрібна
Мультиплатформова синхронізація - це узгоджене оновлення одних і тих же даних на різних пристроях і клієнтах: мобільних додатках (iOS/Android), веб/PWA, десктопах та інтеграціях (боти, міні-додатки). Цілі:- Безперервність: продовжити з того ж місця на будь-якому пристрої.
- Стійкість до офлайну: працювати без мережі і безпечно «наздоганяти» сервер.
- Швидкість продукту: мінімальні затримки між дією і появою результату скрізь.
2) Базова архітектура (скелет)
1. Єдина доменна модель: чіткі сутності (користувач, гаманець/баланс, транзакція, налаштування, обране тощо) та їх зв'язки.
2. Сервер синхронізації: API-шлюз (REST/GraphQL), шар версіонування, журнал змін (event log).
3. Клієнти: локальна БД (SQLite/Room/Core Data/Realm/IndexedDB), кеш статик-ресурсів (App Shell), outbox для офлайн-операцій.
4. Транспорт: запити на читання/запис + канали «пуш-інвалідation» (WebSocket, SSE, мобільні пуши) для повідомлення про нові версії.
5. Ідентифікація та доступ: OIDC/OAuth2 + короткоживучі токени (access) і ротація refresh-токенів.
6. Спостережуваність: логи сінка, метрики, алерти.
3) Модель даних і версіонування
Глобальні версії: 'updated _ at '/' version'на кожному об'єкті, монотонно зростаючі.
Інкрементальні фіди: `GET /changes? since = cursor'повертає дельту змін.
ETag/If-None-Match: економить трафік на незмінених ресурсах.
Локальні «тіні» (shadow state): клієнт зберігає останню відому версію для порівняння і мерджа.
4) Патерн офлайну: outbox + ідемпотентність
Будь-яка дія «на запис» потрапляє в outbox з тимчасовим'client _ id', часом, типом операції і тілом запиту.
Надсилання пакетами (batch) з експоненціальним backoff при помилках.
Ідемпотентність: в заголовку/ендпоінті - ключ операції ('Idempotency-Key'). Повтор не створить дублів.
Атомарність: додавання в outbox і локальне оновлення - в одній транзакції БД.
5) Конфлікти і стратегії мерджа
LWW (Last Write Wins): просто і швидко; ризик втрати правок, підходить для налаштувань/лайків/прапорів.
Версіонування/Precondition: сервер відхиляє застарілі записи ('412 Precondition Failed') → клієнт показує дифф і пропонує перезаписати/об'єднати.
OT (Operational Transform): для текстів/спільного редагування.
CRDT (Conflict-free Replicated Data Types): для списків, лічильників, наборів; автоматичний мердж без конфліктів.
Польова політика: «істина сервера» для грошей/балансів; «істина клієнта» для локальних міток.
UX при конфлікті: бейдж «Потрібне рішення», порівняння версій, вибір «Залишити моє/Злити/Перезавантажити».
6) Транспорт і способи доставки змін
Pull: періодичні запити'changes? since = cursor'( дешево і просто).
Push-invalidate: WebSocket/SSE шле «хінт» про нові зміни → клієнт робить швидкий pull.
Webhooks: сервер повідомляє сторонні сервіси/ботів; для клієнтів - краще push + pull.
GraphQL Subscriptions: для realtime-сценаріїв, при цьому все одно зберігайте локальний курсор.
7) Фонові задачі та обмеження платформ
iOS: Background Tasks/Push with content-available; обмеження часу та енергії.
Android: WorkManager/Foreground service за потребою (дбайливо до батареї).
PWA: Background Sync/Periodic Sync (з нюансами на iOS), Service Worker для кешу та офлайну.
Політика retries: backoff, ліміти, стоп при low battery/roaming (настроюється).
8) Безпека і приватність
Автентифікація: OIDC/OAuth2, PKCE для публічних клієнтів.
Шифрування в транзиті: TLS 1. 2/1. 3, строгий ciphersuite, HSTS; по можливості - certificate pinning в мобайлі.
Шифрування на пристрої: ключі/токени - в Keychain/Keystore; чутливі дані - AES-GCM.
Ізоляція середовищ: dev/stage/prod з різними ключами, заборонений «бойовий» датасет поза prod.
Авторизація на об'єкт: серверна перевірка прав на кожну сутність в синці (не довіряйте клієнту).
Журнал аудиту: хто що змінив і коли; потрібен для фінансових/регуляторних кейсів.
9) Продуктивність і економія трафіку
Дельти замість повнотілих об'єктів (patch/JSON Patch, GraphQL @defer/ @stream).
Компресія: Brotli/Gzip; двійкові протоколи (MessagePack/Protobuf) для чатів/телеметрії.
Курсори та пагінація: 'limit/next _ cursor', ніяких важких «все і відразу».
Коалессенс подій: об'єднуйте часті дрібні зміни (debounce) перед відправкою.
Кеш-контроль: розумні TTL і ETag для незмінних ресурсів.
10) Спостережуваність і метрики синхронізації
Sync Success Rate: частка успішних циклів сінка.
Time To Consistency (TTC): середній час, за який зміна видно на всіх активних пристроях.
Conflict Rate и Resolve Time.
Outbox Depth і середній Age елементів.
Payload Size / Session и Retry Count.
Battery Impact (мобайл), Data usage.
SLO: Наприклад, 95% змін консистентні ≤ 3 сек при онлайні.
11) Тестування та хаос-сценарії
Network Shaping: 2G/3G, високий RTT, втрати 1-10%, «флапаючий» Wi-Fi.
Kill & Resume: вбивство процесу в момент сінка.
Дедлоки/конкуренція: паралельні правки з двох пристроїв під різними акаунтами/ролями.
Масова міграція схеми: відкат/повтор при помилці міграції локальної БД.
Безпека: підміна токена, MITM-тести, спроби re-use ідемпотентних ключів.
12) Міграції схеми і зворотна сумісність
Версії схеми: 'schema _ version'в клієнтській БД; міграції покрокові і безпечні до відкату.
Forward/Backward сумісність API: додавайте поля неруйнівно; старі клієнти ігнорують невідоме.
Feature flags: поетапне включення нових типів даних/подій.
Подвійний запис (dual-write) на час міграції на сервері + валідація консистентності.
13) Часті помилки - і швидкі фікси
«Пишемо відразу в мережу, а офлайн потім» → починайте з outbox-патерну та ідемпотентності.
Немає курсорів/дельт → вибухає трафік і час синка. Вводите'changes? since`.
LWW для критичних фінансових даних → використовуйте суворі інваріанти, транзакції та бізнес-правила на сервері.
Приховані конфлікти → додайте користувальницький дифф/решалку.
Фонові завдання без лімітів → посадіть батарею; поважайте OS-політики.
Зберігання секретів у відкритому вигляді → Keychain/Keystore + шифрування.
Відсутність метрик → неможливо зрозуміти, де «тече». Увімкніть Telemetry/Tracing з PII-санітайзером.
14) Чек-лист впровадження (90 днів)
1. Специфікація моделі і карти даних (ERD), вибір стратегій мерджа по сутностях.
2. API для дельт: `/changes? since', курсори, ETag, пагінація.
3. Outbox на клієнтах: транзакції, ідемпотентні ключі, backoff.
4. Push-invalidate: WebSocket/SSE або пуши з content-available → швидкий pull.
5. Локальна БД + міграції (Room/Core Data/Realm/IndexedDB).
6. Безпека: OIDC, TLS, pinning, шифрування на пристрої, RBAC на сервері.
7. Метрики та логи: TTC, conflict rate, outbox depth, retries, battery/data usage.
8. Хаос-тести: погана мережа, kill-resume, конфлікти, міграції.
9. UX-сигнали: статуси онлайн/офлайн/сінк, дифф при конфлікті, «повторити/скасувати».
10. Поступовий rollout: прапори, канарки, фільтр по регіонах.
15) Міні-FAQ
Pull або push?
Краще гібрид: push-invalidate повідомляє «є нове», а потім легкий pull по курсору.
CRDT або LWW?
CRDT дорожче в реалізації, але хороший для спільного редагування/списків. Для більшості налаштувань/прапорів вистачить LWW, для фінансів - строгі серверні інваріанти.
Як вкластися в батарею?
Батчі, backoff, групова відправка, «тихі вікна» і відключення агресивних ретраїв в роумінгу/низькому заряді.
Що робити з приватними даними офлайн?
Мінімізувати, шифрувати, зберігати ключі тільки в Keychain/Keystore; передбачити авто-очищення.
Чи потрібен GraphQL?
Зручний для вибірок і дельт; але REST з курсорами і ETag теж відмінно працює. Головне - дисципліна версій і дельт.
Мультиплатформова синхронізація - це не одна «магічна» технологія, а система: єдина модель даних і версіонування, офлайн-черга і ідемпотентність, розумні стратегії мерджа, гібрид push/pull, фонові завдання з повагою до батареї, сувора безпека і прозорі метрики. Реалізувавши ці шари послідовно і перевіривши їх в хаос-сценаріях, ви отримаєте передбачувану, швидку і безпечну синхронізацію на всіх платформах - без втрат даних і нервів користувачів.