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ão | Sigla | Descrição | Quando Usar |
|---|---|---|---|
| Shared Kernel | SK | Modelo compartilhado entre times | Equipe única, contextos fortemente acoplados |
| Customer-Supplier | CS | Cliente downstream, fornecedor upstream | Relacionamento formal, contratos definidos |
| Conformist | CF | Downstream conforma ao modelo upstream | Sem poder de negociação, aceita modelo do upstream |
| Anti-Corruption Layer | ACL | Camada de tradução que protege modelo interno | Integração com legado ou sistemas externos |
| Open Host Service | OHS | API pública documentada para múltiplos consumidores | Serviço core usado por vários contextos |
| Published Language | PL | Linguagem bem documentada para integração | Formato padrão (JSON Schema, OpenAPI) |
| Separate Ways | SW | Contextos completamente independentes | Sem integração, duplicação aceitável |
| Partnership | PS | Desenvolvimento coordenado entre times | Dependência mútua, evolução conjunta |
| Upstream | U | Fornece dados/serviços | - |
| Downstream | D | Consome 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
// 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 RoleAssignedRelacionamentos
- 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
// 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 OperatingHoursUpdatedRelacionamentos
- 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
// 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 MaintenanceScheduledPadrõ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
// 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 LatePenaltyAppliedRelacionamentos
- 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
// 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 LessonCompletedRelacionamentos
- 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
// 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 MatchEventRelacionamentos
- 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
// 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 PresenceTimeoutRelacionamentos
- 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
// 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 BracketGeneratedRelacionamentos
- 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
// 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 PaymentFailedRelacionamentos
- 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
// 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 WalletEventPadrõ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
// 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 LevelUpRelacionamentos
- 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
// 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 SensorTriggeredRelacionamentos
- 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
// 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 ExposureTrackedRelacionamentos
- 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
// 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 ReportGeneratedRelacionamentos
- 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
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
Framework: Vue.js 3.4
Language: TypeScript
State: Pinia
Router: Vue Router
Build: Vite 5
UI: Tailwind CSS + shadcn-vueDevOps & Infra
Containers: Docker
Orchestration: Kubernetes
CI/CD: GitHub Actions
IaC: Terraform
Monitoring: Prometheus + Grafana
Logging: ELK Stack
Tracing: OpenTelemetry + JaegerEstrutura 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 cargaPró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
- https://martinfowler.com/eaaCatalog/
- https://microservices.io/patterns/
- https://www.enterpriseintegrationpatterns.com/
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