Bilanciamento e portafogli: architettura multi-wallet
1) Perché multi-wallet e quali obiettivi
Una voce «saldo = numero» non copre la realtà. Servono portafogli/cassette separati: denaro reale (cash), bonus, wager pool, fresine, PC-point, a volte portafogli in valuta (EUR/USD/BRL).
Obiettivi dell'architettura:- Precisione del denaro (doppio-entry, audibile).
- Criteri di prelievo (ad esempio, prima bonus/wager, poi cash).
- Velocità (p95 API da 250 a 400 ms, puntata/settlent in tempo reale).
- Sicurezza e compilazione (KYC/AML, limiti di gioco responsabile, regolatori).
- Scala: picchi di decine di migliaia di operazioni/secondo, miliardi di posting/mese.
2) Modello dati: «Ledger + Subwallets»
Entità minime
Account: giocatore/marchio/market.
Esempio di tabelle (semplificata)
sql
- Bilanci per la doppia-entry (inclusi quelli di servizio)
accounts(id, owner_user_id, type, currency, status,...)
-- Cablaggio (doppio record, collegamento a un'operazione aziendale)
ledger_entries(id, posting_id, debit_account_id, credit_account_id,        amount_minor, currency, category, operation_id, created_at)
-- Hold (riserve)
holds(id, account_id, amount_minor, currency, reason, expires_at, state,    operation_id, created_at)
-- Criteri di cancellazione (priorità)
spend_policies(id, market, wallet_priority jsonb, updated_at)
-- Tassi di cambio di fx _ rates (ccy _ from, ccy _ to, rate, precisione, valid _ from)Regola: la verità vive nel registro dei fili ('ledger _ entries'). Il saldo corrente è un aggregato (snapshot materializzato) o è calcolato dal registro (costoso, ma solo corretto).
3) Tipi di portafogli e il loro comportamento
4) Criteri di cancellazione e ordine di priorità
Formalizza in modo chiaro l'algoritmo di origine degli strumenti: Esempio (slot/casinò):1. Prima cancella da WAGER (se il wager è attivo).
2. Poi dal BONUS, finché non è esaurito.
3. Il resto è di CASH.
Esempio (sport):1. Prima CASH (regolatore/tassa).
2. Poi BONUS (freebet), tradotto in WAGER.
Conservare in Postings la «soluzione di criteri» come attributo in modo che lo zapport e il controllo vedano «perché è stato cancellato».
5) Ciclo di vita di denaro e operazioni
Deposito
1. 'POST/wallet/deposit'creiamo una voce pending (inbox salsiccia PSP).
2. Webhook PSP (firma HMAC, idampotenza per «operation _ id») → credit CASH, category = «DEPOSIT».
3. Pubblichiamo l'evento wallet _ updated.
Puntata
1. 'POST/bet/place', creiamo hold (riserva) sul conto sorgente (CASH/BONUS/WAGER).
2. Quando la scommessa viene confermata, la traduzione hold debit della fonte, credit del conto di servizio «calcolato» del provider.
3. Al momento dell'annullamento - release hold.
Settlement (risultato)
La vincita è debit il conto «calcolato» del provider di credit CASH o della politica.
Se perdiamo, chiudiamo il flusso del provider senza prestiti al giocatore.
1. Controllo KYC/AML, limiti di gioco responsabile.
2. Hold per l'importo di output.
3. Il successo di PSP è il debit finale di CASH credit conto «pagamento».
4. PSP → release hold non riuscito.
6) Idampotenza e exactly-once «in senso»
Dappertutto «operation _ id» (UUID/ULID avanzato) con indice univoco. Ripetere la richiesta per lo stato dell'operazione precedente.
Webhoop PSP/provider di giochi: tabella Inbox con dedupe a «event _ id + firma». Elaborazione: Idempotent Worker (Outbox-Pattern).
Idempotency-Key su HTTP per il client; TTL ≥ 24-72 ore
7) Riserve e colline (holds)
Hold non è un prelievo, ma un'congelamento "del resto disponibile.
Regole:- Durata della collina: seconds→minutes (puntata) o ore (output).
- Hold può essere parzialmente o completamente rimborsato (partial settle).
- Espire - release automatica e evento.
- Memorizza il collegamento «hold _ id» ↔ «bet _ id/withdraw _ id».
8) Valute, FX e arrotondamenti
Le somme di denaro sono in unità minori (cents), il tipo è intero.
Arrotondamenti bancari (round half to even) o T & C.
FX: «CASH (EUR)» ↔ «CASH (USD)» è meglio separare i portafogli. Conversione come operazione separata:- 'debit EUR, credit FX _ EURUSD'e 'debit FX _ EURUSD, credit USD' è trasparente per il controllo.
- Vietato da un distributore automatico di rotta durante una discussione; tutte le regole sono FX.
9) Gioco responsabile e limiti
Deposit/Bet/Loss/Sessione limiti (giorno/settimana/mese), cooling-off, self-exclusion.
Implementato come pre-check prima di hold/debit.
I loghi di errore sono un registro di controllo separato, accessibili allo zapport e al regolatore.
10) Segnali antifrode intorno al portafoglio
Cluster di dispositivi/ASN, depositi frequenti di piccole dimensioni, grandi conclusioni, pattern di riciclaggio.
Limiti Velocity a «deposit/withdraw» per BIN/paese/dispositivo.
Fogli di blocco per destinatari (portafogli/BAN), elenco dei muli.
Gli eventi del portafoglio vengono visualizzati nella feature store (login/deposito/tasso).
11) Consistenza e prestazioni
Verità vs cache
La verità è in ledger. Per l'API «Riscuote equilibrio» - Mantieni lo snipshot materializzato ('user _ id + wallet _ type _ minor, version').
Scrivi: Una transazione in un database può invalidare la cache.
Nei flow «pesanti» (live) è appropriato short-TTL 1-5 con + controllo obbligatorio della verità prima del ritiro/grande puntata.
Scalare
Sharding per «user _ id» (modulo/classificazione), singoli pool shard sotto CASH vs BONUS.
Chiavi hot (VIP/bot) - richiest coalescing in'user _ id '.
Aggregazioni asincrone (compila «posting» «snapshot-updater» sullo sfondo).
12) Appalti API (pseudo)
Bilanciamento
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}
]}Puntata (con collina)
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}Settlement
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) Esempi di cablaggio (doppio-entry)
Deposito €100 (PSP fee €1, Commis. conto - separato)
Debit: PSP_Settlements(EUR)   10000
Credit: User. CASH(EUR)         10000
Debit: User. CASH (EUR) 100 (fee reimpostato)
Credit: PSP_Fees(EUR)          100Puntata €5 da BONUS (tradotto in WAGER)
Debit: User. BONUS(EUR)       500
Credit: User. WAGER (EUR) 500 (Wager)
Debit: User. WAGER(EUR)       500
Credit: Provider. Settlement (EUR) 500 (tasso azzerato)Vinca 12 €. 5 → in CASH
Debit: Provider. Settlement(EUR)  1250
Credit: User. CASH(EUR)         1250Prelievo collettivo (implementazione tramite conto di servizio HOLD)
Debit: User. CASH(EUR)       500
Credit: User. HOLD (EUR) 500 (creato da hold)
-- a settle
Debit: User. HOLD(EUR)       500
Credit: Provider. Settlement(EUR)   500
-al momento dell'annullamento
Debit: User. HOLD(EUR)       500
Credit: User. CASH(EUR)         50014) Controllo, invariabilità e conformità
WORM/immutability per il registro (archivio oggetti/archivio WAL).
Lanciatori di accesso: chi ha letto/cambiato i limiti, chi ha effettuato regolazioni manuali (solo tramite «adjustment-posting» con giustificazione).
Regolatori GDPR: conservazione delle transazioni di 5-10 anni (giurisdizione), trasparenza dei calcoli per il giocatore (cronologia dei prelievi/versamenti).
15) Disponibilità e DR
Multi-AZ è obbligatorio; Serie DR per portafogli: replica sync in zona, async in regione PITR attivato.
Promote standby - Solo manualmente su foglio di assegno (escludere split-brain).
Il ripristino viene controllato settimanalmente (test-restore), il calcolo dell'importo dei report di controllo.
16) Osservabilità portafoglio
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`.
Alert: la caduta di success PSP sul mercato, la crescita dì hold _ expired _ rate ", la rassincron del provider di giochi (nessuna conferma> N min).
17) Test e controllo qualità
Test contrattuali con PSP/videogame provider (webhoop/firme).
Test di denaro property-based: importo dei debiti = = importo dei prestiti in ogni Posting.
Fuzz/chaos: ritardi PSP/provider, ripetizioni di webhoop, flappy di rete.
Carichi di lavoro: puntate burst (60-120 s), soaks (4-8 h), controllo «queue _ lag» e p99.
18) Assegno-foglia di produzione-pronto
- Doppia voce ledger, tutte le operazioni tramite Posting con'operation _ id '.
- Spend-policies nitidi e ordine di priorità (personalizzato con il posting).
- Colline con TTL/partial settle/expiry, collegamento con bet/withdraw.
- Inbox/Outbox, webhoop HMAC, idipotenza su tutti i confini.
- Portafogli CASH/BONUS/WAGER/FS/PUNTI separati; divisioni in valuta.
- FX e arrotondamenti in unità minori; la conversione è un'operazione separata.
- Limiti di gioco responsabile a hold/debit; Controllo dei guasti.
- Cache per la lettura (TTL breve) + verifica obbligatoria della verità prima delle attività critiche.
- PITR/backap/script DR; promote manuale, esercitazioni DR regolari.
- Dashboard/alert SLI + tecnico; login WORM e metaggini di accesso.
- Test di carico/caos; reconciazione con PSP/provider.
Curriculum
L'architettura multi-wallet non è «molti numeri di bilanciamento», ma un sistema finanziario a doppia voce, regole di spesa, riserva e una traccia trasparente per il controllo e i giocatori. Tenete la verità nella rivista, usate le colline e l'idimpotenza, separate portafogli e valute, automatizzate la reconciazione e DR. In questo modo il portafoglio sarà veloce per UX, preciso per il denaro e sostenibile per i picchi di carico e controlli regolatori.
