users

Core identity, authentication and account-state table
SQL Identity Critical
users

Purpose

Stores the primary account record for every user in BattleScore. This table underpins authentication, ownership, subscription state, policy acceptance, account status, and cross-area access to app, TO, and admin functionality.

Role in the system

users
 ├── user_sessions
 ├── password_resets
 ├── email_verifications
 ├── army_lists
 ├── games
 ├── tournaments / TO ownership
 └── referrals / claims / profile flows

Columns

Column Type Null Notes
idbigint unsignedNoPrimary key
emailvarchar(255)NoLogin identity
password_hashvarchar(255)NoHashed password
first_namevarchar(80)YesProfile field
last_namevarchar(80)YesProfile field
display_namevarchar(120)NoPublic/user-facing identifier
roleenum('user','admin')NoAuthorization role
is_activetinyint(1)NoAccount active flag
suspended_atdatetime(3)YesSuspension timestamp
suspension_reasonvarchar(255)YesSuspension reason text
email_verified_atdatetime(3)YesEmail verification completion timestamp
last_login_atdatetime(3)YesMost recent login
failed_login_countintNoLockout support
locked_untildatetime(3)YesTemporary lockout expiry
first_game_usedtinyint(1)NoFree-period logic flag
subscription_statusenum('none','trial','active','past_due','canceled','expired')NoSubscription state
subscription_started_atdatetime(3)YesSubscription start
subscription_expires_atdatetime(3)YesSubscription expiry
cancel_at_period_endtinyint(1)NoBilling lifecycle flag
billing_providervarchar(30)Yese.g. PayPal
billing_customer_idvarchar(80)YesExternal customer identifier
billing_subscription_idvarchar(80)YesExternal subscription identifier
terms_accepted_atdatetime(3)YesTerms acceptance timestamp
privacy_accepted_atdatetime(3)YesPrivacy acceptance timestamp
terms_versionvarchar(20)YesAccepted terms version
privacy_versionvarchar(20)YesAccepted privacy version
marketing_opt_intinyint(1)NoConsent flag
marketing_opt_in_atdatetime(3)YesConsent timestamp
analytics_opt_intinyint(1)NoConsent flag
analytics_opt_in_atdatetime(3)YesConsent timestamp
created_atdatetime(3)NoCreation timestamp
updated_atdatetime(3)NoLast update timestamp
deleted_atdatetime(3)YesSoft delete marker

Keys and indexes

  • PRIMARY KEY (id)
  • UNIQUE KEY ux_users_email (email)
  • UNIQUE KEY ux_users_display_name (display_name)
  • idx_users_role (role)
  • idx_users_subscription_status (subscription_status)
  • idx_users_deleted_at (deleted_at)
  • idx_users_email_verified_at (email_verified_at)

Relationships

Relationship Type Notes
user_sessions.user_id → users.idOne-to-manyActive and historical sessions
password_resets.user_id → users.idOne-to-manyPassword reset requests
email_verifications.user_id → users.idOne-to-manyEmail verification tokens
army_lists.user_id → users.idOne-to-manyArmy ownership
games.user_id / opponent_user_id → users.idReferenced externallyGame ownership and opponents

Used by

  • Signup, login, logout, me, verify, forgot, reset
  • Profile and subscription flows
  • Admin identity management
  • Ownership checks across app, TO and admin

Design notes

  • This table combines identity, auth state, profile data, subscription state, and consent tracking
  • Role support already exists in schema via role, even if not fully enforced everywhere
  • Soft delete exists alongside active/suspended/locked states, so account lifecycle is multi-layered
  • Display name is unique and functions as a public-facing identifier

Risks

  • This table is overloaded and central to nearly every subsystem
  • State combinations can become complex: active vs suspended vs deleted vs locked
  • Subscription and consent logic live alongside auth logic, increasing coupling

Recommended future improvements

  • Document account lifecycle rules explicitly
  • Ensure role-based authorization is consistently enforced everywhere
  • Consider whether subscription data should remain embedded here long-term
  • Add audit/change tracking for high-risk identity updates