Skip to content

Domain Model - Sport Tech Club

Visão Geral

Este documento descreve o modelo de domínio completo do Sport Tech Club, organizado em Bounded Contexts seguindo os princípios de Domain-Driven Design (DDD).

Contextos Delimitados (Bounded Contexts)

┌─────────────────────────────────────────────────────────────────────┐
│                         Sport Tech Club                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                       │
│  ┌──────────────────┐  ┌──────────────────┐  ┌─────────────────┐   │
│  │ Identity & Access│  │  Arena Context   │  │ Courts & Alloc  │   │
│  └──────────────────┘  └──────────────────┘  └─────────────────┘   │
│                                                                       │
│  ┌──────────────────┐  ┌──────────────────┐  ┌─────────────────┐   │
│  │   Scheduling     │  │ Lessons & Coach  │  │  Play & Match   │   │
│  └──────────────────┘  └──────────────────┘  └─────────────────┘   │
│                                                                       │
│  ┌──────────────────┐  ┌──────────────────┐  ┌─────────────────┐   │
│  │     Events       │  │ Access & Presence│  │  Devices & IoT  │   │
│  └──────────────────┘  └──────────────────┘  └─────────────────┘   │
│                                                                       │
│  ┌──────────────────┐  ┌──────────────────┐  ┌─────────────────┐   │
│  │  Media & Video   │  │Commerce & Billing│  │ Wallet & Value  │   │
│  └──────────────────┘  └──────────────────┘  └─────────────────┘   │
│                                                                       │
│  ┌──────────────────┐  ┌──────────────────┐  ┌─────────────────┐   │
│  │Engagement & Game │  │ Sponsorship & Ads│  │    Analytics    │   │
│  └──────────────────┘  └──────────────────┘  └─────────────────┘   │
│                                                                       │
│                    ┌──────────────────┐                              │
│                    │  Shared Kernel   │                              │
│                    └──────────────────┘                              │
└─────────────────────────────────────────────────────────────────────┘

1. Identity & Access Context

Objetivo

Gerenciar identidades, autenticação, autorização e controle de acesso para todos os usuários e sistemas.

Aggregates

1.1 Tenant (Aggregate Root)

Descrição: Representa uma organização/arena que utiliza o sistema em modelo multi-tenant.

Atributos:

  • id: TenantId (Identifier)
  • name: string
  • subdomain: string (único)
  • status: TenantStatus (ACTIVE, SUSPENDED, INACTIVE)
  • subscription: SubscriptionInfo
  • configuration: TenantConfiguration
  • createdAt: Date
  • activatedAt: Date?

Relacionamentos:

  • Possui múltiplas ArenaTenant (arenas físicas)
  • Possui múltiplos UserAccount
  • Define Policy de segurança

Invariantes:

  • Subdomain deve ser único e válido (DNS-safe)
  • Tenant ativo deve ter pelo menos uma arena
  • Configuração deve ser válida para o plano contratado

1.2 ArenaTenant

Descrição: Vincula um Tenant a uma Arena física específica.

Atributos:

  • id: ArenaTenantId
  • tenantId: TenantId
  • arenaId: ArenaId
  • role: TenantRole (OWNER, OPERATOR, PARTNER)
  • accessLevel: AccessLevel
  • activeSince: Date

Relacionamentos:

  • Pertence a um Tenant
  • Referencia uma Arena (Arena Context)

1.3 UserAccount (Aggregate Root)

Descrição: Conta de usuário no sistema, identidade digital única.

Atributos:

  • id: UserId (Identifier)
  • tenantId: TenantId
  • email: Email (Value Object)
  • username: string?
  • status: AccountStatus (ACTIVE, SUSPENDED, LOCKED, PENDING_VERIFICATION)
  • emailVerified: boolean
  • phoneNumber: PhoneNumber? (Value Object)
  • phoneVerified: boolean
  • mfaEnabled: boolean
  • passwordExpiresAt: Date?
  • lockedUntil: Date?
  • lastLoginAt: Date?
  • createdAt: Date

Relacionamentos:

  • Possui um ou mais PersonProfile
  • Possui múltiplos Credential
  • Possui múltiplas Session
  • Possui múltiplos Role
  • Possui Consent para políticas de privacidade

Invariantes:

  • Email deve ser único por tenant
  • Conta suspensa não pode autenticar
  • MFA obrigatório para roles administrativos

Comportamentos:

  • authenticate(credential): AuthResult
  • suspend(reason): void
  • activate(): void
  • lockAccount(duration): void
  • enableMFA(): void
  • verifyEmail(token): void

1.4 PersonProfile

Descrição: Perfil de pessoa física (dados pessoais).

Atributos:

  • id: PersonProfileId
  • userId: UserId
  • fullName: FullName (Value Object)
  • dateOfBirth: Date?
  • gender: Gender?
  • document: Document? (CPF, RG, Passport)
  • address: Address? (Value Object)
  • avatar: MediaAssetId?
  • preferences: UserPreferences
  • createdAt: Date

Relacionamentos:

  • Pertence a um UserAccount
  • Pode ter PlayerProfile
  • Pode ter InstructorProfile
  • Pode ter StaffProfile
  • Pode ter GuestProfile

Invariantes:

  • Pessoa menor de idade requer responsável

1.5 PlayerProfile

Descrição: Perfil específico para jogadores (alunos/atletas).

Atributos:

  • id: PlayerProfileId
  • personProfileId: PersonProfileId
  • playerId: string (código/matrícula)
  • skillLevel: SkillLevel (BEGINNER, INTERMEDIATE, ADVANCED, PROFESSIONAL)
  • preferredHand: Hand (LEFT, RIGHT, AMBIDEXTROUS)
  • playStyle: PlayStyle[]
  • medicalClearance: MedicalClearance?
  • emergencyContact: EmergencyContact
  • memberSince: Date
  • status: PlayerStatus (ACTIVE, INACTIVE, SUSPENDED)

Relacionamentos:

  • Pertence a um PersonProfile
  • Possui PlayerProgress (Engagement Context)
  • Possui Wallet (Wallet Context)
  • Participa de Match (Play Context)
  • Inscreve-se em Lesson (Lessons Context)

Invariantes:

  • Jogador ativo deve ter atestado médico válido
  • Menor de idade requer autorização dos responsáveis

1.6 InstructorProfile

Descrição: Perfil de instrutor/professor.

Atributos:

  • id: InstructorProfileId
  • personProfileId: PersonProfileId
  • instructorCode: string
  • specialties: Specialty[] (TENNIS, PADEL, BEACH_TENNIS)
  • certifications: Certification[]
  • bio: string?
  • hourlyRate: Money?
  • commissionRate: Percentage?
  • availability: InstructorAvailability
  • status: InstructorStatus
  • hiredAt: Date

Relacionamentos:

  • Pertence a um PersonProfile
  • Ministra Lesson (Lessons Context)
  • Possui InstructorPayout (Commerce Context)

Invariantes:

  • Instrutor ativo deve ter pelo menos uma certificação válida
  • Disponibilidade deve respeitar regras trabalhistas

1.7 StaffProfile

Descrição: Perfil de funcionário da arena (não instrutor).

Atributos:

  • id: StaffProfileId
  • personProfileId: PersonProfileId
  • employeeCode: string
  • department: Department (RECEPTION, MAINTENANCE, MANAGEMENT, OPERATIONS)
  • position: string
  • hiredAt: Date
  • status: EmploymentStatus

Relacionamentos:

  • Pertence a um PersonProfile
  • Possui Role específicas

1.8 GuestProfile

Descrição: Perfil temporário para visitantes não cadastrados.

Atributos:

  • id: GuestProfileId
  • personProfileId: PersonProfileId
  • guestCode: string
  • sponsor: UserId? (quem convidou)
  • validUntil: Date
  • purpose: GuestPurpose (TRIAL, EVENT, ONE_TIME_PLAY)

Relacionamentos:

  • Pertence a um PersonProfile
  • Possui acesso limitado

Invariantes:

  • Convidado não pode reservar quadras sem patrocínio
  • Acesso expira automaticamente

1.9 Role (Aggregate Root)

Descrição: Papel/função que agrupa permissões.

Atributos:

  • id: RoleId
  • tenantId: TenantId
  • name: string
  • description: string?
  • type: RoleType (SYSTEM, TENANT, CUSTOM)
  • isActive: boolean
  • createdAt: Date

Relacionamentos:

  • Possui múltiplas Permission
  • Atribuído a múltiplos UserAccount

Invariantes:

  • Roles de sistema não podem ser modificadas
  • Nome deve ser único por tenant

Comportamentos:

  • grantPermission(permission): void
  • revokePermission(permission): void
  • hasPermission(permission): boolean

Exemplos de Roles:

  • SUPER_ADMIN: acesso total ao sistema
  • ARENA_ADMIN: administrador da arena
  • INSTRUCTOR: professor/instrutor
  • RECEPTIONIST: recepcionista
  • PLAYER: jogador/aluno
  • GUEST: visitante

1.10 Permission

Descrição: Permissão atômica para executar ação específica.

Atributos:

  • id: PermissionId
  • resource: string (ex: "court", "booking", "user")
  • action: string (ex: "create", "read", "update", "delete")
  • scope: PermissionScope (SYSTEM, TENANT, OWN)
  • conditions: Condition[]? (regras condicionais)

Formato: resource:action:scope

Exemplos:

  • court:create:tenant - criar quadras na arena
  • booking:read:own - ler próprias reservas
  • user:update:tenant - atualizar usuários da arena
  • match:score:system - pontuar partidas (qualquer)

1.11 Policy (Aggregate Root)

Descrição: Política de segurança e governança.

Atributos:

  • id: PolicyId
  • tenantId: TenantId
  • type: PolicyType (PASSWORD, SESSION, ACCESS, DATA_RETENTION)
  • rules: PolicyRule[]
  • isActive: boolean
  • effectiveFrom: Date
  • effectiveUntil: Date?

Relacionamentos:

  • Pertence a um Tenant
  • Aplicada em UserAccount e Session

Exemplos de Políticas:

  • Password: comprimento mínimo, complexidade, expiração
  • Session: timeout, max concurrent, device binding
  • Access: horários permitidos, IPs permitidos, geolocalização

1.12 Credential (Aggregate Root)

Descrição: Credencial de autenticação (abstração para múltiplos tipos).

Atributos Base:

  • id: CredentialId
  • userId: UserId
  • type: CredentialType (PASSWORD, OAUTH, RFID, QR_CODE, WRISTBAND, BIOMETRIC)
  • status: CredentialStatus (ACTIVE, EXPIRED, REVOKED, SUSPENDED)
  • createdAt: Date
  • lastUsedAt: Date?
  • expiresAt: Date?

Subtipos:

PasswordCredential:

  • passwordHash: string
  • salt: string
  • algorithm: HashAlgorithm
  • mustChangeOnNextLogin: boolean
  • previousHashes: string[] (histórico para evitar reuso)

OAuthCredential:

  • provider: IdentityProvider
  • providerUserId: string
  • accessToken: string? (encrypted)
  • refreshToken: string? (encrypted)
  • tokenExpiresAt: Date?

RFIDCredential:

  • tagId: string
  • tagType: RFIDTagType
  • assignedTo: DeviceId?

QRCodeCredential:

  • code: string (único, rotativo)
  • generatedAt: Date
  • validUntil: Date
  • usageCount: number
  • maxUsages: number?

WristbandCredential:

  • wristbandId: string
  • batteryLevel: number?
  • assignedAt: Date

Comportamentos:

  • verify(input): boolean
  • rotate(): void (para QR Code)
  • revoke(): void
  • renew(): void

1.13 Session (Aggregate Root)

Descrição: Sessão de autenticação ativa.

Atributos:

  • id: SessionId
  • userId: UserId
  • token: string (JWT ou session token)
  • deviceInfo: DeviceInfo (user agent, OS, browser)
  • ipAddress: string
  • geoLocation: GeoLocation?
  • createdAt: Date
  • lastActivityAt: Date
  • expiresAt: Date
  • status: SessionStatus (ACTIVE, EXPIRED, TERMINATED)

Relacionamentos:

  • Pertence a um UserAccount
  • Registra AuthenticationAttempt

Invariantes:

  • Sessão expirada não pode ser renovada
  • Usuário pode ter limite de sessões concorrentes

Comportamentos:

  • refresh(): void
  • terminate(): void
  • isExpired(): boolean
  • recordActivity(): void

1.14 AuthenticationAttempt

Descrição: Registro de tentativa de autenticação (sucesso ou falha).

Atributos:

  • id: AuthAttemptId
  • userId: UserId?
  • email: string?
  • credentialType: CredentialType
  • result: AuthResult (SUCCESS, INVALID_CREDENTIALS, LOCKED, MFA_REQUIRED)
  • ipAddress: string
  • userAgent: string
  • timestamp: Date
  • failureReason: string?

Relacionamentos:

  • Vinculado a UserAccount (se sucesso)
  • Gera Session (se sucesso)

Uso: Auditoria, detecção de ataques brute force, análise de segurança


1.15 AuthorizationGrant

Descrição: Concessão de autorização (OAuth 2.0 / OIDC).

Atributos:

  • id: GrantId
  • userId: UserId
  • clientId: string (aplicação cliente)
  • scope: string[]
  • grantType: GrantType (AUTHORIZATION_CODE, REFRESH_TOKEN, CLIENT_CREDENTIALS)
  • code: string?
  • redirectUri: string?
  • expiresAt: Date
  • createdAt: Date

Relacionamentos:

  • Pertence a um UserAccount
  • Gera Session ou access token

1.16 IdentityProvider

Descrição: Provedor de identidade externo (SSO).

Atributos:

  • id: ProviderId
  • tenantId: TenantId
  • type: ProviderType (GOOGLE, FACEBOOK, APPLE, SAML, OIDC)
  • name: string
  • clientId: string
  • clientSecret: string (encrypted)
  • configuration: ProviderConfig (endpoints, scopes)
  • isActive: boolean

Relacionamentos:

  • Pertence a um Tenant
  • Gera OAuthCredential

Descrição: Consentimento do usuário para políticas (LGPD/GDPR).

Atributos:

  • id: ConsentId
  • userId: UserId
  • policyType: PolicyType (TERMS_OF_SERVICE, PRIVACY_POLICY, MARKETING, DATA_SHARING)
  • policyVersion: string
  • consentedAt: Date
  • ipAddress: string
  • revokedAt: Date?

Relacionamentos:

  • Pertence a um UserAccount

Invariantes:

  • Consentimento obrigatório para usar o sistema
  • Revogação de consentimento crítico pode suspender conta

2. Arena Context

Objetivo

Gerenciar arenas físicas, suas configurações, áreas, zonas de acesso e calendários operacionais.

Aggregates

2.1 Arena (Aggregate Root)

Descrição: Representação de uma arena física (complexo esportivo).

Atributos:

  • id: ArenaId
  • name: string
  • displayName: LocalizedText
  • slug: string (URL-friendly)
  • description: string?
  • address: Address (Value Object)
  • geoLocation: GeoLocation (Value Object)
  • timezone: string (IANA timezone)
  • phoneNumber: PhoneNumber
  • email: Email
  • website: string?
  • status: ArenaStatus (ACTIVE, UNDER_CONSTRUCTION, MAINTENANCE, INACTIVE)
  • openedAt: Date
  • capacity: ArenaCapacity (max concurrent players)
  • features: ArenaFeature[] (PARKING, RESTAURANT, SHOP, LOCKER_ROOMS)
  • photos: MediaAssetId[]

Relacionamentos:

  • Possui uma ArenaConfiguration
  • Possui múltiplas ArenaArea
  • Possui múltiplas AccessZone
  • Possui um BusinessCalendar
  • Possui múltiplas Court (Courts Context)

Invariantes:

  • Arena ativa deve ter pelo menos uma quadra operacional
  • Timezone deve ser válida
  • Capacidade deve respeitar limites de segurança

Comportamentos:

  • isOpen(date: Date): boolean
  • getCurrentOccupancy(): number
  • canAccommodate(playerCount: number): boolean

2.2 ArenaConfiguration

Descrição: Configurações operacionais da arena.

Atributos:

  • id: ConfigId
  • arenaId: ArenaId
  • defaultCourtDuration: Duration (ex: 1h30)
  • minAdvanceBooking: Duration (ex: 30 minutos)
  • maxAdvanceBooking: Duration (ex: 30 dias)
  • cancellationWindow: Duration (ex: 24 horas)
  • autoReleaseNoShow: Duration (ex: 15 minutos)
  • checkInWindow: TimeRange (ex: -15min a +5min)
  • defaultCurrency: Currency
  • taxSettings: TaxSettings
  • paymentMethods: PaymentMethod[]
  • supportedLanguages: string[]
  • notificationSettings: NotificationSettings

Relacionamentos:

  • Pertence a uma Arena

Invariantes:

  • Durações devem ser positivas e lógicas
  • Pelo menos um método de pagamento ativo

2.3 ArenaArea

Descrição: Área física dentro da arena (abstração).

Atributos Base:

  • id: AreaId
  • arenaId: ArenaId
  • name: string
  • type: AreaType (COURT, HOSPITALITY, EVENT, LOCKER_ROOM, COMMON)
  • description: string?
  • floor: number?
  • capacity: number?
  • status: AreaStatus (AVAILABLE, OCCUPIED, MAINTENANCE, CLOSED)

Subtipos:

CourtArea:

  • courtId: CourtId
  • surface: SurfaceType (SYNTHETIC_GRASS, CEMENT, CLAY)
  • isIndoor: boolean
  • hasLighting: boolean
  • hasRoof: boolean

HospitalityArea:

  • serviceType: ServiceType (RESTAURANT, BAR, CAFE, LOUNGE)
  • seatingCapacity: number
  • operatingHours: OperatingHours

EventArea:

  • setupType: SetupType (THEATER, BANQUET, COCKTAIL, CUSTOM)
  • equipmentAvailable: Equipment[]

LockerRoomArea:

  • gender: Gender? (null = unisex)
  • lockerCount: number
  • hasShowers: boolean
  • hasRestrooms: boolean

Relacionamentos:

  • Pertence a uma Arena
  • Associada a AccessZone

2.4 AccessZone

Descrição: Zona lógica de controle de acesso (pode agrupar múltiplas áreas).

Atributos:

  • id: ZoneId
  • arenaId: ArenaId
  • name: string
  • description: string?
  • type: ZoneType (PUBLIC, RESTRICTED, PRIVATE, VIP)
  • areas: AreaId[]
  • accessLevel: AccessLevel (OPEN, MEMBER_ONLY, EVENT_ONLY, STAFF_ONLY)
  • isActive: boolean

Relacionamentos:

  • Pertence a uma Arena
  • Referencia múltiplas ArenaArea
  • Controlada por ZoneRuleSet
  • Monitorada por CheckInPoint (Access Context)

Invariantes:

  • Zona VIP requer validação de acesso
  • Zona restrita não pode ser pública

2.5 ZoneRuleSet

Descrição: Conjunto de regras de acesso para uma zona.

