DDD no núcleo iGaming
O iGaming-Plataforma é um complexo sistema de domínios em conexão entre finanças, entretenimento e complacência. O DDD ajuda a manter a complexidade: destaca bounded contexts, capta ubiquitous language, protege os invariantes com agregados, simplifica a integração através de camadas anticorrupção e torna o comportamento do sistema transparente graças a eventos de domínio.
1) Mapa de domínios e bounded contexts (design estratégico)
Descomposição recomendada:- Player/KYC Context - inscrição, verificação, limites de jogo responsável, estatais KYC/AML.
- Wallet/Ledger Context - balanços, reservas, cabos, multiversibilidade, cursos.
- Betting Context - apostas/tíquetes, par/resultado, cotação, cálculo, cancelamento.
- Casino/Game Round Context - sessões, rodadas, costas, controle RTP, limites de aposta.
- Bónus/Promo Context - regras de bónus, vagar, equinos de bônus, anti-abws.
- Risk/Fraud Context - mapeamento, sinais comportamentais, desencadeadores de bloqueio/temporais.
- Payments Context - depósitos/conclusões, passagens de pagamento, eventos de marceback.
- Compliance/Reporting Context - relatórios aos reguladores, listas de sanções, auditorias.
- Conteúdo/Provider Integration Context - Integração com provedores de jogos, diretórios, tecnologia. estatais.
- Analytics/Read Models - projeções e vitrines para leitura de alimentos.
2) Ubiquitous language: núcleo de termos
Player (Jogador), Sessão (Sessão), GameRound (Rodada), Bet/Jet (Aposta),
Ledger Entry (Fio), Hold/Reserve (Reserva), Senslement (Cálculo),
Bonus Credit / Bonus Balance, Wagering Requirement (Вейджер),
KYC Tier, Limit (depósito/sessão/perda), Self-Exclusion,
Provider Game, RTP Window, Risk Flag, Compliance Case.
Estes nomes são usados igualmente em código, base de dados, documentação, testes e interfaces.
3) Unidades e invariantes (design tático)
3. 1 Wallet (Aggregate: `Wallet`)
Invariantes:- O equilíbrio não vai para menos.
- Reserva + disponível ≤ saldo total.
- Fio atômico e idempotental (por 'operation _ id').
- `Wallet. Reserve(amount, reason, op_id)` → `WalletReserved`
- `Wallet. Commit(op_id)` → `WalletCommitted`
- `Wallet. Rollback(op_id)` → `WalletRolledBack`
Fronteira: Wallet desconhece Bet/Bónus; Ele mantém operações de fio e reservas.
3. 2 Bet/Ticket (Aggregate: `Bet`)
Invariantes:- A taxa só pode ser aceita na janela de cotação ativa; soma ≤ limite de jogador/sessão.
- Depois de 'Setled', o status foi 'finalizado'; O novo cálculo só pode ser feito através de transações de compensação (void/recalc) com uma auditoria clara.
- `Bet. Place(player_id, amount, price, op_id)` → `BetPlaced` (требует Wallet. Reserve)
- `Bet. Setle (outcome, payout) '→' BetSettled '(exige Wallet. Commit/Release)
- `Bet. Void(reason)` → `BetVoided`
Fronteira: Bet não se «mete» em Wallet - vira-se através de comandos de domínio/orquestração.
3. 3 GameRound (Aggregate: `Round`)
Invariantes:- Cada spin/round tem um único 'round _ id' e um valor de aposta/ganho associado.
- A janela RTP não ultrapassa os limites definidos (nível do provedor + regras locais).
- `Round. Started`, `Round. Staked`, `Round. Resulted`, `Round. Closed`.
3. 4 Bonus (Aggregate: `BonusGrant`)
Invariantes:- A Vager é reduzida apenas por tráfico de valor, o bónus não vai para o débito.
- Não é possível cancelar o bónus e os fundos reais de acordo com a regra de prioridade.
- `BonusGranted`, `BonusWagered`, `BonusExpired`, `BonusConverted`.
4) Orquestões, sagas e coerência
Sincronizado (COP): Aceitação de apostas e reserva de fundos - caminho único: 'Bet. Place` → `Wallet. Reserve '(através do comando de domínio/orquestrador com deadline).
Asincrono (EC): cálculo da taxa, bônus, analista, eventos + outbox.
A versão TCC é «TryReserve» (hold), «Confirm» (commit), «Cancel» (rollback) para efeitos monetários.
Idempotidade: Todos os comandos carregam 'operation _ id', os consoantes são 'inbox'.
5) Camadas anti-corrupção (LCA) e integração
Provider LCA: transmissão de eventos de provedor 'SpinResult', 'BonusWin' para 'Round' interior. Resulted`, `BonusWagered`. Os circuitos e versões estão dentro da LCA.
PSP ACL: normalização de pagamentos, idempotidade por 'psp _ tx _ id', tradução para 'LedgerEntry'.
Compliance ACL: integração com listas de sanções/RER - no contexto externo; apenas os 'ScreeningUpdated' normalizados entram no domínio.
Regra: Os dicionários/formatos externos não «escapam» para dentro do núcleo.
6) Projeções e Read Models
Player Profile Read Model: estados KYC, limites, bônus ativos, transações recentes.
Balances Read Model: leitura rápida para UI/marketing; a origem é 'Wallet' evento.
Bet History Read Model: paginação por datas/jogos; a fonte é 'BetPlaced/Settled'.
Compliance Reports: representações materializadas por tenante/região.
Todas as projeções são upsert idempotentes com versionagem e 'as _ of/freshness'.
7) Multi tenante e região multi
Todas as entidades-chave carregam 'tenant _ id' e 'region', se necessário.
Limites de dados: jogador, carteira, apostas - região «doméstica»; As regiões cruzadas são apenas unidades/relatórios.
Fairness/quotas: limites por comandos/segundos e rábeis por tenentes.
Residency/complacência: dados pessoais e fios não saem da região.
8) Seleção de coerência (PACELC) por contexto
Wallet/Ledger - Strong/COP: cabos lineáveis, quórum de gravações.
Bet acceptance - Confirmação sincronizada (CP) + rápido Read Models para UI.
Senslement/Bónus/Analytics - EC com compensações determinadas por merge/compensação.
KYC/Compliance - Pode ser EC para estatais, mas as regras «bloqueadoras» são aplicadas sincronicamente.
9) Eventos de domínio: contratos e versão
Conjunto mínimo de campos:json
{
"event_id": "uuid",
"event_type": "BetPlaced",
"occurred_at": "timestamp",
"tenant_id": "T123",
"aggregate_id": "BET-...-UUID",
"version": 7,
"payload": { "...domain fields..." },
"schema_version": "v3"
}
Regras:
- Back/forward-compat circuitos; evolução através de 'schema _ version'.
- 'outbox' em uma transação com alterações de domínio; publicar batches com backoff.
10) Exemplo de fluxo «Aposta com bónus» (seqüência verbal)
1. `Bet. Place '(comando) → verificar os limites do jogador e as regras do bónus →' Wallet. Reserve(real+bonus_equiv, op_id)`
2. 'BetPlaced' (evento) → Read Model atualiza «Apostas abertas»
3. O provedor publica o resultado → LCA → 'Round. Resulted`
4. O orquestrador conta, 'Bet. Settle(outcome,payout)` → `Wallet. Commit (op _ id) 'e, se ganhar,' BonusWagered '→ uma possível conversão do bónus em real.
5. ' ', projecções de história e balanços, relatórios.
11) Invariantes e política de testes
Invariantes-chave:- A soma de todos os 'LedgerEntry' é igual ao balanço; Não há resíduos negativos.
- Não é possível aceitar uma taxa com self-exclusion/status KYC congelado.
- O Vager só pode diminuir e não balançar para menos.
- O Senslement não altera o status da taxa já finalizada - apenas através de 'Void/Recalc' + fio compensatório.
- Testes property-based invariantes carteira e apostas.
- Contornos de caos: atrasos do provedor, falhas PSP, redbox/DLQ.
- Controle de padrão: migração de eventos, backfill projeções.
12) Telemetria e auditoria
Métricas: p95/p99 por PlaceBet/Reserve/Commit, proporção de falhas por limite/CUS, DLQ rate, redrive sucess, lag projeções.
Tracing: spans «komanda→agregat→outbox→konsyumer→proyektsiya», tags «tenant _ id», «operation _ id», «saga _ id».
Auditoria: registro de domínio imutável, compatível com os requisitos regulatórios.
13) Esquema de armazenamento (simplificado)
Wallet:
wallet(id, tenant_id, currency, balance, reserved, version)
ledger(id, wallet_id, amount, type, operation_id, occurred_at)
holds(id, wallet_id, amount, operation_id, expires_at, status)
Bet:
bet(id, tenant_id, player_id, amount, price, status, placed_at, settled_at, operation_id)
Bonus:
bonus_grant(id, tenant_id, player_id, amount, wager_left, status, expires_at)
A versionização em unidades ('version') protege contra lost update em uma gravação competitiva.
14) Exemplo de comandos API (pseudo)
http
POST /bets. place
{
"tenant_id":"T1",
"player_id":"P42",
"amount":"10. 00",
"price":"2. 1",
"operation_id":"op-uuid",
"context":{"game_id":"g777","channel":"web"}
}
→ 202 Accepted + BetPlaced
POST /wallets. reserve
{ "wallet_id":"W1", "amount":"10. 00", "operation_id":"op-uuid", "reason":"bet" }
→ 200 { "reserved_balance":"..." }
Todos os comandos são 'operation _ id' para idempotação, e as respostas são 'as _ of '/' version'.
15) Segurança e conformidade
RLS/LCA: Todas as solicitações são no contexto 'tenant _ id', acesso por papel.
PII-Minimização: Separando os eventos de domínio dos dados pessoais; camuflagem em DLQ/logs.
Relatórios regulatórios: projeções com assinaturas de hash inalteráveis de janelas de tempo.
16) Erros típicos
Forte conectividade entre contextos (Wallet conhece diretamente Bet/Bónus).
Dual-write em contextos diferentes sem sagas/outbox → alinhamento de balanços e estatais.
A falta de idempotação dos comandos e consoantes → as duplicações de fios/cálculos.
Flui os contratos de provedor para o modelo de domínio (mais difícil de migrar).
Uma unidade «gigante» (Player inclui tudo) é bloqueada, e um throughput baixo.
Não há invariantes aparentes que não possam ser verificados ou monitores.
17) Receitas rápidas
Início: Fixe o Ubiquitous Language e os limites contextuais; documentem os invariantes.
Dinheiro: Wallet/Ledger - CDP, quórum, TCC para efeitos externos.
Apostas: recepção sincronizada + cálculo asincrônico, tudo através de eventos e outbox; Idimpotência em todo o lado.
Bónus: unidade separada com prioridade clara de cancelamento e vager.
Integração: sempre através de LCA + circuitos/versões; Nada de «matéria-prima» payload 'ov no núcleo.
Leituras: projeções/vitrines para as necessidades do produto; SLA frescura + 'as _ of'.
Operação: métricas de invariantes, DLQ/Readbooks playbooks, rebuild vitrines.
18) Folha de cheque antes de vender
- Definidos bounded contexts e seus contratos (comandos/eventos).
- As unidades têm invariantes claros, versionagem e comandos idempotentes.
- Transações em dinheiro - via TCE/Transacionalidade rigorosa; a auditoria está ativada.
- Integração - via LCA com versionização de circuitos e testes de evolução.
- Estão incorporados outbox/inbox, DLQ e redrave seguro.
- Projeções implementam SLA frescura, há métricas de lag/staleness.
- Quotas multi-tenentes/limites e dados residency foram cumpridos.
- Observabilidade: Trailing «komanda→sobytiye→proyektsiya», alertas de invariantes.
- Documentação: linguagem de domínio, diagramas de contextos, playbooks de incidentes.
Conclusão
O DDD no núcleo iGaming é uma disciplina de divisão de complexidade: limites claros de contextos, agregados com invariantes, eventos como fonte de verdade, LCA para integração externa e escolha consciente de coerência. Esta abordagem torna a plataforma escalável, confiável e adequada, acelera o desenvolvimento de fichas e reduz os riscos operacionais - mesmo com o rápido crescimento do tráfego, das geografias e da linha de alimentos.