Commit Graph

751 Commits

Author SHA1 Message Date
Thomas Hallock 7ba746b6bd fix: update lockfile and fix Makefile paths
- Update pnpm-lock.yaml with new semantic-release dependencies
- Fix Makefile paths to use packages/core/src/ instead of src/
- All Python scripts now reference correct monorepo structure

Fixes:
- ERR_PNPM_OUTDATED_LOCKFILE in CI workflows
- Missing generate_examples.py in verify-examples workflow

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-07 09:05:41 -05:00
Thomas Hallock 6a51c1e9bd fix: upgrade CI dependencies and fix deprecated actions
- Upgrade pnpm from 8.0.0 to 9.15.4 to fix ERR_INVALID_THIS registry errors
- Upgrade actions/upload-artifact from v3 to v4 (v3 deprecated)
- Add missing semantic-release peer dependencies:
  - @semantic-release/commit-analyzer@^11.0.0
  - @semantic-release/release-notes-generator@^12.0.0

Fixes GitHub Actions failures in:
- Deploy Storybooks workflow
- Release workflow
- Verify Examples workflow

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-07 09:02:22 -05:00
Thomas Hallock af8d993628 fix: lazy-load database connection to prevent build-time access
Refactor db/index.ts to use lazy initialization via Proxy pattern.
This prevents the database from being accessed at module import time,
which was causing Next.js build failures in CI/CD environments where
no database file exists.

The database connection is now created only when first accessed at
runtime, allowing static site generation to complete successfully.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-07 08:41:06 -05:00
Thomas Hallock a9175a050c feat: add arcade room system database schema and managers (Phase 1)
Implement foundational infrastructure for multi-room arcade system:

Database:
- Add arcade_rooms table for room metadata and lifecycle
- Add room_members table for membership tracking
- Add nullable roomId field to arcade_sessions for room association
- Create migration 0003_naive_reptil.sql

Managers:
- Implement room-manager.ts with full CRUD operations
- Implement room-membership.ts for member management
- Add room-code.ts utility for unique room code generation
- Include TTL-based room cleanup functionality

Documentation:
- Add arcade-rooms-technical-plan.md with complete system design
- Add arcade-rooms-implementation-tasks.md with 62-task breakdown

This establishes the foundation for public multiplayer rooms with:
- URL-addressable rooms with unique codes
- Guest user support
- Configurable TTL for automatic cleanup
- Room creator moderation controls

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 15:11:24 -05:00
Thomas Hallock 9165014997 refactor: remove duplicate game control buttons from game phases
Remove duplicate New Game button from GamePhase and update ResultsPhase
to use proper arcade navigation now that controls are in the nav bar.

- Remove New Game button from GamePhase (now in nav)
- Change ResultsPhase "Back to Games" to "Back to Arcade"
- Add proper session exit in ResultsPhase arcade navigation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 14:25:01 -05:00
Thomas Hallock 4758ad2f26 feat: implement game control callbacks in MemoryPairsGame
Connect game control buttons to actual game actions using context
functions for Setup, New Game, and Quit functionality.

- Setup: exit session and navigate to /arcade/matching (returns to setup)
- New Game: call resetGame() from context
- Quit: exit session and navigate to /arcade

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 14:24:51 -05:00
Thomas Hallock fbd8cd4a6b feat: integrate GameControlButtons into navigation
Wire up GameControlButtons through PageWithNav and GameContextNav to
enable game control buttons in the navigation bar during gameplay.

- Add onSetup, onNewGame props to PageWithNav and GameContextNav
- Show GameControlButtons when !showFullscreenSelection && !canModifyPlayers
- Pass callbacks through component hierarchy

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 14:24:40 -05:00
Thomas Hallock 1f45c17e0a feat: add GameControlButtons component with unit tests
Add reusable GameControlButtons component with Setup, New Game, and Quit
buttons for arcade game navigation. Includes comprehensive unit tests.

