Skip to content

Sport Tech Club - Arquitetura de Software

Visão Geral

O Sport Tech Club é uma plataforma SaaS multi-tenant para gestão inteligente de arenas esportivas, com foco em rachadões de tênis, futevôlei e beach tennis. A arquitetura é baseada em Domain-Driven Design (DDD), Clean Architecture e Event-Driven Architecture (EDA).

Características Principais

  • Multi-tenant por arena
  • Event-Driven para integrações e consistência eventual
  • Microserviços focados em bounded contexts
  • CQRS para otimização de leitura/escrita
  • Event Sourcing em contextos críticos (wallet, partidas)
  • Real-time para presença, partidas e alocação

Classificação de Domínios (Domain Classification)

Core Domain (Diferenciação Competitiva)

1. Courts & Allocation Context

Complexidade: Alta | Valor: Crítico

Motor inteligente de alocação de quadras baseado em:

  • Perfis de jogadores (nível, gênero, preferências)
  • Estados de quadra (disponível, ocupada, manutenção)
  • Fila dinâmica com prioridades
  • Regras de balanceamento de partidas
  • Algoritmos de matching de jogadores

Diferencial: Sistema preditivo que otimiza uso de quadras e experiência do jogador.

2. Wallet & Value Context

Complexidade: Alta | Valor: Estratégico

Sistema de economia interna da plataforma:

  • Carteiras digitais por entidade (usuário, arena, evento, app)
  • Tokens/moedas próprias do clube
  • Transações peer-to-peer
  • Apostas em partidas ("valendo")
  • Cashback e recompensas
  • Sistema de créditos e débitos

Diferencial: Economia circular que aumenta engajamento e recorrência.

3. Scheduling Context

Complexidade: Média | Valor: Alto

Agenda unificada multi-propósito:

  • Reservas de quadra
  • Agendamento de aulas
  • Day-use
  • Eventos especiais
  • Políticas dinâmicas (cancelamento, no-show, atraso)

Diferencial: Flexibilidade para múltiplos tipos de uso simultâneos.

Supporting Domain (Suporte ao Core)

4. Arena Management Context

Gestão de infraestrutura física e operacional.

5. Lessons & Coaching Context

Gestão de aulas, professores e turmas.

6. Play & Match Context

Registro e gestão de partidas e resultados.

7. Access & Presence Context

Controle de presença física e auditoria de uso.

8. Events Context

Gestão de eventos e torneios.

9. Engagement & Gamification Context

Rankings, conquistas, badges e desafios.

10. Media & IoT Context

Captura de vídeos, highlights e integração com dispositivos.

11. Sponsorship & Ads Context

Gestão de patrocinadores e inventário de anúncios.

12. Analytics & Intelligence Context

Métricas, relatórios e inteligência de negócio.

Generic Domain (Commodities)

13. Identity & Access Context

Autenticação, autorização, RBAC multi-tenant. Solução: Keycloak + custom extensions

14. Commerce & Billing Context

Faturamento, mensalidades, pacotes. Solução: Integração com Stripe/Mercado Pago

15. Integrations Context

Adaptadores para sistemas externos. Padrão: Anti-Corruption Layer (ACL)


Context Map (Mapa de Contextos)

Legenda de Relacionamentos

PadrãoSiglaDescriçãoQuando Usar
Shared KernelSKModelo compartilhado entre timesEquipe única, contextos fortemente acoplados
Customer-SupplierCSCliente downstream, fornecedor upstreamRelacionamento formal, contratos definidos
ConformistCFDownstream conforma ao modelo upstreamSem poder de negociação, aceita modelo do upstream
Anti-Corruption LayerACLCamada de tradução que protege modelo internoIntegração com legado ou sistemas externos
Open Host ServiceOHSAPI pública documentada para múltiplos consumidoresServiço core usado por vários contextos
Published LanguagePLLinguagem bem documentada para integraçãoFormato padrão (JSON Schema, OpenAPI)
Separate WaysSWContextos completamente independentesSem integração, duplicação aceitável
PartnershipPSDesenvolvimento coordenado entre timesDependência mútua, evolução conjunta
UpstreamUFornece dados/serviços-
DownstreamDConsome dados/serviços-

Bounded Contexts Detalhados

1. Identity & Access Context

Tipo: Generic Domain
Tecnologia: Keycloak + Custom Extensions

