Skip to content

Sport Tech Club - UML Class Diagram ​

Comprehensive Domain Model: Complete representation of all entities, relationships, and business logic in the Sport Tech Club system.


Table of Contents ​

  1. Complete System Class Diagram
  2. Core Domain Models
  3. Supporting Domain Models
  4. Generic Domain Models
  5. Enumerations
  6. Relationships Summary

Complete System Class Diagram ​


Core Domain Models ​

Identity & Access Context ​

The Identity & Access context manages authentication, authorization, and user lifecycle.

Key Classes:

  • User: Aggregate root representing a system user with authentication credentials and profile
  • Session: Manages JWT-based authentication sessions with expiry and refresh capabilities
  • Role: Enum defining role-based access control (RBAC) levels
  • TenantMembership: Value object linking users to arena tenants with permissions

Business Rules:

  • Email must be unique across the system
  • Password requires minimum 8 characters with complexity rules
  • MFA is mandatory for ARENA_OWNER and administrative roles
  • Sessions expire after 24 hours, refresh tokens after 7 days
  • Users can be members of multiple arenas (multi-tenancy)

Arena Management Context ​

Manages the physical infrastructure and operational configuration of arenas.

Key Classes:

  • Arena: Aggregate root representing a sports facility with courts, areas, and operational rules
  • Court: Entity representing a playable space with sport type, surface, and availability status
  • CourtProfile: Value object defining recommended usage patterns and player requirements
  • OperatingCalendar: Defines regular hours and special dates (holidays, events)
  • ArenaSettings: Centralized configuration for booking policies, pricing, and queue rules

Business Rules:

  • CNPJ must be valid and unique per arena
  • Operating hours must not overlap with special dates
  • Court capacity must be enforced based on sport type
  • Priority scoring determines court allocation preferences
  • Maintenance blocks override all other reservations

Courts & Allocation Context (CORE) ​

⭐ Core Domain - Intelligent court allocation and queue management system.

Key Classes:

  • AllocationEngine: Service that orchestrates the complex allocation logic using multiple rules
  • PlayerQueue: Entity managing FIFO queue with priority adjustments
  • QueueEntry: Value object representing a player's position with metadata
  • AllocationRule: Strategy pattern for pluggable allocation algorithms
  • WinnerStaysRule: Implements "winner stays, loser rotates" gameplay mode

Business Rules:

  • Allocation considers: skill level, wait time, membership tier, court preferences
  • Winner can stay maximum 3 consecutive victories
  • Teams are formed automatically based on skill rating (ELO-based)
  • Priority formula: priority = (membershipTier * 10) + (waitMinutes * 0.5) - (todayGames * 2)
  • Queue entries timeout after 2 minutes when called
  • Court profile matching ensures compatible skill levels play together

Allocation Algorithm:

typescript
// Pseudocode for allocation decision
function allocateNext(courtId: UUID): AllocationResult {
  const court = getCourt(courtId)
  const queue = getQueue(courtId)
  const requiredPlayers = court.capacity
  
  // Get top N players from queue
  const candidates = queue.getNext(requiredPlayers)
  
  // Validate compatibility
  if (!areCompatible(candidates, court.profile)) {
    return AllocationResult.NoMatch
  }
  
  // Balance teams if needed
  const teams = balanceTeams(candidates)
  
  // Execute allocation
  court.allocate(teams)
  queue.remove(candidates)
  
  return AllocationResult.Success(teams)
}

Scheduling Context (CORE) ​

⭐ Core Domain - Unified multi-purpose booking system.

Key Classes:

  • Booking: Aggregate root for all types of reservations (court rental, lessons, events)
  • TimeRange: Value object with validation and overlap detection
  • BookingPolicy: Encapsulates cancellation rules, advance notice requirements
  • Participant: Represents additional people involved in a booking

Business Rules:

  • Minimum advance booking: 2 hours (configurable per arena)
  • Maximum advance booking: 30 days
  • Cancellation >24h: 100% refund
  • Cancellation 2-24h: 50% refund
  • Cancellation <2h: no refund
  • No-show policy: 3 strikes = 7-day suspension
  • Check-in required within 15 minutes of start time
  • Bookings cannot overlap on the same court

State Machine:

PENDING → CONFIRMED → IN_PROGRESS → COMPLETED
                 ↓           ↓
              CANCELLED   NO_SHOW

Wallet & Value Context (CORE) ​

⭐ Core Domain - Internal economy with tokens, transactions, and stakes.

