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.
96 lines
8.2 KiB
Markdown
96 lines
8.2 KiB
Markdown
# 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-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
|