Responsabilidades

  • Autenticação (OAuth2, JWT)
  • Autorização (RBAC, ABAC)
  • Multi-tenancy por arena
  • Gestão de usuários, roles e permissões
  • Social login (Google, Facebook, Apple)

Entidades Core

typescript
// Aggregate Root
class User {
  id: UserId
  email: Email
  profile: UserProfile
  tenants: TenantMembership[]
  roles: Role[]
  status: UserStatus
}

// Value Objects
class TenantMembership {
  tenantId: TenantId
  joinedAt: Date
  status: MembershipStatus
}

// Domain Events
class UserRegistered
class UserActivated
class RoleAssigned

Relacionamentos

  • Upstream (U) para todos os contextos (fornece identidade)
  • Shared Kernel (SK) com Arena Management

2. Arena Management Context

Tipo: Supporting Domain

Responsabilidades

  • Cadastro e configuração de arenas
  • Áreas físicas (quadras, vestiários, bar)
  • Zonas de acesso (check-in, VIP, comum)
  • Calendário operacional (horários, feriados)
  • Configurações por arena (regras, preços base)

Entidades Core

typescript
// Aggregate Root
class Arena {
  id: ArenaId
  name: string
  tenant: TenantId
  areas: PhysicalArea[]
  zones: AccessZone[]
  calendar: OperatingCalendar
  settings: ArenaSettings
  
  addArea(area: PhysicalArea): void
  updateOperatingHours(hours: TimeRange): void
  isOpenAt(datetime: Date): boolean
}

class PhysicalArea {
  id: AreaId
  name: string
  type: AreaType // COURT, LOCKER_ROOM, BAR, PARKING
  capacity: number
  amenities: Amenity[]
}

// Domain Events
class ArenaCreated
class AreaAdded
class OperatingHoursUpdated

Relacionamentos

  • Shared Kernel (SK) com Identity & Access
  • Upstream para Courts, Lessons, Events

3. Courts & Allocation Context (CORE)

Tipo: Core Domain
Complexidade: Alta

Responsabilidades

  • Quadra como entidade inteligente
  • Estados de quadra (disponível, ocupada, manutenção, reservada)
  • Perfis de jogadores (nível, gênero, preferências)
  • Motor de alocação inteligente
  • Fila dinâmica com prioridades
  • Regras de balanceamento de partidas

Entidades Core

typescript
// Aggregate Root
class Court {
  id: CourtId
  arenaId: ArenaId
  name: string
  surface: SurfaceType
  sport: Sport
  state: CourtState
  currentOccupancy: Occupancy | null
  maintenanceSchedule: MaintenanceWindow[]
  
  allocate(players: Player[], priority: Priority): AllocationResult
  release(): void
  startMaintenance(window: MaintenanceWindow): void
  isAvailableAt(datetime: Date): boolean
}

class CourtState {
  status: CourtStatus // AVAILABLE, OCCUPIED, MAINTENANCE, RESERVED
  since: Date
  estimatedUntil: Date | null
  
  canTransitionTo(newStatus: CourtStatus): boolean
}

// Aggregate Root - Motor de Alocação
class AllocationEngine {
  arenaId: ArenaId
  courts: Court[]
  queue: PlayerQueue
  rules: AllocationRule[]
  
  enqueue(player: Player, priority: Priority): QueuePosition
  dequeue(playerId: PlayerId): void
  allocateNext(): AllocationResult
  rebalance(): void
  
  private matchPlayers(players: Player[]): MatchingScore
  private selectBestCourt(players: Player[]): Court
}

class PlayerQueue {
  entries: QueueEntry[]
  
  add(player: Player, priority: Priority): void
  remove(playerId: PlayerId): void
  getNext(count: number): Player[]
  reorder(): void
}

// Value Objects
class PlayerProfile {
  level: SkillLevel // BEGINNER, INTERMEDIATE, ADVANCED, PRO
  gender: Gender
  preferences: PlayerPreferences
  stats: PlayerStats
  
  isCompatibleWith(other: PlayerProfile): boolean
  calculateMatchQuality(other: PlayerProfile): MatchQuality
}

class AllocationRule {
  name: string
  priority: number
  condition: (context: AllocationContext) => boolean
  action: (context: AllocationContext) => void
}