Key Classes:

  • Wallet: Aggregate root with event sourcing for full audit trail
  • Balance: Multi-currency support (BRL, USD, ARENA_TOKEN) with locked/available amounts
  • Transaction: Immutable ledger entry with idempotency key
  • MatchStakes: Stakes placed on matches with automatic distribution

Business Rules:

  • All transactions are idempotent (duplicate protection via idempotencyKey)
  • Wallet uses event sourcing: state reconstructed from transaction history
  • Token exchange rate defined per arena (e.g., 1 token = R$ 0.10)
  • Locked balance cannot be withdrawn (used for pending stakes)
  • Transaction history is immutable and auditable
  • Arena takes 10% commission on stake winnings

Event Sourcing Events:

  • WalletCreated
  • FundsCredited
  • FundsDebited
  • FundsTransferred
  • FundsLocked
  • FundsUnlocked
  • TransactionCompleted
  • TransactionFailed

Supporting Domain Models ​

Lessons & Coaching Context ​

Key Classes:

  • Lesson: Aggregate root for structured teaching sessions
  • Instructor: Certified professional with specialties and availability
  • Student: Enrolled participant with progress tracking
  • Attendance: Records presence with status (present, absent, late, excused)

Business Rules:

  • Instructors can only teach sports they're certified in
  • Group lessons limited by court capacity
  • Attendance tracked automatically via check-in
  • Students can evaluate instructors (1-5 stars)
  • Payment split: 70% instructor, 30% arena

Play & Match Context ​

Key Classes:

  • Match: Aggregate root with event sourcing for real-time scoring
  • Team: 1-2 players competing as a unit
  • Player: Domain representation with profile, stats, and skill rating
  • Score: Tracks sets, games, points with sport-specific rules
  • MatchStakes: Optional stakes (tokens or ranking points)

Business Rules:

  • Skill rating uses ELO algorithm
  • Stats updated automatically after match completion
  • Winner stays rule applies in queue mode
  • Match stakes distributed automatically to winners
  • Points awarded: +25 XP for win, +10 XP for participation

ELO Rating Formula:

New Rating = Old Rating + K × (Actual - Expected)

Where:
  K = 32 (rating volatility factor)
  Expected = 1 / (1 + 10^((OpponentRating - YourRating) / 400))
  Actual = 1 (win), 0.5 (draw), 0 (loss)

Access & Presence Context ​

Key Classes:

  • PresenceSession: Tracks user physical presence with check-in/out
  • PresenceEvidence: Multi-source validation (GPS, RFID, facial recognition)
  • PresenceAudit: Service for compliance and usage verification

Business Rules:

  • Check-in requires being within 50m of arena (GPS)
  • Alternative check-in methods: QR code, RFID bracelet, facial recognition
  • Auto check-out after 2 hours of inactivity
  • Presence evidence captured every 5 minutes
  • Audit trail for billing disputes

Events Context ​

Key Classes:

  • Event: Aggregate root for tournaments, clinics, festivals
  • Tournament: Structured competition with brackets and rounds
  • EventZone: Defines access-controlled areas during events
  • EventParticipant: Registered attendee with entry fee payment

Business Rules:

  • Arena enters "Event Mode" with special access rules
  • Participants receive RFID pass for automated access
  • Tournament brackets generated automatically based on seeds
  • Entry fees collected upfront
  • Refund policy: 100% until 7 days before, 50% until 3 days, 0% after

Engagement & Gamification Context ​

Key Classes:

  • PlayerRanking: Aggregate root tracking player positions
  • Achievement: Unlockable goals with badge rewards
  • Challenge: Time-limited objectives (daily, weekly, seasonal)
  • XPSystem: Service calculating experience points for activities

Business Rules:

  • XP awarded for: check-ins (+10), matches (+50), wins (+25), streaks (+10/day)
  • Level up at XP thresholds: [100, 300, 600, 1000, 1500, ...]
  • Rankings reset monthly for fresh competition
  • Achievements give XP bonuses and unlock perks
  • Top 10 players each month receive prizes

Achievement Examples:

  • "First Blood": Play first match (+50 XP)
  • "Centurion": Win 100 matches (+500 XP, VIP badge)
  • "Iron Streak": Play 7 days consecutively (+200 XP)
  • "Master of Court 1": Win 50 times on same court (+300 XP)

Generic Domain Models ​

Commerce & Billing Context ​

Key Classes:

  • Invoice: Aggregate root for billing with line items
  • Payment: Handles transaction processing with external gateways
  • Subscription: Recurring membership plans
  • LineItem: Individual charge on an invoice

