Implement leaderboard service and POC HTTP handlers with Swagger documentation

This commit is contained in:
2026-07-15 11:29:19 +04:00
parent c25e0bc581
commit 4a894a4399
10 changed files with 1300 additions and 3 deletions
+138
View File
@@ -1012,6 +1012,72 @@ const docTemplate = `{
}
}
},
"/api/leaderboard": {
"get": {
"description": "Returns paginated leaderboard list. Supports overall leaderboard or track-specific leaderboard for the current year.",
"produces": [
"application/json"
],
"tags": [
"leaderboard"
],
"summary": "Leaderboard",
"parameters": [
{
"type": "string",
"description": "Track ID. If empty, returns overall leaderboard.",
"name": "track_id",
"in": "query"
},
{
"type": "integer",
"description": "Year. Defaults to current year.",
"name": "year",
"in": "query"
},
{
"type": "integer",
"description": "Limit (1..200, default 50)",
"name": "limit",
"in": "query"
},
{
"type": "integer",
"description": "Offset (default 0)",
"name": "offset",
"in": "query"
},
{
"type": "string",
"description": "Current driver ID. Defaults to driver-seed-001 (mock Alice).",
"name": "X-Driver-Id",
"in": "header"
}
],
"responses": {
"200": {
"description": "Leaderboard page and current driver position",
"schema": {
"$ref": "#/definitions/transport.LeaderboardResponse"
}
},
"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)",
@@ -2315,6 +2381,78 @@ const docTemplate = `{
}
}
},
"transport.LeaderboardEntry": {
"type": "object",
"properties": {
"avatar_url": {
"type": "string",
"example": "https://cdn.example.com/u/ace.png"
},
"best_pos": {
"description": "Only populated for track-specific leaderboard",
"type": "integer",
"example": 1
},
"best_time_ms": {
"type": "integer",
"example": 15000
},
"clan_id": {
"type": "string",
"example": "clan-seed-001"
},
"clan_tag": {
"type": "string",
"example": "ACE"
},
"driver_id": {
"type": "string",
"example": "driver-seed-001"
},
"name": {
"type": "string",
"example": "Alice"
},
"nickname": {
"type": "string",
"example": "ACE"
},
"points": {
"type": "integer",
"example": 25
},
"rank": {
"type": "integer",
"example": 1
}
}
},
"transport.LeaderboardResponse": {
"type": "object",
"properties": {
"current_driver": {
"$ref": "#/definitions/transport.LeaderboardEntry"
},
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/transport.LeaderboardEntry"
}
},
"limit": {
"type": "integer",
"example": 50
},
"offset": {
"type": "integer",
"example": 0
},
"total": {
"type": "integer",
"example": 8
}
}
},
"transport.LobbyRace": {
"type": "object",
"properties": {