YYayaw

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:

SectionRoute rootPurpose
Home/dashboardPermission-aware navigation hub for visible dashboard sections and quick links.
Admin/dashboard/adminPlatform health and superadmin controls.
Content/dashboard/contentCMS, media, pages, sections, components, data, design tokens, and transactional emails.
Organization/dashboard/organizationOrganization billing, plans, code access, members, and organization settings.
Settings/dashboard/settingsPersonal account, security, preferences, organizations, and developer API keys.
Test/dashboard/testInternal 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.tsx
  • src/blocks/dashboard/navigation/*
  • src/blocks/dashboard/auth-checker.server.tsx
  • src/blocks/dashboard/auth-checker.client.tsx
  • src/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.ts
  • src/lib/server/services/dashboard/dashboard-analytics.ts
  • src/lib/server/services/dashboard/cms-dashboard.ts
  • src/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:

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/billing for current state and activity
  • /dashboard/organization/plans for checkout actions
  • /dashboard/organization/code-access for 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 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.role as application authorization
  • test routes under /dashboard/test are 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:

  1. Add the route under the right section root.
  2. Add or update route metadata/navigation config.
  3. Ensure the parent section dashboard links to it when visible.
  4. Add server-side route access checks.
  5. Gate user-facing navigation with the same authz/resource intent.
  6. Add translations under src/messages/default/dashboard.json and src/messages/fr/dashboard.json.
  7. Update the relevant English docs.
  8. 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