Business Rules:

  • Payment methods: PIX (instant), Credit Card (T+1), Boleto (T+2)
  • Invoice due date: 5 days after generation
  • Subscription auto-renews unless cancelled
  • Prorated credits for plan changes
  • Invoice must balance: total = subtotal + taxes

Media & IoT Context ​

Key Classes:

  • MediaAsset: Recorded videos/photos from matches
  • Highlight: Short clips (5-30s) of key moments
  • IoTDevice: Tablets, cameras, sensors, RFID readers

Business Rules:

  • Videos auto-recorded for all matches
  • Highlights triggered by: button press, AI detection, post-match tagging
  • Retention: 7 days for full videos, 90 days for highlights
  • Users can download their match videos
  • Cameras track ball movement using computer vision

Sponsorship & Ads Context ​

Key Classes:

  • Sponsor: Paying advertiser with contracts
  • Advertisement: Ad creative with targeting rules
  • AdInventory: Available ad slots by location/type

Business Rules:

  • Ad types: Court banners, app banners, video pre-rolls, push notifications
  • Pricing: CPM (cost per 1000 impressions) or flat rate
  • Max 1 ad per 5 minutes of video
  • Sponsors receive monthly reports with impressions/clicks/ROI

Enumerations ​

User & Access Enums ​

typescript
enum Role {
  SUPER_ADMIN     // Full system access
  ARENA_OWNER     // Arena ownership, billing
  ARENA_MANAGER   // Operational management
  RECEPTIONIST    // Check-in, manual bookings
  INSTRUCTOR      // Teach lessons, manage students
  PLAYER          // Default user role
}

enum UserStatus {
  PENDING     // Email verification pending
  ACTIVE      // Normal active user
  SUSPENDED   // Temporarily blocked
  INACTIVE    // Voluntarily deactivated
  DELETED     // LGPD deletion in progress
}

enum MembershipStatus {
  ACTIVE
  SUSPENDED
  CANCELLED
  EXPIRED
}

Arena & Court Enums ​

typescript
enum SportType {
  BEACH_TENNIS
  BEACH_VOLLEYBALL
  FOOTVOLLEY
  TENNIS
  PADEL
}

enum CourtStatus {
  AVAILABLE    // Ready for use
  OCCUPIED     // Currently in use
  RESERVED     // Future booking exists
  MAINTENANCE  // Undergoing repairs
  BLOCKED      // Admin blocked
}

enum SurfaceType {
  SAND
  CLAY
  GRASS
  SYNTHETIC
  HARD_COURT
}

enum AreaType {
  COURT
  LOCKER_ROOM
  BAR
  PARKING
  LOUNGE
}

Booking & Queue Enums ​

typescript
enum BookingType {
  COURT_RENTAL   // Standard hourly rental
  LESSON         // Instruction session
  DAY_USE        // Pay-per-entry access
  EVENT          // Special event booking
  TOURNAMENT     // Competition
}

enum BookingStatus {
  PENDING       // Awaiting payment/approval
  CONFIRMED     // Paid and scheduled
  IN_PROGRESS   // Currently happening
  COMPLETED     // Finished successfully
  CANCELLED     // User cancelled
  NO_SHOW       // Didn't show up
}

enum QueueStatus {
  WAITING   // In queue
  CALLED    // Notified, awaiting response
  ACCEPTED  // Confirmed ready to play
  DECLINED  // Refused the call
  TIMEOUT   // Didn't respond in time
}

enum Priority {
  VIP      // Top priority (VIP members)
  HIGH     // Monthly members, long wait
  NORMAL   // Standard users
  LOW      // Recent players, penalties
}

Match & Gamification Enums ​

typescript
enum MatchType {
  CASUAL        // Friendly game
  COMPETITIVE   // Ranked match
  TOURNAMENT    // Part of competition
  TRAINING      // Practice session
}

enum MatchStatus {
  SCHEDULED
  IN_PROGRESS
  PAUSED
  FINISHED
  CANCELLED
}

enum SkillLevel {
  BEGINNER       // 0-6 months experience
  INTERMEDIATE   // 6-24 months
  ADVANCED       // 2-5 years
  PROFESSIONAL   // 5+ years, competitive
}

enum RankingScope {
  GLOBAL    // Across all arenas
  ARENA     // Single arena
  WEEKLY    // Reset every 7 days
  MONTHLY   // Reset monthly
  SEASONAL  // 3-month seasons
}

