strat-gameplay-webapp/frontend-sba/store/CLAUDE.md
Cal Corum 9c90893b5d CLAUDE: Update documentation across codebase
Updated CLAUDE.md files with:
- Current test counts and status
- Session injection pattern documentation
- New module references and architecture notes
- Updated Phase status (3E-Final complete)
- Enhanced troubleshooting guides

Files updated:
- Root CLAUDE.md: Project overview and phase status
- backend/CLAUDE.md: Backend overview with test counts
- backend/README.md: Quick start and development guide
- backend/app/api/CLAUDE.md: API routes documentation
- backend/app/database/CLAUDE.md: Session injection docs
- backend/app/utils/CLAUDE.md: Utilities documentation
- backend/tests/CLAUDE.md: Testing patterns and policy
- frontend-sba/CLAUDE.md: Frontend overview
- frontend-sba/store/CLAUDE.md: Store patterns

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 12:10:10 -06:00

147 lines
3.7 KiB
Markdown

# Store Directory
Pinia stores for centralized state management. All stores use Composition API syntax.
## Available Stores
### game.ts - Active Game State
**Purpose**: Central state for real-time gameplay, synchronized via WebSocket.
**Key State**:
```typescript
gameState: GameState | null // Full game state from backend
homeLineup: Lineup[] // Cached home team roster
awayLineup: Lineup[] // Cached away team roster
playHistory: PlayResult[] // Play-by-play history
currentDecisionPrompt: DecisionPrompt | null
pendingRoll: RollData | null // Manual mode dice roll
```
**Critical Getters**:
```typescript
// Team determination (mirrors backend logic)
battingTeamId // away if top, home if bottom
fieldingTeamId // home if top, away if bottom
// Current players (LineupPlayerState)
currentBatter
currentPitcher
currentCatcher
// Decision state
needsDefensiveDecision
needsOffensiveDecision
canRollDice
canSubmitOutcome
```
**Player Lookup Method**:
```typescript
// Critical: Joins LineupPlayerState with full Lineup data
findPlayerInLineup(lineupId: number): Lineup | undefined
```
### auth.ts - Authentication
**Purpose**: Discord OAuth state with HttpOnly cookie-based authentication.
**Key State**: `currentUser`, `isAuthenticated`
**Critical Pattern - SSR Cookie Forwarding**:
```typescript
// checkAuth() must forward cookies during SSR
async function checkAuth(): Promise<boolean> {
const headers: Record<string, string> = {}
if (import.meta.server) {
const event = useRequestEvent()
const cookieHeader = event?.node.req.headers.cookie
if (cookieHeader) {
headers['Cookie'] = cookieHeader // Forward to backend
}
}
const response = await $fetch('/api/auth/me', {
credentials: 'include',
headers,
})
}
```
**API Calls Pattern**:
```typescript
// ALL API calls must use credentials: 'include'
const response = await $fetch('/api/games/', {
credentials: 'include', // Sends HttpOnly cookies
})
// NEVER use Authorization header - tokens are in cookies
```
**Reference**: See `COOKIE_AUTH_IMPLEMENTATION.md` for complete auth flow documentation.
### ui.ts - UI State
**Purpose**: Toasts, modals, loading states.
**Key Methods**: `showSuccess()`, `showError()`, `showWarning()`, `showInfo()`
## Data Resolution Pattern
Game state contains minimal `LineupPlayerState`:
```typescript
interface LineupPlayerState {
lineup_id: number // Key for lookup
card_id: number
position: string
// NO player name, headshot, etc.
}
```
Store caches full `Lineup` with nested player:
```typescript
interface Lineup {
lineup_id: number
player: {
id: number
name: string
headshot: string
}
}
```
**Resolution**:
```typescript
const batterState = gameStore.currentBatter // LineupPlayerState
const batterLineup = gameStore.findPlayerInLineup( // Full Lineup
batterState.lineup_id
)
const name = batterLineup?.player.name // "Mike Trout"
```
## Store Patterns
### Nuxt 4 Import Requirement
```typescript
// ALWAYS explicitly import stores
import { useGameStore } from '~/store/game'
const gameStore = useGameStore()
// NEVER rely on auto-imports (breaks in Nuxt 4)
```
### Readonly State
All state refs are exposed as `readonly()` to prevent direct mutation:
```typescript
return {
gameState: readonly(gameState), // Can't do gameStore.gameState.value = x
setGameState, // Use action instead
}
```
### Team Determination Logic
```typescript
// Same logic as backend state_manager.py
const battingTeamId = computed(() => {
return gameState.value.half === 'top'
? gameState.value.away_team_id // Top: away bats
: gameState.value.home_team_id // Bottom: home bats
})
```