VEU.WathBody/1-docs/4-modules/m09-phone-core/module_reqs.md

6.4 KiB
Raw Permalink Blame History

Требования к модулю: m09-phone-core

Модуль — телефонное ядро Phone.WatchBody (Android, Kotlin, архитектура разд. 1.2): WorkoutCore (тренировка/допуск/дневник/ перерывы — единственный писатель LocalDb), LocalDb (Room/SQLite, офлайн-first), SyncQueue (очередь с client_guid, пакеты ≤ 50, идемпотентная отправка POST /api/v1/sync). UI — m10 (Compose), голосовой ввод — m11, канал часов — m12. Самодостаточная копия требований (d-dev-6).

1. Назначение и границы

В границах модуля:

  • Gradle-проект 3-app\4-phone\Phone.WatchBody (app-модуль :app, Kotlin, minSdk 26, targetSdk 36; Compose-зависимость подключается в m10 — здесь только ядро и unit-тесты);
  • LocalDb (Room): таблицы-зеркала сервера с UUID-PK телефона (Р2-Б): exercise, program_version, workout, workout_set, command_log, daily_log, breaks, profile (singleton), плюс sync_pending(guid, entity, payload, created_at); настройки — DataStore (Server.BaseUrl, Server.ApiKey, Sync.WifiOnly, Rest.DefaultSec, Safety.* — Р3-А, телефонные пороги допуска);
  • WorkoutCore: старт/финиш/отмена тренировки (session_kind, привязка активной версии программы); фиксация подхода с пометкой «по плану» (план сессии дня: вес ± 2,5 кг, повторения ± 0 — Ф-11.2); журнал команд (заглушка ручного ввода — голос m11); дневник самоконтроля (день уникален, upsert); предстартовый допуск (АД > 150/90 → отмена; 140–150/90–95 → только кардио; пульс сидя > 90 → перенос — пороги Safety.*, 🛡 блокировка обходится логированием, Ф-13.2); перерывы: объявление source=manual (тип/план. возврат), закрытие первой сессией (данные для правил сервера); 🛡 единственный писатель LocalDb;
  • SyncQueue: каждая запись получает client_guid (UUID v4) и payload по контракту sync (tech-req 2.1/2.2, snake_case); WorkManager-воркер: пакеты ≤ 50 по времени создания, отправка X-Api-Key, подтверждённые GUID удаляются; ретрай 1→64 мин экспоненциально; ограничение Sync.WifiOnly; тихий статус (баннеры — m10);
  • ApiClient: HTTP-клиент /api/v1/sync (+ GET /api/v1/workouts, GET /api/v1/programs/active — тянет активную программу);
  • unit-тесты (JUnit, pure JVM): WorkoutCore (in_plan, допуск, статусы), batcher очереди, сериализация payload (контракт snake_case против фикстур сервера).

Вне границ модуля: экраны (m10 TrainingUi), STT/TTS и грамматика (m11), companion-канал (m12), LocalDb↔сервер маппинг серверных вычислений (метрики/правила — на сервере), восстановление пульса пропущенного периода (m12 — по каналу часов).

2. Контракт sync (tech-req 2.1/2.2)

  • конверт: {"client_guid", "entity", "op": "upsert", "data"};
  • entity ∈ workout | workout_set | command_log | daily_log | break | exercise | program_version | profile; поля — snake_case, как серверные sync-сущности (m02 spec 03);
  • workout_set.exercise_id, workout.program_version_id — локальные UUID (Р2-Б: маппинг id не нужен);
  • break.source телефон передаёт только manual (🛡 авто-детект — сервер, Ф-14.1).

3. Инварианты (🛡 — нарушать запрещено)

  1. Офлайн-first — сеть только на пути SyncQueue; запись в LocalDb никогда не ждёт сети (КУ-3).
  2. Единственный писатель — LocalDb пишет только WorkoutCore (+ SyncQueue свой статус); UI/m10 — через WorkoutCore.
  3. UUID генерирует телефон для всех клиентских сущностей (Р2-Б); client_guid = PK записи.
  4. Идемпотентность — повторная отправка не меняет данные (сервер считает по GUID; очередь удаляет только подтверждённые).
  5. Тайны — API-ключ только в DataStore, в логи не пишется (З-6).
  6. Допуск — пороги только из Safety.* (Р3-А); обход блокировки («всё равно начать») логируется.

4. Критерии приёмки модуля

  1. Unit-тесты зелёные: in_plan (вес ± 2,5 кг / повторы ± 0 от плана), допуск (отмена/кардио/перенос/норма), жизненный цикл тренировки, batcher (порция ≤ 50, порядок по created_at, удаление accepted).
  2. Payload всех 8 сущностей соответствует фикстурам контракта (snake_case, обязательные поля).
  3. Сборка проекта Gradle проходит (assembleDebug без UI — модуль app-библиотеки-каркаса m10); при отсутствии локального Android SDK — сборка у владельца по инструкции (решение гейта 1.3).
  4. Интеграция со стеклянным (docker) сервером: сценарий «запись офлайн → sync → данные в src.*» проверен вручную curl-фикстурой payload-ов (при доступном SDK — инструментальным тестом).