enum Rarity {
  COMMON     // Easy to unlock
  RARE       // Requires effort
  EPIC       // Major achievement
  LEGENDARY  // Very rare milestone
}

Commerce Enums ​

typescript
enum PaymentMethod {
  PIX             // Brazilian instant payment
  CREDIT_CARD     // Card payment
  DEBIT_CARD      // Debit card
  BOLETO          // Brazilian bank slip
  WALLET          // Internal wallet balance
  CASH            // On-site cash
}

enum PaymentStatus {
  PENDING     // Awaiting processing
  PROCESSING  // Being processed
  APPROVED    // Successfully paid
  DECLINED    // Payment failed
  REFUNDED    // Money returned
  CANCELLED   // Cancelled before processing
}

enum InvoiceStatus {
  DRAFT      // Being created
  PENDING    // Awaiting payment
  PAID       // Fully paid
  OVERDUE    // Past due date
  CANCELLED  // Cancelled before payment
}

Transaction Enums ​

typescript
enum TransactionType {
  CREDIT     // Money added to wallet
  DEBIT      // Money removed from wallet
  TRANSFER   // Between wallets
  PURCHASE   // Payment for service
  REFUND     // Money returned
  REWARD     // Bonus/prize received
  STAKE      // Bet placed on match
}

enum TransactionStatus {
  PENDING     // Waiting to process
  PROCESSING  // Being processed
  COMPLETED   // Successfully finished
  FAILED      // Processing failed
  CANCELLED   // User cancelled
  REFUNDED    // Reversed transaction
}

enum Currency {
  BRL          // Brazilian Real
  USD          // US Dollar
  ARENA_TOKEN  // Internal virtual currency
}

Relationships Summary ​

One-to-One Relationships ​

User 1:1 UserProfile
User 1:1 Wallet
Arena 1:1 OperatingCalendar
Arena 1:1 ArenaSettings
Court 1:1 CourtProfile
Booking 1:1 TimeRange
Booking 1:1 BookingPolicy
Match 1:1 Score
Player 1:1 PlayerProfile
Player 1:1 PlayerStats
Subscription 1:1 SubscriptionPlan

One-to-Many Relationships ​

Arena 1:N Court
Arena 1:N PhysicalArea
Arena 1:N Event
User 1:N Session
User 1:N Booking
User 1:N TenantMembership
Court 1:N Booking
Court 1:N Match
AllocationEngine 1:N PlayerQueue
PlayerQueue 1:N QueueEntry
Lesson 1:N Student
Lesson 1:N Attendance
Match 1:N Team
Team 1:N Player
Wallet 1:N Balance
Wallet 1:N Transaction
Invoice 1:N LineItem
Invoice 1:N Payment
Tournament 1:N Match
Event 1:N EventZone
PlayerRanking 1:N RankingEntry
Sponsor 1:N Advertisement

Many-to-Many Relationships ​

Player N:M Achievement (earned achievements)
Player N:M Challenge (participated challenges)
User N:M Role (user can have multiple roles)
User N:M Arena (via TenantMembership)
Match N:M Player (via Team)
Event N:M User (via EventParticipant)

Architectural Notes ​

Aggregate Roots ​

The following classes are Aggregate Roots (entry points for modifications):

  • Core Domain: User, Arena, Booking, Wallet, Match, AllocationEngine
  • Supporting: Lesson, Event, PresenceSession, PlayerRanking, Achievement
  • Generic: Invoice, Subscription, Sponsor, MediaAsset

Event Sourcing ​

The following aggregates use Event Sourcing:

  • Wallet: All state reconstructed from transaction events
  • Match: Score changes tracked as events for replay/audit

CQRS ​

Applied in:

  • Wallet: Write (transactions) vs Read (balance queries)
  • Match: Write (score updates) vs Read (leaderboards, stats)
  • Booking: Write (reservations) vs Read (availability calendar)

Multi-Tenancy ​

All domain entities include:

  • tenantId (Arena identifier) for row-level isolation
  • Queries always filter by tenantId
  • PostgreSQL Row Level Security (RLS) enforces access

Value Objects (Immutable) ​

  • TimeRange, Score, Balance, CourtProfile
  • PlayerProfile, PlayerStats, Address, Contact
  • BookingPolicy, CancellationPolicy, PricingConfig

Usage Examples ​

Creating a Booking ​