// Domain Events
class CourtAllocated
class PlayerEnqueued
class PlayerDequeued
class CourtReleased
class AllocationFailed
class MaintenanceScheduled

Padrões Aplicados

  • Strategy Pattern: Diferentes algoritmos de matching
  • State Pattern: Estados de quadra
  • Observer Pattern: Notificações de mudança de estado
  • Specification Pattern: Regras de alocação

Relacionamentos

  • Open Host Service (OHS) para Scheduling
  • Conformist (CF) com Play & Match
  • Anti-Corruption Layer (ACL) com Access & Presence

4. Scheduling Context (CORE)

Tipo: Core Domain

Responsabilidades

  • Agenda unificada multi-propósito
  • Reservas (quadra, aula, day-use, evento)
  • Políticas de cancelamento, no-show, atraso
  • Conflitos e validações
  • Notificações de lembretes

Entidades Core

typescript
// Aggregate Root
class Schedule {
  id: ScheduleId
  arenaId: ArenaId
  resourceId: ResourceId // Court, Area, Coach
  bookings: Booking[]
  
  book(request: BookingRequest): BookingResult
  cancel(bookingId: BookingId, reason: string): void
  reschedule(bookingId: BookingId, newTime: TimeRange): void
  checkConflicts(timeRange: TimeRange): Conflict[]
}

// Aggregate Root
class Booking {
  id: BookingId
  scheduleId: ScheduleId
  resourceId: ResourceId
  userId: UserId
  type: BookingType // COURT, LESSON, DAY_USE, EVENT
  timeRange: TimeRange
  status: BookingStatus
  participants: Participant[]
  policies: BookingPolicy[]
  
  confirm(): void
  cancel(reason: string): CancellationResult
  checkIn(): void
  noShow(): void
  applyLatePenalty(): void
}

// Value Objects
class BookingPolicy {
  type: PolicyType // CANCELLATION, NO_SHOW, LATE_ARRIVAL
  rules: PolicyRule[]
  
  evaluate(context: PolicyContext): PolicyResult
}

class CancellationPolicy extends BookingPolicy {
  freeUntil: Duration // ex: 24h antes
  penaltyPercentage: number
  
  calculatePenalty(canceledAt: Date, bookingStart: Date): Money
}

// Domain Events
class BookingCreated
class BookingConfirmed
class BookingCanceled
class BookingRescheduled
class NoShowRecorded
class LatePenaltyApplied

Relacionamentos

  • Conformist (CF) com Lessons & Coaching
  • Conformist (CF) com Events
  • Customer-Supplier (CS) com Courts & Allocation

5. Lessons & Coaching Context

Tipo: Supporting Domain

Responsabilidades

  • Gestão de aulas (individual, grupo, turma)
  • Professores e instrutores
  • Programas de treinamento
  • Presença em aulas
  • Avaliações de progresso

Entidades Core

typescript
// Aggregate Root
class Lesson {
  id: LessonId
  type: LessonType // INDIVIDUAL, GROUP, CLASS
  coachId: CoachId
  students: Student[]
  schedule: LessonSchedule
  curriculum: Curriculum | null
  attendances: Attendance[]
  
  recordAttendance(studentId: StudentId, status: AttendanceStatus): void
  evaluateStudent(studentId: StudentId, evaluation: Evaluation): void
  reschedule(newSchedule: LessonSchedule): void
}

class Coach {
  id: CoachId
  userId: UserId
  specialties: Sport[]
  certifications: Certification[]
  availability: Availability
  rating: Rating
  
  isAvailableAt(datetime: Date): boolean
  canTeach(sport: Sport, level: SkillLevel): boolean
}

// Domain Events
class LessonScheduled
class AttendanceRecorded
class StudentEvaluated
class LessonCompleted

Relacionamentos

  • Conformist (CF) com Arena Management
  • Conformist (CF) com Scheduling

6. Play & Match Context

Tipo: Supporting Domain

Responsabilidades

  • Registro de partidas
  • Times e jogadores
  • Placar em tempo real
  • Resultados e estatísticas
  • Partidas "valendo" (com stakes)

Entidades Core

typescript
// Aggregate Root (Event Sourcing)
class Match {
  id: MatchId
  courtId: CourtId
  sport: Sport
  teams: Team[]
  score: Score
  status: MatchStatus
  startedAt: Date
  finishedAt: Date | null
  stakes: MatchStakes | null
  events: MatchEvent[]
  
