- Complete rewrite for single Court Manager user - Feature 1: Player Management (CRUD, ELO, skill level) - Feature 2: Court Reservation (timeline, override) - Feature 3: Match Event Builder (3-step wizard) - Step 1: Event setup with player selection + stage calculator - Step 2: Stage configurator (Open/Skill/RR/Tournament) - Step 3: Auto bracket generation - Feature 4: Live Court View (main dashboard, 2x2 grid) - Event Control: score entry, bracket advancement, court assignment - Screen view: TV display per court (/screen/:id) - Seed: 8 players, 4 courts, 1 completed + 1 active event - Routes: / players courts events events/new events/:id screen/:id
129 lines
5.5 KiB
Python
129 lines
5.5 KiB
Python
from datetime import datetime
|
|
from sqlalchemy import Column, Integer, String, Float, Boolean, DateTime, ForeignKey, JSON, Text
|
|
from sqlalchemy.orm import relationship
|
|
from .database import Base
|
|
|
|
|
|
class Player(Base):
|
|
__tablename__ = "players"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String(100), nullable=False)
|
|
contact = Column(String(100), nullable=True)
|
|
skill_level = Column(String(20), nullable=False, default="Beginner") # Beginner/Intermediate/Advanced/Elite
|
|
matches_played = Column(Integer, default=0)
|
|
wins = Column(Integer, default=0)
|
|
losses = Column(Integer, default=0)
|
|
elo = Column(Float, default=1000.0)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
event_players = relationship("EventPlayer", back_populates="player")
|
|
|
|
|
|
class Court(Base):
|
|
__tablename__ = "courts"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String(100), nullable=False)
|
|
court_type = Column(String(100), default="Sport Court")
|
|
status = Column(String(20), default="available") # available/in_use/reserved/maintenance
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
reservations = relationship("CourtReservation", back_populates="court")
|
|
matches = relationship("Match", back_populates="court")
|
|
|
|
|
|
class CourtReservation(Base):
|
|
__tablename__ = "court_reservations"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
court_id = Column(Integer, ForeignKey("courts.id"), nullable=False)
|
|
player_id = Column(Integer, ForeignKey("players.id"), nullable=True)
|
|
group_name = Column(String(100), nullable=True)
|
|
start_time = Column(DateTime, nullable=False)
|
|
end_time = Column(DateTime, nullable=False)
|
|
notes = Column(Text, nullable=True)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
court = relationship("Court", back_populates="reservations")
|
|
player = relationship("Player")
|
|
|
|
|
|
class Event(Base):
|
|
__tablename__ = "events"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String(200), nullable=False)
|
|
format = Column(String(20), default="Singles") # Singles/Doubles
|
|
courts_count = Column(Integer, default=1)
|
|
status = Column(String(20), default="setup") # setup/active/completed
|
|
current_stage_id = Column(Integer, nullable=True)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
started_at = Column(DateTime, nullable=True)
|
|
completed_at = Column(DateTime, nullable=True)
|
|
|
|
event_players = relationship("EventPlayer", back_populates="event", cascade="all, delete-orphan")
|
|
stages = relationship("Stage", back_populates="event", order_by="Stage.order", cascade="all, delete-orphan")
|
|
|
|
|
|
class EventPlayer(Base):
|
|
__tablename__ = "event_players"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
event_id = Column(Integer, ForeignKey("events.id"), nullable=False)
|
|
player_id = Column(Integer, ForeignKey("players.id"), nullable=False)
|
|
skill_level_override = Column(String(20), nullable=True)
|
|
|
|
event = relationship("Event", back_populates="event_players")
|
|
player = relationship("Player", back_populates="event_players")
|
|
|
|
|
|
class Stage(Base):
|
|
__tablename__ = "stages"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
event_id = Column(Integer, ForeignKey("events.id"), nullable=False)
|
|
name = Column(String(100), nullable=False)
|
|
match_type = Column(String(30), nullable=False) # Open/Skill-Based/Round Robin/Tournament
|
|
rounds = Column(Integer, default=1)
|
|
advance_count = Column(Integer, default=0) # 0 = all advance
|
|
status = Column(String(20), default="pending") # pending/active/completed
|
|
order = Column(Integer, default=0)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
event = relationship("Event", back_populates="stages")
|
|
matches = relationship("Match", back_populates="stage", cascade="all, delete-orphan")
|
|
|
|
|
|
class Match(Base):
|
|
__tablename__ = "matches"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
stage_id = Column(Integer, ForeignKey("stages.id"), nullable=False)
|
|
court_id = Column(Integer, ForeignKey("courts.id"), nullable=True)
|
|
round_number = Column(Integer, default=1)
|
|
match_number = Column(Integer, default=1)
|
|
# Singles: player1_id, player2_id
|
|
# Doubles: team1_players and team2_players are JSON lists
|
|
player1_id = Column(Integer, ForeignKey("players.id"), nullable=True)
|
|
player2_id = Column(Integer, ForeignKey("players.id"), nullable=True)
|
|
team1_players = Column(JSON, nullable=True) # [player_id, player_id]
|
|
team2_players = Column(JSON, nullable=True)
|
|
score1 = Column(Integer, nullable=True)
|
|
score2 = Column(Integer, nullable=True)
|
|
winner_id = Column(Integer, ForeignKey("players.id"), nullable=True) # for singles
|
|
winner_team = Column(Integer, nullable=True) # 1 or 2 for doubles
|
|
status = Column(String(20), default="scheduled") # scheduled/in_progress/completed/bye
|
|
bracket_position = Column(String(20), nullable=True) # winners/losers
|
|
next_winner_match_id = Column(Integer, nullable=True)
|
|
next_loser_match_id = Column(Integer, nullable=True)
|
|
scheduled_time = Column(DateTime, nullable=True)
|
|
started_at = Column(DateTime, nullable=True)
|
|
completed_at = Column(DateTime, nullable=True)
|
|
|
|
stage = relationship("Stage", back_populates="matches")
|
|
court = relationship("Court", back_populates="matches")
|
|
player1 = relationship("Player", foreign_keys=[player1_id])
|
|
player2 = relationship("Player", foreign_keys=[player2_id])
|
|
winner = relationship("Player", foreign_keys=[winner_id])
|