chore: refactor admin system for UUID identity (refs #213)

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 <noreply@anthropic.com>
This commit is contained in:
Eric Gullickson
2026-02-16 09:52:09 -06:00
parent b418a503b2
commit fd9d1add24
8 changed files with 319 additions and 294 deletions

View File

@@ -10,29 +10,49 @@ import { logger } from '../../../core/logging/logger';
export class AdminRepository {
constructor(private pool: Pool) {}
async getAdminByAuth0Sub(auth0Sub: string): Promise<AdminUser | null> {
async getAdminById(id: string): Promise<AdminUser | null> {
const query = `
SELECT auth0_sub, email, role, created_at, created_by, revoked_at, updated_at
SELECT id, user_profile_id, email, role, created_at, created_by, revoked_at, updated_at
FROM admin_users
WHERE auth0_sub = $1
WHERE id = $1
LIMIT 1
`;
try {
const result = await this.pool.query(query, [auth0Sub]);
const result = await this.pool.query(query, [id]);
if (result.rows.length === 0) {
return null;
}
return this.mapRowToAdminUser(result.rows[0]);
} catch (error) {
logger.error('Error fetching admin by auth0_sub', { error, auth0Sub });
logger.error('Error fetching admin by id', { error, id });
throw error;
}
}
async getAdminByUserProfileId(userProfileId: string): Promise<AdminUser | null> {
const query = `
SELECT id, user_profile_id, email, role, created_at, created_by, revoked_at, updated_at
FROM admin_users
WHERE user_profile_id = $1
LIMIT 1
`;
try {
const result = await this.pool.query(query, [userProfileId]);
if (result.rows.length === 0) {
return null;
}
return this.mapRowToAdminUser(result.rows[0]);
} catch (error) {
logger.error('Error fetching admin by user_profile_id', { error, userProfileId });
throw error;
}
}
async getAdminByEmail(email: string): Promise<AdminUser | null> {
const query = `
SELECT auth0_sub, email, role, created_at, created_by, revoked_at, updated_at
SELECT id, user_profile_id, email, role, created_at, created_by, revoked_at, updated_at
FROM admin_users
WHERE LOWER(email) = LOWER($1)
LIMIT 1
@@ -52,7 +72,7 @@ export class AdminRepository {
async getAllAdmins(): Promise<AdminUser[]> {
const query = `
SELECT auth0_sub, email, role, created_at, created_by, revoked_at, updated_at
SELECT id, user_profile_id, email, role, created_at, created_by, revoked_at, updated_at
FROM admin_users
ORDER BY created_at DESC
`;
@@ -68,7 +88,7 @@ export class AdminRepository {
async getActiveAdmins(): Promise<AdminUser[]> {
const query = `
SELECT auth0_sub, email, role, created_at, created_by, revoked_at, updated_at
SELECT id, user_profile_id, email, role, created_at, created_by, revoked_at, updated_at
FROM admin_users
WHERE revoked_at IS NULL
ORDER BY created_at DESC
@@ -83,61 +103,61 @@ export class AdminRepository {
}
}
async createAdmin(auth0Sub: string, email: string, role: string, createdBy: string): Promise<AdminUser> {
async createAdmin(userProfileId: string, email: string, role: string, createdBy: string): Promise<AdminUser> {
const query = `
INSERT INTO admin_users (auth0_sub, email, role, created_by)
INSERT INTO admin_users (user_profile_id, email, role, created_by)
VALUES ($1, $2, $3, $4)
RETURNING auth0_sub, email, role, created_at, created_by, revoked_at, updated_at
RETURNING id, user_profile_id, email, role, created_at, created_by, revoked_at, updated_at
`;
try {
const result = await this.pool.query(query, [auth0Sub, email, role, createdBy]);
const result = await this.pool.query(query, [userProfileId, email, role, createdBy]);
if (result.rows.length === 0) {
throw new Error('Failed to create admin user');
}
return this.mapRowToAdminUser(result.rows[0]);
} catch (error) {
logger.error('Error creating admin', { error, auth0Sub, email });
logger.error('Error creating admin', { error, userProfileId, email });
throw error;
}
}
async revokeAdmin(auth0Sub: string): Promise<AdminUser> {
async revokeAdmin(id: string): Promise<AdminUser> {
const query = `
UPDATE admin_users
SET revoked_at = CURRENT_TIMESTAMP
WHERE auth0_sub = $1
RETURNING auth0_sub, email, role, created_at, created_by, revoked_at, updated_at
WHERE id = $1
RETURNING id, user_profile_id, email, role, created_at, created_by, revoked_at, updated_at
`;
try {
const result = await this.pool.query(query, [auth0Sub]);
const result = await this.pool.query(query, [id]);
if (result.rows.length === 0) {
throw new Error('Admin user not found');
}
return this.mapRowToAdminUser(result.rows[0]);
} catch (error) {
logger.error('Error revoking admin', { error, auth0Sub });
logger.error('Error revoking admin', { error, id });
throw error;
}
}
async reinstateAdmin(auth0Sub: string): Promise<AdminUser> {
async reinstateAdmin(id: string): Promise<AdminUser> {
const query = `
UPDATE admin_users
SET revoked_at = NULL
WHERE auth0_sub = $1
RETURNING auth0_sub, email, role, created_at, created_by, revoked_at, updated_at
WHERE id = $1
RETURNING id, user_profile_id, email, role, created_at, created_by, revoked_at, updated_at
`;
try {
const result = await this.pool.query(query, [auth0Sub]);
const result = await this.pool.query(query, [id]);
if (result.rows.length === 0) {
throw new Error('Admin user not found');
}
return this.mapRowToAdminUser(result.rows[0]);
} catch (error) {
logger.error('Error reinstating admin', { error, auth0Sub });
logger.error('Error reinstating admin', { error, id });
throw error;
}
}
@@ -202,30 +222,11 @@ export class AdminRepository {
}
}
async updateAuth0SubByEmail(email: string, auth0Sub: string): Promise<AdminUser> {
const query = `
UPDATE admin_users
SET auth0_sub = $1,
updated_at = CURRENT_TIMESTAMP
WHERE LOWER(email) = LOWER($2)
RETURNING auth0_sub, email, role, created_at, created_by, revoked_at, updated_at
`;
try {
const result = await this.pool.query(query, [auth0Sub, email]);
if (result.rows.length === 0) {
throw new Error(`Admin user with email ${email} not found`);
}
return this.mapRowToAdminUser(result.rows[0]);
} catch (error) {
logger.error('Error updating admin auth0_sub by email', { error, email, auth0Sub });
throw error;
}
}
private mapRowToAdminUser(row: any): AdminUser {
return {
auth0Sub: row.auth0_sub,
id: row.id,
userProfileId: row.user_profile_id,
email: row.email,
role: row.role,
createdAt: new Date(row.created_at),