VEU.WathBody/1-docs/4-modules/m09-phone-core/api_specs/03-sync-queue.md

2.7 KiB

Спецификация 03: SyncQueue и ApiClient

Источники: Ф-7, tech-req 5 (SyncQueue: пакеты ≤ 50, WorkManager, ретрай 1→64 мин, WifiOnly), m02 spec 03 (POST /api/v1/sync).

1. Очередь

  • sync_pending(client_guid PK, entity, payload JSON, created_at); запись — только из WorkoutCore (spec 02 §5);
  • Batcher (чистая функция, unit-тест): fun batch(rows: List<Pending>, max: Int = 50): List<List<Pending>> — по возрастанию created_at, порциями ≤ max.

2. SyncWorker (WorkManager, Expedited/OneTime)

  1. Прочитать порции Batcher'ом;
  2. для каждой: POST {BaseUrl}/api/v1/sync c X-Api-Key, тело — JSON-массив конвертов (spec 04 §1);
  3. ответ 200 {"accepted":[guid…]} → deleteAll(accepted) (частично принятый пакет — удалить принятые, rest останется);
  4. 401/409 — не ретраить автоматически: 401 — флаг authError (баннер m10 «ключ неверен»), 409 — конфликт версии программы (пользовательское разрешение — m10; запись остаётся);
  5. сеть/5xx — Result.retry() c backoff WorkManager (setInitialDelay экспоненциально 1→64 мин, policy LINEAR по умолчанию меняем на ручной расчёт от attemptCount);
  6. Sync.WifiOnly=true → constraint UNMETERED;
  7. триггеры: enqueue записи, восстановление сети (constraint), запуск приложения (m10 подпишется).

3. ApiClient (Retrofit + OkHttp + kotlinx-serialization)

interface WatchBodyApi {
    @POST("api/v1/sync") suspend fun sync(@Body items: List<SyncItem>): SyncResponse
    @GET("api/v1/programs/active") suspend fun activeProgram(): ActiveProgramResponse?
}
  • BaseUrl из DataStore (Server.BaseUrl), интерцептор X-Api-Key;
  • SyncResponse { accepted: List<String> };
  • activeProgram — «тяни и держи»: ответ маппится в program_version LocalDb (status=active, локальный uuid клиента — серверный versionId приходит в теле; хранение по нему), вызов — при старте приложения/после sync (m10); 404 → активной нет.

4. Инварианты 🛡

  • сеть только здесь (офлайн-first, 🛡1);
  • удаление из очереди — только по подтверждению сервера (🛡4);
  • API-ключ не логируется (🛡5; OkHttp-лог выключен в release).