Dashboard
Dashboard information architecture, navigation, role-aware homes, and shared shell behavior.
Overview
The dashboard is the authenticated product shell. It is not a single generic home page; it is a set of role-aware operational surfaces rooted under:
/dashboard/dashboard/admin/dashboard/content/dashboard/organization/dashboard/settings/dashboard/test
All dashboard routes are locale-prefixed at runtime, for example
/en/dashboard/content/pages.
Route Groups
Dashboard routes are organized by user intent:
| Section | Route root | Purpose |
|---|---|---|
| Home | /dashboard | Permission-aware navigation hub for visible dashboard sections and quick links. |
| Admin | /dashboard/admin | Platform health and superadmin controls. |
| Content | /dashboard/content | CMS, media, pages, sections, components, data, design tokens, and transactional emails. |
| Organization | /dashboard/organization | Organization billing, plans, code access, members, and organization settings. |
| Settings | /dashboard/settings | Personal account, security, preferences, organizations, and developer API keys. |
| Test | /dashboard/test | Internal authorization and route diagnostics. |
Sidebar parent items are navigable section dashboards. A parent route must never point at a hidden or missing page. This keeps keyboard command navigation, breadcrumbs, and direct links predictable.
Shared Shell
The dashboard shell provides:
- authenticated layout and active-organization checks
- sidebar navigation
- app bar actions
- breadcrumbs
- command menu
- active organization switcher
- user menu
- focus overlay for guarded dashboard content
Server-side dashboard reads use an effective active organization resolved from the Better Auth session and the user's organization memberships. When the stored Better Auth active organization is missing or no longer belongs to the user, the server falls back to the user's default organization and then to the first membership. Dashboard view models, navigation filtering, and server actions must rely on this server session context rather than waiting for client-side organization hydration.
Key files:
src/app/[locale]/dashboard/layout.tsxsrc/blocks/dashboard/navigation/*src/blocks/dashboard/auth-checker.server.tsxsrc/blocks/dashboard/auth-checker.client.tsxsrc/blocks/dashboard/section-dashboard/index.tsx
Dashboard routes should use PageDashboard or the local dashboard block
patterns rather than creating unrelated page chrome.
Section Dashboards
Section dashboards are compact route-root pages that summarize useful health signals for the current section. They prevent sidebar parents from behaving like non-clickable labels without repeating the page title already owned by the dashboard app bar.
The dashboard shell renders a desktop shared section navigation bar in a sticky
subheader directly under the dashboard app bar, with breadcrumbs above it when
the breadcrumb flag is active. It is derived from the filtered sidebar tree and
only lists child routes for the active section, so it stays compact,
permission-aware, and focused on local subsection navigation instead of
duplicating the top-level dashboard sections.
The breadcrumb trail and section navigation bar are controlled independently by
the dashboard-breadcrumbs-enabled and
dashboard-section-navigation-enabled managed feature flags.
Current section dashboards:
/dashboard/admin/dashboard/content/dashboard/organization/dashboard/settings/dashboard/test
Each section dashboard should:
- rely on the shell-level section navigation for visible child links
- respect authz visibility
- show operational cards, charts, and action prompts that are specific to that section
- avoid duplicating hidden admin, billing, or top-level navigation actions through standalone shortcut cards
Role-Aware Home
The main /dashboard route is the permission-aware navigation home. It is
driven by a server view-model that reads the filtered dashboard sidebar tree and
turns visible section roots into cards plus a short set of quick links.
Because the home page derives from navigationConfig.nav.sidebar.groups after
filterNavigationByPermissions(...), future dashboard pages can appear on the
home page by being added to the normal sidebar model and passing the same authz
filters. Do not maintain a second home-page shortcut registry.
All authenticated users:
- receive section cards for the dashboard roots visible to their role
- receive quick links generated from visible child routes
- see active organization context when one is available
- do not receive duplicated organization health, billing, content, revenue, or provider analytics on the home page
Key services:
src/lib/server/services/dashboard/dashboard-home.tssrc/lib/server/services/dashboard/dashboard-analytics.tssrc/lib/server/services/dashboard/cms-dashboard.tssrc/lib/server/services/dashboard/dashboard-sources.ts
Metric reads are server-only and flow through a shared dashboard source
contract. Database, PostHog, Stripe, and deployment sources report ready, stale,
missing_config, timeout, or error with source status metadata. Aggregate
reads use the shared Next.js Data Cache for 5 minutes, keyed by route,
timeframe, organization, and access scope, with in-flight metric coalescing to
avoid duplicate cold-cache reads during server render and client refresh. A
short in-process last-good snapshot keeps previously loaded metrics visible when
a source later times out or fails. Session resolution and authorization checks
still run per request. TanStack Query may refresh these read-only dashboard
models through /api/dashboard/*, but it must not refetch automatically on
mount, focus, reconnect, or retry loops, and it must not replace server-side
authorization. Raw SQL and provider errors must stay in server logs instead of
being serialized into client view models.
Admin Dashboard
/dashboard/admin is the superadmin platform health surface. It summarizes:
- Stripe revenue and subscription health
- PostHog audience and activity
- deployment status from Vercel or static self-host metadata when configured
- registered-user growth
- failed billing webhooks
- Stripe catalog sync issues
- permission-aware admin section navigation
/dashboard/admin/users is the superadmin user-management surface. It is gated
by Yayaw user:manage, not by Better Auth user.role. It lists Better Auth
users, ban and 2FA status, default organizations, active sessions, and
organization membership counts. The detail drawer lets superadmins add a user
to another organization, change a Better Auth organization membership role,
remove a membership, set the default organization, inspect the matching Yayaw
groups, and start or stop RBAC-checked impersonation.
This page replaces the older /dashboard/admin/status route as the sidebar
entry point. Treat /dashboard/admin as the canonical platform status URL in
new docs and navigation.
Content Dashboard
/dashboard/content is the CMS health dashboard. Its primary page-focused
surface summarizes publication progress, new page creation in the selected
range, and recently updated pages, then supports that with broader CMS signals:
- sections
- media storage
- dashboard-visible CMS page view analytics and top-page rankings from PostHog when private Query API variables are configured
- CMS data models and entries
- Page AI and Section AI activity
- publication health
- section navigation to content surfaces the current user can access
The default CMS dashboard read path uses fast indexed database counters for
pages, sections, media, components, data models, and email templates so the
route renders promptly. PostHog page view reads run separately as a best-effort
provider, scoped by the cms_page_viewed event emitted by the CMS page runtime
and the CMS page scopes visible in the dashboard. Organization page views use the
active organization scope; global page views require global page:manage access
because global page:read can represent public runtime access. The dashboard
shows both the selected range total and a top-pages table ordered by views, then
degrades without blocking database counters if PostHog is unavailable. Both
database counters and page view aggregates are cached for 5 minutes with
access-aware cache keys. Set CMS_DASHBOARD_FULL_METRICS=true only after the
database is tuned for the heavier publication and activity aggregates.
Content-specific docs:
- Pages Catalog
- Sections Catalog
- Component Catalog
- CMS Data Models
- Media Library
- Design Tokens
- Transactional Email Templates
Organization Dashboard
/dashboard/organization is the section root for active-organization
operations:
- organization activity metrics
- member, content, media, and PostHog usage signals
- billing status and seat consumption
- billing summary
- plan selection
- purchased code access
- members
- organization settings
Billing surfaces intentionally stay split:
/dashboard/organization/billingfor current state and activity/dashboard/organization/plansfor checkout actions/dashboard/organization/code-accessfor purchased source-code deliverables
This split keeps plan comparison, billing history, and post-purchase access flows from crowding into one page.
Settings Dashboard
/dashboard/settings groups personal and developer settings:
- account inventory
- security posture
- profile and preference snapshots
- account profile
- security and MFA
- preferences
- joined organizations
- developer API keys
The Developer settings page uses Yayaw's custom API key block, not the generic Better Auth API key UI, because control-plane permissions are server-managed and must be written through Yayaw's permission repair/issue flow.
/dashboard/test is an internal diagnostics overview. It summarizes dashboard
route coverage, managed feature flag seeding, and authorization resource/action
contracts, then links into the route and authorization test surfaces.
Navigation Rules
Navigation should use the shared route/navigation config and @/i18n/navigation
helpers. Avoid raw next/link and raw path concatenation in dashboard
navigation components unless there is a specific route-level reason.
Rules:
- sidebar labels and command menu entries must resolve from the same route model
- breadcrumbs should reflect real navigable parents
- hidden routes should not appear in the sidebar or command menu
- parent items should have a real page, not only expandable children
- route visibility should match authz/resource gates
Authorization
Dashboard route access uses the Yayaw authorization service on top of Better Auth session and organization membership.
Important contracts:
- route checks are server-side
- generated DB actions still run
can(...) - navigation visibility does not replace server authorization
- platform user management and impersonation use
user:manage - Yayaw never treats Better Auth
user.roleas application authorization - test routes under
/dashboard/testare diagnostics only
The authorization admin page lives at:
/dashboard/admin/authorization
It supports group/role/policy inspection, quick evaluation, detail views, and audit-oriented diagnostics for the RBAC model.
Development Checklist
When adding a dashboard page:
- Add the route under the right section root.
- Add or update route metadata/navigation config.
- Ensure the parent section dashboard links to it when visible.
- Add server-side route access checks.
- Gate user-facing navigation with the same authz/resource intent.
- Add translations under
src/messages/default/dashboard.jsonandsrc/messages/fr/dashboard.json. - Update the relevant English docs.
- Add focused tests when the route changes navigation, authz, or shared dashboard view-model behavior.
Validation
Useful checks after dashboard navigation changes:
bun run check
bunx tsc --noEmit
bun test src/lib/server/authz/contracts.test.ts
bun run build