diff --git a/.gitignore b/.gitignore index f805890..489e0c9 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,6 @@ coverage .tmp tmp *.tmp + +# Claude Code +CLAUDE.md diff --git a/MISSING_BACKEND_API.md b/MISSING_BACKEND_API.md index 7fd370e..6f5e237 100644 --- a/MISSING_BACKEND_API.md +++ b/MISSING_BACKEND_API.md @@ -449,3 +449,724 @@ Once backend provides this data, frontend will automatically display it. } } ``` + +--- + +# 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_ diff --git a/src/lib/components/player/PlayerCard.svelte b/src/lib/components/player/PlayerCard.svelte index d5ded6e..6323384 100644 --- a/src/lib/components/player/PlayerCard.svelte +++ b/src/lib/components/player/PlayerCard.svelte @@ -1,5 +1,5 @@