  start(): void
  recordPoint(teamId: TeamId): void
  finish(): void
  applyStakes(): void
  
  // Event Sourcing
  private apply(event: MatchEvent): void
}

class MatchStakes {
  type: StakeType // WALLET_TOKENS, RANKING_POINTS
  amount: number
  participants: StakeParticipant[]
  
  distribute(winner: Team): Transaction[]
}

// Value Objects
class Score {
  sets: Set[]
  winner: TeamId | null
  
  addPoint(teamId: TeamId): Score
  isFinished(): boolean
}

// Domain Events (Event Sourcing)
class MatchStarted implements MatchEvent
class PointScored implements MatchEvent
class SetCompleted implements MatchEvent
class MatchFinished implements MatchEvent
class StakesApplied implements MatchEvent

Relacionamentos

  • Conformist (CF) com Engagement & Gamification
  • Conformist (CF) com Wallet & Value
  • Partnership (PS) com Media & IoT

7. Access & Presence Context

Tipo: Supporting Domain

Responsabilidades

  • Check-in/check-out físico
  • Presença real por quadra
  • Auditoria de uso
  • Integração com catracas/tablets
  • Controle de capacidade

Entidades Core

typescript
// Aggregate Root
class PresenceSession {
  id: SessionId
  userId: UserId
  arenaId: ArenaId
  courtId: CourtId | null
  checkInAt: Date
  checkOutAt: Date | null
  status: PresenceStatus
  
  checkIn(location: Location): void
  checkOut(): void
  moveToArea(areaId: AreaId): void
  timeout(): void
}

class PresenceAudit {
  sessions: PresenceSession[]
  
  getUsersInArea(areaId: AreaId): User[]
  getCapacity(areaId: AreaId): CapacityInfo
  detectAnomalies(): Anomaly[]
}

// Domain Events
class UserCheckedIn
class UserCheckedOut
class UserMovedArea
class CapacityExceeded
class PresenceTimeout

Relacionamentos

  • Conformist (CF) com Courts & Allocation
  • Conformist (CF) com Identity & Access

8. Events Context

Tipo: Supporting Domain

Responsabilidades

  • Eventos como modo operacional especial
  • Torneios, campeonatos, festivais
  • Inscrições e participantes
  • Regras específicas por evento
  • Zonas e acessos customizados

Entidades Core

typescript
// Aggregate Root
class Event {
  id: EventId
  arenaId: ArenaId
  name: string
  type: EventType // TOURNAMENT, CHAMPIONSHIP, FESTIVAL, CLINIC
  period: TimeRange
  participants: Participant[]
  zones: EventZone[]
  rules: EventRule[]
  brackets: Bracket[] | null
  
  register(userId: UserId): RegistrationResult
  start(): void
  finish(): void
  applyRules(context: EventContext): void
}

class EventZone {
  id: ZoneId
  areas: AreaId[]
  accessControl: AccessRule[]
  capacity: number
  
  canAccess(userId: UserId): boolean
}

// Domain Events
class EventCreated
class ParticipantRegistered
class EventStarted
class EventFinished
class BracketGenerated

Relacionamentos

  • Conformist (CF) com Scheduling
  • Conformist (CF) com Sponsorship & Ads

9. Commerce & Billing Context

Tipo: Generic Domain

Responsabilidades

  • Consumo (quadra, aula, day-use)
  • Faturamento e cobrança
  • Mensalidades e pacotes
  • Integração com gateways de pagamento

Entidades Core

typescript
// Aggregate Root
class Invoice {
  id: InvoiceId
  userId: UserId
  arenaId: ArenaId
  lineItems: LineItem[]
  total: Money
  status: InvoiceStatus
  dueDate: Date
  
  addItem(item: LineItem): void
  calculate(): Money
  pay(payment: Payment): void
}

class Subscription {
  id: SubscriptionId
  userId: UserId
  plan: SubscriptionPlan
  status: SubscriptionStatus
  currentPeriod: BillingPeriod
  
  renew(): void
  cancel(): void
  upgrade(newPlan: SubscriptionPlan): void
}

// Domain Events
class InvoiceGenerated
class PaymentReceived
class SubscriptionRenewed
class PaymentFailed

Relacionamentos

  • Downstream (D) para Wallet & Value
  • Anti-Corruption Layer (ACL) via Integrations