Atributos:

  • id: RuleSetId
  • zoneId: ZoneId
  • name: string
  • rules: AccessRule[]
  • effectivePeriod: DateRange
  • priority: number
  • isActive: boolean

AccessRule (Value Object):

  • condition: RuleCondition (ex: "has valid booking", "is VIP member")
  • action: RuleAction (ALLOW, DENY, REQUIRE_APPROVAL)
  • timeRestriction: TimeRange?
  • dayOfWeekRestriction: DayOfWeek[]?

Comportamentos:

  • evaluate(user: UserId, context: AccessContext): RuleResult

2.6 BusinessCalendar (Aggregate Root)

Descrição: Calendário operacional da arena com horários e feriados.

Atributos:

  • id: CalendarId
  • arenaId: ArenaId
  • timezone: string
  • defaultOperatingHours: OperatingHours
  • specialDates: SpecialDate[]

Relacionamentos:

  • Pertence a uma Arena
  • Possui OperatingHours
  • Possui HolidayCalendar

Comportamentos:

  • getOperatingHours(date: Date): OperatingHours
  • isOpen(dateTime: Date): boolean
  • isHoliday(date: Date): boolean
  • getNextAvailableSlot(from: Date): Date?

2.7 OperatingHours

Descrição: Horário de funcionamento (pode variar por dia da semana).

Atributos:

  • id: OperatingHoursId
  • calendarId: CalendarId
  • dayOfWeek: DayOfWeek
  • openTime: Time
  • closeTime: Time
  • isClosed: boolean
  • breakPeriods: TimeRange[]? (ex: almoço)

Invariantes:

  • Horário de abertura deve ser antes do fechamento
  • Períodos de pausa não podem sobrepor

2.8 HolidayCalendar

Descrição: Feriados e datas especiais.

Atributos:

  • id: HolidayCalendarId
  • calendarId: CalendarId
  • year: number
  • holidays: Holiday[]

Holiday (Value Object):

  • date: Date
  • name: string
  • type: HolidayType (NATIONAL, REGIONAL, CUSTOM)
  • isRecurring: boolean
  • operatingHours: OperatingHours? (se opera em horário especial)
  • isClosed: boolean

3. Courts & Allocation Context

Objetivo

Gerenciar quadras, suas características, disponibilidade, e o sistema inteligente de alocação de jogadores para partidas.

Aggregates

3.1 Court (Aggregate Root)

Descrição: Quadra esportiva (tennis, padel, beach tennis).

Atributos:

  • id: CourtId
  • arenaId: ArenaId
  • code: string (ex: "C1", "PADEL-A")
  • name: string
  • sport: Sport (TENNIS, PADEL, BEACH_TENNIS, PICKLEBALL)
  • surface: SurfaceType (SYNTHETIC_GRASS, CEMENT, CLAY, SAND)
  • isIndoor: boolean
  • hasLighting: boolean
  • hasRoof: boolean
  • capacity: CourtCapacity (singles: 2, doubles: 4)
  • dimensions: CourtDimensions (length, width em metros)
  • features: CourtFeature[] (ELECTRONIC_SCOREBOARD, CAMERA, HIGHLIGHT_BUTTON)
  • status: CourtStatus (AVAILABLE, OCCUPIED, MAINTENANCE, OUT_OF_SERVICE)
  • maintenanceSchedule: MaintenanceSchedule?

Relacionamentos:

  • Pertence a uma Arena
  • Possui um CourtProfile
  • Possui múltiplos CourtState (histórico de estados)
  • Possui CourtAvailability
  • Possui CourtRuleSet
  • Associada a CourtArea (Arena Context)
  • Possui Device instalados (Devices Context)

Invariantes:

  • Quadra ocupada não pode aceitar novas alocações
  • Quadra em manutenção não aparece como disponível
  • Capacidade deve respeitar o esporte

Comportamentos:

  • isAvailable(timeSlot: TimeRange): boolean
  • occupy(match: MatchId): void
  • release(): void
  • scheduleMainte(period: DateRange): void

3.2 CourtProfile

Descrição: Perfil de características para matching de jogadores.

Atributos:

  • id: CourtProfileId
  • courtId: CourtId
  • skillLevelProfile: SkillLevelProfile
  • genderProfile: GenderProfile
  • playStyleProfile: PlayStyleProfile
  • preferredFormats: MatchFormat[] (SINGLES, DOUBLES, MIXED_DOUBLES)
  • ageGroups: AgeGroup[]?

Relacionamentos:

  • Pertence a uma Court

Uso: Sistema de alocação usa este perfil para formar partidas equilibradas


3.3 SkillLevelProfile

Descrição: Perfil de nível técnico aceito na quadra.

Atributos:

  • allowedLevels: SkillLevel[] (ex: [INTERMEDIATE, ADVANCED])
  • mixedLevelPolicy: MixedLevelPolicy (ALLOWED, RESTRICTED, PROHIBITED)
  • maxLevelGap: number? (diferença máxima entre jogadores)

3.4 GenderProfile

Descrição: Perfil de gênero para formação de partidas.

Atributos:

  • policy: GenderPolicy (MIXED, MALE_ONLY, FEMALE_ONLY, PREFERENCE)
  • mixedDoublesAllowed: boolean

3.5 PlayStyleProfile

Descrição: Perfil de estilo de jogo.

Atributos:

  • styles: PlayStyle[] (RECREATIONAL, COMPETITIVE, TRAINING, PROFESSIONAL)
  • allowMixedStyles: boolean

3.6 CourtState

Descrição: Estado da quadra em um momento específico (snapshot).

Atributos:

  • id: StateId
  • courtId: CourtId
  • status: CourtStatus
  • occupiedBy: MatchId?
  • temperature: number?
  • humidity: number?
  • lightLevel: number?
  • timestamp: Date

Relacionamentos:

  • Pertence a uma Court

Uso: Histórico de estados, telemetria, analytics


3.7 CourtAvailability

Descrição: Disponibilidade da quadra (agenda).

Atributos:

  • id: AvailabilityId
  • courtId: CourtId
  • date: Date
  • slots: AvailabilitySlot[]

AvailabilitySlot (Value Object):

  • timeRange: TimeRange
  • status: SlotStatus (AVAILABLE, BOOKED, BLOCKED, MAINTENANCE)
  • bookingId: BookingId?
  • price: Money?

Comportamentos:

  • getAvailableSlots(date: Date): AvailabilitySlot[]
  • blockSlot(timeRange: TimeRange, reason: string): void
  • releaseSlot(timeRange: TimeRange): void

3.8 CourtRuleSet

Descrição: Regras específicas da quadra.

Atributos:

  • id: RuleSetId
  • courtId: CourtId
  • accessRules: AccessRule[] (quem pode usar)
  • bookingRules: BookingRule[] (restrições de reserva)
  • playRules: PlayRule[] (regras de jogo)

Exemplos:

  • "Membros VIP têm prioridade"
  • "Máximo 2 horas consecutivas por pessoa"
  • "Obrigatório uso de calçado apropriado"

3.9 AllocationPolicy (Aggregate Root)

Descrição: Política de alocação automática de jogadores.

Atributos:

  • id: PolicyId
  • arenaId: ArenaId
  • name: string
  • mode: AllocationMode (FIFO, SKILL_BASED, RANDOM, PRIORITY_BASED)
  • priorityRules: PriorityRule[]
  • eligibilityRules: EligibilityRule[]
  • matchTerminationRules: MatchTerminationRule[]
  • isActive: boolean

Relacionamentos:

  • Pertence a uma Arena
  • Aplicada a AllocationQueue

Comportamentos:

  • evaluate(queue: AllocationQueue): AllocationDecision
  • prioritize(entries: QueueEntry[]): QueueEntry[]

3.10 AllocationQueue (Aggregate Root)

Descrição: Fila de espera para alocação em quadras.

Atributos:

  • id: QueueId
  • courtId: CourtId? (null = qualquer quadra)
  • createdAt: Date
  • entries: QueueEntry[]
  • status: QueueStatus (ACTIVE, PAUSED, CLOSED)

Relacionamentos:

  • Associada a uma Court (ou todas)
  • Contém múltiplos QueueEntry
  • Gera AllocationDecision

Invariantes:

  • Fila deve manter ordem baseada em política
  • Entrada duplicada do mesmo jogador não permitida

Comportamentos:

  • addPlayer(player: PlayerId): QueueEntry
  • removePlayer(player: PlayerId): void
  • processNext(): AllocationDecision?
  • getPosition(player: PlayerId): number

3.11 QueueEntry

Descrição: Entrada de jogador na fila de alocação.

Atributos:

  • id: EntryId
  • queueId: QueueId
  • playerId: PlayerId
  • joinedAt: Date
  • priority: number (calculado por regras)
  • skillLevel: SkillLevel
  • preferredFormat: MatchFormat?
  • maxWaitTime: Duration?
  • status: EntryStatus (WAITING, ALLOCATED, EXPIRED, CANCELLED)

Relacionamentos:

  • Pertence a uma AllocationQueue
  • Referencia um PlayerProfile

Comportamentos:

  • calculatePriority(rules: PriorityRule[]): number
  • isEligible(court: Court): boolean
  • isExpired(): boolean

3.12 AllocationDecision

Descrição: Decisão de alocação tomada pelo sistema.

Atributos:

  • id: DecisionId
  • queueId: QueueId
  • courtId: CourtId
  • selectedPlayers: PlayerId[]
  • matchFormat: MatchFormat
  • reasoning: string (explicação da decisão)
  • confidence: number (0-1, qualidade do match)
  • decidedAt: Date
  • status: DecisionStatus (PENDING_ACCEPTANCE, ACCEPTED, REJECTED, EXPIRED)
  • expiresAt: Date

Relacionamentos:

  • Originada de AllocationQueue
  • Aloca Court
  • Cria Match (se aceita) (Play Context)

Comportamentos:

  • accept(players: PlayerId[]): Match
  • reject(reason: string): void
  • expire(): void

3.13 PriorityRule

Descrição: Regra para calcular prioridade na fila.

Atributos:

  • id: RuleId
  • name: string
  • type: PriorityRuleType (WAIT_TIME, MEMBERSHIP_LEVEL, PLAY_FREQUENCY, SKILL_LEVEL)
  • weight: number (peso na fórmula de prioridade)
  • parameters: Record<string, any>

Exemplos:

  • WAIT_TIME: +10 pontos por hora de espera
  • MEMBERSHIP_LEVEL: VIP +50, Premium +30, Basic +10
  • PLAY_FREQUENCY: -5 pontos se jogou nas últimas 2 horas

3.14 EligibilityRule

Descrição: Regra de elegibilidade para alocação.

Atributos:

  • id: RuleId
  • name: string
  • type: EligibilityRuleType (SKILL_MATCH, MEMBERSHIP_REQUIRED, TIME_BASED, CREDITS_REQUIRED)
  • condition: RuleCondition
  • errorMessage: string

Comportamentos:

  • evaluate(player: PlayerProfile, court: Court): boolean

Exemplos:

  • "Jogador deve ter nível compatível com a quadra"
  • "Requer membro ativo"
  • "Deve ter pelo menos 1 crédito disponível"

3.15 MatchTerminationRule

Descrição: Regra para finalizar partidas automaticamente.

Atributos:

  • id: RuleId
  • type: TerminationRuleType (TIME_LIMIT, SCORE_LIMIT, WINNER_STAYS, MANUAL)
  • parameters: RuleParameters

Subtipos:

TimeLimitRule:

  • maxDuration: Duration (ex: 1h30)
  • warningBefore: Duration (ex: 10 minutos)
  • gracePeriod: Duration (ex: 5 minutos para finalizar)

ScoreLimitRule:

  • winningScore: number (ex: 6 games)
  • isTiebreakEnabled: boolean
  • tiebreakScore: number? (ex: 7 pontos)

WinnerStaysRule:

  • maxConsecutiveWins: number (ex: 2)
  • rotationPolicy: RotationPolicy (LOSER_OUT, ROTATE_ALL)

ManualOverride:

  • allowStaffOverride: boolean
  • requiresReason: boolean

4. Scheduling Context

Objetivo

Gerenciar agendamentos de quadras, aulas, day use e eventos, com políticas de reserva, cancelamento e waitlist.

Aggregates

4.1 Schedule (Aggregate Root)

Descrição: Agenda mestre de uma arena ou recurso.

Atributos:

  • id: ScheduleId
  • resourceId: ResourceId (Court, Instructor, Area)
  • resourceType: ResourceType
  • timezone: string
  • effectivePeriod: DateRange

Relacionamentos:

  • Associado a um recurso (Court, Instructor, etc)
  • Contém múltiplos ScheduleSlot
  • Referenciado por Booking

Comportamentos:

  • getAvailableSlots(date: Date): ScheduleSlot[]
  • book(slot: ScheduleSlot, booking: Booking): void
  • cancelBooking(bookingId: BookingId): void
  • findConflicts(timeRange: TimeRange): Booking[]

4.2 ScheduleSlot

Descrição: Slot de tempo específico na agenda.

Atributos:

  • id: SlotId
  • scheduleId: ScheduleId
  • timeRange: TimeRange
  • status: SlotStatus (AVAILABLE, BOOKED, BLOCKED, MAINTENANCE)
  • capacity: number (quantos podem reservar)
  • currentOccupancy: number
  • price: Money?
  • bookingIds: BookingId[]

Relacionamentos:

  • Pertence a um Schedule
  • Pode ter múltiplas Booking (se capacidade > 1, ex: aulas)

Comportamentos:

  • isAvailable(): boolean
  • isFull(): boolean
  • canAccommodate(count: number): boolean

4.3 Booking (Aggregate Root)

Descrição: Reserva abstrata (base para diferentes tipos).

Atributos Base:

  • id: BookingId
  • tenantId: TenantId
  • bookingNumber: string (único, legível)
  • type: BookingType (COURT, LESSON, DAY_USE, EVENT)
  • bookedBy: UserId
  • participants: UserId[]
  • scheduleId: ScheduleId
  • slotId: SlotId
  • timeRange: TimeRange
  • status: BookingStatus (PENDING, CONFIRMED, CHECKED_IN, COMPLETED, CANCELLED, NO_SHOW)
  • price: Money
  • paidAmount: Money
  • paymentStatus: PaymentStatus (PENDING, PARTIAL, PAID, REFUNDED)
  • createdAt: Date
  • confirmedAt: Date?
  • cancelledAt: Date?
  • cancellationReason: string?
  • notes: string?

Subtipos:

CourtBooking:

  • courtId: CourtId
  • sport: Sport
  • matchFormat: MatchFormat
  • skillLevel: SkillLevel?
  • isRecurring: boolean
  • recurrenceRule: RecurrenceRule?

LessonBooking:

  • lessonId: LessonId
  • instructorId: InstructorId
  • lessonType: LessonType (PRIVATE, GROUP, CLINIC)
  • enrollmentId: ClassEnrollmentId?

DayUseBooking:

  • accessZones: ZoneId[]
  • includesLockerRoom: boolean
  • guestCount: number

EventBooking:

  • eventId: EventId
  • ticketType: TicketType
  • seatNumber: string?

Relacionamentos:

  • Pertence a um UserAccount (bookedBy)
  • Associada a um ScheduleSlot
  • Possui PaymentStatus (Commerce Context)
  • Pode ter Waitlist entries
  • Gera CheckInRecord (Access Context)

Invariantes:

  • Reserva confirmada não pode sobrepor outra
  • Cancelamento deve respeitar política de cancelamento
  • No-show registrado se não houve check-in no prazo

Comportamentos:

  • confirm(): void
  • cancel(reason: string): void
  • checkIn(time: Date): void
  • markNoShow(): void
  • reschedule(newSlot: ScheduleSlot): void
  • canCancel(at: Date): boolean
  • canReschedule(at: Date): boolean

4.4 BookingPolicy (Aggregate Root)

Descrição: Política de reservas da arena.

Atributos:

  • id: PolicyId
  • arenaId: ArenaId
  • name: string
  • resourceType: ResourceType
  • minAdvanceBooking: Duration
  • maxAdvanceBooking: Duration
  • maxConcurrentBookings: number
  • maxBookingsPerDay: number
  • maxBookingsPerWeek: number
  • requiresPaymentUpfront: boolean
  • allowGuestBooking: boolean
  • guestBookingRequiresApproval: boolean
  • cancellationPolicy: CancellationPolicy
  • noShowPolicy: NoShowPolicy
  • lateArrivalPolicy: LateArrivalPolicy
  • effectivePeriod: DateRange
  • isActive: boolean

Relacionamentos:

  • Pertence a uma Arena
  • Aplicada a Booking

Comportamentos:

  • canBook(user: UserId, timeRange: TimeRange): ValidationResult
  • calculateCancellationFee(booking: Booking, cancelAt: Date): Money
  • getPenalty(offense: PolicyOffense): Penalty

4.5 CancellationPolicy

Descrição: Política de cancelamento.

Atributos:

  • allowCancellation: boolean
  • cancellationWindow: Duration (ex: 24 horas antes)
  • feeStructure: CancellationFee[]

CancellationFee (Value Object):

  • timeBeforeBooking: Duration
  • feeType: FeeType (PERCENTAGE, FIXED)
  • amount: number

Exemplos:

  • Mais de 24h antes: sem taxa
  • Entre 24h-12h antes: 50% do valor
  • Menos de 12h antes: 100% do valor

4.6 NoShowPolicy

Descrição: Política para falta sem aviso.

Atributos:

  • penaltyType: PenaltyType (WARNING, FEE, SUSPENSION, CREDIT_LOSS)
  • penaltyAmount: Money?
  • suspensionDuration: Duration?
  • creditsLost: number?
  • warningCountBeforeSuspension: number?
  • resetPeriod: Duration (período para zerar contador)

4.7 LateArrivalPolicy

Descrição: Política para atrasos.

Atributos:

  • gracePeriod: Duration (ex: 10 minutos)
  • maxLateness: Duration (ex: 20 minutos)
  • afterMaxLatenessAction: Action (TREAT_AS_NO_SHOW, REDUCE_TIME, CANCEL)
  • penaltyForLateness: Penalty?

4.8 RecurrenceRule

Descrição: Regra de recorrência para reservas repetitivas.

Atributos:

  • pattern: RecurrencePattern (DAILY, WEEKLY, MONTHLY)
  • interval: number (ex: a cada 2 semanas)
  • daysOfWeek: DayOfWeek[]? (para padrão semanal)
  • dayOfMonth: number? (para padrão mensal)
  • endDate: Date?
  • occurrenceCount: number?
  • exceptions: Date[] (datas excluídas)

Comportamentos:

  • generateOccurrences(from: Date, to: Date): Date[]
  • addException(date: Date): void

4.9 Waitlist (Aggregate Root)

Descrição: Lista de espera para reservas esgotadas.

Atributos:

  • id: WaitlistId
  • resourceId: ResourceId (Court, Lesson, Event)
  • resourceType: ResourceType
  • targetDate: Date
  • targetTimeRange: TimeRange?
  • entries: WaitlistEntry[]
  • status: WaitlistStatus (ACTIVE, CLOSED, EXPIRED)
  • expiresAt: Date?

Relacionamentos:

  • Associada a recurso específico
  • Contém múltiplos WaitlistEntry

