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>
This commit is contained in:
2025-12-07 20:42:08 +01:00
parent 848dc95e77
commit 22244e5ed7

View File

@@ -1,11 +1,157 @@
# Missing Backend API Data
This document outlines data that the frontend is ready to display but is not currently provided by the backend API. These features would enhance the match analysis experience.
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.
## Round Winner & Win Reason
---
## 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.
```typescript
// 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**:
```json
{
"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**:
```json
{
"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.
```typescript
// 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**:
```json
{
"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.
```typescript
// 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**:
```json
@@ -15,28 +161,13 @@ This document outlines data that the frontend is ready to display but is not cur
}
```
**Missing Fields Needed**:
| Field | Type | Description |
| ------------ | -------- | -------------------------------------- |
| `winner` | `number` | Team ID that won the round (1=T, 2=CT) |
| `win_reason` | `string` | How the round ended |
**Win Reason Values**:
- `elimination` - All enemies killed
- `bomb_defused` - CT defused the bomb
- `bomb_exploded` - Bomb detonated successfully
- `time` - Round timer expired (CT win)
- `target_saved` - Hostage rescued (rare mode)
**Expected Response Format**:
**Expected Format**:
```json
{
"0": {
"winner": 1,
"win_reason": "elimination",
"winner": 2,
"win_reason": "bomb_exploded",
"players": {
"player_id": [bank, equipment, spent]
}
@@ -44,35 +175,150 @@ This document outlines data that the frontend is ready to display but is not cur
}
```
**Implementation**: Demo parser needs to capture `RoundEnd` game events and extract:
**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) |
- `winner` field from the event
- `reason` field from the event
**Backend Implementation**: Extract from `RoundEnd` game events in demo parser.
---
## Per-Round Player Stats
## 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.
```typescript
// 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`):
```typescript
dmg_enemy?: number; // Damage dealt to enemies
dmg_team?: number; // Damage dealt to team (friendly fire)
```
**Expected Format**:
```json
{
"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**:
```typescript
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**:
```json
{
"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**:
| Field | Type | Description |
| ------------------ | -------- | -------------------------------------------- |
| `kills_in_round` | `number` | Kills this player got in this specific round |
| `damage_in_round` | `number` | Total damage dealt this round |
| `assists_in_round` | `number` | Assists this round |
```typescript
kills_in_round?: number; // Kills in this specific round
damage_in_round?: number; // Damage dealt this round
assists_in_round?: number; // Assists this round
```
**Implementation**: During demo parse, aggregate `player_death` and `player_hurt` events per round, grouped by attacking player.
**Expected Format**:
```json
{
"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.
---
## Loss Bonus Tracking
## 8. Low: Loss Bonus Tracking
**Endpoint**: `GET /match/{id}/rounds`
**Issue**: Not tracked in backend.
**Missing Fields per Team per Round**:
| Field | Type | Description |
| ------------- | -------- | ------------------------------ |
| `loss_streak` | `number` | Consecutive round losses (0-4) |
| `loss_bonus` | `number` | Current loss bonus amount |
```typescript
loss_streak?: number; // Consecutive round losses (0-4)
loss_bonus?: number; // Current loss bonus amount
```
**CS2 Loss Bonus Scale**:
| Consecutive Losses | Bonus |
@@ -83,7 +329,45 @@ This document outlines data that the frontend is ready to display but is not cur
| 3 | $2,900 |
| 4+ | $3,400 |
**Implementation**: Track `RoundEnd` events and maintain loss counter per team, resetting on win.
**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
---
@@ -91,17 +375,77 @@ This document outlines data that the frontend is ready to display but is not cur
The frontend already has:
- Type definitions for all missing fields (`src/lib/types/RoundStats.ts`)
- Zod validation schemas (`src/lib/schemas/roundStats.schema.ts`)
- UI components ready to display win reasons with icons
- Mock handlers showing expected data structure (`src/mocks/handlers/matches.ts`)
- 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 the backend provides this data, the frontend will automatically display it.
Once backend provides this data, frontend will automatically display it.
---
## Priority
## API Response Examples
1. **High**: Round winner & win reason - enables win/loss correlation analysis
2. **Medium**: Per-round player stats - enables round-by-round performance tracking
3. **Low**: Loss bonus tracking - nice-to-have for economy analysis
### Ideal Match Response
```json
{
"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
```json
{
"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
```json
{
"weapons": {
"7": {
"name": "AK-47",
"kills": 12,
"damage": 1847,
"hits": 45,
"headshots": 8
}
}
}
```