Migrate all database foreign keys from auth0_sub VARCHAR(255) to user_profiles.id UUID as the primary user identifier across 17 feature tables, admin system, and audit logs
Update auth plugin to set userContext.userId to UUID (from profile lookup) instead of raw JWT sub claim
Refactor admin system for UUID identity: admin_users gains id UUID PK + user_profile_id UUID FK, admin creation now requires existing user_profiles entry
Update all frontend admin UI to use user.id (UUID) instead of user.auth0Sub for API calls
Multi-phase SQL migration converting all user_id columns from
VARCHAR(255) auth0_sub to UUID referencing user_profiles.id.
Restructures admin_users with UUID PK and user_profile_id FK.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Auth plugin now uses profile.id (UUID) as userContext.userId instead
of raw JWT sub. Admin guard queries admin_users by user_profile_id.
Auth0 Management API calls continue using auth0Sub from JWT.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Updated user-profile.repository.ts to use UUID instead of auth0_sub:
- Added getById(id) method for UUID-based lookups
- Changed all methods (except getByAuth0Sub, getOrCreate) to accept userId (UUID) instead of auth0Sub
- Updated SQL WHERE clauses from auth0_sub to id for UUID-based queries
- Fixed cross-table joins in listAllUsers and getUserWithAdminStatus to use user_profile_id
- Updated hardDeleteUser to use UUID for all DELETE statements
- Updated auth.plugin.ts to call updateEmail and updateEmailVerified with userId (UUID)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Migrate admin controller, routes, validation, and users controller
from auth0Sub identifiers to UUID. Admin CRUD now uses admin UUID id,
user management routes use user_profiles UUID. Clean up debug logging.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- audit-log: JOIN on user_profiles.id instead of auth0_sub
- backup: use userContext.userId instead of auth0Sub
- ocr: use request.userContext.userId instead of request.user.sub
- user-profile controller: use getById() with UUID instead of getOrCreateProfile()
- user-profile service: accept UUID userId for all admin-focused methods
- user-profile repository: fix admin JOIN aliases from auth0_sub to id
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Backend test fixtures:
- Replace auth0|xxx format with UUID in all test userId values
- Update admin tests for new id/userProfileId schema
- Add missing deletionRequestedAt/deletionScheduledFor to auth test mocks
- Fix admin integration test supertest usage (app.server)
Frontend:
- AdminUser type: auth0Sub -> id + userProfileId
- admin.api.ts: all user management methods use userId (UUID) params
- useUsers/useAdmins hooks: auth0Sub -> userId/id in mutations
- AdminUsersPage + AdminUsersMobileScreen: user.auth0Sub -> user.id
- Remove encodeURIComponent (UUIDs don't need encoding)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
user_preferences had rows where user_id already contained user_profiles.id
(UUID) instead of auth0_sub. Added second backfill pass matching UUID-format
values directly, and cleanup for 2 orphaned rows with no matching profile.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Users with both auth0_sub and UUID rows in user_preferences get the same
user_profile_id after backfill, causing unique constraint violation on
rename. Keep the newest row per user_profile_id.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
16 controllers still used request.user.sub (Auth0 ID) instead of
request.userContext.userId (UUID) after the user_id column migration,
causing 500 errors on all authenticated endpoints including dashboard.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Vehicles service and subscriptions code still queried user_profiles by
auth0_sub after the UUID migration, causing 500 errors on GET /api/vehicles.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
auth0_sub VARCHAR(255)touser_profiles.id UUIDas the primary user identifier across 17 feature tables, admin system, and audit logsuserContext.userIdto UUID (from profile lookup) instead of raw JWTsubclaimadmin_usersgainsid UUID PK+user_profile_id UUID FK, admin creation now requires existinguser_profilesentryuser.id(UUID) instead ofuser.auth0Subfor API callsFixes #206
Fixes #211
Fixes #212
Fixes #213
Fixes #214
Fixes #215
Fixes #216
Fixes #217
Commits
60118881321440userContext.userId= UUID; admin guard queriesuser_profile_idfd9d1adid+userProfileIdb418a50getById()for UUID lookups; admin joins onuser_profiles.id3b1112a754639cuser.idArchitecture Change
auth0_subremains only inuser_profilestable for JWT-to-profile resolutionuser_profiles.idUUID viauser_idFKadmin_usershas its ownidUUID PK +user_profile_idFK (not renamed to avoid ambiguity)Test plan
Generated with Claude Code
Bug report created: #220 - documents all changes from this PR for debugging session.