mirror of
https://github.com/IS1DI/x0gp.git
synced 2026-07-17 04:57:55 +00:00
2369 lines
62 KiB
YAML
2369 lines
62 KiB
YAML
basePath: /
|
|
definitions:
|
|
transport.BatteryWire:
|
|
properties:
|
|
capacity_mah:
|
|
type: integer
|
|
cells:
|
|
type: integer
|
|
chemistry:
|
|
type: string
|
|
voltage_v:
|
|
type: number
|
|
type: object
|
|
transport.CarAck:
|
|
properties:
|
|
car:
|
|
$ref: '#/definitions/transport.CarWire'
|
|
error:
|
|
type: string
|
|
id:
|
|
type: string
|
|
ok:
|
|
type: boolean
|
|
type: object
|
|
transport.CarCreateRequest:
|
|
properties:
|
|
car:
|
|
$ref: '#/definitions/transport.CarWire'
|
|
type: object
|
|
transport.CarPatch:
|
|
properties:
|
|
active:
|
|
type: boolean
|
|
avatar_url:
|
|
type: string
|
|
battery:
|
|
$ref: '#/definitions/transport.BatteryWire'
|
|
chassis:
|
|
$ref: '#/definitions/transport.ChassisWire'
|
|
color_hex:
|
|
type: string
|
|
drive:
|
|
type: string
|
|
height_mm:
|
|
type: number
|
|
length_mm:
|
|
type: number
|
|
motor:
|
|
$ref: '#/definitions/transport.MotorWire'
|
|
name:
|
|
type: string
|
|
scale:
|
|
type: integer
|
|
top_speed_ms:
|
|
type: number
|
|
visibility:
|
|
type: string
|
|
weight_g:
|
|
type: number
|
|
width_mm:
|
|
type: number
|
|
type: object
|
|
transport.CarUpdateRequest:
|
|
properties:
|
|
id:
|
|
type: string
|
|
patch:
|
|
$ref: '#/definitions/transport.CarPatch'
|
|
type: object
|
|
transport.CarWire:
|
|
properties:
|
|
active:
|
|
type: boolean
|
|
avatar_url:
|
|
type: string
|
|
battery:
|
|
$ref: '#/definitions/transport.BatteryWire'
|
|
best_lap_ms:
|
|
type: integer
|
|
chassis:
|
|
$ref: '#/definitions/transport.ChassisWire'
|
|
color_hex:
|
|
type: string
|
|
created_ms:
|
|
type: integer
|
|
drive:
|
|
type: string
|
|
height_mm:
|
|
type: number
|
|
id:
|
|
type: string
|
|
length_mm:
|
|
type: number
|
|
motor:
|
|
$ref: '#/definitions/transport.MotorWire'
|
|
name:
|
|
type: string
|
|
owner_id:
|
|
type: string
|
|
scale:
|
|
type: integer
|
|
top_speed_ms:
|
|
type: number
|
|
total_distance_m:
|
|
type: number
|
|
total_laps:
|
|
type: integer
|
|
total_races:
|
|
type: integer
|
|
updated_ms:
|
|
type: integer
|
|
visibility:
|
|
type: string
|
|
weight_g:
|
|
type: number
|
|
width_mm:
|
|
type: number
|
|
type: object
|
|
transport.ChassisWire:
|
|
properties:
|
|
material:
|
|
type: string
|
|
model:
|
|
type: string
|
|
printed:
|
|
type: boolean
|
|
track_mm:
|
|
type: number
|
|
wheelbase_mm:
|
|
type: number
|
|
type: object
|
|
transport.Clan:
|
|
properties:
|
|
avatar_url:
|
|
example: https://cdn.example.com/c/ace.png
|
|
type: string
|
|
created_ms:
|
|
type: integer
|
|
id:
|
|
example: clan-1782000-1
|
|
type: string
|
|
name:
|
|
example: Ace Racing
|
|
type: string
|
|
tag:
|
|
example: ACE
|
|
type: string
|
|
updated_ms:
|
|
type: integer
|
|
type: object
|
|
transport.ClanCreateRequest:
|
|
properties:
|
|
avatar_url:
|
|
example: https://cdn.example.com/c/ace.png
|
|
type: string
|
|
id:
|
|
example: clan-1782000-1
|
|
type: string
|
|
name:
|
|
example: Ace Racing
|
|
type: string
|
|
tag:
|
|
example: ACE
|
|
type: string
|
|
type: object
|
|
transport.ClanListResponse:
|
|
properties:
|
|
count:
|
|
type: integer
|
|
items:
|
|
items:
|
|
$ref: '#/definitions/transport.Clan'
|
|
type: array
|
|
type: object
|
|
transport.ClanUpdateRequest:
|
|
properties:
|
|
avatar_url:
|
|
example: https://cdn.example.com/c/ace.png
|
|
type: string
|
|
name:
|
|
example: Ace Racing
|
|
type: string
|
|
type: object
|
|
transport.Driver:
|
|
properties:
|
|
avatar_url:
|
|
example: https://cdn.example.com/u/ace.png
|
|
type: string
|
|
clan_id:
|
|
example: clan-1782000-1
|
|
type: string
|
|
created_ms:
|
|
type: integer
|
|
id:
|
|
example: driver-1782000-123
|
|
type: string
|
|
name:
|
|
example: Alice
|
|
type: string
|
|
nickname:
|
|
example: ACE
|
|
type: string
|
|
updated_ms:
|
|
type: integer
|
|
type: object
|
|
transport.DriverCreateRequest:
|
|
properties:
|
|
avatar_url:
|
|
example: https://cdn.example.com/u/ace.png
|
|
type: string
|
|
clan_id:
|
|
example: clan-1782000-1
|
|
type: string
|
|
id:
|
|
example: driver-1782000-123
|
|
type: string
|
|
name:
|
|
example: Alice
|
|
type: string
|
|
nickname:
|
|
example: ACE
|
|
type: string
|
|
type: object
|
|
transport.DriverListResponse:
|
|
properties:
|
|
count:
|
|
type: integer
|
|
items:
|
|
items:
|
|
$ref: '#/definitions/transport.Driver'
|
|
type: array
|
|
type: object
|
|
transport.DriverUpdateRequest:
|
|
properties:
|
|
avatar_url:
|
|
example: https://cdn.example.com/u/ace.png
|
|
type: string
|
|
clan_id:
|
|
example: clan-1782000-1
|
|
type: string
|
|
name:
|
|
example: Alice
|
|
type: string
|
|
type: object
|
|
transport.Envelope:
|
|
properties:
|
|
payload: {}
|
|
seq:
|
|
type: integer
|
|
ts_ms:
|
|
type: integer
|
|
type:
|
|
$ref: '#/definitions/transport.MessageType'
|
|
type: object
|
|
transport.LeaderboardEntry:
|
|
properties:
|
|
avatar_url:
|
|
example: https://cdn.example.com/u/ace.png
|
|
type: string
|
|
best_pos:
|
|
description: Only populated for track-specific leaderboard
|
|
example: 1
|
|
type: integer
|
|
best_time_ms:
|
|
example: 15000
|
|
type: integer
|
|
clan_id:
|
|
example: clan-seed-001
|
|
type: string
|
|
clan_tag:
|
|
example: ACE
|
|
type: string
|
|
driver_id:
|
|
example: driver-seed-001
|
|
type: string
|
|
name:
|
|
example: Alice
|
|
type: string
|
|
nickname:
|
|
example: ACE
|
|
type: string
|
|
points:
|
|
example: 25
|
|
type: integer
|
|
rank:
|
|
example: 1
|
|
type: integer
|
|
type: object
|
|
transport.LeaderboardResponse:
|
|
properties:
|
|
current_driver:
|
|
$ref: '#/definitions/transport.LeaderboardEntry'
|
|
items:
|
|
items:
|
|
$ref: '#/definitions/transport.LeaderboardEntry'
|
|
type: array
|
|
limit:
|
|
example: 50
|
|
type: integer
|
|
offset:
|
|
example: 0
|
|
type: integer
|
|
total:
|
|
example: 8
|
|
type: integer
|
|
type: object
|
|
transport.LobbyRace:
|
|
properties:
|
|
created_ms:
|
|
type: integer
|
|
driver_ids:
|
|
items:
|
|
type: string
|
|
type: array
|
|
id:
|
|
type: string
|
|
laps:
|
|
type: integer
|
|
max_cars:
|
|
type: integer
|
|
name:
|
|
type: string
|
|
podium:
|
|
description: Podium is populated only for finished races. Empty for live ones.
|
|
items:
|
|
$ref: '#/definitions/transport.RacePodiumEntry'
|
|
type: array
|
|
started_ms:
|
|
type: integer
|
|
status:
|
|
type: string
|
|
time_limit_s:
|
|
type: integer
|
|
track_id:
|
|
type: string
|
|
type: object
|
|
transport.MessageType:
|
|
enum:
|
|
- client_hello
|
|
- join_race
|
|
- leave_race
|
|
- input_state
|
|
- chat_message
|
|
- ping
|
|
- lobby_list
|
|
- lobby_create
|
|
- lobby_quick_play
|
|
- lobby_join_race
|
|
- lobby_leave_race
|
|
- lobby_kick_driver
|
|
- lobby_delete
|
|
- track_list
|
|
- track_get
|
|
- track_create
|
|
- track_update
|
|
- track_delete
|
|
- car_list
|
|
- car_get
|
|
- car_create
|
|
- car_update
|
|
- car_delete
|
|
- stats_request
|
|
- server_hello
|
|
- race_snapshot
|
|
- input_ack
|
|
- correction
|
|
- race_event
|
|
- pong
|
|
- error
|
|
- lobby_snapshot
|
|
- track_snapshot
|
|
- track_ack
|
|
- car_snapshot
|
|
- car_ack
|
|
- catalog_summary
|
|
- stats_snapshot
|
|
- driver_profile
|
|
- lap_recorded
|
|
- race_result
|
|
- race_standings
|
|
type: string
|
|
x-enum-varnames:
|
|
- TypeClientHello
|
|
- TypeJoinRace
|
|
- TypeLeaveRace
|
|
- TypeInputState
|
|
- TypeChatMessage
|
|
- TypePing
|
|
- TypeLobbyList
|
|
- TypeLobbyCreate
|
|
- TypeLobbyQuickPlay
|
|
- TypeLobbyJoinRace
|
|
- TypeLobbyLeaveRace
|
|
- TypeLobbyKickDriver
|
|
- TypeLobbyDelete
|
|
- TypeTrackList
|
|
- TypeTrackGet
|
|
- TypeTrackCreate
|
|
- TypeTrackUpdate
|
|
- TypeTrackDelete
|
|
- TypeCarList
|
|
- TypeCarGet
|
|
- TypeCarCreate
|
|
- TypeCarUpdate
|
|
- TypeCarDelete
|
|
- TypeStatsRequest
|
|
- TypeServerHello
|
|
- TypeRaceSnapshot
|
|
- TypeInputAck
|
|
- TypeCorrection
|
|
- TypeRaceEvent
|
|
- TypePong
|
|
- TypeError
|
|
- TypeLobbySnapshot
|
|
- TypeTrackSnapshot
|
|
- TypeTrackAck
|
|
- TypeCarSnapshot
|
|
- TypeCarAck
|
|
- TypeCatalogSummary
|
|
- TypeStatsSnapshot
|
|
- TypeDriverProfile
|
|
- TypeLapRecorded
|
|
- TypeRaceResult
|
|
- TypeRaceStandings
|
|
transport.MotorWire:
|
|
properties:
|
|
class:
|
|
type: string
|
|
kind:
|
|
type: string
|
|
kv:
|
|
type: integer
|
|
power_w:
|
|
type: number
|
|
type: object
|
|
transport.RaceListResponse:
|
|
properties:
|
|
count:
|
|
type: integer
|
|
items:
|
|
items:
|
|
$ref: '#/definitions/transport.LobbyRace'
|
|
type: array
|
|
next_cursor:
|
|
example: MTcwMDAwMDAwMDAwMDpyYWNlLWFiYzpmaW5pc2hlZA
|
|
type: string
|
|
type: object
|
|
transport.RacePlan:
|
|
properties:
|
|
count:
|
|
example: 0
|
|
type: integer
|
|
created_ms:
|
|
type: integer
|
|
enabled:
|
|
example: true
|
|
type: boolean
|
|
fires_done:
|
|
type: integer
|
|
id:
|
|
example: plan-1730000-1
|
|
type: string
|
|
interval_s:
|
|
example: 3600
|
|
type: integer
|
|
laps:
|
|
example: 10
|
|
type: integer
|
|
max_cars:
|
|
example: 4
|
|
type: integer
|
|
name:
|
|
example: Daily Monza
|
|
type: string
|
|
next_fire_ms:
|
|
type: integer
|
|
start_at_ms:
|
|
example: 1730000000000
|
|
type: integer
|
|
time_limit_s:
|
|
type: integer
|
|
track_id:
|
|
example: default
|
|
type: string
|
|
updated_ms:
|
|
type: integer
|
|
type: object
|
|
transport.RacePlanCreateRequest:
|
|
properties:
|
|
count:
|
|
example: 0
|
|
type: integer
|
|
enabled:
|
|
example: true
|
|
type: boolean
|
|
id:
|
|
example: plan-1730000-1
|
|
type: string
|
|
interval_s:
|
|
example: 3600
|
|
type: integer
|
|
laps:
|
|
example: 10
|
|
type: integer
|
|
max_cars:
|
|
example: 4
|
|
type: integer
|
|
name:
|
|
example: Daily Monza
|
|
type: string
|
|
start_at_ms:
|
|
example: 1730000000000
|
|
type: integer
|
|
time_limit_s:
|
|
type: integer
|
|
track_id:
|
|
example: default
|
|
type: string
|
|
type: object
|
|
transport.RacePlanListResponse:
|
|
properties:
|
|
count:
|
|
type: integer
|
|
items:
|
|
items:
|
|
$ref: '#/definitions/transport.RacePlan'
|
|
type: array
|
|
next_cursor:
|
|
type: string
|
|
type: object
|
|
transport.RacePodiumEntry:
|
|
properties:
|
|
avatar_url:
|
|
type: string
|
|
clan_id:
|
|
example: clan-bob
|
|
type: string
|
|
driver_id:
|
|
example: driver-alice
|
|
type: string
|
|
name:
|
|
example: driver-alice
|
|
type: string
|
|
nickname:
|
|
example: driver-alice
|
|
type: string
|
|
position:
|
|
example: 1
|
|
type: integer
|
|
total_time_ms:
|
|
example: 123456
|
|
type: integer
|
|
type: object
|
|
transport.RaceQueueEntry:
|
|
properties:
|
|
driver_id:
|
|
example: driver-42
|
|
type: string
|
|
enqueued_ms:
|
|
example: 1730000000000
|
|
type: integer
|
|
plan_id:
|
|
example: plan-1730000-1
|
|
type: string
|
|
race_id:
|
|
example: race-1730000-7
|
|
type: string
|
|
type: object
|
|
transport.RaceQueueJoinRequest:
|
|
properties:
|
|
driver_id:
|
|
example: driver-42
|
|
type: string
|
|
limit:
|
|
example: 3
|
|
type: integer
|
|
type: object
|
|
transport.RaceQueueJoinResponse:
|
|
properties:
|
|
joined:
|
|
items:
|
|
$ref: '#/definitions/transport.RaceQueueEntry'
|
|
type: array
|
|
skipped:
|
|
example:
|
|
- race-1
|
|
- race-2
|
|
items:
|
|
type: string
|
|
type: array
|
|
type: object
|
|
transport.RaceQueueListResponse:
|
|
properties:
|
|
count:
|
|
type: integer
|
|
items:
|
|
items:
|
|
$ref: '#/definitions/transport.RaceQueueEntry'
|
|
type: array
|
|
type: object
|
|
transport.RaceUpcomingItem:
|
|
properties:
|
|
meta:
|
|
$ref: '#/definitions/transport.LobbyRace'
|
|
plan_id:
|
|
type: string
|
|
queue_len:
|
|
type: integer
|
|
start_at_ms:
|
|
type: integer
|
|
type: object
|
|
transport.RaceUpcomingResponse:
|
|
properties:
|
|
count:
|
|
type: integer
|
|
items:
|
|
items:
|
|
$ref: '#/definitions/transport.RaceUpcomingItem'
|
|
type: array
|
|
type: object
|
|
transport.TrackAck:
|
|
properties:
|
|
error:
|
|
type: string
|
|
id:
|
|
type: string
|
|
ok:
|
|
type: boolean
|
|
track:
|
|
$ref: '#/definitions/transport.TrackWire'
|
|
type: object
|
|
transport.TrackBounds:
|
|
properties:
|
|
length_m:
|
|
type: number
|
|
max_x:
|
|
type: number
|
|
max_y:
|
|
type: number
|
|
min_x:
|
|
type: number
|
|
min_y:
|
|
type: number
|
|
width_m:
|
|
type: number
|
|
type: object
|
|
transport.TrackCalendarCreateRequest:
|
|
properties:
|
|
end_at:
|
|
example: "2026-07-30T00:00:00Z"
|
|
type: string
|
|
start_at:
|
|
example: "2026-07-15T00:00:00Z"
|
|
type: string
|
|
track_id:
|
|
example: monaco
|
|
type: string
|
|
type: object
|
|
transport.TrackCalendarEntry:
|
|
properties:
|
|
end_at:
|
|
example: "2026-07-30T00:00:00Z"
|
|
type: string
|
|
id:
|
|
example: 1
|
|
type: integer
|
|
start_at:
|
|
example: "2026-07-15T00:00:00Z"
|
|
type: string
|
|
track_id:
|
|
example: monaco
|
|
type: string
|
|
type: object
|
|
transport.TrackCalendarLeaderboard:
|
|
properties:
|
|
current_driver:
|
|
$ref: '#/definitions/transport.LeaderboardEntry'
|
|
end_at:
|
|
example: "2026-07-30T00:00:00Z"
|
|
type: string
|
|
podium:
|
|
items:
|
|
$ref: '#/definitions/transport.LeaderboardEntry'
|
|
type: array
|
|
start_at:
|
|
example: "2026-07-15T00:00:00Z"
|
|
type: string
|
|
status:
|
|
example: active
|
|
type: string
|
|
track_id:
|
|
example: monaco
|
|
type: string
|
|
track_name:
|
|
example: Monaco
|
|
type: string
|
|
type: object
|
|
transport.TrackCalendarLeaderboardResponse:
|
|
properties:
|
|
items:
|
|
items:
|
|
$ref: '#/definitions/transport.TrackCalendarLeaderboard'
|
|
type: array
|
|
type: object
|
|
transport.TrackCalendarResponse:
|
|
properties:
|
|
items:
|
|
items:
|
|
$ref: '#/definitions/transport.TrackCalendarEntry'
|
|
type: array
|
|
type: object
|
|
transport.TrackCreateRequest:
|
|
properties:
|
|
track:
|
|
$ref: '#/definitions/transport.TrackWire'
|
|
type: object
|
|
transport.TrackPatch:
|
|
properties:
|
|
centerline:
|
|
items:
|
|
$ref: '#/definitions/transport.TrackWaypoint'
|
|
type: array
|
|
description:
|
|
type: string
|
|
lane_width_m:
|
|
type: number
|
|
length_m:
|
|
type: number
|
|
name:
|
|
type: string
|
|
scale:
|
|
type: integer
|
|
surface:
|
|
type: string
|
|
tags:
|
|
items:
|
|
type: string
|
|
type: array
|
|
visibility:
|
|
type: string
|
|
width_m:
|
|
type: number
|
|
type: object
|
|
transport.TrackUpdateRequest:
|
|
properties:
|
|
id:
|
|
type: string
|
|
patch:
|
|
$ref: '#/definitions/transport.TrackPatch'
|
|
type: object
|
|
transport.TrackWaypoint:
|
|
properties:
|
|
curvature:
|
|
type: number
|
|
heading_rad:
|
|
type: number
|
|
speed_ms:
|
|
type: number
|
|
x:
|
|
type: number
|
|
"y":
|
|
type: number
|
|
type: object
|
|
transport.TrackWire:
|
|
properties:
|
|
author_id:
|
|
type: string
|
|
best_lap_holder:
|
|
type: string
|
|
best_lap_ms:
|
|
type: integer
|
|
bounds:
|
|
$ref: '#/definitions/transport.TrackBounds'
|
|
centerline:
|
|
items:
|
|
$ref: '#/definitions/transport.TrackWaypoint'
|
|
type: array
|
|
created_ms:
|
|
type: integer
|
|
description:
|
|
type: string
|
|
id:
|
|
type: string
|
|
is_active:
|
|
example: true
|
|
type: boolean
|
|
lane_width_m:
|
|
type: number
|
|
length_m:
|
|
type: number
|
|
name:
|
|
type: string
|
|
scale:
|
|
type: integer
|
|
surface:
|
|
type: string
|
|
tags:
|
|
items:
|
|
type: string
|
|
type: array
|
|
updated_ms:
|
|
type: integer
|
|
visibility:
|
|
type: string
|
|
width_m:
|
|
type: number
|
|
type: object
|
|
transport.VersionResponse:
|
|
properties:
|
|
version:
|
|
example: 0.1.0-poc
|
|
type: string
|
|
type: object
|
|
transport.WebRTCConnectRequest:
|
|
properties:
|
|
driver_id:
|
|
example: driver-alice
|
|
type: string
|
|
sdp:
|
|
type: string
|
|
type:
|
|
example: offer
|
|
type: string
|
|
type: object
|
|
transport.WebRTCConnectResponse:
|
|
properties:
|
|
sdp:
|
|
type: string
|
|
type:
|
|
example: answer
|
|
type: string
|
|
type: object
|
|
host: localhost:8080
|
|
info:
|
|
contact:
|
|
name: x0gp
|
|
description: |-
|
|
Minimal HTTP+WebSocket server for the x0gp RC racing PoC. REST endpoints under /api/* manage the track/car catalog; /health and /stats expose server liveness and realtime metrics; /ws carries the realtime race protocol.
|
|
Auth is intentionally disabled in PoC mode (X0GP_DEV_MODE=true). All catalog mutations are allowed without a JWT.
|
|
license:
|
|
name: MIT
|
|
title: x0gp PoC server API
|
|
version: 0.1.0-poc
|
|
paths:
|
|
/api/cars:
|
|
get:
|
|
description: 'Returns all cars visible to the caller. Optional query filters:
|
|
`scope=system|public|private`, `owner_id=<string>`.'
|
|
parameters:
|
|
- description: Filter by visibility
|
|
enum:
|
|
- system
|
|
- public
|
|
- private
|
|
in: query
|
|
name: scope
|
|
type: string
|
|
- description: Filter by owner id
|
|
in: query
|
|
name: owner_id
|
|
type: string
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: List of cars with count
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: List cars
|
|
tags:
|
|
- cars
|
|
post:
|
|
consumes:
|
|
- application/json
|
|
description: Creates a new car. The server fills `id` if the client sends an
|
|
empty one. `owner_id` should be the caller's id in production (auth is disabled
|
|
in PoC).
|
|
parameters:
|
|
- description: Car to create
|
|
in: body
|
|
name: car
|
|
required: true
|
|
schema:
|
|
$ref: '#/definitions/transport.CarCreateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"201":
|
|
description: Created
|
|
schema:
|
|
$ref: '#/definitions/transport.CarAck'
|
|
"400":
|
|
description: Invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"409":
|
|
description: Car id already exists
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Create a car
|
|
tags:
|
|
- cars
|
|
/api/cars/{id}:
|
|
delete:
|
|
description: Dispatches on HTTP method. The id is taken from the URL path (`/api/cars/{id}`).
|
|
System cars are immutable and cannot be updated or deleted.
|
|
parameters:
|
|
- description: Car id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: car
|
|
schema:
|
|
$ref: '#/definitions/transport.CarUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Car payload (GET) or update ack (PUT)
|
|
schema:
|
|
$ref: '#/definitions/transport.CarWire'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.CarAck'
|
|
"400":
|
|
description: Bad request / invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"403":
|
|
description: System car is immutable
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Car not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"409":
|
|
description: Car id already exists
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a car by id
|
|
tags:
|
|
- cars
|
|
get:
|
|
description: Dispatches on HTTP method. The id is taken from the URL path (`/api/cars/{id}`).
|
|
System cars are immutable and cannot be updated or deleted.
|
|
parameters:
|
|
- description: Car id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: car
|
|
schema:
|
|
$ref: '#/definitions/transport.CarUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Car payload (GET) or update ack (PUT)
|
|
schema:
|
|
$ref: '#/definitions/transport.CarWire'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.CarAck'
|
|
"400":
|
|
description: Bad request / invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"403":
|
|
description: System car is immutable
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Car not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"409":
|
|
description: Car id already exists
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a car by id
|
|
tags:
|
|
- cars
|
|
put:
|
|
description: Dispatches on HTTP method. The id is taken from the URL path (`/api/cars/{id}`).
|
|
System cars are immutable and cannot be updated or deleted.
|
|
parameters:
|
|
- description: Car id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: car
|
|
schema:
|
|
$ref: '#/definitions/transport.CarUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Car payload (GET) or update ack (PUT)
|
|
schema:
|
|
$ref: '#/definitions/transport.CarWire'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.CarAck'
|
|
"400":
|
|
description: Bad request / invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"403":
|
|
description: System car is immutable
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Car not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"409":
|
|
description: Car id already exists
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a car by id
|
|
tags:
|
|
- cars
|
|
/api/catalog:
|
|
get:
|
|
description: 'Returns the full in-memory catalog: all tracks, all cars, and
|
|
aggregate counters. This is the cheapest way for a UI to bootstrap its initial
|
|
state.'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Snapshot of tracks, cars and summary counters
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Combined catalog snapshot
|
|
tags:
|
|
- catalog
|
|
/api/clans:
|
|
get:
|
|
description: Returns clans ordered by tag. Limit 1..200, default 50.
|
|
parameters:
|
|
- description: Page size
|
|
in: query
|
|
name: limit
|
|
type: integer
|
|
- description: Page offset
|
|
in: query
|
|
name: offset
|
|
type: integer
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Page of clans
|
|
schema:
|
|
$ref: '#/definitions/transport.ClanListResponse'
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: List clans
|
|
tags:
|
|
- clans
|
|
post:
|
|
consumes:
|
|
- application/json
|
|
description: Creates a new clan. `tag` must be exactly 3 uppercase ASCII letters
|
|
(e.g. "ACE") and unique.
|
|
parameters:
|
|
- description: Clan to create
|
|
in: body
|
|
name: clan
|
|
required: true
|
|
schema:
|
|
$ref: '#/definitions/transport.ClanCreateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"201":
|
|
description: Created clan
|
|
schema:
|
|
$ref: '#/definitions/transport.Clan'
|
|
"400":
|
|
description: Invalid input (tag must be 3 uppercase letters)
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"409":
|
|
description: Clan with that tag already exists
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Create a clan
|
|
tags:
|
|
- clans
|
|
/api/clans/{id}:
|
|
delete:
|
|
description: Dispatches on HTTP method.
|
|
parameters:
|
|
- description: Clan id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: clan
|
|
schema:
|
|
$ref: '#/definitions/transport.ClanUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Clan payload or update result
|
|
schema:
|
|
$ref: '#/definitions/transport.Clan'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.Clan'
|
|
"400":
|
|
description: Bad request
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Clan not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a clan by id
|
|
tags:
|
|
- clans
|
|
get:
|
|
description: Dispatches on HTTP method.
|
|
parameters:
|
|
- description: Clan id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: clan
|
|
schema:
|
|
$ref: '#/definitions/transport.ClanUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Clan payload or update result
|
|
schema:
|
|
$ref: '#/definitions/transport.Clan'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.Clan'
|
|
"400":
|
|
description: Bad request
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Clan not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a clan by id
|
|
tags:
|
|
- clans
|
|
put:
|
|
description: Dispatches on HTTP method.
|
|
parameters:
|
|
- description: Clan id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: clan
|
|
schema:
|
|
$ref: '#/definitions/transport.ClanUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Clan payload or update result
|
|
schema:
|
|
$ref: '#/definitions/transport.Clan'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.Clan'
|
|
"400":
|
|
description: Bad request
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Clan not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a clan by id
|
|
tags:
|
|
- clans
|
|
/api/drivers:
|
|
get:
|
|
description: Returns drivers ordered by nickname. Optional `clan_id` filter.
|
|
parameters:
|
|
- description: Page size
|
|
in: query
|
|
name: limit
|
|
type: integer
|
|
- description: Page offset
|
|
in: query
|
|
name: offset
|
|
type: integer
|
|
- description: Filter by clan id
|
|
in: query
|
|
name: clan_id
|
|
type: string
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Page of drivers
|
|
schema:
|
|
$ref: '#/definitions/transport.DriverListResponse'
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: List drivers
|
|
tags:
|
|
- drivers
|
|
post:
|
|
consumes:
|
|
- application/json
|
|
description: Creates a new driver. `nickname` must be exactly 3 uppercase ASCII
|
|
letters (e.g. "ACE") and unique. `clan_id` is optional and must reference
|
|
an existing clan.
|
|
parameters:
|
|
- description: Driver to create
|
|
in: body
|
|
name: driver
|
|
required: true
|
|
schema:
|
|
$ref: '#/definitions/transport.DriverCreateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"201":
|
|
description: Created driver
|
|
schema:
|
|
$ref: '#/definitions/transport.Driver'
|
|
"400":
|
|
description: Invalid input (nickname must be 3 uppercase letters)
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"409":
|
|
description: Driver with that nickname already exists
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Create a driver
|
|
tags:
|
|
- drivers
|
|
/api/drivers/{id}:
|
|
delete:
|
|
description: Dispatches on HTTP method. Path `/api/drivers/by-nick/{nick}` is
|
|
a convenience that returns the driver by 3-letter nickname.
|
|
parameters:
|
|
- description: Driver id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: driver
|
|
schema:
|
|
$ref: '#/definitions/transport.DriverUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Driver payload or update result
|
|
schema:
|
|
$ref: '#/definitions/transport.Driver'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.Driver'
|
|
"400":
|
|
description: Bad request
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Driver not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a driver by id
|
|
tags:
|
|
- drivers
|
|
get:
|
|
description: Dispatches on HTTP method. Path `/api/drivers/by-nick/{nick}` is
|
|
a convenience that returns the driver by 3-letter nickname.
|
|
parameters:
|
|
- description: Driver id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: driver
|
|
schema:
|
|
$ref: '#/definitions/transport.DriverUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Driver payload or update result
|
|
schema:
|
|
$ref: '#/definitions/transport.Driver'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.Driver'
|
|
"400":
|
|
description: Bad request
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Driver not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a driver by id
|
|
tags:
|
|
- drivers
|
|
put:
|
|
description: Dispatches on HTTP method. Path `/api/drivers/by-nick/{nick}` is
|
|
a convenience that returns the driver by 3-letter nickname.
|
|
parameters:
|
|
- description: Driver id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: driver
|
|
schema:
|
|
$ref: '#/definitions/transport.DriverUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Driver payload or update result
|
|
schema:
|
|
$ref: '#/definitions/transport.Driver'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.Driver'
|
|
"400":
|
|
description: Bad request
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Driver not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a driver by id
|
|
tags:
|
|
- drivers
|
|
/api/drivers/{id}/device:
|
|
put:
|
|
description: Dispatches on HTTP method. Path `/api/drivers/by-nick/{nick}` is
|
|
a convenience that returns the driver by 3-letter nickname.
|
|
parameters:
|
|
- description: Driver id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: driver
|
|
schema:
|
|
$ref: '#/definitions/transport.DriverUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Driver payload or update result
|
|
schema:
|
|
$ref: '#/definitions/transport.Driver'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.Driver'
|
|
"400":
|
|
description: Bad request
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Driver not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a driver by id
|
|
tags:
|
|
- drivers
|
|
/api/leaderboard:
|
|
get:
|
|
description: Returns paginated leaderboard list. Supports overall leaderboard
|
|
or track-specific leaderboard for the current year.
|
|
parameters:
|
|
- description: Track ID. If empty, returns overall leaderboard.
|
|
in: query
|
|
name: track_id
|
|
type: string
|
|
- description: Year. Defaults to current year.
|
|
in: query
|
|
name: year
|
|
type: integer
|
|
- description: Limit (1..200, default 50)
|
|
in: query
|
|
name: limit
|
|
type: integer
|
|
- description: Offset (default 0)
|
|
in: query
|
|
name: offset
|
|
type: integer
|
|
- description: Current driver ID. Defaults to driver-seed-001 (mock Alice).
|
|
in: header
|
|
name: X-Driver-Id
|
|
type: string
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Leaderboard page and current driver position
|
|
schema:
|
|
$ref: '#/definitions/transport.LeaderboardResponse'
|
|
"400":
|
|
description: Invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Leaderboard
|
|
tags:
|
|
- leaderboard
|
|
/api/leaderboard/tracks:
|
|
get:
|
|
description: Returns the list of scheduled tracks with their status (finished/active/planned),
|
|
top 3 drivers, and current driver position, sorted by calendar start date.
|
|
parameters:
|
|
- description: Year. Defaults to current year.
|
|
in: query
|
|
name: year
|
|
type: integer
|
|
- description: Current driver ID. Defaults to driver-seed-001 (mock Alice).
|
|
in: header
|
|
name: X-Driver-Id
|
|
type: string
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Calendar leaderboards list
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackCalendarLeaderboardResponse'
|
|
"400":
|
|
description: Invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Track Calendar Leaderboards
|
|
tags:
|
|
- leaderboard
|
|
/api/races:
|
|
get:
|
|
description: |-
|
|
Returns one keyset page of races. Live races (status lobby|racing) come from in-memory lobby.Service; finished races come from Postgres. The two sources are merged and ordered by (started_ms DESC, id ASC). The cursor is opaque: pass back the next_cursor verbatim from a previous page.
|
|
## Filters
|
|
- `status` (comma-separated, e.g. "racing,finished"). Recognised values: all, lobby, racing, finished.
|
|
- `track_id` (exact match against a physical track id; custom lobbies are not supported in this build).
|
|
- `limit` (1..200, default 50)
|
|
parameters:
|
|
- description: Comma-separated status filter
|
|
enum:
|
|
- all
|
|
- lobby
|
|
- racing
|
|
- finished
|
|
in: query
|
|
name: status
|
|
type: string
|
|
- description: Filter by physical track id
|
|
in: query
|
|
name: track_id
|
|
type: string
|
|
- description: Opaque keyset cursor (next_cursor from previous page)
|
|
in: query
|
|
name: cursor
|
|
type: string
|
|
- description: Page size (1..200, default 50)
|
|
in: query
|
|
name: limit
|
|
type: integer
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Page of races
|
|
schema:
|
|
$ref: '#/definitions/transport.RaceListResponse'
|
|
"400":
|
|
description: Bad request / invalid cursor / invalid status
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: List races (keyset paginated)
|
|
tags:
|
|
- races
|
|
/api/races/plans:
|
|
get:
|
|
description: Returns race plans in ascending start_at order. Pass back the `next_cursor`
|
|
to get the next page.
|
|
parameters:
|
|
- description: Opaque keyset cursor
|
|
in: query
|
|
name: cursor
|
|
type: string
|
|
- description: Page size (default 50)
|
|
in: query
|
|
name: limit
|
|
type: integer
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Page of plans
|
|
schema:
|
|
$ref: '#/definitions/transport.RacePlanListResponse'
|
|
"400":
|
|
description: Invalid cursor
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: List race plans (keyset paginated)
|
|
tags:
|
|
- plans
|
|
post:
|
|
consumes:
|
|
- application/json
|
|
description: Creates a recurring or one-off scheduled race. The scheduler materialises
|
|
a lobby race when `next_fire_ms` <= now. If `interval_s` > 0 the plan repeats;
|
|
if `count` > 0 the plan disables itself after that many fires.
|
|
parameters:
|
|
- description: Plan to create
|
|
in: body
|
|
name: plan
|
|
required: true
|
|
schema:
|
|
$ref: '#/definitions/transport.RacePlanCreateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"201":
|
|
description: Created plan
|
|
schema:
|
|
$ref: '#/definitions/transport.RacePlan'
|
|
"400":
|
|
description: Invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"409":
|
|
description: Plan id already exists
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Create a race plan
|
|
tags:
|
|
- plans
|
|
/api/races/plans/{id}:
|
|
delete:
|
|
description: Removes a plan by id. Materialised races already in the lobby are
|
|
not affected.
|
|
parameters:
|
|
- description: Plan id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: ok
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Plan not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Delete a race plan
|
|
tags:
|
|
- plans
|
|
/api/races/queue:
|
|
delete:
|
|
description: Removes a single (driver, race) entry from the queue. Does not
|
|
detach the driver from the race if already joined.
|
|
parameters:
|
|
- description: Driver id
|
|
in: header
|
|
name: X-Driver-Id
|
|
type: string
|
|
- description: Driver id
|
|
in: query
|
|
name: driver_id
|
|
type: string
|
|
- description: Race id
|
|
in: query
|
|
name: race_id
|
|
required: true
|
|
type: string
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: ok
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"400":
|
|
description: driver_id and race_id required
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: queue entry not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Leave a queue entry
|
|
tags:
|
|
- races
|
|
get:
|
|
description: Returns the queue entries for a driver, oldest first.
|
|
parameters:
|
|
- description: Driver id
|
|
in: header
|
|
name: X-Driver-Id
|
|
type: string
|
|
- description: Driver id (alternative to header)
|
|
in: query
|
|
name: driver_id
|
|
type: string
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Queue entries
|
|
schema:
|
|
$ref: '#/definitions/transport.RaceQueueListResponse'
|
|
"400":
|
|
description: driver_id required
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: List driver's queue entries
|
|
tags:
|
|
- races
|
|
/api/races/queue/join:
|
|
post:
|
|
consumes:
|
|
- application/json
|
|
description: Puts the driver in the queue for each of the next N (default 3)
|
|
lobby|countdown races, soonest first. If a race has a free slot, the driver
|
|
is also attached to it (best effort). Idempotent per (driver, race).
|
|
parameters:
|
|
- description: Driver id (alternative to body)
|
|
in: header
|
|
name: X-Driver-Id
|
|
type: string
|
|
- description: Driver id and optional limit
|
|
in: body
|
|
name: body
|
|
schema:
|
|
$ref: '#/definitions/transport.RaceQueueJoinRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Queue entries created
|
|
schema:
|
|
$ref: '#/definitions/transport.RaceQueueJoinResponse'
|
|
"400":
|
|
description: driver_id required
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Enqueue driver on next N upcoming races
|
|
tags:
|
|
- races
|
|
/api/races/upcoming:
|
|
get:
|
|
description: Returns up to `limit` races currently in status lobby|countdown,
|
|
ordered soonest first. Useful for the "join queue" UI and dashboard.
|
|
parameters:
|
|
- description: Number of races to return (1..16, default 3)
|
|
in: query
|
|
name: limit
|
|
type: integer
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Upcoming races
|
|
schema:
|
|
$ref: '#/definitions/transport.RaceUpcomingResponse'
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Next N upcoming races
|
|
tags:
|
|
- races
|
|
/api/tracks:
|
|
get:
|
|
description: 'Returns all tracks visible to the caller. Optional query filters:
|
|
`scope=system|public|private`, `tag=<string>`.'
|
|
parameters:
|
|
- description: Filter by visibility
|
|
enum:
|
|
- system
|
|
- public
|
|
- private
|
|
in: query
|
|
name: scope
|
|
type: string
|
|
- description: Filter by tag (case-insensitive)
|
|
in: query
|
|
name: tag
|
|
type: string
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: List of tracks with count
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: List tracks
|
|
tags:
|
|
- tracks
|
|
post:
|
|
consumes:
|
|
- application/json
|
|
description: Creates a new track. The server fills `id` if the client sends
|
|
an empty one. `author_id` should be the caller's id in production (auth is
|
|
disabled in PoC).
|
|
parameters:
|
|
- description: Track to create
|
|
in: body
|
|
name: track
|
|
required: true
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackCreateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"201":
|
|
description: Created
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackAck'
|
|
"400":
|
|
description: Invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"409":
|
|
description: Track id already exists
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Create a track
|
|
tags:
|
|
- tracks
|
|
/api/tracks/{id}:
|
|
delete:
|
|
description: Dispatches on HTTP method. The id is taken from the URL path (`/api/tracks/{id}`).
|
|
System tracks are immutable and cannot be updated or deleted.
|
|
parameters:
|
|
- description: Track id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: track
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Track payload (GET) or update ack (PUT)
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackWire'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackAck'
|
|
"400":
|
|
description: Bad request / invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"403":
|
|
description: System track is immutable
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Track not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"409":
|
|
description: Track id already exists
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a track by id
|
|
tags:
|
|
- tracks
|
|
get:
|
|
description: Dispatches on HTTP method. The id is taken from the URL path (`/api/tracks/{id}`).
|
|
System tracks are immutable and cannot be updated or deleted.
|
|
parameters:
|
|
- description: Track id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: track
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Track payload (GET) or update ack (PUT)
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackWire'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackAck'
|
|
"400":
|
|
description: Bad request / invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"403":
|
|
description: System track is immutable
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Track not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"409":
|
|
description: Track id already exists
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a track by id
|
|
tags:
|
|
- tracks
|
|
put:
|
|
description: Dispatches on HTTP method. The id is taken from the URL path (`/api/tracks/{id}`).
|
|
System tracks are immutable and cannot be updated or deleted.
|
|
parameters:
|
|
- description: Track id
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: string
|
|
- description: Patch payload (only for PUT)
|
|
in: body
|
|
name: track
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackUpdateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Track payload (GET) or update ack (PUT)
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackWire'
|
|
"204":
|
|
description: Delete ack
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackAck'
|
|
"400":
|
|
description: Bad request / invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"403":
|
|
description: System track is immutable
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Track not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"409":
|
|
description: Track id already exists
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal server error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get / update / delete a track by id
|
|
tags:
|
|
- tracks
|
|
/api/tracks/calendar:
|
|
get:
|
|
description: Returns the full calendar of track active periods.
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: List of scheduled active periods
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackCalendarResponse'
|
|
"500":
|
|
description: Internal error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Get Track Calendar
|
|
tags:
|
|
- tracks
|
|
post:
|
|
consumes:
|
|
- application/json
|
|
description: Schedules an active period for a physical track.
|
|
parameters:
|
|
- description: Calendar entry details
|
|
in: body
|
|
name: payload
|
|
required: true
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackCalendarCreateRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"201":
|
|
description: Created calendar entry
|
|
schema:
|
|
$ref: '#/definitions/transport.TrackCalendarEntry'
|
|
"400":
|
|
description: Invalid input
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"404":
|
|
description: Track not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Schedule Track Active Period
|
|
tags:
|
|
- tracks
|
|
/api/tracks/calendar/{id}:
|
|
delete:
|
|
description: Deletes a scheduled active period by ID.
|
|
parameters:
|
|
- description: Calendar Entry ID
|
|
in: path
|
|
name: id
|
|
required: true
|
|
type: integer
|
|
responses:
|
|
"204":
|
|
description: No Content
|
|
"404":
|
|
description: Not found
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"500":
|
|
description: Internal error
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Delete Scheduled Period
|
|
tags:
|
|
- tracks
|
|
/api/version:
|
|
get:
|
|
description: Returns the current server version.
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Success
|
|
schema:
|
|
$ref: '#/definitions/transport.VersionResponse'
|
|
summary: Get server version
|
|
tags:
|
|
- system
|
|
/api/video/control:
|
|
post:
|
|
description: Sends a text command (e.g. start, stop, left, right) to the ESP32
|
|
command port (UDP 8888).
|
|
parameters:
|
|
- description: Device ID (0..127)
|
|
in: query
|
|
name: id
|
|
type: integer
|
|
- description: Command text
|
|
in: query
|
|
name: cmd
|
|
required: true
|
|
type: string
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Command sent
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
"400":
|
|
description: Missing cmd parameter
|
|
schema:
|
|
type: string
|
|
"500":
|
|
description: Internal error
|
|
schema:
|
|
type: string
|
|
summary: Send command to ESP32
|
|
tags:
|
|
- video
|
|
/api/video/stream:
|
|
get:
|
|
description: Streams video frames received via UDP as multipart/x-mixed-replace.
|
|
Suitable for raw img tags in browser.
|
|
parameters:
|
|
- description: Device ID (0..127)
|
|
in: query
|
|
name: id
|
|
type: integer
|
|
produces:
|
|
- multipart/x-mixed-replace
|
|
responses:
|
|
"200":
|
|
description: MJPEG stream
|
|
schema:
|
|
type: string
|
|
summary: Get MJPEG video stream from ESP32
|
|
tags:
|
|
- video
|
|
/api/webrtc/connect:
|
|
post:
|
|
consumes:
|
|
- application/json
|
|
description: Accepts SDP Offer, negotiates peer connection, and returns SDP
|
|
Answer. Routes video and control data via DataChannels.
|
|
parameters:
|
|
- description: SDP Offer details
|
|
in: body
|
|
name: body
|
|
required: true
|
|
schema:
|
|
$ref: '#/definitions/transport.WebRTCConnectRequest'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: SDP Answer negotiation success
|
|
schema:
|
|
$ref: '#/definitions/transport.WebRTCConnectResponse'
|
|
summary: Establish WebRTC connection for driver-car 1-to-1 proxying
|
|
tags:
|
|
- webrtc
|
|
/health:
|
|
get:
|
|
description: Returns 200 OK with current engine phase, WS connection count and
|
|
total snapshot drops. Intended for load-balancer health checks.
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Server is up
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Liveness probe
|
|
tags:
|
|
- system
|
|
/stats:
|
|
get:
|
|
description: 'Returns the current race phase plus realtime counters: active
|
|
WS connections and total snapshots dropped due to slow consumers.'
|
|
produces:
|
|
- application/json
|
|
responses:
|
|
"200":
|
|
description: Runtime counters
|
|
schema:
|
|
additionalProperties: true
|
|
type: object
|
|
summary: Realtime runtime stats
|
|
tags:
|
|
- system
|
|
/ws:
|
|
get:
|
|
description: |-
|
|
Opens a bidirectional WebSocket for the realtime race protocol. The server replies with `server_hello`, then broadcasts `race_snapshot` frames at `X0GP_SNAPSHOT_HZ`.
|
|
## Frame format
|
|
Every frame is a JSON envelope of the form:
|
|
```json
|
|
{ "type": "<message_type>", "seq": 42, "ts_ms": 1700000000000, "payload": { ... } }
|
|
```
|
|
`type` discriminates the payload; `payload` is documented per message type in the schemas listed in `components/schemas` (see `Envelope`, `ClientHello`, `ServerHello`, `InputState`, `JoinRace`, `LeaveRace`, `RaceSnapshot`, `InputAck`, `RaceEvent`, `Ping`, `Pong`, `ErrorMsg`, plus the catalog/lobby/stats envelopes).
|
|
## Client -> Server
|
|
- `client_hello` — first frame after connect. Sent once.
|
|
- `join_race` / `leave_race` — join or leave the race session.
|
|
- `input_state` — high-rate control (steering/throttle/brake/gear). Send at 60-120 Hz.
|
|
- `ping` — round-trip time probe.
|
|
- `track_*` / `car_*` — catalog CRUD (mirror of the REST /api/* endpoints).
|
|
- `lobby_*` — lobby management.
|
|
- `stats_request` — ask for a stats snapshot.
|
|
## Server -> Client
|
|
- `server_hello` — handshake reply; includes session id and engine config.
|
|
- `race_snapshot` — periodic authoritative state broadcast.
|
|
- `input_ack` — per-input acknowledgement (optional; drop-tolerant).
|
|
- `race_event` — start/lap/sector/dnf/finish.
|
|
- `track_snapshot` / `car_snapshot` / `catalog_summary` — catalog feeds on change.
|
|
- `lobby_snapshot` — full lobby state on change.
|
|
- `stats_snapshot` / `race_standings` / `lap_recorded` / `race_result` — stats feeds.
|
|
- `error` — protocol or validation error.
|
|
## Notes
|
|
- Origin checks are disabled in PoC mode (`CheckOrigin: always-allow`).
|
|
- Ping interval: 20 s. Pong wait: 60 s. Max frame size: 8 KiB.
|
|
- Input acks are best-effort and silently dropped under load.
|
|
responses:
|
|
"101":
|
|
description: Switching protocols. Subsequent frames follow the envelope
|
|
schema.
|
|
schema:
|
|
$ref: '#/definitions/transport.Envelope'
|
|
summary: WebSocket endpoint (binary JSON envelope protocol)
|
|
tags:
|
|
- websocket
|
|
schemes:
|
|
- http
|
|
- ws
|
|
swagger: "2.0"
|