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

105 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Требования к модулю: 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`.