fix(GRO-1272): auto-provision staff record on first OIDC login (#19)
Fixes HTTP 403 on all authenticated routes for new OIDC users by auto-creating
a minimal groomer staff record on first login when a Better-Auth user exists
but no staff record is found.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
GRO-1325 was marked done but never implemented. This adds the missing
Better-Auth user + account seeding for UAT email+password logins.
For each SEED_UAT_*_PASSWORD env var present, the seed now:
1. Creates (or links to existing) a Better-Auth user record with
emailVerified: true
2. Creates a credential account with providerId: "credential"
and a bcrypt-hashed password (using better-auth/crypto)
3. Links the staff record to the Better-Auth user via userId
Idempotent: skips user/account creation if already seeded.
Updated UAT_PLAYBOOK.md §4.1 — TC-API-1.4 through 1.9 now reference
the new seed provisioning (GRO-1325 was the missing piece).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Rename insertedStaff to _insertedStaff (ESLint unused var, line 49)
- Rename table param to _table in insert mock (ESLint unused param, line 91)
- Fix buildApp jwtPayload to prefer userLookupResult.id over staffLookupResult.userId
(corrects auto-provision test failures where sub was 'unknown-sub' instead of 'ba-user-new')
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add null guard for newStaff after .returning() in auto-provision block
- Make buildQuery() iterable without .limit() call (for WHERE-only queries)
- Use fallback in .limit() for manager-fallback dev-mode tests
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add user table mock and db.insert returning chain to rbac.test.ts
- Add three new tests: happy-path auto-provision, email-prefix fallback,
and miss-path (no user → 403)
- Add TC-API-1.4 to UAT_PLAYBOOK.md §4.1 for first-login auto-provision
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When a user authenticates via OIDC but has no staff record (userId NULL,
oidcSub mismatch, email mismatch), resolveStaffMiddleware now checks for
a Better-Auth user record by jwt.sub and auto-creates a minimal groomer
staff record on first login.
This fixes the UAT regression where all API routes returned 403 for all
authenticated users after GRO-1207, because seedKnownUsers() sets
oidcSub to Authentik integer PKs or emails rather than the actual Authentik
OIDC sub (a UUID). The auto-provision path bridges the gap for all UAT
personas without requiring seed/Terraform changes.
Co-Authored-By: Paperclip <noreply@paperclip.ing>