- Create GameControlButtons component with optional callbacks
- Add flexWrap: nowrap and whiteSpace: nowrap to prevent wrapping
- Write 10 unit tests covering all button behaviors
- All tests passing

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 14:24:31 -05:00
Thomas Hallock 2248c34215 chore: improve logging in arcade session management
Added detailed logging to help debug player ID vs user ID flow:
- useArcadeSocket: Log full move payload with JSON stringification
- session-manager: Log player ID, game state players, and phase info

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 13:27:19 -05:00
Thomas Hallock ea1b1a2f69 fix: require activePlayers in START_GAME, never fallback to userId
START_GAME moves must explicitly provide activePlayers array containing
database player IDs. Removed fallback to [data.userId] which incorrectly
used guest ID as player ID. Server now rejects START_GAME moves that are
missing activePlayers.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 13:27:10 -05:00
Thomas Hallock d00abd25e7 fix: pass player IDs (not user IDs) in all arcade game moves
All game moves now explicitly include the database player ID (avatar ID)
in the playerId field. This fixes multiplayer turn validation which was
failing because it was comparing database player IDs with guest IDs.

- FLIP_CARD: Use state.currentPlayer (database player ID)
- START_GAME/resetGame: Use first active player ID, with validation
- CLEAR_MISMATCH: Use state.currentPlayer

Removed fallback to viewerId which incorrectly conflated user/guest IDs
with player IDs.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 13:27:00 -05:00
Thomas Hallock d5a8a2a14c fix: enforce playerId must be explicitly provided in arcade moves
Player IDs (database avatar IDs) must never be conflated with or fall back
to user/guest IDs. This commit makes playerId a required field in all game
moves and throws an error if missing.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 13:26:49 -05:00
Thomas Hallock 22541df99f fix: use UUID player IDs in session creation fallback
- Changed CreateSessionOptions.activePlayers from number[] to string[]
- Updated socket-server.ts fallback from [1] to [data.userId]
- Added debug logging to validateFlipCard to diagnose turn validation issues

This ensures that when a session is created without explicit activePlayers,
it uses the actual UUID of the requesting player instead of the numeric value 1.
2025-10-06 13:04:33 -05:00
Thomas Hallock ccd0d6d94c fix: use player IDs instead of array indices in matching game
Changed Player type from number to string (UUID) throughout the
matching game to properly identify players by their unique IDs
rather than array positions. This fixes the "Not your turn"
validation errors that were occurring because server-side
validation was comparing UUIDs (move.playerId) with numeric
indices (state.currentPlayer).

Changes:
- Updated Player type from number to string in both arcade and
  games matching context types
- Changed all player tracking to use UUID strings instead of
  numeric indices (1, 2, 3)
- Updated turn validation in MatchingGameValidator to compare
  string IDs correctly
- Fixed all UI components (GameCard, PlayerStatusBar, etc.) to
  use player.findIndex() for array positions when needed
- Updated MatchingStartGameMove type to expect string[] for
  activePlayers
- Re-enabled turn validation (previously disabled as workaround)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 12:49:10 -05:00
Thomas Hallock 619be9859c test: add E2E tests for arcade modal session behavior
Added comprehensive Playwright tests for arcade modal session system:
- Session redirects and persistence
- Player modification blocking during games
- "Return to Arcade" button functionality
- Session lifecycle from creation to end

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 12:21:42 -05:00
Thomas Hallock 7c0e6b142b fix: disable turn validation in arcade mode matching game
Removed turn validation check that was causing "Not your turn" errors.
The validator was comparing player numbers (1, 2, 3) with viewer UUIDs,
which never matched. In arcade mode, a single user controls all players,
so turn validation is not applicable.

- Removed comparison of state.currentPlayer (number) vs playerId (UUID)
- Allows single user to flip cards for any player in arcade mode
- Fixes card flipping functionality in matching game

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 12:21:34 -05:00
Thomas Hallock 70d6f43d6d feat: emit session-state after creating arcade session
Added session-state event emission after creating new arcade session
during START_GAME. This ensures connected clients (like useArcadeRedirect)
are immediately notified of the new session, triggering proper UI updates.

