Skip to main content

KioskGaming — Test Cases cho QC

Phiên bản: 2026-05-10
Nguồn tài liệu: site-documents/docs/
Dành cho: QC Tester
Ký hiệu kết quả: ✅ Pass | ❌ Fail | ⏭ Skip


Mục lục

  1. Kiến trúc & Phân cấp vai trò
  2. Đăng ký Player
  3. Hệ thống Ví (Wallet)
  4. Hệ thống Nạp tiền (Deposit)
  5. Tính phí (Fee Calculation)
  6. Hệ thống Rút tiền (Withdrawal)
  7. Payment Gateway Callbacks
  8. Game Wallet & Sync
  9. Transaction State Machine
  10. Tính năng Xác nhận Crypto khi Rút tiền
  11. Giới hạn Giao dịch & Fraud Flag
  12. Shop USD Wallet — Mua Credit & Rút tiền
  13. API Endpoints & Error Handling

1. Kiến trúc & Phân cấp vai trò

TC-ARCH-001 — Phân cấp tạo tài khoản

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Admin tạo Super AgentĐăng nhập Admin panel → Tạo tài khoản Super AgentTài khoản Super Agent được tạo thành công
2Super Agent tạo AgentĐăng nhập Super Agent portal → Tạo tài khoản AgentTài khoản Agent được tạo thành công
3Agent tạo ShopĐăng nhập Agent portal → Tạo tài khoản ShopTài khoản Shop được tạo thành công
4Shop tạo PlayerĐăng nhập Shop portal → Tạo tài khoản PlayerTài khoản Player được tạo thành công
5Shop không thể tạo AgentĐăng nhập Shop portal → Thử tạo AgentHệ thống từ chối, trả về lỗi phân quyền
6Agent không thể tạo Super AgentĐăng nhập Agent portal → Thử tạo Super AgentHệ thống từ chối, trả về lỗi phân quyền