Invariantes:

  • Entrada duplicada do mesmo usuário não permitida
  • Notificação automática quando vaga disponível

Comportamentos:

  • addEntry(user: UserId, preferences: Preferences): WaitlistEntry
  • removeEntry(entryId: EntryId): void
  • notifyAvailability(slot: ScheduleSlot): void
  • getPosition(userId: UserId): number

4.10 WaitlistEntry

Descrição: Entrada individual na waitlist.

Atributos:

  • id: EntryId
  • waitlistId: WaitlistId
  • userId: UserId
  • joinedAt: Date
  • position: number
  • preferences: WaitlistPreferences
  • notificationsSent: number
  • lastNotifiedAt: Date?
  • status: EntryStatus (WAITING, NOTIFIED, CONVERTED, EXPIRED, CANCELLED)
  • expiresAt: Date?

WaitlistPreferences (Value Object):

  • flexibleTime: boolean
  • acceptableTimeRanges: TimeRange[]?
  • maxPriceWillingToPay: Money?
  • notificationChannels: Channel[] (EMAIL, SMS, PUSH, WHATSAPP)

Relacionamentos:

  • Pertence a uma Waitlist
  • Referencia um UserAccount

Comportamentos:

  • notify(availableSlot: ScheduleSlot): void
  • convert(booking: Booking): void
  • expire(): void

5. Lessons & Coaching Context

Objetivo

Gerenciar aulas, turmas, planos de aula, instrutores, matrículas e frequência.

Aggregates

5.1 Lesson (Aggregate Root)

Descrição: Aula ou sessão de treinamento.

Atributos:

  • id: LessonId
  • arenaId: ArenaId
  • type: LessonType (PRIVATE, SEMI_PRIVATE, GROUP, CLINIC, CAMP)
  • sport: Sport
  • level: SkillLevel
  • title: string
  • description: string?
  • instructorId: InstructorId
  • courtId: CourtId?
  • classGroupId: ClassGroupId? (para aulas em turma)
  • schedule: LessonSchedule
  • capacity: LessonCapacity
  • currentEnrollment: number
  • price: Money
  • status: LessonStatus (SCHEDULED, IN_PROGRESS, COMPLETED, CANCELLED)
  • createdAt: Date

LessonSchedule (Value Object):

  • startTime: Date
  • duration: Duration
  • recurrenceRule: RecurrenceRule?

LessonCapacity (Value Object):

  • minStudents: number
  • maxStudents: number
  • currentEnrolled: number

Relacionamentos:

  • Ministrada por InstructorProfile
  • Ocorre em Court
  • Pertence a ClassGroup (se em turma)
  • Possui LessonPlan
  • Possui múltiplas LessonSession (ocorrências)
  • Possui múltiplos ClassEnrollment
  • Gera AttendanceRegister

Invariantes:

  • Aula privada: max 1-2 alunos
  • Aula em grupo: min 4, max 12 alunos
  • Instrutor não pode ter duas aulas simultâneas
  • Quadra não pode estar reservada para outro fim

Comportamentos:

  • enroll(student: PlayerId): ClassEnrollment
  • unenroll(student: PlayerId): void
  • start(): void
  • complete(): void
  • cancel(reason: string): void
  • isFull(): boolean
  • canStart(): boolean (verifica min de alunos)

5.2 LessonPlan

Descrição: Plano de aula (conteúdo pedagógico).

Atributos:

  • id: PlanId
  • lessonId: LessonId
  • title: string
  • objectives: string[]
  • warmUp: ActivityDescription
  • mainActivities: ActivityDescription[]
  • coolDown: ActivityDescription
  • equipment: Equipment[]
  • duration: Duration
  • notes: string?

ActivityDescription (Value Object):

  • name: string
  • description: string
  • duration: Duration
  • difficulty: Difficulty
  • focusAreas: string[] (ex: "forehand", "serve", "footwork")

Relacionamentos:

  • Pertence a uma Lesson

5.3 LessonSession

Descrição: Ocorrência específica de uma aula (instância).

Atributos:

  • id: SessionId
  • lessonId: LessonId
  • occurrenceNumber: number
  • scheduledStart: Date
  • scheduledEnd: Date
  • actualStart: Date?
  • actualEnd: Date?
  • instructorId: InstructorId
  • courtId: CourtId
  • status: SessionStatus (SCHEDULED, IN_PROGRESS, COMPLETED, CANCELLED, RESCHEDULED)
  • attendanceRegisterId: AttendanceRegisterId?
  • notes: string?
  • weatherConditions: WeatherConditions? (para outdoor)

Relacionamentos:

  • Pertence a uma Lesson
  • Ministrada por InstructorProfile
  • Possui AttendanceRegister

Comportamentos:

  • start(): void
  • complete(notes: string): void
  • reschedule(newDate: Date): void
  • cancel(reason: string): void

5.4 ClassGroup (Aggregate Root)

Descrição: Turma fixa de alunos (programa contínuo).

Atributos:

  • id: ClassGroupId
  • arenaId: ArenaId
  • name: string (ex: "Turma Iniciante - Terças 18h")
  • sport: Sport
  • level: SkillLevel
  • ageGroup: AgeGroup?
  • schedule: GroupSchedule (dias e horários fixos)
  • instructorId: InstructorId
  • courtId: CourtId
  • capacity: number
  • currentEnrollment: number
  • startDate: Date
  • endDate: Date?
  • price: Money (valor mensal)
  • status: ClassGroupStatus (ENROLLING, ACTIVE, COMPLETED, CANCELLED)

GroupSchedule (Value Object):

  • daysOfWeek: DayOfWeek[]
  • time: Time
  • duration: Duration
  • lessonsPerWeek: number

Relacionamentos:

  • Possui múltiplas Lesson
  • Possui múltiplos ClassEnrollment
  • Possui InstructorAssignment

Invariantes:

  • Turma não pode iniciar sem mínimo de alunos
  • Não pode exceder capacidade máxima

Comportamentos:

  • enroll(student: PlayerId): ClassEnrollment
  • unenroll(student: PlayerId, reason: string): void
  • start(): void
  • complete(): void
  • isFull(): boolean

5.5 ClassEnrollment

Descrição: Matrícula de aluno em turma ou aula.

Atributos:

  • id: EnrollmentId
  • studentId: PlayerId
  • lessonId: LessonId?
  • classGroupId: ClassGroupId?
  • enrolledAt: Date
  • startDate: Date
  • endDate: Date?
  • status: EnrollmentStatus (ACTIVE, SUSPENDED, COMPLETED, DROPPED, EXPELLED)
  • paymentStatus: PaymentStatus
  • attendanceRate: number (percentual de presença)
  • droppedAt: Date?
  • dropReason: string?

Relacionamentos:

  • Pertence a um PlayerProfile
  • Vinculada a Lesson ou ClassGroup
  • Possui múltiplos AttendanceEntry

Invariantes:

  • Matrícula ativa requer pagamento em dia
  • Drop antes do período mínimo pode gerar multa

Comportamentos:

  • suspend(reason: string, until: Date): void
  • reactivate(): void
  • drop(reason: string): void
  • calculateAttendanceRate(): number

5.6 InstructorAssignment

Descrição: Atribuição de instrutor a turma/aula.

Atributos:

  • id: AssignmentId
  • instructorId: InstructorId
  • lessonId: LessonId?
  • classGroupId: ClassGroupId?
  • assignedAt: Date
  • startDate: Date
  • endDate: Date?
  • role: InstructorRole (PRIMARY, ASSISTANT, SUBSTITUTE)
  • compensationType: CompensationType (HOURLY, PER_STUDENT, FIXED, COMMISSION)
  • compensationAmount: Money
  • status: AssignmentStatus (ACTIVE, COMPLETED, CANCELLED)

Relacionamentos:

  • Vinculado a InstructorProfile
  • Vinculado a Lesson ou ClassGroup

5.7 AttendanceRegister (Aggregate Root)

Descrição: Registro de frequência de uma sessão de aula.

Atributos:

  • id: RegisterId
  • lessonSessionId: SessionId
  • date: Date
  • instructorId: InstructorId
  • entries: AttendanceEntry[]
  • completedAt: Date?
  • completedBy: UserId?
  • status: RegisterStatus (OPEN, COMPLETED, LOCKED)

Relacionamentos:

  • Pertence a uma LessonSession
  • Contém múltiplos AttendanceEntry

Comportamentos:

  • markAttendance(student: PlayerId, status: AttendanceStatus): void
  • complete(): void
  • lock(): void (impede alterações)
  • calculateAttendanceRate(): number

5.8 AttendanceEntry

Descrição: Entrada individual de frequência.

Atributos:

  • id: EntryId
  • registerId: RegisterId
  • studentId: PlayerId
  • status: AttendanceStatus (PRESENT, ABSENT, LATE, EXCUSED, EARLY_DEPARTURE)
  • checkInTime: Date?
  • checkOutTime: Date?
  • notes: string?
  • markedBy: UserId
  • markedAt: Date

Relacionamentos:

  • Pertence a um AttendanceRegister
  • Referencia PlayerProfile

Documento continua no próximo bloco...

6. Play & Match Context

Objetivo

Gerenciar partidas, formação de times, pontuação, resultados e participação dos jogadores.

Aggregates

6.1 Match (Aggregate Root)

Descrição: Partida esportiva (casual ou competitiva).

Atributos:

  • id: MatchId
  • arenaId: ArenaId
  • courtId: CourtId
  • matchNumber: string (identificador único legível)
  • sport: Sport
  • format: MatchFormat (SINGLES, DOUBLES, MIXED_DOUBLES)
  • type: MatchType (CASUAL, FRIENDLY, COMPETITIVE, TOURNAMENT, RANKING)
  • ruleSet: MatchRuleSet
  • scheduledStart: Date
  • actualStart: Date?
  • scheduledEnd: Date
  • actualEnd: Date?
  • status: MatchStatus (SCHEDULED, IN_PROGRESS, PAUSED, COMPLETED, CANCELLED, ABANDONED)
  • teams: Team[]
  • scoreboard: Scoreboard
  • result: MatchResult?
  • hasStake: boolean (partida "valendo")
  • matchStake: MatchStake?
  • videoRecordingId: RecordingSessionId?
  • createdAt: Date
  • createdBy: UserId

Relacionamentos:

  • Ocorre em Court
  • Possui 2+ Team
  • Possui um Scoreboard
  • Possui MatchResult (ao finalizar)
  • Possui múltiplos MatchParticipation
  • Pode ter MatchStake
  • Pode ter RecordingSession (Media Context)
  • Pode ter HighlightClip (Media Context)
  • Pode ser parte de Tournament (Engagement Context)

Invariantes:

  • Singles: 2 jogadores (1 por time)
  • Doubles: 4 jogadores (2 por time)
  • Partida completada deve ter resultado
  • Partida com stake requer validação de créditos

Comportamentos:

  • start(): void
  • pause(reason: string): void
  • resume(): void
  • complete(): MatchResult
  • abandon(reason: string): void
  • cancel(reason: string): void
  • recordScore(team: TeamId, points: number): void
  • getCurrentSet(): number
  • getWinner(): Team?

6.2 MatchFormat

Descrição: Formato da partida (Value Object).

Atributos:

  • type: FormatType (SINGLES, DOUBLES, MIXED_DOUBLES)
  • scoringSystem: ScoringSystem (TRADITIONAL_TENNIS, NO_AD, MATCH_TIEBREAK, PADEL)
  • numberOfSets: number (1, 3, 5)
  • gamesPerSet: number (geralmente 6)
  • tiebreakAt: number? (ex: 6-6)
  • decidingSetType: DecidingSetType (FULL_SET, SUPER_TIEBREAK, MATCH_TIEBREAK)
  • pointsToWinTiebreak: number (geralmente 7)

6.3 MatchRuleSet

Descrição: Regras específicas da partida.

Atributos:

  • id: RuleSetId
  • matchId: MatchId
  • format: MatchFormat
  • timeLimit: Duration?
  • warmUpDuration: Duration (ex: 5 minutos)
  • breakBetweenGames: Duration (ex: 90 segundos)
  • breakBetweenSets: Duration (ex: 2 minutos)
  • medicalTimeoutAllowed: boolean
  • coachingAllowed: boolean
  • lineCallSystem: LineCallSystem (HUMAN, HAWK_EYE, SELF_CALL)
  • ballChangeFrequency: number? (a cada X games)

Relacionamentos:

  • Pertence a um Match

6.4 Team

Descrição: Time/equipe na partida.

Atributos:

  • id: TeamId
  • matchId: MatchId
  • name: string? (ex: "Team A", ou gerado automaticamente)
  • side: Side (TEAM_1, TEAM_2)
  • players: PlayerAssignment[]
  • color: TeamColor? (para identificação visual)

Relacionamentos:

  • Pertence a um Match
  • Contém múltiplos PlayerAssignment

Comportamentos:

  • addPlayer(player: PlayerId, position: Position): void
  • removePlayer(player: PlayerId): void
  • getScore(): number

6.5 PlayerAssignment

Descrição: Atribuição de jogador a time em posição específica.

Atributos:

  • id: AssignmentId
  • teamId: TeamId
  • playerId: PlayerId
  • position: Position? (PLAYER_1, PLAYER_2 para doubles)
  • side: CourtSide? (DEUCE, AD para doubles)
  • joinedAt: Date
  • leftAt: Date?
  • role: PlayerRole (REGULAR, SUBSTITUTE)

Relacionamentos:

  • Pertence a um Team
  • Referencia PlayerProfile

6.6 Scoreboard (Aggregate Root)

Descrição: Placar da partida.

Atributos:

  • id: ScoreboardId
  • matchId: MatchId
  • currentSet: number
  • currentGame: number
  • server: TeamId
  • sets: SetScore[]
  • games: GameScore[]
  • points: PointScore
  • history: ScoreEvent[]

SetScore (Value Object):

  • setNumber: number
  • team1Games: number
  • team2Games: number
  • isTiebreak: boolean
  • tiebreakScore: TiebreakScore?

GameScore (Value Object):

  • setNumber: number
  • gameNumber: number
  • team1Points: number
  • team2Points: number
  • isBreakPoint: boolean
  • isGamePoint: boolean
  • isSetPoint: boolean
  • isMatchPoint: boolean

PointScore (Value Object):

  • team1: string (ex: "0", "15", "30", "40", "AD")
  • team2: string

Relacionamentos:

  • Pertence a um Match
  • Contém múltiplos ScoreEvent

Comportamentos:

  • recordPoint(winnerTeam: TeamId): void
  • recordGame(winnerTeam: TeamId): void
  • recordSet(winnerTeam: TeamId): void
  • undo(): void (desfazer último ponto)
  • getCurrentScore(): ScoreSnapshot
  • getLeader(): TeamId?

6.7 ScoreEvent

Descrição: Evento de pontuação (histórico).

Atributos:

  • id: EventId
  • scoreboardId: ScoreboardId
  • timestamp: Date
  • type: ScoreEventType (POINT, GAME, SET, ACE, DOUBLE_FAULT, WINNER, UNFORCED_ERROR)
  • team: TeamId
  • player: PlayerId?
  • setNumber: number
  • gameNumber: number
  • scoreAfter: ScoreSnapshot
  • rallyLength: number? (quantidade de toques)
  • shotType: ShotType? (FOREHAND, BACKHAND, VOLLEY, SMASH, SERVE)
  • videoTimestamp: number? (timestamp no vídeo)

Relacionamentos:

  • Pertence a Scoreboard

Uso: Analytics, highlights automáticos, estatísticas de jogo


6.8 MatchResult

Descrição: Resultado final da partida.

Atributos:

  • id: ResultId
  • matchId: MatchId
  • winnerTeamId: TeamId
  • loserTeamId: TeamId
  • finalScore: FinalScore
  • resultType: ResultType (COMPLETED, WALKOVER, RETIREMENT, DISQUALIFICATION, TIME_LIMIT)
  • completedAt: Date
  • duration: Duration
  • statistics: MatchStatistics

FinalScore (Value Object):

  • sets: SetScore[]
  • totalGames: number
  • totalPoints: number

MatchStatistics (Value Object):

  • aces: Record<TeamId, number>
  • doubleFaults: Record<TeamId, number>
  • winners: Record<TeamId, number>
  • unforcedErrors: Record<TeamId, number>
  • breakPointsWon: Record<TeamId, number>
  • breakPointsTotal: Record<TeamId, number>
  • firstServePercentage: Record<TeamId, number>
  • pointsWonOnFirstServe: Record<TeamId, number>

Relacionamentos:

  • Pertence a um Match
  • Gera MatchParticipation para cada jogador

Comportamentos:

  • calculatePlayerStats(player: PlayerId): PlayerMatchStats

6.9 MatchParticipation

Descrição: Participação de jogador em partida (para histórico).

Atributos:

  • id: ParticipationId
  • matchId: MatchId
  • playerId: PlayerId
  • teamId: TeamId
  • result: ParticipationResult (WON, LOST, DRAW)
  • statisticsContribution: PlayerMatchStats
  • skillLevelBefore: SkillLevel
  • skillLevelAfter: SkillLevel?
  • pointsEarned: number (para ranking)
  • playedAt: Date

PlayerMatchStats (Value Object):

  • aces: number
  • doubleFaults: number
  • winners: number
  • unforcedErrors: number
  • breakPointsConverted: number

Relacionamentos:

  • Pertence a um Match
  • Referencia PlayerProfile
  • Atualiza PlayerProgress (Engagement Context)

6.10 MatchStake

Descrição: Aposta/stake em partida (partida "valendo").

Atributos:

  • id: StakeId
  • matchId: MatchId
  • type: StakeType (FRIENDLY_WAGER, CREDITS, POINTS, TOKENS, PRIZE_POOL)
  • currency: ValueUnit (credits, tokens, points, money)
  • amountPerPlayer: Money | number
  • totalPot: Money | number
  • winnerTakeAll: boolean
  • distribution: PrizeDistribution? (se não winner-take-all)
  • status: StakeStatus (PENDING, LOCKED, COMPLETED, CANCELLED, DISPUTED)
  • paidOut: boolean
  • paidOutAt: Date?

PrizeDistribution (Value Object):

  • winnerShare: Percentage
  • loserShare: Percentage? (se houver consolação)

Relacionamentos:

  • Pertence a um Match
  • Gera WalletTransaction ao finalizar (Wallet Context)

Invariantes:

  • Todos jogadores devem ter saldo suficiente antes do início
  • Stake travado não pode ser alterado
  • Pagamento automático ao resultado

Comportamentos:

  • lock(): void (travar fundos)
  • distribute(result: MatchResult): void
  • refund(reason: string): void (em caso de cancelamento)
  • dispute(reason: string): void

7. Events Context

Objetivo

Gerenciar eventos especiais (torneios internos, sociais, corporativos), participantes, ingressos e políticas de consumo.

Aggregates

7.1 Event (Aggregate Root)

Descrição: Evento especial na arena.

