Controle de promoções e bónus de nível backend
Texto completo do artigo
1) Por que levar a promoção para um backend separado
Invariantes em dinheiro. O bónus ≠ «ajustou o saldo» é um contrato de condições (vager, contribuição de jogo, máxima de apostas/ganhos).
Taxa de alteração. Equipes de marketing lançam campanhas diariamente - precisa de um motor declaratório de regras e um retrocesso.
Anti-abws/complacência. KYC/RG/AML, velocity, segmentação, tascos «quatro olhos» para offs caros.
Observabilidade e relatórios. SLO, valor da promoção, influência sobre GGR/NGR/LTV.
O princípio é que o núcleo de promoção é um serviço separado com as próprias máquinas estatutárias, e o dinheiro só se move através da carteira, de forma idimpotente.
2) Tipologia de bônus e invariantes
Deposit match (100% a X): é cobrado após capture depósito, vager X x.
Cashback (perder-back): Calculado pela janela do tempo/jogos, pode ser sticky/não-sticky.
Free Spins/Free Bets: cupons/tokens com price por spin/taxa, pulo RTP fixo.
Buscas/missões, missão → progresso → recompensa.
Torneios/voos-iventes: contribuições de eventos, classificação, prémios.
Invariantes:- Sticky: não pode ser exibido antes que as condições sejam cumpridas.
- Max bet/Max win: limites para taxa/pagamento de bónus.
- Contribuições de jogos (por exemplo, slots = 100%, live = 10%).
- Expiry: prazo de validade do bónus e da janela do vager.
3) Arquitetura do serviço de bónus
Admin (campanhas/regras) ─Promo API ─Rules Engine/Elisibility
│
├─Bonus Ledger (estado off)
├─Wagering Engine (progresso)
├─Anti -Abuse (limites/frod/velocity)
└─Outbox (events) ─Kafka/Pulsar ─BI/DWH/CRM
Wallet/Ledger── Idempotent Commands ───┘Rulas Engine - termos declaratórios (segmentos, geo/licença, canais, KYC/RG).
4) Modelo de dados (simplificado)
`bonus_grant`
`wager_progress`- `grant_id, required_minor, contributed_minor, remaining_minor, last_update_at`
- `schema_id, rules: [{game_type:"slot", pct:100},{game_type:"live", pct:10}]`
'bônus _ ledger _ entry' (auditoria)
5) Máquinas estatutárias e sagas
5. 1 Emissão (issue) - saga
1. eligibility. check (segmento RG/KYC, velocity)
2. grant. create (status=`issued`)
3. wallet. credit [bônus] (idimpotente; com sticky - no subbalanceamento de bónus)
4. activate (status=`active`)
5. emit `bonus. issued`
Rollback: ao cair 3 passos → 'grant. cancel '+ evento' bônus. revoked`.
5. 2 Progresso Vager
Na 'bet. setled 'contar a contribuição =' stake _ menor contagem _ pct '(ou segundo as regras win/loss).
Atualizar 'wager _ progress' atomano; ao atingir 100% - 'complete'.
5. 3 Conclusão (consume)
complete → `wallet. convert _ bônus _ to _ cash '(se não-sticky) ou remoção de restrições de saída.
emit `bonus. consumed`.
5. 4 Caducidade/revisão
Por 'expires _ at' ou regra de frod → 'revoke' (idumpotente), é possível compensar de acordo com a política.
6) Contratos com carteira (somente via API, sempre idepotente)
Pagar bónus
POST /v1/wallet/credit
Headers: X-Idempotency-Key: bonus_grant_123
{
"player_id":"p_001",  "amount":{"minor_units":100000,"currency":"EUR"},  "balance_type":"bonus",  "reference":{"grant_id":"gr_123","offer_id":"of_777"}
}
→ 200 {"status":"credited","entry_id":"e_9001"}Converter para o dinheiro após o cumprimento das condições
POST /v1/wallet/convert
Headers: X-Idempotency-Key: bonus_convert_gr_123
{
"player_id":"p_001",  "from_balance":"bonus",  "to_balance":"cash",  "amount_minor":100000,  "reference":{"grant_id":"gr_123"}
}
→ 200 {"status":"converted","entry_id":"e_9010"}- solicitação de 'bets. autorize 'rejeitado pelo código' BÓNUS _ MAX _ BET _ EXCEEDED '.
7) API do serviço de promoção (referência)
Criar off (admin)
POST /v1/offers
{
"name":"Welcome 100% up to 100€",  "type":"deposit_match",  "params":{"match_pct":100,"cap_minor":10000,"wager_x":20,"sticky":true,       "max_bet_minor":200,"max_win_minor":50000,"contribution_schema_id":"c_slot100_live10"},  "eligibility":{"brands":["A"],"regions":["EU"],"segment":"new_depositors"},  "schedule":{"start":"2025-10-20T00:00:00Z","end":"2025-11-30T23:59:59Z"}
}
→ 201 {"offer_id":"of_777"}Emitir bônus (runtime)
POST /v1/bonus/grants
Headers: X-Idempotency-Key: grant_p001_of777
{
"player_id":"p_001","offer_id":"of_777","trigger":"deposit_captured","amount_minor":10000
}
→ 200 {"grant_id":"gr_123","status":"active"}Progressão do Vager (read)
GET /v1/bonus/grants/gr_123/progress
→ 200 {"required_minor":200000,"contributed_minor":45000,"remaining_minor":155000,"pct":0. 225}Cancelar/retirar
POST /v1/bonus/grants/gr_123/revoke
Headers: X-Idempotency-Key: revoke_gr_123
{ "reason":"fraud_velocity" }
→ 200 {"status":"revoked"}Todas as chamadas write são com 'X-Idempotency-Key' e 'X-Trace-Id'.
8) Anti-Abus e Complacência
Velocity limites: emissões/conversões/tentativas de depósito (Redis counters + TTL + Lua).
Um depósito → um grant em regra.
Segmentação e RG: excluir self-exclused/limitados; per brand/region licenças.
Bloco de conflito off: apenas um bónus welcome está ativo ao mesmo tempo; Prioridades.
Detector de anomalias: múltiplas contas/dispositivos/ASN, «desobstruções» rápidas do vager.
Quatro olhos para grandes bolsas e ajustes manuais.
A auditoria WORM de todas as alterações de regras/bolsas/conversões.
9) Observabilidade, métricas e SLO
SLO (orientações):- `grant. issue p95` (issue→credited) ≤ 300–500 мс.
- Atualizar 'wager _ progress p95' ≤ 200 ms desde 'bet. settled`.
- Eventos de bónus no pneu p95 ≤ 2 min do que aconteceu.
- «Bolsas/conversões perdidas/duplicadas» = 0.
- Rate/latency по `issue/convert/revoke`, error-rate (business/4xx/5xx), `IDEMPOTENCY_MISMATCH`.
- Conversão de vager, média 'time-to-complete', proporção de vencimentos.
- Valor da promoção: 'promo _ cost' (menor) e 'promo _ ri' nos cômodos.
- Anti-Abuse: Activação da velocidade desviada pelo max bet/win.
Tracing: na cadeia 'trigger' grant wallet. credit → progress. update → convert`.
10) Integração com RGS/Jogos
Cupons Free Spins/Free Bets - através de 'entitlements' API: emissão de tokens, cancelamento em rate, telemetria de uso.
Max bet/win - regras em 'bets. authorize` и `bets. settle`; devolver os códigos 'BÓNUS _ RULE _ VIOLATION'.
O Contorno é um esquema de nível 'bet. setled '(por' game _ tipo/provider _ id '), versionalização de esquemas.
11) DWH/BI e relatórios
Evento outbox → Lake (bronze) → Silver (SCD2) → vitrines Gold:- `fact_bonus_grants`, `fact_wager_progress`, `fact_bonus_cost`, `fact_promo_roi`.
- SLA frescura: Silver ≤ 15 min, Gold ≤ 30-60 min
- Painéis: conversão por off/segmentos, time-to-complete, contribuição de jogos, abuse-incidentes.
12) Segurança e residência
mTLS + OAuth2 CC; scope’ы `promo:issue`, `promo:convert`, `promo:revoke`.
Chaves/tokens - per brand/region, de curta duração; segredos em Vault/HSM.
Isolamento PII: 'player _ id' - pseudônimo; RLS по `brand/region`.
Rate limits e quotas de emissão; protecção contra tempestades de retrações.
13) Folhas de cheque
Plataforma/operadora
- Todas as transações em dinheiro vão através do Wallet com 'Idempotency-Key'.
- Rulas/Elisibility são versionados; «carta dupla» de eventos nas migrações.
- Os circuitos contábeis estão centralizados, cobertos por testes.
- Velocity e anti-frod estão incluídos; Quatro olhos para grandes somas.
- Outbox/CDC, DLQ e replay controlado para 'bônus.'.
- SLO-dashboard, OpenTelemetry, auditoria WORM.
- Vitrines DWH para RG/AML.
Integração (RGS/carteira/CRM)
- Verifico max bet/win; devolvo o código de erro de negócio.
- Anoto 'trace _ id' e 'idempotency _ key'.
- Provento de desencadeadores e garantia de entrega (webhooks assinados).
14) Bandeiras vermelhas (anti-pattern)
Atribuir o bónus «manualmente» diretamente para o balanço, passando pelo Wallet.
Falta de idempotidade → dobradinha/conversão.
Vager conta por 'bet. placed ', não' bet '. settled`.
Não existem circuitos contábeis ou estão «costurados» no código dos provedores.
Os offs em conflito são ativados simultaneamente.
Não há velocity/anti-frod ou auditoria WORM.
Eventos 'bonus' são publicados para contornar outbox/CDC.
Os indicadores de promoção não são compatíveis com Ledger/BI (nenhuma vitrine ROY).
15) Resultado
Um backend confiável é uma promoção de contratos e invariantes, em vez de «aumentar o equilíbrio». Ele separa as regras do dinheiro, considera o progresso do resultado real, garante a idempotidade e observabilidade, protege contra o abjuz e fornece a complacência. Com esse núcleo de marketing move-se rapidamente, o jogador vê condições justas, e as finanças e reguladores obtêm uma imagem exata do custo e do efeito de cada off.