TC-ARCH-002 — Cô lập phiên đăng nhập theo vai trò

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Shop session không truy cập được API của AgentDùng token của Shop gọi API endpoint dành cho AgentHTTP 403 hoặc 401
2Player session không truy cập được Admin APIDùng token của Player gọi /api/admin/*HTTP 403 hoặc 401

2. Đăng ký Player

TC-REG-001 — Shop tạo Player (Managed Player)

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Shop tạo player thành côngĐăng nhập Shop portal → Tạo player với tên + thông tin đăng nhậpPlayer được tạo, liên kết với Shop
2Player đăng nhập sau khi Shop tạoDùng thông tin Shop cấp để đăng nhập Player Web / kioskĐăng nhập thành công
3Tên player không được để trốngTạo player với tên rỗngValidation lỗi, không tạo được

TC-REG-002 — Player tự đăng ký (Free Player)

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Đăng ký bằng emailTruy cập Player Web → Điền email + thông tin → SubmitTài khoản được tạo, không liên kết Shop
2Đăng ký bằng số điện thoạiTruy cập Player Web → Điền số điện thoại + thông tin → SubmitTài khoản được tạo, không liên kết Shop
3Email đã tồn tạiThử đăng ký với email đã có trong hệ thốngThông báo lỗi "email đã được sử dụng"
4Free player không liên kết ShopKiểm tra DB sau khi self-registershop_id = NULL trên tài khoản vừa tạo

3. Hệ thống Ví (Wallet)

TC-WALLET-001 — Master Wallet

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Mỗi tài khoản có đúng 1 master walletTạo player mới → Kiểm tra bảng walletsCó đúng 1 bản ghi với (owner_type='player', owner_id=<id>)
2Balance ban đầu = 0Tạo tài khoản mới → Kiểm tra balancebalance = 0, reservedBalance = 0
3Wallet status mặc định là activeTạo tài khoản mớistatus = 'active'
4Không thể tạo 2 master wallet cho cùng 1 ownerInsert bản ghi trùng (owner_type, owner_id) vào DBLỗi unique constraint

TC-WALLET-002 — USD Wallet (Shop/Agent)

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Shop có USD walletTạo shop mới → Kiểm tra bảng usd_walletsCó bản ghi USD wallet cho shop
2Player không có USD walletKiểm tra bảng usd_wallets cho playerKhông có bản ghi
3balanceGrossbalanceNet khi shop nhận deposit từ playerThực hiện nạp tiền player → Kiểm tra shop USD walletbalanceGross tăng theo tổng USD, balanceNet = gross − fee

TC-WALLET-003 — Game Wallet (Player)

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Mỗi player có 1 game wallet per game providerPlayer nạp tiền vào game lần đầu → Kiểm tra user_game_walletsCó bản ghi với đúng userId + gameProviderId
2syncStatus ban đầu là never_synced hoặc pendingKiểm tra sau khi tạo game wallet lần đầusyncStatus = 'never_synced' hoặc 'pending'
3walletBalanceinGameBalance khớp sau sync thành côngNạp tiền vào game → Đợi sync hoàn tấtwalletBalance == inGameBalance, syncStatus = 'in_sync'

4. Hệ thống Nạp tiền (Deposit)

TC-DEP-001 — Flow 1: Player nạp online (Wallet-only)

Tiên quyết: Player là free player, không chọn game cụ thể.

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Tạo giao dịch thành côngPlayer chọn số tiền + phương thức → POST /api/payment/depositTrả về { transactionId, paymentUrl, status: 'pending', expiresAt }
2transactionId có format đúng khi tạoKiểm tra transactionId trả vềCó format TEMP_{timestamp}_{userId}
3Trạng thái ban đầu là pendingKiểm tra DB sau khi tạostatus = 'pending'
4Sau khi IPN/callback nhận đượcGiả lập IPN thành công từ gatewayStatus chuyển pending → processing → completed
5Credit vào master wallet sau khi hoàn thànhHoàn tất nạp $10 → Kiểm tra walletbalance += 10 credits
6Không nạp được với player inactiveĐặt status player = inactive → Thử nạp tiềnHTTP 400 "User inactive"
7Không nạp được với số tiền âmPOST deposit với amount = -5HTTP 400 "Invalid amount"
8Không nạp được với số tiền = 0POST deposit với amount = 0HTTP 400 "Invalid amount"

TC-DEP-002 — Flow 1 (phụ): Nạp thẳng vào game (Direct-to-game)

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Chọn game provider khi nạp tiềnPOST deposit với gameProviderId được điềnwalletFlow = 'master_to_game' trên transaction
2Credits đi vào inGameBalance thay vì chỉ master walletHoàn tất nạp $10 trực tiếp vào game → Kiểm tra user_game_walletsinGameBalance += 10
3syncStatus = 'pending' sau khi master wallet được creditKiểm tra sau khi payment completedsyncStatus = 'pending'
4Sau khi game sync thành côngĐợi async sync hoàn tấtsyncStatus = 'completed', walletBalanceinGameBalance khớp
5Game provider không tồn tạiPOST deposit với gameProviderId không có trong DBHTTP 400 "Provider not found"

TC-DEP-003 — Flow 2: Shop Player Deposit (CDN Flow)

Tiên quyết: Player liên kết với Shop.

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Shop đủ credit — Shop wallet bị trừShop có 50 credits, player nạp $10 (10 credits) → Hoàn tấtShop master wallet: −10 credits; Player master wallet: +10 credits
2Shop đủ credit — Shop nhận USDKiểm tra Shop USD wallet sau khi player nạp $10, fee 0%Shop USD wallet: +$10
3Shop đủ credit — Shop nhận USD trừ feeShop nhận deposit với fee 10%, player nạp $10Shop USD wallet: +$9 (trừ $1 fee)
4Player nhận đủ credit dù shop có hay không có creditShop không có credit, player nạp $10Player master wallet: +10 credits
5Shop không nhận USD khi hệ thống coverShop = 0 credits, player nạp $10 → Hoàn tấtShop USD wallet không tăng; hệ thống giữ USD
6Payer cascade khi Shop hết creditShop = 0 credit, Agent có credit → Player nạpAgent wallet bị trừ, Player nhận đủ

TC-DEP-004 — Flow 3: Shop Counter Deposit (Cashier)

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Staff chuyển credit thành côngĐăng nhập Shop portal → "Transfer to Player" → Nhập player + amount → ConfirmShop master wallet: −amount, Player master wallet: +amount
2CashierTransaction được tạoKiểm tra DB sau khi transferCó bản ghi type = 'deposit_credits' trong cashier_transactions
3paymentMethod được lưu đúngThực hiện transfer với paymentMethod = 'cash'cashier_transactions.paymentMethod = 'cash'
4Player không thuộc shop bị từ chốiThử transfer cho player thuộc shop khácLỗi "Player không thuộc shop này"
5Shop inactive không thể thực hiệnĐặt shop status = 'inactive' → Thử cashier depositHTTP 4xx / thông báo lỗi shop không hoạt động

TC-DEP-005 — Flow 4: Multi-Game Deposit

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Nạp $50 phân bổ cho 3 gameTạo deposit với syncMetadata.allocations = [{game1: $20}, {game2: $20}, {game3: $10}] → Hoàn tấtMỗi game wallet được credit đúng số lượng
2multiGameProcessedAt được set sau khi xử lýKiểm tra syncMetadata sau khi hoàn tấtsyncMetadata.multiGameProcessedAt có giá trị ISO timestamp
3Game provider có depositType = 'manual' → vào manual_pendingCó 1 game trong danh sách có depositType = 'manual'allocationResults[i].status = 'manual_pending', tạo manual deposit request
4Idempotency: gọi lại xử lý lần 2Trigger processMultiGameDeposit() lần 2 cho cùng transactionKhông bị credit 2 lần (bị skip vì multiGameProcessedAt đã tồn tại)

TC-DEP-006 — Flow 5: CDN Credit Purchase (Agent/Shop mua credit qua gateway)

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Shop mua credit thành côngShop dùng payment gateway thanh toán $80, costRate=0.80Shop credit wallet: +100 credits
2Tính đúng số credit theo costRatecostRate = 0.80, grossUsd = $80 → creditComputed = 80 / 0.80creditComputed = 100
3USD wallet shop được cộng sau khi muaKiểm tra shop USD wallet sau khi CDN purchase hoàn tấtbalanceGross += 80, balanceNet += 80 − fee
4Xử lý 0x insufficient (partial payment)0x webhook trả về status='insufficient' nhưng receivedUsd ≥ expected × (1 − feeRate)Transaction vẫn được mark completed, xử lý với receivedNetUsd

5. Tính phí (Fee Calculation)

TC-FEE-001 — Deposit Fee Logic

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Player nhận đủ credit không bị trừ feeNạp $10 với feeRate = 10%Player nhận 10 credits (không phải 9)
2Fee trừ vào phần Shop nhậnShop nhận USD sau khi player nạp $10, feeRate=10%Shop nhận $10 − $1 = $9 (USD)
3Tính đúng lợi nhuận shopshopRate=0.80, player nạp $10, fee=10%Shop profit = $9 − ($10 × $0.80) = $9 − $8 = $1
4Fee lookup — Exact matchCấu hình fee cho (provider, 'deposit', methodId)Sử dụng fee rate của exact match
5Fee lookup — Fallback khi không có exact matchKhông có fee cho methodId cụ thể, có fee cho (provider, 'deposit', 'all')Sử dụng fee rate của 'all' fallback
6Fee lookup — Default = 0Không có cấu hình fee nào khớpplatformFeeRate = 0, platformFeeAmount = 0
7Fee rate là snapshot bất biếnTạo transaction, sau đó thay đổi fee configFee trên transaction không thay đổi theo config mới
8Lỗi resolve fee không block giao dịchSimulate lỗi khi resolve fee rateGiao dịch vẫn tiếp tục với feeRate = 0 (non-blocking)

6. Hệ thống Rút tiền (Withdrawal)

TC-WD-001 — Luồng rút tiền cơ bản

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Tạo yêu cầu rút tiền thành côngPlayer submit withdrawal với amount, withdrawalTypePaymentTransaction tạo với status = 'pending', reservedBalance += amount
2Credit bị lock khi pendingKiểm tra master wallet sau khi submitreservedBalance += amount, balance không thay đổi
3Admin approve → chuyển sang processingAdmin duyệt withdrawalStatus: pending → approved → processing
4Admin approve → Payout adapter được gọiSau khi admin approvePayout adapter (LinkMePay/BTCPay/0x) nhận lệnh chuyển tiền
5Hoàn tất — wallet bị trừ, status completedPayout thành côngStatus → completed, balance −= amount, reservedBalance −= amount
6Admin reject — reserved balance được giải phóngAdmin từ chối withdrawalStatus → rejected, reservedBalance −= amount (credits trả lại)
7Tính phí rút tiền đúngRút $100 với platformFeeRate = 2%grossUsd = 100, platformFeeAmount = $2, netPayoutUsd = $98
8Pending timeout → auto-rejectĐể giao dịch pending quá timeoutHệ thống tự chuyển sang rejected, credits được giải phóng

TC-WD-002 — Phương thức rút tiền

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Rút qua bank transfer (LinkMePay)withdrawalType = 'bank_transfer'Gọi LinkMePay payout adapter
2Rút qua Bitcoin (BTCPay)withdrawalType = 'bitcoin_transfer'Gọi BTCPay withdrawal adapter
3Rút qua USDT (0x Processing)withdrawalType = 'zerox_usdt'Gọi 0xProcessing withdrawal adapter

7. Payment Gateway Callbacks

TC-CALLBACK-001 — LinkMePay IPN

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1IPN với HMAC hợp lệ được xử lýGửi POST tới /api/payment/linkmepay/ipn/:id với signature đúngRaw payload lưu vào CallbackLog, transaction được cập nhật
2IPN với HMAC sai bị từ chốiGửi IPN với signature không đúngHTTP 403
3ALLOW_UNVERIFIED_LINKMEPAY_CALLBACKS=true bypass signatureBật env var, gửi IPN không có signatureIPN được xử lý (không bị từ chối)
4IPN thành công → processCompletedDepositGửi IPN với status=success hoặc state=2Gọi processCompletedDeposit(), credit wallet
5IPN thất bại (state=3)Gửi IPN với state=3Transaction chuyển sang failed

TC-CALLBACK-002 — 0x Processing Webhook

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Webhook deposit (status='success')Gửi webhook 0x với status='success'Transaction → completed, credit wallet
2Webhook status='insufficient' đủ thresholdGửi webhook với status='insufficient', receivedUsd ≥ expected × (1 − feeRate)Transaction được mark completed, syncMetadata.receivedNetUsd lưu giá trị nhận được
3Webhook status='insufficient' không đủ thresholdreceivedUsd < expected × (1 − feeRate)Transaction không được settle, bị skip
4Webhook withdrawal (has ID + Address)Gửi webhook với ID + AddressXử lý như withdrawal callback
5Webhook CDN static wallet (ClientId starts with 'shop:')Gửi webhook với ClientId = 'shop:xxx'Xử lý như CDN static wallet

TC-CALLBACK-003 — BTCPay Webhook

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Webhook với signature hợp lệGửi webhook với HMAC đúng trong header btcpay-sigĐược xử lý
2Webhook không có signature (khi secret đã cấu hình)Gửi webhook không có header btcpay-sigHTTP 401
3BTCPay invoice settled → processCompletedDepositGửi webhook event InvoiceSettledGọi processCompletedDeposit(), credit wallet

8. Game Wallet & Sync

TC-GAMEWALLET-001 — Sync quy trình 2 transaction

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Txn 1: lock + set status processingTheo dõi DB khi sync bắt đầuGameWalletTransaction.status = 'processing'
2External API call thành công → Txn 2 hoàn tấtGame API trả về thành côngstatus = 'completed', walletBalance được trừ đúng
3External API call thất bạiSimulate game API lỗiGameWalletTransaction → 'failed' trong transaction riêng
4Balance thay đổi giữa Txn 1 và Txn 2 → rejectThay đổi balance giữa 2 transaction DBTxn 2 phát hiện bất nhất → không commit
5Idempotency khi gọi lại syncTrigger sync 2 lần cho cùng transactionChỉ credit 1 lần (lần 2 bị bỏ qua)

TC-GAMEWALLET-002 — syncStatus flow

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Wallet-only deposit có syncStatus = 'none'Thực hiện deposit không chọn gamesyncStatus = 'none'
2Direct-to-game: pending → in_progress → completedThực hiện direct-to-game deposit và sync thành côngsyncStatus lần lượt = pendingin_progresscompleted
3Retry khi syncStatus = 'failed'Sync thất bại → Worker retryretryCount tăng lên, nextRetryAt được set

9. Transaction State Machine

TC-SM-001 — Deposit state transitions

#Chuyển trạng tháiThực hiệnKết quả mong đợiKết quả thực tế
1pending → processingGateway trả về đang xử lýCho phép
2processing → completedGateway xác nhận thành côngCho phép
3processing → failedGateway báo lỗiCho phép
4processing → expiredQuá DEPOSIT_TIMEOUT_MSCho phép
5processing → cancelledUser/admin cancelCho phép
6awaiting_admin → completedAdmin duyệt manual game depositCho phép
7awaiting_admin → rejectedAdmin từ chốiCho phép
8completed → pending (không hợp lệ)Thử đảo ngược trạng tháiHTTP 409 — Transition not allowed, wallet không bị thay đổi
9failed → completed (không hợp lệ)Thử chuyển từ failed sang completed trực tiếpHTTP 409 — Transition not allowed

TC-SM-002 — Withdrawal state transitions

#Chuyển trạng tháiThực hiệnKết quả mong đợiKết quả thực tế
1pending → approvedAdmin approveCho phép
2approved → processingGọi payout adapterCho phép
3processing → completedPayout thành côngCho phép
4pending → rejectedAdmin rejectCho phép
5completed → pending (không hợp lệ)Thử đảo ngượcHTTP 409 — không cho phép
6approved → rejected (không hợp lệ)Thử skip stepHTTP 409 — không cho phép (phải qua processing)

10. Tính năng Xác nhận Crypto khi Rút tiền

Tính năng mới: Hiển thị số crypto ước tính trước khi player xác nhận rút tiền.

TC-CRYPTO-001 — API Endpoint /api/payment/crypto-estimate

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Estimate cho BTC (BTCPay)GET /api/payment/crypto-estimate?withdrawalType=bitcoin_transfer&netUsd=98Trả về { coin: 'BTC', provider: 'btcpay', estimatedCryptoAmount, rateUsd, source: 'btcpay_rates_api' }
2Estimate cho LTC (BTCPay)withdrawalType=litecoin_transfer&netUsd=98Trả về coin: 'LTC', estimate tương ứng
3Estimate cho DOGE (BTCPay)withdrawalType=dogecoin_transfer&netUsd=98Trả về coin: 'DOGE', estimate tương ứng
4Estimate cho USDT (0xProcessing)withdrawalType=zerox_usdt&netUsd=98Trả về { coin: 'USDT', provider: 'zeroxprocessing', estimatedCryptoAmount ≈ 98, rateUsd ≈ 1 }
5Estimate cho ETH (0xProcessing)withdrawalType=zerox_eth&netUsd=98Trả về coin: 'ETH', estimate theo tỉ giá hiện tại
6Thiếu tham số withdrawalTypeGọi API không có withdrawalTypeHTTP 400 / validation error
7Thiếu tham số netUsdGọi API không có netUsdHTTP 400 / validation error
8netUsd = 0netUsd=0Skip fetch, không tính estimate (hoặc trả về 0)
9Coin không tồn tại trong 0xwithdrawalType=zerox_fakecoinHTTP 422 với reason: 'coin_not_supported'
10Không có player authGọi không có tokenHTTP 401
11fetchedAt là ISO-8601Kiểm tra responsefetchedAt có format YYYY-MM-DDTHH:mm:ss.sssZ

TC-CRYPTO-002 — Hiển thị modal (Frontend)

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Modal BTC hiển thị ước tính với prefix Rút tiền BTC → Mở confirm modalHiển thị ≈ 0.00101234 BTC
2Modal BTC hiển thị rateXem modal BTCHiển thị Rate: 1 BTC = $XX,XXX.XX (live estimate)
3USDT hiển thị note stablecoinRút tiền USDT → Mở modalHiển thị 1 USDT ≈ $1.00 — stablecoin
4Địa chỉ ví được maskĐịa chỉ dài → Hiển thị trong modalHiển thị dạng bc1q...a7fg (6 ký tự đầu + ... + 4 ký tự cuối)
5Disclaimer của BTCPay đúng nội dungKiểm tra modal BTCCó text "Final amount determined by BTCPay at payout time"
6Disclaimer của 0xProcessing đúng nội dungKiểm tra modal USDTCó text "Final amount confirmed by 0xProcessing at payout time"
7Bank transfer không hiển thị crypto sectionChọn bank_transfer → Mở modalKhông có section "Estimated crypto payout"
8BTC decimal precision: 8 chữ sốKiểm tra hiển thị BTC0.00101234 (8 chữ số thập phân)
9DOGE decimal precision: 2 chữ sốKiểm tra hiển thị DOGEXX.XX DOGE (2 chữ số thập phân)
10USDT decimal precision: 2 chữ sốKiểm tra hiển thị USDT98.00 USDT (2 chữ số thập phân)

TC-CRYPTO-003 — Edge cases

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Estimate API timeout → modal vẫn mở đượcSimulate API timeoutModal mở không có crypto section; player vẫn submit được
2Estimate API lỗi → modal vẫn mở đượcSimulate API 500Modal mở không có crypto section; không block submit
3Modal mở > 2 phút — badge "Rate may be stale"Để modal mở hơn 2 phútXuất hiện badge cảnh báo "Rate may be stale — close and reopen to refresh"
4Rate không tự động refreshĐợi > 2 phút trong modalRate không tự động cập nhật (tránh race condition)
5BTCPay testnet — label (testnet)Dùng môi trường testnetHiển thị thêm (testnet) bên cạnh coin symbol

TC-CRYPTO-004 — Snapshot lưu trong transaction

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Snapshot được lưu vào metadataSubmit withdrawal với cryptoEstimateSnapshottransaction.metadata.cryptoEstimateSnapshot có đủ các field
2Snapshot không ảnh hưởng tính toán backendGửi snapshot sai tỉ giáPayout amount vẫn được tính từ netPayoutUsd theo thời gian thực
3Bank transfer — không có snapshotSubmit bank_transfer withdrawalmetadata.cryptoEstimateSnapshot = null
4Snapshot chứa đúng fieldKiểm tra DB{ coin, rateUsd, estimatedCryptoAmount, source, fetchedAt }

11. Giới hạn Giao dịch & Fraud Flag

TC-LIMIT-001 — Transaction Limits

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Vượt giới hạn deposit tối đa per transactionCấu hình max $500/tx → Thử nạp $600Bị từ chối, thông báo vượt giới hạn
2Vượt giới hạn deposit hàng ngàyCấu hình max $1000/ngày → Nạp tổng >$1000 trong ngàyGiao dịch bị từ chối
3Vượt giới hạn số lượt deposit per giờCấu hình max 5 deposits/giờ → Thực hiện lượt 6 trong cùng giờBị từ chối, rate limit

TC-LIMIT-002 — Fraud Flags

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Giao dịch đáng ngờ bị flagThực hiện giao dịch vượt ngưỡng fraudFlagsGiao dịch được tạo bản ghi trong transaction_fraud_flags
2Admin có thể xem fraud flagsĐăng nhập Admin panel → Kiểm tra fraud flagsHiển thị danh sách giao dịch bị flag

12. Shop USD Wallet — Mua Credit & Rút tiền

TC-SHOP-001 — Mua credit từ USD wallet

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Shop mua 100 credits với costRate=0.80Shop USD wallet = $100, mua 100 creditsUSD wallet: −$80, Credit wallet: +100
2Shop không đủ USD → bị từ chốiUSD wallet = $50, thử mua 100 credits ($80)Lỗi không đủ số dư
3Số dư USD còn lại đúng sau muaSau bước 1USD wallet balance = $20
4costRate được áp dụng đúngMua với costRate khác nhauCredits = USD / costRate

TC-SHOP-002 — Shop rút tiền USD

#Mô tảBước thực hiệnKết quả mong đợiKết quả thực tế
1Shop tạo yêu cầu rút USDShop submit withdrawal từ USD walletTạo PaymentTransaction { type: 'withdrawal' }
2Quy trình duyệt giống player withdrawalAdmin approve, payout adapter được gọiCùng flow: pending → approved → processing → completed

13. API Endpoints & Error Handling

TC-API-001 — Player-facing Endpoints

#EndpointTestKết quả mong đợiKết quả thực tế
1POST /api/payment/depositKhông có authHTTP 401
2GET /api/payment/deposit-historyPlayer có authTrả về danh sách transactions của player đó
3GET /api/payment/balancePlayer có authTrả về { balance, reservedBalance }
4GET /api/payment/supported-methodsPlayer có authTrả về danh sách phương thức thanh toán đang hoạt động
5GET /api/payment/provider-fee-ratePlayer có auth, provider hợp lệTrả về fee rate
6GET /api/payment/zeroxprocessing/coinsPlayer có authTrả về danh sách coin 0x hỗ trợ
7GET /api/payment/reserved-balance-detailPlayer có authTrả về chi tiết reserved balance

TC-API-002 — Shop-facing Endpoints

#EndpointTestKết quả mong đợiKết quả thực tế
1POST /api/shop/depositsShop auth, player thuộc shopCredits được chuyển thành công
2POST /api/shop/depositsShop auth, player không thuộc shopHTTP 400/403
3GET /api/shop/depositsShop authTrả về lịch sử deposits của shop

TC-API-003 — Error Responses

#Mô tảKích hoạtHTTP StatusMessage mong đợi
1User inactiveDeposit với user status inactive400"User inactive"
2Invalid amountAmount = 0 hoặc âm400"Invalid amount"
3Unknown game providergameProviderId không tồn tại400"Provider not found"
4Payment adapter failureGateway down500"Gateway error"
5Webhook signature invalidHMAC sai403"Signature mismatch"
6Invalid state transitionChuyển trạng thái không hợp lệ409"Transition not allowed"

Tổng hợp Test Cases

ModuleSố TCGhi chú
Kiến trúc & Vai trò8
Đăng ký Player7
Hệ thống Ví9
Nạp tiền (5 flows)27Flow CDN, cashier, multi-game, direct-to-game
Tính phí8
Rút tiền10
Callbacks (3 gateways)13LinkMePay, 0x, BTCPay
Game Wallet & Sync8
State Machine11
Xác nhận Crypto (tính năng mới)26API + UI + edge cases + snapshot
Giới hạn & Fraud5
Shop USD Wallet6
API Endpoints16
Tổng154

Tài liệu được tạo từ site-documents/docs/ — phiên bản 2026-05-10