Atributos:

  • id: EventId
  • arenaId: ArenaId
  • type: EventType
  • title: string
  • description: string
  • slug: string
  • startDate: Date
  • endDate: Date
  • registrationStartDate: Date
  • registrationEndDate: Date
  • venue: EventVenue (áreas utilizadas)
  • capacity: number
  • currentParticipants: number
  • price: Money?
  • isPublic: boolean
  • requiresApproval: boolean
  • status: EventStatus (DRAFT, PUBLISHED, REGISTRATION_OPEN, IN_PROGRESS, COMPLETED, CANCELLED)
  • posterImage: MediaAssetId?
  • tags: Tag[]
  • createdAt: Date
  • publishedAt: Date?

Relacionamentos:

  • Ocorre em Arena
  • Possui EventConfiguration
  • Possui múltiplos EventParticipant
  • Possui múltiplos EventInvitation
  • Possui múltiplos EventAccessPass
  • Define EventZoneRuleSet
  • Define EventConsumptionPolicy
  • Pode ter Tournament associado (Engagement Context)

Invariantes:

  • Evento publicado não pode ser deletado (só cancelado)
  • Capacidade não pode ser excedida
  • Datas de registro devem estar dentro do período do evento

Comportamentos:

  • publish(): void
  • register(user: UserId): EventParticipant
  • approve(participant: ParticipantId): void
  • reject(participant: ParticipantId, reason: string): void
  • start(): void
  • complete(): void
  • cancel(reason: string): void
  • isFull(): boolean
  • canRegister(user: UserId): ValidationResult

7.2 EventType

Descrição: Tipo de evento (Value Object enum).

Valores:

  • TOURNAMENT: Torneio esportivo
  • SOCIAL: Evento social (confraternização, happy hour)
  • CORPORATE: Evento corporativo
  • CLINIC: Clínica esportiva
  • CHARITY: Evento beneficente
  • EXHIBITION: Exibição/demonstração
  • LEAGUE_MATCH: Partida de liga
  • CHAMPIONSHIP: Campeonato
  • PARTY: Festa temática
  • WORKSHOP: Workshop/palestra
  • OTHER: Outro tipo

7.3 EventConfiguration

Descrição: Configurações específicas do evento.

Atributos:

  • id: ConfigId
  • eventId: EventId
  • checkInEnabled: boolean
  • checkInStartTime: Date?
  • checkInEndTime: Date?
  • requiresWristband: boolean
  • allowsGuestPlusOne: boolean
  • maxGuestsPerParticipant: number
  • consumptionPolicy: EventConsumptionPolicy
  • zonesAllowed: ZoneId[]
  • parkingIncluded: boolean
  • dresscode: string?
  • ageRestriction: AgeRestriction?

Relacionamentos:

  • Pertence a um Event

7.4 EventParticipant

Descrição: Participante inscrito no evento.

Atributos:

  • id: ParticipantId
  • eventId: EventId
  • userId: UserId
  • registeredAt: Date
  • status: ParticipantStatus (PENDING, APPROVED, REJECTED, CHECKED_IN, ATTENDED, NO_SHOW)
  • ticketType: TicketType?
  • ticketNumber: string?
  • paymentStatus: PaymentStatus
  • checkedInAt: Date?
  • guestsCount: number
  • guestNames: string[]?
  • specialRequirements: string? (dietary, accessibility, etc)
  • wristbandId: string?

Relacionamentos:

  • Pertence a um Event
  • Referencia UserAccount
  • Possui EventAccessPass

Comportamentos:

  • approve(): void
  • reject(reason: string): void
  • checkIn(): void
  • issueWristband(wristbandId: string): void

7.5 EventInvitation

Descrição: Convite para evento privado.

Atributos:

  • id: InvitationId
  • eventId: EventId
  • invitedUserId: UserId? (null = convite aberto)
  • invitedEmail: Email?
  • invitedBy: UserId
  • code: string (código único do convite)
  • sentAt: Date
  • expiresAt: Date?
  • acceptedAt: Date?
  • declinedAt: Date?
  • status: InvitationStatus (PENDING, ACCEPTED, DECLINED, EXPIRED, REVOKED)
  • message: string?

Relacionamentos:

  • Pertence a um Event
  • Enviado para UserAccount

Comportamentos:

  • accept(): EventParticipant
  • decline(reason: string): void
  • revoke(): void
  • isValid(): boolean

7.6 EventAccessPass

Descrição: Passe de acesso para evento.

Atributos:

  • id: PassId
  • eventId: EventId
  • participantId: ParticipantId
  • passType: PassType (PARTICIPANT, GUEST, VIP, STAFF, PRESS)
  • qrCode: string (código QR único)
  • accessLevel: AccessLevel
  • zonesAllowed: ZoneId[]
  • validFrom: Date
  • validUntil: Date
  • isActive: boolean
  • usageCount: number
  • maxUsages: number?
  • lastUsedAt: Date?

Relacionamentos:

  • Pertence a um Event
  • Atribuído a EventParticipant
  • Validado em CheckInPoint (Access Context)

Comportamentos:

  • validate(at: Date): ValidationResult
  • use(): void
  • deactivate(): void
  • canAccessZone(zone: ZoneId): boolean

7.7 EventZoneRuleSet

Descrição: Regras de acesso a zonas durante evento.

Atributos:

  • id: RuleSetId
  • eventId: EventId
  • zoneId: ZoneId
  • accessRules: AccessRule[]
  • capacityOverride: number? (capacidade diferente do normal)
  • timeRestrictions: TimeRange[]?

Relacionamentos:

  • Pertence a um Event
  • Aplicada a AccessZone (Arena Context)

7.8 EventConsumptionPolicy

Descrição: Política de consumo em eventos (abstração).

Atributos Base:

  • id: PolicyId
  • eventId: EventId
  • type: ConsumptionPolicyType (ALL_INCLUSIVE, PAY_PER_ITEM, TICKET_SYSTEM, CREDIT_BASED)

Subtipos:

AllInclusivePolicy:

  • includedItems: ProductCategory[] (ex: food, beverages, soft_drinks)
  • excludedItems: ProductItemId[] (ex: premium drinks)
  • quantityLimits: Record<ProductCategory, number>?

PayPerItemPolicy:

  • priceList: PriceListId
  • taxIncluded: boolean
  • paymentMethods: PaymentMethod[]

TicketSystemPolicy:

  • ticketsPerParticipant: number
  • ticketValue: Money
  • exchangeableFor: ProductCategory[]

CreditBasedPolicy:

  • creditsPerParticipant: number
  • creditValue: Money (valor de 1 crédito)
  • productCosts: Record<ProductItemId, number> (custo em créditos)

Relacionamentos:

  • Pertence a um Event
  • Aplicada em Tab (Commerce Context)

8. Access & Presence Context

Objetivo

Gerenciar controle de acesso físico, check-in/check-out, presença e integração com sistemas de controle de acesso.

Aggregates

8.1 AccessControlSystem (Aggregate Root)

Descrição: Sistema de controle de acesso integrado.

Atributos:

  • id: SystemId
  • arenaId: ArenaId
  • vendor: string (ex: "Intelbras", "HID", "Hikvision")
  • model: string
  • apiEndpoint: string
  • apiKey: string (encrypted)
  • configuration: SystemConfiguration
  • status: SystemStatus (ONLINE, OFFLINE, ERROR, MAINTENANCE)
  • lastSyncAt: Date?

Relacionamentos:

  • Pertence a uma Arena
  • Controla múltiplos CheckInPoint
  • Usa AccessIntegrationAdapter

Comportamentos:

  • sync(): void
  • authorize(credential: Credential, zone: ZoneId): AuthorizationResult
  • revokeAccess(userId: UserId): void
  • grantTemporaryAccess(userId: UserId, zones: ZoneId[], validUntil: Date): void

8.2 AccessIntegrationAdapter

Descrição: Adaptador para integração com sistema específico.

Atributos:

  • id: AdapterId
  • systemId: SystemId
  • vendor: string
  • protocol: IntegrationProtocol (REST_API, SOAP, MQTT, TCP, WIEGAND)
  • configuration: AdapterConfiguration
  • mappings: FieldMapping[] (mapeia campos do sistema externo)

Relacionamentos:

  • Pertence a AccessControlSystem

Comportamentos:

  • connect(): void
  • disconnect(): void
  • sendCommand(command: AccessCommand): void
  • parseEvent(event: ExternalEvent): AccessEvent

8.3 CheckInPoint (Aggregate Root)

Descrição: Ponto de check-in/check-out físico.

Atributos Base:

  • id: CheckInPointId
  • arenaId: ArenaId
  • type: CheckInPointType (COURT, GATE, EVENT, AREA, VIRTUAL)
  • name: string
  • location: Location (descrição física)
  • zoneId: ZoneId
  • deviceId: DeviceId? (reader, terminal)
  • requiresManualValidation: boolean
  • isActive: boolean

Subtipos:

CourtCheckInPoint:

  • courtId: CourtId
  • checkInRadius: number? (metros, para check-in por geolocalização)

GateCheckInPoint:

  • direction: Direction (ENTRY, EXIT, BOTH)
  • hasTurnstile: boolean

EventCheckInPoint:

  • eventId: EventId

Relacionamentos:

  • Pertence a uma Arena
  • Vinculado a AccessZone
  • Conectado a Device (Devices Context)
  • Registra CheckInRecord e CheckOutRecord

Comportamentos:

  • checkIn(credential: Credential): CheckInRecord
  • checkOut(credential: Credential): CheckOutRecord
  • validateAccess(user: UserId, context: AccessContext): ValidationResult

8.4 CheckInRecord

Descrição: Registro de check-in.

Atributos:

  • id: RecordId
  • checkInPointId: CheckInPointId
  • userId: UserId
  • resourceId: ResourceId? (Court, Event, etc)
  • resourceType: ResourceType?
  • credentialType: CredentialType
  • credentialId: CredentialId
  • timestamp: Date
  • evidence: PresenceEvidence
  • validationResult: ValidationResult
  • bookingId: BookingId?
  • eventId: EventId?

Relacionamentos:

  • Gerado por CheckInPoint
  • Referencia UserAccount
  • Associado a Booking ou Event
  • Inicia PresenceSession

8.5 CheckOutRecord

Descrição: Registro de check-out.

Atributos:

  • id: RecordId
  • checkInRecordId: RecordId
  • checkInPointId: CheckInPointId
  • userId: UserId
  • timestamp: Date
  • evidence: PresenceEvidence
  • duration: Duration (tempo de permanência)

Relacionamentos:

  • Vinculado a CheckInRecord
  • Finaliza PresenceSession

8.6 PresenceSession (Aggregate Root)

Descrição: Sessão de presença contínua de um usuário.

Atributos:

  • id: SessionId
  • userId: UserId
  • arenaId: ArenaId
  • resourceId: ResourceId? (Court, Area)
  • resourceType: ResourceType?
  • startedAt: Date
  • endedAt: Date?
  • duration: Duration?
  • checkInRecordId: RecordId
  • checkOutRecordId: RecordId?
  • evidenceRecords: PresenceEvidenceId[]
  • status: SessionStatus (ACTIVE, ENDED, ABANDONED)

Relacionamentos:

  • Iniciada por CheckInRecord
  • Finalizada por CheckOutRecord
  • Contém múltiplos PresenceEvidence
  • Gera UsageAuditRecord

Comportamentos:

  • end(): void
  • abandon(reason: string): void
  • addEvidence(evidence: PresenceEvidence): void
  • getCurrentDuration(): Duration

8.7 PresenceEvidence

Descrição: Evidência de presença (abstração).

Atributos Base:

  • id: EvidenceId
  • sessionId: SessionId
  • userId: UserId
  • timestamp: Date
  • type: EvidenceType (DEVICE_TAP, QR_SCAN, RFID_SCAN, BIOMETRIC, GEOLOCATION, BLUETOOTH)

Subtipos:

DeviceTap:

  • deviceId: DeviceId
  • location: Location

QRCodeScan:

  • code: string
  • scannedBy: DeviceId

RFIDScan:

  • tagId: string
  • readerId: DeviceId
  • signalStrength: number

BiometricEvidence:

  • biometricType: BiometricType (FINGERPRINT, FACE, IRIS)
  • confidence: number

GeolocationEvidence:

  • coordinates: GeoLocation
  • accuracy: number (metros)
  • provider: string (GPS, WiFi, Bluetooth)

Relacionamentos:

  • Pertence a PresenceSession
  • Capturado por Device (Devices Context)

8.8 UsageAuditRecord

Descrição: Registro de auditoria de uso.

Atributos:

  • id: AuditRecordId
  • tenantId: TenantId
  • userId: UserId
  • resourceId: ResourceId
  • resourceType: ResourceType
  • action: AuditAction (CHECK_IN, CHECK_OUT, ACCESS_GRANTED, ACCESS_DENIED, BOOKING_CREATED, etc)
  • timestamp: Date
  • ipAddress: string?
  • deviceInfo: DeviceInfo?
  • metadata: Record<string, any>
  • result: ActionResult (SUCCESS, FAILURE, ERROR)
  • errorMessage: string?

Relacionamentos:

  • Referencia UserAccount
  • Associado a recurso específico

Uso: Compliance, LGPD, analytics, troubleshooting


Documento continua no próximo bloco...

9. Devices & IoT Context

Objetivo

Gerenciar dispositivos IoT, tablets de quadra, botões de highlight, leitores de acesso, sensores e telemetria.

Aggregates

9.1 Device (Aggregate Root)

Descrição: Dispositivo físico (abstração para diversos tipos).

Atributos Base:

  • id: DeviceId
  • arenaId: ArenaId
  • type: DeviceType (COURT_TABLET, HIGHLIGHT_BUTTON, ACCESS_READER, SCORE_TERMINAL, SENSOR, CAMERA, WEARABLE)
  • name: string
  • model: string
  • manufacturer: string
  • serialNumber: string
  • macAddress: string?
  • ipAddress: string?
  • firmwareVersion: string?
  • status: DeviceStatus (ONLINE, OFFLINE, ERROR, MAINTENANCE, DECOMMISSIONED)
  • lastSeenAt: Date?
  • installedAt: Date
  • location: DeviceLocation
  • configuration: DeviceConfiguration

Subtipos:

CourtTablet:

  • courtId: CourtId
  • screenSize: number (inches)
  • operatingSystem: string (Android, iOS)
  • appVersion: string
  • batteryLevel: number?

HighlightButton:

  • courtId: CourtId
  • buttonType: ButtonType (WALL_MOUNTED, PORTABLE, WEARABLE)
  • batteryPowered: boolean
  • batteryLevel: number?

AccessReader:

  • checkInPointId: CheckInPointId
  • readerType: ReaderType (RFID, NFC, QR, BARCODE, BIOMETRIC)
  • protocol: ReaderProtocol (WIEGAND, OSDP, TCP_IP)

ScoreTerminal:

  • courtId: CourtId
  • hasDisplay: boolean
  • displaySize: number?
  • inputType: InputType (TOUCH, KEYPAD, REMOTE)

Sensor:

  • courtId: CourtId?
  • areaId: AreaId?
  • sensorType: SensorType (TEMPERATURE, HUMIDITY, LIGHT, MOTION, OCCUPANCY)
  • measurementUnit: string
  • measurementRange: Range
  • readingInterval: Duration

Wearable:

  • wearableType: WearableType (WRISTBAND, WATCH, TAG, SENSOR_PATCH)
  • assignedTo: UserId?

Relacionamentos:

  • Pertence a uma Arena
  • Pode estar vinculado a Court, CheckInPoint, Arena Area
  • Possui DeviceRegistration
  • Pode ter DeviceAssignment (se atribuído a usuário)
  • Envia DeviceTelemetry
  • Recebe DeviceCommand
  • Emite DeviceEvent

Invariantes:

  • Serial number deve ser único
  • Dispositivo offline não pode executar comandos críticos
  • Tablet de quadra deve estar vinculado a uma quadra

Comportamentos:

  • register(): DeviceRegistration
  • assign(userId: UserId): DeviceAssignment
  • unassign(): void
  • sendCommand(command: DeviceCommand): void
  • reportTelemetry(data: TelemetryData): DeviceTelemetry
  • updateFirmware(version: string): void
  • decommission(reason: string): void

9.2 DeviceRegistration

Descrição: Registro de dispositivo no sistema.

Atributos:

  • id: RegistrationId
  • deviceId: DeviceId
  • registeredAt: Date
  • registeredBy: UserId
  • activationCode: string?
  • certificate: string? (para autenticação mTLS)
  • provisioningStatus: ProvisioningStatus (PENDING, PROVISIONED, ACTIVATED, DEACTIVATED)

Relacionamentos:

  • Pertence a um Device

9.3 DeviceAssignment

Descrição: Atribuição de dispositivo a usuário.

Atributos:

  • id: AssignmentId
  • deviceId: DeviceId
  • userId: UserId
  • assignedAt: Date
  • assignedBy: UserId
  • returnedAt: Date?
  • expectedReturnDate: Date?
  • status: AssignmentStatus (ACTIVE, RETURNED, LOST, DAMAGED)
  • notes: string?

Relacionamentos:

  • Vincula Device a UserAccount

Comportamentos:

  • return(condition: DeviceCondition): void
  • reportLost(): void
  • reportDamaged(description: string): void

9.4 DeviceTelemetry

Descrição: Dados de telemetria do dispositivo.

Atributos:

  • id: TelemetryId
  • deviceId: DeviceId
  • timestamp: Date
  • metrics: Record<string, number> (temperatura, bateria, uso de memória, CPU, etc)
  • status: DeviceStatus
  • errorCode: string?
  • errorMessage: string?

Exemplos de Métricas:

  • battery_level: 85 (%)
  • temperature: 23.5 (°C)
  • humidity: 60 (%)
  • light_level: 800 (lux)
  • cpu_usage: 45 (%)
  • memory_usage: 2048 (MB)
  • uptime: 86400 (segundos)

Relacionamentos:

  • Pertence a um Device

Uso: Monitoramento, manutenção preditiva, alertas


9.5 DeviceCommand

Descrição: Comando enviado para dispositivo.

Atributos:

  • id: CommandId
  • deviceId: DeviceId
  • type: CommandType (REBOOT, UPDATE_FIRMWARE, CHANGE_CONFIG, TRIGGER_ACTION, CAPTURE_DATA)
  • payload: Record<string, any>
  • sentAt: Date
  • sentBy: UserId
  • status: CommandStatus (PENDING, SENT, ACKNOWLEDGED, EXECUTED, FAILED, TIMEOUT)
  • executedAt: Date?
  • result: string?
  • errorMessage: string?

Exemplos de Comandos:

  • REBOOT: reiniciar dispositivo
  • UPDATE_FIRMWARE: atualizar firmware para versão X
  • CHANGE_CONFIG: alterar configuração (ex: interval de leitura)
  • TRIGGER_ACTION: acionar ação específica (ex: abrir catraca)
  • CAPTURE_DATA: capturar foto/vídeo

Relacionamentos:

  • Enviado para Device

Comportamentos:

  • acknowledge(): void
  • markExecuted(result: string): void
  • markFailed(error: string): void

9.6 DeviceEvent

Descrição: Evento emitido por dispositivo.

