Skip to main content
The user management interface provides admins and moderators with tools to view, search, filter, and moderate users across the platform.

Access Requirements

role
string
required
Requires moderator or admin role to access /admin/users

User List View

The main user management page displays all platform users with:
  • Statistics cards: Total users, hidden count, banned count, and elevated roles (admins/moderators)
  • Search: Filter by display name or username (case-insensitive)
  • Tab filters: All, Active, Hidden, Banned
  • Pagination: 20 users per page
Each user card shows:
  • Avatar and display name (obfuscated for privacy)
  • Username (if set)
  • Clerk ID (obfuscated, click to reveal)
  • Role badge (user, moderator, or admin)
  • Status badge (Active, Hidden, or Banned)
  • Country code and account age
  • Quick action buttons

Privacy Features

Personally identifiable information (PII) is automatically obfuscated in the list view. Click to reveal specific fields as needed. This protects user privacy during live streaming or screen sharing.

User Detail View

Navigate to /admin/users/[id] to view comprehensive user details:

Profile Information

  • Display name, username, Clerk ID
  • Country and region (ISO codes)
  • Experience level
  • Bio and social links (GitHub, Twitter, website, Twitch)
  • Account creation date

Moderation History

If a user is banned or hidden, the status panel displays:
  • Action timestamp
  • Name of admin/moderator who performed the action
  • Ban reason (if provided)

Activity

  • Event Registrations: Shows registered events with team preference and commitment level
  • Projects: Lists all projects created by the user (with links if slug exists)

Moderation Actions

Hide User

Permission: Moderators and admins Soft-hides a user profile from public view without blocking authentication:
hideUser({ profileId: string })
  • Sets hiddenAt timestamp and hiddenBy actor ID
  • User can still sign in but profile is filtered from public queries
  • Cannot hide super-admins (defined in ADMIN_USER_IDS env var)
  • Logs action to adminAuditLog table
Restrictions:
  • Cannot hide users who are already hidden
  • Cannot hide super-admins

Unhide User

Permission: Moderators and admins Reverts a hide action:
unhideUser({ profileId: string })
  • Clears hiddenAt and hiddenBy fields
  • Restores profile to public queries
  • Logs action to audit log

Ban User

Permission: Moderators and admins (with restrictions) Permanently blocks a user from accessing the platform:
banUser({ profileId: string, reason?: string })
  • Sets bannedAt, bannedBy, and optional banReason
  • Calls clerk.users.banUser(clerkId) to disable authentication
  • Banned users are redirected to /banned page by middleware
  • Logs action with reason to audit log
Moderator Restrictions:
Moderators cannot ban users with admin role. Only admins can ban other admins.
Additional Protections:
  • Cannot ban super-admins
  • Cannot ban yourself
  • Cannot ban already-banned users

Unban User

Permission: Admin only Reverts a ban and restores full account access:
unbanUser({ profileId: string })
  • Clears bannedAt, bannedBy, banReason, hiddenAt, and hiddenBy
  • Calls clerk.users.unbanUser(clerkId) to restore authentication
  • Logs action to audit log
Unbanning also clears any hidden status to ensure full restoration.

Delete User

Permission: Admin only
Permanently deletes a user account and all associated data. This action cannot be undone.
Cascading deletion order (see lib/db/delete-profile.ts):
  1. Team invites (sent and received)
  2. Project memberships
  3. Event registrations
  4. Event projects
  5. Projects (owned)
  6. Profile record
After database deletion:
  • Logs to audit log with deleted user metadata (since target profile no longer exists)
  • Calls clerk.users.deleteUser(clerkId) to remove from Clerk
Restrictions:
  • Cannot delete super-admins
  • Cannot delete yourself

Implementation Details

Database Schema

Relevant profiles table columns (from lib/db/schema.ts:77-105):
{
  id: uuid,
  clerkId: text (unique),
  username: text (unique, nullable),
  displayName: text,
  role: userRoleEnum, // user | moderator | admin
  bannedAt: timestamp (nullable),
  bannedBy: uuid (nullable, FK to profiles),
  banReason: text (nullable),
  hiddenAt: timestamp (nullable),
  hiddenBy: uuid (nullable, FK to profiles),
  createdAt: timestamp
}

Server Actions

All moderation actions are defined in app/admin/users/actions.ts:
  • hideUser (lines 36-74)
  • unhideUser (lines 76-111)
  • banUser (lines 113-182)
  • unbanUser (lines 184-237)
  • deleteUser (lines 239-309)
Each action:
  1. Verifies actor permissions via isModerator(userId) or isAdmin(userId)
  2. Validates target user state and super-admin checks
  3. Performs database updates
  4. Syncs with Clerk (non-blocking — DB is source of truth)
  5. Logs to adminAuditLog
  6. Revalidates /admin/users path
  7. Returns { success: true } or { success: false, error: string }

Queries

User management queries are in lib/admin/queries.ts:
  • getAdminUserList() (lines 144-163): Returns all profiles ordered by creation date
  • getAdminUserDetail(profileId) (lines 165-204): Returns profile with relations (projects, registrations) and moderator names
  • getAdminUserStats() (lines 241-265): Returns counts for total, hidden, banned, and elevated users

Client Components

AdminUsersClient (app/admin/users/admin-users-client.tsx):
  • Client-side search and filtering state
  • Obfuscated field rendering for PII protection
  • Action buttons conditional on user status and current role
  • Real-time role badge and status indicators
UserDetailActions (app/admin/users/[id]/user-detail-actions.tsx):
  • Renders action buttons based on current moderation state
  • Shows unban button only to admins
  • Confirmation dialogs for destructive actions

Role Permissions Matrix

ActionUserModeratorAdmin
View user listNoYesYes
View user detailNoYesYes
Hide userNoYesYes
Unhide userNoYesYes
Ban user (user role)NoYesYes
Ban adminNoNoYes
Unban userNoNoYes
Delete userNoNoYes

Best Practices

  1. Always provide a ban reason to document moderation decisions
  2. Use hide instead of ban for temporary visibility restrictions
  3. Check audit log before reversing another moderator’s actions
  4. Verify super-admin status before attempting admin-level actions (system will prevent, but awareness helps)
  5. Review user activity (registrations, projects) before deletion to assess impact

Build docs developers (and LLMs) love