Game Backend Routing and APIGW Architecture
Game Backend Routing and APIGW Architecture
Decision
Option A: Subdomain per pack + serverUrl in launch params
Chosen over:
- Option B (single domain, path prefix per pack)
- Option C (APIGW body inspection by gameId - rejected, anti-pattern)
Architecture
Traffic Flow
RGS generates launch URL:
https://feg-fe-staging.pixentech.com/royale81/?token=...&serverUrl=https://pack-alpha.game-be-tst.api.ifortuna.cz
Internet
|
APIGW (SSL termination)
pack-alpha.game-be-tst.api.ifortuna.cz
|
OCP Route (internal FEG network)
pack-alpha-gaming-studio-shared.apps.ocp02-shared...
|
K8s Service: pack-alpha:8000
|
Pack-Alpha Pod
URL Convention (proposed, pending infra confirmation)
| Environment | External URL |
|---|---|
| TST | pack-alpha.game-be-tst.api.ifortuna.cz |
| STG | pack-alpha.game-be-stg.api.ifortuna.cz |
| PROD | pack-alpha.game-be.api.ifortuna.cz |
Wildcard cert *.game-be.api.ifortuna.cz covers all packs and environments - infra manages once.
Why This Approach
serverUrl in Launch Params
- Industry standard (Pragmatic Play, Evolution, NetEnt all use this pattern)
- FE already supports it - confirmed from existing staging launch URL format:
?token=...&language=en&serverUrl=https://... - No FE rebuild when game moves between packs - RGS config update only
- Secure: game outcome determined server-side by RGS, not FE. Even if player tampers with serverUrl, real wallet is unaffected (only legitimate BE can call RGS with valid session token)
FE Domain Allowlist (security mitigation)
FE should validate serverUrl against allowlist before using:
const ALLOWED_PATTERN = /^https:\/\/[\w-]+\.game-be(-tst|-stg)?\.api\.ifortuna\.cz$/;
if (!ALLOWED_PATTERN.test(serverUrl)) throw new Error('Invalid serverUrl');
Subdomain per Pack
- Clean isolation - pack failure doesn't affect other packs or their URLs
- Simple APIGW config: one subdomain route per pack
- No routing tables, no body inspection, no path rewriting
- Wildcard cert covers all future packs automatically
Adding a New Pack (Full Process)
When pack-beta is added:
Dev team:
- Create
apps/pack-beta/with games registered inAppModule - CI detects affected pack via Nx, builds and deploys automatically via Helm
- Create
pack-beta-configConfigMap in OCP with env vars
Infra (one ticket):
4. Add APIGW route: pack-beta.game-be-tst.api.ifortuna.cz → pack-beta OCP service
5. Wildcard cert already covers it - no cert work
RGS config:
6. Register pack-beta games with serverUrl=https://pack-beta.game-be-tst.api.ifortuna.cz
FE: 7. No changes - reads serverUrl from launch params at runtime
Total infra effort per new pack: 1 ticket.
Current OCP State
pack-alphadeployed ingaming-studio-sharednamespace- OCP Route auto-created by Helm:
pack-alpha-gaming-studio-shared.apps.ocp02-shared.t.dc1.cz.ipa.ifortuna.cz - This OCP Route URL is the upstream target for APIGW
Helm Chart
No changes needed. Existing route.yaml creates OCP Route per pack automatically:
apiVersion: route.openshift.io/v1
kind: Route
spec:
to:
kind: Service
name: {{ .Values.packName }} # auto: pack-alpha, pack-beta, etc.
tls:
termination: edge
Security Note for PROD
OCP Route is currently publicly accessible (anyone with the URL bypasses APIGW). For PROD: restrict OCP Route to internal network only via OCP network policy, forcing all traffic through APIGW. Not urgent for TST.
Pending: Infra Team Response
Questions sent to infra:
- Is APIGW the right solution here, or direct Ingress for TST?
- Preferred subdomain naming convention for TST/STG/PROD?
- Swagger needed per pack or once (all packs identical API)?
- Any Helm chart annotations/labels needed for their ingress/APIGW?
Pending: Swagger Setup
Infra needs swagger to configure APIGW routes. Task: add @nestjs/swagger
to pack-alpha. All packs have identical API surface:
GET /games/health
POST /games/init
POST /games/spin
POST /games/feature
One swagger definition covers all packs (same schema, different host per pack).