VEU.WathBody/1-docs/4-modules/m07-fit-fetch/module_reqs.md

81 lines
5.6 KiB
Markdown
Raw Permalink 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.

# Требования к модулю: m07-fit-fetch
> Модуль — проект `Server.WatchBody.Fetch` и режим `--mode fetch`
> единой точки входа CLI: неофициальный клиент Garmin Connect под
> учётной записью владельца (Ф-8.1, решение опросника 4.3, ОВ-1-А),
> скачивание .fit новых силовых тренировок в `Garmin.DownloadDir`,
> дедупликация по `fit_file_id` (🛡 — повторный запуск не качает
> дубли), разбор и запись фактов конвейером m06. Самодостаточная
> копия требований (d-dev-6).
## 1. Назначение и границы
**В границах модуля:**
- класс `GarminClient` (HTTP-клиент Garmin Connect): SSO-логин
(embed → csrf → signin → ticket → OAuth1 → Bearer) по контракту
семьи библиотек `garminconnect` (tech-req разд. 5); список
активностей; скачивание .fit по activityId. `HttpMessageHandler`
инъецируется (тесты — фейковый handler с формальным SSO-флоу и
настоящими .fit-байтами; против живого Garmin прогон не
автоматизируется — прототип ОВ этапа 7);
- класс `FitFetcher`: `FetchNew()` — логин → список → фильтр
`strength_training` → скачивание `{activityId}.fit` в
`Garmin.DownloadDir` (файл уже в папке → скачивания нет) →
`FitParser` → `WorkoutImporter` (m06) → скачанный файл, давший
дубль по `fit_file_id` в БД, удаляется. Возврат
(downloaded, skipped, failed);
- режим `--mode fetch` в `Program.cs` Web (единая точка входа,
requirements 2.3): `Garmin.Login/Password` обязательны (иначе код 1),
коды 0/1/2 — как у import; расписание — внешний планировщик ОС
(ОВ-4, интервал 15 мин — в код не входит);
- конфиг `Garmin.Login` / `Garmin.Password` / `Garmin.DownloadDir`
(+ `Garmin.BaseUrl` — замена точек входа для тестов);
- тесты (интеграционные против docker `watchbody-pg` + фейковый
Garmin-handler).
**Вне границ модуля:** парсинг/запись фактов (m06, конвейер общий),
fallback-папка импорта (m06, работает независимо — деградация при
блокировке логина), метрики (m04 пересчитает при следующем sync),
несколько учётных записей атлетов (ОВ-10 — v2), расписание (ОС),
MFA-логин (не поддерживается в v1 — сообщается ошибкой).
## 2. Дедупликация (🛡, Ф-8.1)
Два рубежа:
1. **Быстрый (без сети)**: файл `{activityId}.fit` уже есть в
`Garmin.DownloadDir` → activityId пропускается, повторного
скачивания нет.
2. **По БД**: скачанный файл разбирается, `fit_file_id` (FileId
сообщения) ищется в `src.workout` — есть → это дубль
(повторный забор того же .fit): файл удаляется, запись не
выполняется (`WorkoutImporter` m06 возвращает существующий id —
запись идемпотентна и без удаления файла).
## 3. Инварианты (🛡 — нарушать запрещено)
1. **Изоляция атлета** — факты пишутся на атлета-владельца учётки
(config → атлет с этим именем; не найден — ошибка fetch, файл
остаётся в DownloadDir).
2. **Повторный запуск не качает дубли** — оба рубежа разд. 2.
3. **Сбой одного файла не останавливает пакет** (как import) —
файл остаётся в DownloadDir, failed++, итоговый код 2.
4. **Тайны** — пароль Garmin в логи не пишется (З-2, З-6); куки/
токены не логируются.
5. **Детерминированность записи** — только конвейер m06, никаких
собственных SQL-записей.
## 4. Критерии приёмки модуля
1. Фейковый Garmin: логин (формальный SSO), список из strength +
cardio активностей — скачивается и импортируется только strength;
`facts_json`/`avg_hr` в БД.
2. Повторный `FetchNew()` — 0 скачиваний (папка-кэш), БД без дублей.
3. .fit, уже импортированный ранее (тот же `fit_file_id` под другим
activityId) — скачивается, файл удаляется, второй строки нет.
4. Неуспешный логин (фейковый 401/antics) — исключение с сообщением
без пароля; CLI-код 2; fallback — подсказка про папку импорта.
5. Тесты интеграционные против docker `watchbody-pg` — зелёные;
сборка решения без ошибок.