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)

EnvironmentExternal URL
TSTpack-alpha.game-be-tst.api.ifortuna.cz
STGpack-alpha.game-be-stg.api.ifortuna.cz
PRODpack-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:

  1. Create apps/pack-beta/ with games registered in AppModule
  2. CI detects affected pack via Nx, builds and deploys automatically via Helm
  3. Create pack-beta-config ConfigMap 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-alpha deployed in gaming-studio-shared namespace
  • 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:

  1. Is APIGW the right solution here, or direct Ingress for TST?
  2. Preferred subdomain naming convention for TST/STG/PROD?
  3. Swagger needed per pack or once (all packs identical API)?
  4. 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).

Built with LogoFlowershow