Audit Log System
All administrative and moderation actions are automatically logged to theadminAuditLog table for accountability and compliance.
Database Schema
Fromlib/db/schema.ts:331-343:
actorProfileId: Admin/moderator who performed the actionaction: Action type (string identifier)targetProfileId: User who was acted upon (nullable for non-user actions)metadata: JSON-encoded context (reason, old/new values, etc.)createdAt: Timestamp of action
Logged Actions
All moderation actions automatically log to audit table:| Action | Actor Role | Target | Metadata |
|---|---|---|---|
hide_user | Moderator/Admin | User profile ID | None |
unhide_user | Moderator/Admin | User profile ID | None |
ban_user | Moderator/Admin | User profile ID | { reason: string } |
unban_user | Admin only | User profile ID | None |
delete_user | Admin only | null | { deletedProfileId, displayName, username, clerkId } |
set_role | Admin only | User profile ID | { oldRole, newRole } |
approve_mentor | Admin only | null | { applicationId, applicantName, applicantEmail } |
decline_mentor | Admin only | null | { applicationId, applicantName, applicantEmail } |
delete_user sets targetProfileId to null because the profile record is deleted before logging. Metadata preserves identifying information.Audit Log Viewer
Access Requirements:Requires
admin role to access /admin/auditapp/admin/audit/page.tsx:8.
Features:
- Displays all audit entries in reverse chronological order
- Shows actor name (via
display_namejoin) - Shows target name (if applicable, via left join)
- Displays action type and metadata
- Timestamp for each entry
lib/admin/queries.ts:217-239):
profiles twice (once for actor, once for target).
Ban Workflow
A comprehensive process for permanently blocking abusive users.Initiating a Ban
- Navigate to
/admin/usersor/admin/users/[id] - Click the ban icon (block symbol)
- Dialog prompts for optional ban reason
- Confirm action
Server Action Flow
Fromapp/admin/users/actions.ts:113-182:
- Authorization: Verify actor is moderator/admin
- Validation:
- User exists and is not already banned
- Target is not a super-admin
- Moderators cannot ban admins
- Cannot ban yourself
- Database Update:
- Clerk Sync (non-blocking):
Disables authentication. If Clerk call fails, Sentry reports but DB ban remains (source of truth).
- Audit Log:
- Revalidation:
revalidatePath("/admin/users")
Middleware Redirect
Banned users are automatically redirected byapp/proxy.ts:
Ban Page
app/banned/page.tsx displays:
- Ban notice
- Ban reason (if provided)
- Support contact link
/admin/users.
Unbanning
Permission: Admin only Fromapp/admin/users/actions.ts:184-237:
clerk.users.unbanUser(clerkId) to restore authentication.
Unbanning automatically unhides the user to ensure full account restoration.
Hide Workflow
A softer moderation action that removes profiles from public view without blocking authentication.Use Cases
- Temporary content policy violations
- Suspicious accounts under investigation
- User-requested profile privacy during sensitive situations
Hide vs Ban
| Feature | Hide | Ban |
|---|---|---|
| Profile visible in public lists | No | No |
| Can sign in | Yes | No |
| Can edit own profile | Yes | No |
| Can create projects | Yes | No |
| Reversible by moderators | Yes | No (admin only) |
| Clerk authentication disabled | No | Yes |
Server Action Flow
Fromapp/admin/users/actions.ts:36-74:
- User not already hidden
- Target is not a super-admin
Public Query Filtering
All public-facing queries filter out hidden and banned profiles viaisProfileVisible helper in lib/queries.ts:
getHackathonProfiles(): List pagegetProfileByUsername(): Detail pagegetHackathonProjects(): Project list (owner must be visible)getProjectBySlug(): Project detail (owner must be visible)
Mentor Application Review
Access Requirements:Requires
admin role to access /admin/mentorsapp/admin/mentors/page.tsx:11.
Application Schema
Fromlib/db/schema.ts:365-387:
Review Interface
Navigate to/admin/mentors to view:
- Statistics: Total applications, pending count, approved count, declined count
- Application list: All applications with status badges
- Details: Expand to see mentor type, background, availability
- Actions: Approve or decline pending applications
Approval Workflow
Fromapp/admin/mentors/actions.ts:20-69:
- Verify actor is admin
- Fetch application and check status is
pending - Update application:
- Log to audit:
- Revalidate
/admin/mentors
Approving a mentor application does not automatically assign a role. Admins must separately grant
moderator or admin role via /admin/roles if elevated permissions are needed.Decline Workflow
Fromapp/admin/mentors/actions.ts:71-120:
status: "declined" and logs "decline_mentor" action.
Public Submission Form
Mentor applications are submitted via/mentor-apply (public, no auth required):
- Collects contact info, social handles, mentor types, background, availability
- Validates email uniqueness (DB constraint)
- Inserts into
mentorApplicationswithstatus: "pending" - Fires Discord notification via
notifyMentorApplicationwebhook
app/mentor-apply/actions.ts.
Best Practices
Audit Log
- Review regularly to detect suspicious patterns (e.g., mass bans, frequent role escalations)
- Export for compliance if required by data protection regulations
- Reference before reversing actions to understand original context (especially ban reasons)
Moderation
- Default to hide for first offenses unless behavior is egregiously abusive
- Always provide ban reasons — logged metadata helps future reviewers understand context
- Coordinate with team before unbanning to ensure consensus on policy violations
- Monitor ban page traffic via analytics to track how many users hit the ban wall
Mentor Applications
- Respond to pending applications within 7 days to maintain applicant trust
- Document decision criteria in team guidelines (experience level, availability, mentor type balance)
- Follow up with approved mentors via email to onboard and assign Discord roles (manual process)
- Track approval rate (stats displayed on
/admin/mentors) to ensure consistent standards