Skip to content

Concepts

These six ideas are the whole mental model behind CGSP. Read them once; refer back as needed. With them, the rest of the docs make sense.

Cloud1x2 splits the world in two.

  • Platform — Launcher + Wallet API + Back Office + Ledger, all on one Postgres database (cloud1x2_platform). Owned by the platform. A game service developer writes no code here.
  • Game Service — one process per game (or per family of game variants). It owns its own datastore. The game logic, the bet rows, the per-round state all belong to the service.

The boundary is HTTP-only. A game service never reads a platform table directly, and the platform never reads a service table. Every cross-side data flow goes over HTTP.

Why so strict? Three reasons:

  1. Independence — a service deploys, scales, fails, and recovers without coordinating with the platform database.
  2. Stability — the platform can refactor its internal schema freely; nothing in the service breaks, because the service depends only on the HTTP contract.
  3. Isolation — fifty services on one platform, none able to reach another’s data.

Three layers, all owned by the platform and exposed to the service over the protocol.

LayerWhat it isWhere it lives
EngineA running state machine producing rounds. One process can host many engines.The game service (in memory)
Runtime ProfileConfig describing how an engine behaves: RTP, max multiplier, bot count, round wait, plus an engine-specific opaque config_json.Platform DB
SkinVisual style + localized strings, scoped per game/operator.Service DB (assets), platform DB (translator assignments)

Bucketing rule: multiple games rows that share the same runtime_profile_id share one engine instance at runtime. The platform calls this a “bucket.” Players on different skins of the same bucket sit in the same round — the platform decides the bucketing, the service does not compute it.

Every engine has a deterministic identity, so the platform and the service always converge on the same string for the same logical engine — even after a restart:

engineId = "{service_uid}:{bucketKey}"
bucketKey = "p:{runtimeProfileId}" // preferred
| "g:{gameExternalId}" // when no profile exists

For example wp9dvdgp4wfqmxq4:p:42.

Every bet a service mints has a unique ID with a fixed shape:

{service_uid}-{ulid}
16 1 26
  • service_uid — 16-char Crockford Base32, assigned to the service at creation time. The platform sends it in the desired-state payload. Immutable.
  • ulid — a standard 26-character ULID (48-bit ms timestamp + 80-bit randomness), lowercase. The service mints one per bet.
  • - — a single separator.

Total: 43 characters, self-identifying — the prefix names the owning service. It is the idempotency key when the ledger entry is written: re-posting the same (engineType, serviceBetUid) pair is a no-op. The service mints bet IDs through the shared helper and never invents its own format. See Bet UID Format.

CGSP is exactly four surfaces. Knowing which side calls which removes most of the confusion.

flowchart TB
subgraph Platform[Cloud1x2 Platform]
direction LR
CP[Control Plane API]
CL[Config + Ledger API]
WAPI[Wallet API]
VL[Verify-Launch API]
end
subgraph Service[Game Service]
direction LR
CPS[Control Plane Server]
GP[Gameplay WS Server]
end
CPS -->|implements| CP
Service -->|calls| CL
Service -->|calls| WAPI
Service -->|calls| VL
Browser -->|WebSocket| GP
#SurfaceDirectionThe service…
1Control PlanePlatform → Service (HTTP)implements it (desired-state, status, health, pause/resume)
2Config + LedgerService → Platform (HTTP)calls it (runtime profiles, open/settle ledger, round-start-check, bet templates)
3WalletService → Platform → Operator (HTTP)calls it (debit, credit, rollback)
4GameplayBrowser → Service (WebSocket)serves it (session, placeBet, round_*)

Each surface is guarded by its own secret header: x-internal-control-secret, x-internal-config-secret, x-internal-wallet-secret, and x-internal-verify-launch-secret. The secrets are independent.

Every player session is exactly one of two modes. The launch URL decides, and the mode never changes mid-session.

DemoReal
Triggered bydemo=true in the URLdemo=false or omitted
Currencyfrom the runtime profile (demo_currency)from the URL, validated against the partner wallet
Starting balancedemo_start_balance from the profilereal partner wallet balance
Partner wallet callsskippedrequired: authenticate, debit, credit, rollback
Bet persistenceoptional (save_demo_bets flag)always

Two round-trips matter most: the launch handshake that starts a session, and the wallet flow that moves money on each bet.

sequenceDiagram
participant Browser
participant LN as Cloud1x2 Launcher
participant GS as Game Service
participant PL as Platform
Browser->>LN: GET launch URL (gameId, token, currency)
LN->>GS: proxy the iframe content
GS-->>Browser: game SPA + assets
Browser->>GS: WebSocket connect (launch query)
GS->>PL: POST /internal/verify-launch
PL-->>GS: ok + session fields<br/>(currency, balance, demo, locale, limits)
GS-->>Browser: emit 'session' (+ first round events)

verify-launch is the single source of truth for whether a launch is allowed, whether it is real or demo, and the starting balance, currency, bet limits, and locale. If it fails, the service rejects the WebSocket connection.

sequenceDiagram
participant Player
participant GS as Game Service
participant PL as Platform
participant OP as Partner Operator
Player->>GS: place bet
GS->>PL: POST /internal/wallet/debit
PL->>OP: partner-side debit (signed)
OP-->>PL: ok + new balance
PL-->>GS: ok + new balance
GS->>PL: POST /internal/consolidated/tx (open ledger)
GS-->>Player: bet accepted
Note over GS: round runs...
GS->>GS: settle the round (win / lose)
GS->>PL: POST /internal/wallet/credit (only on win)
PL->>OP: partner-side credit
PL-->>GS: ok
GS->>PL: POST /internal/consolidated/tx/settle (status)
GS-->>Player: outcome (+ payout if won)

Three rules:

  • A game service never speaks to the operator directly. The platform is always the bridge — secret signing, retries, and format translation happen there.
  • Demo skips the whole wallet half. The ledger is still written when save_demo_bets is set, but partner endpoints are not called.
  • If something fails mid-flight (a debit succeeded but the round irrecoverably errored before settle), the service calls rollback to compensate.

That is the model. When ready, build the smallest working version in the Quickstart, then reach for the Protocol Reference while implementing each endpoint.