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