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.mdfor 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 setADMIN— Verified by Courtex administratorsORGANISER— Verified by a club or tournament organiserPLAYERS— Verified by all playersVIDEO— 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 verifiedPENDING— Verification in progressVERIFIED— Successfully verifiedREJECTED— 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:Matchis linked toSessionandRoundmmr:MMRrecords referenceMatchandSetto track rating changes per matchusers: Players (player_onethroughplayer_four) areUserinstancesclubs: Matchsportfield usesSportchoices defined in the clubs app