7.6 KiB
Требования к модулю: 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. Инварианты (🛡 — нарушать запрещено)
- Изоляция атлетов — все функции слоя
src, кромеathlete_*иmigration_*, принимаютp_athlete_idи выбирают/пишут только в пределах атлета. - Идемпотентность —
workout_insertпри повтореclient_guid(PKiduuid) возвращает существующий id; PK uuid клиентских сущностей генерирует телефон (строки «только .fit» — сервер). - Неизменяемость истории —
program_version_updateменяет толькоstatus(переходы draft→active→archived; активной становится ровно одна версия на программу — частичный уникальный индекс);command_logне редактируется;workout_setбез update/delete (правка = новая записьsource=edit);exercise_delete— только логическое (is_active=0). - Атлет без удаления —
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. Критерии приёмки модуля
--mode migrateна чистой БД применяет все миграции; повторный запуск — 0 применений; сбой миграции откатывает её и завершается кодом возврата 1.- Все psql-функции списка имеют код и тесты; тесты проходят на чистой
БД (включая проверки изоляции
p_athlete_id, идемпотентностиworkout_insert, единственностиactive-версии). - DAL-репозитории покрывают все функции; юнит-/интеграционные тесты репозиториев проходят.
- Статусы в 2-db{src,ref}\functions.md доведены до
DONE.