typescript
// User creates a booking
const booking = Booking.create({
  userId: "user-123",
  courtId: "court-1",
  timeRange: TimeRange.create("2025-01-10T18:00", "2025-01-10T19:00"),
  type: BookingType.COURT_RENTAL,
  policy: arena.settings.bookingRules
})

// Validate availability
if (!court.isAvailableAt(booking.timeRange)) {
  throw new ConflictError("Court not available")
}

// Process payment
const payment = Payment.create({
  invoiceId: invoice.id,
  amount: Money.fromCents(5000), // R$ 50.00
  method: PaymentMethod.PIX
})

await payment.process()

// Confirm booking
booking.confirm()

// Publish event
eventBus.publish(new BookingConfirmedEvent(booking))

Allocating Players from Queue ​

typescript
// Court becomes available
court.release()

// Allocation engine finds next players
const allocationResult = allocationEngine.allocateNext(court.id)

if (allocationResult.success) {
  const players = allocationResult.players
  
  // Balance teams using ELO rating
  const teams = balanceTeams(players)
  
  // Create match
  const match = Match.create({
    courtId: court.id,
    teams: teams,
    type: MatchType.CASUAL,
    sport: court.sportType
  })
  
  // Notify players
  players.forEach(player => {
    notificationService.send(player.userId, {
      title: "Your turn!",
      body: `Court ${court.name} is ready`,
      data: { matchId: match.id }
    })
  })
  
  // Start match
  match.start()
}

Recording Match Result & Distributing Stakes ​

typescript
// Match finishes
match.recordSet(team1.id, 6, 4)
match.recordSet(team1.id, 7, 5)
match.finish()

// Update player ratings
const winner = match.getWinner()
players.forEach(player => {
  const newRating = calculateEloRating(
    player.rating,
    match.getOpponentRating(player),
    match.getResult(player)
  )
  player.updateRating(newRating)
  player.updateStats(match)
})

// Distribute stakes if match had bets
if (match.stakes) {
  const transactions = match.stakes.distribute(winner)
  transactions.forEach(txn => txn.execute())
}

// Award XP
xpSystem.awardXP(winner.playerId, 25) // Win bonus
players.forEach(player => {
  xpSystem.awardXP(player.playerId, 10) // Participation
})

// Update rankings
playerRanking.updateScore(winner.playerId, 100)

Validation Rules Summary ​

Booking Validation ​

typescript
class BookingValidator {
  validate(booking: Booking): ValidationResult {
    // Time range validation
    if (!booking.timeRange.isValid()) {
      return ValidationResult.error("Invalid time range")
    }
    
    // Advance notice
    const hoursAhead = booking.timeRange.startTime.diffInHours(now())
    if (hoursAhead < booking.policy.minAdvance.hours) {
      return ValidationResult.error("Minimum 2 hours advance required")
    }
    
    // Court availability
    if (!court.isAvailableAt(booking.timeRange)) {
      return ValidationResult.error("Court not available")
    }
    
    // User eligibility
    if (user.hasOutstandingNoShows()) {
      return ValidationResult.error("No-show suspension active")
    }
    
    return ValidationResult.success()
  }
}

Wallet Transaction Validation ​

typescript
class TransactionValidator {
  validate(transaction: Transaction): ValidationResult {
    // Idempotency check
    if (this.isDuplicate(transaction.idempotencyKey)) {
      return ValidationResult.duplicate(this.findByKey(transaction.idempotencyKey))
    }
    
    // Sufficient balance
    if (transaction.type === TransactionType.DEBIT) {
      const wallet = getWallet(transaction.fromWalletId)
      if (!wallet.hasAvailableBalance(transaction.amount)) {
        return ValidationResult.error("Insufficient balance")
      }
    }
    
    // Wallet not frozen
    if (wallet.status === WalletStatus.FROZEN) {
      return ValidationResult.error("Wallet is frozen")
    }
    
    return ValidationResult.success()
  }
}

Next Steps ​

This class diagram serves as the single source of truth for the domain model. Use it to:

  1. Generate Database Schema: Map entities to tables, value objects to JSON columns
  2. Implement Domain Layer: Create TypeScript classes following this structure
  3. Define API Contracts: OpenAPI specs mirror these entities
  4. Write Tests: Test cases validate business rules defined here
  5. Team Alignment: Ensure developers, PO, and stakeholders share same vocabulary

Version: 1.0.0
Last Updated: 2025-01-09
Author: Atlas (Claude Opus 4.5)
Status: Approved


"The class diagram is not just documentation—it's the architectural DNA of the system."
— Vaughn Vernon, Implementing Domain-Driven Design