⚡ You're viewing a live demo of ChimerAI. Data resets daily at midnight UTC.Get the CLI →

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 admin role 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

Further reading

ChimerAI Docs · Back to Demo