Skip to main content
InternalMarkdown

Architecture

PlayerPal is a privacy-preserving loyalty and analytics sidecar for operators, game providers, affiliates and reward partners. It maintains a persistent player account, loyalty ledger, campaign progress and analytics, and does not store a player's email address, name or telephone number.

This page is the system overview. Identity and authentication detail: spec/PLAYERPAL_AUTH_IDENTITY_SPEC.md (wins on conflict). Topic pages under docs/ are the day-to-day source of truth.

Design principle​

ONE PRIVATE PLAYER IDENTITY
MANY AUDIENCE-SPECIFIC EXTERNAL ALIASES
NO PLAYER EMAIL STORED BY PLAYERPAL
  • Players may register directly, from an operator, or from a provider when the provider is the integration entry point.
  • A successful authentication resolves to one private PlayerPal player. The player can see pp_plr_.... Operators and providers never receive it.
  • Connecting an operator issues pp_plr_opr_.... Reporting activity through a provider-operator integration issues pp_plr_prv_....
  • PlayerPal is not on the game critical path. If every PlayerPal service is down, the casino and provider must still authenticate the player, launch the game, accept bets, settle rounds and pay winnings. See ingestion-and-availability.md and ADR 0015.

Components​

Player and admin clients
→ API gateway / BFF
→ IAM (Keycloak or ZITADEL) protocols, credentials, sessions
→ Identity Service players, aliases, links, consent
→ Authorization Service organisation, audience, resource
→ Ingestion API
→ durable inbox / object storage
→ Loyalty engine
→ Analytics pipeline

Logical components (spec §22):

ComponentOwns
IAM platformOIDC/OAuth, passkeys, social federation, MFA, enterprise SSO, machine tokens
Player BFFBrowser session boundary
Identity ServicePlayers, auth mappings, aliases, links, Unlink, Delete Account
Integration RegistryOperators, providers, credentials, namespaces
Authorization ServiceOrganisation and resource decisions
Ingestion APIAuthenticated batch acceptance (integration-scoped)
Event streamDecoupled processing (Postgres inbox first; Redpanda/Kafka later)
Loyalty engineLedger, rules, campaigns
AnalyticsProvider studio cohort and per-alias numbers; no partner-facing identity keys

Do not store loyalty balances, aliases, operator connections or gameplay facts as IAM attributes. See ADR 0011.

Initial stack​

Technology-neutral in the spec; pragmatic first deployment (spec §24, §35):

StageInitial choice
IAMZITADEL for local POC (ADR 0021); production pick still needs §23.2
Core API (control plane)NestJS modular monolith (services/api)
Data-plane workersGo (services/worker) when ingestion load justifies it
Identity / ledgerPostgreSQL (TypeORM DDL, ADR 0023)
Player webReact portals + NestJS BFF; popup + postMessage for embedded operator flows
CacheValkey/Redis where needed; never source of truth
Bulk landingS3-compatible object storage
Batch jobsDagster
ObservabilityOpenTelemetry, Prometheus/Grafana

Start as a modular monolith plus an independent ingestion worker. Split services only at measured hotspots. Airflow is not the default orchestrator.

Delivery​

Spec §42 (preferred over the earlier four-phase sketch in §28 where they differ):

  1. Contract and failure proof. Freeze identifiers and error codes; prove play continues while PlayerPal is blocked; no-email IAM POC.
  2. Thin vertical slice. ZITADEL (local POC), Nest-owned passkey/password/social, one social method, Bucks Casino linking, Pragmatic Play alias in the link exchange, Postgres, points ledger, player wallet.
  3. Production hardening. Provider outbox, gzip batches, idempotency, object-storage profile, key rotation, SLOs.
  4. Scale where observed. Redpanda, analytical store, regional ingestion, policy engine only if application authZ is no longer enough.
  • 0001 generic party model
  • 0004 async-first ingestion
  • 0005 Postgres inbox then Redpanda
  • 0011 IAM vs identity graph
  • 0015 off the game path
  • 0026 analytics subject and cohort