VEU.WathBody/1-docs/4-modules/m06-fit-import/api_specs/01-facts-schema.md

63 lines
3.2 KiB
Markdown
Raw 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.

# Спецификация 01: FitParser — канонический факт workout-facts/1
Источники: tech-req 2.3, Ф-8.2, Ф-13.4. SDK — `Garmin.FIT.Sdk`
(NuGet 21.218.0), namespace `Dynastream.Fit`, событийный
`Decode.MesgEvent`.
## 1. Сигнатура
```csharp
public sealed record FitFacts(
string FactsJson, // workout-facts/1, разд. 2
DateTime StartedAt, // session start (UTC)
int? AvgHr, // среднее records.hr (округление AwayFromZero)
int? HrRecoveryS, // разд. 3
string FitFileId, // file_idmesg.time_created (UTC ISO) + серийник
string Device); // device_infomesg (продукт/версия) или ""
```
`Parse(string path)` — файл читается один раз (потоково,
tech-req 5); `Decode.CheckIntegrity` перед разбором; кривой файл →
`FitException` (обрабатывает ImportService — spec 04).
## 2. Схема JSON
```json
{"schema": "workout-facts/1",
"session": {"type": "strength_training", "start": "2026-10-18T18:00:00Z",
"duration_s": 3600},
"laps": [{"index": 0, "start": "...", "duration_s": 120}],
"records": [{"t_offset_s": 0, "hr": 95}],
"sets": [{"index": 0, "reps": 12, "weight_kg": 100.0}],
"fit_file_id": "...", "device": "..."}
```
| Сообщение | Что берём |
|---|---|
| `FileIdMesg` | `TimeCreated` (UTC) + `SerialNumber` → `fit_file_id` (`"{serial}-{yyyyMMddTHHmmssZ}"`); оба пусты → имя файла |
| `SessionMesg` | `Sport`/`SubSport` (строкой), `StartTime`, `TotalTimerTime` → `duration_s` (сек, округление) |
| `LapMesg` | index по порядку, `StartTime`, `TotalTimerTime` |
| `RecordMesg` | `Timestamp` → `t_offset_s` (от session start), `HeartRate` (есть и > 0) |
| `SetMesg` | index по порядку, `NumReps`, `Weight` (кг; 0xFFFF/0 — нет) |
| `DeviceInfoMesg` | последний (свежий) `Product`/`GarminProduct` → `device` (строкой) |
- Session нет → `FitException` (файл не активность).
- `sets`/`laps`/`records` пустые → пустые массивы (не null).
- Тип сессии — как есть строкой (`strength_training`, `cardio`, …);
фильтра по типу импорт не делает (решает сопоставление).
## 3. hr_recovery_s (Ф-13.4)
Конец последнего Lap (`start + duration`) → первый Record строго
после него с `hr < 90` (порог `Safety.RestingHrSitting` — конфиг,
Р3-А): `hr_recovery_s = t_offset(record) − конец последнего lap в
offset`. Нет записей после последнего Lap или не опустился → `null`.
## 4. Тест-фикстуры
Генерируются в тестах энкодером SDK (`Encode`, `Mesg`-объекты в
прямом порядке FileId → DeviceInfo → Record* → Lap* → Set* → Session):
полная активность (3 рекорда до/1 после Lap с hr < 90, Set с
reps/weight), активность без Set, битый файл (усечённый байтовый
массив).