TeeTime Identity Mapping (IDP → Player)
This document describes how TeeTime resolves an authenticated user from the IDP
to a TeeTime Player and how to backfill mappings for existing users.
Overview
TeeTime stores player data under the teetime-client schema where
Player.id is a UUID. Authentication is handled by the IDP (e.g., Auth0),
which exposes a subject (e.g., auth0|abc-123-def). To bridge these systems,
the schema includes a UserIdentity table that maps (provider, subject) to a
Player.id (UUID).
UserIdentity(provider, subject) ───► Player(id UUID)
The TeeTime backend exposes “me” endpoints (favorites/buddies) that resolve the current player from the JWT and then operate on that player:
GET /api/players/me/favoritesPOST /api/players/me/favoritesDELETE /api/players/me/favorites/:clubIdGET /api/players/me/buddies— returns buddy relationships with contact details (buddy.firstName,buddy.lastName,buddy.fullName,buddy.email,buddy.phoneNumber)POST /api/players/me/buddiesDELETE /api/players/me/buddies/:buddyId
These endpoints use the DB‑backed resolver to find (or create) the player.
Buddy response shape (example):
[
{
"id": "rel-123",
"playerId": "player-abc",
"buddyId": "player-def",
"createdAt": "2025-12-05T10:00:00.000Z",
"buddy": {
"id": "player-def",
"firstName": "Rory",
"lastName": "McIlroy",
"fullName": "Rory McIlroy",
"email": "rory@example.com",
"phoneNumber": "+27820000001"
}
}
]
Backfill script
Script: tools/scripts/teetime/import-seed/backfill-user-identities.mjs
Purpose:
- Link existing IDP users to TeeTime players by
(provider, subject). - Resolve by email when possible; optionally create the player on first use.
Usage:
export TEETIME_DATABASE_URL=postgresql://user:pass@host:5432/teetime_db?schema=public
# CSV input (subject,email,givenName,familyName,preferredName)
node tools/scripts/teetime/import-seed/backfill-user-identities.mjs \
--file identities.csv \
--provider auth0 \
--create
# NDJSON input (one JSON per line)
node tools/scripts/teetime/import-seed/backfill-user-identities.mjs \
--file identities.ndjson \
--provider idp \
--format ndjson
Dry run (preview changes):
node tools/scripts/teetime/import-seed/backfill-user-identities.mjs \
--file identities.csv \
--provider auth0 \
--dry-run
# Example output
{
"provider": "auth0",
"create": false,
"dryRun": true,
"linked": 0,
"exists": 5,
"unresolved": 1,
"wouldLink": 3,
"wouldCreate": 2
}
Prerequisite (migration):
Before running the backfill, ensure the UserIdentity table is present:
# Generate/apply migration
pnpm nx run teetime-client:prisma:migrate
# Or directly via Prisma (from repo root):
cd libs/prisma/teetime-client
pnpm exec prisma migrate dev --name add_user_identity_table
Input formats:
- CSV headers:
subject,email,givenName,familyName,preferredName - NDJSON fields:
{ subject, email, givenName, familyName, preferredName }
Behavior:
- If
(provider, subject)exists inUserIdentity, skip (statusexists). - Else, if
emailmatches an existingPlayer.email, link identity (statuslinked). - Else, when
--createis present, create aPlayerfrom the provided names and link (statuslinked). - Otherwise, report
unresolved.
Output example:
{
"provider": "auth0",
"create": true,
"linked": 42,
"exists": 10,
"unresolved": 3
}
Sample inputs
- CSV (
identities.csv):
subject,email,givenName,familyName,preferredName
auth0|abc-123-def,jane.doe@example.com,Jane,Doe,
idp|user-789,joe.bloggs@example.com,Joe,Bloggs,Joe B.
- NDJSON (
identities.ndjson):
{"subject":"auth0|abc-123-def","email":"jane.doe@example.com","givenName":"Jane","familyName":"Doe"}
{"subject":"idp|user-789","email":"joe.bloggs@example.com","givenName":"Joe","familyName":"Bloggs","preferredName":"Joe B."}
Operational notes
- Run in staging first. Review
unresolvedentries and rerun with--createif appropriate. - The resolver logs links as they’re created:
Linked identity <provider>:<subject> -> player <uuid>. - The backend “me” endpoints will succeed once an identity mapping exists. With
findOrCreateenabled in the resolver, the mapping may be created on first use.
Troubleshooting
TEETIME_DATABASE_URLmissing – ensure the env is exported before running the script.- Duplicate email edge cases – the backfill prefers
UserIdentityexact match, then email, then create (when--create).