10. Wallet & Value Context (CORE)

Tipo: Core Domain (Diferenciação)
Event Sourcing: Sim

Responsabilidades

  • Carteiras digitais por entidade
  • Tokens/moedas próprias do clube
  • Transações peer-to-peer
  • Apostas em partidas
  • Cashback e recompensas
  • Sistema de créditos e débitos

Entidades Core

typescript
// Aggregate Root (Event Sourcing)
class Wallet {
  id: WalletId
  ownerId: OwnerId // User, Arena, Event, Application
  ownerType: OwnerType
  balances: Balance[]
  transactions: Transaction[]
  status: WalletStatus
  
  credit(amount: Money, reason: string): Transaction
  debit(amount: Money, reason: string): Transaction
  transfer(to: WalletId, amount: Money): Transfer
  freeze(): void
  unfreeze(): void
  
  // Event Sourcing
  private apply(event: WalletEvent): void
}

class Balance {
  currency: Currency // BRL, USD, CLUB_TOKEN
  amount: Money
  locked: Money
  available: Money
  
  lock(amount: Money): void
  unlock(amount: Money): void
}

// Aggregate Root
class Transaction {
  id: TransactionId
  fromWallet: WalletId | null // null = external source
  toWallet: WalletId | null // null = external destination
  amount: Money
  currency: Currency
  type: TransactionType
  status: TransactionStatus
  metadata: TransactionMetadata
  createdAt: Date
  
  execute(): void
  rollback(): void
  settle(): void
}

class Stake {
  id: StakeId
  matchId: MatchId
  participants: StakeParticipant[]
  pool: Money
  status: StakeStatus
  
  placeBet(userId: UserId, amount: Money, prediction: Prediction): void
  settle(winner: TeamId): void
  distribute(): Transaction[]
}

// Domain Events (Event Sourcing)
class WalletCreated implements WalletEvent
class FundsCredited implements WalletEvent
class FundsDebited implements WalletEvent
class FundsTransferred implements WalletEvent
class FundsLocked implements WalletEvent
class FundsUnlocked implements WalletEvent
class WalletFrozen implements WalletEvent
class TransactionCompleted implements WalletEvent
class TransactionFailed implements WalletEvent

Padrões Aplicados

  • Event Sourcing: Todo estado reconstruído a partir de eventos
  • CQRS: Separação total entre escrita (commands) e leitura (queries)
  • Saga Pattern: Transações distribuídas
  • Idempotency: Proteção contra duplicação

Relacionamentos

  • Conformist (CF) com Commerce & Billing
  • Conformist (CF) com Engagement & Gamification
  • Upstream para múltiplos contextos

11. Engagement & Gamification Context

Tipo: Supporting Domain

Responsabilidades

  • Rankings (global, arena, semanal)
  • Conquistas e badges
  • Desafios e missões
  • Campeonatos e ligas
  • Sistema de progressão
  • Neurociência aplicada (dopamina, recompensas)

Entidades Core

typescript
// Aggregate Root
class PlayerRanking {
  id: RankingId
  scope: RankingScope // GLOBAL, ARENA, WEEKLY
  sport: Sport
  entries: RankingEntry[]
  period: Period
  
  updateScore(playerId: PlayerId, points: number): void
  recalculate(): void
  getPosition(playerId: PlayerId): number
}

class Achievement {
  id: AchievementId
  name: string
  description: string
  criteria: AchievementCriteria
  reward: Reward
  rarity: Rarity
  
  evaluate(player: Player): boolean
  grant(player: Player): void
}

class Challenge {
  id: ChallengeId
  name: string
  type: ChallengeType // DAILY, WEEKLY, SPECIAL
  objectives: Objective[]
  rewards: Reward[]
  startDate: Date
  endDate: Date
  
  participate(playerId: PlayerId): void
  updateProgress(playerId: PlayerId, progress: Progress): void
  complete(playerId: PlayerId): void
}

// Domain Events
class AchievementUnlocked
class ChallengeCompleted
class RankingUpdated
class BadgeEarned
class LevelUp

Relacionamentos

  • Conformist (CF) com Play & Match
  • Conformist (CF) com Analytics & Intelligence

12. Media & IoT Context

Tipo: Supporting Domain

