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