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.md for 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 in mmr.MMR and linked to User
  • finance: AccountBalance is created for every user in finance.AccountBalance
  • clubs: User is referenced as organiser, member, and owner of clubs
  • sport_sessions: User is linked to RSVP, session attendance, and match history
  • payments: Stripe webhook events reference User for subscription processing