5.6 KiB
5.6 KiB
Требования к модулю: m03-program-store
Модуль — сервис
ProgramStoreвServer.WatchBody.Core: единая точка работы с программами атлета — версионный JSON, жизненный цикл версийdraft → active → archived, гарантия «active— ровно одна». Самодостаточная копия требований (d-dev-6).
1. Назначение и границы
В границах модуля:
- класс
ProgramStore(Server.WatchBody.Core, каталогPrograms\): сервис над репозиториями m01 (ProgramRepository,ProgramVersionRepository) — единственный вход для всех потребителей (REST API m02/m08, ProgressionRules m05); - жизненный цикл версий: создание draft (новая версия на основе актуальной), активация, архивация;
- чтение: активная версия (с body), список версий (без body), версия по id (с body);
- тесты сервиса (интеграционные, docker
watchbody-pg).
Вне границ модуля: правила прогрессии и делоада (m05 — создают draft-версии через ProgramStore), импорт пакета программы (m06 — тоже через ProgramStore), редактор программы на телефоне (m09), запись версий из sync в m02 (остаётся на репозиториях — уже работает; переход на ProgramStore — кандидат рефакторинга, не в v1). Схема тела программы (недели → тренировки → упражнения → подходы-план, дизайн LLM-планирования разд. 2) в v1 сервером не валидируется — хранится как есть (jsonb).
2. Стек и соглашения
- C# / .NET 10,
Server.WatchBody.Core; доступ к БД — только репозитории m01 (Kit.Helpers), прямого SQL нет. - Конфиг
Progression.*/Deload.*в модуле не потребляется (это m05). - Логи — Kit.Helpers
Log.Logger(уровень Info).
3. Инварианты (🛡 — нарушать запрещено)
- Программы принадлежат атлету — все операции принимают
athleteId; чужие программы/версии недоступны. - Неизменяемость версии — после создания
body,author,based_on_versionне меняются; меняется толькоstatus. - Ровно одна
activeна программу — активация переводит прежнюю активную вarchived(гарантия БД — частичный уникальный индекс; ProgramStore использует только переходы, разрешённые БД). - Переходы статусов только
draft → active → archived— повторная активация archived-версии запрещена (явное действие пользователя — Ф-10.4); 🛡 автоматической смены активной версии нет (vision 2.4). - Тренировки ссылаются на версию, активную на их начало — ProgramStore не перепривязывает ссылки (история не «поплывёт»).
4. Состав сервиса (контракты, шаг 1)
| # | Метод | Назначение |
|---|---|---|
| 1 | EnsureProgram(athleteId, title) |
программа атлета (создаёт при отсутствии; UNIQUE(athlete_id)) |
| 2 | CreateDraft(athleteId, body, author, rationale, basedOnVersion = null) |
новая draft-версия: version = max+1 (БД), based_on_version = актуальная максимальная (или явная); author ∈ user/admin/rules (llm — v2) |
| 3 | Activate(athleteId, versionId) |
draft → active; прежняя active → archived; не-draft → ошибка |
| 4 | Archive(athleteId, versionId) |
active → archived (смена активной = активация другой версии) |
| 5 | GetActive(athleteId) |
активная версия с body (или null) |
| 6 | ListVersions(athleteId) |
версии программы без body (статусы, номера, rationale) |
| 7 | GetVersion(athleteId, versionId) |
версия с body |
5. Критерии приёмки модуля
- Жизненный цикл: CreateDraft → Activate → (новая draft) → Activate — активна ровно одна, прежняя archived; повторная активация archived — ошибка.
- Изоляция: операции одного атлета не видят/не трогают программы другого.
- Неизменяемость: после создания body/author/based_on_version не меняются ни одним методом сервиса.
- CreateDraft фиксирует
based_on_version= актуальная максимальная версия (история версий — цепочка). - Тесты интеграционные против docker
watchbody-pg— зелёные; сборка решения без ошибок.