Admin Panel
ChimerAI includes a built-in Admin Panel with workspace overview, user statistics, system health monitoring, and quick-access controls — all protected by role-based access control.
What you get
- Dashboard overview — Active users, MRR, storage usage, API call counts
- Quick actions — Impersonate users, force-reset passwords, clear caches
- System health — DB connection, Redis latency, AI service status
- Workspace management — View and manage all tenants (multi-tenant mode)
- Config editor — Update feature flags without redeployment
- RBAC protection — Only
adminrole can access; nested route protection
Quick setup
npx chimerai add admin
Scaffolds:
app/admin/layout.tsx ← Admin shell (auth guard + nav)
app/admin/page.tsx ← Dashboard
app/api/admin/stats/route.ts ← Metrics endpoint
app/api/admin/health/route.ts ← Health check
lib/admin.ts ← Admin helpers
middleware.ts (updated) ← /admin/* protection
Protecting the admin section
// app/admin/layout.tsx
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { redirect } from 'next/navigation';
export default async function AdminLayout({ children }: { children: React.ReactNode }) {
const session = await getServerSession(authOptions);
if (session?.user?.role !== 'admin') redirect('/');
return (
<div className="min-h-screen flex">
<AdminSidebar />
<main className="flex-1 p-8">{children}</main>
</div>
);
}
Stats endpoint
// app/api/admin/stats/route.ts
import { db } from '@/lib/db';
export async function GET() {
const [userCount, workspaceCount, messageCount] = await Promise.all([
db.user.count(),
db.workspace.count(),
db.message.count(),
]);
return Response.json({ userCount, workspaceCount, messageCount });
}
Health check endpoint
// app/api/admin/health/route.ts
import { db } from '@/lib/db';
import { redis } from '@/lib/redis';
export async function GET() {
const checks = await Promise.allSettled([
db.$queryRaw`SELECT 1`,
redis.ping(),
fetch(process.env.AI_SERVICE_URL + '/health'),
]);
return Response.json({
database: checks[0].status === 'fulfilled' ? 'ok' : 'error',
redis: checks[1].status === 'fulfilled' ? 'ok' : 'error',
aiService: checks[2].status === 'fulfilled' ? 'ok' : 'error',
timestamp: new Date().toISOString(),
});
}
Feature flags
// lib/feature-flags.ts
export const FEATURES = {
webhooks: process.env.FEATURE_WEBHOOKS === 'true',
guardrails: process.env.FEATURE_GUARDRAILS === 'true',
mfa: process.env.FEATURE_MFA === 'true',
} as const;
export type FeatureFlag = keyof typeof FEATURES;
// Usage in any component:
import { FEATURES } from '@/lib/feature-flags';
if (!FEATURES.guardrails) return null; // Feature disabled