---
name: "wow-view-host"
description: "Wire the Wow View Engine into a host app over Wow V10 services: one engine with query-route sources, datasets and a view store (MemoryViewStore, WowViewStore), ViewHost, bind and routes, commands on records as declared actions, moving off fetcher-viewer. Use for @ahoo-wang/wow-view-engine hosts, including the Wow repository's ops console and Storybook. Exclude definitions (wow-view-definition), other client code, changing the engine."
---

# wow-view-host

The job: definitions exist, and an application has to show them, keep the views people save, and let people act on the records. The deliverable is a host a reviewer can merge: one engine for the application, registered once with every resource and a store; a `ViewHost` around the pages with the router, the language and the theme; a `bind` per resource with its route, its record reading and the commands on its records declared as actions; and tests that read those declarations, routes and definitions the way the engine does. What a definition declares is `wow-view-definition`; this Skill takes the definitions as given.

The engine owns the mechanism — where a command is placed, the confirmation, a selection partly able to take it, running a few at a time, progress, the refresh after, the address's `?view=` and `?id=`, light and dark. The host owns the choices: which resources, where each one's rows and saved views come from, which commands reach the screen, when each is available and what a refusal says. Write only the choices.

## What a Wow V10 service gives a host

- **Rows and descriptors:** each query model has one HTTP route, `/{context}/{aggregate}/{model}/query` with the model `snapshot` or `events`: `POST` queries, `GET` returns the capability descriptor with its version as the `ETag`.
  The clients `wow-generator` generates from the service's Manifest (`…SnapshotQueryClient`, `…EventQueryClient`), or wow-client's `SnapshotQueryClient` and `EventQueryClient`, are those routes; `viewSourceOf` from `@ahoo-wang/wow-view-store` makes one a source.
- **Datasets:** `GET /wow/dataset` lists the wide and warehouse tables the service publishes at run time; `DatasetResources` with `datasetCatalogOf` registers them.
- **Commands:** the generated command clients, which send `Wow-Wait` and read problem+json refusals.
- **Saved views:** the V10 view store service (`platform/view-store`), two Wow aggregates reached through `WowViewStore`. It takes who is asking from the caller's principal and authorizes every write itself.

## Before writing

1. Find the host's router, i18n, theme (shadcn or none, who paints dark mode), its Wow clients (generated by `wow-generator`, committed under `src/generated/`), how it authenticates (a CoSec token, or nobody signs in), and whether it renders on the server (Next.js). A page still on the deprecated `@ahoo-wang/fetcher-viewer` is rebuilt, not renamed: `references/wiring.md` has the path.
2. Collect the definitions to register and the words of their keys, per language.
3. For each resource, read the aggregate's commands and state in its Manifest or generated client: which commands a person issues on a record, and which state fields decide whether one is allowed.
4. Load `references/wiring.md` before writing the engine and the host.

## Workflow

1. **One engine, registered once.** `new ViewEngine({ resources, store, environment })` at the application's start, shared by every page. Each resource pairs a definition with its source, `viewSourceOf(queryClient)`: the client's `paged`, `cursor`, `aggregate` and `describe`, so the engine narrows each definition to the backend it runs on. A board's definition has no source. Give the fetcher a timeout (`fetcher.timeout = 60_000`): neither fetcher nor the engine sets one, and a server that never answers holds a view's opening, and the engine's query slots, for ever.
2. **Choose the store** by who must see saved views: `MemoryViewStore` for tests and demos, `localStorageSnapshot` for one browser (the ops console keeps an operator's views this way), `WowViewStore` on the V10 view store service for everyone else. Load `references/storage.md`. The store takes no tenant, owner or user: the fetcher's interceptors carry the caller, and the service decides from its roles who writes the shared views (`view-store.shared-writer`) and the stored system views (`view-store.system-writer`). `permissions` only enables buttons, by the same roles; grant `editSystem` only to the system writers.
3. **One `ViewHost` around the pages:** `engine`, `router` (`useReactRouter()` from `@ahoo-wang/wow-view-engine/react-router`, or the two-member `ViewRouter`), `locale` and `messages` (the engine's catalogue plus the definitions' words), `bindings`, and one theme path. Surfaces under it take only an id: `<DataWorkbench definitionId="orders" />`.
4. **Bind each resource.** `route(instanceId)` is the path of the page that opens a view of it (`null`: the page's default) — the engine keeps `?view=` and `?id=` in sync itself, so do not write that glue. `reading` is how one record reads in its detail. `actions` are its commands, declared. Draw your shell's navigation from `useViewNavigation()`; there is no page shell to configure.
5. **From commands to actions.** Load `references/actions.md` and decide, per command: whether it reaches the screen; the rule that makes it available, read from the record's state (declare the fields it reads in the definition's `record.rowFields`); the refusal in the audience's words; the aggregate id it goes to (read off the row when the row key is a business key); a confirmation asked for one record too (`ask` left at `'always'`) wherever it cannot be undone, `ask: 'bulk'` only where it is undone as easily, and `tone: 'danger'` only where something is lost (cancel, refund, delete), not for a routine step such as shipping; whether a selection may take it (`on`); the form or choice it needs; when its availability flips on its own (`changesAt`); and `run` resolving only after the read model shows the command (wait for the `SNAPSHOT` stage). Slots are the escape hatch, not the path.
6. **Theme and CSP are pointers, not work:** pick `theme="host"` (with `shadcn-bridge.css`) or a `preset` (with its stylesheet), `colorMode="host"` where the app already paints dark mode, and follow the engine's Content Security Policy page where the host has one. Do not hand-write token overrides or a dark-mode switch.

## Self-check

A host is done when its tests read the declarations as the engine does and they pass:

- **Actions:** `actionHarness(actions, rows, { now })` from `@ahoo-wang/wow-view-engine/testing` — each action offered where intended (`at`), available or refused with the right reason on representative rows (`state`, `bulk`), asked where intended (`asks`), and `run` sending the right command (a fake commands object).
- **Routes:** `resolveNavigation(to, bindingOf)` over the host's own bindings sends each resource's ways off to its page.
- **Definitions:** `admit` over the registered resources and committed descriptors in every language returns `[]` or only findings asserted with their reason (`wow-view-definition` owns fixing them).
- These tests and `admit` run in Node; give them a Node Vitest config where the package's own is a browser project.
- The host's type check, lint and existing tests; `references/actions.md` lists the report.

Do not re-verify by hand what these read; they run the engine's own rules.

## References

The references hold names, shapes, rules and gotchas; each links the page of https://wow.ahoo.me/typescript/view-engine/ that covers its topic in depth. Repository paths (`platform/…`, `typescript/…`) are in the Wow repository.

- `references/wiring.md`: sources over V10 query routes, datasets, the engine, `ViewHost`, `bind`, routes, navigation, the record reading, theme and CSP pointers, the route test, server rendering, and moving off fetcher-viewer. Load it first.
- `references/actions.md`: from Wow commands to declared actions, the decisions per command, an example over a command client, the harness test and the report. Load it for any command on a record.
- `references/storage.md`: choosing a store, `WowViewStore` on the V10 view store service, its roles, permissions and `editSystem`, stored and configured system views, dataset wordings, and a host nobody signs in to. Load it before choosing the store.

## Related Skills

- $wow-view-definition: what each definition declares, its words, system views and boards.
- $wow-client: the command and query clients themselves, errors and wait stages, and generating the typed clients the sources and actions use.
- $wow-migrate: a host still on 9.x clients (`@ahoo-wang/fetcher-wow`, the 9.x wow-client) or the 9.x view store moves to V10 first.
