Document all frontend expectations vs backend reality: - Critical: KAST%, ADR, weapon kills (all show 0) - High: Round winner/reason, damage stats - Medium: Utility stats, per-round performance, loss bonus Includes impact summary, code locations, expected formats, and backend implementation checklist. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
9.8 KiB
Missing Backend API Data
This document outlines data that the frontend expects but is not currently provided by the backend API. These features would enhance the match analysis experience.
Impact Summary
| Field | Severity | Status | Impact |
|---|---|---|---|
| KAST % | Critical | Missing | Players display 0% KAST |
| ADR | Critical | Missing | Statistics incomplete |
| Weapon Kills | High | Missing | Weapon stats show 0 kills |
| Round Winner | High | Missing | No round outcome analysis |
| Win Reason | High | Missing | Can't show how rounds ended |
| Headshot % | Medium | Partial | Sometimes missing |
| Damage Stats | Medium | Not extracted | Data sent but unused |
| Utility Stats | Medium | Missing | Grenade analysis unavailable |
| Per-Round Stats | Medium | Missing | No round-by-round performance |
| Loss Bonus | Low | Missing | Economy analysis incomplete |
1. Critical: KAST Percentage
Endpoint: GET /match/{id} (player stats)
Location in Frontend: src/lib/api/players.ts:49-76
Issue: KAST (Kill/Assist/Survive/Trade) is completely unavailable. Frontend returns placeholder 0.
// Current workaround in players.ts
const totalKast = recentMatches.reduce((sum, _m) => {
// KAST is a percentage, we need to calculate it
// For now, we'll use a placeholder
return sum + 0;
}, 0);
Affected Components:
/player/[id]/+page.svelte- Player profile stats chart/match/[id]/+page.svelte:28-29- Team average KAST- Match scoreboard KAST% column
Expected Format:
{
"players": [
{
"kast": 72.5
}
]
}
Backend Implementation: Calculate per player per match:
KAST% = (Rounds with Kill + Rounds with Assist + Rounds Survived + Rounds Traded) / Total Rounds * 100
2. Critical: Average Damage per Round (ADR)
Endpoint: GET /match/{id} (player stats)
Location in Frontend: src/lib/types/Match.ts:114-115
Issue: ADR not provided. Components use player.adr || 0 fallback.
Affected Components:
/match/[id]/+page.svelte:27, 44, 83- Team and player ADR/match/[id]/damage/+page.svelte- Damage analysis page/player/[id]/+page.svelte:280- Player profile
Expected Format:
{
"players": [
{
"adr": 85.3
}
]
}
Backend Implementation:
ADR = Total Damage to Enemies / Rounds Played
3. High: Weapon Kill Counts
Endpoint: GET /match/{id}/weapons
Location in Frontend: src/lib/api/transformers/weaponsTransformer.ts:85-87
Issue: Backend provides damage/hits but NOT kill counts. All weapons show 0 kills.
// Current workaround
weapon_stats.push({
// Kill data not available - API only provides hit/damage events
kills: 0, // HARDCODED ZERO - should be from backend
damage: stats.damage,
hits: stats.hits
});
Expected Format:
{
"weapons": {
"7": {
"kills": 12,
"damage": 1847,
"hits": 45
}
}
}
Backend Implementation: Correlate player_hurt events with player_death events to determine which weapon dealt the killing blow.
4. High: Round Winner & Win Reason
Endpoint: GET /match/{id}/rounds
Location in Frontend: src/lib/api/transformers/roundsTransformer.ts:71-76
Issue: Backend only returns economy data, not round outcomes.
// Current hardcoded placeholders
rounds.push({
round: roundNum + 1,
winner: 0, // HARDCODED - should be 2 (T) or 3 (CT)
win_reason: '', // HARDCODED - should be enum
players
});
Currently Returns:
{
"0": { "player_id": [bank, equipment, spent] },
"1": { "player_id": [bank, equipment, spent] }
}
Expected Format:
{
"0": {
"winner": 2,
"win_reason": "bomb_exploded",
"players": {
"player_id": [bank, equipment, spent]
}
}
}
Win Reason Values:
| Value | Description |
|---|---|
elimination |
All enemies killed |
bomb_defused |
CT defused the bomb |
bomb_exploded |
Bomb detonated (T win) |
time |
Round timer expired (CT win) |
target_saved |
Hostage rescued (rare) |
Backend Implementation: Extract from RoundEnd game events in demo parser.
5. Medium: Damage Statistics (dmg_enemy, dmg_team)
Endpoint: GET /match/{id} (player stats)
Location in Frontend: src/lib/api/transformers.ts:96
Issue: Backend sends dmg as Record<string, unknown> but fields aren't extracted.
// In transformer - data received but not mapped
dmg?: Record<string, unknown>; // NOT EXTRACTED to dmg_enemy/dmg_team
Type Definition (src/lib/types/Match.ts:134-135):
dmg_enemy?: number; // Damage dealt to enemies
dmg_team?: number; // Damage dealt to team (friendly fire)
Expected Format:
{
"players": [
{
"dmg": {
"enemy": 2847,
"team": 45
}
}
]
}
Fix: Either:
- Backend returns flat
dmg_enemyanddmg_teamfields, OR - Frontend transformer extracts from
dmg.enemyanddmg.team
6. Medium: Utility/Grenade Statistics
Endpoint: GET /match/{id} (player stats)
Location in Frontend: src/lib/types/Match.ts:144-148
Issue: Not provided by backend at all.
Missing Fields:
ud_he?: number; // HE grenade damage dealt
ud_flames?: number; // Molotov/Incendiary damage dealt
ud_flash?: number; // Flash grenades thrown (count)
ud_smoke?: number; // Smoke grenades thrown (count)
ud_decoy?: number; // Decoy grenades thrown (count)
Expected Format:
{
"players": [
{
"ud_he": 156,
"ud_flames": 89,
"ud_flash": 8,
"ud_smoke": 12,
"ud_decoy": 2
}
]
}
Backend Implementation: Count grenade events and sum damage from player_hurt events where weapon is HE/molotov/incendiary.
7. Medium: Per-Round Player Statistics
Endpoint: GET /match/{id}/rounds
Issue: No per-round performance data for players.
Missing Fields per Player per Round:
kills_in_round?: number; // Kills in this specific round
damage_in_round?: number; // Damage dealt this round
assists_in_round?: number; // Assists this round
Expected Format:
{
"1": {
"winner": 2,
"win_reason": "elimination",
"players": {
"76561198012345678": {
"bank": 4000,
"equipment": 3750,
"spent": 2900,
"kills": 2,
"damage": 187,
"assists": 1
}
}
}
}
Backend Implementation: Aggregate player_death and player_hurt events per round, grouped by attacker.
8. Low: Loss Bonus Tracking
Endpoint: GET /match/{id}/rounds
Issue: Not tracked in backend.
Missing Fields per Team per Round:
loss_streak?: number; // Consecutive round losses (0-4)
loss_bonus?: number; // Current loss bonus amount
CS2 Loss Bonus Scale:
| Consecutive Losses | Bonus |
|---|---|
| 0 | $1,400 |
| 1 | $1,900 |
| 2 | $2,400 |
| 3 | $2,900 |
| 4+ | $3,400 |
Backend Implementation: Track RoundEnd events and maintain loss counter per team, resetting on win.
9. Optional Fields (Expected Gaps)
These fields are intentionally optional due to data availability:
| Field | Reason |
|---|---|
replay_url |
Only available for matches < 4 weeks old (Valve retention) |
share_code |
Not all matches have share codes |
tick_rate |
May not be in older demos |
game_mode |
Legacy CS:GO matches don't have this |
avg_ping |
Not always recorded in demos |
Backend Implementation Checklist
Priority 1: Critical
- Add KAST calculation per player per match
- Add ADR calculation per player per match
- Add weapon kill tracking (correlate damage with death events)
- Add round winner from
RoundEndevents - Add win_reason enumeration from
RoundEndevents
Priority 2: High
- Extract
dmg_enemyanddmg_teamin player stats - Add utility grenade statistics (ud_he, ud_flames, ud_flash, ud_smoke, ud_decoy)
- Ensure
hs_percentis always calculated
Priority 3: Medium
- Add per-round player stats (kills, damage, assists per round)
- Add loss bonus tracking per team per round
- Ensure
tick_rateis always provided when available
Frontend Readiness
The frontend already has:
- Type definitions for all fields (
src/lib/types/) - Components ready to display data (using fallbacks currently)
- Transformers prepared to extract nested data
- UI for all features (showing placeholders/zeros)
Once backend provides this data, frontend will automatically display it.
API Response Examples
Ideal Match Response
{
"match_id": "123456",
"players": [
{
"id": "76561198012345678",
"name": "Player1",
"kills": 25,
"deaths": 18,
"assists": 4,
"kast": 72.5,
"adr": 85.3,
"hs_percent": 45.2,
"dmg_enemy": 2847,
"dmg_team": 12,
"ud_he": 156,
"ud_flames": 89,
"ud_flash": 8,
"ud_smoke": 12
}
]
}
Ideal Rounds Response
{
"1": {
"winner": 2,
"win_reason": "bomb_exploded",
"t_loss_streak": 0,
"ct_loss_streak": 1,
"players": {
"76561198012345678": {
"bank": 4000,
"equipment": 3750,
"spent": 2900,
"kills": 2,
"damage": 187
}
}
}
}
Ideal Weapons Response
{
"weapons": {
"7": {
"name": "AK-47",
"kills": 12,
"damage": 1847,
"hits": 45,
"headshots": 8
}
}
}