- Fetches newly created session after START_GAME
- Emits session-state to all clients in user's arcade room
- Enables "Return to Arcade" button to appear immediately

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 12:21:24 -05:00
Thomas Hallock 4153929a2a fix: show "Return to Arcade" button only during active game
Modified GameContextNav to only display "Return to Arcade" button when
user cannot modify players (i.e., during active game session). This
prevents the button from appearing during game setup phase.

- Button now conditional on !canModifyPlayers
- Removed incorrect "Setup" button display during setup

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 12:21:15 -05:00
Thomas Hallock c7ad3c0695 fix: allow navigation to game setup pages without active session
Modified useArcadeRedirect to not redirect users away from game pages
when they have no active session. Users can now navigate to game setup
pages to start new sessions.

- Removed redirect logic from onNoActiveSession callback
- Updated canModifyPlayers to allow modification whenever no active session
- Only redirect when user has active session for DIFFERENT game

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 12:21:07 -05:00
Thomas Hallock 3b3cad4b76 feat: add server-side validation for player modifications during active arcade sessions
Prevents users from changing isActive status of players while they have
an active arcade session in progress. Returns 403 error with game info
when blocked.

- Added arcade session check in PATCH /api/players/[id] endpoint
- Enhanced error handling to surface server validation errors to users
- Added comprehensive E2E tests for validation behavior

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 12:20:58 -05:00
Thomas Hallock ff16303a7c feat: add arcade matching game components and utilities
- Add game components (GameCard, GamePhase, SetupPhase, MemoryGrid)
- Add player status bar with multiplayer support
- Add emoji picker for player customization
- Add card generation and validation utilities
- Add game scoring system with combo multipliers
- Add page route for arcade matching game

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 11:04:41 -05:00
Thomas Hallock 9d4cba05be fix: make results screen compact to fit viewport without scrolling
- Use flexbox with space-between for non-scrollable layout
- Reduce all spacing and font sizes for compactness
- Remove performance analysis section
- Add responsive breakpoints for mobile/desktop
- Ensures Play Again button is always visible

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 11:04:29 -05:00
Thomas Hallock ae1318e8bf feat: add Setup button to exit arcade sessions
- Add onExitSession prop to PageWithNav and GameContextNav
- Display Setup button (⚙️) in nav bar during games
- Call exitSession() and reload page to return to setup
- Provides consistent exit UI across all arcade games

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 11:04:22 -05:00
Thomas Hallock abc2ea50d0 feat: add exitSession to MemoryPairsContextValue interface
- Add exitSession method to context type definition
- Enables arcade session cleanup and return to setup

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 11:04:15 -05:00
Thomas Hallock 158f52773d fix: add CLEAR_MISMATCH move to allow mismatch feedback to auto-dismiss
- Add MatchingClearMismatchMove type to arcade validation types
- Implement CLEAR_MISMATCH validation in MatchingGameValidator
- Keep mismatched cards visible briefly (1.5s) so player can see them
- Auto-dismiss mismatch feedback toast after timeout
- Essential for memory gameplay where seeing wrong cards builds memory

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 11:04:03 -05:00
Thomas Hallock 7829d8a0fb fix: move auth.ts to src/ to match @/ path alias
- Moved apps/web/auth.ts to apps/web/src/auth.ts
- Updated import in src/lib/viewer.ts to use @/auth alias
- Fixes 'Module not found: Can't resolve @/auth' error
- This error was not caught in dev due to typescript.ignoreBuildErrors
  but caused production build failures and 500 errors on /api/auth/* endpoints

The @/* path alias resolves to src/*, so auth.ts must be in src/ directory.
Previously, /api/auth/csrf and other NextAuth endpoints returned 500 errors.
2025-10-06 06:46:18 -05:00
Thomas Hallock a216a3d343 fix: add Python setuptools and build tools for better-sqlite3 compilation
- Add python3, py3-setuptools, make, g++ to Alpine base image
- Required for better-sqlite3 native module compilation in Docker build
- Fixes 'ModuleNotFoundError: No module named distutils' error
2025-10-06 06:46:04 -05:00
Thomas Hallock aa1ad315ef feat: add security tests and userId injection protection
Security improvements:
- Add comprehensive e2e tests for userId injection attacks
- Explicitly strip userId from abacus-settings PATCH request body
- Add security comments to player update routes
- Tests verify foreign key and unique constraints prevent attacks
- Document that API layer security is critical (DB constraints insufficient)

Test coverage:
- 12 tests for abacus-settings API (including 3 security tests)
- 11 tests for players API (including 3 security tests)
- All 23 tests passing

Key findings documented in tests:
- Database foreign keys prevent invalid userId references
- Primary key constraints prevent duplicate userIds (abacus_settings)
- For players, userId CAN be changed to another valid userId at DB level
- API layer MUST filter userId from request body and use session-derived userId
- WHERE clauses scope all queries to current user's data

Defense in depth:
1. Session-derived userId (JWT cookie)
2. Explicit userId filtering from request body
3. WHERE clauses limiting scope to user's own data
4. Foreign key constraints (fallback)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 19:57:51 -05:00
Thomas Hallock 92ef1360a4 feat: migrate abacus display settings to database
- Add abacus_settings table with all display configuration fields
- Create API routes (GET/PATCH) for abacus settings
- Add React Query hooks with optimistic updates
- Create AbacusSettingsSync component to bridge localStorage and API
- Settings now persist server-side per guest/user session
- Maintains backward compatibility with existing localStorage pattern

Migration includes:
- Database schema for 12 abacus display settings
- Automatic migration generation and application
- API-driven persistence with guest session support
- Sync component loads from API on mount and saves changes automatically

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 19:34:33 -05:00
Thomas Hallock b62cf26fb6 feat: add optimistic updates and remove dead code
Phase 4 & 5: Cleanup + Optimistic Updates
- Removed dead localStorage types from player.ts
- Added optimistic updates to all player mutations
- Added optimistic updates to stats mutations
- Instant UI feedback with automatic rollback on error

Breaking changes: None

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 18:21:33 -05:00
Thomas Hallock fe01a1fe18 feat: migrate contexts to React Query (remove localStorage)
Phase 3: React Query Integration
- Created useUserPlayers hook with CRUD mutations
- Created useUserStats hook with update mutations
- Rewrote GameModeContext to use API instead of localStorage
- Rewrote UserProfileContext to use API instead of localStorage
- Removed playerMigration.ts (localStorage utilities)
- Maintained backward-compatible interfaces

Technical details:
- All data now persists to SQLite via API
- React Query handles caching, invalidation, and optimistic updates
- Contexts still provide same interface for existing components
- No localStorage dependencies remaining (except sound settings)

Breaking changes:
- None - interfaces remain compatible

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 18:13:32 -05:00
Thomas Hallock 6f940e24d6 feat: add API routes for players and user stats
Phase 2.2: API Routes
- POST /api/players - Create player
- GET /api/players - List user's players
- PATCH /api/players/[id] - Update player
- DELETE /api/players/[id] - Delete player
- GET /api/user-stats - Get user statistics
- PATCH /api/user-stats - Update user statistics

Technical details:
- Middleware passes guest ID via x-guest-id header for same-request access
- API routes use getViewerId() to identify guest/user sessions
- Automatic user record creation on first API access
- Full test coverage (16 tests passing)
- Manual API testing verified with curl

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 18:03:36 -05:00
Thomas Hallock 10d8aaf814 feat: add guest session system with JWT tokens
Phase 1.2: Guest Session System
- Guest token utilities with JWT signing/verification (jose)
- Middleware for automatic guest cookie generation
- NextAuth v5 configuration with guest provider support
- Viewer helper utility for unified session access
- API route handlers for NextAuth
- Comprehensive test coverage (22 tests passing)

Technical details:
- Uses HttpOnly cookies for security
- Conditional cookie naming (__Host- in prod, plain in dev)
- 30-day token expiration with automatic rotation
- No localStorage dependency (fully server-side)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 17:35:18 -05:00
Thomas Hallock 5d5afd4e68 feat: set up Drizzle ORM with SQLite database
Phase 1.1 Complete: Database & Auth Infrastructure

- Configure Drizzle with SQLite and better-sqlite3
- Create schema for users, players, and user_stats tables
- Set up database client with foreign keys and WAL mode enabled
- Add migration runner and package.json scripts
- Generate initial migration (0000_third_carnage.sql)

Database Features:
- Users table with guestId for guest sessions
- Players table with userId FK (cascade delete)
- UserStats table with userId FK (cascade delete)
- Indexes on foreign keys for performance
- Type-safe schema with Drizzle ORM

Testing:
- 20 unit + e2e tests all passing
- Schema validation tests
- Migration idempotency tests
- Foreign key constraint tests
- Cascade delete tests

Scripts added:
- pnpm db:generate - Generate migration from schema
- pnpm db:migrate - Run pending migrations
- pnpm db:push - Push schema directly (dev)
- pnpm db:studio - Visual DB browser
- pnpm db:drop - Drop migration (dev)

User tests verified:
 Migration runs successfully
 Database tables created with correct schema
 Migration is idempotent (can run multiple times)
2025-10-05 17:01:27 -05:00
Thomas Hallock dd0df8c274 docs: add server persistence migration plan
Add comprehensive plan for migrating from localStorage to server-side
database with NextAuth guest sessions.

Key features:
- SQLite + Drizzle ORM with type-safe schema definitions
- NextAuth v5 with JWT strategy for stateless guest sessions
- React Query for client-side data fetching and caching
- Comprehensive testing strategy (unit, e2e, manual)
- Fast-failure approach with no backwards compatibility
- Detailed Drizzle migration setup and workflow
- 5 phases with 10 checkpoints, each with specific tests

Strategy: greenfield approach with hard cutover at each checkpoint,
no localStorage fallbacks, no gradual migration.
2025-10-05 16:55:11 -05:00
Thomas Hallock a3878a8537 feat: add React Query setup with api helper
- Install @tanstack/react-query
- Create QueryClientProvider in ClientProviders with stable client instance
- Add queryClient.ts with createQueryClient() and api() helper
- Add api() helper that wraps fetch with automatic /api prefix
- Add example.ts with complete CRUD hook examples
- Configure sensible defaults (5min staleTime, retry once)

All API routes are now prefixed with /api automatically via api() helper.
2025-10-05 16:55:03 -05:00
Thomas Hallock 1234e6ce60 chore: clean up working tree and update gitignore
Remove unused multiplayer/player code and abandoned e2e tests.
Add gitignore patterns for playwright reports and database files.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 06:59:26 -05:00
Thomas Hallock 5e7b273b33 refactor: split deployment info into server/client components
Refactor to use server component composition pattern where DeploymentInfoContent (server component) imports build info JSON directly and is rendered as a child of DeploymentInfoModal (client component). Eliminates unnecessary API fetch.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 06:43:34 -05:00
Thomas Hallock 43be7ac83a feat: add deployment info modal with keyboard shortcut
Add modal component to view deployment information (version, git commit, build time, etc.) accessible via Cmd/Ctrl+Shift+I keyboard shortcut throughout the app.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 06:37:12 -05:00
Thomas Hallock 571664e725 feat: add build info API endpoint
Add API route to serve deployment information and TypeScript definitions for type safety.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 06:37:05 -05:00
Thomas Hallock 416dc897e2 feat: add build info generation script
Add script to capture deployment metadata (git commit, branch, timestamp, version) at build time and integrate it into the build process.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 06:37:00 -05:00
Thomas Hallock 2e041ddc44 fix: update matching game for UUID player system
- GamePhase: Convert Map to array, map numeric IDs to players
- GameCard: Use active players array for emoji lookup
- PlayerStatusBar: Fix Map.filter, fix duplicate className, fix type comparison
- ResultsPhase: Convert to array-based player lookup, add numericId mapping
- MemoryPairsContext: Create compatibility layer for numeric player IDs
- EmojiPicker: Update import path for PLAYER_EMOJIS
- EmojiPicker test: Update import path

Maintains backward compatibility with internal numeric player tracking
while using UUID-based players from GameModeContext
2025-10-04 17:06:55 -05:00
Thomas Hallock ae4e8fcb5a fix: update race track components for new player system
CircularTrack, LinearTrack, SteamTrainJourney:
- Convert Map to array for active player lookup
- Use player.emoji directly instead of profile.player1Emoji
- Remove hardcoded player ID switch statements
2025-10-04 17:06:55 -05:00
Thomas Hallock 81d17f2397 feat: dynamic player card rendering on games page
- Render player cards from Map instead of hardcoded 1-4
- Support arbitrary number of players
- Use player.color for theming
- Add React import for Fragment usage
2025-10-04 17:06:54 -05:00
Thomas Hallock e85d0415f2 feat: update nav components for UUID players
- Update all player ID types from number to string
- Remove switch statements for player lookups
- Use Map/Set operations instead of array methods
- Support arbitrary number of players
- PlayerConfigDialog now accepts string IDs
2025-10-04 17:06:54 -05:00
Thomas Hallock 2b94cad11b feat: migrate contexts to UUID-based player system
GameModeContext:
- Use Map<string, Player> instead of array
- Use Set<string> for active player tracking
- Add migration support on initialization
- Remove hardcoded 1-4 player limit

UserProfileContext:
- Remove player1-4 fields (moved to GameModeContext)
- Keep only game statistics
- Add stats migration from V1
2025-10-04 17:06:53 -05:00
Thomas Hallock 79f44b25d6 feat: add player types and migration utilities
- Add Player interface with UUID-based id field
- Add PlayerStorageV2 format for new storage schema
- Add migration utilities to convert from V1 (indexed) to V2 (UUID)
- Add validation and rollback support
- Move PLAYER_EMOJIS to shared constants
2025-10-04 17:06:53 -05:00
Thomas Hallock 42b73cf8ee chore: add nanoid dependency
Add nanoid for generating universally unique player IDs
2025-10-04 17:06:53 -05:00
Thomas Hallock 2960eef2b5 debug: add comprehensive passenger boarding debug logging
Adds detailed console logging to capture all state during passenger
boarding and delivery in Steam Sprint mode. When passengers are left
behind, the entire log can be copied and pasted into a new Claude Code
session for immediate debugging.

Debug log includes:
- Train position, speed, momentum, and configuration
- All station positions and details
- Complete passenger states (waiting, boarded, delivered)
- Car positions and occupancy
- Passengers scheduled for delivery in current frame
- Detailed boarding attempt analysis for each waiting passenger
- Distance calculations and eligibility checks per car
- Actual boarding and delivery events

Enable by setting DEBUG_PASSENGER_BOARDING = true in useSteamJourney.ts

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 17:56:21 -05:00
Thomas Hallock e6ebecb09b fix(complement-race): prevent passengers being left behind at delivery stations
The bug occurred when a car reached a station where both:
- A passenger needed to be delivered
- A new passenger was waiting to board

The car appeared occupied during boarding check, then the passenger was delivered,
leaving the new passenger behind.

Fix: Identify passengers to be delivered BEFORE building the occupiedCars map,
and exclude them from the map. This makes cars that are about to become empty
immediately available for new passengers.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 17:48:40 -05:00