5.6 KiB
5.6 KiB
Требования к модулю: 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.csWeb (единая точка входа, 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)
Два рубежа:
- Быстрый (без сети): файл
{activityId}.fitуже есть вGarmin.DownloadDir→ activityId пропускается, повторного скачивания нет. - По БД: скачанный файл разбирается,
fit_file_id(FileId сообщения) ищется вsrc.workout— есть → это дубль (повторный забор того же .fit): файл удаляется, запись не выполняется (WorkoutImporterm06 возвращает существующий id — запись идемпотентна и без удаления файла).
3. Инварианты (🛡 — нарушать запрещено)
- Изоляция атлета — факты пишутся на атлета-владельца учётки (config → атлет с этим именем; не найден — ошибка fetch, файл остаётся в DownloadDir).
- Повторный запуск не качает дубли — оба рубежа разд. 2.
- Сбой одного файла не останавливает пакет (как import) — файл остаётся в DownloadDir, failed++, итоговый код 2.
- Тайны — пароль Garmin в логи не пишется (З-2, З-6); куки/ токены не логируются.
- Детерминированность записи — только конвейер m06, никаких собственных SQL-записей.
4. Критерии приёмки модуля
- Фейковый Garmin: логин (формальный SSO), список из strength +
cardio активностей — скачивается и импортируется только strength;
facts_json/avg_hrв БД. - Повторный
FetchNew()— 0 скачиваний (папка-кэш), БД без дублей. - .fit, уже импортированный ранее (тот же
fit_file_idпод другим activityId) — скачивается, файл удаляется, второй строки нет. - Неуспешный логин (фейковый 401/antics) — исключение с сообщением без пароля; CLI-код 2; fallback — подсказка про папку импорта.
- Тесты интеграционные против docker
watchbody-pg— зелёные; сборка решения без ошибок.