# Build a ZUI analytics view

Build a production-ready analytics view in this existing React and TypeScript
repository using ZUI.

First inspect the repository's package manager, router, global stylesheet,
React version, and existing UI conventions. Preserve those conventions.

## Outcome

- Add one working analytics route for: **[DESCRIBE THE BUSINESS QUESTION]**.
- Use this data contract or sample data: **[PASTE A TYPESCRIPT ROW TYPE OR 5–10 JSON ROWS]**.
- Include useful filters, 2–4 KPIs, at least one chart, and a sortable data grid.
- Filtering a shared dataset must update its KPIs, charts, and grid together.
- Keep dataset definitions in source code so changes are governed through pull
  requests. They may live in front-end code or backend code.
- Keep API fetching, credentials, authoritative access control, routing, and
  side effects in host code.

## Use these ZUI APIs

- `ViewRenderer`, `createViewRegistry`, `defineDataset`, `defineActions`, and
  `validateViewSpec`, plus the `DatasetSchema`, `FilterDescriptor`, and
  `ViewDataQuery` types, from `@zuilib/apps`.
- `coreViewTypes` from `@zuilib/apps/core`.
- `chartViewTypes` from `@zuilib/apps/charts`.
- `dataGridViewTypes` from `@zuilib/apps/data-grid`.
- `analyticsViewTypes` from `@zuilib/apps/analytics`.

Compose the registry with:

```ts
const registry = createViewRegistry(
  coreViewTypes,
  chartViewTypes,
  dataGridViewTypes,
  analyticsViewTypes,
)
```

## Implementation rules

1. Determine who owns each dataset definition from the request and existing
   architecture. Use front-end ownership by default for a view-only integration;
   use backend ownership when a shared catalog, dataset discovery permissions,
   or field-level visibility requires it. Do not define the same schema twice.
2. Keep every production dataset definition in source code, not an application
   database, so ordinary pull requests, tests, ownership rules, and deployments
   govern changes.
3. For a front-end-owned schema, declare it once with `defineDataset`. For a
   backend-owned schema, define the same JSON-compatible `DatasetSchema` object
   as a constant in the existing backend language, authorize its endpoint, fetch
   it in the React host, and pass the returned object to `datasetSchemas`.
   Include meaningful labels, descriptions, column types, enum values, formats,
   and `enableFiltering` where appropriate.
4. Treat schemas as metadata rather than a security boundary. Every data API
   must independently enforce authentication plus dataset, field, tenant, and
   row access. Never trust a filter or query payload merely because it came from
   `ViewRenderer`.
5. Create a `ViewSpec` with `version: 2`. Give every meaningful node a short,
   unique `id`.
6. Keep the `ViewSpec` inert and JSON-safe. Do not put functions, credentials,
   fetched live rows, arbitrary CSS, or executable expressions inside it.
7. Supply live rows through `<ViewRenderer datasets={{...}} />` under names
   matching the dataset schemas.
8. Fetch the initial rows in host code and communicate loading and errors to the
   renderer. `onDataRequest` is not the initial-load mechanism when using
   `ViewRenderer` directly.
9. Use `{$bind: "datasetName"}` for data props and
   `{$action: "actionName"}` for behavior.
10. Declare action names with `defineActions`; implement handlers in the host
   component's `actions` prop.
11. Use a `filter-bar` and bind related `metric`, `chart`, and `data-grid` nodes
   to the same dataset so built-in filtering and chart cross-filtering work.
12. Keep filtering client-side when all rows are already present. For a large or
    permission-scoped dataset, list its name in `serverDatasetNames`, handle the
    full `ViewDataQuery` from `onDataRequest`, refetch in host code, and pass the
    resulting rows back through `datasets`. Validate dataset names, fields,
    operators, and values before translating the query into parameterized SQL
    or a semantic-layer request.
13. Use `onFiltersChange` to observe, persist, or control the complete shared
    filter list. If the host supplies the controlled `filters` prop, it must
    update that prop from `onFiltersChange`.
14. Validate the final spec with
   `validateViewSpec(spec, registry, {datasets, actions, data})`; fix every
   error.
15. If this is Next.js or another server-first framework, put the renderer
   behind a client component.
16. Wire styling into the existing Tailwind 4 global CSS. Import the
    package-owned `tailwind.css` entries for `@zuilib/primitives`,
    `@zuilib/apps`, `@zuilib/charts`, and `@zuilib/data-grid` after Tailwind.
17. Do not invent a `zui create`, `zui analytics`, or `zui view check` command;
    none exists.
18. Do not introduce `AppSpec`, Builder, workflows, a backend, authentication,
    a database, or a model provider unless the repository, requested dataset
    ownership, or task already requires them.

If dependencies are missing, use the repository's package manager to install:

```text
@zuilib/apps @zuilib/charts @zuilib/data-grid
```

## Before finishing

- Run the relevant typecheck, tests, and build.
- Report the chosen dataset-ownership model, route, files changed, validation
  result, backend endpoints, and any host callbacks the engineering team still
  needs to connect.

Reference: https://zuilib.com/llms.txt
