Files
Balance/docs/SYNC_PROTOCOL.md
wt da9e17f45f
Android CI / Build and Test (push) Failing after 13m25s
iOS CI / Build and Test SwiftUI App (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s
added AGENTS.md and docs in root dir
2026-09-08 13:36:43 +07:00

6.1 KiB

Единый протокол синхронизации

Все клиенты (iOS, macOS, watchOS, Android, web) синхронизируются с BalanceServer через один и тот же HTTP(S) API и один и тот же набор инвариантов. Это сводка контракта; детальные описания на стороне сервера — BalanceServer/docs/API.md и BalanceServer/docs/SYNC.md. Клиентские реализации — Balance/docs/SYNC.md и BalanceAndroid/docs/SYNC.md.

Эндпоинты

Метод Путь Назначение
GET /health Health check
POST /v1/auth/register Создание аккаунта
POST /v1/auth/login Вход, выдача access/refresh токенов
POST /v1/auth/refresh Ротация токенов
POST /v1/auth/logout Отзыв refresh-токена
GET /v1/me Текущий аккаунт
POST /v1/sync Push и pull изменений

Нативные клиенты используют Authorization: Bearer <access-token>. Web-клиент использует HttpOnly/SameSite=Strict cookie-сессию — это единственное отличие транспорта, сама sync-семантика идентична.

Основные инварианты

  1. Cursor — каждый клиент хранит курсор последнего успешно применённого изменения. Курсор сохраняется только после успешного применения соответствующего batch, не раньше.
  2. Sequence — сервер поддерживает глобальный монотонный порядок изменений в change stream; порядок не должен уменьшаться и должен быть однозначным при конкурентных запросах.
  3. Push — клиент отправляет свои изменения (POST /v1/sync); сервер валидирует, проверяет владение записью (ownership) и добавляет изменение в change stream. Повторный push (retry) не должен создавать вторую логическую запись из одного и того же client-change (идемпотентность).
  4. Pull — клиент запрашивает изменения после своего курсора; сервер никогда не возвращает чужие данные (изоляция по аккаунту) и поддерживает постраничный pull с продолжением от нового курсора.
  5. Conflict resolution — last-write-wins по updatedAt (syncUpdatedAt на Apple, updatedAt на Android/сервере). Сервер — единственный источник правды в этом сравнении, поэтому не должен произвольно перезаписывать updatedAt при каждом чтении.
  6. Удаления (tombstones) — удаление сущности не является простым DELETE; оно создаёт запись изменения вида { "entity": ..., "id": ..., "deleted": true, "updatedAt": ... }, которая проходит через тот же change stream, что и обычные изменения. На Apple это SyncTombstone/modelContext.deleteForSync, на Android — deletion_journal через DAO-методы deleteTransaction / deleteCategory / deleteBudget.
  7. Batch — Apple-клиент отправляет батчи до 100 изменений и может делить крупные payload'ы; сервер не должен предполагать, что все изменения аккаунта приходят одним запросом. Android должен оставаться совместимым с этим же батчингом.
  8. Reset/full sync — если клиент теряет курсор, сервер должен поддерживать предусмотренный API механизм полного pull или новый baseline-курсор. Неизвестный/просроченный курсор нельзя молча трактовать как актуальный.

Синхронизируемые сущности

  • Транзакция (доход/расход, сумма, дата, заметка, snapshot категории);
  • Пользовательская категория (имя, иконка/emoji, цвет);
  • Месячный бюджет (категория, месяц, лимит);
  • Tombstone / deletion journal запись для удалений.

Подробное пополевое сопоставление — docs/DATA_MODEL.md.

Что нельзя менять без координации

Любое из следующих изменений — breaking change для всех клиентов одновременно, даже если каждый подпроект по отдельности компилируется и проходит собственные тесты:

  • имена/типы JSON-полей в payload'ах /v1/sync и auth-эндпоинтов;
  • HTTP-методы или пути эндпоинтов;
  • семантика курсора/sequence;
  • правило разрешения конфликтов (last-write-wins по updatedAt);
  • формат tombstone-записи.

При таком изменении обнови одновременно: BalanceServer (API + хендлеры + docs/API.md/docs/SYNC.md), Balance/Shared/ServerSync.swift (+ Balance/docs/SYNC.md), BalanceAndroid/.../sync/* (+ BalanceAndroid/docs/SYNC.md) и этот файл.