VEU.WathBody/1-docs/2-arch/hld.puml

108 lines
4.4 KiB
Plaintext
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.

@startuml hld
' ============================================================================
' Феникс 6X — high level design (диаграмма развертывания).
' Нотация: A -> B — зависит/использует; A <>-> B — содержит/управляет.
' Цвета (d-drg-4): жёлтый #FFF4D6 — внешнее; серый #BFBFBF — не в v1.
' ============================================================================
title Феникс 6X: часы + телефон атлета + личный сервер\n(v1.0; серым — v2, жёлтым — внешние системы)
skinparam shadowing false
skinparam defaultTextAlignment center
skinparam backgroundColor #FFFFFF
skinparam defaultFontName Segoe UI
skinparam defaultFontSize 12
skinparam ArrowColor #444444
skinparam component {
BackgroundColor #F5F7FA
BorderColor #7A8899
}
skinparam database {
BackgroundColor #F5F7FA
BorderColor #7A8899
}
together {
node "Часы атлета\n(Garmin, Connect IQ)" as Watch {
component "FenixDataField\nполе данных «Феникс»:\nпульс, зоны, подходы, вибро" as DataField
}
node "Телефон атлета\n(Android, Kotlin)" as Phone {
component "VoiceInput\nофлайн-STT + грамматика команд" as VoiceInput
component "TrainingUi\nэкран тренировки, таймеры, история" as TrainingUi
component "WorkoutCore\nлогика тренировки, допуск,\nдневник, перерывы" as WorkoutCore
component "LocalDb\nRoom/SQLite" as LocalDb
component "SyncQueue\nочередь + идемпотентность" as SyncQueue
component "WatchChannel\ncompanion-канал Connect IQ" as WatchChannel
}
cloud "Личный сервер\n(C# / .NET 10)" as Server {
package "WebApp\nASP.NET Core" as WebApp {
component "RestApi\nsync, workouts, programs\n(X-Api-Key атлета)" as RestApi
component "AdminWeb\nконсоль владельца\n(логин/пароль)" as AdminWeb
}
package "FitPipeline\nзабор и парсинг" as FitPipeline {
component "FitFetcher\nклиент Garmin Connect\n(+ папка импорта)" as FitFetcher
component "FitParser\nGarmin FIT SDK" as FitParser
}
component "MetricsEngine\nadherence, тоннаж, 1ПМ" as MetricsEngine
component "ProgressionRules\nправила прогрессии → draft" as ProgressionRules
component "ProgramStore\nверсии программ (JSON)" as ProgramStore
database "PostgreSQL\nслои src | ref" as Db
}
component "LlmPlanner\nеженедельный контур LLM" as LlmPlanner #BFBFBF
cloud "Garmin Connect\n(облако, .fit)" as GarminConnect #FFF4D6
}
' — зависимости / использование
DataField --> WatchChannel : пульс, зоны,\nтаймер отдыха
WatchChannel --> TrainingUi : live-данные\n(если связь есть)
VoiceInput --> TrainingUi : команды
TrainingUi --> WorkoutCore
WorkoutCore --> LocalDb
LocalDb --> SyncQueue
SyncQueue --> RestApi : HTTPS\nPOST /sync
FitFetcher --> GarminConnect : .fit по расписанию
FitParser --> Db : workout_facts
MetricsEngine --> Db
ProgressionRules --> ProgramStore : draft-версия
ProgramStore --> Db
RestApi --> Db
AdminWeb --> Db
RestApi --> ProgramStore : активная\nверсия
LlmPlanner ..> MetricsEngine : сводка недели\n(v2)
LlmPlanner ..> ProgramStore : предложение\n(v2)
legend bottom
|= Связь |= Значение |
| ""A -> B"" | A зависит от / использует B |
| ""A ..> B"" | связь версии v2 (в v1 не реализована) |
| <back:#FFF4D6>жёлтый</back> | внешняя система |
| <back:#BFBFBF>серый</back> | задумано, не в v1 |
endlegend
note bottom of Watch
Инвариант: часы автономны — запись .fit ведёт
платформа Garmin, поле — только отображение.
Один код поля — сборки под модели Garmin.
end note
note bottom of Phone
Инвариант офлайн-first: все данные сначала в LocalDb;
сеть — только SyncQueue. Каждой записи — client_guid.
end note
note bottom of Db
Инвариант изоляции атлетов: ключ → athlete_id,
все выборки — по атлету.
end note
@enduml