# Архитектура: Феникс 6X v1 > Шаг 4 процесса разработки (`std1\_process\process.md`). > Источники: [vision.md](../1-reqs/vision.md) (v1.4, изменения 1.1–1.4), > [requirements.md](../1-reqs/requirements.md) v1.4 (черновик, ревью №2), > дизайн LLM-планирования (разд. 8), документ форматов, документы > «Метрики…» и «Перерывы…». > Схема компонентов: [hld.puml](hld.puml) (+ рендер [hld.svg](hld.svg), > [hld.png](hld.png)). > Версия 1.0 — **УТВЕРЖДЕНО** (2026-10-17). > Версия 1.1 — **УТВЕРЖДЕНО** (2026-10-17): актуализация под Ф-13 > (ревью З-2) и Ф-14 — перерывы (изменение vision 1.4); волна 2 ревью > (Р1–Р3). > Версия 1.2 — **УТВЕРЖДЕНО** (2026-10-17): ревью №2, З-29 — перечень `LocalDb` > дополнен (`daily_log`, `breaks`); источник — requirements v1.4. ## 1. Компоненты и размещение ### 1.1. Часы атлета — `FenixDataField` (Monkey C, Connect IQ) Поле данных «Феникс» в штатном профиле «Силовая». Только отображение (пульс, средний за подход, время, цвет зоны, вибро) — запись `.fit` ведёт платформа Garmin (инвариант из requirements, Ф-2.7). Один исходный код, сборки под целевые модели Garmin — конфигурациями (изменение vision 1.1); перечень моделей — открытый вопрос 8 требований. Связь с телефоном — companion-канал Connect IQ (`WatchChannel`, компонент телефона): live-пульс, зоны, таймер отдыха передаются в объёме возможностей канала (открытый вопрос 3); отсутствие связи ничего не ломает — часы автономны. ### 1.2. Телефон атлета — **Phone.WatchBody** (Android, Kotlin) - `TrainingUi` — экраны (Jetpack Compose — кандидат, фиксируется шагом 5): активная тренировка, история, программы, профиль, «Сегодня» (дневник) и «Допуск»; тёмная тема, крупные зоны касания. - `VoiceInput` — офлайн-STT (движок — открытый вопрос 2) + грамматика команд (Ф-1.2) + TTS-подтверждения; журнал команд для сопоставления с .fit. - `WorkoutCore` — логика тренировки и программ: подходы, таймеры, план/факт, редактор программ; 🛡 предстартовый допуск (пороги Safety, экран допуска) и дневник самоконтроля (`daily_log`); автомат перерывов и формула возврата (Ф-14); единственный писатель `LocalDb`. - `LocalDb` — Room/SQLite: текущая тренировка, история, программы, библиотека, профиль, дневник самоконтроля (`daily_log`), перерывы (`breaks`), очередь. - `SyncQueue` — исходящие записи с `client_guid`, пакеты ≤ 50, идемпотентная отправка `POST /api/v1/sync`; тихие баннеры статуса. - `WatchChannel` — companion-канал Connect IQ. 🛡 Офлайн-first: сеть стоит только на пути `SyncQueue`; все остальные компоненты работают без сети (requirements, раздел 5). ### 1.3. Личный сервер — **Server.WatchBody** (C# / .NET 10, PostgreSQL) Проекты в `3-app\`: | Компонент | Проект (`3-app\2-cli\`) | Ответственность | |---|---|---| | `RestApi` | `Server.WatchBody.Web` | `POST /api/v1/sync`, `GET workouts`, `GET programs/active`; ключ атлета → `athlete_id`; HTTPS | | `AdminWeb` | `Server.WatchBody.Web` | Консоль владельца (логин/пароль): атлеты, тренировки + ход, программы, планы, метрики, CSV | | `FitFetcher` | `Server.WatchBody.Fetch` | Клиент Garmin Connect (неофициальный, опросник 4.3); `--mode fetch`; дедупликация по `fit_file_id` | | `FitParser` | `Server.WatchBody.Import` | Garmin FIT SDK: Session/Lap/Record/Set → `workout_facts`; `--mode import` (fallback: .fit/.tcx/.gpx из папки) | | `MetricsEngine` | `Server.WatchBody.Core` | adherence, тоннаж по группам, 1ПМ, пульс-метрики, красные флаги (АД/пульс/боль — документ метрик) → `workout_metrics` | | `ProgressionRules` | `Server.WatchBody.Core` | Правила прогрессии, делоада и координации 1–11 (документ метрик) + 12–17 перерывы (документ перерывов): детекция `break` по пропускам, формула возврата → draft-версии (`author=rules`) | | `ProgramStore` | `Server.WatchBody.Core` | Версионированный JSON программ; неизменяемость версий; `active` — ровно один на атлета | | БД | схема `src` \| `ref` | PostgreSQL: атлеты, тренировки/факты + `session_kind`, дневник (`daily_log`), перерывы (`breaks`), метрики, программы, журнал LLM (v2) | Общая библиотека — `Kit.Helpers` (`3-app\1-lib`, std1). Взаимодействие с LLM (v2, `LlmPlanner`) — по правилам std1 `c-llm`; в v1 компонент не реализуется (на схеме — серым). ### 1.4. Внешние системы (жёлтым на схеме) - **Garmin Connect** — облако: источник `.fit` (забор `FitFetcher` по расписанию — внешний планировщик, открытый вопрос 4). - **Garmin (устройства)** — запись `.fit` на часах, companion-канал. ## 2. Поток цикла обработки 0. **Допуск и перерывы.** Перед стартом — экран допуска (АД/пульс; красные флаги блокируют или переводят в лёгкое кардио; обход логируется); автомат перерывов ставит `break` по пропускам и запрашивает причину у атлета; при возврате — формульная версия (Ф-14). 1. **Тренировка.** Атлет запускает «Силовую» на часах (`FenixDataField` показывает пульс/зоны/подходы) и активирует голосовой ввод на телефоне (`VoiceInput` → команды → `WorkoutCore` → `LocalDb`). Часы и телефон независимы: любой из них работает без другого (🛡). 2. **Фиксация плана.** `WorkoutCore` показывает позицию активной программы (`RestApi → ProgramStore`, при наличии сети; локальная копия — офлайн), помечает подходы «по плану/отклонение». 3. **Синхронизация.** `SyncQueue` досылает новые записи на `RestApi` при появлении сети; сервер пишет их по `client_guid` (идемпотентно) от имени атлета ключа. 4. **Трек.** Часы синхронизируются с Garmin Connect; `FitFetcher` по расписанию забирает новые `.fit`, `FitParser` раскладывает в `workout_facts`; сопоставление с тренировкой телефона — по времени начала ± 15 минут (Ф-8.4). 5. **Метрики и правила.** `MetricsEngine` считает adherence/тоннаж/1ПМ; `ProgressionRules` формируют draft-версию следующей программы (микроправки ±2,5 кг / −5 %, делоад). 6. **Подтверждение.** Draft показывается атлету на телефоне (дифф) или владельцу в `AdminWeb`; после подтверждения версия становится `active` (🛡 автоматической смены нет). 7. **Наблюдение.** Владелец видит в `AdminWeb` ход тренировок, планы/факт, динамику; CSV — выгрузка выборки. ## 3. Границы и контракты | Граница | Контракт | Открытые вопросы | |---|---|---| | Телефон ↔ сервер | REST/HTTPS, `X-Api-Key` (атлет), `client_guid`-идемпотентность, пакеты ≤ 50; формат записей — JSON (документ форматов) | — (спецификация — шаг 5) | | Телефон ↔ часы | companion-канал Connect IQ: live-пульс, зоны, таймер отдыха; деградация без связи | ОВ-3 (шаг 4) | | Сервер ↔ Garmin Connect | неофициальный клиент, учётка владельца; деградация — папка импорта `--mode import` | — | | Сервер ↔ LLM (v2) | structured output, валидатор, офлайн-fallback на правила (дизайн LLM-планирования) | до v2 | ## 4. Точки расширения - **Модели часов** — новая конфигурация сборки `FenixDataField` (разметка под экран), код не меняется (изменение vision 1.1). - **LLM-планирование (v2)** — `LlmPlanner` потребляет сводку `MetricsEngine` и предлагает версии через `ProgramStore`; `ProgressionRules` остаются базовым режимом (офлайн-fallback). - **Трековые виды спорта (v3+)** — расширение `FitParser` (телеметрия) и `WorkoutCore` (ввод темпа/дистанции); пульс/синхронизация/архив не меняются (опросник 4.7). - **Общий справочник упражнений (v2)** — надстройка над изолированными библиотеками атлетов (ОВ-11 требований). ## 5. Архитектурные инварианты (🛡) 1. **Независимость частей** — часы, телефон, сервер работают при отсутствии остальных; ни один путь записи не проходит через сеть. 2. **Офлайн-first** — источник истины на телефоне — `LocalDb`; сервер — архив и планирование. 3. **Идемпотентность** — `client_guid` на телефоне ↔ сервере, `fit_file_id` на заборе, архивация файлов импорта: повторы не создают дублей. 4. **Изоляция атлетов** — ключ → `athlete_id`; все выборки API и метрики — в пределах атлета; веб — только владелец. 5. **Неизменяемость истории** — версии программ и факт-записи не переписываются; корректировка = новая версия. 6. **LLM не источник истины** — в v1 решений LLM нет; в v2 — только предложения через валидатор и подтверждение (БР-5).