diff --git a/MISSING_BACKEND_API.md b/MISSING_BACKEND_API.md index f020614..7fd370e 100644 --- a/MISSING_BACKEND_API.md +++ b/MISSING_BACKEND_API.md @@ -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` but fields aren't extracted. + +```typescript +// In transformer - data received but not mapped +dmg?: Record; // 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 + } + } +} +```