Comprehensive documentation of all data models in the Matches app

Matches App Data Models Documentation

Brand values alignment: All features and data models should align with Courtex values: Community, Transparency, Accessibility, Integrity, Humility. Leaderboards and match results should be transparent, accessible, and respectful. See docs/markdown/brand/copilot-instructions.md for full guidance.

Overview

The Matches app tracks individual sport matches, their sets, live point-by-point scoring, verification, and notes. It supports both singles and doubles formats.

Enumerations

Stage (TextChoices)

Tracks the lifecycle phase of a match: - CREATION — Match is being created - PROGRESS — Match is in progress - COMPLETION — Match has been completed - VERIFICATION — Match is awaiting or under verification

Status (TextChoices)

Tracks the operational status of a match: - CREATED — Just created - SCHEDULED — Scheduled for a future time - RESCHEDULED — Previously scheduled, now rescheduled - POSTPONED — Postponed to a later date - IN_PROGRESS — Currently being played - SUSPENDED — Paused mid-match - COMPLETED — Match has concluded - INCOMPLETE — Did not finish - CANCELLED — Match was cancelled

VerificationMethod (TextChoices)

  • NONE — No verification method set
  • ADMIN — Verified by Courtex administrators
  • ORGANISER — Verified by a club or tournament organiser
  • PLAYERS — Verified by all players
  • VIDEO — Verified via a YouTube video link

VerificationStatus (TextChoices)

  • INELIGIBLE — Match cannot be verified (e.g., missing players or incomplete)
  • NOT_VERIFIED — Eligible but not yet verified
  • PENDING — Verification in progress
  • VERIFIED — Successfully verified
  • REJECTED — Verification was rejected

Core Models

1. Match

The Match model represents a single sports match between two teams. Supports singles (2 players) and doubles (4 players) formats.

Key Fields: - uuid: Unique identifier (non-editable) - session: Foreign key to sport_sessions.Session (nullable; CASCADE on delete) - round: Foreign key to sport_sessions.Round (nullable; SET_NULL on delete) - date: Date the match was played - time: Time the match started - combination: Match format — one of MS (Mens Singles), WS (Womens Singles), MD (Mens Doubles), WD (Womens Doubles), XD (Mixed Doubles), NA (Other) - sport: Sport type (inherits Sport choices from clubs; defaults to Badminton) - stage: Current stage of the match (Stage choices) - status: Current status of the match (Status choices) - player_one, player_two: Team 1 players (FKs to User; nullable) - player_three, player_four: Team 2 players (FKs to User; nullable) - winning_team: The winning team (team_one or team_two; nullable)

Inherited from TimeStampedModel: - created_at, updated_at, deleted_at

Properties: - team_one: String representation of Team 1 (single player for singles, two players for doubles) - team_two: String representation of Team 2 - has_all_required_players: Returns True if all required player slots are filled based on match format

Methods (via save()): - Automatically determines winning_team when status is set to COMPLETED, based on sets won - Auto-creates a MatchVerification record for the match if one does not exist - Updates MatchVerification status between NOT_VERIFIED and INELIGIBLE based on eligibility

Business Logic: - A match is eligible for verification only when all required players are linked to user accounts AND the match is COMPLETED - player_one and player_two are Team 1; player_three and player_four are Team 2 - For singles matches, only player_one (Team 1) and player_three (Team 2) are required


2. Set

The Set model represents a single set within a match (e.g., game 1, game 2, game 3).

Key Fields: - match: Foreign key to Match (nullable; CASCADE on delete) - created_by: Foreign key to User who created the set (nullable; SET_NULL on delete) - state: Current state (Status choices; defaults to INCOMPLETE) - set: Set number (1–5); auto-incremented if not provided on creation - winning_team: The winning team for this set (nullable) - team_one_score: Score for Team 1 - team_two_score: Score for Team 2

Meta: - unique_together = ('match', 'set') — prevents duplicate set numbers within a match

Methods: - create_point(winning_team, server, receiver, duration): Adds a point/rally to the set during live scoring (only valid when match is IN_PROGRESS) - delete_last_point(): Removes the most recently recorded point (undo during live scoring)

Business Logic (via save()): - If no set number is provided on creation, auto-increments based on existing sets for the match - Automatically determines winning_team when both scores are present - Sets state to INCOMPLETE if not linked to a match


3. MatchProgression

The MatchProgression model is an audit log recording every stage and status transition a match goes through.

Key Fields: - match: Foreign key to Match (CASCADE on delete) - previous_stage: The stage before the transition - stage: The stage after the transition - previous_status: The status before the transition - status: The status after the transition - exited_at: Optional timestamp when the match left a particular stage/status

Inherited from TimeStampedModel: - created_at, updated_at, deleted_at


4. MatchVerification

The MatchVerification model tracks the verification status and method for a match. One record exists per match.

Key Fields: - match: Foreign key to Match (CASCADE on delete) - verification_method: How the match was verified (VerificationMethod choices) - verification_status: Current verification status (VerificationStatus choices) - verfied_at: Timestamp when verification occurred (note: field name has a typo — verfied_at not verified_at)

Business Logic: - Auto-created by Match.save() whenever a match is saved - Status starts as INELIGIBLE or NOT_VERIFIED based on match completeness and player presence - Upgraded from INELIGIBLE to NOT_VERIFIED automatically when a match becomes eligible


5. PlayerVerification

The PlayerVerification model records an individual player's verification decision for a match.

Key Fields: - match_verification: Foreign key to MatchVerification (CASCADE on delete) - user: Foreign key to User (CASCADE on delete) - verification_status: This player's verification status (VerificationStatus choices) - verfied_at: Timestamp when this player verified (note: field name has a typo — verfied_at)


6. Point

The Point model represents a single rally (point) during live scoring of a match set.

Key Fields: - set: Foreign key to Set (CASCADE on delete) - point_number: Sequential point number within the set (auto-incremented) - duration: Optional duration of the rally - server: Player number who served (1–4) - receiver: Player number who received (1–4) - winning_team: Which team won the rally (team_one or team_two) - created_at: Timestamp when the point was recorded

Meta: - unique_together = ('set', 'point_number') - ordering = ['point_number']

Business Logic (via save()): - Auto-increments point_number on creation based on existing points in the set - On creation, updates the associated set's team_one_score or team_two_score

Business Logic (via delete()): - Decrements the set's score for the winning team when a point is deleted


7. VideoLink

The VideoLink model stores YouTube video links associated with a match or specific set.

Key Fields: - set: Foreign key to Set (nullable; CASCADE on delete) - match: Foreign key to Match (CASCADE on delete) - link: Embed video URL (uses embed_video.fields.EmbedVideoField)


8. Note

The Note model stores user-created notes attached to a match.

Key Fields: - content: Text content of the note (optional) - user: Foreign key to User who wrote the note (PROTECT on delete) - match: Foreign key to Match (nullable; CASCADE on delete)

Inherited from TimeStampedModel: - created_at, updated_at, deleted_at


Relationships Summary

Match ──< Set ──< Point
      │        └──< VideoLink
      │
      ├──< MatchProgression
      ├──< MatchVerification ──< PlayerVerification
      ├──< VideoLink
      └──< Note

Related Apps

  • sport_sessions: Match is linked to Session and Round
  • mmr: MMR records reference Match and Set to track rating changes per match
  • users: Players (player_one through player_four) are User instances
  • clubs: Match sport field uses Sport choices defined in the clubs app