mirror of
https://github.com/IS1DI/x0gp.git
synced 2026-07-16 20:47:55 +00:00
This commit captures the full server code accumulated across
several development sessions. It includes the following layers,
applied in roughly this order during development:
1. Base infrastructure
- cmd/poc-server HTTP+WebSocket server, /health, /stats
- internal/transport wire types (Envelope + all message types)
- internal/catalog, internal/realtime, internal/stats
- internal/storage/postgres with migrations 001-004
- .env, .env.example, docker-compose, Dockerfile, scripts/
2. Swagger documentation
- go get github.com/swaggo/http-swagger
- swag init produces docs/docs.go
- /swagger/index.html UI, /swagger/doc.json spec
- annotations on health/stats/ws and catalog handlers
3. Races API
- internal/races/{store,service,keyset,types}.go
- migration 005_races.sql: finished_races, race_plans, race_queue
- GET /api/races with keyset pagination, status filter
- GET /api/races/upcoming
- POST /api/races/queue/join, GET, DELETE
- POST/GET /api/races/plans, DELETE /{id}
- lobby.RaceMeta simplification (no host_id/host_name)
4. Races seeder
- internal/races/seed with deterministic generator
- --seed-races / --reset CLI flags in main.go
- 30 finished + 5 live + 5 plans + 4 queue entries
5. Drivers and clans
- internal/drivers, internal/clans (CRUD, validation)
- migration 008_drivers_clans.sql
- /api/clans and /api/drivers endpoints
- 3-letter uppercase nickname/tag validation
- lobby.DriverMeta: Nickname, AvatarURL, ClanID, ClanTag
6. Podium
- internal/transport.RacePodiumEntry
- lobby.SetDriverProfile for in-memory metadata sync
- migration 007_podium.sql (podium JSONB column)
- seeder populates top-3 per finished race
7. Live races persistence
- migration 009_live_persistence.sql: live_races,
live_race_drivers, lobby_drivers
- internal/races/live_store.go: LiveStore with write-side
mirror for lobby.Service mutations
- Service.collectLive and Upcoming read from Postgres
- main.go RestoreFromDB rehydrates lobby on startup
8. Unify live + finished into one races table
- migration 010_unify_races.sql: rename finished_races to
races, expand status CHECK, merge live rows
- PgStore now hosts both write paths; LiveStore is a
thin facade implementing lobby.Persistence
- seeder resetAll drops only finished/cancelled rows and
race_plans / race_queue / lobby_drivers
Each layer is consistent on its own; cross-layer changes are
visible in the file history. A future refactor may split this
commit into the per-stage boundaries listed above.
8.2 KiB
8.2 KiB
AGENTS.md — заметки для ассистента
Этот файл — заметки, которые нужно помнить между сессиями.
MCP-инструменты, которые здесь работают
blender-mcp
Управляет Blender-сценой напрямую. Используй когда нужно менять/осматривать 3D-модель машинки (OpenRC_F1_2018_Halo, BodyCam, LayoutCam, Battery и др.).
Типичные задачи:
- Осмотреть сцену:
blender-mcp_get_scene_info,blender-mcp_get_viewport_screenshot - Менять геометрию:
blender-mcp_execute_blender_code(Python в Blender) - Скачивать ассеты:
blender-mcp_download_polyhaven_asset,blender-mcp_search_sketchfab_models,blender-mcp_download_sketchfab_model,blender-mcp_set_texture - Генерировать 3D по тексту/картинке:
blender-mcp_generate_hyper3d_model_via_text,blender-mcp_generate_hyper3d_model_via_images,blender-mcp_generate_hunyuan3d_model
В текущей сцене 78 объектов, 49 материалов. Корневая папка модели — D:/x0gp. Blender-сцену открывать не надо — MCP подключён к запущенному Blender.
chrome-mcp-server
Управляет Chrome-браузером. Удобно для проверки ссылок на товары из CART_MVP.md (Ozon/WB/AliExpress).
Типичные задачи:
- Список открытых вкладок:
chrome-mcp-server_get_windows_and_tabs - Открыть URL:
chrome-mcp_navigate - Прочитать страницу:
chrome-mcp_read_page(предпочтительнее скриншота),chrome-mcp_get_web_content - Клик/ввод:
chrome-mcp_click_element,chrome-mcp_fill_or_select,chrome-mcp_keyboard - Переключить вкладку:
chrome-mcp_switch_tab - Скриншот:
chrome-mcp_computerсaction=screenshotилиchrome-mcp_screenshot
Сейчас уже открыто ~20 вкладок с товарами из корзины MVP. Не закрывай их без причины.
Ключевые файлы проекта
D:/x0gp/hardware/CART_MVP.md— корзина MVP (что заказать)D:/x0gp/hardware/ASSEMBLY.md— пошаговая сборкаD:/x0gp/hardware/BOM_v4.json— структурированный BOM (машины в JSON)D:/x0gp/hardware/SHOPPING_LIST.md— каталог альтернатив (бонусы)D:/x0gp/hardware/PLAN.md— общий планD:/x0gp/hardware/print/stl/*.stl— STL для печати на P1S (13 шт)D:/x0gp/hardware/print/parts_manifest.md— манифест печатиD:/x0gp/ARCHITECTURE.md— общая архитектура проекта
Сервер x0gp (D:/x0gp/server)
- Go 1.26, бинарь
cmd/poc-server. Сборка:go build ./...илиgo build -o poc-server.exe ./cmd/poc-server. - HTTP+WebSocket, роутер
http.NewServeMux. Запуск требуетDATABASE_URL(см..env). - Swagger UI:
GET /swagger/index.html, спекаGET /swagger/doc.json(14 paths, 29 definitions). - Генерация спеки:
swag init -g cmd/poc-server/main.go -o docs --parseInternalизD:/x0gp/server. CLI ставится черезgo install github.com/swaggo/swag/cmd/swag@v1.16.4. - Аннотации swag живут над хендлерами в
cmd/poc-server/main.go,catalog_handlers.go,races_handlers.go. При добавлении нового REST-эндпоинта — добавить@Router/@Param/@Successи перегенеритьdocs/. - Не использовать
--parseDependency: падает на stdlib (runtime/mprof.go).
Хранилище гонок (гибрид)
- Live (status=lobby|countdown|racing): in-memory
lobby.Service. - Finished: Postgres (
finished_races), снапшот пишется вlobby.SetRaceLifecycleHookприSetRaceStatus(finished). - Race plans (
race_plans): расписание, материализуется в lobby шедулером раз в 5 сек. - Queue (
race_queue): подписки(driver_id, race_id).
API гонок (keyset-пагинация)
GET /api/races— список (live + finished), фильтрыstatus,track_id,cursor,limit(1..200, default 50). Status enum:all|lobby|racing|finished. Кастомных лобби нет — гонки привязаны к физическим трекам, фильтр только поtrack_id. Cursor — base64(ms:id[:src]).GET /api/races/upcoming?limit=3— ближайшие lobby|countdown.POST /api/races/queue/join— встать в очередь на следующие N (body:driver_id,limitили headerX-Driver-Id).GET /api/races/queue?driver_id=...— посмотреть.DELETE /api/races/queue?driver_id=...&race_id=...— выйти.POST /api/races/plans— создать расписание (start_at_ms, interval_s, count, ...).GET /api/races/plans— список планов (keysetstart_at_ms ASC, id ASC).DELETE /api/races/plans/{id}— удалить.
Сущности drivers и clans
- Таблицы
drivers(id, nickname [3 uppercase letters], name, avatar_url, clan_id?) иclans(id, tag [3 uppercase letters], name, avatar_url). - CRUD:
POST/GET /api/clans,GET/PUT/DELETE /api/clans/{id},GET /api/clans/by-tag/{tag}POST/GET /api/drivers,GET/PUT/DELETE /api/drivers/{id},GET /api/drivers/by-nick/{nick}
PUT /api/drivers/{id}принимаетclan_idкак*string(nil = оставить, "" = очистить, иначе = назначить).- Сидер (через
--seed-races) заполняет 3 клана и 8 водителей, треки берутся изtracksкаталога (никаких выдуманных id вfinished_races/race_plans). - Podium в
LobbyRaceзаполняется только для finished-гонок (top-3: position, driver_id, name, total_time_ms).
TODO
- Реальная сущность driver ещё не используется для lobby.DriverMeta при входе через WS — там пока захардкоженный driver. При первой сессии надо подтягивать профиль из таблицы
driversи зватьlobby.SetDriverProfile(id, nick, avatar, clanID, clanTag).
Сид моковых гонок
poc-server.exe --seed-races— при старте наполняет БД и lobby детерминированными моками: 30 finished, 5 live, 5 plans, 4 queue-entries.poc-server.exe --seed-races --reset— сначалаTRUNCATE finished_races, race_plans, race_queueи очищает lobby.- Без флага
--seed-racesсидер не запускается, даже еслиX0GP_SEED_RACES=1(флаг > env). - Драйвер — константный, водители в lobby под именами
driver-alice…driver-heidi.
Важные факты о машинке (x0gp F1 1/27)
- Масштаб: 1/27, wheelbase 102мм, deck 80×135мм, толщина 1.5мм PETG
- Мотор MVP: коллекторный 370 35T (Ø24×30мм) с Ozon
- ⚠️
motor_mount.stlсейчас под мотор 130/180 (Ø20мм) — надо перепечатать под Ø24мм до сборки - Кузов печатаем сами (PETG, body_shell.stl), готовый Kyosho НЕ покупаем
- Подшипники: 684ZZ 4×9×4 (перед) + 693ZZ 3×8×4 (зад)
- ESP32-S3-DevKitC-1 N16R8 + U.FL (Wi-Fi агент, не RC-приёмник!)
- MPU-6050 пины: SDA=GPIO21, SCL=GPIO22 (это уже исправлено в ASSEMBLY.md)
- FPV: AIO модуль с WB (1997₽) + антенна RUSHFPV с AliExpress (1050₽) — это разные вещи (передатчик vs антенна к нему)
- VRX (приёмник видео) для MVP не нужен — показываем картинку через Wi-Fi стрим ESP32 на телефон/PC