Files
csgowtf/MISSING_BACKEND_API.md
vikingowl 22244e5ed7 docs: Comprehensive analysis of missing backend API data
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>
2025-12-07 20:42:08 +01:00

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:

  1. Backend returns flat dmg_enemy and dmg_team fields, OR
  2. Frontend transformer extracts from dmg.enemy and dmg.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 RoundEnd events
  • Add win_reason enumeration from RoundEnd events

Priority 2: High

  • Extract dmg_enemy and dmg_team in player stats
  • Add utility grenade statistics (ud_he, ud_flames, ud_flash, ud_smoke, ud_decoy)
  • Ensure hs_percent is 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_rate is 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
		}
	}
}