# Battleground Investigation Report

**Date:** 2026-01-18
**Status:** ✅ FIXED (Commit 3cfcecb)
**Severity:** Critical - All XP/gamification data going to wrong user

---

## Executive Summary

Battleground stats are not updating because XP-related routes use `req.headers['x-user-id']` to identify the user, but the frontend **never sends this header**. All XP gets stored under `'default-user'` instead of real user IDs.

---

## Data Flow Diagram

```
EXPECTED FLOW:
┌──────────────┐    ┌────────────────┐    ┌─────────────┐    ┌───────────────┐
│ User Action  │ -> │ Frontend Call  │ -> │ Backend API │ -> │ Database      │
│ (e.g. call)  │    │ with Bearer    │    │ req.user.id │    │ user_xp table │
└──────────────┘    │ token          │    │ = "abc-123" │    │ user_id=abc-123│
                    └────────────────┘    └─────────────┘    └───────────────┘

ACTUAL FLOW (BROKEN):
┌──────────────┐    ┌────────────────┐    ┌─────────────────┐    ┌───────────────┐
│ User Action  │ -> │ Frontend Call  │ -> │ Backend XP API  │ -> │ Database      │
│ (e.g. call)  │    │ with Bearer    │    │ checks header   │    │ user_xp table │
└──────────────┘    │ token (NO      │    │ 'x-user-id'     │    │ user_id=      │
                    │ x-user-id!)    │    │ NOT FOUND! ❌   │    │ 'default-user'│
                    └────────────────┘    │ defaults to     │    └───────────────┘
                                          │ 'default-user'  │
                                          └─────────────────┘
```

---

## Component-by-Component Analysis

### 1. Frontend API Client (`admin/src/api/client.js`)
**Status:** ✅ Working correctly

