/work Systems
Real-Money Gaming Backend
Backend systems for real-money gaming (Ludo + cards) — transaction integrity, fairness, anti-cheat, regulatory considerations.
Scope
Game-state and transaction systems where every balance-changing action must be explainable
Owned
- Transactional integrity and idempotency
- Game-state and wallet boundaries
- Fairness, anti-cheat, and audit surfaces
Constraints
- Retries must never duplicate a monetary effect
- Game outcomes and wallet movements need durable traceability
- Untrusted clients cannot own authoritative state
Decisions
- Append-only ledger as the source of financial truth
- Idempotency keys around every balance-changing command
- Separate game simulation from wallet settlement
Outcome
- Operated real-money game flows with auditable transaction boundaries
Volumes, providers, and security controls are intentionally omitted.
Case study narrative
Why the boundary matters
A real-money game joins two systems with different semantics. The game engine reasons about turns, timeouts, moves, and outcomes. The wallet reasons about immutable entries, balances, settlement, and reconciliation. Combining them into one mutable state object makes failures difficult to explain and retries dangerous.
The architecture separates game authority from monetary authority and connects them through idempotent commands and durable events.
System architecture
Game state and monetary state
- Untrusted client Submits signed intent; never submits an authoritative outcome Trust boundary
- Game service Validates membership, turn, rules, and server-owned state Game authority
- Outcome service Finalizes a result once and emits a durable settlement command Finality boundary
- Wallet service Applies idempotent debit and credit entries Money authority
- Ledger Append-only entries with references and reconciliation state Source of truth
- Audit/operations Explains a game, command, and balance movement end to end Evidence boundary
Idempotent settlement
Networks retry. Workers restart. Clients repeat actions. The settlement path must treat duplication as a normal input rather than a rare bug. Every balance-changing command carries a stable key derived from the business event, not from an individual HTTP request.
type SettlementCommand = {
idempotencyKey: string; // game:{gameId}:settlement:v1
gameId: string;
resultVersion: number;
entries: Array<{ accountId: string; direction: "DEBIT" | "CREDIT"; amount: Money }>;
};
// Illustrative only — transaction details are simplified.
async function settle(command: SettlementCommand) {
return database.transaction(async (tx) => {
const existing = await tx.settlements.find(command.idempotencyKey);
if (existing) return existing.result;
assertBalanced(command.entries);
const result = await tx.ledger.append(command.entries);
await tx.settlements.record(command.idempotencyKey, result);
return result;
});
}
The ledger entries must balance and the idempotency record must be committed atomically with them. A retry returns the original result without creating a second financial effect.
Request sequence
Game completion and settlement
- 01 Game servicefinalizes outcome
Persists a server-authoritative result with an immutable result version.
- 02 Outcome servicecreates settlement command
Builds balanced entries and a stable idempotency key.
- 03 Walletchecks prior execution
Returns the existing result if this business command already succeeded.
- 04 Ledgerappends entries
Commits debit and credit records without mutating historical entries.
- 05 Reconcilermatches result and money
Flags missing, duplicate, or mismatched references for operations.
Fairness and anti-cheat surfaces
Fairness is a chain of custody. Randomness must be generated or verified on trusted infrastructure, game rules must be deterministic for the same authoritative inputs, and the server must reject client state that attempts to skip valid transitions.
Anti-cheat design focuses on signals rather than a single detector:
- Impossible action sequences or timing.
- Client state inconsistent with the authoritative version.
- Repeated disconnect patterns around unfavorable outcomes.
- Device or account relationships that require risk review.
- Result distributions that diverge from expected game behavior.
The enforcement path should be separate from the signal path. Signals can be collected and scored without allowing one noisy rule to directly seize funds or permanently block a player.
Tradeoff matrix
Financial source of truth
| Option | Strengths | Costs | Decision |
|---|---|---|---|
| Mutable balance only | Simple reads and minimal storage | Weak auditability and difficult reconciliation | Rejected |
| Append-only ledger + balance projectionChosen | Traceable entries, replay, reconciliation, and explicit correction | More operational and consistency work | Selected |
| Game record as wallet truth | One domain record | Couples money to game lifecycle and retry semantics | Rejected across the boundary |
Audit and failure recovery
An operator should be able to start from a user-visible complaint and follow references through game, outcome, settlement command, ledger entries, and reconciliation status. Correlation identifiers are domain identifiers—game ID, result version, settlement key, ledger entry IDs—not just infrastructure trace IDs.
Corrections are compensating entries, never edits to history. If an outcome is overturned, the system records why, who authorized it, the original references, and the new entries. This preserves both the financial state and the explanation.
Representative failure handling includes:
- Outcome persisted but command publication delayed: recover from an outbox or reconciliation scan.
- Wallet applied but response lost: retry returns the existing idempotent result.
- Invalid unbalanced command: reject before writing any entries.
- Game and settlement disagree: quarantine for review instead of guessing.
- Downstream reporting delayed: replay from the ledger without changing balances.
Outcome and lessons
The system supported real-money game operations with explicit transaction, fairness, and audit boundaries. Public details are intentionally limited to architecture and engineering decisions.
Bounded proof
Operational guarantees
- Retries
- One effect
- Audit
- End-to-end
- Correction
- Append-only
Stable idempotency keys prevent duplicate balance changes.
Game results and ledger entries share durable business references.
Compensating entries preserve the original financial history.
The most durable lesson was that “exactly once” is not a transport feature. It is a business invariant assembled from stable identities, atomic writes, durable evidence, and safe retries.
Want to discuss this work in more detail? Get in touch.
Back to all work