Responsabilidades

  • Captura de vídeos e fotos
  • Geração de highlights
  • Integração com tablets (quadra)
  • Botões físicos (ponto, fim de jogo)
  • Sensores (presença, bola)
  • Streaming de partidas

Entidades Core

typescript
// Aggregate Root
class MediaAsset {
  id: AssetId
  type: MediaType // VIDEO, PHOTO, HIGHLIGHT
  matchId: MatchId | null
  courtId: CourtId
  url: string
  metadata: MediaMetadata
  status: AssetStatus
  
  process(): void
  generateHighlight(markers: Marker[]): MediaAsset
  share(platforms: Platform[]): void
}

class IoTDevice {
  id: DeviceId
  type: DeviceType // TABLET, BUTTON, SENSOR, CAMERA
  courtId: CourtId | null
  status: DeviceStatus
  lastSeen: Date
  
  sendCommand(command: Command): void
  processEvent(event: DeviceEvent): void
}

// Domain Events
class VideoRecorded
class HighlightGenerated
class DeviceConnected
class DeviceDisconnected
class ButtonPressed
class SensorTriggered

Relacionamentos

  • Partnership (PS) com Play & Match
  • Conformist (CF) com Courts & Allocation

13. Sponsorship & Ads Context

Tipo: Supporting Domain

Responsabilidades

  • Gestão de patrocinadores
  • Contratos e cotas
  • Inventário de anúncios (quadra, app, eventos)
  • Métricas de exposição
  • ROI de patrocínio

Entidades Core

typescript
// Aggregate Root
class Sponsor {
  id: SponsorId
  name: string
  logo: string
  contracts: Contract[]
  status: SponsorStatus
  
  addContract(contract: Contract): void
  trackExposure(impression: Impression): void
  calculateROI(): ROI
}

class AdInventory {
  id: InventoryId
  type: AdType // COURT_BANNER, APP_BANNER, VIDEO_AD
  location: AdLocation
  availableSlots: Slot[]
  
  book(sponsor: Sponsor, slot: Slot): Booking
  getMetrics(): InventoryMetrics
}

// Domain Events
class ContractSigned
class AdDisplayed
class AdClicked
class ExposureTracked

Relacionamentos

  • Conformist (CF) com Events

14. Analytics & Intelligence Context

Tipo: Supporting Domain

Responsabilidades

  • Métricas de negócio
  • Relatórios operacionais
  • Análise de comportamento
  • Previsões (ocupação, receita)
  • Recomendações personalizadas
  • Dashboards em tempo real

Entidades Core

typescript
// Read Model (CQRS)
class ArenaMetrics {
  arenaId: ArenaId
  date: Date
  occupancy: OccupancyMetrics
  revenue: RevenueMetrics
  users: UserMetrics
  
  calculate(): void
  compare(period: Period): Comparison
}

class PredictionModel {
  type: PredictionType // OCCUPANCY, REVENUE, CHURN
  algorithm: MLAlgorithm
  accuracy: number
  
  train(data: TrainingData): void
  predict(input: PredictionInput): Prediction
}

// Domain Events
class MetricsCalculated
class PredictionGenerated
class AnomalyDetected
class ReportGenerated

Relacionamentos

  • Upstream (U) para Courts & Allocation
  • Upstream (U) para Play & Match
  • Upstream (U) para Wallet & Value

15. Integrations Context

Tipo: Generic Domain

Responsabilidades

  • Adaptadores para sistemas externos
  • Anti-Corruption Layers
  • Webhooks e eventos externos
  • Sincronização de dados

Padrões Aplicados

  • Anti-Corruption Layer (ACL) para todos os sistemas externos
  • Adapter Pattern para cada integração
  • Facade Pattern para simplificar APIs complexas

Relacionamentos

  • Anti-Corruption Layer (ACL) com Commerce & Billing

Decisões Arquiteturais

ADR-001: Event-Driven Architecture

Status: Aceito

Contexto:
Sistema distribuído com múltiplos bounded contexts que precisam se comunicar de forma assíncrona.

Decisão:
Adotar Event-Driven Architecture com:

  • Event Bus: RabbitMQ ou Kafka
  • Event Store: PostgreSQL para Event Sourcing
  • Patterns: Event Notification, Event-Carried State Transfer, Event Sourcing