- Sends `Authorization: Bearer <token>` header
- Does NOT send `x-user-id` header (and shouldn't need to - auth middleware extracts user from token)

### 2. Auth Middleware (`src/middleware/auth.js`)
**Status:** ✅ Working correctly

- Validates Bearer token with Supabase
- Sets `req.user = { id, email, displayName }` correctly
- All protected routes use this middleware

### 3. XP Routes (`src/routes/xp.js`)
**Status:** ❌ BROKEN - Uses wrong pattern

**Lines with issue:**
- Line 53: `const userId = req.headers['x-user-id'] || 'default-user';`
- Line 120: `const userId = req.headers['x-user-id'] || 'default-user';`
- Line 243: `const userId = req.headers['x-user-id'] || 'default-user';`

**Should be:** `const userId = req.user?.id || 'default-user';`

### 4. Battleground Routes (`src/routes/battleground.js`)
**Status:** ⚠️ Better but still defaults to 'default-user'

- Uses `req.user?.id || 'default-user'` (correct pattern)
- BUT if auth middleware fails silently, still goes to default-user
- Main issue is XP data is already wrong, so leaderboard queries find nothing

### 5. Leaderboard Service (`src/services/leaderboardService.js`)
**Status:** ✅ Working correctly

- Queries `user_xp` and `xp_history` tables correctly
- Problem is the data was stored under wrong user_id

### 6. Challenges Service (`src/services/challengesService.js`)
**Status:** ✅ Working correctly

- Challenge logic is sound
- But relies on correct user_id being passed

### 7. Achievements Routes (`src/routes/achievements.js`)
**Status:** ❌ BROKEN - Uses wrong pattern

**Lines with issue:**
- Line 247: `const userId = req.headers['x-user-id'] || 'default-user';`
- Line 301: `const userId = req.headers['x-user-id'] || 'default-user';`

### 8. AI Alerts Routes (`src/routes/aiAlerts.js`)
**Status:** ❌ BROKEN - Uses wrong pattern (6 places)

**Lines:** 27, 76, 119, 143, 166, 189

### 9. Analytics Routes (`src/routes/analytics.js`)
**Status:** ❌ BROKEN - Uses wrong pattern

**Line:** 15

### 10. Coaching Routes (`src/routes/coaching.js`)
**Status:** ❌ BROKEN - Uses wrong pattern (4 places)

**Lines:** 59, 115, 205, 277

### 11. SMS Routes (`src/routes/sms.js`)
**Status:** ❌ BROKEN - Uses wrong pattern

**Line:** 355

### 12. Dashboard Routes (`src/routes/dashboard.js`)
**Status:** ⚠️ Mixed - mostly correct, one broken

**Broken line:** 1642: `const userId = req.headers['x-user-id'] || 'default-user';`

---

## Root Cause(s) Identified

### Primary Root Cause
**Inconsistent user identification pattern across routes.**

Some routes use `req.user?.id` (correct - extracted by auth middleware)
Some routes use `req.headers['x-user-id']` (incorrect - never sent by frontend)

### Secondary Root Cause
**Frontend never sends `x-user-id` header** because it doesn't need to - the auth middleware correctly extracts user ID from the Bearer token.

---

## Impact

1. **All XP awards** → stored under `'default-user'`
2. **Leaderboard** → shows empty or incorrect data
3. **Daily Challenges** → all users see same challenges (for 'default-user')
4. **Achievements** → tracked for wrong user
5. **Coaching scores** → tracked for wrong user
6. **AI Alerts** → all going to 'default-user'

---

## Fixes Required

### File: `src/routes/xp.js`
```javascript
// Line 53, 120, 243 - Change from:
const userId = req.headers['x-user-id'] || 'default-user';
// To:
const userId = req.user?.id || 'default-user';
```

### File: `src/routes/achievements.js`
```javascript
// Line 247, 301 - Change from:
const userId = req.headers['x-user-id'] || 'default-user';
// To:
const userId = req.user?.id || 'default-user';
```

### File: `src/routes/aiAlerts.js`
```javascript
// Lines 27, 76, 119, 143, 166, 189 - Change from:
const userId = req.headers['x-user-id'] || 'default-user';
// To:
const userId = req.user?.id || 'default-user';
```

### File: `src/routes/analytics.js`
```javascript
// Line 15 - Change from:
const userId = req.headers['x-user-id'] || 'default-user';
// To:
const userId = req.user?.id || 'default-user';
```

### File: `src/routes/coaching.js`
```javascript
// Lines 59, 115, 205, 277 - Change from:
const userId = req.headers['x-user-id'] || 'default-user';
// To:
const userId = req.user?.id || 'default-user';
```

### File: `src/routes/sms.js`
```javascript
// Line 355 - Change from:
const userId = req.headers['x-user-id'] || 'default-user';
// To:
const userId = req.user?.id || 'default-user';
```

### File: `src/routes/dashboard.js`
```javascript
// Line 1642 - Change from:
const userId = req.headers['x-user-id'] || 'default-user';
// To:
const userId = req.user?.id || 'default-user';
```

---

## Data Migration (Optional)

After fixing the code, existing data in these tables is stored under 'default-user':
- `user_xp`
- `xp_history`
- `daily_challenges`
- `achievements` (if user-specific)
- `ai_alerts`

Options:
1. **Let it rebuild naturally** - new actions will use correct user_id
2. **Manual SQL migration** - update old records to correct user_id (complex, need to identify which actions belonged to which user from timestamps)

Recommendation: Option 1 - just let it rebuild. Battleground is a fresh feature and data loss is acceptable for a new launch.

---

## Testing Checklist

After applying fixes:

- [ ] Log a call → Check `user_xp` table has correct user_id
- [ ] Award XP manually → Verify correct user_id
- [ ] View Leaderboard → Shows logged-in user's stats
- [ ] Complete a challenge → Progress tracked for correct user
- [ ] Earn achievement → Tracked for correct user
- [ ] View coaching scores → Shows user's own scores

---

## Summary

| Category | Count | Files |
|----------|-------|-------|
| Routes using WRONG pattern | 7 | xp.js, achievements.js, aiAlerts.js, analytics.js, coaching.js, sms.js, dashboard.js |
| Total lines to fix | 17 | See fix details above |
| Estimated fix time | Quick | Simple find/replace |

**Priority:** HIGH - This is a fundamental data integrity issue affecting all gamification features.
