Developer DocsSecurity & compliance

Security & compliance

How the platform protects data, and the compliance tooling it ships. Relevant to iGaming operators handling player PII and financial history.

Isolation

  • Row-Level Security (RLS) enforces multi-tenant/brand isolation in the database — not only in application code. Every brand-scoped table has policies that constrain reads/writes to the caller’s assigned brands. See Database & RLS and RBAC & permissions.
  • The Platform Owner operates cross-tenant through the same RLS, via super-aware helper functions — no separate bypass path.

Authentication & secrets

  • Operator API keys are stored as SHA-256 hashes — the raw plq_… value is shown once and never persisted. Keys can be brand-pinned and carry least-privilege scopes (events:write for ingestion). See PAM Integration → Authentication.
  • The service-role API-key backdoor is off unless ALLOW_SERVICE_ROLE_API_KEY=true — never enabled in production.
  • Operator sessions use Supabase Auth with cookie-based SSR sessions.
  • Outbound webhooks are HMAC-SHA256 signed (X-PlaylogiQ-Signature); receivers verify against the shared secret. See Outbound webhooks.

Transport & network

  • All external traffic is HTTPS; Caddy terminates TLS and auto-renews certificates. Internal services talk over the Docker network; Postgres, Redis, and the Supabase internals are not publicly exposed.

Data residency & ownership

The stack is self-hosted (see Deployment) — the database, including append-only player_events and balance_transactions, lives on the operator’s own server, backed up off-site to a Hetzner Storage Box. Nothing is sent to a managed third-party data plane.

GDPR tooling

The platform ships right-to-access and right-to-erasure for players (Players → a player → GDPR actions):

  • Data export — gathers the player’s rows (identity, profile, events, sessions, transactions, consent) for a subject-access request.

  • Erasuregdpr_erase_player() anonymizes the PII-bearing rows (email, phone, name, gender, metadata cleared; status set to closed; external_id replaced with an opaque token) and removes contact channels and delivered messages, while retaining financial/event history keyed by an opaque UUID for regulatory retention. The player is marked with erased_at. The function is tenant-guarded (SECURITY DEFINER + explicit p_tenant).

  • Consent — a master marketing consent plus per-channel consent is respected by all outbound messaging; suppression lists and frequency caps add further guardrails.

Responsible gaming

RG enforcement (limits, self-exclusion, cooling-off) is owned by the operator’s PAM. PlaylogiQ consumes those signals as events (limit_set, self_exclusion, cooling_off, status_changed) and reflects them on the player, but does not itself act as the RG controller.

Audit

Sensitive actions are recorded in the audit log (Settings → Audit log), readable by tenant admins and above.

Go-live hygiene

Rotate any keys/secrets shared during development, confirm production .env values, keep .env backups out of world-readable paths, and re-tighten the server deploy key to read-only. The authoritative checklist is in the project CLAUDE.md. See also Deployment.