The Esports
match blueprint
Live scoreboards, post-match recaps, standings tables, and player telemetry — every esports surface derives from the Match, Team, and Player models documented here.
Models
3
Statuses
live · upcoming · final
Card variants
3
Routes
/esports/$matchId
Live match hero
The detail page leads with the live scoreboard, format/map context, and tournament metadata aside.
Sentinel
NA
BO5 · Map 4 — Haven (8:6)
Iron Maple
EU
Objective control
SEN 56% · IRM 44%
First kills
SEN 18 · IRM 14
Avg round time
1m 29s
Map summary & player table
Per-map outcomes plus compact player telemetry; both share team FKs with the scoreboard.
| Player | Team | Role | Rating | KDA | Signature |
|---|---|---|---|---|---|
| Phantom | SEN | Duelist | 1.34 | 1.62 | Jett |
| Aegis | SEN | Initiator | 1.22 | 1.41 | Sova |
| Aria | IRM | Controller | 1.21 | 1.39 | Omen |
| Iris | IRM | Sentinel | 1.12 | 1.18 | Killjoy |
MatchCard variants
The same MatchCard renders the three states with subtle status accents.
Match model & sample payload
export interface Match {
id: string;
game: EsportsGame; // Valorant | CS2 | LoL | Dota 2
tournament: string;
status: "live" | "upcoming" | "finished";
startsAt: string; // ISO 8601
teamAId: string; // FK -> Team.id
teamBId: string;
scoreA: number;
scoreB: number;
format: string; // "BO3", "BO5"
currentMap?: string; // live ticker
viewers?: number; // live concurrency
}{
"id": "vct-2026-uf-sen-irm",
"game": "Valorant",
"tournament": "Valor Arena Champions · Upper Final",
"status": "live",
"startsAt": "2026-05-07T18:30:00.000Z",
"teamAId": "sentinel",
"teamBId": "iron-maple",
"scoreA": 2,
"scoreB": 1,
"format": "BO5",
"currentMap": "Map 4 — Haven (8:6)",
"viewers": 512000
}Match fields
field · type · description
idrequiredstringOpaque match id; powers /esports/$matchId.
gamerequiredEsportsGameEnum: Valorant | CS2 | League of Legends | Dota 2.
tournamentrequiredstringSeries + stage label, e.g. 'Champions · Upper Final'.
statusrequired'live' | 'upcoming' | 'finished'Drives badge color and card variant.
startsAtrequiredstring (ISO)ISO 8601; powers countdown + ordering.
teamAIdrequiredstringFK → Team.id (left side).
teamBIdrequiredstringFK → Team.id (right side).
scoreArequirednumberMaps won or game points.
scoreBrequirednumberSame as scoreA.
formatrequiredstringShort label, 'BO3' / 'BO5'.
currentMapstring?Live ticker string; live status only.
viewersnumber?Live concurrency count.
Cross-model alignment
Match references Team and Player by id — keep these consistent across endpoints.
Team contract
tag— 2–3 char monogram, drives crests.logoColor— hex for crest fill.formStreak— last 5 results, ('W'|'L')[].wins · losses · points— standings columns.region · game— partition for filters.
Player contract
teamId— FK → Team.id; required.game— must match team.game.role— game-specific string.rating · kda— numeric, decimal places preserved.signature— agent / champion / hero name.
Tip
When status === "live", also return currentMap and viewers — the UI hides the badge if either is missing.