Comprehensive documentation of all data models in the Users app
Users App Data Models Documentation
Brand values alignment: All features and data models should align with Courtex values: Community, Transparency, Accessibility, Integrity, Humility. See
docs/markdown/brand/copilot-instructions.mdfor full guidance.
Overview
The Users app is responsible for user identity, authentication metadata, subscription management, and profile information. It extends Django's built-in AbstractUser and adds Courtex-specific fields and behaviour.
Core Models
1. User
The User model is the central identity model for all Courtex users. It extends both TimeStampedModel and Django's AbstractUser.
Key Fields:
- uuid: Unique UUID identifier (non-editable, used for public-facing references)
- gender: Optional gender choice (Male, Female, Other)
- handedness: Optional handedness choice (R Right, L Left, O Other)
- avatar: Foreign key to Avatar model (nullable)
- intent: User's self-identified intent (player or organiser)
- follows: Self-referential M2M to other users (asymmetric; inverse is followed_by)
- stripe_customer_id: Stripe customer ID (unique, nullable)
- has_set_username: Whether the user has explicitly chosen their username (False for new OAuth users)
Inherited from AbstractUser:
- username, email, first_name, last_name, password, is_active, is_staff, date_joined, etc.
Inherited from TimeStampedModel:
- created_at, updated_at, deleted_at
Methods:
- get_latest_mmr(combination): Returns the most recent MMR record for a given combination (singles/doubles)
- add_subscription(plan_name, **kwargs): Creates a new subscription; automatically adds $10 account balance credit for a user's first premium subscription
- create_stripe_customer(): Creates a Stripe customer via the API and stores the ID
Business Logic:
- save() calls full_clean() to enforce field-level validation (e.g., choices)
- On save, auto-creates an AccountBalance record (from the finance app) if one doesn't exist
- On creation, signals auto-create initial singles and doubles MMR records
- On creation, a signal auto-creates a free Subscription
Related Models:
- Subscription: User's active and historical subscriptions
- Avatar: Profile picture
- mmr.MMR: Match-making rating history (via mmr_history related name)
- finance.AccountBalance: Wallet balance (via account_balance related name)
2. Plan
The Plan model defines subscription tiers available in Courtex.
Key Fields:
- name: Tier name; restricted to Free or Premium
- description: Optional text description of the plan
- price: Decimal price of the plan
- stripe_product_id: Stripe product ID (unique, nullable)
- benefits: Optional text listing plan benefits
Inherited from TimeStampedModel:
- created_at, updated_at, deleted_at
Business Logic:
- Feature gating across the app is controlled based on the plan a user is subscribed to
- Only Free and Premium tiers are supported
3. Subscription
The Subscription model tracks a user's subscription to a plan, including Stripe integration details.
Key Fields:
- user: Foreign key to User
- plan: Foreign key to Plan (nullable; DO_NOTHING on delete)
- stripe_subscription_id: Stripe subscription ID (unique, nullable)
- status: Subscription status (see choices below)
- current_period_start: Auto-updated timestamp for the current billing period start
- current_period_end: Optional end of the current billing period
- cancelled_at: Optional timestamp when the subscription was cancelled
Status Choices:
active, trial, pending, past_due, cancelled, expired, suspended, renewal_pending, paused, inactive, failed, upcoming
Inherited from TimeStampedModel:
- created_at, updated_at, deleted_at
Methods:
- is_active(): Returns True if status is active or trial
- cancel_subscription(): Sets status to cancelled and records cancelled_at timestamp
Business Logic:
- clean() validates that a user cannot have more than one active subscription of the same plan
- save() calls full_clean() to enforce validation before saving
- A user can have multiple subscriptions (historical), but only one active per plan
- Free plan subscription is created automatically when a new User is saved
4. Avatar
The Avatar model stores profile picture options that users can select.
Key Fields:
- name: Human-readable name for the avatar
- image_url: Optional URL for an externally hosted avatar image (unique)
- image_file: Optional file upload for an avatar image
Business Logic:
- Users reference an avatar via User.avatar (foreign key)
- Either image_url or image_file can be used; both are optional
5. RestrictedDomain
The RestrictedDomain model stores email domains that are blocked from creating accounts.
Key Fields:
- domain: The email domain to block (e.g., spam.com); must be unique
Business Logic: - Used at account creation time to prevent registrations from known spam or unwanted domains - Checked during the authentication/registration flow
Signals
| Signal | Trigger | Effect |
|---|---|---|
create_initial_mmr |
post_save on User (created=True) |
Creates initial singles and doubles MMR records |
create_initial_subscription |
post_save on User (created=True) |
Creates a free Subscription for the new user |
Related Apps
mmr: MMR history is stored inmmr.MMRand linked toUserfinance:AccountBalanceis created for every user infinance.AccountBalanceclubs:Useris referenced as organiser, member, and owner of clubssport_sessions:Useris linked to RSVP, session attendance, and match historypayments: Stripe webhook events referenceUserfor subscription processing