Dashboard and Settings
Navigate the authenticated dashboard surface and its flag-gated settings and admin tabs.
The dashboard is the authenticated surface at config.routes.dashboard (/dashboard), a Server Component that fetches GET /dashboard/status (packages/api/src/routes/internal/dashboard.ts) once on the server. Its tabbed sub-surfaces come from the shared sectionTabsConfig in @repo/config (packages/config/src/section-tabs.ts), where each tab declares optional requires (feature flags) and orgRoles gates so anything the viewer or active config can't access hides automatically.
Dashboard surface
The page renders from one server-side fetch - no client loading spinner. The metric row, security/team grid, usage chart, and quick-actions/recent-activity grid all hydrate from the single /dashboard/status payload.
| Metric card | Source field |
|---|---|
| Current plan | planName (falls back to free-plan label) |
| Plan status | planType + isActive (free / lifetime / active / inactive) |
| Security score | security flags, scored 0-2 |
| Team members (multi-tenant) or Member since (single-tenant) | team.memberCount or organizationCreatedAt |
Dashboard status payload
GET /dashboard/status (auth-guarded) returns plan, security, and team stats (multi-tenant only).
// GET /dashboard/status - packages/api/src/routes/internal/dashboard.ts
{
planName, planId, planType, planExpiresAt, isActive,
organizationCreatedAt, // null when single-tenant / no active org
security: { twoFactorEnabled, emailVerified, activeSessionCount, passkeyCount },
team: config.tenancy.multiTenant
? { memberCount, pendingInviteCount, userRole }
: null, // null when single-tenant
}planType is "free" | "lifetime" | "subscription" | null (derived from the resolved billing plan). When config.tenancy.billingScope is not "user", the endpoint returns 400 No active organization if the session has no active org.
Settings tabs
sectionTabsConfig.settings drives the /settings sub-tabs. Profile, Billing, and Security are always present; Developers is flag-gated.
| Tab | Route | Gate |
|---|---|---|
| Profile | /settings/profile | always on |
| Billing | /settings/billing | tab always present; sections gated by config.payment.enabled |
| Security | /settings/security | always on |
| Developers | /settings/developers | requires: ["apiKeys"] |
The Billing tab always renders, but its page sections only appear when config.payment.enabled is true (default true). With payments off, the tab shows nothing actionable.
When config.tenancy.multiTenant is true, an Organization group (sectionTabsConfig.organization) is added:
- Overview:
/settings/organization,match: "exact". - Activity:
/settings/organization-activity, gatedorgRoles: ["owner", "admin"].
Admin panel
The admin panel lives under the (dashboard)/admin route group. Access is enforced server-side in admin/layout.tsx: any session whose user.role !== "admin" is redirected to config.routes.loginRedirect (/dashboard). The sidebar link is separately hidden by roles: ["admin"] in the per-app config/sidebar.ts, so non-admins never see the entry.
Its tabs come from sectionTabsConfig.admin. The whole panel is role-gated by the layout, so individual tabs carry no roles gate - only requires feature flags hide a tab from admins:
| Tab | Route | Tab gate |
|---|---|---|
| Users | /admin/users | none (panel role-gated) |
| Organizations | /admin/organizations | requires: ["multiTenant"] |
| Audit logs | /admin/audit-logs | none (panel role-gated) |
| Billing logs | /admin/billing-logs | none (panel role-gated) |
| API keys | /admin/api-keys | requires: ["apiKeys"] |
| Announcements | /admin/announcements | none (panel role-gated) |
config.routes.admin is /admin/users (the default landing route), not /admin. /admin itself redirects to config.routes.admin, preserving any query string.
Frequently asked questions
Why does the Billing tab show but Developers does not?
Billing is always present so users can view their plan, while Developers carries requires: ["apiKeys"]. When the apiKeys flag is off, the Developers tab is removed from settings.
How do I get the Organization tabs?
Enable config.tenancy.multiTenant. That adds the Organization group (Overview + Activity) to settings and the Organizations tab to the admin panel.
Who can see the admin panel?
Only users with user.role === "admin". admin/layout.tsx redirects everyone else to config.routes.loginRedirect, and the sidebar link is hidden via roles: ["admin"] in config/sidebar.ts - see authorization for how roles are assigned and checked.
Navigation
Configure the Next.js navbar, sidebar, user menu, and section tabs from typed config, with role, org-role, and feature-flag gating plus i18n labels.
Banners
Add marketing and dashboard announcement banners in your Next.js SaaS, toggled by config.banner with role and plan targeting and dismissal.