Admin Panel
The app/admin/ route group provides a comprehensive administration dashboard for super administrators. It covers platform analytics, user management, content moderation, billing, AI operations monitoring, and system monitoring.
Admin Sections
| Section | Route | Purpose |
|---|---|---|
| AI Agents | /admin/ai-agents/ | Agent management + AI operations monitoring (tokens, credits, logs) |
| Applications | /admin/applications/ | View and manage all job applications across the platform |
| Audit Logs | /admin/audit-logs/ | Activity audit trail for compliance and debugging |
| Collaborators | /admin/collaborators/ | Manage collaborator relationships and permissions |
| Companies | /admin/companies/ | Company statistics + searchable company list with suspend/reactivate/transfer actions |
| Connections | /admin/connections/ | View and manage partnership connections |
| CV Processing | /admin/cv-processing/ | Monitor CV parsing pipeline status and errors |
| Emails | /admin/emails/ | Email delivery statistics and log with resend capability |
| Feature Flags | /admin/feature-flags/ | Platform feature flag CRUD management |
| Interviews | /admin/interviews/ | View all scheduled interviews across the platform |
| Jobs | /admin/jobs/ | Job statistics + searchable job list with status moderation |
| Maintenance | /admin/maintenance/ | Maintenance-mode toggle: lock out landing, companies, and/or jobseekers with a scheduled end time |
| Media Manager | /admin/media-manager/ | Upload, compress, and manage media files (uses FFmpeg) |
| Notifications | /admin/notifications/ | System notification management |
| Onboarding | /admin/onboarding/ | User onboarding flow management |
| Payments | /admin/payments/ | Revenue stats + subscription list + enterprise subscription management |
| Plans | /admin/plans/ | Subscription plan configuration (features, limits, pricing) |
| Promo Codes | /admin/promo-codes/ | Create and manage promotional codes |
| Settings | /admin/settings/ | System-wide settings (credits, invoices, roles, schema) |
| System | /admin/system/ | System logs and monitoring (live log streaming) |
| Talent Pools | /admin/talent-pools/ | View all talent pools across the platform |
| Users | /admin/users/ | User statistics + super admin management (grant/revoke) |
Tabbed Pages
Several admin pages use TWTabProvider to organize statistics alongside operational data:
Companies (/admin/companies/)
| Tab | Content |
|---|---|
| Statistics | Platform-wide company stats (total, active, subscription breakdown) |
| Company List | Paginated, searchable company table with status filter. Row click opens detail modal with suspend, reactivate, and ownership transfer actions |
Jobs (/admin/jobs/)
| Tab | Content |
|---|---|
| Statistics | Job posting stats (total, by status, recent activity) |
| Job List | Paginated job table with search, status, and company filters. Row click opens detail modal with status update action (NEW, IN_PROGRESS, PENDING_FEEDBACK, CLOSED, FUTURE_REQUESTS, DRAFT) |
Payments (/admin/payments/)
| Tab | Content |
|---|---|
| Revenue Stats | Revenue overview, transaction history, refund tracking |
| Subscriptions | Paginated subscription list with status filter. Row click opens detail modal with extend, cancel, and change plan actions |
| Enterprise | Enterprise subscription management — create, approve/reject, block/restore access, generate invoices, mark invoices paid, view usage breakdown. Supports both company-scoped and personal (companyId=null, tied to a billing-owner user) subscriptions throughout. See Enterprise Post-Paid Billing. |
Users (/admin/users/)
| Tab | Content |
|---|---|
| Statistics | User registration stats, role breakdown |
| Super Admins | List of super admin users with grant/revoke capability |
Delete taxonomy (SOFT vs HARD)
User deletion exposes an explicit SOFT / HARD choice on both surfaces. The mutations themselves (adminDeleteUser, adminBulkDeleteUsers) are covered in the Admin API Reference; this section documents the panel behavior.
- SOFT — deactivate (reversible). Flips the user inactive; data is preserved.
- HARD — permanent purge. Passes
confirmHardDelete: true, cascade-deletes the user's data, leaves only theAdminAuditLogrow. No undo.
Detail page (app/admin/users/[id]/page.tsx): a Close User Account button opens a confirmation modal with a SOFT/HARD picker, default SOFT. confirmHardDelete: true is sent only when HARD is chosen. When the account is already inactive the button reads "Account Already Closed".
List page (app/admin/users/list/page.tsx): the per-row trash icon opens the same modal SOFT-preselected. The bulk actions bar has two explicit buttons — Deactivate (SOFT) and Permanent Delete (HARD) — and bulk-delete opens the modal HARD-preselected, matching the historical bulk convention.
Single-row deletes preselect SOFT (deactivate), but the bulk Permanent Delete button preselects HARD. Both paths still surface the full SOFT/HARD choice before confirming — read the modal's selected option, not the button you clicked. Before assuming a user is "missing", check the AdminAuditLog: a bulk action may have HARD-purged the row.
HARD delete can fail on a backend foreign-key cascade gap (e.g. ContactToContactTypes lacks onDelete: Cascade, so any user with contacts blocks the purge). Both pages intercept that error into a friendly toast — "Permanent delete blocked by backend cascade … Use Deactivate for now." — instead of the raw GraphQL error. Tracked as handoff #16; SOFT delete continues to work.
AI Agents (/admin/ai-agents/)
| Tab | Content |
|---|---|
| Agents | Agent configuration management |
| AI Operations | Operations overview (total ops, tokens, credits, success/failure), type breakdown, top consumers, paginated operation logs with filters |
Credits (/admin/settings/credits/)
| Tab | Content |
|---|---|
| Packs | Credit pack CRUD |
| Config | Credit cost configuration per AI model |
| Balances | Credit statistics (total in circulation, consumed, earned), top consumers, searchable balance list with adjust credits action |
New Pages
Feature Flags (/admin/feature-flags/)
Single-page CRUD for platform feature flags. Supports create, edit, and delete operations.
- Table columns: Key, Value, Type (string/boolean/number/json), Description, Updated At
- Create/edit via modal form with key, value, type selector, and description fields
- Delete with confirmation dialog
Maintenance Mode (/admin/maintenance/)
Dedicated UI for toggling platform-wide maintenance. Writes 8 dedicated maintenance_* keys into the same SystemSetting table that powers generic feature flags, but surfaces them as a single form with three lock checkboxes, an optional auto-reactivation timestamp, user-facing message/reason fields, and a live preview of the MaintenanceScreen non-superadmin users will see.
- Lock targets (independent): Landing, Companies, Jobseekers
- Auto-reactivation:
maintenance_ends_at— when this time passes, the backend forces all three locks off regardless of their stored values (authoritative server-side expiry) - Content:
maintenance_reason(short),maintenance_message(long),maintenance_support_contact,maintenance_status_page_url— all optional, empty strings hidden on screen - Emergency exit: "End maintenance now" button flips all three locks off and clears the schedule in one go
Frontend consumption:
lib/hooks/useMaintenanceMode.ts— queriespublicSiteStatus(public, no auth) every 60s witherrorPolicy: "ignore"components/visitor/landing/LandingPageGate.tsx— gates the public landing pagecomponents/auth/authGuard.tsx— gates authenticated routes per role (companies vs jobseekers)app/auth/signin/page.tsx— gates the signin screen; supports?bypass=1escape hatch- Super-admin bypass:
user.isSuperAdminalways skips the lock (client-side check; the backend resolver stays dumb-public)
See the Maintenance Mode Runbook for operational steps.
Emails (/admin/emails/)
| Tab | Content |
|---|---|
| Overview | Email delivery statistics — total, sent, failed, pending, delivery rate |
| Email Log | Paginated email list with search, status, and date range filters. Row click opens detail modal showing full content. Failed emails can be resent |
Settings Sub-Sections
The /admin/settings/ route has nested configuration pages:
| Route | Purpose |
|---|---|
credits/ | Credit packs, cost config, and balance management (3 tabs) |
invoices/ | Invoice template configuration |
roles/ | Role-based access control (RBAC) configuration |
schema/ | Database schema inspection tools |
System Monitoring
The /admin/system/ page provides live system log streaming via the useLogStream hook, which connects to the backend's logStream GraphQL subscription (super admin only).
Responsive Design
The admin panel is fully responsive across mobile (>=320px), tablet (>=768px), and desktop (>=1024px). Key responsive patterns:
Sidebar (Mobile Drawer)
On mobile (<768px), the sidebar is hidden by default and replaced by a hamburger menu in the header. Tapping the hamburger opens a full-height slide-out drawer (w-64) with a semi-transparent backdrop. Tapping any nav item or the backdrop closes the drawer.
On desktop (>=768px), the sidebar retains its collapsible behavior (icon-only w-17 or full w-64).
Key files:
AdminSidebar.tsx— acceptsmobileOpenandonMobileCloseprops; renders two<aside>elements (mobile drawer + desktop sidebar)AdminLayout.tsx— managesmobileOpenstate and renders the hamburger button (md:hidden)useIsMobilehook (lib/hooks/useIsMobile.ts) —matchMedia-based breakpoint detection (SSR-safe)
Tables
AdminTable supports a hiddenOnMobile flag on column definitions — columns marked hiddenOnMobile: true receive hidden md:table-cell classes. All tables are wrapped in overflow-x-auto for horizontal scrolling on small screens. Pagination stacks vertically on mobile (flex-col sm:flex-row).
Stat Grids
AdminStatsGrid encapsulates the responsive grid pattern used across all admin pages: grid-cols-1 sm:grid-cols-2 md:grid-cols-{cols}. The cols prop (2–6, default 4) controls the desktop column count.
Modals
TWModal goes near-full-screen on mobile: max-w-full sm:max-w-{size}, with reduced padding (p-2 sm:p-4 wrapper, p-4 sm:p-6 body) and a taller max-height (max-h-[calc(100dvh-140px)] sm:max-h-[65vh]).
Filters
Filter inputs use min-w-0 w-full sm:min-w-[200px] sm:w-auto to stack full-width on mobile and sit inline on larger screens. AdminFilterBar uses gap-2 sm:gap-4 responsive gaps.
Tab Bars
Pages with many tabs (AI Agents, System, Credits, Schema) use overflow-x-auto scrollbar-hide for horizontal scrolling, with text-xs sm:text-sm tab text and whitespace-nowrap.
Admin Components
Admin-specific components live in components/admin/:
| Directory | Purpose |
|---|---|
ai-agents/ | AI agent management and operations monitoring |
companies/ | Company list, detail modal with actions |
credits/ | Credit balance detail modal |
emails/ | Email overview, log, and detail modal |
feature-flags/ | Feature flag form modal |
jobs/ | Job list, detail modal with status update |
layout/ | Admin layout wrappers (AdminGuard, AdminSidebar, AdminLayout) |
payments/ | Subscription list/detail, enterprise tab, usage modal |
promo-codes/ | Promo code management UI |
shared/ | Reusable admin components (see below) |
support/ | Support ticket overview and agent stats |
system/ | System monitoring UI |
users/ | Super admin management tab, documentation access tab |
Shared Admin Components (components/admin/shared/)
A library of reusable components ensuring consistent UI across all admin pages:
| Component | Props | Purpose |
|---|---|---|
AdminStatCard | label, value, color?, format? | Responsive stat card with color variants (gray/blue/green/purple/orange/red) and format options (number/currency/percent/raw). Font and padding scale with breakpoints |
AdminStatsGrid | children, cols? | Responsive grid wrapper: grid-cols-1 sm:grid-cols-2 md:grid-cols-{cols}. Default 4 columns on desktop. Replaces the repeated inline grid pattern across pages |
AdminTable | columns, data, onRowClick?, page?, totalPages?, onPageChange?, totalCount?, emptyMessage?, bare? | Paginated data table with column renderers and hiddenOnMobile column flag. bare mode skips the card wrapper for embedding inside existing cards |
AdminFilterBar | children, hasFilters, onClear, className? | Filter input wrapper with "Clear Filters" button and responsive gaps |
AdminLoadingSkeleton | count?, type?, cols? | Loading skeleton (rows or card grid) with responsive breakpoints |
AdminErrorCard | title, message? | Centered error display card with responsive max-width and padding |
AdminDetailField | label, children | Label + value pair for detail modals |
formatAdminDate() | (dateString) | Formats date as locale string (date only) |
formatAdminDateTime() | (dateString) | Formats date as locale string (date + time) |
Component Patterns
All admin components follow consistent patterns:
- Data fetching:
useQuerywithfetchPolicy: "cache-and-network";useLazyQueryfor modals that load on open - Loading:
AdminLoadingSkeleton(rows for tables, cards for stat grids) - Errors:
AdminErrorCardwith title and message - Tables:
AdminTablewith typed column definitions, optional row click, andhiddenOnMobileper column - Filters:
AdminFilterBarwrappingTWInput/TWSelectfields with responsive stacking - Stat cards:
AdminStatsGrid+AdminStatCardwith responsive grid and typography - Detail modals:
TWModal(full-screen on mobile) withAdminDetailFieldgrid layout - Mutations:
useMutationwithrefetchQueries,addTWToastfor success/error feedback - Destructive actions:
TWConfirmDialog(usesisLoadingprop, notloading) - Toasts:
addTWToast({ title, description?, color, timeout })
Media Manager
The media manager at /admin/media-manager/ provides:
- File upload and browsing
- Image/video compression (via FFmpeg)
- Bulk media operations
- Media replacement for existing records
GraphQL Operations
Admin GraphQL operations are organized in two files:
graphql/operations/admin/queries.ts— 21+ admin queries (stats, lists, detail fetches)graphql/operations/admin/mutations.ts— 19+ admin mutations (CRUD, status changes, credit adjustments)
See the Admin API Reference for the complete operation inventory.