Ревью №3 утверждено: Ф-13.7 источник не программа (З-30), импорт пакета программы ОВ-11 + program-import-format.md + src.program.external_id (З-31, О-4-Б), backspace в 2-db readme (З-33), косметика (З-34)

This commit is contained in:
virus-home 2026-10-17 23:10:41 +05:00
parent 0e8e3a6ad6
commit a1b4969f57
10 changed files with 322 additions and 21 deletions

View File

@ -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) |

View File

@ -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\<BS>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` — эксплуатационные данные, правилами ревью не
регулируются; в документационный коммит не включать; авторство правки
подтвердить у владельца.

View File

@ -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) |

View File

@ -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),

View File

@ -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)

View File

@ -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) |

View File

@ -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() | — |

View File

@ -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`.

View File

@ -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» в ТЗ — описка исходника |

View File

@ -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**: контент подстраивается под контекст (время суток, день недели, запланированная тренировка).