Files
servesync-demo/backend/app/models/match.py
Forge 46fd2953c3 🏓 Initial ServeSync demo build
- FastAPI backend with PostgreSQL + Redis
- 4 core features: Registration, Courts, Matchmaking, Tournament
- Double elimination tournament with bracket visualization
- ELO-based matchmaking (Stage 1 Open, Stage 2 Skill-Based)
- Real-time WebSocket updates
- TV Screen display for courts
- Vue 3 + Tailwind CSS frontend
- Seed data: 12 players, 4 courts, active matches, tournament in progress
- Docker compose stack with Nginx reverse proxy
2026-03-19 00:58:17 +08:00

74 lines
2.5 KiB
Python

from sqlalchemy import Column, Integer, ForeignKey, DateTime, Float, String, Enum, Boolean, JSON
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from app.database import Base
import enum
class MatchStage(str, enum.Enum):
OPEN = "open"
SKILL_BASED = "skill_based"
TOURNAMENT = "tournament"
class MatchStatus(str, enum.Enum):
LOBBY = "lobby"
IN_PROGRESS = "in_progress"
COMPLETED = "completed"
CANCELLED = "cancelled"
class MatchType(str, enum.Enum):
SINGLES = "singles"
DOUBLES = "doubles"
class Match(Base):
__tablename__ = "matches"
id = Column(Integer, primary_key=True, index=True)
court_id = Column(Integer, ForeignKey("courts.id"), nullable=True)
stage = Column(Enum(MatchStage), default=MatchStage.OPEN)
match_type = Column(Enum(MatchType), default=MatchType.DOUBLES)
status = Column(Enum(MatchStatus), default=MatchStatus.LOBBY)
# Scores
team1_score = Column(Integer, default=0)
team2_score = Column(Integer, default=0)
team1_games = Column(Integer, default=0)
team2_games = Column(Integer, default=0)
# Game details
max_players = Column(Integer, default=4)
min_elo = Column(Float, nullable=True)
max_elo = Column(Float, nullable=True)
# Match metadata
title = Column(String(200))
started_at = Column(DateTime(timezone=True), nullable=True)
ended_at = Column(DateTime(timezone=True), nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
# Relationships
court = relationship("Court", back_populates="matches")
match_players = relationship("MatchPlayer", back_populates="match", cascade="all, delete-orphan")
class MatchPlayer(Base):
__tablename__ = "match_players"
id = Column(Integer, primary_key=True, index=True)
match_id = Column(Integer, ForeignKey("matches.id"), nullable=False)
player_id = Column(Integer, ForeignKey("players.id"), nullable=False)
team = Column(Integer, nullable=False) # 1 or 2
elo_before = Column(Float, nullable=True)
elo_after = Column(Float, nullable=True)
elo_change = Column(Float, default=0.0)
is_winner = Column(Boolean, nullable=True)
joined_at = Column(DateTime(timezone=True), server_default=func.now())
# Relationships
match = relationship("Match", back_populates="match_players")
player = relationship("Player", back_populates="match_players")