Atributos:

  • id: EventId
  • deviceId: DeviceId
  • type: DeviceEventType (BUTTON_PRESSED, ACCESS_GRANTED, ACCESS_DENIED, SENSOR_TRIGGERED, ERROR, BATTERY_LOW, OFFLINE, ONLINE)
  • timestamp: Date
  • data: Record<string, any>
  • severity: EventSeverity (INFO, WARNING, ERROR, CRITICAL)
  • processedAt: Date?
  • processedBy: string? (handler que processou)

Exemplos de Eventos:

  • BUTTON_PRESSED: botão de highlight pressionado
    • data: { courtId, matchId, timestamp }
  • ACCESS_GRANTED: acesso concedido
    • data: { userId, zoneId, credentialType }
  • SENSOR_TRIGGERED: sensor de movimento ativado
    • data: { sensorId, reading, threshold }
  • BATTERY_LOW: bateria baixa
    • data: { batteryLevel, estimatedRuntime }

Relacionamentos:

  • Emitido por Device
  • Pode disparar ações no sistema (ex: criar highlight, registrar acesso)

Uso: Event-driven architecture, automações, notificações


10. Media & Video Context

Objetivo

Gerenciar captação de vídeo, gravações de partidas, highlights automáticos e manuais, associação de mídia a jogadores e partidas.

Aggregates

10.1 MediaAsset (Aggregate Root)

Descrição: Ativo de mídia (abstração para vídeo, imagem, etc).

Atributos Base:

  • id: MediaAssetId
  • tenantId: TenantId
  • type: MediaType (VIDEO, IMAGE, AUDIO, DOCUMENT)
  • title: string?
  • description: string?
  • fileName: string
  • fileSize: number (bytes)
  • mimeType: string
  • storageProvider: StorageProvider (S3, AZURE, GCS, LOCAL)
  • storagePath: string
  • url: string (CDN URL)
  • thumbnailUrl: string?
  • duration: number? (para vídeos, em segundos)
  • dimensions: Dimensions? (width x height)
  • uploadedBy: UserId
  • uploadedAt: Date
  • processingStatus: ProcessingStatus (PENDING, PROCESSING, COMPLETED, FAILED)
  • tags: Tag[]
  • isPublic: boolean
  • metadata: MediaMetadata

Subtipos:

VideoAsset:

  • resolution: Resolution (1080p, 720p, 4K)
  • framerate: number (fps)
  • codec: string
  • bitrate: number (kbps)
  • hasAudio: boolean
  • streamingUrl: string? (HLS/DASH)
  • thumbnailsGenerated: boolean
  • thumbnailsInterval: number? (segundos)

ImageAsset:

  • resolution: Resolution
  • format: ImageFormat (JPEG, PNG, WEBP)
  • colorSpace: ColorSpace (RGB, CMYK)

Relacionamentos:

  • Possui múltiplos MediaAssociation (vinculação a Match, Player, Court, etc)
  • Pode ser RecordingSession (se vídeo de partida)
  • Pode ser HighlightClip (se highlight)

Invariantes:

  • URL deve ser acessível
  • Vídeos devem ter thumbnail

Comportamentos:

  • process(): void (transcodificar, gerar thumbnails)
  • generateThumbnails(): void
  • associateTo(entity: EntityId, entityType: EntityType): MediaAssociation
  • makePublic(): void
  • makePrivate(): void
  • archive(): void
  • delete(): void

10.2 Camera

Descrição: Câmera instalada na arena.

Atributos:

  • id: CameraId
  • deviceId: DeviceId (referencia Device)
  • arenaId: ArenaId
  • courtId: CourtId?
  • areaId: AreaId?
  • name: string
  • manufacturer: string
  • model: string
  • ipAddress: string
  • rtspUrl: string? (para streaming)
  • resolution: Resolution
  • framerate: number
  • hasPTZ: boolean (Pan-Tilt-Zoom)
  • hasNightVision: boolean
  • viewAngle: ViewAngle
  • position: CameraPosition (descrição da posição)
  • status: CameraStatus (ONLINE, OFFLINE, RECORDING, ERROR)

Relacionamentos:

  • Pertence a Arena
  • Vinculada a Court ou ArenaArea
  • Gera RecordingSession

Comportamentos:

  • startRecording(): RecordingSession
  • stopRecording(): void
  • moveToPosition(pan: number, tilt: number, zoom: number): void (se PTZ)
  • captureSnapshot(): ImageAsset

10.3 RecordingSession (Aggregate Root)

Descrição: Sessão de gravação de vídeo.

Atributos:

  • id: SessionId
  • cameraId: CameraId
  • matchId: MatchId?
  • courtId: CourtId
  • startedAt: Date
  • endedAt: Date?
  • duration: Duration?
  • status: RecordingStatus (RECORDING, STOPPED, PROCESSING, COMPLETED, FAILED)
  • videoAssetId: MediaAssetId?
  • storageSize: number? (bytes)
  • recordingQuality: Quality (LOW, MEDIUM, HIGH, ULTRA)
  • isAutoRecording: boolean (gravação automática vs manual)
  • triggeredBy: UserId?

Relacionamentos:

  • Capturada por Camera
  • Associada a Match (se gravação de partida)
  • Gera VideoAsset
  • Pode gerar múltiplos HighlightClip

Invariantes:

  • Sessão finalizada deve ter vídeo associado
  • Duração deve ser positiva

Comportamentos:

  • stop(): VideoAsset
  • process(): void
  • generateHighlights(triggers: HighlightTrigger[]): HighlightClip[]
  • archive(): void
  • delete(reason: string): void

10.4 HighlightClip (Aggregate Root)

Descrição: Clip de highlight (momento marcante).

Atributos:

  • id: ClipId
  • recordingSessionId: SessionId
  • videoAssetId: MediaAssetId
  • matchId: MatchId?
  • title: string
  • description: string?
  • startTime: number (timestamp no vídeo original, segundos)
  • endTime: number
  • duration: Duration
  • type: HighlightType (ACE, WINNER, RALLY, MATCH_POINT, FUNNY_MOMENT, CUSTOM)
  • automaticallyGenerated: boolean
  • confidence: number? (0-1, se gerado por IA)
  • tags: Tag[]
  • associatedPlayers: PlayerId[]
  • createdAt: Date
  • createdBy: UserId?
  • views: number
  • likes: number
  • shares: number

Relacionamentos:

  • Extraído de RecordingSession
  • Referencia VideoAsset
  • Associado a Match
  • Criado por HighlightTrigger
  • Associado a PlayerProfile (via MediaAssociation)

Comportamentos:

  • view(): void (incrementar contador)
  • like(userId: UserId): void
  • unlike(userId: UserId): void
  • share(platform: string): void
  • edit(startTime: number, endTime: number): void
  • publish(): void
  • unpublish(): void

10.5 HighlightTrigger

Descrição: Gatilho para criação de highlight.

Atributos:

  • id: TriggerId
  • recordingSessionId: SessionId
  • type: TriggerType (BUTTON_PRESS, APP_ACTION, SCORE_EVENT, AI_DETECTION)
  • timestamp: Date
  • videoTimestamp: number (timestamp no vídeo, segundos)
  • triggeredBy: UserId? (se manual)
  • deviceId: DeviceId? (se por botão físico)
  • scoreEventId: ScoreEventId? (se por evento de pontuação)
  • metadata: Record<string, any>
  • processed: boolean
  • processedAt: Date?
  • resultingClipId: ClipId?

Subtipos:

ButtonTrigger:

  • deviceId: DeviceId (HighlightButton)
  • buttonLocation: Location

AppTrigger:

  • userId: UserId
  • appVersion: string
  • deviceType: DeviceType

ScoreEventTrigger:

  • scoreEventId: ScoreEventId
  • eventType: ScoreEventType (ACE, WINNER, MATCH_POINT)

AIDetectionTrigger:

  • detectionType: AIDetectionType (RALLY, EMOTION, ACTION)
  • confidence: number
  • detectionModel: string

Relacionamentos:

  • Pertence a RecordingSession
  • Pode ser originado de Device (HighlightButton)
  • Pode ser originado de ScoreEvent (Play Context)
  • Gera HighlightClip

Comportamentos:

  • process(): HighlightClip
  • calculateClipBoundaries(): { start: number, end: number }

10.6 MediaAssociation

Descrição: Associação de mídia a entidades do domínio.

Atributos:

  • id: AssociationId
  • mediaAssetId: MediaAssetId
  • entityId: string (Match, Player, Court, etc)
  • entityType: EntityType
  • associationType: AssociationType (PROFILE_PICTURE, MATCH_VIDEO, HIGHLIGHT, EVIDENCE, DOCUMENTATION)
  • associatedAt: Date
  • associatedBy: UserId?
  • displayOrder: number? (para ordenação)
  • isPrimary: boolean (ex: foto de perfil principal)

Exemplos:

  • Vídeo de partida → Match
  • Highlight → Player + Match
  • Foto de perfil → Player
  • Foto de quadra → Court
  • Vídeo promocional → Arena

Relacionamentos:

  • Vincula MediaAsset a qualquer entidade
  • Permite relacionamento many-to-many

11. Commerce & Billing Context

Objetivo

Gerenciar produtos, vendas, consumo, pagamentos, assinaturas, pacotes, créditos, faturas, comissões e pagamentos a instrutores.

Aggregates

11.1 ProductItem (Aggregate Root)

Descrição: Item/produto vendido na arena.

Atributos:

  • id: ProductItemId
  • arenaId: ArenaId
  • sku: string (código único)
  • name: string
  • description: string?
  • category: ProductCategory (COURT_RENTAL, LESSON, EQUIPMENT, FOOD, BEVERAGE, MERCHANDISE, DAY_USE, MEMBERSHIP)
  • type: ProductType (GOOD, SERVICE, DIGITAL)
  • unit: Unit (HOUR, UNIT, LESSON, MONTH)
  • price: Money
  • taxProfile: TaxProfileId
  • isActive: boolean
  • requiresInventory: boolean
  • stockQuantity: number?
  • minStock: number?
  • imageUrl: string?
  • tags: Tag[]

Relacionamentos:

  • Pertence a Arena
  • Possui TaxProfile
  • Listado em PriceList
  • Vendido em OrderLine
  • Consumido em Tab

Invariantes:

  • SKU deve ser único por arena
  • Produto inativo não pode ser vendido
  • Produto com estoque deve controlar quantidade

Comportamentos:

  • adjustStock(quantity: number, reason: string): void
  • isAvailable(): boolean
  • calculatePrice(quantity: number): Money
  • applyDiscount(discount: Discount): Money

11.2 PriceList

Descrição: Lista de preços (pode variar por contexto).

Atributos:

  • id: PriceListId
  • arenaId: ArenaId
  • name: string
  • type: PriceListType (STANDARD, HAPPY_HOUR, WEEKEND, MEMBER, VIP, EVENT)
  • effectiveFrom: Date
  • effectiveUntil: Date?
  • prices: ProductPrice[]
  • isActive: boolean

ProductPrice (Value Object):

  • productItemId: ProductItemId
  • price: Money
  • discountPercentage: number?

Relacionamentos:

  • Pertence a Arena
  • Aplica preços a ProductItem

Comportamentos:

  • getPrice(productId: ProductItemId): Money
  • isEffective(date: Date): boolean

11.3 TaxProfile

Descrição: Perfil tributário.

Atributos:

  • id: TaxProfileId
  • arenaId: ArenaId
  • name: string
  • taxes: Tax[]
  • isActive: boolean

Tax (Value Object):

  • name: string (ex: "ICMS", "ISS", "Service Fee")
  • type: TaxType (PERCENTAGE, FIXED)
  • rate: number (percentual ou valor fixo)
  • isInclusive: boolean (incluído no preço ou adicional)

Relacionamentos:

  • Aplicado a ProductItem

Comportamentos:

  • calculate(baseAmount: Money): Money
  • getTotalRate(): number

11.4 Order (Aggregate Root)

Descrição: Pedido/ordem de venda.

Atributos:

  • id: OrderId
  • arenaId: ArenaId
  • orderNumber: string
  • customerId: UserId
  • orderDate: Date
  • lines: OrderLine[]
  • subtotal: Money
  • taxAmount: Money
  • discountAmount: Money
  • total: Money
  • status: OrderStatus (DRAFT, CONFIRMED, PAID, PARTIALLY_REFUNDED, REFUNDED, CANCELLED)
  • paymentStatus: PaymentStatus (PENDING, PAID, PARTIAL, REFUNDED)
  • source: OrderSource (POS, ONLINE, MOBILE_APP, KIOSK)
  • notes: string?
  • createdBy: UserId
  • createdAt: Date

Relacionamentos:

  • Pertence a Arena
  • Cliente: UserAccount
  • Contém múltiplos OrderLine
  • Possui múltiplos Payment
  • Pode gerar Invoice

Invariantes:

  • Ordem confirmada não pode alterar items
  • Total deve ser soma de linhas + taxas - descontos
  • Pagamento total deve igualar valor da ordem

Comportamentos:

  • addLine(product: ProductItemId, quantity: number, price: Money): OrderLine
  • removeLine(lineId: OrderLineId): void
  • applyDiscount(discount: Discount): void
  • confirm(): void
  • cancel(reason: string): void
  • calculateTotal(): Money

11.5 OrderLine

Descrição: Linha de pedido (item individual).

Atributos:

  • id: OrderLineId
  • orderId: OrderId
  • lineNumber: number
  • productItemId: ProductItemId
  • productName: string (snapshot)
  • quantity: number
  • unitPrice: Money
  • discount: Money?
  • taxAmount: Money
  • total: Money
  • notes: string?

Relacionamentos:

  • Pertence a um Order
  • Referencia ProductItem

Comportamentos:

  • calculateTotal(): Money

11.6 Tab (Aggregate Root)

Descrição: Comanda de consumo (tipicamente em eventos ou áreas de hospitalidade).

Atributos:

  • id: TabId
  • arenaId: ArenaId
  • tabNumber: string
  • ownerId: UserId
  • eventId: EventId? (se em evento)
  • zoneId: ZoneId? (zona onde é válida)
  • openedAt: Date
  • closedAt: Date?
  • lines: TabLine[]
  • subtotal: Money
  • taxAmount: Money
  • serviceCharge: Money?
  • total: Money
  • status: TabStatus (OPEN, CLOSED, PAID, TRANSFERRED)
  • paymentStatus: PaymentStatus
  • consumptionPolicy: EventConsumptionPolicyId?

Relacionamentos:

  • Pertence a Arena
  • Proprietário: UserAccount
  • Pode estar associada a Event
  • Contém múltiplos TabLine
  • Registra ConsumptionRecord
  • Possui Payment ao fechar

Invariantes:

  • Comanda fechada não aceita novos itens
  • Total deve ser calculado segundo política de consumo do evento

Comportamentos:

  • addItem(product: ProductItemId, quantity: number): TabLine
  • removeItem(lineId: TabLineId): void
  • close(): void
  • pay(payment: Payment): void
  • transfer(newOwner: UserId): void
  • split(portions: number): Tab[] (dividir comanda)

11.7 TabLine

Descrição: Item consumido na comanda.

Atributos:

  • id: TabLineId
  • tabId: TabId
  • lineNumber: number
  • productItemId: ProductItemId
  • productName: string
  • quantity: number
  • unitPrice: Money
  • total: Money
  • consumedAt: Date
  • servedBy: UserId? (staff)

Relacionamentos:

  • Pertence a um Tab
  • Referencia ProductItem

11.8 ConsumptionRecord

Descrição: Registro de consumo individual.

Atributos:

  • id: RecordId
  • tabId: TabId?
  • userId: UserId
  • productItemId: ProductItemId
  • quantity: number
  • consumedAt: Date
  • location: Location?
  • zoneId: ZoneId?
  • withinAllowance: boolean (se dentro do permitido pela política)
  • chargeApplied: Money?

Relacionamentos:

  • Vinculado a Tab (se houver)
  • Referencia UserAccount e ProductItem

Uso: Controle de consumo em eventos all-inclusive, analytics


11.9 ConsumptionZoneAllowance

Descrição: Permissão de consumo em zona específica.

Atributos:

  • id: AllowanceId
  • userId: UserId
  • eventId: EventId?
  • zoneId: ZoneId
  • allowedCategories: ProductCategory[]
  • quantityLimit: number?
  • valueLimit: Money?
  • validFrom: Date
  • validUntil: Date
  • currentUsage: number
  • currentValue: Money

Relacionamentos:

  • Pertence a UserAccount
  • Aplicada em AccessZone
  • Definida por EventConsumptionPolicy

Comportamentos:

  • canConsume(product: ProductItemId, quantity: number): boolean
  • recordConsumption(product: ProductItemId, quantity: number): void
  • getRemainingAllowance(): number | Money

11.10 Payment (Aggregate Root)

Descrição: Pagamento realizado.

Atributos:

  • id: PaymentId
  • arenaId: ArenaId
  • payerId: UserId
  • amount: Money
  • method: PaymentMethod
  • status: PaymentStatus (PENDING, PROCESSING, AUTHORIZED, CAPTURED, COMPLETED, FAILED, REFUNDED)
  • transactionId: string? (ID do gateway)
  • gatewayResponse: string?
  • paidAt: Date?
  • refundedAt: Date?
  • refundAmount: Money?
  • relatedOrderId: OrderId?
  • relatedTabId: TabId?
  • relatedInvoiceId: InvoiceId?
  • metadata: Record<string, any>
  • createdAt: Date

Relacionamentos:

  • Pago por UserAccount
  • Associado a Order, Tab, ou Invoice
  • Usa PaymentMethod

Invariantes:

  • Pagamento completado não pode ser editado
  • Reembolso não pode exceder valor pago

Comportamentos:

  • authorize(): void
  • capture(): void
  • complete(): void
  • fail(reason: string): void
  • refund(amount: Money, reason: string): void

11.11 PaymentMethod

Descrição: Método de pagamento (Value Object/Enum).

Valores:

  • CASH: Dinheiro
  • CREDIT_CARD: Cartão de crédito
  • DEBIT_CARD: Cartão de débito
  • PIX: PIX
  • BANK_TRANSFER: Transferência bancária
  • WALLET: Carteira digital (da arena)
  • CREDIT_PACKAGE: Pacote de créditos
  • INVOICE: Faturado (pagamento posterior)
  • COMPLIMENTARY: Cortesia

11.12 BillingAccount (Aggregate Root)

Descrição: Conta de cobrança (para clientes corporativos ou mensalidades).

Atributos:

  • id: BillingAccountId
  • arenaId: ArenaId
  • accountNumber: string
  • accountHolder: UserId (empresa ou pessoa)
  • billingAddress: Address
  • taxId: string (CNPJ/CPF)
  • paymentTerms: PaymentTerms (ex: NET 30)
  • creditLimit: Money?
  • currentBalance: Money
  • status: AccountStatus (ACTIVE, SUSPENDED, CLOSED)
  • createdAt: Date

Relacionamentos:

  • Pertence a Arena
  • Titular: UserAccount
  • Gera múltiplas Invoice

Comportamentos:

  • addCharge(amount: Money, description: string): void
  • addCredit(amount: Money, description: string): void
  • generateInvoice(period: DateRange): Invoice
  • suspend(reason: string): void

