VEU.WathBody/1-docs/4-modules/m03-program-store/module_reqs.md

5.6 KiB
Raw Blame History

Требования к модулю: 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. Инварианты (🛡 — нарушать запрещено)

  1. Программы принадлежат атлету — все операции принимают athleteId; чужие программы/версии недоступны.
  2. Неизменяемость версии — после создания body, author, based_on_version не меняются; меняется только status.
  3. Ровно одна active на программу — активация переводит прежнюю активную в archived (гарантия БД — частичный уникальный индекс; ProgramStore использует только переходы, разрешённые БД).
  4. Переходы статусов только draft → active → archived — повторная активация archived-версии запрещена (явное действие пользователя — Ф-10.4); 🛡 автоматической смены активной версии нет (vision 2.4).
  5. Тренировки ссылаются на версию, активную на их начало — 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. Критерии приёмки модуля

  1. Жизненный цикл: CreateDraft → Activate → (новая draft) → Activate — активна ровно одна, прежняя archived; повторная активация archived — ошибка.
  2. Изоляция: операции одного атлета не видят/не трогают программы другого.
  3. Неизменяемость: после создания body/author/based_on_version не меняются ни одним методом сервиса.
  4. CreateDraft фиксирует based_on_version = актуальная максимальная версия (история версий — цепочка).
  5. Тесты интеграционные против docker watchbody-pg — зелёные; сборка решения без ошибок.