Consequências:

  • (+) Desacoplamento entre contextos
  • (+) Escalabilidade horizontal
  • (+) Auditoria completa
  • (-) Complexidade de debug
  • (-) Consistência eventual

ADR-002: CQRS nos Core Domains

Status: Aceito

Contexto:
Core domains (Courts, Wallet, Scheduling) têm requisitos diferentes para escrita e leitura.

Decisão:
Implementar CQRS (Command Query Responsibility Segregation):

  • Write Side: Event Sourcing para Wallet e Match
  • Read Side: Materialized Views otimizadas
  • Sync: Event handlers atualizam read models

Consequências:

  • (+) Performance de leitura otimizada
  • (+) Modelos específicos para cada caso de uso
  • (+) Escalabilidade independente
  • (-) Complexidade adicional
  • (-) Sincronização assíncrona

ADR-003: Multi-Tenancy Strategy

Status: Aceito

Contexto:
SaaS com múltiplas arenas, cada uma isolada.

Decisão:
Shared Database, Shared Schema com tenantId discriminator:

  • Todos os dados filtrados por tenantId
  • Row Level Security (RLS) no PostgreSQL
  • Keycloak multi-realm

Consequências:

  • (+) Custo otimizado
  • (+) Manutenção simplificada
  • (+) Queries cross-tenant para analytics
  • (-) Risco de vazamento de dados
  • (-) Performance pode degradar com escala

Alternativa Futura: Migrar para Shared Database, Separate Schema quando crescer.


ADR-004: Event Sourcing para Wallet

Status: Aceito

Contexto:
Wallet precisa de auditoria completa, histórico imutável e capacidade de rebuild.

Decisão:
Implementar Event Sourcing para Wallet Context:

  • Todo estado reconstruído a partir de eventos
  • Snapshots a cada 100 eventos
  • Event Store dedicado

Consequências:

  • (+) Auditoria completa
  • (+) Reconstrução de estado
  • (+) Temporal queries
  • (-) Complexidade de implementação
  • (-) Performance de leitura (mitigado por snapshots)

ADR-005: Real-Time Communication

Status: Aceito

Contexto:
Necessidade de updates em tempo real (placar, presença, alocação).

Decisão:
Usar WebSockets (Socket.io) para comunicação real-time:

  • Server-Sent Events (SSE) como fallback
  • Redis Pub/Sub para broadcast entre instâncias

Consequências:

  • (+) Latência mínima
  • (+) Experiência rica
  • (-) Complexidade de infraestrutura
  • (-) Gestão de conexões

ADR-006: API Gateway Pattern

Status: Aceito

Contexto:
Múltiplos microserviços precisam de ponto de entrada único.

Decisão:
Implementar API Gateway:

  • Backend for Frontend (BFF): APIs específicas para web/mobile
  • Kong ou NestJS Gateway como tecnologia
  • Rate limiting, autenticação, roteamento

Consequências:

  • (+) Ponto único de entrada
  • (+) Cross-cutting concerns centralizados
  • (+) BFF otimizado por cliente
  • (-) Single point of failure (mitigado com HA)

Princípios Arquiteturais

1. Domain-First Design

"Código deve expressar o domínio, não a tecnologia."

  • Camadas de domínio puras, sem dependências de framework
  • Linguagem ubíqua (ubiquitous language) em código
  • Domain experts colaboram ativamente

2. Separation of Concerns

"Cada componente tem uma responsabilidade clara."

  • Clean Architecture com camadas bem definidas
  • Bounded Contexts isolados
  • Single Responsibility Principle

3. Evolutionary Architecture

"Arquitetura deve evoluir com o negócio."

  • Fitness functions para governança
  • Documentação como código (ADRs)
  • Refactoring contínuo

4. Resilience by Design

"Falhas vão acontecer. Esteja preparado."

  • Circuit breakers para chamadas externas
  • Retry policies com backoff exponencial
  • Timeouts em todas as operações
  • Graceful degradation

5. Observability First

"Se não pode medir, não pode melhorar."

  • Logs estruturados (JSON)
  • Métricas de negócio e técnicas
  • Distributed tracing (OpenTelemetry)
  • Health checks e readiness probes

6. Security by Default

"Segurança não é feature, é fundação."

  • Defense in depth
  • Least privilege principle
  • Secrets management (Vault)
  • Auditoria de todas as ações críticas

Stack Tecnológica

Backend