11.13 Subscription (Aggregate Root)

Descrição: Assinatura recorrente (mensalidade, plano).

Atributos:

  • id: SubscriptionId
  • arenaId: ArenaId
  • subscriberId: UserId
  • planId: SubscriptionPlanId
  • status: SubscriptionStatus (ACTIVE, PAUSED, CANCELLED, EXPIRED, PAST_DUE)
  • startDate: Date
  • endDate: Date?
  • nextBillingDate: Date
  • billingCycle: BillingCycle (MONTHLY, QUARTERLY, YEARLY)
  • price: Money
  • paymentMethod: PaymentMethod
  • autoRenew: boolean
  • cancelledAt: Date?
  • cancellationReason: string?

Relacionamentos:

  • Pertence a Arena
  • Assinante: UserAccount
  • Baseada em SubscriptionPlan
  • Gera Invoice recorrente

Invariantes:

  • Assinatura ativa requer pagamento em dia
  • Cancelamento respeitando período de aviso

Comportamentos:

  • pause(until: Date): void
  • resume(): void
  • cancel(reason: string): void
  • renew(): void
  • changePlan(newPlan: SubscriptionPlanId): void

11.14 SubscriptionPlan

Descrição: Plano de assinatura.

Atributos:

  • id: PlanId
  • arenaId: ArenaId
  • name: string
  • description: string
  • price: Money
  • billingCycle: BillingCycle
  • benefits: PlanBenefit[]
  • courtCredits: number? (créditos de quadra inclusos)
  • lessonCredits: number?
  • discountPercentage: number? (desconto em produtos)
  • priorityBooking: boolean
  • guestPasses: number?
  • isActive: boolean

PlanBenefit (Value Object):

  • type: BenefitType (COURT_CREDIT, LESSON_DISCOUNT, FREE_DAY_USE, PRIORITY_BOOKING)
  • quantity: number?
  • description: string

Relacionamentos:

  • Pertence a Arena
  • Usado por múltiplas Subscription

11.15 Package (Aggregate Root)

Descrição: Pacote de créditos/serviços pré-pago.

Atributos:

  • id: PackageId
  • arenaId: ArenaId
  • name: string
  • description: string
  • price: Money
  • credits: PackageCredit[]
  • validityPeriod: Duration (ex: 90 dias)
  • isTransferable: boolean
  • isRefundable: boolean
  • isActive: boolean

PackageCredit (Value Object):

  • type: CreditType (COURT_HOUR, LESSON, DAY_USE, GENERAL)
  • quantity: number
  • restrictions: CreditRestriction[]? (ex: "apenas dias úteis")

Relacionamentos:

  • Pertence a Arena
  • Adquirido em Order
  • Gera CreditWallet

11.16 CreditWallet

Descrição: Carteira de créditos de um usuário.

Atributos:

  • id: WalletId
  • userId: UserId
  • packageId: PackageId? (se veio de pacote)
  • creditType: CreditType
  • balance: number
  • originalBalance: number
  • purchasedAt: Date
  • expiresAt: Date?
  • status: WalletStatus (ACTIVE, EXPIRED, DEPLETED)

Relacionamentos:

  • Pertence a UserAccount
  • Originada de Package

Comportamentos:

  • debit(amount: number, reason: string): void
  • credit(amount: number, reason: string): void
  • isExpired(): boolean
  • getAvailableBalance(): number

11.17 Invoice (Aggregate Root)

Descrição: Fatura/Nota fiscal.

Atributos:

  • id: InvoiceId
  • arenaId: ArenaId
  • invoiceNumber: string
  • billingAccountId: BillingAccountId?
  • customerId: UserId
  • issueDate: Date
  • dueDate: Date
  • periodStart: Date?
  • periodEnd: Date?
  • lines: InvoiceLine[]
  • subtotal: Money
  • taxAmount: Money
  • total: Money
  • amountPaid: Money
  • amountDue: Money
  • status: InvoiceStatus (DRAFT, ISSUED, SENT, PAID, OVERDUE, CANCELLED, REFUNDED)
  • paidAt: Date?
  • pdfUrl: string?
  • xmlUrl: string? (NFe XML)
  • nfeKey: string? (chave de acesso NFe)

Relacionamentos:

  • Pertence a Arena
  • Cliente: UserAccount
  • Associada a BillingAccount (se corporativo)
  • Contém múltiplos InvoiceLine
  • Possui Payment

Comportamentos:

  • issue(): void
  • send(email: Email): void
  • pay(payment: Payment): void
  • cancel(reason: string): void
  • generatePDF(): string
  • generateNFe(): string (integração fiscal)

11.18 Refund

Descrição: Reembolso/Estorno.

Atributos:

  • id: RefundId
  • arenaId: ArenaId
  • originalPaymentId: PaymentId
  • amount: Money
  • reason: string
  • requestedBy: UserId
  • requestedAt: Date
  • approvedBy: UserId?
  • approvedAt: Date?
  • processedAt: Date?
  • status: RefundStatus (REQUESTED, APPROVED, DENIED, PROCESSING, COMPLETED, FAILED)
  • method: RefundMethod (ORIGINAL_METHOD, CREDIT, TRANSFER)

Relacionamentos:

  • Associado a Payment original
  • Pode gerar Payment negativo ou CreditWallet

Comportamentos:

  • approve(approver: UserId): void
  • deny(reason: string): void
  • process(): void
  • complete(): void

11.19 CommissionRule

Descrição: Regra de comissionamento (para instrutores, vendedores).

Atributos:

  • id: RuleId
  • arenaId: ArenaId
  • name: string
  • applicableTo: CommissionTarget (INSTRUCTOR, SALESPERSON, STAFF)
  • type: CommissionType (PERCENTAGE, FIXED_PER_UNIT, TIERED)
  • rate: number (percentual ou valor)
  • tiers: CommissionTier[]? (se tiered)
  • appliesTo: ProductCategory[]
  • minimumAmount: Money?
  • effectiveFrom: Date
  • effectiveUntil: Date?
  • isActive: boolean

CommissionTier (Value Object):

  • from: Money (valor mínimo)
  • to: Money? (valor máximo, null = infinito)
  • rate: number

Relacionamentos:

  • Pertence a Arena
  • Aplicada a InstructorProfile, StaffProfile

Comportamentos:

  • calculate(amount: Money): Money
  • isApplicable(date: Date, product: ProductItemId): boolean

11.20 Payout (Aggregate Root)

Descrição: Pagamento/repasse (genérico).

Atributos:

  • id: PayoutId
  • arenaId: ArenaId
  • recipientId: UserId
  • recipientType: RecipientType (INSTRUCTOR, STAFF, VENDOR, PARTNER)
  • amount: Money
  • period: DateRange
  • items: PayoutItem[]
  • status: PayoutStatus (PENDING, APPROVED, PAID, CANCELLED)
  • approvedBy: UserId?
  • approvedAt: Date?
  • paidAt: Date?
  • paymentMethod: PaymentMethod
  • referenceNumber: string?

PayoutItem (Value Object):

  • description: string
  • amount: Money
  • referenceId: string? (Order, Lesson, etc)
  • referenceType: string?

Relacionamentos:

  • Pertence a Arena
  • Destinatário: UserAccount (Instructor, Staff)

Comportamentos:

  • approve(approver: UserId): void
  • pay(payment: Payment): void
  • cancel(reason: string): void

11.21 InstructorPayout

Descrição: Pagamento específico para instrutor (herda de Payout).

Atributos (adicionais):

  • instructorId: InstructorId
  • lessons: LessonId[]
  • totalHours: number
  • hourlyRate: Money
  • commissions: Money
  • bonuses: Money?
  • deductions: Money?

Relacionamentos:

  • Destinatário: InstructorProfile
  • Baseado em Lesson ministradas
  • Usa CommissionRule

Documento continua no próximo bloco...

12. Wallet & Value Context

Objetivo

Gerenciar carteiras digitais multi-moeda (dinheiro real, tokens da arena, pontos, créditos), transações, apostas, prêmios, cashback, conversões e políticas de uso.

Aggregates

12.1 Wallet (Aggregate Root)

Descrição: Carteira digital multi-moeda e multi-propósito.

Atributos:

  • id: WalletId
  • ownerId: WalletOwnerId
  • ownerType: WalletOwnerType (USER, ARENA, APPLICATION, EVENT)
  • walletNumber: string (identificador único)
  • type: WalletType (PERSONAL, CORPORATE, SYSTEM, ESCROW, PRIZE_POOL)
  • balances: WalletBalance[] (múltiplas moedas/tokens)
  • status: WalletStatus (ACTIVE, SUSPENDED, FROZEN, CLOSED)
  • createdAt: Date
  • suspendedAt: Date?
  • suspensionReason: string?

Relacionamentos:

  • Pertence a WalletOwner (User, Arena, Application, Event)
  • Possui múltiplos WalletBalance (uma por ValueUnit)
  • Registra múltiplas WalletTransaction
  • Possui WalletPolicy
  • Auditada por WalletAuditTrail

Invariantes:

  • Saldo não pode ser negativo (exceto wallets especiais)
  • Wallet suspensa não aceita transações
  • Cada ValueUnit tem apenas um balance

Comportamentos:

  • getBalance(valueUnit: ValueUnit): Money | number
  • credit(amount: Money | number, valueUnit: ValueUnit, reason: string): WalletTransaction
  • debit(amount: Money | number, valueUnit: ValueUnit, reason: string): WalletTransaction
  • transfer(toWallet: WalletId, amount: Money | number, valueUnit: ValueUnit): WalletTransaction
  • freeze(reason: string): void
  • unfreeze(): void
  • canTransact(amount: Money | number, valueUnit: ValueUnit): boolean

12.2 WalletOwner

Descrição: Proprietário de carteira (abstração).

Valores:

  • USER: Carteira pessoal de usuário
  • ARENA: Carteira da arena (revenue)
  • APPLICATION: Carteira do sistema (fees, reservas)
  • EVENT: Carteira de evento (prize pool, cashback pool)
  • ESCROW: Carteira de garantia (stakes, apostas)

12.3 WalletBalance

Descrição: Saldo de uma moeda/token específica.

Atributos:

  • id: BalanceId
  • walletId: WalletId
  • valueUnit: ValueUnit
  • available: Money | number (disponível para uso)
  • locked: Money | number (bloqueado, ex: apostas pendentes)
  • total: Money | number (available + locked)
  • lastTransactionAt: Date?
  • lastTransactionId: TransactionId?

Relacionamentos:

  • Pertence a uma Wallet
  • Associado a um ValueUnit

Invariantes:

  • total = available + locked
  • available >= 0
  • locked >= 0

Comportamentos:

  • lock(amount: Money | number): void
  • unlock(amount: Money | number): void
  • add(amount: Money | number): void
  • subtract(amount: Money | number): void

12.4 WalletTransaction (Aggregate Root)

Descrição: Transação de carteira (abstração para múltiplos tipos).

Atributos Base:

  • id: TransactionId
  • walletId: WalletId
  • type: TransactionType (CREDIT, DEBIT, TRANSFER, REWARD, BET, CASHBACK, CONVERSION, EXPIRATION, ADJUSTMENT)
  • valueUnit: ValueUnit
  • amount: Money | number
  • balanceBefore: Money | number
  • balanceAfter: Money | number
  • status: TransactionStatus (PENDING, PROCESSING, COMPLETED, FAILED, REVERSED)
  • timestamp: Date
  • description: string
  • metadata: Record<string, any>
  • relatedEntityId: string? (Order, Match, Bet, etc)
  • relatedEntityType: string?
  • initiatedBy: UserId?
  • reversedAt: Date?
  • reversalReason: string?

Subtipos:

CreditTransaction:

  • source: CreditSource (PURCHASE, REFUND, REWARD, BONUS, TRANSFER_IN, ADMIN_ADJUSTMENT)
  • sourceTransactionId: TransactionId?

DebitTransaction:

  • destination: DebitDestination (PURCHASE, WITHDRAWAL, TRANSFER_OUT, FEE, EXPIRATION, PENALTY)
  • destinationTransactionId: TransactionId?

TransferTransaction:

  • fromWalletId: WalletId
  • toWalletId: WalletId
  • fee: Money?

RewardTransaction:

  • rewardRuleId: RewardRuleId
  • triggerEvent: string (ex: "match_completed", "referral", "milestone")
  • multiplier: number?

BetTransaction:

  • matchId: MatchId
  • betAmount: Money | number
  • potentialWin: Money | number
  • odds: number?

CashbackTransaction:

  • originalTransactionId: TransactionId
  • cashbackRate: number
  • calculatedFrom: Money

ConversionTransaction:

  • fromValueUnit: ValueUnit
  • toValueUnit: ValueUnit
  • fromAmount: Money | number
  • toAmount: Money | number
  • exchangeRate: number
  • conversionRuleId: ConversionRuleId

Relacionamentos:

  • Pertence a uma Wallet
  • Registrada em TransactionLedger
  • Pode gerar outra transação (ex: transfer gera crédito + débito)

Invariantes:

  • Transação completada é imutável
  • Reversão cria nova transação (não altera original)
  • Balance before + amount = balance after

Comportamentos:

  • complete(): void
  • fail(reason: string): void
  • reverse(reason: string): WalletTransaction

12.5 ValueUnit

Descrição: Unidade de valor (moeda ou token).

Atributos:

  • id: ValueUnitId
  • type: ValueUnitType (CURRENCY, ARENA_TOKEN, POINT, CREDIT)
  • code: string (ex: "BRL", "USD", "STC_TOKEN", "POINTS")
  • name: string
  • symbol: string? (ex: "R$", "ST")
  • decimals: number (casas decimais, ex: 2 para moeda)
  • isActive: boolean

Subtipos:

Currency:

  • isoCode: string (ISO 4217)
  • country: string

ArenaToken:

  • arenaId: ArenaId
  • tokenDefinition: TokenDefinitionId
  • canBeTraded: boolean
  • canBeTransferred: boolean

Point:

  • pointSystem: PointSystem (LOYALTY, RANKING, EXPERIENCE)
  • expirationRule: ExpirationRuleId?

Credit:

  • creditType: CreditType (COURT_HOUR, LESSON, DAY_USE, GENERAL)
  • expirationRule: ExpirationRuleId?

Relacionamentos:

  • Usado em WalletBalance
  • Usado em WalletTransaction
  • Pode ter ExchangeRule para conversão

12.6 TokenDefinition (Aggregate Root)

Descrição: Definição de token customizado da arena.

Atributos:

  • id: TokenDefinitionId
  • arenaId: ArenaId
  • code: string (ex: "PADDLE_COIN")
  • name: string (ex: "Paddle Coin")
  • symbol: string (ex: "PC")
  • description: string?
  • type: TokenType (UTILITY, REWARD, STAKE)
  • totalSupply: number? (limite de emissão)
  • currentSupply: number
  • mintable: boolean (pode emitir mais)
  • burnable: boolean (pode destruir)
  • transferable: boolean
  • tradeable: boolean (pode trocar entre usuários)
  • pegged: boolean (atrelado a moeda real)
  • pegRatio: number? (1 token = X reais)
  • expirationRule: ExpirationRuleId?
  • rewardRules: RewardRuleId[]
  • isActive: boolean
  • launchedAt: Date

Relacionamentos:

  • Pertence a Arena
  • Gera ArenaToken (ValueUnit)
  • Usa RewardRule, ExpirationRule

Comportamentos:

  • mint(amount: number, recipient: WalletId): void
  • burn(amount: number, fromWallet: WalletId): void
  • calculateValue(amount: number): Money (se pegged)

12.7 ExchangeRule

Descrição: Regra de conversão entre unidades de valor.

Atributos:

  • id: RuleId
  • arenaId: ArenaId
  • name: string
  • fromValueUnit: ValueUnit
  • toValueUnit: ValueUnit
  • exchangeRate: number
  • inverseRate: number
  • fee: Money | number?
  • feeType: FeeType (PERCENTAGE, FIXED)
  • minAmount: Money | number?
  • maxAmount: Money | number?
  • dailyLimit: Money | number?
  • effectiveFrom: Date
  • effectiveUntil: Date?
  • isActive: boolean

Exemplos:

  • 1 BRL = 10 PADDLE_COINS
  • 100 POINTS = 1 COURT_CREDIT
  • 1 USD = 5.20 BRL

Relacionamentos:

  • Pertence a Arena
  • Converte entre ValueUnit
  • Usada em ConversionTransaction

Comportamentos:

  • convert(amount: Money | number): Money | number
  • calculateFee(amount: Money | number): Money | number
  • isAvailable(date: Date): boolean

12.8 ConversionRule

Descrição: Regra específica de conversão (alias para ExchangeRule com lógica adicional).

Atributos Adicionais:

  • requiresApproval: boolean
  • autoConvert: boolean (conversão automática)
  • conversionSchedule: Schedule? (ex: converter pontos em créditos mensalmente)

12.9 ExpirationRule

Descrição: Regra de expiração de valores.

Atributos:

  • id: RuleId
  • arenaId: ArenaId
  • name: string
  • valueUnit: ValueUnit
  • expirationType: ExpirationType (FIXED_DATE, DURATION_FROM_ACQUISITION, ROLLING_WINDOW, NEVER)
  • duration: Duration? (se DURATION_FROM_ACQUISITION)
  • fixedDate: Date? (se FIXED_DATE)
  • rollingWindowSize: Duration? (se ROLLING_WINDOW)
  • warningBefore: Duration (avisar antes de expirar)
  • action: ExpirationAction (EXPIRE, CONVERT, EXTEND)
  • convertTo: ValueUnit? (se action = CONVERT)
  • conversionRate: number?
  • isActive: boolean

Exemplos:

  • Créditos expiram em 90 dias após compra
  • Pontos expiram em 31/12 de cada ano
  • Tokens nunca expiram

Relacionamentos:

  • Aplicada a ValueUnit
  • Pode gerar WalletTransaction (expiration)

Comportamentos:

  • isExpired(acquisitionDate: Date, now: Date): boolean
  • getExpirationDate(acquisitionDate: Date): Date
  • apply(wallet: WalletId, amount: Money | number): void

12.10 RewardRule (Aggregate Root)

Descrição: Regra de recompensa.

Atributos:

  • id: RuleId
  • arenaId: ArenaId
  • name: string
  • description: string?
  • trigger: RewardTrigger (MATCH_COMPLETION, MATCH_WIN, REFERRAL, MILESTONE, PURCHASE, CHECK_IN_STREAK)
  • conditions: RewardCondition[]
  • rewardType: RewardType (FIXED, PERCENTAGE, TIERED, MULTIPLIER)
  • valueUnit: ValueUnit
  • amount: Money | number?
  • percentage: number?
  • tiers: RewardTier[]?
  • maxPerUser: number? (limite por usuário)
  • maxPerPeriod: number? (limite global)
  • effectiveFrom: Date
  • effectiveUntil: Date?
  • isActive: boolean

RewardTrigger (Value Object):

  • event: string (nome do evento que dispara)
  • frequency: TriggerFrequency (ONCE, DAILY, WEEKLY, ALWAYS)

