Add leaderboard for all tracks and track calendar

This commit is contained in:
2026-07-15 11:53:35 +04:00
parent 4a894a4399
commit a56841237d
20 changed files with 1394 additions and 25 deletions
+263
View File
@@ -1078,6 +1078,54 @@ const docTemplate = `{
}
}
},
"/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.",
"produces": [
"application/json"
],
"tags": [
"leaderboard"
],
"summary": "Track Calendar Leaderboards",
"parameters": [
{
"type": "integer",
"description": "Year. Defaults to current year.",
"name": "year",
"in": "query"
},
{
"type": "string",
"description": "Current driver ID. Defaults to driver-seed-001 (mock Alice).",
"name": "X-Driver-Id",
"in": "header"
}
],
"responses": {
"200": {
"description": "Calendar leaderboards list",
"schema": {
"$ref": "#/definitions/transport.TrackCalendarLeaderboardResponse"
}
},
"400": {
"description": "Invalid input",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal server error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/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.\n## Filters\n- ` + "`" + `status` + "`" + ` (comma-separated, e.g. \"racing,finished\"). Recognised values: all, lobby, racing, finished.\n- ` + "`" + `track_id` + "`" + ` (exact match against a physical track id; custom lobbies are not supported in this build).\n- ` + "`" + `limit` + "`" + ` (1..200, default 50)",
@@ -1586,6 +1634,123 @@ const docTemplate = `{
}
}
},
"/api/tracks/calendar": {
"get": {
"description": "Returns the full calendar of track active periods.",
"produces": [
"application/json"
],
"tags": [
"tracks"
],
"summary": "Get Track Calendar",
"responses": {
"200": {
"description": "List of scheduled active periods",
"schema": {
"$ref": "#/definitions/transport.TrackCalendarResponse"
}
},
"500": {
"description": "Internal error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
},
"post": {
"description": "Schedules an active period for a physical track.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"tracks"
],
"summary": "Schedule Track Active Period",
"parameters": [
{
"description": "Calendar entry details",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/transport.TrackCalendarCreateRequest"
}
}
],
"responses": {
"201": {
"description": "Created calendar entry",
"schema": {
"$ref": "#/definitions/transport.TrackCalendarEntry"
}
},
"400": {
"description": "Invalid input",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"404": {
"description": "Track not found",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/api/tracks/calendar/{id}": {
"delete": {
"description": "Deletes a scheduled active period by ID.",
"tags": [
"tracks"
],
"summary": "Delete Scheduled Period",
"parameters": [
{
"type": "integer",
"description": "Calendar Entry ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"description": "No Content"
},
"404": {
"description": "Not found",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/api/tracks/{id}": {
"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.",
@@ -2913,6 +3078,100 @@ const docTemplate = `{
}
}
},
"transport.TrackCalendarCreateRequest": {
"type": "object",
"properties": {
"end_at": {
"type": "string",
"example": "2026-07-30T00:00:00Z"
},
"start_at": {
"type": "string",
"example": "2026-07-15T00:00:00Z"
},
"track_id": {
"type": "string",
"example": "monaco"
}
}
},
"transport.TrackCalendarEntry": {
"type": "object",
"properties": {
"end_at": {
"type": "string",
"example": "2026-07-30T00:00:00Z"
},
"id": {
"type": "integer",
"example": 1
},
"start_at": {
"type": "string",
"example": "2026-07-15T00:00:00Z"
},
"track_id": {
"type": "string",
"example": "monaco"
}
}
},
"transport.TrackCalendarLeaderboard": {
"type": "object",
"properties": {
"current_driver": {
"$ref": "#/definitions/transport.LeaderboardEntry"
},
"end_at": {
"type": "string",
"example": "2026-07-30T00:00:00Z"
},
"podium": {
"type": "array",
"items": {
"$ref": "#/definitions/transport.LeaderboardEntry"
}
},
"start_at": {
"type": "string",
"example": "2026-07-15T00:00:00Z"
},
"status": {
"type": "string",
"example": "active"
},
"track_id": {
"type": "string",
"example": "monaco"
},
"track_name": {
"type": "string",
"example": "Monaco"
}
}
},
"transport.TrackCalendarLeaderboardResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/transport.TrackCalendarLeaderboard"
}
}
}
},
"transport.TrackCalendarResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/transport.TrackCalendarEntry"
}
}
}
},
"transport.TrackCreateRequest": {
"type": "object",
"properties": {
@@ -3023,6 +3282,10 @@ const docTemplate = `{
"id": {
"type": "string"
},
"is_active": {
"type": "boolean",
"example": true
},
"lane_width_m": {
"type": "number"
},
+263
View File
@@ -1076,6 +1076,54 @@
}
}
},
"/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.",
"produces": [
"application/json"
],
"tags": [
"leaderboard"
],
"summary": "Track Calendar Leaderboards",
"parameters": [
{
"type": "integer",
"description": "Year. Defaults to current year.",
"name": "year",
"in": "query"
},
{
"type": "string",
"description": "Current driver ID. Defaults to driver-seed-001 (mock Alice).",
"name": "X-Driver-Id",
"in": "header"
}
],
"responses": {
"200": {
"description": "Calendar leaderboards list",
"schema": {
"$ref": "#/definitions/transport.TrackCalendarLeaderboardResponse"
}
},
"400": {
"description": "Invalid input",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal server error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/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.\n## Filters\n- `status` (comma-separated, e.g. \"racing,finished\"). Recognised values: all, lobby, racing, finished.\n- `track_id` (exact match against a physical track id; custom lobbies are not supported in this build).\n- `limit` (1..200, default 50)",
@@ -1584,6 +1632,123 @@
}
}
},
"/api/tracks/calendar": {
"get": {
"description": "Returns the full calendar of track active periods.",
"produces": [
"application/json"
],
"tags": [
"tracks"
],
"summary": "Get Track Calendar",
"responses": {
"200": {
"description": "List of scheduled active periods",
"schema": {
"$ref": "#/definitions/transport.TrackCalendarResponse"
}
},
"500": {
"description": "Internal error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
},
"post": {
"description": "Schedules an active period for a physical track.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"tracks"
],
"summary": "Schedule Track Active Period",
"parameters": [
{
"description": "Calendar entry details",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/transport.TrackCalendarCreateRequest"
}
}
],
"responses": {
"201": {
"description": "Created calendar entry",
"schema": {
"$ref": "#/definitions/transport.TrackCalendarEntry"
}
},
"400": {
"description": "Invalid input",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"404": {
"description": "Track not found",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/api/tracks/calendar/{id}": {
"delete": {
"description": "Deletes a scheduled active period by ID.",
"tags": [
"tracks"
],
"summary": "Delete Scheduled Period",
"parameters": [
{
"type": "integer",
"description": "Calendar Entry ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"description": "No Content"
},
"404": {
"description": "Not found",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/api/tracks/{id}": {
"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.",
@@ -2911,6 +3076,100 @@
}
}
},
"transport.TrackCalendarCreateRequest": {
"type": "object",
"properties": {
"end_at": {
"type": "string",
"example": "2026-07-30T00:00:00Z"
},
"start_at": {
"type": "string",
"example": "2026-07-15T00:00:00Z"
},
"track_id": {
"type": "string",
"example": "monaco"
}
}
},
"transport.TrackCalendarEntry": {
"type": "object",
"properties": {
"end_at": {
"type": "string",
"example": "2026-07-30T00:00:00Z"
},
"id": {
"type": "integer",
"example": 1
},
"start_at": {
"type": "string",
"example": "2026-07-15T00:00:00Z"
},
"track_id": {
"type": "string",
"example": "monaco"
}
}
},
"transport.TrackCalendarLeaderboard": {
"type": "object",
"properties": {
"current_driver": {
"$ref": "#/definitions/transport.LeaderboardEntry"
},
"end_at": {
"type": "string",
"example": "2026-07-30T00:00:00Z"
},
"podium": {
"type": "array",
"items": {
"$ref": "#/definitions/transport.LeaderboardEntry"
}
},
"start_at": {
"type": "string",
"example": "2026-07-15T00:00:00Z"
},
"status": {
"type": "string",
"example": "active"
},
"track_id": {
"type": "string",
"example": "monaco"
},
"track_name": {
"type": "string",
"example": "Monaco"
}
}
},
"transport.TrackCalendarLeaderboardResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/transport.TrackCalendarLeaderboard"
}
}
}
},
"transport.TrackCalendarResponse": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/transport.TrackCalendarEntry"
}
}
}
},
"transport.TrackCreateRequest": {
"type": "object",
"properties": {
@@ -3021,6 +3280,10 @@
"id": {
"type": "string"
},
"is_active": {
"type": "boolean",
"example": true
},
"lane_width_m": {
"type": "number"
},
+180
View File
@@ -644,6 +644,71 @@ definitions:
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:
@@ -716,6 +781,9 @@ definitions:
type: string
id:
type: string
is_active:
example: true
type: boolean
lane_width_m:
type: number
length_m:
@@ -1505,6 +1573,39 @@ paths:
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: |-
@@ -2024,6 +2125,85 @@ paths:
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.