From a22513b05308ee0aac80463e777f56c5c1cf2f29 Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Wed, 14 Jan 2026 23:55:53 -0600 Subject: [PATCH] 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 --- ...d3195c64c_add_schedule_game_id_to_games.py | 37 +++++++++++++++++++ backend/app/api/routes/games.py | 9 ++++- backend/app/database/operations.py | 3 ++ backend/app/models/db_models.py | 3 ++ frontend-sba/pages/index.vue | 34 +++++++++++++++-- frontend-sba/types/game.ts | 14 +++++-- 6 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 backend/alembic/versions/62bd3195c64c_add_schedule_game_id_to_games.py diff --git a/backend/alembic/versions/62bd3195c64c_add_schedule_game_id_to_games.py b/backend/alembic/versions/62bd3195c64c_add_schedule_game_id_to_games.py new file mode 100644 index 0000000..eecc9de --- /dev/null +++ b/backend/alembic/versions/62bd3195c64c_add_schedule_game_id_to_games.py @@ -0,0 +1,37 @@ +"""add schedule_game_id to games + +Revision ID: 62bd3195c64c +Revises: 005 +Create Date: 2026-01-14 23:44:40.038088 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '62bd3195c64c' +down_revision: Union[str, None] = '005' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # Add schedule_game_id column for linking webapp games to external schedule systems + op.add_column( + 'games', + sa.Column('schedule_game_id', sa.Integer(), nullable=True) + ) + # Add index for efficient lookups + op.create_index( + 'ix_games_schedule_game_id', + 'games', + ['schedule_game_id'] + ) + + +def downgrade() -> None: + op.drop_index('ix_games_schedule_game_id', table_name='games') + op.drop_column('games', 'schedule_game_id') diff --git a/backend/app/api/routes/games.py b/backend/app/api/routes/games.py index ac936f1..18275ce 100644 --- a/backend/app/api/routes/games.py +++ b/backend/app/api/routes/games.py @@ -33,6 +33,8 @@ class GameListItem(BaseModel): away_score: int = 0 inning: int | None = None half: str | None = None # 'top' or 'bottom' + # External schedule reference (for linking to SBA/PD schedule systems) + schedule_game_id: int | None = None class CreateGameRequest(BaseModel): @@ -59,6 +61,7 @@ class QuickCreateRequest(BaseModel): home_team_id: int | None = Field(None, description="Home team ID (uses default if not provided)") away_team_id: int | None = Field(None, description="Away team ID (uses default if not provided)") + schedule_game_id: int | None = Field(None, description="External schedule game ID for linking") class LineupPlayerRequest(BaseModel): @@ -219,6 +222,7 @@ async def list_games(): away_score=game.away_score or 0, inning=game.current_inning, half=game.current_half, + schedule_game_id=game.schedule_game_id, ) ) @@ -358,7 +362,7 @@ async def quick_create_game( game_id = uuid4() league_id = "sba" - # Determine team IDs + # Determine team IDs and schedule link use_custom_teams = ( request is not None and request.home_team_id is not None @@ -368,10 +372,12 @@ async def quick_create_game( if use_custom_teams: home_team_id = request.home_team_id away_team_id = request.away_team_id + schedule_game_id = request.schedule_game_id else: # Default demo teams home_team_id = 35 away_team_id = 38 + schedule_game_id = None # Get creator's discord_id from authenticated user creator_discord_id = user.get("discord_id") if user else None @@ -399,6 +405,7 @@ async def quick_create_game( away_team_id=away_team_id, game_mode="friendly", visibility="public", + schedule_game_id=schedule_game_id, ) if use_custom_teams: diff --git a/backend/app/database/operations.py b/backend/app/database/operations.py index 49fe800..bd83efe 100644 --- a/backend/app/database/operations.py +++ b/backend/app/database/operations.py @@ -102,6 +102,7 @@ class DatabaseOperations: home_team_is_ai: bool = False, away_team_is_ai: bool = False, ai_difficulty: str | None = None, + schedule_game_id: int | None = None, ) -> Game: """ Create new game in database. @@ -116,6 +117,7 @@ class DatabaseOperations: home_team_is_ai: Whether home team is AI away_team_is_ai: Whether away team is AI ai_difficulty: AI difficulty if applicable + schedule_game_id: External schedule game ID for linking (SBA, PD, etc.) Returns: Created Game model @@ -134,6 +136,7 @@ class DatabaseOperations: home_team_is_ai=home_team_is_ai, away_team_is_ai=away_team_is_ai, ai_difficulty=ai_difficulty, + schedule_game_id=schedule_game_id, status="pending", ) session.add(game) diff --git a/backend/app/models/db_models.py b/backend/app/models/db_models.py index 7b6a709..3b0904a 100644 --- a/backend/app/models/db_models.py +++ b/backend/app/models/db_models.py @@ -99,6 +99,9 @@ class Game(Base): away_team_is_ai = Column(Boolean, default=False) ai_difficulty = Column(String(20), nullable=True) + # External schedule reference (league-agnostic - works for SBA, PD, etc.) + schedule_game_id = Column(Integer, nullable=True, index=True) + # Timestamps created_at = Column( DateTime, default=lambda: pendulum.now("UTC").naive(), index=True diff --git a/frontend-sba/pages/index.vue b/frontend-sba/pages/index.vue index 8bd313a..54f444a 100755 --- a/frontend-sba/pages/index.vue +++ b/frontend-sba/pages/index.vue @@ -144,11 +144,21 @@ Final + +