RewardCondition (Value Object):

  • field: string (ex: "match.type", "user.skillLevel")
  • operator: Operator (EQUALS, GREATER_THAN, IN, NOT_IN)
  • value: any

RewardTier (Value Object):

  • from: number
  • to: number?
  • rewardAmount: Money | number

Relacionamentos:

  • Pertence a Arena
  • Aplicada a ValueUnit
  • Gera RewardTransaction

Exemplos:

  • Ganhe 10 tokens ao completar uma partida
  • Ganhe 5% de cashback em compras acima de R$100
  • Convide um amigo e ganhe 50 pontos

Comportamentos:

  • evaluate(context: RewardContext): RewardResult
  • calculateReward(context: RewardContext): Money | number
  • canApply(user: UserId, context: RewardContext): boolean

12.11 BetRule

Descrição: Regra para apostas em partidas.

Atributos:

  • id: RuleId
  • arenaId: ArenaId
  • name: string
  • allowedMatchTypes: MatchType[]
  • allowedValueUnits: ValueUnit[]
  • minBetAmount: Money | number
  • maxBetAmount: Money | number
  • maxBetPerUser: Money | number?
  • houseEdge: number (percentual da casa, ex: 5%)
  • payoutRatio: number (proporção de pagamento, ex: 1.8)
  • lockBeforeStart: Duration (bloquear apostas X minutos antes)
  • requiresBalance: boolean
  • isActive: boolean

Relacionamentos:

  • Pertence a Arena
  • Aplicada a Match (Play Context)
  • Usa ValueUnit

Comportamentos:

  • canBet(user: UserId, match: MatchId, amount: Money | number): boolean
  • calculatePayout(betAmount: Money | number, outcome: MatchResult): Money | number

12.12 PrizeRule

Descrição: Regra de prêmios (para torneios, eventos).

Atributos:

  • id: RuleId
  • eventId: EventId?
  • tournamentId: TournamentId?
  • name: string
  • prizePool: Money | number
  • valueUnit: ValueUnit
  • distribution: PrizeDistribution[]
  • minimumParticipants: number?
  • payoutTrigger: PayoutTrigger (AUTOMATIC, MANUAL, SCHEDULED)
  • payoutDelay: Duration?

PrizeDistribution (Value Object):

  • position: number (1º, 2º, 3º lugar)
  • share: Percentage? (% do prize pool)
  • fixedAmount: Money | number?

Exemplos:

  • 1º lugar: 50% do prize pool
  • 2º lugar: 30%
  • 3º lugar: 20%

Relacionamentos:

  • Aplicada a Event ou Tournament (Engagement Context)
  • Gera WalletTransaction (prêmios)

Comportamentos:

  • calculatePrize(position: number): Money | number
  • distributePrizes(results: TournamentResult[]): void

12.13 TransactionLedger (Aggregate Root)

Descrição: Livro-razão de transações (imutável, append-only).

Atributos:

  • id: LedgerId
  • arenaId: ArenaId
  • entries: LedgerEntry[]
  • createdAt: Date

Relacionamentos:

  • Pertence a Arena
  • Contém múltiplos LedgerEntry

Uso: Auditoria financeira, reconciliação, compliance


12.14 LedgerEntry

Descrição: Entrada no livro-razão (dupla entrada contábil).

Atributos:

  • id: EntryId
  • ledgerId: LedgerId
  • transactionId: TransactionId
  • entryNumber: number (sequencial)
  • timestamp: Date
  • debitAccount: AccountCode
  • creditAccount: AccountCode
  • valueUnit: ValueUnit
  • amount: Money | number
  • description: string
  • metadata: Record<string, any>

AccountCode (Value Object):

  • Código contábil (ex: "USER_WALLET", "ARENA_REVENUE", "ESCROW", "PRIZE_POOL")

Relacionamentos:

  • Pertence a TransactionLedger
  • Referencia WalletTransaction

Invariantes:

  • Toda transação gera pelo menos 2 entradas (débito e crédito)
  • Soma de débitos = soma de créditos

12.15 WalletPolicy

Descrição: Política de uso da carteira.

Atributos:

  • id: PolicyId
  • walletId: WalletId? (null = política global)
  • arenaId: ArenaId
  • limits: WalletLimit[]
  • restrictions: WalletRestriction[]
  • isActive: boolean

WalletLimit (Value Object):

  • type: LimitType (DAILY_SPENDING, DAILY_WITHDRAWAL, TRANSACTION_SIZE, BALANCE_MAX)
  • valueUnit: ValueUnit
  • amount: Money | number

WalletRestriction (Value Object):

  • type: RestrictionType (ALLOWED_TRANSACTIONS, ALLOWED_VALUE_UNITS, REQUIRE_APPROVAL)
  • parameters: Record<string, any>

Relacionamentos:

  • Aplicada a Wallet

Comportamentos:

  • canTransact(transaction: WalletTransaction): ValidationResult
  • hasReachedLimit(limitType: LimitType, current: Money | number): boolean

12.16 WalletAuditTrail

Descrição: Trilha de auditoria da carteira.

Atributos:

  • id: AuditTrailId
  • walletId: WalletId
  • entries: AuditEntry[]

AuditEntry (Value Object):

  • timestamp: Date
  • action: AuditAction (CREATED, TRANSACTION, BALANCE_ADJUSTED, SUSPENDED, CLOSED)
  • performedBy: UserId?
  • details: string
  • beforeState: WalletState?
  • afterState: WalletState?

Relacionamentos:

  • Pertence a Wallet

Uso: Compliance, LGPD, troubleshooting


13. Engagement & Gamification Context

Objetivo

Gerenciar progressão de jogadores, avaliação de habilidades, conquistas, badges, leaderboards, rankings, torneios, desafios e recompensas.

Aggregates

13.1 PlayerProgress (Aggregate Root)

Descrição: Progressão e evolução do jogador.

Atributos:

  • id: ProgressId
  • playerId: PlayerId
  • sport: Sport
  • currentLevel: number
  • experiencePoints: number (XP)
  • nextLevelThreshold: number
  • matchesPlayed: number
  • matchesWon: number
  • matchesLost: number
  • winRate: number (percentual)
  • currentStreak: number (vitórias consecutivas)
  • bestStreak: number
  • totalPlayTime: Duration
  • skillRatings: SkillRating[]
  • lastUpdated: Date

SkillRating (Value Object):

  • skill: SkillType (SERVE, FOREHAND, BACKHAND, VOLLEY, OVERALL)
  • rating: number (0-100)
  • trend: Trend (IMPROVING, STABLE, DECLINING)

Relacionamentos:

  • Pertence a PlayerProfile (Identity Context)
  • Atualizado por MatchParticipation (Play Context)
  • Gera Achievement quando atinge marcos
  • Contribui para Leaderboard

Comportamentos:

  • recordMatch(participation: MatchParticipation): void
  • addExperience(points: number): void
  • levelUp(): void
  • updateSkillRating(skill: SkillType, newRating: number): void
  • calculateWinRate(): number

13.2 SkillAssessment (Aggregate Root)

Descrição: Avaliação formal de habilidades.

Atributos:

  • id: AssessmentId
  • playerId: PlayerId
  • sport: Sport
  • assessedBy: UserId (instrutor ou sistema)
  • assessmentDate: Date
  • assessmentType: AssessmentType (INITIAL, PERIODIC, TOURNAMENT, PROMOTION)
  • skillScores: SkillScore[]
  • overallScore: number
  • suggestedLevel: SkillLevel
  • previousLevel: SkillLevel?
  • notes: string?
  • videoEvidenceIds: MediaAssetId[]?

SkillScore (Value Object):

  • skill: SkillType
  • score: number (0-10)
  • observations: string?

Relacionamentos:

  • Pertence a PlayerProfile
  • Realizada por InstructorProfile ou sistema
  • Pode ter VideoAsset como evidência

Comportamentos:

  • approve(): void
  • reject(reason: string): void
  • promotePlayer(): void (se sugere nível superior)

13.3 Achievement (Aggregate Root)

Descrição: Conquista/marco alcançado.

Atributos:

  • id: AchievementId
  • arenaId: ArenaId
  • code: string (único)
  • name: string
  • description: string
  • category: AchievementCategory (MATCHES, SKILLS, SOCIAL, MILESTONES, SPECIAL)
  • type: AchievementType (ONE_TIME, PROGRESSIVE, REPEATABLE)
  • criteria: AchievementCriteria
  • reward: AchievementReward?
  • badgeId: BadgeId?
  • iconUrl: string?
  • rarity: Rarity (COMMON, UNCOMMON, RARE, EPIC, LEGENDARY)
  • points: number (achievement points)
  • isActive: boolean

AchievementCriteria (Value Object):

  • conditions: Condition[]
  • threshold: number?

AchievementReward (Value Object):

  • type: RewardType (XP, TOKENS, CREDITS, BADGE)
  • amount: number
  • valueUnit: ValueUnit?

Exemplos de Achievements:

  • "Primeira Vitória": Ganhe sua primeira partida
  • "Maratonista": Jogue 100 partidas
  • "Sem Erros": Vença uma partida sem erros não forçados
  • "Social": Convide 5 amigos

Relacionamentos:

  • Pertence a Arena
  • Associada a Badge
  • Concedida como PlayerBadge
  • Pode gerar RewardTransaction

Comportamentos:

  • evaluate(player: PlayerProgress): boolean
  • grant(playerId: PlayerId): PlayerBadge

13.4 Badge

Descrição: Emblema/insígnia.

Atributos:

  • id: BadgeId
  • arenaId: ArenaId
  • code: string
  • name: string
  • description: string
  • category: BadgeCategory (ACHIEVEMENT, RANK, EVENT, SPECIAL)
  • imageUrl: string
  • rarity: Rarity
  • issuedCount: number (quantas vezes foi concedido)
  • isActive: boolean

Relacionamentos:

  • Pertence a Arena
  • Associado a Achievement
  • Concedido como PlayerBadge

13.5 PlayerBadge

Descrição: Badge conquistado por jogador.

Atributos:

  • id: PlayerBadgeId
  • playerId: PlayerId
  • badgeId: BadgeId
  • achievementId: AchievementId?
  • earnedAt: Date
  • earnedFrom: string? (descrição do contexto)
  • isDisplayed: boolean (exibir no perfil)
  • displayOrder: number?

Relacionamentos:

  • Pertence a PlayerProfile
  • Referencia Badge
  • Originado de Achievement

13.6 Leaderboard (Aggregate Root)

Descrição: Ranking/tabela de líderes.

Atributos:

  • id: LeaderboardId
  • arenaId: ArenaId
  • name: string
  • description: string?
  • sport: Sport?
  • category: LeaderboardCategory (OVERALL, SKILL_LEVEL, AGE_GROUP, MONTHLY, WEEKLY, TOURNAMENT)
  • metric: LeaderboardMetric (WINS, WIN_RATE, XP, POINTS, SKILL_RATING, MATCHES_PLAYED)
  • scope: LeaderboardScope (GLOBAL, ARENA, CLUB, EVENT)
  • period: DateRange?
  • rankings: Ranking[]
  • lastUpdated: Date
  • refreshInterval: Duration (ex: atualizar a cada 1 hora)
  • isActive: boolean

Ranking (Value Object):

  • position: number
  • playerId: PlayerId
  • score: number
  • trend: RankTrend (UP, DOWN, STABLE, NEW)
  • previousPosition: number?

Relacionamentos:

  • Pertence a Arena
  • Classifica PlayerProfile
  • Usa RankingRuleSet

Comportamentos:

  • update(): void
  • getRanking(playerId: PlayerId): Ranking?
  • getTopN(n: number): Ranking[]
  • calculateRankings(): Ranking[]

13.7 RankingRuleSet

Descrição: Regras para cálculo de ranking.

Atributos:

  • id: RuleSetId
  • leaderboardId: LeaderboardId
  • name: string
  • components: RankingComponent[]
  • tiebreakers: Tiebreaker[]

RankingComponent (Value Object):

  • metric: RankingMetric (WINS, POINTS, SKILL_RATING)
  • weight: number (peso no cálculo)
  • direction: Direction (HIGHER_IS_BETTER, LOWER_IS_BETTER)

Tiebreaker (Value Object):

  • order: number
  • metric: RankingMetric

Relacionamentos:

  • Pertence a Leaderboard

Comportamentos:

  • calculate(player: PlayerProgress): number
  • compare(player1: PlayerProgress, player2: PlayerProgress): number

13.8 Tournament (Aggregate Root)

Descrição: Torneio competitivo.

Atributos:

  • id: TournamentId
  • eventId: EventId? (se parte de evento)
  • arenaId: ArenaId
  • name: string
  • description: string
  • sport: Sport
  • format: TournamentFormat (SINGLE_ELIMINATION, DOUBLE_ELIMINATION, ROUND_ROBIN, SWISS, LADDER)
  • matchFormat: MatchFormat
  • skillLevelRestriction: SkillLevel[]?
  • ageGroupRestriction: AgeGroup[]?
  • maxParticipants: number
  • currentParticipants: number
  • registrationFee: Money?
  • prizePool: Money?
  • prizeRule: PrizeRuleId?
  • startDate: Date
  • endDate: Date?
  • registrationDeadline: Date
  • status: TournamentStatus (REGISTRATION, DRAW_PENDING, IN_PROGRESS, COMPLETED, CANCELLED)
  • bracketId: TournamentBracketId?

Relacionamentos:

  • Pode ser parte de Event (Events Context)
  • Pertence a Arena
  • Possui TournamentBracket
  • Possui múltiplas TournamentRegistration
  • Contém múltiplas TournamentMatch
  • Pode ter PrizeRule (Wallet Context)

Invariantes:

  • Torneio iniciado não aceita novas inscrições
  • Número de participantes deve respeitar formato

Comportamentos:

  • register(player: PlayerId): TournamentRegistration
  • generateBracket(): TournamentBracket
  • start(): void
  • advance(match: TournamentMatchId): void
  • complete(): void
  • distributePrizes(): void

13.9 TournamentBracket

Descrição: Chaveamento do torneio.

Atributos:

  • id: BracketId
  • tournamentId: TournamentId
  • format: TournamentFormat
  • rounds: BracketRound[]
  • thirdPlaceMatch: boolean
  • generatedAt: Date

BracketRound (Value Object):

  • roundNumber: number
  • roundName: string (ex: "Final", "Semifinal", "Quartas")
  • matches: TournamentMatchId[]

Relacionamentos:

  • Pertence a Tournament
  • Organiza TournamentMatch

13.10 TournamentMatch

Descrição: Partida dentro de torneio (estende Match do Play Context).

Atributos Adicionais:

  • tournamentId: TournamentId
  • roundNumber: number
  • matchNumber: number
  • bracket: BracketPosition (ex: "A1 vs A2")
  • advancesToMatch: TournamentMatchId? (próxima partida)
  • isBronzeMatch: boolean (disputa de 3º lugar)

Relacionamentos:

  • Pertence a Tournament
  • Herda de Match (Play Context)
  • Posicionada em TournamentBracket

Comportamentos:

  • advanceWinner(): void (avançar vencedor para próxima fase)

13.11 TournamentRegistration

Descrição: Inscrição em torneio.

Atributos:

  • id: RegistrationId
  • tournamentId: TournamentId
  • playerId: PlayerId (ou teamId se torneio de duplas)
  • partnerId: PlayerId? (para doubles)
  • registeredAt: Date
  • status: RegistrationStatus (PENDING, CONFIRMED, WITHDRAWN, DISQUALIFIED)
  • seed: number? (cabeça de chave)
  • paymentStatus: PaymentStatus
  • waiverSigned: boolean
  • emergencyContact: EmergencyContact

Relacionamentos:

  • Pertence a Tournament
  • Referencia PlayerProfile

Comportamentos:

  • confirm(): void
  • withdraw(reason: string): void
  • disqualify(reason: string): void

13.12 Challenge (Aggregate Root)

Descrição: Desafio entre jogadores.

Atributos:

  • id: ChallengeId
  • arenaId: ArenaId
  • challengerId: PlayerId
  • challengedId: PlayerId
  • sport: Sport
  • matchFormat: MatchFormat
  • stake: Money | number? (apostado)
  • stakeValueUnit: ValueUnit?
  • message: string?
  • proposedDate: Date?
  • expiresAt: Date
  • status: ChallengeStatus (PENDING, ACCEPTED, DECLINED, EXPIRED, COMPLETED)
  • matchId: MatchId? (se aceito e realizado)
  • acceptedAt: Date?
  • declinedAt: Date?
  • completedAt: Date?

Relacionamentos:

  • Entre dois PlayerProfile
  • Pode gerar Match (Play Context)
  • Pode ter MatchStake (Play Context)

Comportamentos:

  • accept(): void
  • decline(reason: string): void
  • expire(): void
  • scheduleMatch(court: CourtId, time: Date): Match
  • complete(result: MatchResult): void

13.13 Reward

Descrição: Recompensa concedida (registro histórico).

Atributos:

  • id: RewardId
  • playerId: PlayerId
  • rewardRuleId: RewardRuleId
  • type: RewardType
  • amount: Money | number
  • valueUnit: ValueUnit
  • reason: string
  • grantedAt: Date
  • grantedBy: string? (SYSTEM, ADMIN, EVENT)
  • transactionId: TransactionId?

Relacionamentos:

  • Concedida a PlayerProfile
  • Originada de RewardRule (Wallet Context)
  • Pode gerar WalletTransaction

14. Sponsorship & Ads Context

Objetivo

Gerenciar patrocinadores, contratos de patrocínio, inventário de anúncios, campanhas, veiculação, impressões e relatórios de exposição.

Aggregates

14.1 Sponsor (Aggregate Root)

Descrição: Patrocinador/anunciante.

Atributos:

  • id: SponsorId
  • name: string
  • legalName: string
  • taxId: string (CNPJ/CPF)
  • industry: Industry
  • website: string?
  • logo: MediaAssetId?
  • contactPerson: ContactPerson
  • billingAddress: Address
  • status: SponsorStatus (ACTIVE, INACTIVE, SUSPENDED)
  • partnerSince: Date

ContactPerson (Value Object):

  • name: string
  • email: Email
  • phoneNumber: PhoneNumber
  • position: string

Relacionamentos:

  • Possui múltiplos SponsorshipContract
  • Possui múltiplas AdCampaign

14.2 SponsorshipContract (Aggregate Root)

Descrição: Contrato de patrocínio.

Atributos:

  • id: ContractId
  • sponsorId: SponsorId
  • arenaId: ArenaId
  • contractNumber: string
  • type: SponsorshipType (TITLE, PREMIUM, STANDARD, EVENT, COURT, TOURNAMENT)
  • title: string
  • description: string
  • value: Money
  • currency: Currency
  • paymentTerms: PaymentTerms
  • startDate: Date
  • endDate: Date
  • renewalTerms: RenewalTerms?
  • deliverables: Deliverable[]
  • status: ContractStatus (DRAFT, ACTIVE, EXPIRED, CANCELLED, RENEWED)
  • signedAt: Date?
  • signedBy: string?
  • documentUrl: string?

