6.5 KiB
Требования к модулю: m08-admin-web
Модуль — административная консоль владельца (Ф-9, решение владельца 2026-10-17): бэкенд — admin REST API
/api/admin/*вServer.WatchBody.Web; UI — Flutter Web-приложение3-app\3-web\admin-web(SDK 3.47.7 —C:\tools\flutter), сборка отдаётся сервером изwwwroot\admin\. Аутентификация владельца — логин/пароль (Admin.Login/Admin.PasswordHash, PBKDF2) → Bearer-токен сессии; атлеты к консоли доступа не имеют (🛡 изменение vision 1.2). Самодостаточная копия требований (d-dev-6).
1. Назначение и границы
В границах модуля (backend REST):
- аутентификация:
POST /api/admin/login(логин+пароль →pbkdf2$...-проверка → Bearer-токен, in-memory сессия, TTL 8 ч); все/api/admin/*кроме login — только с валидным токеном (401); - атлеты (Ф-9.1): список; создание (имя → сервер генерирует API-ключ, возвращается один раз, в БД — только хэш); смена ключа; блокировка/ разблокировка (заблокированный ключ → 401 на API телефонов);
- тренировки (Ф-9.2): таблица по всем атлетам (фильтр атлет/дата,
пагинация); карточка (подходы, план/факт,
facts_json: таймлайн Lap + пульс Record, средний/пиковый пульс подхода, отдых); CSV-выгрузка текущей выборки (КУ-4, формат tech-req 2.4:;, UTF-8 BOM,athlete;date;duration_min;avg_hr;sets;exercises; adherence_pct); - программы (Ф-9.3): версии атлета (статусы/автор/даты/body);
активация draft (ProgramStore.Activate); применение предложения
правил из консоли — новая версия
author=adminс телом rules-draft, затем активация (🛡 неизменяемость версений, Ф-9.3); - метрики (Ф-9.4): выборка
workout_metricsатлета за период; - планы тренировок (Ф-9.5): сводка план/факт по неделям активной версии (запланировано сессий / выполнено / пропущено; доля);
- отдача статики Flutter-сборки
wwwroot\admin\(если каталог есть) — UI хостится тем же Kestrel.
Вне границ модуля: Flutter Web UI 3-app\3-web\admin-web
(отдельный этап — требует Flutter SDK, решение гейта 1.3), редактор
body версий (v1: просмотр + активация; правка — телефон m09/импорт
m06), LLM-контур (v2), выгрузка АД-журнала CSV (v3).
2. Сессии и токены
- пароль проверяется по
Admin.PasswordHash(PBKDF2 100k, соль в хэше, префиксpbkdf2$; формат —<login>-salt|| PBKDF2-SHA256); несовпадение → 401 без указания, что именно неверно; - токен: 256-bit random (base64url), in-memory словарь
token → (expiresAt); перезапуск сервера — сессии сбрасываются (владелец входит заново); TTL 8 ч; logout — удаление из словаря; - 🛡 токены/пароли в логи не пишутся;
Admin.PasswordHashне возвращается никаким эндпоинтом.
3. Инварианты (🛡 — нарушять запрещено)
- Только владелец —
/api/admin/*недоступен атлетам: ихX-Api-Keyне принимается, изолированный контур (/api/v1/*не меняется). - Тайны — API-ключ атлета возвращается только при создании/смене; хэши, пароли, токены — не возвращаются и не логируются.
- Запись только управляющая — admin API не пишет факт-данные (тренировки/подходы/метрики): только атлеты (create/block/key), статусы версий программ и author=admin-копии предложений.
- Неизменяемость версий — активация через ProgramStore; author=admin-копия создаётся CreateDraft, оригинал rules-draft не меняется.
- Формат CSV — точно tech-req 2.4 (разделитель
;, UTF-8 BOM).
4. Критерии приёмки модуля
- Логин: верный пароль → токен (последующие запросы с Bearer — 200); неверный → 401; без токена/с токеном атлета (X-Api-Key) → 401.
- Атлеты: создание возвращает ключ (в БД только хэш, повторный запрос ключ не отдаёт); смена ключа; блокировка → sync телефона с тем ключом получает 401; разблокировка → снова 200.
- Тренировки: список всех атлетов с фильтрами/пагинацией; карточка с подходами и план/факт; CSV выборки соответствует формату.
- Программы: версии атлета; активация draft меняет active (прежняя — archived); применение rules-предложения → активна версия author=admin с телом предложения.
- Метрики и план/факт: выборка метрик за период; сводка недель (запланировано/выполнено/пропущено) сходится с фактическими тренировками.
- Тесты интеграционные против docker
watchbody-pg— зелёные; сборка решения без ошибок.