yaml
Runtime: Node.js 20 LTS
Language: TypeScript 5.3+
Framework: NestJS 10
ORM: Prisma 5
Database: PostgreSQL 16
Cache: Redis 7
Message Broker: RabbitMQ 3.12
Event Store: PostgreSQL + EventStoreDB (opcional)

Frontend

yaml
Framework: Vue.js 3.4
Language: TypeScript
State: Pinia
Router: Vue Router
Build: Vite 5
UI: Tailwind CSS + shadcn-vue

DevOps & Infra

yaml
Containers: Docker
Orchestration: Kubernetes
CI/CD: GitHub Actions
IaC: Terraform
Monitoring: Prometheus + Grafana
Logging: ELK Stack
Tracing: OpenTelemetry + Jaeger

Estrutura de Monorepo

sport-tech-club/
├── apps/
│   ├── api-gateway/              # BFF + API Gateway
│   ├── admin-console/            # Vue.js - Console Admin
│   └── player-app/               # Vue.js - App do Jogador

├── services/
│   ├── identity-service/         # Identity & Access
│   ├── arena-service/            # Arena Management
│   ├── courts-service/           # Courts & Allocation (CORE)
│   ├── scheduling-service/       # Scheduling (CORE)
│   ├── lessons-service/          # Lessons & Coaching
│   ├── play-service/             # Play & Match
│   ├── access-service/           # Access & Presence
│   ├── events-service/           # Events
│   ├── commerce-service/         # Commerce & Billing
│   ├── wallet-service/           # Wallet & Value (CORE)
│   ├── engagement-service/       # Engagement & Gamification
│   ├── media-service/            # Media & IoT
│   ├── sponsorship-service/      # Sponsorship & Ads
│   └── analytics-service/        # Analytics & Intelligence

├── libs/
│   ├── shared-kernel/            # Shared types, Value Objects
│   ├── domain-primitives/        # Base classes (Entity, AggregateRoot)
│   ├── event-bus/                # Event infrastructure
│   └── design-system/            # UI components

├── infrastructure/
│   ├── docker/                   # Dockerfiles
│   ├── kubernetes/               # K8s manifests
│   └── terraform/                # IaC

├── docs/
│   ├── architecture/             # Esta documentação
│   ├── adr/                      # Architecture Decision Records
│   └── api/                      # OpenAPI specs

└── tests/
    ├── e2e/                      # Testes end-to-end
    └── performance/              # Testes de carga

Próximos Passos

Fase 1: Foundation (Meses 1-2)

  • [ ] Setup de monorepo (pnpm workspaces)
  • [ ] Identity & Access Context (Keycloak)
  • [ ] Arena Management Context
  • [ ] API Gateway + BFF
  • [ ] Infraestrutura base (Docker, K8s local)

Fase 2: Core MVP (Meses 3-4)

  • [ ] Courts & Allocation Context (versão simplificada)
  • [ ] Scheduling Context (apenas reservas)
  • [ ] Access & Presence Context
  • [ ] Admin Console (básico)

Fase 3: Player Experience (Meses 5-6)

  • [ ] Player App (Vue.js)
  • [ ] Play & Match Context
  • [ ] Wallet Context (básico)
  • [ ] Engagement Context (rankings)

Fase 4: Differentiation (Meses 7-9)

  • [ ] Allocation Engine avançado
  • [ ] Event Sourcing no Wallet
  • [ ] Stakes e apostas
  • [ ] Media & IoT Context

Fase 5: Scale & Intelligence (Meses 10-12)

  • [ ] Analytics & Intelligence
  • [ ] ML para previsões
  • [ ] Sponsorship Context
  • [ ] Otimizações de performance

Referências

Livros

  • Domain-Driven Design - Eric Evans
  • Implementing Domain-Driven Design - Vaughn Vernon
  • Clean Architecture - Robert C. Martin
  • Building Microservices - Sam Newman
  • Designing Data-Intensive Applications - Martin Kleppmann

Patterns & Practices

Event Sourcing & CQRS


Versão: 1.0.0
Última Atualização: 2026-01-09
Autor: Engenheiro (Claude Opus 4.5)
Status: Living Document


"Architecture is about the important stuff. Whatever that is."
— Ralph Johnson

"The best architectures, requirements, and designs emerge from self-organizing teams."
— Agile Manifesto