The admin panel lives at /admin and is restricted to users whose session.user.role is "admin". It provides a central place to manage users, billing, experiments, and operational settings without touching the database directly.
Navigation items for the admin panel are configured in src/config/navigation.ts.
Features
| Feature | Description | | ----------------------- | -------------------------------------------------------------------- | | User management | List all users, change roles, delete accounts | | Subscription management | View active subscriptions and plan details | | Feature flags | Toggle features per user, per organization, or globally | | Webhooks | Outgoing webhook delivery log with retry status | | Enterprise SSO | SAML connection management (via BoxyHQ Jackson) | | Performance | Core Web Vitals dashboard (LCP, INP, CLS, FCP, TTFB) | | A/B Testing | Experiment management with weighted variants and conversion tracking | | Email domains | Custom sending domain management (via Resend Domains API) | | Waitlist | Manage waitlist signups and send invitations | | Activity log | Audit trail of admin actions | | Drip campaigns | Automated email sequences triggered by user events |
Access Control
Every admin route checks the session before rendering:
import { getAppSession } from '@/lib/auth';
import { redirect } from 'next/navigation';
const session = await getAppSession();
if (!session || session.user.role !== 'admin') {
redirect('/');
}
Non-admin users who navigate to /admin are redirected away automatically.
Server Actions
Admin mutations are handled by server actions in src/lib/actions/admin.ts. Each action validates the caller's role before proceeding.
changeUserRole
Changes a user's role (e.g. "user" → "admin" or vice versa).
import { changeUserRole } from '@/lib/actions/admin';
await changeUserRole({ userId: 'usr_abc123', role: 'admin' });
deleteUser
Permanently deletes a user account and all associated data.
import { deleteUser } from '@/lib/actions/admin';
await deleteUser({ userId: 'usr_abc123' });
Both actions are protected with requireAuth() and an admin role check. Input is validated with Zod schemas from src/lib/validation.ts.
A/B Testing
The experiment framework in src/lib/experiments/ lets you run A/B tests with:
- Weighted variants — assign traffic percentages to each variant
- Conversion tracking — measure which variant performs better
- Experiment lifecycle — create, start, pause, and conclude experiments
Manage all experiments from the admin panel under the A/B Testing section.
Feature Flags
Feature flags support three scoping levels:
| Scope | Description | | ------------ | ---------------------------------------------- | | Global | Affects all users | | Organization | Affects all members of a specific organization | | User | Affects a single user |
Toggle flags from the admin UI. Check them in code with the feature flag utilities.
Adding Admin Pages
To add a new section to the admin panel:
- Create a page at
src/app/admin/<section>/page.tsx - Add a navigation entry in
src/config/navigation.ts - Check
session.user.role === 'admin'in the page component
Next Steps
- Security — auth guards, rate limiting, and input validation
- Environment Variables — configure SSO, email, and analytics providers
- Customization — branding and white-label settings