DDD în nucleul iGaming
Platforma iGaming este un sistem de domenii complex la intersecția dintre finanțe, divertisment și conformitate. DDD ajută la menținerea complexității: evidențiază contexte delimitate, captează limbajul omniprezent, protejează invarianții cu agregate, simplifică integrările prin straturi anticorupție și face comportamentul sistemului transparent prin evenimente de domeniu.
1) Harta domeniului și contexte delimitate (design strategic)
Descompunerea recomandată:- Player/KYC Context - înregistrare, verificare, limite de joc responsabile, statusuri KYC/AML.
- Context portofel/registru - solduri, rezervări, tranzacții, multicurrency, rate de schimb.
- Context pariuri - pariuri/bilete, pereche/rezultate, cotații, decontare, anulare.
- Context Casino/Game Round - sesiuni, runde, spate, control RTP, limite de pariere.
- Bonus/Promo Context - reguli bonus, pariuri, achiziționarea de fonduri bonus, anti-abuz.
- Contextul riscului/fraudei - scoring, semnale comportamentale, declanșatoare de blocare/timeout.
- Context plăți - depozite/retrageri, statusuri gateway de plată, evenimente chargeback.
- Context de conformitate/raportare - rapoarte către autoritățile de reglementare, liste de sancțiuni, audituri.
- Content/Provider Integration Context - integrare cu furnizorii de jocuri, cataloage, tech. statusuri.
- Analytics/Read Models - proiecții și vitrine pentru citirea produselor.
2) Limba omniprezentă: nucleul termenilor
Jucător, Sesiune, GameRound, Pariu/Bilet,
Înregistrare registru, Hold/Rezerva, decontare,
Bonus Credit/Bonus Sold, Cerință de pariere (Вейджер),
Nivelul KYC, Limita (depozit/sesiune/pierdere), Auto-excludere,
Joc furnizor, fereastră RTP, pavilion de risc, caz de conformitate.
Aceste nume sunt utilizate în mod egal în cod, bază de date, documentație, teste și interfețe.
3) Agregate și invarianți (design tactic)
3. 1 Portofel (agregat: „Portofel”)
Invarianţi:- Soldul nu merge în teritoriu negativ.
- Rezervă + disponibil ≤ soldul total.
- Cablajul este atomic și idempotent (prin "operation _ id').
- Portofel. Rezerva (suma, motivul, op_id) '→' WalletReserved '
- Portofel. Angajează (op_id) '→' WalletCommitted '
- Portofel. Rollback (op_id) '→' WalletRolledBackl'
Frontieră: Portofelul nu știe despre Bet/Bonus; acesta servește detașarea și tranzacțiile de rezervă.
3. 2 Pariu/Bilet (cumulat: 'Pariu')
Invarianţi:- Rata poate fi acceptată numai în fereastra cotației active; Suma ≤ jucător/limita de sesiune.
- După „Settled”, statutul este „finalizat”; recalcularea este permisă numai prin operațiuni de compensare (vid/recalc) cu audit clar.
- "Bet. Plasați (player_id, suma, prețul, op_id) '→' BetPlased '(требует Wallet. Rezervă)
- "Bet. Soluționare (rezultat, plată) "→" BetSettled "(necesită Portofel. Comite/Eliberare)
- "Bet. Gol (motiv) '→' BetVoided '
Frontieră: Pariul nu „urcă” în portofel - apelează prin comenzi de domeniu/orchestrare.
3. 3 GameRound (agregat: 'rotund')
Invarianţi:- Fiecare rotire/rundă are o rundă _ id unică și o sumă de pariu/câștig asociată.
- Fereastra RTP nu depășește pragurile specificate (la nivel de furnizor + reguli locale).
- Rotund. Am început, rotund. Mizat „,” rotund. Rezultat ',' Rotund. Închis ".
3. 4 Bonus (cumulat: 'BonusGrant')
Invarianţi:- Vagerul scade doar din cifra de afaceri valabilă, bonusul nu intră în debit.
- Nu este posibil să scrieți bonusul și fondurile reale în același timp, nu în conformitate cu regula de prioritate.
- "BonusAcordat", "BonusWagered'," BonusExpirat "," BonusConvertit ".
4) Orchestrații, saga și coerență
Sincron (CP): acceptarea pariului și a rezervei de fonduri - într-un singur mod: 'Pariu. Locul „→” portofel. Reserve '(prin intermediul echipei de domeniu/orchestrator cu termen limită).
Asincron (CE): calculul ratei, acumularea bonusului, analiza - prin evenimente + outbox.
Varianta TCC: 'TryReserve' (hold), 'Confirm' (comite),' Anulează '(rollback) pentru efecte monetare.
Idempotence: toate comenzile poartă 'operation _ id', consumatori -' inbox '.
5) Straturi anticorupție (ACL) și integrări
Furnizor ACL: traducerea evenimentelor furnizorului 'SpinResult', 'BonusWin' la intern 'Round. Rezultat „,” BonusWagered'. Schemele și versiunile sunt în interiorul ACL.
PSP ACL: normalizarea statusurilor de plată, idempotența prin 'psp _ tx _ id', transferul la' LedgerEntry '.
Conformitatea ACL: integrarea cu listele de sancțiuni/RAP - într-un context extern; numai „ScreeningUpdated” normalizat intra in domeniu.
Regulă: dicționare externe/formate nu „scurgeri” în nucleu.
6) Proiecții și modele de citire
Profilul jucătorului Citește Modelul: statusuri KYC, limite, bonusuri active, tranzacții proaspete.
Balanțe Citiți modelul: Citește rapid pentru UI/Marketing; sursa - „Wallet” evenimente.
Istoria pariului Citește modelul: Paginare după dată/joc; sursa este „BetPlased/Settled”.
Rapoarte de conformitate - Vizualizări materializate de către chiriaș/regiune.
Toate proiectiile sunt upserts idempotente cu versioning si 'as _ of/prospetime'.
7) Multi-chiriaș și multi-regiune
Toate entitățile cheie poartă "chiriaș _ id' și (dacă este necesar)" regiune ".
Limitele de date: jucător, portofel, pariuri - regiunea „acasă”; numai agregate/rapoarte transregionale.
Corectitudine/cote: limite pe echipe/sec și redistribuie pe chiriași.
Rezidență/conformitate: datele cu caracter personal și tranzacțiile nu părăsesc regiunea.
8) Selectarea consistenței (PACELC) în funcție de context
Portofel/Ledger - Strong/CP: tranzacții liniarizabile, cvorum de înregistrări.
Acceptarea pariului - confirmare sincronă (CP) + modele rapide de citire pentru UI.
Decontare/Bonus/Analytics - CE cu fuziune/compensare deterministă.
KYC/Compliance - poate fi CE pentru statusuri, dar regulile de „blocare” sunt aplicate sincron.
9) Evenimente Domeniu: Contracte și Versiune
Set minim de câmpuri: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"
}
Reguli:
- scheme back/forward-compat; evoluția prin 'schema _ version'.
- „outbox” într-o tranzacție cu modificări de domeniu; publicarea de butches cu backoff.
10) Exemplu de flux „Bet with Bonus” (secvență de cuvinte)
1. Plasează '(echipa) → verificarea limitelor jucătorului și →' Reguli bonus portofel. Rezerva (real + bonus _ equiv, op_id) '
2. 'BetPlased' → Citește actualizările modelului 'Open Wagers'
3. Furnizorul publică rezultatul → Runda ACL a →. Rezultate "
4. Orchestratorul calculează: 'Bet. Soluționare (rezultat, plată) „→” Portofel. Comite (op_id) „și, dacă a câștigat,” BonusWagered' → o posibilă conversie a bonusului în cele reale.
5. „BetSettled” → proiecții de istorie și bilanțuri, raportare.
11) Invarianții și politica de testare
Invarianți cheie:- Suma tuturor „LedgerEntry” din portofel este egală cu soldul; fără reziduuri negative.
- Nu puteți accepta un pariu cu un statut activ de auto-excludere/KYC înghețat.
- Pariul poate doar să scadă și să nu se balanseze „în minus”.
- Decontarea nu modifică statutul ratei deja finalizate - numai prin "Void/Recalc' + tranzacția de compensare.
- Teste bazate pe proprietate ale invarianților și pariurilor pe portofel.
- Contururi de haos: întârzieri furnizor, eșecuri PSP, outbox/DLQ redrive.
- Schema de control: migrații de evenimente, proiecții de rambursare.
12) Telemetrie și audit
Metrici: p95/p99 pe PlaceBet/Reserve/Commit, cota de eșecuri de limite/ACC, rata DLQ, redrive succesul, lag proiecții.
Urmărire: se întinde "komanda→agregat→outbox→konsyumer→proyektsiya", etichete "chiriaș _ id'," operațiune _ id', "saga _ id'.
Audit: un jurnal neschimbător al activităților de domeniu comparabil cu cerințele de reglementare.
13) Schema de stocare (simplificată)
Portofel:
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)
Pariu:
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)
Versionarea pe agregate ('versiune') va proteja împotriva actualizării pierdute în timpul înregistrării competitive.
14) Example Command 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":"..." }
Toate comenzile sunt cu 'operation _ id' pentru idempotency, răspunsurile sunt cu' as _ of '/' version '.
15) Siguranță și conformitate
RLS/ACL: toate cererile - în contextul 'tenant _ id', acces după rol.
PII-minimizare: separarea evenimentelor de domeniu de datele cu caracter personal; mascarea în DLQ/busteni.
Rapoarte de reglementare: proiecții cu semnături hash neschimbătoare în ferestrele de timp.
16) Erori tipice
Conectivitate puternică între contexte (Wallet știe direct Bet/Bonus).
Dual-write în diferite contexte fără sagas/outbox → neconcordanță de echilibre și statusuri.
Lipsa de comandă și idempotența consumatorilor → tranzacții/calcule duplicate.
Fluxul de contracte de furnizor în modelul de domeniu (este mai dificil de a migra).
Un „gigant” agregat (Player include toate) → de blocare, debit redus.
Nu există invarianți evidenți - nu pot fi verificați și monitorizați.
17) Rețete rapide
Start: fixați limbajul omniprezent și limitele contextului; invariante de documente.
Bani: portofel/Ledger - CP, intrări cvorum, TCC pentru efecte externe.
Pariuri: recepție sincronă + calcul asincron, toate prin evenimente și outbox; Idempotenţa este peste tot.
Bonusuri: unitate separată cu prioritate clară și vager.
Integrări: întotdeauna prin intermediul schemelor/versiunilor ACL +; fără sarcini utile „brute” în miez.
Citiri: proiecții/afișări privind nevoile produsului; SLA prospețime + 'as _ of'.
Operare: valori ale invarianților, DLQ/redrave playbooks, reconstrui vitrine.
18) Lista de verificare pre-vânzare
- Contextele delimitate și contractele lor (comenzi/evenimente) sunt definite.
- Agregatele au invarianți expliciți, versiuni și comenzi idempotente.
- Tranzacții monetare - prin TCC/tranzacționalitate strictă; audit activat.
- Integrări - prin ACL-uri cu teste de versiune schemă și evoluție.
- outbox/inbox implementat, DLQ și redesenare sigură.
- Proiecțiile implementează prospețimea SLA, există valori de întârziere/staleness.
- Cotele/limitele multi-chiriașilor și rezidența datelor sunt îndeplinite.
- Observabilitate: urmărirea „komanda→sobytiye→proyektsiya”, alerte de către invarianți.
- Documentație: limbaj de domeniu, diagrame de context, playbook-uri incidente.
Concluzie
DDD în nucleul iGaming este o disciplină de separare a complexității: limite clare de context, agregate cu invarianți, evenimente ca sursă de adevăr, ACL-uri pentru integrări externe și alegeri informate de coerență. Această abordare face platforma scalabilă, fiabilă și conformă cu reglementările, accelerează dezvoltarea caracteristicilor și reduce riscurile operaționale - chiar și cu creșterea rapidă a traficului, a geografiilor și a liniilor de produse.