Deliverable (Value Object):

  • type: DeliverableType (LOGO_PLACEMENT, AD_SLOTS, COURT_NAMING, EVENT_SPONSORSHIP)
  • quantity: number?
  • description: string
  • deadline: Date?

Relacionamentos:

  • Pertence a Sponsor
  • Aplicado a Arena (ou Court, Event)
  • Define AdInventory

Comportamentos:

  • activate(): void
  • renew(newEndDate: Date, newValue: Money?): SponsorshipContract
  • cancel(reason: string): void
  • addDeliverable(deliverable: Deliverable): void

14.3 AdInventory (Aggregate Root)

Descrição: Inventário de espaços publicitários disponíveis.

Atributos:

  • id: InventoryId
  • arenaId: ArenaId
  • name: string
  • type: AdInventoryType (COURT_SCREEN, SCOREBOARD, WALL_BANNER, DIGITAL_BOARD, VIDEO_PRE_ROLL, EMAIL_FOOTER)
  • location: AdLocation
  • capacity: number (quantos anúncios simultâneos)
  • dimensions: AdDimensions? (para banners físicos)
  • screenResolution: Resolution? (para digitais)
  • format: AdFormat (IMAGE, VIDEO, HTML, PHYSICAL)
  • slots: AdSlot[]
  • pricePerSlot: Money
  • status: InventoryStatus (AVAILABLE, SOLD_OUT, MAINTENANCE)

AdLocation (Value Object):

  • courtId: CourtId?
  • areaId: AreaId?
  • description: string

AdDimensions (Value Object):

  • width: number
  • height: number
  • unit: Unit (PIXELS, METERS, INCHES)

Relacionamentos:

  • Pertence a Arena
  • Contém múltiplos AdSlot
  • Pode estar vinculado a Court, ArenaArea

14.4 AdSlot

Descrição: Slot de tempo/espaço para anúncio.

Atributos:

  • id: SlotId
  • inventoryId: InventoryId
  • timeRange: TimeRange? (para slots temporais)
  • dayOfWeek: DayOfWeek[]?
  • status: SlotStatus (AVAILABLE, RESERVED, BOOKED, RUNNING, COMPLETED)
  • campaignId: AdCampaignId?
  • reservedUntil: Date?

Relacionamentos:

  • Pertence a AdInventory
  • Pode estar reservado para AdCampaign

14.5 AdCampaign (Aggregate Root)

Descrição: Campanha publicitária.

Atributos:

  • id: CampaignId
  • sponsorId: SponsorId
  • arenaId: ArenaId
  • name: string
  • description: string?
  • startDate: Date
  • endDate: Date
  • budget: Money
  • spent: Money
  • targetAudience: TargetAudience?
  • creatives: AdCreativeId[]
  • placementRules: AdPlacementRule[]
  • impressions: number (total de exibições)
  • clicks: number (total de cliques)
  • status: CampaignStatus (DRAFT, SCHEDULED, ACTIVE, PAUSED, COMPLETED, CANCELLED)

TargetAudience (Value Object):

  • ageRange: AgeRange?
  • gender: Gender[]?
  • skillLevels: SkillLevel[]?
  • sports: Sport[]?
  • locations: ZoneId[]?

Relacionamentos:

  • Pertence a Sponsor
  • Aplicada a Arena
  • Possui múltiplos AdCreative
  • Possui múltiplas AdPlacementRule
  • Reserva AdSlot
  • Gera AdImpression, AdClick

Comportamentos:

  • start(): void
  • pause(): void
  • resume(): void
  • complete(): void
  • addCreative(creative: AdCreative): void
  • getPerformance(): CampaignPerformance

14.6 AdCreative

Descrição: Peça criativa (banner, vídeo, etc).

Atributos:

  • id: CreativeId
  • campaignId: AdCampaignId
  • name: string
  • type: CreativeType (IMAGE, VIDEO, HTML5, TEXT)
  • format: AdFormat
  • mediaAssetId: MediaAssetId?
  • dimensions: AdDimensions
  • duration: Duration? (para vídeos)
  • clickUrl: string?
  • altText: string?
  • approvalStatus: ApprovalStatus (PENDING, APPROVED, REJECTED)
  • rejectionReason: string?

Relacionamentos:

  • Pertence a AdCampaign
  • Referencia MediaAsset

14.7 AdPlacementRule

Descrição: Regra de veiculação de anúncios.

Atributos:

  • id: RuleId
  • campaignId: AdCampaignId
  • inventoryType: AdInventoryType[]
  • locations: AdLocation[]?
  • timeRanges: TimeRange[]?
  • daysOfWeek: DayOfWeek[]?
  • frequency: AdFrequency
  • priority: number (para resolução de conflitos)
  • conditions: PlacementCondition[]?

AdFrequency (Value Object):

  • type: FrequencyType (CONTINUOUS, INTERVAL, EVENT_TRIGGERED)
  • interval: Duration? (ex: a cada 10 minutos)
  • maxPerDay: number?
  • maxPerUser: number?

PlacementCondition (Value Object):

  • type: ConditionType (MATCH_IN_PROGRESS, SKILL_LEVEL, USER_PROFILE)
  • parameters: Record<string, any>

Relacionamentos:

  • Pertence a AdCampaign
  • Aplicada a AdInventory

14.8 AdImpression

Descrição: Registro de exibição de anúncio.

Atributos:

  • id: ImpressionId
  • campaignId: AdCampaignId
  • creativeId: AdCreativeId
  • inventoryId: InventoryId
  • slotId: SlotId
  • userId: UserId? (se identificado)
  • timestamp: Date
  • duration: Duration? (tempo de exibição)
  • wasViewed: boolean (completamente visualizado)
  • deviceType: DeviceType?
  • location: Location?

Relacionamentos:

  • Pertence a AdCampaign
  • Exibido em AdInventory / AdSlot
  • Visto por UserAccount (se identificado)

Uso: Métricas, faturamento, relatórios


14.9 AdClick

Descrição: Registro de clique em anúncio.

Atributos:

  • id: ClickId
  • impressionId: ImpressionId
  • campaignId: AdCampaignId
  • creativeId: AdCreativeId
  • userId: UserId?
  • timestamp: Date
  • clickUrl: string
  • referrer: string?
  • ipAddress: string?

Relacionamentos:

  • Originado de AdImpression
  • Pertence a AdCampaign

14.10 ExposureReport

Descrição: Relatório de exposição para patrocinador.

Atributos:

  • id: ReportId
  • sponsorId: SponsorId
  • campaignId: AdCampaignId?
  • contractId: ContractId?
  • period: DateRange
  • totalImpressions: number
  • totalClicks: number
  • uniqueUsers: number
  • clickThroughRate: number (CTR)
  • costPerImpression: Money?
  • costPerClick: Money?
  • audienceBreakdown: AudienceBreakdown
  • generatedAt: Date
  • generatedBy: UserId
  • reportUrl: string? (PDF)

AudienceBreakdown (Value Object):

  • byAge: Record<AgeGroup, number>
  • byGender: Record<Gender, number>
  • bySkillLevel: Record<SkillLevel, number>
  • bySport: Record<Sport, number>

Relacionamentos:

  • Pertence a Sponsor
  • Baseado em AdCampaign ou SponsorshipContract
  • Agrega AdImpression e AdClick

15. Analytics & Intelligence Context

Objetivo

Gerenciar métricas, indicadores, relatórios operacionais e recomendações inteligentes.

Aggregates

15.1 Metric

Descrição: Métrica rastreada (abstração).

Atributos:

  • id: MetricId
  • arenaId: ArenaId
  • definition: MetricDefinition
  • currentValue: number
  • unit: string
  • timestamp: Date
  • tags: Tag[]

Relacionamentos:

  • Baseada em MetricDefinition
  • Gera MetricSnapshot (histórico)

15.2 MetricDefinition

Descrição: Definição de uma métrica.

Atributos:

  • id: DefinitionId
  • code: string (ex: "court_occupancy_rate")
  • name: string
  • description: string
  • category: MetricCategory (OPERATIONAL, FINANCIAL, CUSTOMER, ENGAGEMENT)
  • unit: string (%, hours, BRL, count)
  • aggregation: AggregationType (SUM, AVG, MIN, MAX, COUNT)
  • calculationFormula: string?
  • collectionFrequency: Duration
  • isActive: boolean

Exemplos de Métricas:

  • court_occupancy_rate: Taxa de ocupação de quadras (%)
  • revenue_per_court_hour: Receita por hora de quadra (BRL)
  • no_show_rate: Taxa de no-show (%)
  • customer_lifetime_value: Valor do tempo de vida do cliente (BRL)
  • nps_score: Net Promoter Score

15.3 MetricSnapshot

Descrição: Snapshot de métrica em momento específico.

Atributos:

  • id: SnapshotId
  • metricDefinitionId: DefinitionId
  • value: number
  • timestamp: Date
  • period: DateRange? (período agregado)
  • dimensions: Record<string, string> (ex: courtId, sport)

Relacionamentos:

  • Pertence a MetricDefinition

Uso: Séries temporais, dashboards, alertas


15.4 OccupancyReport

Descrição: Relatório de ocupação de quadras.

Atributos:

  • id: ReportId
  • arenaId: ArenaId
  • period: DateRange
  • courts: CourtOccupancy[]
  • overallOccupancyRate: number
  • peakHours: TimeRange[]
  • lowDemandHours: TimeRange[]
  • generatedAt: Date

CourtOccupancy (Value Object):

  • courtId: CourtId
  • courtName: string
  • totalHours: number
  • occupiedHours: number
  • occupancyRate: number
  • revenue: Money

Relacionamentos:

  • Pertence a Arena
  • Analisa Court (Courts Context)
  • Usa Booking (Scheduling Context)

15.5 NoShowReport

Descrição: Relatório de no-shows.

Atributos:

  • id: ReportId
  • arenaId: ArenaId
  • period: DateRange
  • totalBookings: number
  • noShows: number
  • noShowRate: number
  • lostRevenue: Money
  • topOffenders: NoShowOffender[]
  • generatedAt: Date

NoShowOffender (Value Object):

  • userId: UserId
  • userName: string
  • noShowCount: number
  • lastNoShowDate: Date

15.6 RevenueReport

Descrição: Relatório de receita.

Atributos:

  • id: ReportId
  • arenaId: ArenaId
  • period: DateRange
  • totalRevenue: Money
  • revenueByCategory: Record<ProductCategory, Money>
  • revenueByPaymentMethod: Record<PaymentMethod, Money>
  • topProducts: ProductRevenue[]
  • averageTicket: Money
  • transactionCount: number
  • generatedAt: Date

ProductRevenue (Value Object):

  • productId: ProductItemId
  • productName: string
  • quantitySold: number
  • revenue: Money

15.7 EventReport

Descrição: Relatório de evento.

Atributos:

  • id: ReportId
  • eventId: EventId
  • attendance: number
  • noShows: number
  • revenue: Money
  • consumptionBreakdown: Record<ProductCategory, Money>
  • averageConsumptionPerPerson: Money
  • satisfaction: number? (NPS ou rating)
  • generatedAt: Date

15.8 DemandForecast

Descrição: Previsão de demanda.

Atributos:

  • id: ForecastId
  • arenaId: ArenaId
  • resourceType: ResourceType (COURT, INSTRUCTOR, AREA)
  • resourceId: ResourceId?
  • forecastPeriod: DateRange
  • predictions: DemandPrediction[]
  • confidence: number (0-1)
  • model: string (algoritmo usado)
  • generatedAt: Date

DemandPrediction (Value Object):

  • date: Date
  • timeRange: TimeRange
  • predictedDemand: number (0-100%)
  • confidence: number

Uso: Dynamic pricing, sugestão de horários, planejamento de staff


15.9 Recommendation

Descrição: Recomendação inteligente para usuário.

Atributos:

  • id: RecommendationId
  • userId: UserId
  • type: RecommendationType (BOOKING_SLOT, OPPONENT, COURT, LESSON, PRODUCT)
  • targetId: string (ID da entidade recomendada)
  • targetType: string
  • score: number (relevância 0-1)
  • reasoning: string[] (motivos da recomendação)
  • expiresAt: Date
  • status: RecommendationStatus (PENDING, VIEWED, ACCEPTED, DISMISSED)
  • createdAt: Date

Exemplos:

  • "Recomendamos reservar às 18h de terça (histórico de disponibilidade)"
  • "Jogue com João (nível compatível, joga no mesmo horário)"
  • "Experimente a Quadra 3 (menos disputada, boa iluminação)"

Relacionamentos:

  • Destinada a UserAccount
  • Pode recomendar Court, PlayerProfile, ScheduleSlot, etc

16. Shared Kernel

Objetivo

Value Objects, tipos e conceitos compartilhados por múltiplos contextos.

Value Objects

16.1 Money

Descrição: Valor monetário com moeda.

Atributos:

  • amount: number (decimal)
  • currency: Currency (BRL, USD, etc)

Comportamentos:

  • add(other: Money): Money
  • subtract(other: Money): Money
  • multiply(factor: number): Money
  • divide(divisor: number): Money
  • isZero(): boolean
  • isPositive(): boolean
  • equals(other: Money): boolean
  • format(): string (ex: "R$ 150,00")

Invariantes:

  • Operações só são permitidas entre mesma moeda
  • Precisão decimal conforme moeda (geralmente 2)

16.2 Address

Descrição: Endereço físico.

Atributos:

  • street: string
  • number: string
  • complement: string?
  • neighborhood: string
  • city: string
  • state: string
  • country: string
  • postalCode: string

Comportamentos:

  • format(): string
  • formatShort(): string

16.3 GeoLocation

Descrição: Coordenadas geográficas.

Atributos:

  • latitude: number
  • longitude: number
  • altitude: number?
  • accuracy: number? (metros)

Comportamentos:

  • distanceTo(other: GeoLocation): number (em metros)
  • isWithinRadius(center: GeoLocation, radius: number): boolean

16.4 TimeRange

Descrição: Intervalo de tempo.

Atributos:

  • start: Time (HH:mm)
  • end: Time (HH:mm)

Comportamentos:

  • duration(): Duration
  • contains(time: Time): boolean
  • overlaps(other: TimeRange): boolean
  • merge(other: TimeRange): TimeRange?

16.5 DateRange

Descrição: Intervalo de datas.

Atributos:

  • start: Date
  • end: Date

Comportamentos:

  • duration(): Duration
  • contains(date: Date): boolean
  • overlaps(other: DateRange): boolean
  • split(interval: Duration): DateRange[]

16.6 LocalizedText

Descrição: Texto internacionalizado.

Atributos:

  • translations: Record<Locale, string>
  • defaultLocale: Locale

Comportamentos:

  • get(locale: Locale): string
  • set(locale: Locale, text: string): void

16.7 Document

Descrição: Documento de identificação.

Atributos:

  • type: DocumentType (CPF, CNPJ, RG, PASSPORT, DRIVER_LICENSE)
  • number: string
  • issuingAuthority: string?
  • issuedDate: Date?
  • expiryDate: Date?
  • country: string

Comportamentos:

  • isValid(): boolean
  • isExpired(): boolean
  • format(): string

16.8 Tag

Descrição: Tag/etiqueta.

Atributos:

  • key: string
  • value: string?
  • category: string?

Comportamentos:

  • toString(): string (ex: "category:value" ou "key")

16.9 AuditTrail

Descrição: Trilha de auditoria.

Atributos:

  • createdAt: Date
  • createdBy: UserId
  • updatedAt: Date?
  • updatedBy: UserId?
  • deletedAt: Date?
  • deletedBy: UserId?
  • version: number

16.10 AuditEntry

Descrição: Entrada de auditoria.

Atributos:

  • timestamp: Date
  • userId: UserId?
  • action: string
  • entityType: string
  • entityId: string
  • changes: Record<string, ChangeSet>?
  • metadata: Record<string, any>?

ChangeSet (Value Object):

  • field: string
  • oldValue: any
  • newValue: any

16.11 DomainEvent

Descrição: Evento de domínio (base abstrata).

Atributos:

  • eventId: string (UUID)
  • eventType: string (nome do evento)
  • occurredAt: Date
  • aggregateId: string
  • aggregateType: string
  • version: number
  • causationId: string? (ID do comando que causou)
  • correlationId: string? (ID de correlação para rastreamento)

Exemplos de Eventos:

  • UserAccountCreated
  • BookingConfirmed
  • MatchCompleted
  • PaymentProcessed
  • AchievementUnlocked

16.12 Rule

Descrição: Regra de negócio (abstração).

Atributos:

  • id: RuleId
  • name: string
  • description: string?
  • condition: Condition
  • action: Action
  • priority: number
  • isActive: boolean

Condition (Value Object):

  • expression: string
  • parameters: Record<string, any>

Action (Value Object):

  • type: ActionType
  • parameters: Record<string, any>

16.13 RuleSet

Descrição: Conjunto de regras.

Atributos:

  • id: RuleSetId
  • name: string
  • rules: Rule[]
  • evaluationMode: EvaluationMode (ALL, ANY, FIRST_MATCH, PRIORITY)

Comportamentos:

  • evaluate(context: any): RuleResult[]
  • addRule(rule: Rule): void
  • removeRule(ruleId: RuleId): void

16.14 Status

Descrição: Status genérico com transições.

Atributos:

  • current: string
  • previous: string?
  • changedAt: Date
  • changedBy: UserId?
  • reason: string?

Comportamentos:

  • canTransitionTo(newStatus: string): boolean
  • transitionTo(newStatus: string, reason: string?): void

16.15 Identifier

Descrição: Identificador único tipado.

Atributos:

  • value: string (UUID ou outro formato)

Comportamentos:

  • equals(other: Identifier): boolean
  • toString(): string

Exemplos de Identificadores Tipados:

  • UserId
  • ArenaId
  • CourtId
  • MatchId
  • BookingId

Conclusão

Este modelo de domínio representa a estrutura completa do Sport Tech Club, organizado em 15 Bounded Contexts seguindo os princípios de Domain-Driven Design.

Características Principais

  • 200+ Entidades e Value Objects cobrindo todos os aspectos do negócio
  • Separação clara de responsabilidades entre contextos
  • Aggregates bem definidos com fronteiras de consistência
  • Relacionamentos explícitos entre contextos via IDs
  • Invariantes de negócio documentadas
  • Comportamentos ricos nas entidades (não apenas CRUDs)

Próximos Passos

  1. Implementação Gradual: Começar pelos contextos core (Identity, Arena, Courts, Scheduling)
  2. Event Storming: Mapear eventos de domínio e fluxos de processo
  3. Context Mapping: Definir integrações entre contextos (ACL, Shared Kernel, etc)
  4. Ubiquitous Language: Manter glossário vivo e atualizado
  5. Testes de Domínio: TDD para garantir invariantes e comportamentos

Referências

  • Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software
  • Vernon, Vaughn. Implementing Domain-Driven Design
  • Vernon, Vaughn. Domain-Driven Design Distilled
  • Fowler, Martin. Patterns of Enterprise Application Architecture

Documento mantido por: Engenheiro (Arquiteto de Software Sênior)

Última atualização: 2026-01-09

Versão: 1.0