4.0 KiB
Спецификация 04: payload-контракт sync (фикстуры)
Источники: tech-req 2.1/2.2 (конверт, составы data), m02 spec 03 (серверный приёмник). Тест сериализации — каждый payload сравнивается с фикстурой (ключи/типы snake_case).
1. Конверт
{"client_guid": "<uuid>", "entity": "workout_set", "op": "upsert",
"data": { …поля сущности… }}
2. data по сущностям (обязательные/опциональные поля)
| entity | data | Примечание |
|---|---|---|
workout |
program_version_id?, started_at (ISO UTC), ended_at?, status, session_kind, avg_hr? |
status: active/finished/cancelled |
workout_set |
workout_id, exercise_id?, seq, weight_kg, reps, done_at, source, in_plan, rpe?, knee_pain? |
вес — число с точкой |
command_log |
workout_id, t_offset_s, recognized_text, semantics (объект), accepted |
|
daily_log |
date (yyyy-MM-dd), bp_sys?, bp_dias?, weight_kg?, hr_resting?, wellbeing? |
день уникален — сервер upsert |
break |
kind?, source (только manual), started_on, planned_return?, ended_on?, note |
🛡 авто — сервер |
exercise |
name, group (push/pull/legs/core/cardio), is_base, is_active |
id = client_guid (серверу не передаётся) |
program_version |
version (число, обязательно — значение считает БД), based_on_version?, author (user), rationale? + поля программы (weeks…) на верхнем уровне |
errata m10 2026-10-19: контракт m02 spec 03 — data хранится сервером целиком как body; вложенного body НЕТ; локальные draft (в v1 телефона нет писателя — решение гейта 1.3 m10) |
profile |
sex?, birth_year?, weight_kg?, hr_max? |
singleton |
Уточнения против m02 spec 03: exercise_id у workout_set —
локальный UUID упражнения (Р2-Б, строкой); program_version_id —
UUID версии; break.kind ∈ illness/vacation/workload/injury/other.
profile.sex ∈ m/f (валидатор m02), null — не передаётся.
Errata 2026-10-19 (смок против живого сервера): client_guid —
UUID v4 для ВСЕХ сущностей, включая daily_log и profile (даты и
строки-слова сервер отвергает — «client_guid отсутствует или не
uuid»); поэтому в LocalDb у daily_log/profile есть стабильная
колонка guid (spec 01) — WorkoutCore сохраняет существующий guid
при повторных правках, client_guid = guid. Примечание: сервер
(m02 spec 06: «лишние поля игнорируются») не разбирает
break.ended_on — локальное закрытие перерыва в v1 на сервер не
уходит (дату возврата выводит серверный BreakEngine по тренировкам);
кандидат v2.
3. Даты/время
started_at/done_at/ended_at—yyyy-MM-dd'T'HH:mm:ss'Z'UTC (сервер парсит UtcDate);date/started_on/planned_return/ended_on—yyyy-MM-dd.
4. Фикстуры теста
Проверки полей — инлайн в тест-классе SyncPayloadTest (app/src/test):
PayloadFactory.* → JsonObject → assert ключей/типов/значений
snake_case, optional-поля — только при наличии; отдельно недопустимые
варианты: break.source="auto" → исключение фабрики (🛡);
конверт envelope(Pending) — форма client_guid/entity/op/data.