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

452 lines
9.8 KiB
Markdown

# 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.
```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
{
"0": { "player_id": [bank, equipment, spent] },
"1": { "player_id": [bank, equipment, spent] }
}
```
**Expected Format**:
```json
{
"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.
```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**:
```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
```
**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.
---
## 8. Low: Loss Bonus Tracking
**Endpoint**: `GET /match/{id}/rounds`
**Issue**: Not tracked in backend.
**Missing Fields per Team per Round**:
```typescript
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
```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
}
}
}
```