feat: Rebuild as Court Manager Dashboard v2

- 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
This commit is contained in:
Nemo
2026-03-19 07:35:51 +08:00
parent e455accc7e
commit 4421f61c24
56 changed files with 2949 additions and 4209 deletions

View File

@@ -1,439 +1,325 @@
"""Seed demo data for ServeSync"""
import sys
"""
Seed data for ServeSync Demo
- 8 players with varied skills
- 4 courts
- 1 completed event (Spring Singles Open)
- 1 in-progress event (Summer Tournament - Round 2)
- Sample court reservations
"""
import os
from sqlalchemy.orm import Session
from app.database import engine, SessionLocal
from app.models.player import Player, MembershipTier
from app.models.court import Court
from app.models.booking import Booking, BookingStatus
from app.models.match import Match, MatchPlayer, MatchStage, MatchStatus, MatchType
from app.models.tournament import Tournament, TournamentEntry, TournamentMatch, TournamentStatus, BracketType, TournamentMatchStatus
import sys
from datetime import datetime, timedelta
import random
sys.path.insert(0, "/app")
os.environ.setdefault("DATABASE_URL", "postgresql://servesync:servesync@db:5432/servesync")
def clear_data(db: Session):
db.query(TournamentMatch).delete()
db.query(TournamentEntry).delete()
db.query(Tournament).delete()
db.query(MatchPlayer).delete()
db.query(Match).delete()
db.query(Booking).delete()
db.query(Court).delete()
db.query(Player).delete()
db.commit()
# Reset sequences
for table in ['players', 'courts', 'bookings', 'matches', 'match_players',
'tournaments', 'tournament_entries', 'tournament_matches']:
try:
db.execute(__import__('sqlalchemy').text(f"ALTER SEQUENCE {table}_id_seq RESTART WITH 1"))
except Exception:
pass
db.commit()
print("Cleared existing data")
from app.database import engine, SessionLocal
from app.models import Base, Player, Court, CourtReservation, Event, EventPlayer, Stage, Match
Base.metadata.create_all(bind=engine)
db = SessionLocal()
def seed_players(db: Session) -> list:
players_data = [
{"name": "Marco Santos", "email": "marco@demo.com", "elo": 1850, "tier": MembershipTier.ELITE, "color": "#EF4444", "wins": 45, "losses": 8},
{"name": "Sofia Reyes", "email": "sofia@demo.com", "elo": 1720, "tier": MembershipTier.ELITE, "color": "#EC4899", "wins": 38, "losses": 12},
{"name": "Carlos Mendez", "email": "carlos@demo.com", "elo": 1630, "tier": MembershipTier.PLATINUM, "color": "#8B5CF6", "wins": 32, "losses": 15},
{"name": "Ana Cruz", "email": "ana@demo.com", "elo": 1580, "tier": MembershipTier.PLATINUM, "color": "#06B6D4", "wins": 28, "losses": 18},
{"name": "Juan Dela Cruz", "email": "juan@demo.com", "elo": 1450, "tier": MembershipTier.GOLD, "color": "#F59E0B", "wins": 22, "losses": 20},
{"name": "Maria Garcia", "email": "maria@demo.com", "elo": 1380, "tier": MembershipTier.GOLD, "color": "#10B981", "wins": 18, "losses": 22},
{"name": "Pedro Lopez", "email": "pedro@demo.com", "elo": 1250, "tier": MembershipTier.SILVER, "color": "#3B82F6", "wins": 14, "losses": 19},
{"name": "Rosa Martinez", "email": "rosa@demo.com", "elo": 1190, "tier": MembershipTier.SILVER, "color": "#F97316", "wins": 11, "losses": 21},
{"name": "Diego Torres", "email": "diego@demo.com", "elo": 1100, "tier": MembershipTier.SILVER, "color": "#84CC16", "wins": 9, "losses": 18},
{"name": "Lucia Flores", "email": "lucia@demo.com", "elo": 980, "tier": MembershipTier.BRONZE, "color": "#14B8A6", "wins": 6, "losses": 20},
{"name": "Miguel Ortega", "email": "miguel@demo.com", "elo": 920, "tier": MembershipTier.BRONZE, "color": "#6366F1", "wins": 4, "losses": 15},
{"name": "Isabella Vega", "email": "isabella@demo.com", "elo": 850, "tier": MembershipTier.BRONZE, "color": "#D946EF", "wins": 2, "losses": 12},
]
# Clear existing data
print("Clearing existing data...")
db.query(Match).delete()
db.query(Stage).delete()
db.query(EventPlayer).delete()
db.query(Event).delete()
db.query(CourtReservation).delete()
db.query(Court).delete()
db.query(Player).delete()
db.commit()
players = []
for pd in players_data:
p = Player(
name=pd["name"],
email=pd["email"],
elo_rating=pd["elo"],
membership_tier=pd["tier"],
avatar_color=pd["color"],
wins=pd["wins"],
losses=pd["losses"],
total_matches=pd["wins"] + pd["losses"],
)
db.add(p)
players.append(p)
# ─── PLAYERS ────────────────────────────────────────────────────────────────
print("Creating players...")
players_data = [
{"name": "Marco Reyes", "contact": "marco@example.com", "skill_level": "Elite", "elo": 1852, "matches_played": 48, "wins": 38, "losses": 10},
{"name": "Ana Santos", "contact": "ana@example.com", "skill_level": "Advanced", "elo": 1645, "matches_played": 35, "wins": 24, "losses": 11},
{"name": "Carlos Tan", "contact": "carlos@example.com", "skill_level": "Advanced", "elo": 1583, "matches_played": 30, "wins": 20, "losses": 10},
{"name": "Diana Flores", "contact": "diana@example.com", "skill_level": "Intermediate", "elo": 1402, "matches_played": 22, "wins": 13, "losses": 9},
{"name": "Tony Garcia", "contact": "tony@example.com", "skill_level": "Intermediate", "elo": 1281, "matches_played": 18, "wins": 9, "losses": 9},
{"name": "Lisa Cruz", "contact": "lisa@example.com", "skill_level": "Intermediate", "elo": 1318, "matches_played": 15, "wins": 8, "losses": 7},
{"name": "Jake Torres", "contact": "jake@example.com", "skill_level": "Beginner", "elo": 883, "matches_played": 8, "wins": 3, "losses": 5},
{"name": "Maria Lim", "contact": "maria@example.com", "skill_level": "Beginner", "elo": 947, "matches_played": 10, "wins": 4, "losses": 6},
]
db.commit()
for p in players:
db.refresh(p)
print(f"Created {len(players)} players")
return players
players = []
for pd in players_data:
p = Player(**pd)
db.add(p)
players.append(p)
db.commit()
for p in players:
db.refresh(p)
print(f" Created {len(players)} players")
# ─── COURTS ─────────────────────────────────────────────────────────────────
print("Creating courts...")
courts_data = [
{"name": "Court A", "court_type": "Sport Court Premium", "status": "available"},
{"name": "Court B", "court_type": "Sport Court Premium", "status": "available"},
{"name": "Court C", "court_type": "Cushioned Tournament Grade", "status": "in_use"},
{"name": "Court D", "court_type": "Cushioned Tournament Grade", "status": "in_use"},
]
courts = []
for cd in courts_data:
c = Court(**cd)
db.add(c)
courts.append(c)
db.commit()
for c in courts:
db.refresh(c)
print(f" Created {len(courts)} courts")
def seed_courts(db: Session) -> list:
courts_data = [
{"name": "Court 1", "number": 1, "rate": 200.0, "surface": "Sport Court", "features": "LED Lighting, Pro Net System"},
{"name": "Court 2", "number": 2, "rate": 200.0, "surface": "Sport Court", "features": "LED Lighting, Spectator Seating"},
{"name": "Court 3", "number": 3, "rate": 250.0, "surface": "Cushioned", "features": "Tournament Grade, Scoreboards"},
{"name": "Court 4", "number": 4, "rate": 250.0, "surface": "Cushioned", "features": "Tournament Grade, VIP Lounge Access"},
]
# ─── RESERVATIONS ───────────────────────────────────────────────────────────
print("Creating reservations...")
now = datetime.utcnow()
today_2pm = now.replace(hour=6, minute=0, second=0, microsecond=0) + timedelta(hours=8) # 2pm PHT = 6am UTC
today_4pm = today_2pm + timedelta(hours=2)
tomorrow_10am = (now + timedelta(days=1)).replace(hour=2, minute=0, second=0, microsecond=0)
tomorrow_12pm = tomorrow_10am + timedelta(hours=2)
courts = []
for cd in courts_data:
c = Court(
name=cd["name"],
court_number=cd["number"],
hourly_rate=cd["rate"],
surface_type=cd["surface"],
features=cd["features"],
)
db.add(c)
courts.append(c)
reservations = [
CourtReservation(court_id=courts[0].id, player_id=players[5].id,
group_name="Lisa Cruz Group", start_time=today_2pm, end_time=today_4pm,
notes="Training session"),
CourtReservation(court_id=courts[1].id, group_name="Maintenance Crew",
start_time=tomorrow_10am, end_time=tomorrow_12pm,
notes="Net replacement and floor inspection"),
]
for r in reservations:
db.add(r)
db.commit()
db.commit()
for c in courts:
db.refresh(c)
print(f"Created {len(courts)} courts")
return courts
# ─── EVENT 1: SPRING SINGLES OPEN (Completed) ────────────────────────────────
print("Creating completed event...")
event1 = Event(
name="Spring Singles Open",
format="Singles",
courts_count=2,
status="completed",
created_at=now - timedelta(days=7),
started_at=now - timedelta(days=7, hours=2),
completed_at=now - timedelta(days=7),
)
db.add(event1)
db.commit()
db.refresh(event1)
# Add all 8 players to event1
for p in players:
ep = EventPlayer(event_id=event1.id, player_id=p.id, skill_level_override=p.skill_level)
db.add(ep)
db.commit()
def seed_bookings(db: Session, players: list, courts: list):
now = datetime.utcnow()
bookings = []
# Stage 1 - Open Stage (completed)
stage1_e1 = Stage(event_id=event1.id, name="Open Stage", match_type="Open",
rounds=2, advance_count=4, status="completed", order=0)
db.add(stage1_e1)
db.commit()
db.refresh(stage1_e1)
# Future bookings
for i in range(8):
player = players[i % len(players)]
court = courts[i % len(courts)]
start = now + timedelta(hours=i + 2)
end = start + timedelta(hours=1)
b = Booking(
player_id=player.id,
court_id=court.id,
start_time=start,
end_time=end,
duration_hours=1.0,
total_cost=court.hourly_rate,
status=BookingStatus.CONFIRMED,
)
db.add(b)
bookings.append(b)
# Stage 2 - Tournament (completed)
stage2_e1 = Stage(event_id=event1.id, name="Finals Tournament", match_type="Tournament",
rounds=3, advance_count=0, status="completed", order=1)
db.add(stage2_e1)
db.commit()
db.refresh(stage2_e1)
db.commit()
print(f"Created {len(bookings)} bookings")
def seed_active_matches(db: Session, players: list, courts: list) -> list:
matches = []
# Match 1: Active doubles on Court 1 (Open match)
m1 = Match(
court_id=courts[0].id,
stage=MatchStage.OPEN,
match_type=MatchType.DOUBLES,
status=MatchStatus.IN_PROGRESS,
title="Open Doubles - Court 1",
max_players=4,
team1_score=7,
team2_score=5,
started_at=datetime.utcnow() - timedelta(minutes=25),
# Create completed open stage matches
open_matches = [
(players[0], players[7], 21, 8), # Marco vs Maria
(players[1], players[6], 21, 14), # Ana vs Jake
(players[2], players[5], 21, 11), # Carlos vs Lisa
(players[3], players[4], 21, 18), # Diana vs Tony
# Round 2
(players[0], players[6], 21, 10), # Marco vs Jake
(players[1], players[4], 21, 16), # Ana vs Tony
(players[2], players[7], 21, 9), # Carlos vs Maria
(players[3], players[5], 18, 21), # Diana vs Lisa (Lisa wins!)
]
completed_at_base = now - timedelta(days=7, hours=1, minutes=30)
for i, (p1, p2, s1, s2) in enumerate(open_matches):
winner = p1 if s1 > s2 else p2
m = Match(
stage_id=stage1_e1.id,
court_id=courts[i % 2].id,
round_number=1 if i < 4 else 2,
match_number=(i % 4) + 1,
player1_id=p1.id, player2_id=p2.id,
score1=s1, score2=s2,
winner_id=winner.id,
status="completed",
bracket_position="main",
started_at=completed_at_base + timedelta(minutes=i * 20),
completed_at=completed_at_base + timedelta(minutes=i * 20 + 18),
)
db.add(m1)
db.flush()
db.add(m)
db.commit()
for player_id, team in [(players[0].id, 1), (players[1].id, 1), (players[2].id, 2), (players[3].id, 2)]:
mp = MatchPlayer(match_id=m1.id, player_id=player_id, team=team, elo_before=db.query(Player).filter(Player.id == player_id).first().elo_rating)
db.add(mp)
matches.append(m1)
# Tournament bracket for event 1 (QF, SF, Final)
# Top 4 by round wins: Marco, Ana, Carlos, Lisa
top4 = [players[0], players[1], players[2], players[5]] # Marco, Ana, Carlos, Lisa
# Match 2: Active skill-based on Court 2
m2 = Match(
court_id=courts[1].id,
stage=MatchStage.SKILL_BASED,
match_type=MatchType.DOUBLES,
status=MatchStatus.IN_PROGRESS,
title="Skill Match - Platinum League",
max_players=4,
min_elo=1300,
max_elo=1700,
team1_score=3,
team2_score=6,
started_at=datetime.utcnow() - timedelta(minutes=15),
# QF matches
qf1 = Match(stage_id=stage2_e1.id, court_id=courts[0].id, round_number=1, match_number=1,
player1_id=top4[0].id, player2_id=top4[3].id, score1=21, score2=13,
winner_id=top4[0].id, status="completed", bracket_position="winners",
started_at=now - timedelta(days=7, minutes=90),
completed_at=now - timedelta(days=7, minutes=72))
qf2 = Match(stage_id=stage2_e1.id, court_id=courts[1].id, round_number=1, match_number=2,
player1_id=top4[1].id, player2_id=top4[2].id, score1=21, score2=19,
winner_id=top4[1].id, status="completed", bracket_position="winners",
started_at=now - timedelta(days=7, minutes=90),
completed_at=now - timedelta(days=7, minutes=70))
db.add(qf1); db.add(qf2); db.commit()
db.refresh(qf1); db.refresh(qf2)
# Final
final = Match(stage_id=stage2_e1.id, court_id=courts[2].id, round_number=2, match_number=1,
player1_id=top4[0].id, player2_id=top4[1].id, score1=21, score2=17,
winner_id=top4[0].id, status="completed", bracket_position="winners",
started_at=now - timedelta(days=7, minutes=45),
completed_at=now - timedelta(days=7, minutes=25))
db.add(final); db.commit()
# Link bracket
qf1.next_winner_match_id = final.id
qf2.next_winner_match_id = final.id
event1.current_stage_id = stage2_e1.id
db.commit()
print(f" Completed event created: {event1.name}")
# ─── EVENT 2: SUMMER TOURNAMENT (In Progress, Round 2) ───────────────────────
print("Creating in-progress event...")
event2 = Event(
name="Summer Tournament",
format="Singles",
courts_count=2,
status="active",
created_at=now - timedelta(hours=3),
started_at=now - timedelta(hours=2),
)
db.add(event2)
db.commit()
db.refresh(event2)
# Add 8 players
for p in players:
ep = EventPlayer(event_id=event2.id, player_id=p.id)
db.add(ep)
db.commit()
# Stage 1: Open Stage (completed)
stage1_e2 = Stage(event_id=event2.id, name="Open Stage", match_type="Open",
rounds=1, advance_count=4, status="completed", order=0)
db.add(stage1_e2)
db.commit()
db.refresh(stage1_e2)
# Stage 1 completed matches
s1_matches = [
(players[0], players[7], 21, 6, "completed"),
(players[1], players[6], 21, 11, "completed"),
(players[2], players[5], 21, 15, "completed"),
(players[3], players[4], 21, 19, "completed"),
]
for i, (p1, p2, s1, s2, status) in enumerate(s1_matches):
winner = p1 if s1 > s2 else p2
m = Match(
stage_id=stage1_e2.id,
court_id=courts[i % 2].id,
round_number=1, match_number=i + 1,
player1_id=p1.id, player2_id=p2.id,
score1=s1, score2=s2, winner_id=winner.id,
status=status, bracket_position="main",
started_at=now - timedelta(hours=2, minutes=30),
completed_at=now - timedelta(hours=1, minutes=45),
)
db.add(m2)
db.flush()
db.add(m)
db.commit()
for player_id, team in [(players[4].id, 1), (players[5].id, 1), (players[6].id, 2), (players[7].id, 2)]:
mp = MatchPlayer(match_id=m2.id, player_id=player_id, team=team, elo_before=db.query(Player).filter(Player.id == player_id).first().elo_rating)
db.add(mp)
matches.append(m2)
# Stage 2: Tournament (Active, Round 2 in progress)
stage2_e2 = Stage(event_id=event2.id, name="Finals Tournament", match_type="Tournament",
rounds=3, advance_count=0, status="active", order=1)
db.add(stage2_e2)
db.commit()
db.refresh(stage2_e2)
event2.current_stage_id = stage2_e2.id
# Match 3: Lobby (waiting for players)
m3 = Match(
stage=MatchStage.OPEN,
match_type=MatchType.DOUBLES,
status=MatchStatus.LOBBY,
title="Evening Open Game",
max_players=4,
# Tournament bracket - 8 players → QF (R1), SF (R2), Final (R3)
# QF: Round 1 (all completed)
qf_matches = [
(players[0], players[7], 21, 8, "completed", courts[0].id),
(players[1], players[6], 21, 13, "completed", courts[1].id),
(players[2], players[5], 21, 16, "completed", None),
(players[3], players[4], 19, 21, "completed", None), # Tony beats Diana!
]
# SF: Round 2 (2 in progress, 0 completed)
sf_matches = [
(players[0], players[1], None, None, "in_progress", courts[2].id), # Marco vs Ana - LIVE
(players[2], players[4], None, None, "in_progress", courts[3].id), # Carlos vs Tony - LIVE
]
# Final: Round 3 (scheduled)
final_e2 = Match(
stage_id=stage2_e2.id, court_id=None,
round_number=3, match_number=1,
player1_id=None, player2_id=None,
status="scheduled", bracket_position="winners",
)
db.add(final_e2); db.flush(); db.refresh(final_e2)
# Create QF matches
qf_db = []
for i, (p1, p2, s1, s2, status, court_id) in enumerate(qf_matches):
winner = p1 if (s1 and s1 > s2) else p2
m = Match(
stage_id=stage2_e2.id, court_id=court_id,
round_number=1, match_number=i + 1,
player1_id=p1.id, player2_id=p2.id,
score1=s1, score2=s2, winner_id=winner.id if status == "completed" else None,
status=status, bracket_position="winners",
started_at=now - timedelta(hours=1, minutes=30),
completed_at=now - timedelta(hours=1) if status == "completed" else None,
)
db.add(m3)
db.flush()
db.add(m)
qf_db.append(m)
for player_id, team in [(players[8].id, 1), (players[9].id, 2)]:
mp = MatchPlayer(match_id=m3.id, player_id=player_id, team=team, elo_before=db.query(Player).filter(Player.id == player_id).first().elo_rating)
db.add(mp)
matches.append(m3)
db.commit()
for m in qf_db:
db.refresh(m)
# Match 4: Skill-based lobby
m4 = Match(
stage=MatchStage.SKILL_BASED,
match_type=MatchType.DOUBLES,
status=MatchStatus.LOBBY,
title="Gold Tier Challenge",
max_players=4,
min_elo=1200,
max_elo=1600,
# Create SF matches
sf_db = []
for i, (p1, p2, s1, s2, status, court_id) in enumerate(sf_matches):
m = Match(
stage_id=stage2_e2.id, court_id=court_id,
round_number=2, match_number=i + 1,
player1_id=p1.id, player2_id=p2.id,
score1=s1, score2=s2,
status=status, bracket_position="winners",
started_at=now - timedelta(minutes=15) if status == "in_progress" else None,
next_winner_match_id=final_e2.id,
)
db.add(m4)
db.flush()
db.add(m)
sf_db.append(m)
db.commit()
mp = MatchPlayer(match_id=m4.id, player_id=players[4].id, team=1, elo_before=players[4].elo_rating)
db.add(mp)
matches.append(m4)
# Link QF to SF
qf_db[0].next_winner_match_id = sf_db[0].id
qf_db[1].next_winner_match_id = sf_db[0].id
qf_db[2].next_winner_match_id = sf_db[1].id
qf_db[3].next_winner_match_id = sf_db[1].id
db.commit()
db.commit()
for m in matches:
db.refresh(m)
print(f"Created {len(matches)} matches (2 active, 2 lobby)")
return matches
print(f" In-progress event created: {event2.name}")
def seed_tournament(db: Session, players: list, courts: list):
"""Create a sample double elimination tournament in progress"""
t = Tournament(
name="ServeSync Grand Prix - March 2024",
status=TournamentStatus.IN_PROGRESS,
max_participants=8,
current_round=2,
started_at=datetime.utcnow() - timedelta(hours=2),
)
db.add(t)
db.flush()
# Register 8 players
tournament_players = players[:8]
entries = []
for i, player in enumerate(tournament_players):
entry = TournamentEntry(
tournament_id=t.id,
player_id=player.id,
seed=i + 1,
wins=0,
losses=0,
)
db.add(entry)
entries.append(entry)
db.flush()
# Round 1 Winners Bracket (4 matches) - all completed
r1_matches = [
(players[0].id, players[7].id, 11, 5), # 1 vs 8
(players[1].id, players[6].id, 11, 7), # 2 vs 7
(players[2].id, players[5].id, 8, 11), # 3 vs 6 - player 5 wins
(players[3].id, players[4].id, 11, 9), # 4 vs 5
]
winners_r1 = [] # winner player IDs after round 1
losers_r1 = [] # loser player IDs after round 1
for i, (p1_id, p2_id, s1, s2) in enumerate(r1_matches):
tm = TournamentMatch(
tournament_id=t.id,
round_number=1,
match_number=i + 1,
bracket_type=BracketType.WINNERS,
status=TournamentMatchStatus.COMPLETED,
player1_id=p1_id,
player2_id=p2_id,
team1_score=s1,
team2_score=s2,
winner_team=1 if s1 > s2 else 2,
completed_at=datetime.utcnow() - timedelta(hours=1, minutes=30),
)
db.add(tm)
winner_id = p1_id if s1 > s2 else p2_id
loser_id = p2_id if s1 > s2 else p1_id
winners_r1.append(winner_id)
losers_r1.append(loser_id)
# Update entry stats
for entry in entries:
if entry.player_id == winner_id:
entry.wins += 1
elif entry.player_id == loser_id:
entry.losses += 1
entry.is_in_losers = True
db.flush()
# Round 2 Winners Bracket - 2 matches - 1 completed, 1 in progress
# Match 1: players[0] vs players[1]
wm1 = TournamentMatch(
tournament_id=t.id,
round_number=2,
match_number=1,
bracket_type=BracketType.WINNERS,
status=TournamentMatchStatus.COMPLETED,
player1_id=winners_r1[0],
player2_id=winners_r1[1],
team1_score=11,
team2_score=8,
winner_team=1,
completed_at=datetime.utcnow() - timedelta(minutes=45),
)
db.add(wm1)
# Update entries
for entry in entries:
if entry.player_id == winners_r1[0]:
entry.wins += 1
elif entry.player_id == winners_r1[1]:
entry.losses += 1
entry.is_in_losers = True
# Match 2: players[3] (seed4 winner) vs players[5] (seed6 winner)
wm2 = TournamentMatch(
tournament_id=t.id,
round_number=2,
match_number=2,
bracket_type=BracketType.WINNERS,
status=TournamentMatchStatus.IN_PROGRESS,
player1_id=winners_r1[2],
player2_id=winners_r1[3],
team1_score=6,
team2_score=7,
)
db.add(wm2)
# Assign court 3 for active tournament match
m_active = Match(
court_id=courts[2].id,
stage=MatchStage.TOURNAMENT,
match_type=MatchType.SINGLES,
status=MatchStatus.IN_PROGRESS,
title=f"Tournament R2 - {db.query(Player).filter(Player.id == winners_r1[2]).first().name} vs {db.query(Player).filter(Player.id == winners_r1[3]).first().name}",
max_players=2,
team1_score=6,
team2_score=7,
started_at=datetime.utcnow() - timedelta(minutes=20),
)
db.add(m_active)
db.flush()
for player_id, team in [(winners_r1[2], 1), (winners_r1[3], 2)]:
mp = MatchPlayer(match_id=m_active.id, player_id=player_id, team=team,
elo_before=db.query(Player).filter(Player.id == player_id).first().elo_rating)
db.add(mp)
# Losers Bracket Round 1 - 2 matches (losers from r1 matched up)
lb1 = TournamentMatch(
tournament_id=t.id,
round_number=1,
match_number=1,
bracket_type=BracketType.LOSERS,
status=TournamentMatchStatus.COMPLETED,
player1_id=losers_r1[0],
player2_id=losers_r1[1],
team1_score=9,
team2_score=11,
winner_team=2,
completed_at=datetime.utcnow() - timedelta(minutes=90),
)
db.add(lb1)
lb2 = TournamentMatch(
tournament_id=t.id,
round_number=1,
match_number=2,
bracket_type=BracketType.LOSERS,
status=TournamentMatchStatus.COMPLETED,
player1_id=losers_r1[2],
player2_id=losers_r1[3],
team1_score=11,
team2_score=6,
winner_team=1,
completed_at=datetime.utcnow() - timedelta(minutes=60),
)
db.add(lb2)
# Update loser entries
for entry in entries:
if entry.player_id == losers_r1[0]:
entry.losses += 1
entry.is_eliminated = True
entry.final_rank = 8
elif entry.player_id == losers_r1[3]:
entry.losses += 1
entry.is_eliminated = True
entry.final_rank = 7
db.commit()
db.refresh(t)
print(f"Created tournament: {t.name}")
return t
def seed_completed_matches(db: Session, players: list, courts: list):
"""Create some historical completed matches"""
past_matches = []
for i in range(6):
start = datetime.utcnow() - timedelta(days=i + 1, hours=2)
p_list = random.sample(players, 4)
m = Match(
court_id=courts[i % len(courts)].id,
stage=MatchStage.OPEN if i % 2 == 0 else MatchStage.SKILL_BASED,
match_type=MatchType.DOUBLES,
status=MatchStatus.COMPLETED,
title=f"Completed Match #{i + 1}",
max_players=4,
team1_score=11,
team2_score=random.randint(5, 10),
started_at=start,
ended_at=start + timedelta(hours=1),
)
db.add(m)
db.flush()
for player, team in zip(p_list, [1, 1, 2, 2]):
mp = MatchPlayer(match_id=m.id, player_id=player.id, team=team,
elo_before=player.elo_rating, elo_after=player.elo_rating + random.uniform(-10, 10),
elo_change=random.uniform(-10, 10), is_winner=(team == 1))
db.add(mp)
past_matches.append(m)
db.commit()
print(f"Created {len(past_matches)} completed matches")
def main():
print("🌱 Seeding ServeSync demo data...")
db = SessionLocal()
try:
clear_data(db)
players = seed_players(db)
courts = seed_courts(db)
seed_bookings(db, players, courts)
seed_active_matches(db, players, courts)
seed_tournament(db, players, courts)
seed_completed_matches(db, players, courts)
print("✅ Seed complete!")
finally:
db.close()
if __name__ == "__main__":
main()
db.close()
print("\n✅ Seed complete!")
print(f" Players: {len(players)}")
print(f" Courts: {len(courts)}")
print(f" Events: 2 (1 completed, 1 active)")
print(f" Courts C & D: in_use (live matches)")