Admin layout
The admin cluster has its own sub-sidebar within the main dashboard. All /admin/* routes share this chrome.
Shape
┌─────────────────────────────────────────────────────────────────┐
│ Main sidebar (264px) │ Admin sub-sidebar (220px) │
│ (global nav) │ (admin-specific nav) │
│ │ │
│ + New │ Admin (52px header) │
│ 🏠 Home │ │
│ 🗂 Projects │ ── MANAGE │
│ 📖 Library │ Overview │
│ 👤 Admin (active) │ Users │
│ 🛡 Engineer │ Organization │
│ │ Share requests [2] │
│ │ │
│ │ ── INSIGHTS │
│ │ Audit log │
│ │ Usage stats │
│ │ │
└─────────────────────────────┴────────────────────────────────────┘
│ Full-width content │
│ (no max-w-*) │
└────────────────────┘
AdminPageShell
Every admin page wraps with <AdminPageShell>:
export default function UsersPage() {
return (
<AdminPageShell
title="Users"
subtitle="2 of 2 users"
breadcrumb={[
{ label: "Admin", href: "/admin" },
{ label: "Users" },
]}
right={<Button variant="primary" size="sm" onClick={openAdd}>Add user</Button>}
>
{/* your page content — already full-width, padded */}
<UsersTable />
</AdminPageShell>
);
}
<AdminPageShell> provides:
- Topbar with title + breadcrumb + right slot
- Padding
px-6 py-6on content area - Full-width content — do not add
max-w-*inside
Why full-width
The admin area already has a 220px sub-sidebar eating horizontal space. Adding max-w-5xl or max-w-6xl on the content wrapper pinches the KPI grid into wrapping on normal laptop screens (1440px).
Rule (AGENTS.md):
Admin page content is full-width. Do NOT set
max-w-*on the wrapper div insideAdminPageShell. Use<div className="flex flex-col gap-4">or similar — padding comes fromAdminPageShellitself.
Section grouping in the sub-sidebar
Sub-sidebar items group by section:
const ITEMS: NavItem[] = [
{ href: "/admin/overview", label: "Overview", section: "Manage" },
{ href: "/admin/users", label: "Users", section: "Manage" },
{ href: "/admin/organization", label: "Organization", section: "Manage" },
{ href: "/admin/share-requests", label: "Share requests", section: "Manage", badge: 2 },
{ href: "/admin/audit-log", label: "Audit log", section: "Insights" },
{ href: "/admin/usage", label: "Usage stats", section: "Insights" },
];
Sections render with small uppercase muted headers. No "Development" section in prod — the design/access previews are now in the docs site, not the admin area.
Pages
| Route | Purpose |
|---|---|
| /admin/overview | KPI dashboard |
| /admin/users | User list + add/edit/delete |
| /admin/organization | Department tree + groups |
| /admin/departments/:id | Dept detail: members + groups + project grants |
| /admin/share-requests | Approve/reject share requests |
| /admin/audit-log | Filter audit events |
| /admin/usage | LLM token + cost summary |
Each is one page component. No deeper nav inside admin — if a single page needs sub-sections, use <Tabs>.
Don't
- Don't add
max-w-*anywhere inside AdminPageShell - Don't double-up topbars — AdminPageShell handles the topbar; the page just passes props
- Don't build custom sub-sidebar items — add to the
ITEMSarray with a section label