# x0gp — Architecture Overview Корень проекта. Содержит общую картину системы, glossary и связи между подсистемами. Дата фиксации архитектурных решений: 2026-06-18. Дата обновления (Bambu A1, своё шасси, домашний сервер): 2026-06-18. Дата обновления v2 (Orange Pi 5 Pro + Coolify, Compact 1/27): 2026-06-18. --- ## 1. Что такое x0gp x0gp — это платформа для проведения **гонок на реальных радиоуправляемых машинках** через интернет. Игроки подключаются через Web (позже — мобильное приложение), платят за заезд/турнир и управляют физической машинкой в реальном времени. Целевой пользователь: гонщик-любитель 16-45 лет, желающий участвовать в реальных гонках без необходимости ехать в хобби-клуб. --- ## 2. Целевые метрики | Метрика | Цель | |---|---| | Round-trip команды (экран -> колёса) p50 | < 100 мс | | Round-trip команды p99 | < 200 мс | | Tick rate гонки | 60 Hz | | Одновременных активных заездов на Edge-инстанс | 50-100 | | Доступность | 99.5% (PoC) -> 99.9% (prod) | | Конверсия "регистрация -> первый заезд" | > 30% | | Стоимость инфраструктуры на 1 заезд/час | < 5 руб. (цель) | --- ## 3. Компоненты системы ### 3.1. Слой клиента - **Web client** — React, Vite, TypeScript. WebSocket-клиент с client-side prediction. Canvas/WebGL-рендер трассы и машинок. - **Mobile client** (фаза 5) — React Native, общий с Web протокол. - **Admin panel** — React + TanStack Table, управление трассами, турнирами, пользователями. ### 3.2. Edge-сервер (Go) - **api-gateway** — stateless, REST + WS-терминация, auth, rate-limit. - **race-engine** — stateful, authoritative tick 60 Hz, fan-out. - **agent-linker** — long-lived WS к бортовым агентам в помещении. - **indexer** — пайплайн телеметрии в TimescaleDB. - **replay-recorder** — пишет replay-чанки в S3. ### 3.3. Локальная инфраструктура в помещении - **Gateway-агент (мини-ПК)** — Go-бинарь, держит связь с Edge-сервером и машинками, выполняет CV-инференс, буферизует команды на случай обрыва WAN. - **Wi-Fi роутер** — выделенный SSID "x0gp-track", WPA3. - **Overhead-камеры** — 1-2 шт, 1080p 60 fps global shutter. - **IR-магнитные петли** — на секторах трассы. ### 3.4. Борт машинки - **ESP32-S3 агент** — Wi-Fi, WebSocket к gateway, генерация команд ESC/серво. - **Brushless ESC + мотор** — 1/18 scale. - **Mini digital servo** — рулевое. - **IMU, IR/магнитные сенсоры** — телеметрия. ### 3.5. Хранение - **PostgreSQL** — пользователи, платежи, гонки, турниры. - **Redis** — сессии, pub/sub, лобби, rate-limit. - **TimescaleDB** — телеметрия, replay-индекс. - **S3-совместимое** — replay-чанки (видео, JSON-логи). ### 3.6. Observability - **Loki** — логи. - **Prometheus + Grafana** — метрики. - **Tempo / Jaeger** — трейсы. - **Sentry** — ошибки на клиенте и сервере. --- ## 4. Поток данных (упрощённый) ``` 1. Игрок нажимает газ в браузере | 2. Web-client отправляет InputState{seq, tsMs, throttle: 1.0} по WS | 3. api-gateway принимает, валидирует, кладёт в Redis Stream "race:{id}:inputs" | 4. race-engine на ближайшем тике читает stream, применяет к state | 5. race-engine публикует RaceSnapshot в Redis pub/sub | 6. race-engine шлёт AgentCommand в agent-linker (WebSocket в помещение) | 7. agent-linker шлёт AgentCommand по WS на ESP32-S3 машинки | 8. ESP32-S3 выдаёт PWM на ESC и серво | 9. ESP32-S3 шлёт AgentTelemetry обратно (10-30 Hz) | 10. gateway-агент делает CV-инференс и шлёт CarFrame на сервер | 11. race-engine обновляет authoritative state, шлёт следующий Snapshot | 12. Web-client получает Snapshot, корректирует prediction, рисует кадр ``` Типичный round-trip: 50-120 мс (зависит от расстояния до Edge-сервера). --- ## 5. Модель доверия **Authoritative server**: истиной владеет сервер. Клиент может рендерить раньше (через client-side prediction), но любое решение о кругах, победах, позициях принимается сервером на основе данных от agent-linker (телеметрия ESP32 + CV). **Anti-cheat контур**: вход -> sanity check -> race-engine (state) -> agent-linker (CV) -> indexer (telemetry) -> admin (manual review). --- ## 6. Структура репозитория ``` x0gp/ ARCHITECTURE.md # этот файл README.md # quickstart, how to run server/ # Go-код (см. server/PLAN.md) PLAN.md cmd/ internal/ proto/ migrations/ deploy/ hardware/ # CAD, спецификации, BOM (см. hardware/PLAN.md) PLAN.md cad/ bom/ photos/ web/ # React-клиент (отдельный пакет) mobile/ # React Native (фаза 5) ops/ # общие devops-скрипты, конфиги docs/ # ADR, RFC, диаграммы adr/ diagrams/ ``` --- ## 7. Glossary | Термин | Значение | |---|---| | **Race** | Одна гонка: 2-12 игроков на трассе, общий старт, финиш по N кругов или по времени | | **Lobby** | Пре-гонка: игроки подключаются, выбирают машину, ждут старта | | **Tick** | 1 шаг симуляции (16.67 мс, 60 Hz) | | **Snapshot** | Полное состояние гонки на момент тика (позиции, скорости, круги) | | **Prediction** | Локальная симуляция у клиента между Snapshot'ами | | **Correction** | Сообщение сервера о расхождении клиентского prediction | | **Agent** | Софт на борту машинки (ESP32-S3) или в помещении (мини-ПК) | | **Edge** | Сервер в регионе, ближайшем к игрокам и помещению с трассой | | **Gateway-агент** | Локальный мини-ПК, "мост" между сервером и машинками в помещении | | **Track** | Физическая трасса + логическая (layout_id) | | **Class** | Класс машинки (1/18 Formula, 1/20 Mini и т.д.) | | **Sector** | Часть круга (1/3, 2/3) — IR-магнитная метка | | **DNF** | Did Not Finish — игрок не закончил гонку | | **DQF** | Disqualified — дисквалификация за нарушение | | **Replay** | Запись гонки для просмотра и разбора | --- ## 8. Ключевые ADR (Architecture Decision Records) Подробности — в `docs/adr/`. Здесь — сводка: - **ADR-001**: WebSocket + protobuf как основной транспорт. - **ADR-002**: Authoritative server + client-side prediction. - **ADR-003**: ESP32-S3 как бортовая MCU, MicroPython в PoC -> ESP-IDF в проде. - **ADR-004**: Гибрид IR-магнитные секторы + overhead-CV для позиционирования. - **ADR-005**: Масштаб машинки 1/18 (длина шасси 18-22 см), ширина полосы 30-40 см. - **ADR-006**: Edge + Gateway-агент: сервер не знает о Wi-Fi трассе, агент буферизует обрыв WAN. - **ADR-007**: Биллинг через ЮKassa (РФ) + Stripe (международный). - **ADR-008**: 3D-принтер **Bambu A1** как основной для производства шасси, барьеров, маунтов, кузовов. Альтернатива — Bambu P1S при необходимости enclosure для инженерных пластиков. - **ADR-009**: Шасси машинки **полностью своё**, спроектированное и напечатанное на 3D-принтере. Не используем покупные донорские деки. - **ADR-010**: Edge-сервер в PoC и MVP работает на **домашнем сервере** с доступом из интернета через Cloudflare Tunnel (default) или WireGuard. Перенос на облако/VPS — только при появлении коммерческой нагрузки и SLA обязательств. - **ADR-011**: Домашний сервер — **Orange Pi 5 Pro** (RK3588S, ARM64, 8 cores, 6 TOPS NPU, 2×2.5 GbE) с развёрнутым **Coolify** (self-hosted PaaS) для деплоя и управления сервисами. NPU Orange Pi используется для CV-инференса (YOLO/ByteTrack через RKNN Toolkit 2). LAN-порт Orange Pi изолирует сеть трассы от домашней сети. Доступ из интернета — Caddy + Let's Encrypt напрямую (статический IP от провайдера). - **ADR-012**: Масштаб машинки — **Compact 1/27** как primary класс (длина шасси 13-15 см, wheelbase 100-115 мм, вес 150-220 г). Ширина полосы трассы 20-25 см, рабочая зона трассы 200×130 см (помещается в комнату 446×319 см с запасом). Альтернативный класс — Standard 1/24 (16-18 см) для тех, кому нужна чуть большая стабильность. Цель — минимизация площади трассы и стоимости при сохранении управляемости 3D-печати. --- ## 9. Что дальше После фиксации плана — переход к **PoC**: 1. Минимальный набор: 1 машинка, 1 трасса 100x60 см, 1 gateway-агент, 1 сервер. 2. Цель: end-to-end "команда -> колёса крутятся, телеметрия возвращается". 3. Срок: 1-2 недели. Детали — в `server/PLAN.md` (фаза S0) и `hardware/PLAN.md` (фаза H0).