Cactus v10 — Architecture Reference
Plataforma multi-tenant iGaming 100% Cloudflare edge. Target: 100 brands, 30M usuários, 400M tx/dia.
1. Topologia global
Tudo no edge Cloudflare. Apex Worker é o único entry-point externo; faz service bindings pra todos os Workers especializados.
2. Workers index
Inventário completo. URLs internas via service binding; URLs externas via apex proxy.
| Worker | Função | Bindings | Endpoints públicos |
|---|---|---|---|
igaming-apex | Entry point, WAF, rate limit, geo, proxy | +15 service bindings, CONFIG_KV, RATELIM_KV | evian.bet/* |
igaming-auth | JWT, login, OTP, password reset | D1, CONFIG_KV, SESSIONS_KV, EVENTS_QUEUE | /api/auth/* |
igaming-wallet | Wallets, balances, transfers | D1, EVENTS_QUEUE | /api/wallet/* |
igaming-wallet-do | WalletDO single-writer per player | WALLET_DO (DO), SYNC_QUEUE, EVENTS_QUEUE | /wallet-do/{id}/{op} |
igaming-games | Crash/Mines/Tower + CrashRoundDO | CRASH_DO, WALLET_SERVICE, EVENTS_QUEUE | /api/games/* |
igaming-casino-orchestrator | Casino aggregator framework | D1, WALLET_SERVICE, EVENTS_QUEUE | /api/casino/* |
igaming-payments | Payment adapter framework | D1, WALLET_SERVICE, PAYMENT_EVENTS_QUEUE | /api/payments/* |
igaming-push | VAPID push notifications | D1, CONFIG_KV | /push/* |
igaming-comms | Email (Resend) + SMS (Twilio) + WhatsApp | D1, CONFIG_KV, SESSIONS_KV | /comms/* |
igaming-livechat | WebSocket chat + DM + ChatDO | CHAT_DO (DO), D1 | /api/chat/* |
igaming-social | Feed, posts, likes, comments | D1, EVENTS_QUEUE | /api/social/* |
igaming-reports | Analytics, BI reports MCP-shape | D1, AE (Analytics Engine) | /api/reports/* |
igaming-kyc | KYC tiers via Sumsub | D1, R2 (kyc docs), EVENTS_QUEUE | /api/kyc/* |
igaming-bonus | Bonus engine + wagering tracker | D1, WALLET_SERVICE, EVENTS_QUEUE | /api/bonus/* |
igaming-vip | VIP tiers + loyalty points | D1, EVENTS_QUEUE | /api/vip/* |
igaming-rg | Responsible Gaming limits | D1, EVENTS_QUEUE | /api/rg/* |
igaming-affiliate | Referral + CPA + RevShare | D1, EVENTS_QUEUE | /api/affiliate/* |
igaming-gdpr | Data export + right-to-deletion | D1, R2 exports, cron daily | /api/me/data-export |
igaming-backoffice | Admin auth + tenants + audit | D1, CONFIG_KV | /api/bo/* |
igaming-monitor | Status page + uptime cron | D1, CONFIG_KV, cron 2min | /monitor/status |
igaming-d1-batcher | Queue → batched INSERT D1 | 5x D1 (all shards), CONFIG_KV | queue consumer |
igaming-archiver | D1 hot → R2 Iceberg cron | 5x D1, R2, cron 03:00 UTC | /archive/* |
igaming-do-backup | WalletDO snapshot weekly | WALLET_DO_SERVICE, R2, cron SUN 04:00 | /backup/* |
igaming-analytics-consumer | Queue events → D1 + AE | D1, AE | queue consumer |
igaming-kanban-api | Kanban backend (boards/cards) | D1, CONFIG_KV | /api/kanban/* |
3. Request flow — apex middleware stack
Toda request HTTP entra pelo apex e passa por 4 camadas antes de chegar no Worker downstream.
(scanner UA, threat_score) CF->>Apex: forward Apex->>KV: rate limit check (KV-backed sliding window) alt rate limit excedido KV-->>Apex: 429 Apex-->>Client: 429 Too Many Requests end Apex->>KV: tenant lookup (hostname → tenant_id) Apex->>KV: geo-block check (CF-IPCountry vs tenant.restricted_countries) alt geo blocked Apex-->>Client: 451 Unavailable For Legal Reasons end Apex->>Apex: enrich headers (X-CF-Country/City/ASN) Apex->>DS: service binding fetch (proxyReq) DS-->>Apex: response Apex-->>Client: response + CORS headers
4. Crash WebSocket — bet + cashout em ~30ms
Player abre WS persistente. Bet/cashout viajam via WS já aberto (sem TCP handshake) com ACK direto pro socket. Wallet credit em waitUntil.
5. WalletDO sync pipeline
Single-writer per player. SQLite local no DO (consistency forte). Sync periódico pra D1 via queue.
6. Payment routing engine
Adapter pattern + routing por priority+weight+circuit breaker+failover. 7 providers no catálogo (mock, pix-direct, stripe, mercadopago, btag, coinbase, nowpayments).
7. Casino launch + callback
Player lança game → orchestrator gera session → provider iframe URL. Provider chama nosso wallet via callback HMAC.
8. D1 sharding strategy
Tenant_id → brand shard. Player_id → ledger shard via crc32(). Mapeamento em CONFIG_KV[arch:shard_map] com cache 60s.
s0_legacy
evian_bet] B1[cactus-brands-s1
brands 1-20] B2[cactus-brands-s2
brands 21-40] end subgraph "Ledger shards (per-player_id)" L0[player-ledger
s0_legacy
crc32 mod 2 = 0] L1[cactus-ledger-s1
s1
crc32 mod 2 = 1] end subgraph "Global (small tables)" G1[(tenants)] G2[(admin_users)] G3[(payment_providers)] G4[(casino_providers)] end Router -->|getBrandDb tenant_id| B0 Router --> B1 Router --> B2 Router -->|getLedgerDbForPlayer pid| L0 Router --> L1 Router -->|getGlobalDb| G1
9. Archive D1 hot → R2 Iceberg (nightly)
Cron 03:00 UTC. Move rows com archived=0 AND created_at < 90d pra R2 em layout Iceberg-compatible (JSONL.gz). DELETE com grace 10d.
warehouse/tenant=X/database=Y/table=Z/year/month/day/part-uuid.jsonl.gz] R2Put --> Snapshot[Iceberg snapshot manifest
_metadata/snapshot-ts-shard.json] Snapshot --> Mark[UPDATE archived=1] Mark --> Delete[DELETE WHERE archived=1 AND created_at < 100d] style Cron fill:#f59e0b,color:#000 style R2Put fill:#22c55e,color:#000
10. GDPR data export self-service
Player baixa ZIP JSON.gz com TODOS seus dados em <30s. Right-to-deletion com 14d cooldown.
11. Push notifications flow (VAPID)
VAPID via Web Crypto (sem deps). Anonymous subscribe permitido (device_id link).
12. WAF & Security layers
4 camadas de defesa. Per-tenant geo dinâmico via CONFIG_KV[tenant:X:config].restricted_countries.
| Camada | Implementação | Status |
|---|---|---|
| 1. CF Zone WAF | 5 custom rules (UA scanner, threat_score, geo edge) | ✅ Active |
| 2. Rate Limit Worker | 16 rules KV-backed (login 10/60s, withdraw 5/60s, OTP 3/5min, generic 600/min) | ✅ Active |
| 3. Geo-block per-tenant | Runtime check CF-IPCountry vs tenant.restricted_countries → HTTP 451 | ✅ Active |
| 4. CORS + Origin validation | Apex middleware bloqueia mutating requests com Origin inesperado | ✅ Active |
| 5. Bot Fight Mode | CF nativo + UA validation no apex | ✅ Active |
| 6. Service Binding gateway | Workers só falam entre si via service bindings (sem fetch HTTP loopback CF 1042) | ✅ Active |
| 7. Circuit Breakers | KV state machine per (provider×tenant), 5 falhas/60s → open 30s | ✅ Active |
13. Events pipeline (200+ event types)
Toda ação importante emite event. Pipeline: Worker → Queue → Consumer → D1 + Analytics Engine.
batch 100 / 5s] Consumer --> AE[(Analytics Engine
5M writes/s capacity)] Consumer --> D1[(D1 events_recent_90d)] AE -->|SQL aggregate| Reports[igaming-reports] D1 -->|recent queries| Reports Reports -->|BI dashboards| BO[Backoffice /bo/reports]
14. Deployment + CI/CD
Tudo via wrangler. Pages Projects pra frontends. D1 + R2 + KV criados via CF API.
| Asset | Tipo | URL |
|---|---|---|
| evian-bet-frontend | Pages | staging.evian.bet |
| cactus-v10-backoffice | Pages | bo.cactus-v10.com |
| igaming-docs | Pages | docs-new-stack.cactus-v10.com |
| cactus-kanban | Pages | kanban.cactus-v10.com |
| cactus-docs (esta página) | Pages | docs.cactus-v10.com |
15. API endpoints index
Snapshot dos endpoints mais importantes. Lista completa em /api/admin/openapi (TODO).
Auth
POST /api/auth/register POST /api/auth/login POST /api/auth/logout POST /api/auth/refresh POST /api/auth/forgot-password POST /api/auth/reset-password POST /api/auth/2fa/setup GET /api/auth/me
Wallet
GET /api/wallet/balance GET /api/wallet/balances GET /api/wallet/history?limit=&offset= POST /api/wallet/transfer POST /api/wallet/exchange
Games (Crash/Mines/Tower)
WS /api/games/crash/connect?token=JWT
ws msg: {type: 'bet'|'cashout'|'ping'}
ws ack: {type: 'bet_ack'|'cashout_ack'|'pong'}
GET /api/games/crash/state
GET /api/games/crash/history
POST /api/games/crash/bet (fallback)
POST /api/games/crash/cashout (fallback)
POST /api/games/mines/start
POST /api/games/mines/reveal
POST /api/games/tower/start
POST /api/games/tower/reveal
POST /api/games/verify (provably fair)
Payments
GET /api/payments/methods?country=BR¤cy=BRL POST /api/payments/deposit POST /api/payments/withdrawal POST /api/payments/webhook/:provider GET /api/admin/payments/providers GET /api/admin/payments/tenants/:tid/config PATCH /api/admin/payments/tenants/:tid/config POST /api/admin/payments/test/:provider GET /api/admin/payments/circuit-breakers
Casino
GET /api/casino/games?category=slots&provider=&limit= POST /api/casino/launch/:game_id POST /api/casino/callback/:provider GET /api/admin/casino/providers GET /api/admin/casino/tenants/:tid/config POST /api/admin/casino/sync/:provider
GDPR / Player rights
POST /api/me/data-export GET /api/me/data-export/jobs GET /api/me/data-export/jobs/:id GET /api/me/data-export/download/:id POST /api/me/account-deletion GET /api/me/account-deletion DELETE /api/me/account-deletion
Backoffice + System
GET /api/bo/players?search=&status= GET /api/bo/players/:id/full POST /api/bo/players/:id/lock POST /api/bo/players/:id/credit GET /api/admin/system/tenants PATCH /api/admin/system/tenants/:id GET /api/reports/overview GET /monitor/status (público) GET /api/kanban/boards GET /api/kanban/boards/:slug