Data model
Buildable DDL: TypeORM migrations in services/api/src/db/migrations/ (ADR 0023). Historical SQL: schema/historical/.
Demo seeds: schema/seeds/demo.sql.
Conceptual identity and party model from spec §15 / §46.9 and ADRs 0001, 0013, 0014, 0026.
Party (organisations)
Generic party with a type enum (ADR 0001): PLAYER, OPERATOR, PROVIDER, AFFILIATE, MERCHANT, BRAND, APPLICATION, plus integration. External IDs stay typed (pp_opr_..., pp_prv_..., pp_int_...), never pp_party_....
Player identity
Tables (TypeORM entities / baseline migration):
players: private UUIDv7id+public_player_id(pp_plr_...); optionalreservation_expires_atwhile status=reserved(A0 pre-mint);analytics_subject(pp_anl_...) minted at activation;anonymised_at/ status=anonymisedafter Delete Accountauthentication_identities:issuer+ subject cipher + lookup HMAC (UNIQUE(issuer, subject_lookup_hmac)); opaqueiam_subject(OIDC sub / ZITADEL user id) for password sign-in reverse lookup — not PII, never on/v1/meplayer_aliases:pp_plr_opr_.../pp_plr_prv_...(revoked aliases stay reserved)external_identities: partner-issued IDsintegrations: provider × operatoridentity_links: consent /effective_from/unlinked_at/revoked_atlink_intents: short-lived assertion exchangeplayer_registrations: bootstrap state machineplayer_sessions: BFF cookie sessions; optionaliam_user_idfor signed-in factor add; optionaloidc_id_tokenfor logout handle onlywebauthn_credentials: public-key mirror for discoverable portal passkeys (no private keys)player_account_merges: dual-proof merge (UI later)party_jwks/assertion_jti: operator assertion verify + replay protection
Loyalty, Activity, and serving tables (TypeORM):
activity_batches/activity_uploads/activity_events/points_ledger/campaign_versions- Daily serving:
analytics_account_day,analytics_account_provider_day,analytics_partner_player_day(provider Party + that provider’spp_plr_prv_...+ day),analytics_studio_account_day(provider Party + day, distinct Accounts)
The live ledger may reference players.id. Partner studio reads do not. After Delete Account, retained Activity keeps round_ref and analytics subject with player_id / player_alias nulled; partner-player-day rows for those aliases are deleted.
HTTP API
NestJS control plane (services/api): /auth/*, /v1/me, DELETE /v1/me/connections/:audienceId (Unlink), DELETE /v1/me (Delete Account), /v1/player-reservations, /v1/link-intents*, POST /v1/activity-batches, POST /v1/activity-uploads, POST /v1/activity-uploads/:uploadId/complete, GET /v1/analytics/studio, GET /v1/analytics/studio/aliases/:alias. See infra/README.md. Normative examples remain in spec §37.