VEU.WathBody/1-docs/4-modules/m01-server-db/module_reqs.md

7.6 KiB
Raw Blame History

Требования к модулю: m01-server-db

Модуль — серверный слой данных v1: схема PostgreSQL (src, ref), psql-функции, миграции, домен C# и DAL-репозитории, режим --mode migrate. Самодостаточная копия требований (d-dev-6): внешние документы продублированы по содержанию, ссылки на них — только для контекста, не для смысла.

1. Назначение и границы

В границах модуля:

  • SQL-миграции схемы ref и src (журнал src.migration, d-db-1);
  • psql-функции слоя src и ref (список утверждён — разд. 3);
  • psql-тесты функций;
  • доменные объекты C# ({Сущность}.cs, правила c-dm);
  • DAL-репозитории C# ({Сущность}Repository.cs, правила c-dal) поверх Kit.Helpers SqlHelperAbstract (SqlHelperPostgres) (единственный путь к БД);
  • режим запуска --mode migrate сервера (применение миграций по журналу).

Вне границ модуля: REST API (m02), бизнес-логика метрик/правил (m04, m05), импорт .fit (m06), админ-консоль (m08), всё на телефоне и часах.

2. Стек и соглашения

  • PostgreSQL; сервер — C# / .NET 10; доступ к БД — только Kit.Helpers SqlHelperAbstract (SqlHelperPostgres), строка — Db.ConnectionString (appsettings.json, тест подключения при старте — фатально при неудаче).
  • Логи — Kit.Helpers Log.Logger (файл, уровень Info).
  • Миграции — psql-файлы в 2-db\migrations\; каждый применённый файл фиксируется в src.migration(filename); повторный запуск пропускает применённые (журнал — источник истины).
  • Именование функций — {сущность}_{действие}; код функций — {функция}.psql, тесты — test_{функция}.psql (db-func-4, db-tst-1).
  • Статусная модель функций — d-dev-1..3 (PLAN → DEV → DONE; колонки «Функция»/«Репозиторий»: - → REQ → CODE → DONE).

3. Инварианты (🛡 — нарушать запрещено)

  1. Изоляция атлетов — все функции слоя src, кроме athlete_* и migration_*, принимают p_athlete_id и выбирают/пишут только в пределах атлета.
  2. Идемпотентность — workout_insert при повторе client_guid (PK id uuid) возвращает существующий id; PK uuid клиентских сущностей генерирует телефон (строки «только .fit» — сервер).
  3. Неизменяемость истории — program_version_update меняет только status (переходы draft→active→archived; активной становится ровно одна версия на программу — частичный уникальный индекс); command_log не редактируется; workout_set без update/delete (правка = новая запись source=edit); exercise_delete — только логическое (is_active=0).
  4. Атлет без удаления — athlete без _delete: блокировка is_blocked.

4. Схема данных (сводка; полная — 2-db\src\tables.md, 2-db\ref\tables.md)

Таблица Ключевое
src.athlete id serial PK; name; api_key_hash UNIQUE (SHA-256); is_blocked
src.athlete_profile 1:1 к athlete (UNIQUE athlete_id); sex, birth_year, weight_kg, hr_max (NULL → Танака)
src.exercise id uuid PK; UNIQUE(athlete_id, name); group_id → ref; is_base; is_active
src.exercise_replacement ММ-пара (PK exercise_id, replacement_id); CHECK ≠
src.program UNIQUE(athlete_id) — одна программа; title
src.program_version id uuid PK; UNIQUE(program_id, version); status draft/active/archived (active — ровно одна); author user/admin/rules/llm; body jsonb; rationale
src.workout id uuid PK; UNIQUE(athlete_id, fit_file_id); status active/finished/cancelled; session_kind normal/return/deload/test; facts_json jsonb; hr_recovery_s
src.workout_set id uuid PK; athlete_id (денормализация); seq; weight_kg; reps; source voice/watch/edit; in_plan; rpe 1–10; knee_pain 0–10
src.command_log id uuid PK; t_offset_s; recognized_text; semantics jsonb; accepted
src.daily_log id uuid PK; UNIQUE(athlete_id, date); bp_sys/dias, weight_kg, hr_resting, wellbeing 1–5 (waist_cm, sleep_h — v2, колонки есть)
src.workout_metrics id serial PK; UNIQUE(workout_id); adherence, tonnage, tonnage_by_group/e1pm_by_exercise/hr_metrics/red_flags jsonb
src.breaks id uuid PK; kind (NULL до ответа); source auto/manual; started_on; planned_return; ended_on; note
src.migration filename UNIQUE; applied_at
ref.exercise_group справочник двигательных групп (см. 2-db\ref\tables.md)

5. Список функций (утверждён 2026-10-17, статусы — 2-db{src,ref}\functions.md)

src: athlete_insert/update/select/get; athlete_profile_upsert/get; exercise_insert/update/delete/select/get; exercise_replacement_insert/delete; program_insert/select/get; program_version_insert/update/select/get; workout_insert/update/select/get; workout_set_insert/get; command_log_insert/select; daily_log_upsert/select; workout_metrics_upsert/select; break_insert/update/select; migration_insert/select. ref: функции справочника (см. ref\functions.md).

Ключевые контракты из списка: workout_insert(p_athlete_id, p_id uuid, p_program_version_id, p_started_at, p_session_kind) → uuid (идемпотентен); workout_select — карточки + подходы агрегатом jsonb (d-db-6, мультикурсор); program_version_select — без body (body — отдельный get); exercise_select — по умолчанию только активные + пары замен; break_insert — source=manual от телефона, auto проставляет сервер; daily_log_upsert — по UNIQUE(athlete_id, date).

6. Критерии приёмки модуля

  1. --mode migrate на чистой БД применяет все миграции; повторный запуск — 0 применений; сбой миграции откатывает её и завершается кодом возврата 1.
  2. Все psql-функции списка имеют код и тесты; тесты проходят на чистой БД (включая проверки изоляции p_athlete_id, идемпотентности workout_insert, единственности active-версии).
  3. DAL-репозитории покрывают все функции; юнит-/интеграционные тесты репозиториев проходят.
  4. Статусы в 2-db{src,ref}\functions.md доведены до DONE.