# Архитектура ## Модули | Каталог | Назначение | | --- | --- | | `hockey_data/` | Stat2TV, PostgreSQL, матч, статистика, роли, mapping и Agent bridge | | `ui_builder/` | Действующий runtime/редактор UI и активные статические ресурсы | | `broadcast_settings/` | Переносимые настройки команд и vMix JSON | | `khl_site/` | Карточки КХЛ, карьера, обновления и локальные данные | | `agent/` | Windows Agent и исходники Go | | `settings/local/` | Активная конфигурация UI, таймеров, обновлений и восстановление | | `tests/` | Регрессии серверной логики и браузерных функций | | `logs/` | Закрытый постоянный журнал программы в месячных SQLite-файлах | ## Поток данных Stat2TV XML/JSON разбираются сервисом и сохраняются в нормализованных таблицах PostgreSQL: турниры, команды, игроки, составы, события и статистика. Карточки/карьера КХЛ имеют отдельный локальный импорт и синхронизацию. Рабочее состояние матча и права доступа относятся к матчу; персональный канал, назначение устройства и mapping определяют получателя данных vMix. SQL Mapping получает контекст матча/выбора, формирует SetText/SetImage и передаёт их нужному Agent. Отправка команды и её подтверждение — разные этапы. Команды действий (например, Toggle/Cut) нельзя повторять без проверки результата. Восстановление связи должно заново синхронизировать данные, не воспроизводя эфирные действия. Mapping имеет раздельное ожидаемое и подтверждённое состояние. В ожидании ACK — не более одной фоновой Mapping-команды на Agent; доставка не блокирует отдельное чтение heartbeat/ACK. Поколение соединения/назначения отбрасывает устаревшие подтверждения. Новый WebSocket ждёт актуальную inventory перед восстановлением. После committed передачи управления обновляется поколение доставки устройств матча. Шаблон Mapping и опубликованный снимок устройства разделены. Снимок использует существующие таблицы профилей/полей и хранится как технический профиль, связанный с устройством. Сохранение шаблона атомарно проверяет ожидаемую версию. Общие SQL источники остаются общими; параметры контекста разрешаются для конкретного матча. Эксплуатационный журнал независим от доступности PostgreSQL. Он получает структурированные события приложения, стандартный Python logging, Uvicorn, HTTP-аудит и браузерные замеры. Неблокирующая очередь ограничена, запись пакетная; чтение использует короткие подключения и курсорную пагинацию. Секреты маскируются до очереди записи. Запись startup/shutdown закрывается штатно и через atexit. Stat2TV использует общий ограниченный HTTP-пул, а не новое соединение на каждый запрос. Авторизация и timeout передаются отдельно для каждого запроса; при завершении сервера HTTP-клиенты закрываются после фоновых задач. Состояние WebSocket/Agent и часть кэшей находятся в памяти одного процесса. Поэтому запуск нескольких workers без общего хранилища назначения/очередей не является способом масштабирования этой версии. ## Пользовательские данные и артефакты UI хранится атомарно в `settings/local/` либо внешнем `HOCKEY_UI_DATA_DIR`. Одинаковые сохранения не создают копий. Миграция прежней истории backup выполняется однократно; исходные root-настройки сохраняются как bootstrap. `hockey_data/snapshots/` — диагностические XML, а не база рабочего состояния. Новые имена включают полный SHA-256 содержимого и тип ресурса. Повторные данные используют прежний путь без перезаписи. История синхронизаций в БД может ссылаться на эти файлы, поэтому возрастная очистка XML запрещена без сверки ссылок БД. Автоматический retention относится только к самостоятельным JSON-отчётам discovery. Флаги и их LICENSE, шаблоны vMix JSON, исходники Go/Agent.exe, SQL-примеры и проверки входят в проект по назначению. Совпадение имён или содержимого файлов default и локальной конфигурации не делает их взаимозаменяемыми.