/** A user's role — mirrors `profiles.role`'s check constraint. Defined here * (data layer) rather than in state/authStore.ts so both that store and * this repository share one definition without state importing from data * in the wrong direction. */ export type UserRole = 'regular' | 'admin' | 'super_admin' export interface AdminUserSummary { id: string username: string email: string role: UserRole /** Lets this specific Admin post/retire site-wide announcements — a * narrower grant than the role itself (a Super Admin can always post * regardless of this). Meaningless for a regular/super_admin row, but * present either way since it mirrors the underlying profiles column. */ canPostAnnouncements: boolean /** Set (a future timestamp) while banned; undefined otherwise. */ bannedUntil?: string createdAt: string /** Set once this account's data has been moved to another account via * migrateAccount below (organized-ideas.md §2) — never cleared, and * never set back to undefined by anything in this app. */ migratedToUserId?: string migratedToUsername?: string } export interface AccountMigrationImpact { diagramCount: number privateEntityCount: number submissionCount: number } /** One row of the permanent account-migration audit log. */ export interface AccountMigrationRecord extends AccountMigrationImpact { id: string /** Null if that account has since been deleted — fromUsername/toUsername * (snapshotted at migration time) stay populated regardless, so the log * stays legible either way. */ fromUserId: string | null toUserId: string | null fromUsername: string toUsername: string performedBy: string | null verificationNotes: string createdAt: string } /** Storage abstraction for Super-Admin user management (organized-ideas.md * §6's "CRUD user accounts"). Listing and role changes are plain * RLS/privileged-function reads and writes; ban/unban/delete go through * the admin-user-action Edge Function since those specifically need * Supabase Auth's Admin API — see that function's own header comment for * why this can't just be another SQL function like the rest. */ export interface AdminUserRepository { listUsers(): Promise updateRole(userId: string, role: UserRole): Promise /** Super-Admin-only in practice (RLS), same as updateRole — grants or * revokes one Admin's ability to post announcements. */ updateCanPostAnnouncements(userId: string, canPostAnnouncements: boolean): Promise /** Reversible — blocks login without touching the account's data. */ banUser(userId: string): Promise unbanUser(userId: string): Promise /** Irreversible — cascades to the user's profile, diagrams, and owned * private catalog entries via their existing foreign keys. */ deleteUser(userId: string): Promise /** Read-only "what would move" check before committing a migration below — * same idea as the catalog usage-impact check before an unpublish. */ previewAccountMigration(fromUserId: string, toUserId: string): Promise /** Moves diagrams, private catalog entries, and submissions from one * account to another (organized-ideas.md §2's tool for someone who's * lost access to their old account) — never touches credentials or * deletes the old account, just reassigns what it owns. Throws (rather * than swallowing, unlike most methods here) so the caller can surface * *why* it failed — most commonly: already migrated, missing * verification notes, or migrating an account into itself. */ migrateAccount(fromUserId: string, toUserId: string, verificationNotes: string): Promise /** The permanent audit trail, most recent first. */ listAccountMigrations(): Promise }