Files
csgowtf/MISSING_BACKEND_API.md
vikingowl f3d24e0286 docs: Consolidate backend API documentation and feature proposals
- Merge NEW_FEATURES.md into MISSING_BACKEND_API.md as "Future Feature Proposals"
- Remove redundant NEW_FEATURES.md file
- Add CLAUDE.md to .gitignore (local development config)
- Include pending frontend component updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 21:04:13 +01:00

1173 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
}
}
}
```
---
# Future Feature Proposals
The following features require backend changes to implement. They are organized into tiers based on implementation complexity.
---
## Tier 3: API Enhancements (Expose Existing Data)
These features use data that's **already stored** in the database but not currently exposed through the API.
### 3.1 Per-Weapon Kill Attribution
**Current State:**
- `weapon` table stores damage per hit with `hit_group`, `weapon_id`, and `dmg`
- Weapon damage is aggregated in player meta endpoint
**Missing:**
- Kill counts per weapon (correlating damage with deaths)
- Headshot kills vs body shot kills per weapon
**Proposed API Change:**
```typescript
// Extend GET /player/:id/meta/:limit response
interface WeaponStats {
weapon_id: number;
weapon_name: string;
kills: number; // NEW: Total kills with this weapon
headshot_kills: number; // NEW: HS kills with this weapon
damage: number; // Existing
shots: number; // Existing
hits: number; // Existing
}
```
**Implementation Notes:**
- Requires correlating weapon damage events with kill events
- Could be computed at match import time and stored, or calculated on-demand
---
### 3.2 Per-Map Detailed Statistics
**Current State:**
- All player stats exist per match with `map` field
- No pre-aggregated per-map statistics
**Missing:**
- K/D ratio per map
- ADR per map
- Headshot % per map
- Win rate per map
**Proposed API Change:**
```typescript
// Extend GET /player/:id/meta/:limit response
interface MapStats {
map: string;
matches_played: number;
wins: number;
losses: number;
ties: number;
avg_kills: number;
avg_deaths: number;
avg_adr: number;
headshot_pct: number;
}
```
**Use Case:** Players can see which maps they perform best on, helping with map vetoes and practice focus.
---
### 3.3 Hit Group Aggregates
**Current State:**
- `weapon.hit_group` stores where each shot landed (0=head, 1=chest, 2=stomach, 3=left arm, 4=right arm, 5=left leg, 6=right leg)
- Individual hits are stored but not aggregated
**Missing:**
- Aggregated hit distribution across all matches
- Per-weapon accuracy by body part
**Proposed API Change:**
```typescript
// Extend GET /player/:id/meta/:limit response
interface HitGroupStats {
total_hits: number;
head: number; // Count of head hits
chest: number; // Count of chest hits
stomach: number; // Count of stomach hits
arms: number; // Combined left+right arm hits
legs: number; // Combined left+right leg hits
head_pct: number; // Calculated percentage
body_pct: number; // chest + stomach percentage
limb_pct: number; // arms + legs percentage
}
```
**Use Case:** Visual body diagram showing where player typically lands shots, identifying spray control issues.
---
### 3.4 Round Economy Timeline
**Current State:**
- `roundstats` table contains `bank`, `equipment`, `spent` per round
- Data exists but not exposed in player endpoint
**Missing:**
- Economy trends over match history
- Buy pattern analysis (eco/force/full buy distribution)
- Equipment value vs damage dealt correlation
**Proposed API Change:**
```typescript
// New endpoint: GET /player/:id/economy
interface EconomyStats {
avg_equipment_value: number;
avg_bank_at_round_start: number;
eco_round_pct: number; // % of rounds with <$2000 equipment
force_buy_pct: number; // % of rounds with $2000-$4000
full_buy_pct: number; // % of rounds with >$4000
value_per_kill: number; // avg damage dealt / avg equipment value
save_rate: number; // % of rounds where player survived with <$2000
}
```
**Use Case:** Understanding economic efficiency - are they getting value for their money?
---
### 3.5 Opponent History (Head-to-Head)
**Current State:**
- All match participants are stored
- Can identify when two players were in the same match
**Missing:**
- Head-to-head records vs specific players
- Performance when playing with/against specific teammates
**Proposed API Change:**
```typescript
// New endpoint: GET /player/:id/opponents?limit=10
interface OpponentRecord {
opponent_id: string;
opponent_name: string;
opponent_avatar: string;
matches_played: number;
wins: number;
losses: number;
avg_kills_vs: number; // Avg kills when playing against this opponent
avg_deaths_vs: number; // Avg deaths when playing against this opponent
last_match_date: string;
}
```
**Use Case:** "Rival" detection - who do they frequently play against and how do they perform?
---
### 3.6 Crosshair History
**Current State:**
- `crosshair` code stored per match
- `color` enum stored (0=default, 1=green, 2=yellow, 3=blue, 4=cyan)
**Missing:**
- Not exposed in player meta endpoint
- No history of crosshair changes
**Proposed API Change:**
```typescript
// Extend GET /player/:id/meta/:limit response
interface CrosshairInfo {
current_crosshair: string; // Most recent crosshair code
current_color: number; // Most recent color
changes_count: number; // How often they change crosshair
history: Array<{
crosshair: string;
color: number;
first_seen: string;
matches_used: number;
}>;
}
```
**Use Case:** Players curious about what crosshair settings others use, track experimentation.
---
## Tier 4: Demo Parser Additions
These features require **new data collection** from demo files during parsing.
### 4.1 Kill/Death Event Log
**What to Capture:**
```go
type KillEvent struct {
MatchID string
RoundNumber int
Tick int
Timestamp float64 // Seconds into round
KillerID string
VictimID string
AssisterID string // nullable
WeaponID int
Headshot bool
Wallbang bool
Smoke bool // Through smoke
NoScope bool
Flashed bool // Victim was flashed
Distance float32 // Distance between players
KillerX float32
KillerY float32
KillerZ float32
VictimX float32
VictimY float32
VictimZ float32
}
```
**Enables:**
- Opening kill/death statistics (first blood)
- Trade detection (kill within X seconds of teammate death)
- Kill distance analysis (long range vs close quarters)
- Clutch situation detection
- Kill position heatmaps
**Storage Estimate:** ~20-30 kills per match × 20 bytes average = ~500 bytes per match
---
### 4.2 Round Winner Attribution
**What to Capture:**
```go
type RoundResult struct {
MatchID string
RoundNumber int
WinnerTeamID int // 2 or 3
WinReason int // 1=bomb, 2=defuse, 3=elimination, 4=time
ClutchPlayerID string // nullable - player who clutched (1vX)
ClutchSize int // 1v1, 1v2, etc.
MVPPlayerID string // Round MVP
}
```
**Enables:**
- Clutch win rate (1v1, 1v2, 1v3, etc.)
- Bomb plant/defuse success rates
- Round impact scoring
- MVP frequency
---
### 4.3 Position/Heatmap Data
**What to Capture:**
```go
type PlayerPosition struct {
MatchID string
RoundNumber int
Tick int // Sample every ~32 ticks (0.5 seconds)
PlayerID string
X float32
Y float32
Z float32
ViewAngleX float32 // Where they're looking
ViewAngleY float32
IsAlive bool
}
```
**Enables:**
- Kill heatmaps (where do they get kills/die)
- Site preference analysis (A vs B)
- Positioning patterns
- 2D round replay (future)
**Storage Estimate:** High - ~2000 position samples per player per match. Consider:
- Only sample during key moments (kills, bomb plant, round end)
- Downsample to 1 sample per second
- Store as compressed binary blob
---
### 4.4 Trade Detection
**What to Capture:**
- Already covered by Kill Event Log (4.1)
- Calculate at query time: If player A dies and teammate B kills A's killer within 5 seconds = trade
**Derived Stats:**
```typescript
interface TradeStats {
trades_given: number; // Times you avenged a teammate
trades_received: number; // Times a teammate avenged you
trade_success_rate: number; // trades_given / opportunities
trading_partner_id: string; // Who they trade with most often
}
```
---
### 4.5 Utility Timing Analysis
**What to Capture:**
```go
type UtilityEvent struct {
MatchID string
RoundNumber int
Tick int
PlayerID string
UtilityType int // flash, smoke, he, molotov
ThrowX float32
ThrowY float32
ThrowZ float32
LandX float32 // Where it detonated/landed
LandY float32
LandZ float32
PlayersFlashed []FlashedPlayer // For flashbangs
}
type FlashedPlayer struct {
PlayerID string
Duration float32 // Flash duration in seconds
IsTeammate bool
}
```
**Enables:**
- Flash effectiveness (avg flash duration)
- Team flash rate (already have `dmg_team` but duration is more precise)
- Smoke lineup success
- Molotov damage tracking
---
### 4.6 First Blood Statistics
**What to Capture:**
- Mark `is_first_blood` flag in Kill Event (4.1)
- First kill of each round
**Derived Stats:**
```typescript
interface FirstBloodStats {
first_blood_attempts: number; // Rounds where they got first kill OR first death
first_bloods: number; // Times they got first kill
first_deaths: number; // Times they died first
first_blood_rate: number; // first_bloods / first_blood_attempts
opening_duel_win_rate: number; // first_bloods / (first_bloods + first_deaths)
}
```
---
### 4.7 HLTV Rating 2.0
**Formula Components:**
```
Rating 2.0 = 0.0073*KAST + 0.3591*KPR - 0.5329*DPR + 0.2372*Impact + 0.0032*ADR + 0.1587
Where:
- KAST = % of rounds with Kill, Assist, Survived, or Traded
- KPR = Kills per round
- DPR = Deaths per round
- Impact = (2.13*KPR + 0.42*Assist per Round - 0.41)
- ADR = Average damage per round
```
**What's Needed:**
- KAST requires knowing if player survived or was traded (needs trade detection)
- All other components are calculable from existing data
**Proposed Implementation:**
- Add `kast_rounds` counter to match stats
- Calculate Rating 2.0 server-side for consistency
---
## Tier 5: New Systems
These features require **significant new infrastructure**.
### 5.1 Player Comparison Tool
**Description:** Side-by-side comparison of any two players' statistics.
**Requirements:**
- New UI page: `/compare/:player1/:player2`
- API endpoint: `GET /players/compare?ids=player1,player2`
- Returns normalized stats for fair comparison
**Comparison Metrics:**
```typescript
interface PlayerComparison {
players: [PlayerMeta, PlayerMeta];
stats_comparison: {
metric: string;
player1_value: number;
player2_value: number;
player1_percentile: number; // How they rank globally
player2_percentile: number;
}[];
head_to_head?: {
matches_played: number;
player1_wins: number;
player2_wins: number;
};
common_maps: string[];
common_teammates: PlayerMeta[];
}
```
---
### 5.2 Achievement System
**Description:** Badges and milestones for player accomplishments.
**Schema:**
```sql
CREATE TABLE achievements (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
description TEXT,
icon VARCHAR(50),
category VARCHAR(50), -- 'kills', 'utility', 'milestones', 'special'
threshold INT,
stat_key VARCHAR(50) -- Which stat to check
);
CREATE TABLE player_achievements (
player_id VARCHAR(20),
achievement_id INT,
unlocked_at TIMESTAMP,
progress INT, -- For progressive achievements
PRIMARY KEY (player_id, achievement_id)
);
```
**Example Achievements:**
| Name | Description | Threshold |
|------|-------------|-----------|
| Centurion | 100 aces | 100 |
| Headhunter | 1000 headshot kills | 1000 |
| Support Main | 500 flash assists | 500 |
| Clutch Master | 50 1v3+ clutches | 50 |
| Map Scholar | Play 100 matches on each map | 700 total |
| Friendly Fire | Deal 1000 team damage (shame badge) | 1000 |
**Implementation:**
- Background job checks achievement progress after each match import
- Push notification system for newly unlocked achievements
- Achievement showcase on player profile
---
### 5.3 Global Leaderboards
**Description:** Rankings by various statistics.
**Schema:**
```sql
CREATE TABLE leaderboards (
stat_key VARCHAR(50),
time_period VARCHAR(20), -- 'all_time', 'monthly', 'weekly'
player_id VARCHAR(20),
value DECIMAL(10,2),
rank INT,
updated_at TIMESTAMP,
PRIMARY KEY (stat_key, time_period, player_id)
);
```
**Leaderboard Categories:**
- Highest K/D ratio (min 50 matches)
- Most headshot kills
- Highest ADR
- Most flash assists
- Most matches played
- Highest win rate (min 100 matches)
- Most aces
- Longest win streak
**Implementation:**
- Materialized view or dedicated table refreshed hourly/daily
- Pagination support for full leaderboard browsing
- Filter by region/rank bracket (future)
---
### 5.4 Improvement Tips Engine
**Description:** AI-generated suggestions based on weak stats.
**Rules Engine Approach:**
```typescript
interface ImprovementRule {
condition: (stats: PlayerStats) => boolean;
tip: string;
priority: number;
category: 'aim' | 'utility' | 'economy' | 'teamplay' | 'consistency';
}
const rules: ImprovementRule[] = [
{
condition: (s) => s.headshot_pct < 30,
tip: 'Your headshot percentage is below average. Focus on crosshair placement at head level.',
priority: 1,
category: 'aim'
},
{
condition: (s) => s.flash_assists < 1,
tip: "You're not getting many flash assists. Practice pop flashes for your teammates.",
priority: 2,
category: 'utility'
},
{
condition: (s) => s.team_damage_ratio > 3,
tip: 'Your team damage is high. Be more careful with utility and spray control.',
priority: 1,
category: 'teamplay'
}
// ... more rules
];
```
**Alternative - ML Approach:**
- Cluster players by playstyle
- Compare to higher-ranked players with similar style
- Identify key stat differences
- Generate personalized recommendations
---
### 5.5 Match Replay Integration (2D)
**Description:** Simple 2D overhead view of rounds.
**Requirements:**
- Position data from Tier 4.3
- Map radar images (already have some)
- WebGL or Canvas-based renderer
- Playback controls (play/pause/speed)
**Data Format:**
```typescript
interface ReplayFrame {
tick: number;
timestamp: number; // Seconds into round
players: {
id: string;
team: number;
x: number;
y: number;
angle: number;
health: number;
alive: boolean;
weapon: string;
}[];
events: {
type: 'kill' | 'plant' | 'defuse' | 'flash' | 'smoke';
tick: number;
data: any;
}[];
}
```
**Compression:**
- Delta encoding (only send changes)
- Binary format instead of JSON
- Stream in chunks for long rounds
---
### 5.6 Social Features
**Description:** Follow players, activity feed, sharing.
**Schema:**
```sql
CREATE TABLE follows (
follower_id VARCHAR(20),
following_id VARCHAR(20),
created_at TIMESTAMP,
PRIMARY KEY (follower_id, following_id)
);
CREATE TABLE activity_feed (
id SERIAL PRIMARY KEY,
player_id VARCHAR(20),
event_type VARCHAR(50), -- 'match_completed', 'achievement_unlocked', 'rank_changed'
event_data JSONB,
created_at TIMESTAMP
);
```
**Features:**
- Follow/unfollow players
- Activity feed showing followed players' recent matches
- Share profile/match links
- Privacy settings (public/private profiles)
---
## Data Schema Reference
### Current Tables Used
| Table | Key Fields | Notes |
| -------------- | ----------------------------- | --------------------- |
| `players` | id, name, avatar, tracked | Core player data |
| `matches` | match*id, map, date, score*\* | Match metadata |
| `matchplayers` | All per-player stats | Already comprehensive |
| `weapon` | hit_group, weapon_id, dmg | Hit registration |
| `roundstats` | bank, equipment, spent | Economy data |
| `spray` | spray (gob-encoded) | Spray patterns |
### Existing Fields Available but Not Exposed
| Field | Location | Potential Use |
| ----------- | ------------ | ------------------- |
| `crosshair` | matchplayers | Crosshair display |
| `color` | matchplayers | Crosshair color |
| `avg_ping` | matchplayers | Network quality |
| `hit_group` | weapon | Body part accuracy |
| `spray` | spray | Spray visualization |
---
## Priority Recommendations
### High Priority (High Value, Low Effort)
1. **3.1 Per-Weapon Kill Attribution** - Players want to know their best weapons
2. **3.2 Per-Map Detailed Statistics** - Essential for competitive players
3. **3.3 Hit Group Aggregates** - Visual appeal, easy to understand
### Medium Priority (High Value, Medium Effort)
4. **4.1 Kill/Death Event Log** - Unlocks many derived features
5. **4.6 First Blood Statistics** - Key competitive metric
6. **3.5 Opponent History** - Engaging "rivalry" feature
### Lower Priority (High Effort or Niche Appeal)
7. **5.3 Global Leaderboards** - Community engagement
8. **5.1 Player Comparison** - Nice-to-have
9. **5.2 Achievement System** - Gamification
10. **5.5 Match Replay** - High effort, impressive feature
---
## Questions for Discussion
1. **Storage constraints:** Position data (4.3) could be large. What's our storage budget?
2. **Processing time:** Kill event parsing (4.1) adds to import time. Acceptable?
3. **Caching strategy:** Meta stats are cached 30 days. Should new aggregates follow same pattern?
4. **API versioning:** Should we version the API or extend existing endpoints?
5. **Privacy considerations:** Should opponent history require consent?
---
_Document consolidated from separate feature proposals_
_Last updated: December 2024_