Files
x0gp/AGENTS.md
T
x0gp 978d36c505 feat(server): initial implementation
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.
2026-06-22 22:01:09 +04:00

8.2 KiB
Raw Blame History

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 или header X-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 — список планов (keyset start_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-alicedriver-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