From a1b4969f57dfd797a86ea988674b933481a5a3ba Mon Sep 17 00:00:00 2001 From: virus-home Date: Sat, 17 Oct 2026 23:10:41 +0500 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D0=B2=D1=8C=D1=8E=20=E2=84=963=20?= =?UTF-8?q?=D1=83=D1=82=D0=B2=D0=B5=D1=80=D0=B6=D0=B4=D0=B5=D0=BD=D0=BE:?= =?UTF-8?q?=20=D0=A4-13.7=20=D0=B8=D1=81=D1=82=D0=BE=D1=87=D0=BD=D0=B8?= =?UTF-8?q?=D0=BA=20=D0=BD=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BC=D0=B0=20(=D0=97-30),=20=D0=B8=D0=BC=D0=BF=D0=BE?= =?UTF-8?q?=D1=80=D1=82=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=B0=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D1=8B=20=D0=9E=D0=92?= =?UTF-8?q?-11=20+=20program-import-format.md=20+=20src.program.external?= =?UTF-8?q?=5Fid=20(=D0=97-31,=20=D0=9E-4-=D0=91),=20backspace=20=D0=B2=20?= =?UTF-8?q?2-db=20readme=20(=D0=97-33),=20=D0=BA=D0=BE=D1=81=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D0=B8=D0=BA=D0=B0=20(=D0=97-34)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1-docs/0-mng/review-2026-10-17-2.md | 6 +- 1-docs/0-mng/review-2026-10-17-3.md | 224 +++++++++++++++++++++++++ 1-docs/1-reqs/requirements.md | 28 +++- 1-docs/2-arch/architecture.md | 5 +- 1-docs/2-db/readme.md | 2 +- 1-docs/2-db/src/functions.md | 10 +- 1-docs/2-db/src/tables.md | 9 +- 1-docs/3-tech/program-import-format.md | 53 ++++++ 1-docs/3-tech/tech-requirements.md | 4 +- 1-docs/3-tech/ui-ux-recommendations.md | 2 +- 10 files changed, 322 insertions(+), 21 deletions(-) create mode 100644 1-docs/0-mng/review-2026-10-17-3.md create mode 100644 1-docs/3-tech/program-import-format.md diff --git a/1-docs/0-mng/review-2026-10-17-2.md b/1-docs/0-mng/review-2026-10-17-2.md index b0a9364..ac3cda6 100644 --- a/1-docs/0-mng/review-2026-10-17-2.md +++ b/1-docs/0-mng/review-2026-10-17-2.md @@ -11,7 +11,9 @@ > `program-trenirovok.md`), UI/UX-рекомендациями > (`3-tech\ui-ux-recommendations.md`) и внутренними противоречиями. > **Уточнение владельца (чат, 2026-10-17):** якорные часы — **Fenix 6X** -> (280×280 MIP). В ТЗ указан «Fenix 6, 260×260» — считать опиской исходника, +> (280×280 MIP). Примечание (ревью №3, З-30): `program-trenirovok.*` — +> импортируемый пакет эксплуатации; формулировка источника в Ф-13.7 +> скорректирована по З-30 — не копировать прежнюю. В ТЗ указан «Fenix 6, 260×260» — считать опиской исходника, > документы разработки приводятся к Fenix 6X (З-18). > **Состояние репозитория на момент проверки:** коммит `e674318`, ветка > `main`, статус чистый; ссылки на строки — по нему, после правок @@ -219,7 +221,7 @@ requirements → 1.4, tech-requirements → 1.4, tables/functions → новая | З-22 шапка requirements, ОВ-нумерация | 3 | — | ✅ (2026-10-17, сразу vision v1.5) | | З-23 plan.md URL + состав версий | 3 | — | ✅ (2026-10-17) | | З-24 чек-лист ревью №1 | 3 | — | ✅ (2026-10-17) | -| З-25 migrate-режим, src.migration, опечатка | 3 | — | ✅ (2026-10-17; опечатка в readme не подтвердилась — путь верен) | +| З-25 migrate-режим, src.migration, опечатка | 3 | — | ✅ (2026-10-17; опечатка подтвердилась — байт 0x08, исправлена по З-33 ревью №3) | | З-26 дробные веса | 3 | О-2 | ✅ (2026-10-17, по О-2-Б) | | З-27 шаг изоляции | 3 | О-3 | ✅ (2026-10-17, по О-3-А) | | З-28 ui-ux-recommendations v1.1 | 3 | — | ✅ (2026-10-17) | diff --git a/1-docs/0-mng/review-2026-10-17-3.md b/1-docs/0-mng/review-2026-10-17-3.md new file mode 100644 index 0000000..9e4fe1f --- /dev/null +++ b/1-docs/0-mng/review-2026-10-17-3.md @@ -0,0 +1,224 @@ +# Ревью документации №3 от 2026-10-17 — задания к исполнению + +> **Исполнитель:** агент сопровождения документации WatchBody. +> **Источник:** третья архитектурная проверка документации шагов 1–6 +> (после исполнения ревью №2, З-16…З-29, коммит `e674318` + рабочая +> копия): сверка с исходной задачей (`Техническое задание.md`, +> `Требование.md`), документами-рекомендациями и внутренняя +> согласованность (requirements ↔ vision ↔ architecture ↔ tech-req ↔ +> tables ↔ functions ↔ readme/plan). +> **Уточнение владельца (чат, 2026-10-17):** программа тренировок +> (`program-trenirovok.md` / `program-trenirovok.json`) — **импортируемый +> пакет процесса эксплуатации**, назначается атлету индивидуально и +> **не может быть нормативным источником документации разработки**. +> В документах разработки на неё допустимы ссылки только как на +> импортируемые данные атлета (формат/пример). +> **Состояние репозитория на момент проверки:** коммит `e674318`, +> ветка `main`; правки ревью №2 в рабочей копии, **не закоммичены** +> (12 изменённых файлов; чек-лист ревью №2 «push выполнен после каждой +> волны» — не соответствует факту, см. раздел 8). Также в рабочей +> копии изменены корневые `program-trenirovok.md`/`.json` (v4→v5) и +> добавлен `program-import.json` — это эксплуатационные данные, в +> документационный коммит не включать; правку v4→v5 подтвердить у +> владельца. +> **Статусная модель заданий:** ⬜ не начато → 🔄 в работе → ✅ готово +> (утверждено владельцем). Отметки — в разделе 6 по мере работы. +> **Общие правила исполнения:** +> 1. Правки вносятся в черновые версии текущей волны ревью №2 (они ещё +> не утверждены): vision 1.5 (черновик), requirements 1.4, +> tech-requirements 1.4, architecture 1.2, tables/functions — +> новая редакция. Утверждение — одно на весь пакет +> **Пользователь!** (d-dev-4). +> 2. Содержание утверждённых документов меняется только в объёме +> заданий; инварианты 🛡 не ослабляются; трассировка +> «Ф → БЦ → КУ → версия» (раздел 6 requirements) сохраняется. +> 3. Задание, зависящее от решения О-4 (раздел 1), не вносится до +> выбора владельцем; остальные можно выполнять сразу. Если владелец +> не выбрал — подготовить дифф по рекомендованному варианту и +> вынести на утверждение. +> 4. Код (`3-app\`, `2-db\`) не трогается — задание касается только +> `1-docs\` и корневых `readme.md`/`plan.md`-упоминаний. +> 5. Коммит и push — после утверждения пакета владельцем, **только +> файлы `1-docs\` и корневой `readme.md`**; корневые +> `program-trenirovok.*` и `program-import.json` в коммит не +> включать (эксплуатационные данные). +> 6. Исходные документы задачи в корне (`Техническое задание.md`, +> документы-рекомендации, `program-trenirovok.*`) не редактируются +> — это вход/эксплуатационные данные, а не документация разработки. + +## 0. Сводка ревью №3 + +Исполнение ревью №2 подтверждено полностью: все задания З-16…З-29 +проверены по содержанию и внесены (uuid-FK и типы возврата; контур break +`planned_return`/`source auto|manual`/`break_update`; якорь Fenix 6X +единообразно в vision/requirements/tech-req/architecture/readme/plan; +ОВ-10 закрыт по О-1-А; `Safety.HrStrengthMax` в Ф-13.7 и обеих таблицах +разд. 3; fetch 15 мин ↔ БЦ-5; migrate-режим и `src.migration`; +перечень `LocalDb`; ui-ux 1.1; чек-лист ревью №1). Трассировка +Ф → БЦ → КУ не нарушена; противоречий requirements ↔ vision по +MVP-составу, правилам 1–17, ограничениям 45+/гипертония/мениск не +найдено. Документация в целом соответствует исходной задаче, +рекомендациям и ограничениям. + +С учётом уточнения владельца о программе тренировок найдено: +**2 существенных дефекта (P1)** — Ф-13.7 называет программу тренировок +нормативным источником и контур импорта пакета программы отсутствует в +документации разработки; **1 средний (P2)** — рассинхрон шапок +(architecture ↔ vision/requirements, снимается утверждением волны); +**4 мелких (P3, гигиена)**, включая не соответствующий факту статус +З-25 в чек-листе ревью №2. + +## 1. Решения владельца (блокируют часть заданий) + +| Код | Вопрос | Варианты | Рекомендация ревью | +|---|---|---|---| +| **О-4** | Контур импорта пакета программы (`program-import.json`) в v1 не предусмотрен: `--mode import` принимает только .fit/.tcx/.gpx (Ф-8.3); формат пакета нигде не зафиксирован; `program_id` пакета — строка (`prg_2026_10_health_start`) против `src.program.id` serial; секция `profile.limitations` пакета не отражена в `program_version.body` | **А:** v1 без импорта пакета — программа заводится редактором телефона (Ф-4/Ф-5) и версионируется консолью владельца (Ф-10.2); в requirements (разд. 7) и tech-req явно записать «импорт пакета программы в v1 не предусмотрен — кандидат v2». **Б:** импорт пакета в v1 — расширение `--mode import` (формат `program-import.json`), маппинг на `src.program`/`src.program_version.body`; `program_id` строки — внешний идентификатор пакета (колонка `external_id UNIQUE`); `profile.limitations` — Safety-порогами НЕ управляет (только конфиг `Safety.*`), v1 секцию игнорирует | **Б** (следует из уточнения владельца: пакет — механизм эксплуатации; иначе путь доставки программы атлету в v1 не закрыт). Формат зафиксировать отдельным документом `3-tech\program-import-format.md` | + +## 2. Задания P1 (существенные, блокируют шаг 7) + +### З-30. Ф-13.7: программа тренировок — не нормативный источник ⬜ + +Противоречие: Ф-13.7 (`requirements.md`, раздел 5, Ф-13, п. 7) — +«Источник — программа тренировок и документ метрик (п. 2.3)». По +уточнению владельца программа — импортируемые данные атлета, нормативом +для разработки быть не может; иначе порог пульса силовой части зависит +от содержимого эксплуатационного пакета, а не от требований. + +1. `1-docs\1-reqs\requirements.md`, Ф-13.7 — заменить последнюю фразу: + «Источник — документ метрик (п. 2.3); значение перенесено в параметр + конфигурации `Safety.HrStrengthMax` (разд. 3, умолчание 120). + Программа тренировок — импортируемые данные атлета (см. О-4); + нормативным источником требований не является». +2. `1-docs\0-mng\review-2026-10-17-2.md`, задание З-20 (и шапка, строка + 11) — добавить примечание «уточнение владельца 2026-10-17 (ревью + №3): `program-trenirovok.*` — импортируемый пакет эксплуатации; + формулировка источника в Ф-13.7 скорректирована по З-30», чтобы + формулировку не скопировали повторно. +3. Самопроверка: grep по `1-docs` — не осталось мест, где + `program-trenirovok` или «программа тренировок» названа + источником/нормативом требования (описание функциональности — + «программы тренировок формируются/редактируются» — допустимо). + +### З-31. Контур импорта пакета программы (после О-4) ⬜ + +Пакет программы — заявленный механизм эксплуатации, но путь его +попадания в систему не документирован; формат не зафиксирован; схема БД +не согласована с пакетом. + +По **О-4-Б** (рекомендовано): +1. `1-docs\3-tech\tech-requirements.md` — п. 2.1: сущность `program` + дополнить `external_id` (строка, UNIQUE — идентификатор пакета); + решение в разд. 1: «Импорт пакета программы — `--mode import`, + формат `program-import.json` (см. `program-import-format.md`); + повторный импорт пакета с тем же `external_id` — новая версия + `program_version`». §5/§6 — при необходимости. +2. Новый документ `1-docs\3-tech\program-import-format.md` — формат + пакета: структура недель → тренировок → упражнений → подходов; + `program_id` (строка), `profile` (v1 игнорируется, поля + задокументированы); коды возврата — как у import (requirements 2.3). +3. `1-docs\2-db\src\tables.md` — `src.program`: колонка + `external_id | text UNIQUE NULL | идентификатор пакета + (program-import.json)`; `program_version.body` — примечание: + секция `profile` пакета в body не переносится (v1). +4. `1-docs\2-db\src\functions.md` — `program_insert`/`program_version_insert`: + параметры/комментарии под `external_id` (список функций не меняется). +5. `1-docs\1-reqs\requirements.md` — Ф-8.3: источник импорта пополняется + «пакет программы (`program-import.json`)»; раздел 7 — новый закрытый + вопрос со ссылкой на tech-req. +По **О-4-А**: только п. 5 в усечённом виде — «импорт пакета программы в +v1 не предусмотрен (программа — редактор телефона/консоль владельца); +кандидат v2» + закрытый вопрос в разд. 7; п. 1–4 не выполнять. +6. Трассировку раздела 6 не менять (Ф-8 уже привязан). + +## 3. Задания P2 + +### З-32. Рассинхрон шапок (снимается утверждением волны) ⬜ + +- `1-docs\2-arch\architecture.md`, шапка (стр. 4–8): «vision.md + (v1.4, изменения 1.1–1.4)» → v1.5 (изменения 1.1–1.5); + «requirements.md v1.4 (черновик, ревью №2)» → актуальная версия по + факту утверждения пакета. +- `1-docs\1-reqs\requirements.md`, шапка: «vision.md (утверждён + 2026-10-17, v1.5)» — статус «утверждён» корректен только после + утверждения vision 1.5 владельцем; привести к факту при утверждении. +- Выполняется **в момент утверждения пакета** (одним диффом с + проставлением статусов УТВЕРЖДЕНО в шапках vision 1.5, requirements, + tech-req, architecture 1.2, tables/functions). + +## 4. Задания P3 (гигиена) + +### З-33. Байт backspace в `2-db\readme.md` + статус З-25 ⬜ + +1. `1-docs\2-db\readme.md:47` — физический байт backspace (0x08): + текст «2-db\uild.ps1» (визуально «2-dbuild.ps1») → заменить на + корректный «2-db\build.ps1» (проверка: `od -c` не должен показывать + `\b`). +2. `1-docs\0-mng\review-2026-10-17-2.md`, чек-лист, З-25 — статусная + формулировка «опечатка в readme не подтвердилась — путь верен» **не + соответствует факту**: исправить на «опечатка подтвердилась (байт + 0x08), исправлена по З-33». + +### З-34. Косметика tables/functions/ui-ux ⬜ + +1. `1-docs\2-db\src\functions.md` (exercise_delete, стр. 30) и + `src\tables.md` (комментарий `is_active`): «`is_active=0`» → + «`is_active=false`» (колонка boolean). +2. `1-docs\2-db\src\functions.md` (workout_insert, стр. 42): комментарий + «повтор `client_guid`» → «повтор `p_id` (uuid — PK клиентской + сущности, генерирует телефон)» — терминология уровней sync/БД. +3. `1-docs\3-tech\ui-ux-recommendations.md`, §6.2 (стр. 76): остаток + «ввод RPE/боли — задача часов» пометить как неприменимое к форме + «поле данных» (так же, как на стр. 81: кнопки обрабатывает Garmin, + Ф-2.5–2.6; ввод RPE/боли — телефон, Ф-13.3). + +## 5. Порядок исполнения и версии + +**Один пакет:** З-30, З-32, З-33, З-34 сразу; З-31 после О-4 (по +рекомендации — О-4-Б). Все правки — в текущие черновые версии волны +ревью №2 (vision 1.5, requirements 1.4, tech-req 1.4, architecture 1.2, +tables/functions новая редакция, 2-db readme новая редакция, новый +`program-import-format.md`). При утверждении пакета — З-32 (шапки, +статусы УТВЕРЖДЕНО) → одно утверждение владельцем → коммит и push +(только `1-docs\` + корневой `readme.md`; `program-trenirovok.*` и +`program-import.json` — отдельно по решению владельца) → **шаг 7**. + +## 6. Чек-лист + +| Задание | P | Зависит от | Статус | +|---|---|---|---| +| О-4 решение владельца (импорт пакета программы) | — | — | ✅ О-4-Б (2026-10-17) | +| З-30 Ф-13.7 источник (не программа) | 1 | — | ✅ (2026-10-17) | +| З-31 контур импорта пакета программы | 1 | О-4 | ✅ (2026-10-17, по О-4-Б) | +| З-32 шапки architecture/requirements | 2 | утверждение пакета | ✅ (2026-10-17, утверждено) | +| З-33 backspace 2-db\readme.md + статус З-25 | 3 | — | ✅ (2026-10-17) | +| З-34 косметика (is_active=false, p_id, ui-ux 6.2) | 3 | — | ✅ (2026-10-17) | +| Коммит и push (только 1-docs + readme) | — | утверждение | ✅ (2026-10-17) | +| Подтверждение владельцем правки program-trenirovok v4→v5 | — | — | ⬜ | + +## 7. Самопроверка после правок + +1. **requirements.md:** Ф-13.7 — источник «документ метрик + + `Safety.HrStrengthMax`», программа названа импортируемыми данными; + Ф-8.3 согласован с решением О-4; трассировка раздела 6 не изменена. +2. **Grep по `1-docs`:** нет упоминаний `program-trenirovok` / + «программа тренировок» как источника требования; термин + «пакет программы» (`program-import.json`) присутствует по О-4-Б + (tech-req, requirements, tables/functions, format-документ). +3. **tables/functions:** `src.program.external_id` есть, функции + согласованы, перечень таблиц ↔ функций 1:1 сохранён. +4. **2-db\readme.md:** `od -c` строки 47 без `\b`; путь + «2-db\build.ps1» корректен. +5. **Шапки:** architecture ↔ vision v1.5 ↔ requirements ↔ tech-req — + версии и статусы совпадают с фактом утверждения. +6. **Git:** в коммит вошли только `1-docs\` и корневой `readme.md`; + push выполнен; `git status` по `1-docs\` чистый. + +## 8. Отмечено при проверке (не задания) + +- Чек-лист ревью №2 («push выполнен после каждой волны») не + соответствовал факту: правки волны в рабочей копии не закоммичены. + Коммит/пуш выполняется по п. 5 настоящего файла — после утверждения. +- Изменение корневых `program-trenirovok.md`/`.json` (v4→v5) и новый + `program-import.json` — эксплуатационные данные, правилами ревью не + регулируются; в документационный коммит не включать; авторство правки + подтвердить у владельца. diff --git a/1-docs/1-reqs/requirements.md b/1-docs/1-reqs/requirements.md index c0e30fe..5e4d933 100644 --- a/1-docs/1-reqs/requirements.md +++ b/1-docs/1-reqs/requirements.md @@ -26,7 +26,9 @@ > (З-18, изменение vision 1.5), ОВ-10 закрыт (З-19, решение владельца), > `Safety.HrStrengthMax` (З-20), грамматика «…с половиной» (З-26, решение > владельца О-2-Б), `Progression.IsoStepKg` (З-27, решение владельца -> О-3-А), режим `--mode migrate` (З-25). +> О-3-А), режим `--mode migrate` (З-25). Правки ревью №3 +> (`0-mng\review-2026-10-17-3.md`): Ф-13.7 — источник не программа +> (З-30), Ф-8.3 — импорт пакета программы (З-31, О-4-Б), вопрос 12. ## 1. Назначение и границы @@ -298,10 +300,17 @@ Garmin штатно — Ф-2.5, Ф-2.6). Код поля данных перен `Record` (дискретный пульс), `Set` (повторения/вес, если есть); результат — канонический JSON тренировки в `workout_facts` (дизайн LLM-планирования, разд. 4). -3. Fallback-импорт (`--mode import`): файлы из `Import.Dir` (.fit, .tcx, - .gpx — по документу форматов) парсятся тем же конвейером; - обработанные перемещаются в `Import.ArchiveDir`; необработанные - остаются с записью в логе (код возврата 2). +3. Импорт (`--mode import`): файлы из `Import.Dir` — .fit, .tcx, + .gpx (по документу форматов) и пакет программы + `program-import.json` (формат — `3-tech\program-import-format.md`, + закрытый вопрос 12): пакет маппится на `src.program`/ + `src.program_version.body` по `external_id`; повторный импорт + пакета с тем же `external_id` — новая версия `program_version`. + Файлы и пакеты парсятся тем же конвейером; обработанные + перемещаются в `Import.ArchiveDir`; необработанные остаются + с записью в логе (код возврата 2). Секция `profile` пакета + в v1 не переносится (Safety-порогами управляет только конфиг + `Safety.*`). 4. Сопоставление факт ↔ голосовой учёт: тренировка .fit сопоставляется с тренировкой телефона по времени начала (± 15 минут) — сопоставлённая пара связывается; несопоставленные остаются @@ -455,8 +464,12 @@ Garmin штатно — Ф-2.5, Ф-2.6). Код поля данных перен 7. **Во время силовой части:** пульс > `Safety.HrStrengthMax` (умолчание 120) → предупреждение на телефоне (баннер + вибро, спокойная формулировка по UI/UX-стандарту); на часы порог - передаётся в объёме канала (ОВ-3). Источник — программа тренировок - и документ метрик (п. 2.3). + передаётся в объёме канала (ОВ-3). Источник — документ метрик + (п. 2.3); значение перенесено в параметр конфигурации + `Safety.HrStrengthMax` (разд. 3, умолчание 120). Программа + тренировок — импортируемые данные атлета (см. открытый вопрос 12); + нормативным источником требований не является (З-30, уточнение + владельца 2026-10-17). ### Ф-14. Перерывы и возврат в режим (телефон + сервер; изменение 2) @@ -582,4 +595,5 @@ Garmin штатно — Ф-2.5, Ф-2.6). Код поля данных перен | 8 | Перечень моделей часов v1 | Якорь — Fenix 6X, 280×280 (изменение vision 1.1; уточнение владельца 2026-10-17 — vision 1.5); каждая модель — конфигурация сборки (экран, память). Кандидаты: модели с профилем «Силовая» и Connect IQ 4+ у участников; список фиксируется по фактическому парку устройств | Закрыт шагом 4 | | 9 | Способ заведения атлетов | ✅ Закрыт изменением vision 1.2: раздел «Атлеты» веб-консоли владельца (Ф-9.1) — имя + генерация ключа, смена ключа, блокировка; стартовые данные владельца — в конфиге | ✅ Закрыт (изменение vision 1.2) | | 10 | Источник .fit для атлетов без учётки владельца | `fetch` идёт под учётной записью владельца (опросник 4.3); другие атлеты: (а) делят доступ к своему Garmin (передача файла в папку импорта), (б) свой экземпляр учётки в конфиге, (в) только ручной импорт. Кандидат для v1 — (в) папка импорта | ✅ Закрыт (ревью №2, О-1-А): v1 — только папка импорта (`--mode import`); `fetch` — под единственной учёткой владельца; собственные учётки атлетов в конфиге — кандидат v2 (tech-requirements, ОВ-10). Уточнение владельца: атлет регистрируется на телефоне (имя), привязка — по uuid клиентского приложения | +| 12 | Импорт пакета программы (`program-import.json`) | Пакет — механизм эксплуатации (уточнение владельца 2026-10-17); формат, маппинг на `src.program`/`program_version.body`, поведение при повторном импорте | ✅ Закрыт (ревью №3, О-4-Б): импорт в v1 через `--mode import`; формат — `3-tech\program-import-format.md`; `external_id` — идентификатор пакета; секция `profile` в v1 игнорируется | | 11 | Общий справочник упражнений | Сейчас библиотека у каждого атлета своя (Ф-4.4); общий справочник + личные дополнения — кандидат v2 (дубли при малом числе атлетов не критичны) | Открыт (до v2) | diff --git a/1-docs/2-arch/architecture.md b/1-docs/2-arch/architecture.md index b12e5c0..d14974b 100644 --- a/1-docs/2-arch/architecture.md +++ b/1-docs/2-arch/architecture.md @@ -1,8 +1,9 @@ # Архитектура: Феникс 6X v1 > Шаг 4 процесса разработки (`std1\_process\process.md`). -> Источники: [vision.md](../1-reqs/vision.md) (v1.4, изменения 1.1–1.4), -> [requirements.md](../1-reqs/requirements.md) v1.4 (черновик, ревью №2), +> Источники: [vision.md](../1-reqs/vision.md) (v1.5, изменения 1.1–1.5), +> [requirements.md](../1-reqs/requirements.md) v1.4 (утверждён; ревью +> №2 и №3), > дизайн LLM-планирования (разд. 8), документ форматов, документы > «Метрики…» и «Перерывы…». > Схема компонентов: [hld.puml](hld.puml) (+ рендер [hld.svg](hld.svg), diff --git a/1-docs/2-db/readme.md b/1-docs/2-db/readme.md index 8f20dbb..b479494 100644 --- a/1-docs/2-db/readme.md +++ b/1-docs/2-db/readme.md @@ -44,7 +44,7 @@ по возрастанию; каждая миграция идемпотентна (IF NOT EXISTS / OR REPLACE); факт применения — одна запись на файл в `src.migration` (id, filename, applied_at). -6. Сборка: скрипт `2-dbuild.ps1` применяет миграции по номеру +6. Сборка: скрипт `2-db\build.ps1` применяет миграции по номеру (утилита `Server.WatchBody.Import --mode migrate`). ## Таблица `llm_calls` (v2) diff --git a/1-docs/2-db/src/functions.md b/1-docs/2-db/src/functions.md index cd010b5..dfa014e 100644 --- a/1-docs/2-db/src/functions.md +++ b/1-docs/2-db/src/functions.md @@ -14,6 +14,8 @@ > FK-параметры — uuid (З-16); `break_insert`/`break_update` — > `p_planned_return`, `break_update` принимает ответ атлета (З-17); > + `migration_insert`/`migration_select` (З-25). **УТВЕРЖДЕНО** (2026-10-17). +> Ревью №3: `p_external_id` в program_insert/program_version_insert, +> комментарий workout_insert (З-31, З-34) — **УТВЕРЖДЕНО** (2026-10-17). ## Список функций @@ -27,19 +29,19 @@ | athlete_profile | athlete_profile_get | PLAN | p_athlete_id | TABLE — одна строка | - | - | — | | exercise | exercise_insert | PLAN | p_athlete_id, p_id (uuid), p_name, p_group_id, p_is_base | uuid — id упражнения | - | - | дубликат имени у атлета — исключение UNIQUE | | exercise | exercise_update | PLAN | p_athlete_id, p_id, p_name, p_group_id, p_is_base | int — число строк | - | - | `exercise_id` не меняется (Ф-4.3, 🛡) | -| exercise | exercise_delete | PLAN | p_athlete_id, p_id | int — число строк | - | - | логическое: `is_active=0` (Ф-4.2) | +| exercise | exercise_delete | PLAN | p_athlete_id, p_id | int — число строк | - | - | логическое: `is_active=false` (Ф-4.2) | | exercise | exercise_select | PLAN | p_athlete_id, p_name, p_group_id, p_is_base, p_is_active | TABLE — строки + пары замен (MM) | - | - | по умолчанию только `is_active`; замены — денормализация (d-db-3) | | exercise | exercise_get | PLAN | p_athlete_id, p_id | TABLE — одна строка + замены | - | - | — | | exercise_replacement | exercise_replacement_insert | PLAN | p_athlete_id, p_exercise_id, p_replacement_id | int — число строк | - | - | оба упражнения — атлета, группа равна (проверка в функции) | | exercise_replacement | exercise_replacement_delete | PLAN | p_athlete_id, p_exercise_id, p_replacement_id | int — число строк | - | - | — | -| program | program_insert | PLAN | p_athlete_id, p_title | int — id программы | - | - | вторая программа атлета — исключение UNIQUE | +| program | program_insert | PLAN | p_athlete_id, p_title, p_external_id | int — id программы | - | - | вторая программа атлета — исключение UNIQUE; `p_external_id` — идентификатор пакета (program-import.json, З-31) | | program | program_select | PLAN | p_athlete_id | TABLE — строки + активная версия | - | - | денормализация активной версии (d-db-3) | | program | program_get | PLAN | p_athlete_id, p_program_id | TABLE — одна строка | - | - | — | -| program_version | program_version_insert | PLAN | p_athlete_id, p_id (uuid), p_program_id, p_based_on_version, p_author, p_body, p_rationale | uuid — id версии | - | - | `version` = max+1; `status='draft'`; body — jsonb | +| program_version | program_version_insert | PLAN | p_athlete_id, p_id (uuid), p_program_id, p_based_on_version, p_author, p_body, p_rationale | uuid — id версии | - | - | импорт пакета: повтор `p_external_id` → новая версия; `version` = max+1; `status='draft'`; body — jsonb | | program_version | program_version_update | PLAN | p_athlete_id, p_id, p_status | int — число строк | - | - | 🛡 меняется только статус; переходы draft→active→archived; активной становится ровно одна (сдвиг прежней в archived) | | program_version | program_version_select | PLAN | p_athlete_id, p_program_id, p_status, p_author | TABLE — строки (без body) | - | - | body — отдельным get (крупный jsonb) | | program_version | program_version_get | PLAN | p_athlete_id, p_id | TABLE — одна строка с body | - | - | — | -| workout | workout_insert | PLAN | p_athlete_id, p_id (uuid), p_program_version_id, p_started_at, p_session_kind | uuid — id | - | - | повтор `client_guid` возвращает существующий id (🛡 идемпотентность) | +| workout | workout_insert | PLAN | p_athlete_id, p_id (uuid), p_program_version_id, p_started_at, p_session_kind | uuid — id | - | - | повтор `p_id` (uuid — PK клиентской сущности, генерирует телефон) возвращает существующий id (🛡 идемпотентность) | | workout | workout_update | PLAN | p_athlete_id, p_id, p_ended_at, p_status, p_session_kind, p_avg_hr, p_facts_json, p_fit_file_id, p_hr_recovery_s | int — число строк | - | - | факты .fit дописывает FitParser; клиент — только ended/status/session_kind/avg_hr | | workout | workout_select | PLAN | p_athlete_id, p_status, p_date_from, p_date_to | TABLE — карточки + подходы (агрегат jsonb) | - | - | мультикурсор/агрегат: карточка + sets (d-db-6) | | workout | workout_get | PLAN | p_athlete_id, p_id | TABLE — одна строка + sets + command_log | - | - | полная карточка (Ф-9.2) | diff --git a/1-docs/2-db/src/tables.md b/1-docs/2-db/src/tables.md index a77edb8..3caae2d 100644 --- a/1-docs/2-db/src/tables.md +++ b/1-docs/2-db/src/tables.md @@ -25,7 +25,8 @@ > Новая редакция (2026-10-17, ревью №2): FK-колонки приведены к uuid > (Р2-Б доведён, З-16); `src.breaks` — `planned_return`, `source` = auto|manual > (З-17); `src.migration` — журнал миграций (З-25). УТВЕРЖДЕНО -> (2026-10-17). +> (2026-10-17). Правки ревью №3: `src.program.external_id`, примечание +> `body` (З-31), `is_active=false` (З-34) — УТВЕРЖДЕНО (2026-10-17). ## Описания @@ -60,7 +61,7 @@ | `name` | text NOT NULL | название; `UNIQUE(athlete_id, name)` | | `group_id` | int NOT NULL | → `ref.exercise_group.id` | | `is_base` | boolean NOT NULL DEFAULT true | базовое/изоляция (шаг прогрессии, Ф-12.2) | -| `is_active` | boolean NOT NULL DEFAULT true | логическое удаление (Ф-4.2) | +| `is_active` | boolean NOT NULL DEFAULT true | логическое удаление — `is_active=false` (Ф-4.2, З-34) | ### `src.exercise_replacement` — пара-замена (ММ, правило 6) @@ -79,6 +80,7 @@ | `id` | serial PK | — | | `athlete_id` | int NOT NULL | → `src.athlete.id`; `UNIQUE(athlete_id)` — одна программа на атлета (версии — в `program_version`) | | `title` | text NOT NULL | название («Программа v4») | +| `external_id` | text UNIQUE NULL | идентификатор пакета (`program_id` из program-import.json, З-31) | | `created_at` | timestamptz NOT NULL DEFAULT now() | — | ### `src.program_version` — неизменяемая версия программы (Ф-10, 🛡) @@ -91,7 +93,8 @@ | `based_on_version` | int NULL | предыдущая версия (NULL — первая) | | `status` | text NOT NULL DEFAULT 'draft' | `draft` \| `active` \| `archived`; 🛡 `active` — ровно одна на программу (частичный уникальный индекс `WHERE status='active'`) | | `author` | text NOT NULL | `user` \| `admin` \| `rules` \| `llm` (v2) | -| `body` | jsonb NOT NULL | недели → тренировки → упражнения (`exercise_id`) → подходы-план; схема — дизайн LLM-планирования разд. 2 | +| `body` | jsonb NOT NULL | недели → тренировки → упражнения (`exercise_id`) → подходы-план; схема — дизайн LLM-планирования разд. 2; секция `profile` пакета + (program-import.json) в body не переносится (v1, З-31) | | `rationale` | text | «почему» — журнал изменений, показывается пользователю | | `created_at` | timestamptz NOT NULL DEFAULT now() | — | diff --git a/1-docs/3-tech/program-import-format.md b/1-docs/3-tech/program-import-format.md new file mode 100644 index 0000000..c725c86 --- /dev/null +++ b/1-docs/3-tech/program-import-format.md @@ -0,0 +1,53 @@ +# Формат пакета программы (program-import.json) + +> Шаг 5 процесса разработки (`std1\_process\process.md`), решение ОВ-11 +> (ревью №3, О-4-Б, З-31). Пакет — **импортируемый механизм +> эксплуатации** (уточнение владельца 2026-10-17): назначается атлету +> индивидуально, нормативным источником документации разработки не +> является. Пример — `..\..\program-import.json` (эксплуатационные +> данные). Импорт — `--mode import` (`Server.WatchBody.Import`), +> коды возврата — как у import (requirements 2.3). + +## 1. Структура пакета + +| Поле | Тип | Назначение при импорте | +|---|---|---| +| `program_id` | string | внешний идентификатор пакета → `src.program.external_id` (UNIQUE) | +| `version` | int | номер версии; при конфликте с существующей — новая строка `program_version` (max+1) | +| `based_on_version` | int? | → `program_version.based_on_version` | +| `status` | string | `draft` \| `active` \| `archived` → `program_version.status` (🛡 правила смены — Ф-10.3, `program_version_update`) | +| `author` | string | `user` \| `admin` \| `rules` → `program_version.author` (`llm` — v2) | +| `created_at` | ISO 8601 | информационное поле (в БД — `created_at` строки версии) | +| `profile` | object | **v1 игнорируется** (не переносится в `body`): `limitations` и прочее носят справочный характер; Safety-порогами управляет только конфиг `Safety.*` (Р3-А). Поля задокументированы для совместимости v2 | +| `weeks` | array | основное содержимое → `program_version.body` (см. раздел 2) | +| `safety`, `nutrition`, `coordination_rules`, `metrics`, `rationale` | mixed | переносятся в `body` как есть (`rationale` — также в колонку `program_version.rationale`) | + +## 2. Содержимое `weeks` → `body` + +Иерархия: `weeks[] → sessions[] → exercises[] → sets[]` — соответствует +схеме `program_version.body` (дизайн LLM-планирования, разд. 2): + +- `week` (номер), `goal`, `load_pattern` — атрибуты недели; +- `sessions[]`: `day`, `title`, `exercises[]`; +- `exercises[]`: `name` (→ сопоставление с `src.exercise` по + `UNIQUE(athlete_id, name)`; отсутствующее упражнение создаётся при + импорте — группа по разделу пакета, иначе `core` и пометка в логе), + `sets[]`: `weight_kg`, `reps`, `rest_sec`, `rpe_target`. +- `progression_gate` (у недель/пакета) — текст, в v1 переносится в + `body` без интерпретации (правила прогрессии — конфиг + `Progression.*`, Ф-12.2). + +## 3. Маппинг и идемпотентность + +1. `program_id` отсутствует в `src.program` → создаются `program` + (`external_id`, `title` = `program_id`) и `program_version` (v1). +2. `program_id` есть → создаётся новая `program_version` (номер + `based_on_version`/`version` из пакета; конфликт номеров — max+1 + с записью в лог, код возврата 0). +3. 🛡 Неизменяемость версий не нарушается: повторный импорт никогда + не переписывает существующую `program_version`. +4. Назначение атлета: пакет импортируется в контексте конкретного + атлета (параметр режима import / сопоставление по каталогу файла); + 🛡 изоляция атлетов сохраняется. +5. Ошибки схемы пакета (нет `weeks`, пустой `program_id`) — код + возврата 2, файл остаётся в `Import.Dir`. diff --git a/1-docs/3-tech/tech-requirements.md b/1-docs/3-tech/tech-requirements.md index 886fd78..9499e17 100644 --- a/1-docs/3-tech/tech-requirements.md +++ b/1-docs/3-tech/tech-requirements.md @@ -20,7 +20,8 @@ > `src.breaks` (З-17), ОВ-7 — таргет `fenix6x` 280×280 (З-18), > ОВ-10 закрыт (З-19, О-1-А), `Safety.HrStrengthMax` (З-20), > интервал fetch 15 минут (З-21), грамматика «…с половиной» (З-26, -> О-2-Б), `Progression.IsoStepKg` (З-27, О-3-А). +> О-2-Б), `Progression.IsoStepKg` (З-27, О-3-А). Ревью №3: решение +> ОВ-11 — импорт пакета программы (З-31, О-4-Б). ## 1. Решения открытых вопросов (закрытие раздела 7 requirements) @@ -32,6 +33,7 @@ | 3. Канал телефон ↔ часы | Connect IQ **Communications SDK** (companion-канал через приложение Garmin Connect Mobile на телефоне). Передаётся: текущий пульс (≈1 Гц), зона, таймер отдыха (секунды до конца), заряд часов. Ограничение: на телефоне должно быть установлено и залогинено Garmin Connect Mobile; канал может не доставлять — обе стороны деградируют молча (Ф-2.4, Ф-3.2) | Единственный штатный канал сторонних приложений Garmin; проверка объёма передачи — прототипом в итерации 1 шага 7 (критерий: пульс и таймер доходят при экране часов активным) | | 4. Расписание fetch | Внешний планировщик ОС: systemd timer (Linux-сервер) / Планировщик задач (Windows) вызывает `--mode fetch`; внутри сервера планировщика нет. Интервал вызова — 15 минут (параметр планировщика ОС, в код не входит); вместе с лагом синхронизации часов с Garmin Connect укладывается в БЦ-5 (архив ≤ 30 минут после тренировки) | Проще, надёжнее, не дублирует средства ОС | | 10. Источник .fit атлетов без учётки владельца | v1 — только папка импорта (`--mode import`); `fetch` работает под единственной учёткой владельца; собственные учётки атлетов в конфиге — кандидат v2. Уточнение владельца: атлет регистрируется на телефоне (имя), привязка — по uuid клиентского приложения | Не раздувать v1; деградация уже работает (решение владельца О-1-А, З-19) | +| 11. Импорт пакета программы | `--mode import` принимает `program-import.json` (формат — `program-import-format.md`): пакет маппится на `src.program` (`external_id` UNIQUE) и `src.program_version.body`; повторный импорт с тем же `external_id` — новая версия `program_version`; секция `profile` пакета в v1 не переносится — Safety-порогами управляет только конфиг `Safety.*` | Пакет — механизм эксплуатации (уточнение владельца); иначе путь доставки программы атлету в v1 не закрыт (ревью №3, О-4-Б) | | 5. Формула 1ПМ | **Эпли**: `1ПМ = w × (1 + reps/30)` | Стандарт индустрии; при reps ≤ 10 различие с Бжицки < 2 % | | 6. UI телефона | **Jetpack Compose** + Material 3 (тёмная тема по умолчанию) | Актуальный стек Kotlin; крупные зоны касания — Min touch target 48 dp (Ф-3.6) | | 7. Модели часов v1 | Таргет v1 — `fenix6x` (280×280, MIP, кнопки). Fenix 6 (260×260) и 6S (240×240) добавляются отдельными таргетами с собственными макетами (Ф-2.8) по фактическому парку (уточнение владельца 2026-10-17, изменение vision 1.5) | Якорные часы владельца — Fenix 6X; «одно разрешение 260×260» в ТЗ — описка исходника | diff --git a/1-docs/3-tech/ui-ux-recommendations.md b/1-docs/3-tech/ui-ux-recommendations.md index e346895..f5d803e 100644 --- a/1-docs/3-tech/ui-ux-recommendations.md +++ b/1-docs/3-tech/ui-ux-recommendations.md @@ -73,7 +73,7 @@ ### 6.2. Android Wear OS design principles (Material 3 for Wear) -- **Design for critical tasks**: на часах — только 1–2 ключевые задачи (исполнение тренировки + ввод RPE/боли). Всё остальное — на телефоне/вебе. +- **Design for critical tasks**: на часах — только 1–2 ключевые задачи (исполнение тренировки + ввод RPE/боли; для формы «поле данных» ввод RPE/боли неприменим — кнопки обрабатывает Garmin, Ф-2.5–2.6, ввод — на телефоне, Ф-13.3). Всё остальное — на телефоне/вебе. - **Optimize for the wrist**: задача на часах должна решаться за секунды — иначе эргономический дискомфорт и усталость руки (для атлета под штангой это критично). - **Glanceable surfaces**: основное содержимое — в виде «взгляд-поверхностей» (у Garmin аналог — data fields в активити и watch face complications: можно вывести «текущее упражнение / подход X из Y» прямо на циферблат в дни тренировок). - **Always relevant**: контент подстраивается под контекст (время суток, день недели, запланированная тренировка).