Balans i portfele: architektura wielopaletowa
1) Dlaczego multi-portfel i jakie cele
Jeden wpis „balance = number” nie obejmuje rzeczywistości iGaming. Potrzebne są oddzielne portfele/subkontyngenty: prawdziwe pieniądze (gotówka), fundusze bonusowe, pula zakładów, freespins, punkty komputerowe, czasami portfele walutowe (EUR/USD/BRL).
Cele architektury to:- Dokładność pieniędzy (podwójne wejście, możliwość audytu).
- Zasady umorzenia (na przykład najpierw bonus/vager, a następnie gotówka).
- Prędkość (p95 API ≤ 250-400 ms, zakład/rozrachunek w czasie rzeczywistym).
- Bezpieczeństwo i zgodność (KYC/AML, granice odpowiedzialności, regulatory).
- Skala: szczyty → dziesiątki tysięcy operacji/s, miliardy postów/miesiąc.
2) Model danych: „Księga + portfele”
Minimalne jednostki
Konto: gracz/marka/rynek.
Przykład tabel (uproszczony)
sql
-- Rachunki bilansowe dotyczące podwójnego wpisu (w tym działalności gospodarczej)
rachunki (id, owner_user_id, rodzaj, waluta, status,...)
-- Delegowanie (podwójny wpis, odniesienie do transakcji biznesowych)
ledger_entries (id, posting_id, debit_account_id, credit_account_id, amount_minor, waluta, kategoria, operation_id, created_at)
-- Posiadania (rezerwy)
posiadacze (id, account_id, amount_minor, waluta, powód, expires_at, stan, operation_id, created_at)
-- Polityka umorzeń (priorytety)
spend_policies (id, market, wallet_priority jsonb, updated_at)
-- fx_rates kursów wymiany (ccy_from, ccy_to, kurs, precyzja, valid_from)Zasada: Prawda żyje w dzienniku transakcji („ledger _ entries”). Bieżące saldo jest albo agregatem (zmaterializowanym migawką), albo jest obliczane z dziennika (drogie, ale tylko prawdziwe).
3) Rodzaje portfeli i ich zachowanie
4) Polityka umorzeń i porządek priorytetowy
Wyraźnie sformalizować algorytm dla źródła funduszy: Przykład (sloty/kasyna):1. Po pierwsze, odpis z WAGER (jeśli zakład jest aktywny).
2. Następnie od BONUS do wyczerpania.
3. Pozostała część pochodzi z CASH.
Przykład (sport):1. Pierwszy CASH (regulator/podatek).
2. Następnie BONUS (freebet), tłumacząc na WAGER.
Zapisz „decyzję o polityce” jako atrybut w Postings, tak aby wsparcie i audyt zobaczyć „dlaczego to spisali”.
5) Cykl życia pieniędzy i operacji
Depozyt
1. „POST/wallet/deposit” → utwórz oczekujący wpis (skrzynka odbiorcza kiełbasy PSP).
2. Webhook PSP (podpis HMAC, idempotence by 'operation _ id') → credit CASH, kategoria =' DEPOSIT '.
3. Publikujemy wydarzenie 'wallet _ updated'.
Stawka
1. „POST/bet/place” → utworzyć blokadę (rezerwę) na rachunku źródłowym (CASH/BONUS/WAGER).
2. Przy potwierdzeniu kursu, przelew blokady → źródło debetowe, kredyt z konta usługi „rozrachunek” dostawcy jest →.
3. Po anulowaniu - zwolnienie blokady.
Rozrachunek (wynik)
Zyski: obciążenie rachunku „rozliczeniowego” dostawcy → kredyt GOTÓWKA lub polityka WAGER → BONUS → GOTÓWKA.
Strata: zamknąć „koszt” dostawcy transakcją → bez kredytów dla gracza.
1. KYC/AML sprawdzić, odpowiedzialne grać limity.
2. Zatrzymaj kwotę wypłaty.
3. Sukces PSP → ostateczny debet CASH → rachunek kredytowy „płatność”.
4. PSP → zwolnienie blokady nie powiodło się.
6) Idempotencja i dokładnie raz „w rozumieniu”
Wszędzie 'operation _ id' (UUID/enhanced ULID) z unikalnym indeksem. Ponowne żądanie → status wcześniejszej transakcji.
PSP/dostawca gier haki internetowe: Tabela skrzynki odbiorczej z dedupe przez 'event _ id + signature'. Przetwarzanie - pracownik idempotent (wzorzec Outbox).
Idempotence-Key na HTTP dla klienta; Przechowywać TTL ≥ 24-72 godziny.
7) Rezerwy i posiadania
Hold nie jest odpisem, ale „zamrożeniem” dostępnego salda.
Zasady:- Trzymaj żywotność: sekundy → minuty (szybkość) lub godziny (wyjście).
- Ładownia może być częściowo lub całkowicie wygaszona (częściowa osada).
- Po wygaśnięciu - automatyczne zwolnienie i zdarzenie.
- Zachowaj relację 'hold _ id' z' bet _ id/withdraw _ id'.
8) Waluty, waluty i zaokrąglanie
Kwoty pieniężne - w jednostkach mniejszych (centów), typ - liczba całkowita.
Zaokrąglanie bankowe (okrągłe do połowy) lub przez T & C.
FX: „CASH (EUR)” i „CASH (USD)” lepiej jest podzielić portfele. Konwertuj jako oddzielna operacja:- "ebit EUR, FX_EURUSD' kredytowe i" debit FX_EURUSD, USD kredytu "- przejrzysty do audytu.
- Zabrania się automatycznego „sięgania” do kursu w sporze; wszystkie zasady są w polityce FX.
9) Odpowiedzialna zabawa i ograniczenia
Depozyt/Zakład/Strata/Limity sesji (dzień/tydzień/miesiąc), chłodzenie, wykluczenie.
Zaimplementowany jako pre-check przed hold/debit.
Dzienniki awarii - w oddzielnym dzienniku audytu, dostępnym dla wsparcia i regulatora.
10) Sygnały przeciwko oszustwom wokół portfela
Klastry urządzeń/ASN, częste małe depozyty → duże wypłaty, wzory mycia.
Ograniczenia prędkości „depozytu/wewnątrz” przez BIN/kraj/urządzenie.
Listy bloków dla odbiorców (portfele/IBAN), lista „mułów”.
Zdarzenia portfelowe → w sklepie z punktacją (login/deposit/rate).
11) Spójność i wydajność
True vs cache
Prawda jest w księdze. Dla API „get balance” należy zachować zmaterializowaną migawkę ('user _ id + wallet _ type → balance_minor, version').
Napisz: transakcja w bazie → unieważnienie pamięci podręcznej.
W „ciężkim” przepływie (live), short-TTL 1-5 s + obowiązkowa kontrola prawdy przed wycofaniem/duży zakład jest odpowiedni.
Skalowanie
Shading przez 'user _ id' (moduł/ranking), oddzielne baseny shard dla CASH vs BONUS.
Klucze gorące (VIP/boty) - żądanie koalescencji przez 'user _ id'.
Asynchroniczne agregacje (komponować 'posting' → „snapshot-update” w tle).
12) Umowy API (pseudo)
Saldo
http
GET/v1/portfele? rodzaje = GOTÓWKA, BONUS
→ 200 {„portfele”: [
{„typ „: „CASH „, „currency „: „EUR „, „available”: 12050,” hold”: 500,” version”: 1942}, {„type „: „BONUS „, „currency „: „EUR „, „available”: 3000,” wager _ req”: 15000}
]}Zakład (z przytrzymaniem)
http
POST/v1/zakłady/miejsce
{„bet _ id':” b _ 123 „,” kwota „: 500,” waluta „:” EUR „,” source _ policy „:” casino _ default „,” idempotency_key":"ik_abc"}
→ 201 {"status": "HELD", "hold _ id':" h _ 789 "," expires _ in ": 30}Rozrachunek
http
POST/v1/zakłady/rozrachunek
{"bet _ id':" b _ 123 "," result ":" WIN "," payout ": 1250}
→ 200 {„status „: „SETTLED „,” cash _ delta”: + 1250}http
POST/v1/wypłaty
{„wycofać _ id':” w _ 456 „,” kwota „: 10000,” waluta „:” EUR „,” metoda „:” sepa „,” idempotency_key":"ik_def"}
→ 202 {"state": "PENDING", "next _ check _ sec": 2, "status _ url': "/v1/withdrawals/w _ 456"}13) Przykłady delegowania (podwójny wpis)
Depozyt €100 (opłata PSP €1, przecinek. konto - oddzielne)
Obciążenie: PSP_Settlements (EUR) 10000
Kredyt: Użytkownik. GOTÓWKA (EUR) 10000
Debet: Użytkownik. GOTÓWKA (EUR) 100 (zmiana opłaty)
Kredyt: PSP_Fees (EUR) 100Zakład €5 z BONUS (przeniesienie do WAGER)
Debet: Użytkownik. BONUS (EUR) 500
Kredyt: Użytkownik. WAGER (EUR) 500 (przejście na zakład)
Debet: Użytkownik. ZAKŁAD (EUR) 500
Kredyt: Dostawca. Rozliczenie (EUR) 500 (odpisana stawka)Wygraj 12 €. 5 → w gotówce
Debet: Dostawca. Rozliczenie (EUR) 1250
Kredyt: Użytkownik. GOTÓWKA (EUR) 1250Wstrzymaj umorzenie (realizacja za pośrednictwem rachunku usług HOLD)
Debet: Użytkownik. ŚRODKI PIENIĘŻNE (EUR) 500
Kredyt: Użytkownik. HOLD (EUR) 500 (utworzony przez holding)
-- na osiedlu
Debet: Użytkownik. HOLD (EUR) 500
Kredyt: Dostawca. Rozliczenie (EUR) 500
-- w sprawie anulowania
Debet: Użytkownik. HOLD (EUR) 500
Kredyt: Użytkownik. ŚRODKI PIENIĘŻNE (EUR) 50014) Audyt, niezmienność i zgodność
WORM/immunitet dla dziennika (przechowywanie obiektów/archiwum WAL).
Dostęp do meta-logów: którzy odczytują/zmieniają limity, którzy dokonali ręcznych korekt (tylko poprzez „regulację-delegowanie” z uzasadnieniem).
RODO/organy regulacyjne: przechowywanie transakcji przez 5-10 lat (według jurysdykcji), przejrzystość rozliczeń dla gracza (historia umorzeń/zakładów).
15) Tolerancja błędów i DR
Multi-AZ obowiązkowe; DR-region dla portfela: synchronizacja w strefie, async - do regionu; PITR jest włączony.
Promuj czuwanie - tylko ręcznie za pomocą listy kontrolnej (wyklucz podział-mózg).
Co tydzień przywracaj kontrolę (test-restore), uzgadnianie ilości raportów kontrolnych.
16) Obserwowalność portfela
SLI: „deposit _ success _ ratio”, „withdraw _ success _ ratio”, „bet _ hold _ latency _ p95”, „settlement _ latency _ p95”.
Теz: 'ledger _ postings _ rate', 'db _ connections _ saturation', 'queue _ lag _ seconds', 'hold _ expired _ rate'.
Alerts: spadek sukcesu PSP na rynku, wzrost „hold _ expired _ rate”, dostawca gier poza synchronizacją (brak potwierdzeń> N min).
17) Badania i kontrola jakości
Testy kontraktowe z dostawcami PSP/gier (haki/podpisy).
Testy majątkowe pieniądza: suma debetów = = suma kredytów w każdym delegowaniu.
Fuzz/chaos: opóźnienia PSP/dostawcy, powtórzenia haków internetowych, klapy sieciowe.
Obciążenie: zakłady wybuchowe (60-120 s), moczenie (4-8 h), sterowanie „kolejka _ lag” i p99.
18) Lista kontrolna gotowości do produkcji
- Podwójny wpis w księdze rejestracyjnej, wszystkie operacje za pośrednictwem Posting z 'operation _ id'.
- Jasna polityka wydatkowania i porządek priorytetowy (utrzymuje się wraz z delegowaniem).
- Trzyma z TTL/częściowe rozliczenie/wygaśnięcie, komunikacja z zakładu/wycofać.
- Skrzynka odbiorcza/Outbox, haki internetowe HMAC, idempotencja na wszystkich granicach.
- Portfele indywidualne CASH/BONUS/WAGER/FS/POINTS; podzielone według walut.
- FX i zaokrąglanie drobne; konwersja - oddzielna operacja.
- Granice odpowiedzialnego grania do przechowywania/debetowania; audyt awaryjny.
- Przeczytaj pamięć podręczną (short TTL) + wymagane sprawdzanie prawdy przed krytycznymi działaniami.
- PITR/kopie zapasowe/skrypty DR; instrukcja obsługi, regularne ćwiczenia DR.
- Deski rozdzielcze/alerty SLI + techniczne; Dzienniki WORM i dzienniki dostępu.
- Badania obciążenia/chaosu; raporty dotyczące uzgodnień z PSP/dostawcami.
Wznów streszczenie
Architektura wielopaletowa nie jest „wieloma liczbami bilansu”, ale systemem finansowym z podwójnym wejściem, polityką wydatków, rezerwacją i przejrzystym szlakiem dla audytorów i graczy. Zachowaj prawdę w dzienniku, użyj ładowni i idempotencji, oddzielne portfele i waluty, zautomatyzuj pojednanie i DR. Dzięki temu portfel będzie szybki dla UX, dokładny dla pieniędzy i odporny na obciążenia szczytowe i kontrole regulacyjne.
