Commit Graph

88 Commits

Author SHA1 Message Date
Cal Corum
46caf9cd81 CLAUDE: Update color scheme - red for runners, blue for catcher
Runner highlights and cards:
- Pills: red-500 ring, red-50 background when selected
- Full cards: red gradient (red-900 to red-950), red-600 border
- Pulse glow: red animation (rgba(239, 68, 68))
- Hardcoded red color (#ef4444) for runner pill borders

Catcher highlights and cards:
- Pill: blue-500 ring, blue-50 background when selected
- Full card: blue gradient (blue-900 to blue-950), blue-600 border
- Pulse glow: blue animation (rgba(59, 130, 246))

Updated tests to expect new colors

All 15 RunnersOnBase tests passing
All 16 RunnerCard tests passing
2026-02-07 23:50:24 -06:00
Cal Corum
6b86afe5e4 CLAUDE: Show lead runner + catcher when catcher is selected
- When catcher pill is clicked, display lead runner (3B > 2B > 1B priority) + catcher side-by-side
- Maintains consistent layout whether runner or catcher is selected
- Add leadRunnerBase computed to find highest priority runner
- Add displayedRunnerBase computed to show selected OR lead runner
- Update template to use displayedRunnerPlayer for consistent rendering

All 15 RunnersOnBase tests passing
2026-02-07 23:45:19 -06:00
Cal Corum
d6ea5104d6 CLAUDE: Enhance baserunner panel with lead runner auto-select and clickable catcher
- Swap base order to 3B, 2B, 1B (left to right, closer to baseball diamond)
- Auto-select lead runner on mount (priority: 3B > 2B > 1B)
- Make catcher pill clickable to show catcher card only
- Add 'catcher' as a selection option alongside runner bases
- Update expanded view to handle catcher-only display (centered, single card)
- Add toggleCatcher() function
- Update tests for new base order and auto-selection behavior

All 15 RunnersOnBase tests passing
All 16 RunnerCard tests passing
2026-02-07 23:42:25 -06:00
Cal Corum
5118335020 CLAUDE: Update RunnersOnBase tests for new horizontal layout
- Replace .border-l-4.border-gray-600 checks with .catcher-pill
- Update isExpanded prop references to isSelected
- Adjust expanded view tests for new side-by-side layout
  - matchup-card-blue = runner full card
  - matchup-card = catcher full card
- Fix deselection test to check isSelected prop (Transition keeps DOM during animation)

All 15 RunnersOnBase tests passing
All 16 RunnerCard tests passing
2026-02-07 23:36:07 -06:00
Cal Corum
453280487c CLAUDE: Integrate XCheckWizard into GameplayPanel and wire up WebSocket/store
Step 7 of x-check interactive workflow implementation:

Frontend Integration:
- GameplayPanel.vue: Add x_check_result_pending workflow state, show XCheckWizard when decision_phase is awaiting_x_check_result, handle interactive vs read-only mode based on active_team_id
- store/game.ts: Add xCheckData and decideData state, add needsXCheckResult/needsDecide* getters, add set/clear actions for x-check and decide data
- useWebSocket.ts: Handle decision_required events with x_check_result/decide_advance/decide_throw/decide_speed_check types, route to appropriate store actions, clear x-check/decide data on play_resolved
- useGameActions.ts: Add submitXCheckResult(), submitDecideAdvance(), submitDecideThrow(), submitDecideResult() action wrappers
- types: Export XCheckData, DecideAdvanceData, DecideThrowData, DecideSpeedCheckData, PendingXCheck, and new WebSocket request types

Type fixes:
- XCheckData: Allow readonly arrays for d6_individual and chart_row (store returns readonly refs)
- GameplayPanel: Add userTeamId prop for determining interactive mode

Tests: 460 passing, 28 failing (GameplayPanel.spec.ts needs Pinia setup - pre-existing issue)

Next: Step 8 - End-to-end testing of basic x-check flow (no DECIDE)
2026-02-07 17:43:17 -06:00
Cal Corum
f77666db87 CLAUDE: Add XCheckWizard component and result constants (step 6)
New files:
- constants/xCheckResults.ts - Labels, helpers for all result codes
- components/Gameplay/XCheckWizard.vue - Interactive x-check UI

XCheckWizard features:
 Displays d20 and 3d6 dice results prominently
 Shows 5-column chart row (Range 1-5) as selectable buttons
 Hash result sub-choices (G2#/G3# → pick G2 or SI2)
 SPD result sub-choice (click to reveal d20, pick safe/out)
 Error selection (NO/E1/E2/E3/RP) based on 3d6
 Submit validation (both result + error required)
 Read-only mode for transparency (opponent sees same UI)
 Mobile-responsive layout (stacks on small screens)
 Tailwind styling with clear visual hierarchy

Helper functions:
- getResultLabel() - Display names for all codes
- getErrorLabel() - Display names for error types
- isHashResult() - Detect G2#/G3#
- isSpdResult() - Detect SPD
- getHashConversions() - Get conversion options

Next: Integrate XCheckWizard into GameplayPanel

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-07 17:36:23 -06:00
Cal Corum
defa06653d CLAUDE: Add interactive x-check workflow foundation (steps 1-5)
Backend changes:
- Add PendingXCheck model for interactive x-check state
- Extend decision_phase/pending_decision validators with 4 new phases
- Add initiate_x_check() to roll dice and present chart to player
- Add submit_x_check_result() to process player selection
- Add resolve_x_check_from_selection() to resolve from player input
- Add WebSocket handlers for x-check workflow
- Modify resolve_manual_play() to route X_CHECK to interactive flow
- All 986 unit tests passing

Frontend changes:
- Extend DecisionPhase type with x-check/DECIDE phases
- Add XCheckData, DecideAdvanceData, DecideThrowData, DecideSpeedCheckData interfaces
- Add PendingXCheck to GameState
- Add 4 new client→server WebSocket events

Next: Implement XCheckWizard component and GameplayPanel integration

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-07 17:21:19 -06:00
Cal Corum
ae728fd052 CLAUDE: Flip mobile layout - batter on top, pitcher below 2026-02-06 22:57:39 -06:00
Cal Corum
05d34f5b4f CLAUDE: Add responsive layout - stack pitcher/batter on mobile with pitcher on top 2026-02-06 19:53:56 -06:00
Cal Corum
45098955f1 CLAUDE: Increase transparency of runners container (bg-white/20) for more subtle appearance 2026-02-06 19:48:19 -06:00
Cal Corum
c6cf8e49fb CLAUDE: Make runners container background more transparent (bg-white/50) 2026-02-06 19:45:58 -06:00
Cal Corum
2e8c01f154 CLAUDE: Reverse pitcher/batter positions - batter now on left, pitcher on right 2026-02-06 19:44:11 -06:00
Cal Corum
078516f682 CLAUDE: Add comprehensive tests for RunnersOnBase and RunnerCard components
- Test empty/occupied/expanded states
- Test player name handling and initials
- Test runner selection and catcher card expansion
- Test team color integration
- All 40 tests passing
2026-02-06 19:38:18 -06:00
Cal Corum
f0979ccc9e CLAUDE: Add TODO for visual polish on RunnersOnBase component
- Added TODO comment to improve styling, colors, animations
- Component is functional and working well, ready for future aesthetic improvements
2026-02-06 19:28:37 -06:00
Cal Corum
659ac7759d CLAUDE: Remove GameBoard (diamond) component from gameplay view
- Removed GameBoard component from both mobile and desktop layouts
- Removed unused GameBoard import
- RunnersOnBase component now handles runner display
- Cleaner UI focused on pitcher/batter matchup and expandable runner cards
2026-02-06 19:21:52 -06:00
Cal Corum
674749975f CLAUDE: Fix invalid Tailwind duration class in RunnerCard
- Changed duration-400 to duration-300 (valid Tailwind class)
- Fixes PostCSS build error
2026-02-06 19:19:40 -06:00
Cal Corum
5d20d84568 CLAUDE: Add RunnersOnBase component with expanding cards and runner/catcher matchup
- Created RunnersOnBase.vue component with split layout (runners left, catcher right)
- Created RunnerCard.vue for individual runner cards with expand-in-place functionality
- Integrated component into GamePlay.vue (mobile and desktop layouts)
- Added team color computed properties for batting/fielding teams
- Component only shows when runners on base (hasRunners computed)
- Click runner card to expand in place and show full player card + catcher matchup
- Smooth CSS transitions and animations matching pitcher/batter card style
- Includes design documentation and HTML mockup for reference
2026-02-06 19:13:52 -06:00
Cal Corum
2b8fea36a8 CLAUDE: Redesign dice display with team colors and consolidate player cards
Backend:
- Add home_team_dice_color and away_team_dice_color to GameState model
- Extract dice_color from game metadata in StateManager (default: cc0000)
- Add runners_on_base param to roll_ab for chaos check skipping

Frontend - Dice Display:
- Create DiceShapes.vue with SVG d6 (square) and d20 (hexagon) shapes
- Apply home team's dice_color to d6 dice, white for resolution d20
- Show chaos d20 in amber only when WP/PB check triggered
- Add automatic text contrast based on color luminance
- Reduce blank space and remove info bubble from dice results

Frontend - Player Cards:
- Consolidate pitcher/batter cards to single location below diamond
- Add active card highlighting based on dice roll (d6_one: 1-3=batter, 4-6=pitcher)
- New card header format: [Team] Position [Name] with full card image
- Remove redundant card displays from GameBoard and GameplayPanel
- Enlarge PlayerCardModal on desktop (max-w-3xl at 1024px+)

Tests:
- Add DiceShapes.spec.ts with 34 tests for color calculations and rendering
- Update DiceRoller.spec.ts for new DiceShapes integration
- Fix test_roll_dice_success for new runners_on_base parameter

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 00:16:32 -06:00
Cal Corum
be31e2ccb4 CLAUDE: Complete in-game UI overhaul with player cards and outcome wizard
Features:
- PlayerCardModal: Tap any player to view full playing card image
- OutcomeWizard: Progressive 3-step outcome selection (On Base/Out/X-Check)
- GameBoard: Expandable view showing all 9 fielder positions
- Post-roll card display: Shows batter/pitcher card based on d6 roll
- CurrentSituation: Tappable player cards with modal integration

Bug fixes:
- Fix batter not advancing after play (state_manager recovery logic)
- Add dark mode support for buttons and panels (partial - iOS issue noted)

New files:
- PlayerCardModal.vue, OutcomeWizard.vue, BottomSheet.vue
- outcomeFlow.ts constants for outcome category mapping
- TEST_PLAN_UI_OVERHAUL.md with 23/24 tests passing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 15:23:38 -06:00
Cal Corum
52706bed40 CLAUDE: Mobile drag-drop lineup builder and touch-friendly UI improvements
- Add vuedraggable for mobile-friendly lineup building
- Add touch delay and threshold settings for better mobile UX
- Add drag ghost/chosen/dragging visual states
- Add replacement mode visual feedback when dragging over occupied slots
- Add getBench action to useGameActions for substitution panel
- Add BN (bench) to valid positions in LineupPlayerState
- Update lineup service to load full lineup (active + bench)
- Add touch-manipulation CSS to UI components (ActionButton, ButtonGroup, ToggleSwitch)
- Add select-none to prevent text selection during touch interactions
- Add mobile touch patterns documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 22:17:16 -06:00
Cal Corum
e058bc4a6c CLAUDE: RosterLink refactor for bench players with cached player data
- Add player_positions JSONB column to roster_links (migration 006)
- Add player_data JSONB column to cache name/image/headshot (migration 007)
- Add is_pitcher/is_batter computed properties for two-way player support
- Update lineup submission to populate RosterLink with all players + positions
- Update get_bench handler to use cached data (no runtime API calls)
- Add BenchPlayer type to frontend with proper filtering
- Add new Lineup components: InlineSubstitutionPanel, LineupSlotRow,
  PositionSelector, UnifiedLineupTab
- Add integration tests for get_bench_players

Bench players now load instantly without API dependency, and properly
filter batters vs pitchers (including CP closer position).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 22:15:12 -06:00
Cal Corum
64325d7163 CLAUDE: Fix game recovery to load team display info and add score text outline
Backend:
- Add game_metadata to load_game_state() return dict in DatabaseOperations
- Populate team display fields (name, color, thumbnail) in _rebuild_state_from_data()
  so recovered games show team colors/names

Frontend:
- Add text-outline CSS for score visibility on any background (light logos, gradients)
- Handle thumbnail 404 with @error event, show enhanced shadow when no thumbnail
- Apply consistent outline across mobile and desktop layouts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 09:03:59 -06:00
Cal Corum
d60b7a2d60 CLAUDE: Store team display info in DB and fix lineup auto-start
Backend:
- Add game_metadata to create_game() and quick_create_game() endpoints
- Fetch team display info (lname, sname, abbrev, color, thumbnail) from
  SBA API at game creation time and store in DB
- Populate GameState with team display fields from game_metadata
- Fix submit_team_lineup to cache lineup in state_manager after DB write
  so auto-start correctly detects both teams ready

Frontend:
- Read team colors/names/thumbnails from gameState instead of useState
- Remove useState approach that failed across SSR navigation
- Fix create.vue redirect from legacy /games/lineup/[id] to /games/[id]
- Update game.vue header to show team names from gameState

Docs:
- Update CLAUDE.md to note dev mode has broken auth, always use prod

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 08:43:26 -06:00
Cal Corum
ff3f1746d6 CLAUDE: Add team color gradient to scoreboard and fix sticky tabs
- ScoreBoard: Dynamic gradient using team colors (away left, home right)
  with dark center blend and 20% overlay for text readability
- Fetch team colors from API using cached season from schedule state
- Fix sticky tabs by removing overflow-auto from game layout main
- Move play-by-play below gameplay panel on mobile layout

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 23:14:46 -06:00
Cal Corum
3a91a5d477 CLAUDE: Fix connection status indicator showing disconnected while playing
Use useWebSocket composable directly as source of truth for connection
status instead of gameStore.isConnected which could get out of sync.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 15:59:33 -06:00
Cal Corum
1f5e290d8b CLAUDE: Add game page tabs with lineup persistence and per-team submission
- Refactor game page into tab container with Game, Lineups, Stats tabs
- Extract GamePlay, LineupBuilder, GameStats components from page
- Add manager-aware default tab logic (pending + manager → Lineups tab)
- Implement per-team lineup submission (each team submits independently)
- Add lineup-status endpoint with actual lineup data for recovery
- Fix lineup persistence across tab switches and page refreshes
- Query database directly for pending games (avoids GameState validation)
- Add userTeamIds to auth store for manager detection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 14:08:39 -06:00
Cal Corum
f8435a2fae CLAUDE: UI fixes - lineup builder layout and team order
- Lineup builder: Use layout: false to remove white border/padding
- Create game: Swap team order so Away Team appears above Home Team

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 14:59:03 -06:00
Cal Corum
2dd2b530f8 CLAUDE: Fix lineup builder bugs and improve player image display
Bug fixes:
- Fix pitcher filter to recognize SP, RP, CP positions (not just P)
- Fix validation to allow 9 players when pitcher bats (no DH games)
- Simplify position filters to All/Batters/Pitchers

Image display improvements:
- Use headshot > vanity_card priority (avoid card images in circles)
- Show player initials as fallback (e.g., "AV" for Alex Verdugo)
- Handle name suffixes (Jr, Sr, II, III, IV) correctly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 13:58:02 -06:00
Cal Corum
d65ae19f5e CLAUDE: Add lineup builder polish - search, filters, player preview, visual improvements
Features:
- Player search box with filter by name
- Position filter tabs (All, Catchers, Infielders, Outfielders, Pitchers)
- Player preview modal on click (shows positions, wara rating)
- Clear lineup button with confirmation styling
- Progress bar showing lineup completion
- Player headshots in both roster list and lineup slots
- Skeleton loading state during data fetch
- Sticky navigation header with back button
- Improved visual styling throughout (pills, cards, badges)

TypeScript fixes:
- Added pitcherPlayer computed property for proper type narrowing
- Removed non-existent SbaPlayer stats (batting_average, home_runs, rbi)
- Fixed unused variable warnings

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 10:08:25 -06:00
Cal Corum
a22513b053 CLAUDE: Add schedule_game_id linking for webapp games to external schedules
Enables precise tracking of which webapp games correspond to specific
scheduled matchups from SBA/PD league systems.

Backend:
- Add schedule_game_id column to games table with index
- Create Alembic migration for the new column
- Update QuickCreateRequest to accept schedule_game_id
- Update GameListItem response to include schedule_game_id
- Update DatabaseOperations.create_game() to store the link

Frontend:
- Pass schedule_game_id when creating game from "Play" button
- Add activeScheduleGameMap to track webapp games by schedule ID
- Show "In Progress" (green) link for active games
- Show "Resume" (green) link for pending games
- Show "Play" (blue) button for unstarted games

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 23:55:53 -06:00
Cal Corum
fbbb1cc5da CLAUDE: Add SBA schedule integration with weekly matchup display
Implements schedule viewing from SBA production API with week navigation
and game creation from scheduled matchups. Groups games by team matchup
horizontally with games stacked vertically for space efficiency.

Backend:
- Add schedule routes (/api/schedule/current, /api/schedule/games)
- Add SBA API client methods for schedule data
- Fix multi-worker state isolation (single worker for in-memory state)
- Add Redis migration TODO for future scalability
- Support custom team IDs in quick-create endpoint

Frontend:
- Add Schedule tab as default on home page
- Week navigation with prev/next and "Current Week" jump
- Horizontal group layout (2-6 columns responsive)
- Completed games show score + "Final" badge (no Play button)
- Incomplete games show "Play" button to create webapp game

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 23:39:31 -06:00
Cal Corum
403ba7c90f CLAUDE: Update project plan with HIGH-003 resolution phase fix
Added HIGH-003 task documenting the isMyTurn resolution phase bug
that was discovered and fixed during integration testing. All 6
production blockers now complete.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 23:55:50 -06:00
Cal Corum
38fb76c849 CLAUDE: Fix resolution phase control and add demo mode
Bug fix: During resolution phase (dice rolling), isMyTurn was false
for both players, preventing anyone from seeing the dice roller.
Now the batting team has control during resolution since they read
their card.

Demo mode: myTeamId now returns whichever team needs to act,
allowing single-player testing of both sides.

Changes:
- Add creator_discord_id to GameState (backend + frontend types)
- Add get_current_user_optional dependency for optional auth
- Update quick-create to capture creator's discord_id
- Fix isMyTurn to give batting team control during resolution
- Demo mode: myTeamId returns active team based on phase

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 23:47:21 -06:00
Cal Corum
581bc33f15 CLAUDE: Move games list to index page for better UX
SBA users are already league members - they don't need a marketing page.
Moving the games list to "/" reduces friction by eliminating a redirect.

Changes:
- pages/index.vue: Now shows games list (was marketing/dashboard)
- pages/games/index.vue: Redirects to / for backwards compatibility
- Updated all internal links from /games to /
- Auth callback redirects to / after login

User flow is now:
- Not logged in: / → auth middleware → Discord OAuth → /
- Logged in: / shows games list directly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 20:59:34 -06:00
Cal Corum
39cea607dd CLAUDE: Mark HIGH-001 as complete in project plan
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 20:53:06 -06:00
Cal Corum
a9a3e9992d CLAUDE: Add error boundary UI for WebSocket failures (HIGH-001)
When WebSocket connection fails after max attempts (permanentlyFailed state):
- Show red error banner with "Connection Failed" message and "Try Again" button
- Loading modal distinguishes between connecting/reconnecting/failed states
- "Try Again" button uses manualRetry() to reset state and attempt fresh connection
- Yellow reconnecting banner only shows during active reconnection attempts

Uses permanentlyFailed state and manualRetry() from HIGH-002.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 20:52:34 -06:00
Cal Corum
ac7712d2cc CLAUDE: Mark HIGH-002 as complete in project plan
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 20:49:38 -06:00
Cal Corum
1a7e464990 CLAUDE: Fix infinite WebSocket reconnection loop (HIGH-002)
After max reconnection attempts (10), the stuck state detector was
continuing to retry forever. Now:

- Add permanentlyFailed state flag to track when we've given up
- Set flag and stop stuck state detector when max attempts reached
- Add manualRetry() method for UI to reset state and try again
- Expose permanentlyFailed in public API for error boundary (HIGH-001)

Also marks CRIT-002 and CRIT-002-BACKEND as completed in project plan.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 20:49:04 -06:00
Cal Corum
89a63af2a8 CLAUDE: Fix Nuxt 4 store import in game layout
Add explicit Pinia store imports to layouts/game.vue. Nuxt 4 requires
explicit imports for stores - auto-imports no longer work.

This fixes: ReferenceError: useAuthStore is not defined

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 20:41:04 -06:00
Cal Corum
c5869f5ba2 CLAUDE: Add team ownership to auth flow (CRIT-002)
Backend:
- Add get_teams_by_owner() to SBA API client
- Update /api/auth/me to return user's teams from SBA API
- Add sba_current_season config setting (default: 13)

Frontend:
- Replace hardcoded myTeamId with computed from auth store teams
- Fix isMyTurn logic to check actual team ownership
- Update REFACTORING_PLAN.json

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 20:28:08 -06:00
Cal Corum
f2ce91a239 CLAUDE: Add submitSubstitution unified wrapper for all substitution types
- Add submitSubstitution() method that routes to appropriate internal method
- Remove individual substitution methods from exports (now internal only)
- Add validation for defensive_replacement requiring position parameter
- Update tests to use unified wrapper, add test for validation error

Fixes CRIT-001: Game page called non-existent submitSubstitution method

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 20:00:22 -06:00
Cal Corum
e0c12467b0 CLAUDE: Improve UX with single-click OAuth, enhanced games list, and layout fix
Frontend UX improvements:
- Single-click Discord OAuth from home page (no intermediate /auth page)
- Auto-redirect authenticated users from home to /games
- Fixed Nuxt layout system - app.vue now wraps NuxtPage with NuxtLayout
- Games page now has proper card container with shadow/border styling
- Layout header includes working logout with API cookie clearing

Games list enhancements:
- Display team names (lname) instead of just team IDs
- Show current score for each team
- Show inning indicator (Top/Bot X) for active games
- Responsive header with wrapped buttons on mobile

Backend improvements:
- Added team caching to SbaApiClient (1-hour TTL)
- Enhanced GameListItem with team names, scores, inning data
- Games endpoint now enriches response with SBA API team data

Docker optimizations:
- Optimized Dockerfile using --chown flag on COPY (faster than chown -R)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 16:14:00 -06:00
Cal Corum
7d28eebd24 CLAUDE: Add multi-domain environment configuration support
- Create frontend-sba/.env.example and frontend-pd/.env.example templates
- Fix hardcoded allowedHosts in nuxt.config.ts (now reads NUXT_ALLOWED_HOSTS)
- Add NUXT_ALLOWED_HOSTS support to frontend-pd/nuxt.config.ts
- Update docker-compose.yml with missing env vars:
  - FRONTEND_URL, DISCORD_SERVER_REDIRECT_URI
  - ALLOWED_DISCORD_IDS, WS_HEARTBEAT_INTERVAL, WS_CONNECTION_TIMEOUT
  - NUXT_ALLOWED_HOSTS for both frontends
- Create docker-compose.prod.yml for production overrides
- Update root .env.example with new variables
- Add "Multi-Domain Deployment" section to README.md with checklist
- Update all CLAUDE.md files with environment configuration docs
- Remove obsolete 'version' attribute from docker-compose files

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 13:58:42 -06:00
Cal Corum
751dcaf972 CLAUDE: Fix SSR/hydration issues in WebSocket composable
Refactored useWebSocket.ts to prevent SSR-related connection issues:

- Created ClientState interface to encapsulate all client-only state
- Added getClientState() function with lazy initialization on client only
- Added SSR guards (import.meta.client) to all connection functions
- Reset reactive state on client hydration to ensure clean slate
- Moved heartbeatInterval and stuckStateCheckInterval into ClientState
- Changed NodeJS.Timeout to ReturnType<typeof setTimeout/setInterval>
- Wrapped auth watcher in import.meta.client guard

Root cause: Module-level singleton state was being initialized during
SSR, then persisting in a potentially corrupted state during hydration.
This caused intermittent "Socket exists: no" issues where the browser
wouldn't even attempt WebSocket connections.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 15:29:24 -06:00
Cal Corum
b68e3ceacf CLAUDE: Improve service scripts and fix WebSocket plugin conflict
Service Scripts:
- start-services.sh: Add pre-flight checks, health monitoring, --dev/--prod modes,
  port options, dependency checks, and version logging
- stop-services.sh: Add port 3000 cleanup, verification, --quiet/--force flags
- status-services.sh: New script for monitoring service status with --watch mode

WebSocket:
- Remove conflicting socket.client.ts plugin that was interfering with
  useWebSocket.ts composable (used JWT auth vs cookie auth)
- Add debugging logs to useWebSocket.ts to diagnose intermittent connection issues

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 15:23:41 -06:00
Cal Corum
364c5149a4 CLAUDE: Fix Safari WebSocket connection issues
Frontend fixes for Safari/iPad WebSocket reliability:

1. Add Vite allowedHosts config (nuxt.config.ts)
   - Allow gameplay-demo.manticorum.com for external access
   - Fixes "Blocked request" error after Vite security update

2. Add connection timeout failsafe (useWebSocket.ts)
   - 10-second timeout resets stuck "isConnecting" state
   - Prevents Heisenbug where Safari connections hang indefinitely
   - Auto-schedules reconnection after timeout

3. Add visible debug info to connection modal (games/[id].vue)
   - Shows WS URL, socket status, and connection log
   - Helps diagnose Safari-specific issues without dev tools

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 22:37:53 -06:00
Cal Corum
acd080b437 CLAUDE: Fix Safari/iPad auth failure on game detail page
Root cause: Auth middleware was commented out on game detail page
([id].vue), causing SSR to render without checking authentication.
Safari's client-side auth check wasn't reaching the backend due to
caching behavior, resulting in "Auth: Failed" display.

Changes:
- Re-enabled middleware: ['auth'] in pages/games/[id].vue
- Added /api/auth/ws-token endpoint for Safari WebSocket fallback
- Added expires_minutes param to create_token() for short-lived tokens
- Added token query param support to WebSocket handlers
- Updated SAFARI_WEBSOCKET_ISSUE.md documentation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 21:53:20 -06:00
Cal Corum
646878c572 CLAUDE: Optimize play history sync to O(1) with setPlayHistory
Replaced O(n²) deduplication check per play with O(1) array replacement:
- Added setPlayHistory() for game_state_sync (replaces entire array)
- Simplified addPlayToHistory() for live play_resolved events (just push)

This separates sync operations (replace) from live events (append),
eliminating the need for deduplication checks during gameplay.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 12:41:50 -06:00
Cal Corum
19b35f148b CLAUDE: Load play history on mid-game join via game_state_sync
Backend changes:
- Modified request_game_state handler to fetch plays from database
- Convert Play DB models to frontend-compatible PlayResult dicts
- Emit game_state_sync event with state + recent_plays array

Frontend changes:
- Added deduplication by play_number in addPlayToHistory()
- Prevents duplicate plays when game_state_sync is received

Field mapping from Play model:
- hit_type -> outcome
- result_description -> description
- batter_id -> batter_lineup_id
- batter_final -> batter_result

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 12:38:56 -06:00
Cal Corum
57121b62bd CLAUDE: Add tabbed Recent/Scoring views to PlayByPlay component
Enhanced PlayByPlay with a tabbed interface:
- "Recent" tab shows plays from current half inning only
- "Scoring" tab shows all plays where runs were scored
- Badge counts on each tab show number of matching plays
- Tab-aware empty states with contextual messaging
- Footer shows total game plays count

Removed unused showFilters prop and showAllPlays toggle.

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

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