# Dashboard analytics UI — design system reference

The Navi operations console uses one composable surface for every analytics
view: a server component that fetches typed DTOs from `/v1/admin/analytics/*`
and renders them through a small set of reusable primitives.

## Component inventory

All components live under `apps/dashboard/src/components/analytics/` and
its `charts/` subdirectory.

| Component                | Server / Client | Purpose                                                                    |
| ------------------------ | --------------- | -------------------------------------------------------------------------- |
| `KpiCard`                | server          | Single number / money tile. Optional `tone`: neutral, positive, warning, critical. |
| `AnalyticsPanel`         | server          | Card wrapper with title, description, optional actions.                    |
| `AnalyticsLoadingSkeleton` | server        | Animated placeholder while data is fetching.                               |
| `AnalyticsEmptyState`    | server          | "No data yet" banner — for legitimately empty windows.                     |
| `AnalyticsErrorState`    | server          | API error banner with retry suggestion.                                    |
| `AnalyticsForbiddenState` | server         | RBAC-deny banner: tell the user they don't have access.                    |
| `RiskPanel`              | server          | Top-of-fold strip — lights up when failed syncs / pending refunds / unhealthy providers exist. |
| `ProviderHealthTable`    | server          | Tabular view of failed provider syncs with health status badges.           |
| `AnalyticsFilterBar`     | client          | Date range + provider environment filter, syncs to `searchParams`. Disabled fields render the "Coming soon" label. |
| `RevenueTrendChart`      | client          | Recharts area chart, captured + total daily payments.                      |
| `BookingStatusChart`     | client          | Recharts bar chart, bookings by status.                                    |
| `ProviderReadinessChart` | client          | Recharts bar chart, categories by operating mode.                          |
| `CustomerBehaviorFunnel` | client          | Recharts horizontal bar funnel: searches → views → saves → booking attempts. |

## Data flow

1. Server component (`apps/dashboard/src/app/(app)/overview/page.tsx`) reads
   `searchParams` and resolves the trailing 30-day window when the caller
   does not specify one.
2. RBAC visibility is computed from `getCurrentAccess()` against the shared
   constants `ANALYTICS_GLOBAL_READ_PERMISSIONS` and
   `ANALYTICS_OPERATIONAL_READ_PERMISSIONS` exported from **`@navi/config`**.
3. Server-side fetches go through `apps/dashboard/src/lib/analyticsApi.ts`,
   which wraps the cookie-aware `dashboardApi` helper and returns a tagged
   union: `{ status: 'ok', data } | { status: 'forbidden' } | { status: 'error', message }`.
4. The page passes those tagged unions to `renderState` and to the panel
   components, which choose between success / forbidden / error rendering.

## RBAC (UI visibility only)

The dashboard never makes authorization decisions. The API enforces the
same permission matrix server-side. UI visibility rules:

- `*` wildcard or any of `ANALYTICS_GLOBAL_READ_PERMISSIONS` →
  KPI grid, revenue, bookings, customer behavior, recent bookings table.
- `*` wildcard or any of `ANALYTICS_OPERATIONAL_READ_PERMISSIONS` →
  provider readiness chart, provider health table.
- Neither → `AnalyticsForbiddenState` covers the whole page.

A Support agent with only `provider_integration.health.read` should see
the provider sections and *only* those — the global panels render
`AnalyticsForbiddenState` when the API responds 403.

## Brand palette

The analytics surface uses the existing Navi token vocabulary:

- Primary blue `#2563eb` for captured payments and KPI accents.
- Cyan `#06b6d4` for total payment volume and search funnel top.
- Emerald `#10b981` for healthy / live-ready / "all clear".
- Amber `#f59e0b` for warning tones (pending partner reviews, refund queue).
- Red `#ef4444` for critical tones (provider errors, failed syncs).
- Slate (`#475569`, `#94a3b8`) for muted secondary text.

Card chrome reuses the existing `--navi-border` (`#e6eaf0`), 18–24px
radii, and the soft 4px shadow elevation already in use elsewhere in
the dashboard.

## Adding a new analytics panel

1. Add the DTO to `packages/types/src/analytics.ts` and a Zod query schema
   to `packages/validators/src/analytics.ts`.
2. Add a new endpoint and tests in `apps/api/src/modules/analytics/`.
3. Add a fetch helper to `apps/dashboard/src/lib/analyticsApi.ts` that
   returns `AnalyticsResult<TheNewDto>`.
4. Create a panel using `AnalyticsPanel`, render the success branch with
   either tabular data or a `'use client'` Recharts component.
5. Decide which permission group it belongs to (global vs operational) and
   gate it via `canSeeGlobal` / `canSeeProviders` in the page.
6. Document the new panel here and in `docs/qa/dashboard-overview-checklist.md`.

## What this page is NOT

- Not authoritative for permissions. The API always re-checks.
- Not a place to embed mock data. If real data isn't available, show
  empty / forbidden / error states. Never inline placeholder values that
  look real.
- Not a destination for highly interactive client logic. Anything stateful
  beyond the filter bar should be a dedicated route.
