Equilíbrio e carteiras: arquitetura multi-wallet
1) Porquê multi-wallet e quais são os objetivos
Uma gravação «balanço = número» não cobre a realidade iGaming. São necessárias carteiras individuais/subcontinentes: dinheiro real (cash), fundos de bônus, wager pool, frisas, PCs, às vezes carteiras de câmbio (EUR/USD/BRL).
Objetivos da arquitetura:- Precisão do dinheiro (duplo-entry, audibilidade).
- Políticas de cancelamento (por exemplo, primeiro bónus/wager, depois cash).
- Velocidade (p95 API ≤ 250-400 ms, aposta/setlment em tempo real).
- Segurança e Complacência (KYC/AML, limites de jogo responsável, reguladores).
- Escala: picos → dezenas de milhares de operações/segundo, bilhões de postings/mês.
2) Modelo de dados: «Ledger + Subwallets»
Entidades mínimas
Conta: jogador/marca/market.
Exemplo de tabelas (simplificado)
sql
-- Contas de balanço para duplo-entry (incluindo prestações de serviço)
accounts(id, owner_user_id, type, currency, status,...)
-- Fio (dupla gravação, referência para transação de negócios)
ledger_entries(id, posting_id, debit_account_id, credit_account_id,        amount_minor, currency, category, operation_id, created_at)
-- Colinas (reservas)
holds(id, account_id, amount_minor, currency, reason, expires_at, state,    operation_id, created_at)
-- Políticas de cancelamento (prioridades)
spend_policies(id, market, wallet_priority jsonb, updated_at)
-- Taxas de câmbio cruzadas fx _ rates (ccy _ from, ccy _ to, rate, precisão, valid _ from)Regra: a verdade vive no registro de fios ('ledger _ entries'). O balanço atual é uma unidade (snapshot materializado) ou é calculado a partir de um registro (caro, mas único válido).
3) Tipos de carteira e seu comportamento
4) Políticas de cancelamento e ordem de prioridade
Formalize claramente o algoritmo de origem de ferramentas: Exemplo (slots/cassinos):1. Primeiro descontar do WAGER (se o wager estiver ativo).
2. Depois do BÓNUS até esgotar.
3. O resto é da CASH.
Exemplo (esportes):1. Primeiro CASH (regulador/imposto).
2. Depois BÓNUS (freebet), traduzindo para WAGER.
Mantenha «solução de política» no Postings como atributo para que a safra e a auditoria vejam «por que isso foi descartado».
5) Ciclo de vida de dinheiro e operações
Depósito
1. 'POST/wallet/deposit' → criando uma gravação pending (inbox salsicha PSP).
2. Webhook PSP (HMAC, Idempotação por 'operation _ id') → credit CASH, category = 'DEPOSIT'.
3. Publicamos o evento 'wallet _ updated'.
Aposta
1. 'POST/bet/place' → criando hold (reserva) na conta de origem (CASH/BÓNUS/WAGER).
2. Quando a taxa for confirmada, → a transferência hold → debit da fonte, credit da conta de serviço do provedor.
3. Quando cancelado, release hold.
Setlment (resultado)
Ganho: debit conta «calculada» do provedor → credit CASH ou WAGER→BONUS→CASH de política.
Perder: fechamos com o fio «consumo» do provedor → sem crédito para o jogador.
1. Teste KYC/AML, limites do jogo responsável.
2. Hold para o valor da retirada.
3. O sucesso do PSP é o debit final do CASH credit a conta «pagamento».
4. Recusa PSP → release hold.
6) Idempotidade e exactly-once «no sentido»
«operation _ id» (UUID/ULID avançado) está em todo o lado com um índice exclusivo. Uma nova solicitação → o status da última operação.
Webhoop PSP/Provedor de jogos: Tabela inbox com dedupe por 'event _ id + marca'. Processamento - Worker Idempotental (Outbox-Pattern).
Idempotency-Key em HTTP para o cliente; TTL armazenar ≥ 24-72 h.
7) Reservas e colinas (holds)
O Hold não é um cancelamento, é um congelamento do resto disponível.
Regras:- Tempo de vida da colina: seconds→minutes (aposta) ou relógio (conclusão).
- Hold pode ser parcialmente ou totalmente reembolsado (partial setle).
- O expire é um release automático e um evento.
- Guarde a ligação 'hold _ id' ↔ 'bet _ id/withdraw _ id'.
8) Moedas, FX e arredondados
Somas em dinheiro em unidades menores (cents), tipo inteiro.
Arredondamentos bancários (round half to even) ou T & C.
FX: 'CASH' n' CASH (USD) 'é melhor separar as carteiras. Conversão como uma operação individual:- 'debit EUR, credit FX _ EURUSD' e 'debit FX _ EURUSD, credit USD' são transparentes para a auditoria.
- Proibido pela máquina de «alcançar» o curso na disputa; todas as regras estão na política FX.
9) Jogo responsável e limites
Deposit/Bet/Loss/Sessão limites (dia/semana/mês), «cooling-off», self-exclusion.
Implementado como pré-check antes de hold/debit.
Logs de rejeição - em um registro de auditoria separado, disponível para safort e regulador.
10) Sinais antifrod em torno da carteira
Clusters/ASN, depósitos frequentes de baixo valor → grandes conclusões, pattern de lavagem.
Os limites Velocity para 'deposit/withdraw' são BIN/país/dispositivo.
Folhas para destinatários (carteiras/IBAN), lista «mulas».
Os eventos da carteira → na função store de download (login/depósito/taxa).
11) Consistência e desempenho
Verdade vs dinheiro
A verdade está na ledger. Para a API «obter um equilíbrio», mantenha o snapshot materializado ('user _ id + wallet _ tipo → balance _ menor, version').
Escrever: Transação na Base de Dados → deficiente em dinheiro.
Em «pesados» flow (live) é apropriado short-TTL 1-5 com + verificação obrigatória da verdade antes da retirada/grande aposta.
Escalar
Sharding por 'user _ id' (pod/classificação), esparsos individuais sob CASH vs BONES.
Chaves quentes (VIP/bots) - request coalescing por 'user _ id'.
Agregações asinhrônicas (junte 'posting' → 'updater' no fundo).
12) Contratos API (pseudo)
Equilíbrio
http
GET /v1/wallets? types=CASH,BONUS
→ 200 {"wallets":[
{"type":"CASH","currency":"EUR","available":12050,"hold":500,"version":1942},  {"type":"BONUS","currency":"EUR","available":3000,"wager_req":15000}
]}Aposta (com a colina)
http
POST /v1/bets/place
{"bet_id":"b_123","amount":500,"currency":"EUR","source_policy":"casino_default", "idempotency_key":"ik_abc"}
→ 201 {"status":"HELD","hold_id":"h_789","expires_in":30}Setlment
http
POST /v1/bets/settle
{"bet_id":"b_123","result":"WIN","payout":1250}
→ 200 {"status":"SETTLED","cash_delta":+1250}http
POST /v1/withdrawals
{"withdraw_id":"w_456","amount":10000,"currency":"EUR","method":"sepa", "idempotency_key":"ik_def"}
→ 202 {"state":"PENDING","next_check_sec":2,"status_url":"/v1/withdrawals/w_456"}13) Exemplos de fio (duplo-entry)
Depósito de €100 (PSP fee €1, Comms. conta - separada)
Debit: PSP_Settlements(EUR)   10000
Credit: User. CASH(EUR)         10000
Debit: User. CASH (EUR) 100 (fee transferido)
Credit: PSP_Fees(EUR)          100Taxa de €5 do BÓNUS (transferência para WAGER)
Debit: User. BONUS(EUR)       500
Credit: User. WAGER (EUR) 500 (deslocamento para «wager»)
Debit: User. WAGER(EUR)       500
Credit: Provider. Senslement (EUR) 500 (taxa cancelada)Ganho de €12. 5 → em CASH
Debit: Provider. Settlement(EUR)  1250
Credit: User. CASH(EUR)         1250Cancelamento (implementação por conta de serviço HOLD)
Debit: User. CASH(EUR)       500
Credit: User. HOLD (EUR) 500 (criado por hold)
-- no setle
Debit: User. HOLD(EUR)       500
Credit: Provider. Settlement(EUR)   500
-- ao cancelar
Debit: User. HOLD(EUR)       500
Credit: User. CASH(EUR)         50014) Auditoria, imutabilidade e conformidade
WORM/imutability para registro (armazenamento de objetos/arquivo WAL).
Lançadores de acesso: quem leu/alterou limites, quem fez ajustes manuais (somente por meio de «adjustment-posting» com justificativa).
GDPR/reguladores: armazenamento de transações de 5 a 10 anos (jurisdição), transparência de cálculo para o jogador (histórico de cancelamentos/wager).
15) Resistência a falhas e DR
Multi-AZ é obrigatório; Região DR para carteira: replicação sync na área, async - região; O PITR está ligado.
Promote standby - apenas manualmente por folha de cheque (excluir split-brain).
Restabelecer semanalmente (teste-restore), combinando o valor dos relatórios de controle.
16) Observabilidade da carteira
SLI: `deposit_success_ratio`, `withdraw_success_ratio`, `bet_hold_latency_p95`, `settlement_latency_p95`.
Тех: `ledger_postings_rate`, `db_connections_saturation`, `queue_lag_seconds`, `hold_expired_rate`.
Alerts: Queda de sucess PSP no mercado, crescimento de 'hold _ expired _ rate', descarga do provedor de jogos (nenhuma confirmação> N min).
17) Testes e controle de qualidade
Testes contratuais com provedores de jogos PSP (webhooks/assinaturas).
Testes de dinheiro property-based: soma de débitos = = soma de créditos em cada Posting.
Fuzz/chaos: atrasos de PSP/provedor, repetições de webhooks, flappies de rede.
Cargas: burst apostas (60-120 s), soaks (4-8 h), controle 'queue _ lag' e p99.
18) Folha de cheque de produção pronta
- Entrada dupla ledger, todas as operações via Posting com 'operation _ id'.
- Spend-policies nítidos e ordem de prioridade (com posting).
- Colinas com TTL/partial setle/expedy, ligação com bet/withdraw.
- Inbox/Outbox, webhooks HMAC, idepotência em todas as fronteiras.
- Carteiras individuais CASH/BÓNUS/WAGER/FS/PONTOS; Divisão de divisas.
- FX e arredondados em unidades menores; a conversão é uma operação separada.
- Limites de jogo responsável até hold/debit; auditoria de falhas.
- Caixa de leitura (TTL curto) + verificação de verdade obrigatória antes de ações críticas.
- PITR/Bacapes/DR; propaganda manual, ensinamentos DR regulares.
- Dashboards/alertas SLI + técnicos; logs do WORM e metajwings de acesso.
- Testes de carga/caos; relatórios de reconciação com PSP/provedores.
Currículos
A arquitetura multi-wallet não é «muitos números de balanço», mas sim um sistema financeiro com registro duplo, políticas de gastos, reserva e um rasto transparente para a auditoria e jogadores. Mantenha a verdade na revista, use as colinas e idempotidade, divida carteiras e moedas, automatize a reconciação e DR. Assim, a carteira será rápida para UX, preciso para o dinheiro e sustentável sob cargas de pico e verificações regulatórias.
