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>
452 lines
9.8 KiB
Markdown
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
|
|
}
|
|
}
|
|
}
|
|
```
|