KB-6265

08 — Nuxt Render-Shell Implementation Pack (Branch G)

4 min read Revision 1
registries-pivotnuxtrender-shelldieu28no-business-logicconvergencepack-only2026-05-31

title: 08 — Nuxt Render-Shell Implementation Pack (Branch G) date: 2026-05-31 status: implementation PACK only — NO production Nuxt change

08 — Nuxt Render-Shell Implementation Pack (Branch G)

Production-ready spec for the converged surface. Not implemented — no Nuxt change this macro. Nuxt renders only registered templates; no business logic, no hardcode, no local count/label/pin math (Đ28 NT-D1/NT-D3, Test-4).

Route plan

  • Canonical: /knowledge/registries-pivot (ONE page; no 3rd page).
  • Keep /knowledge/pivot (clean render-shell over pivot_results) as the structural basis.
  • Converge /knowledge/registries (the legacy Đ28 page) onto the canonical route at cutover (doc 09); until then /knowledge/registries stays as-is.

Component structure (all dumb/presentational; data via fetch)

pages/knowledge/registries-pivot/index.vue        // shell: layout + section slots only
  ├─ RootSummaryCards.vue        ← /grand-total (PIV-500) + /integrity summary
  ├─ DisagreeingTotals.vue       ← the 6 totals, each tagged source/trusted
  ├─ CountIntegrityPanel.vue     ← /integrity (status FAILED honest)
  ├─ DriftTable.vue              ← /drift (source_model classification)
  ├─ PivotTreeDrill.vue          ← /tree + recursive drill (count>1 ⇒ fetch child layer)
  ├─ LeafSubstratePanel.vue      ← /substrate?code= (file path vs PG table)
  ├─ LabelGroupingPanel.vue      ← /labels (PIV-311) + grouping_required flag
  ├─ PinColumn.vue               ← /pins?scope=
  └─ OrphanPhantomWarnings.vue   ← /integrity + /drift (candidate, never "phantom")

Props / data contract

Each component receives a typed object matching the doc-06 endpoint shapes. No component computes a total, gap, classification, or grouping decision — those arrive pre-computed from PG. Drill state (is_root, has_children, child rows) comes from v_registries_pivot_tree + backend, never a frontend tree.

Fetch strategy

  • useFetch/$fetch to the doc-06 read endpoints (which themselves read Directus, the pivot-query.get.ts pattern).
  • SSR-friendly; cache per endpoint (mirror health.get.ts 60s cache but over pivot data).
  • Drilldown is lazy: a node with has_children fetches /tree?parent= on expand; a leaf fetches /substrate?code=.

Forbidden in the shell (CI-enforced, doc 10/12)

  • No hardcoded arrays of CAT-/PIV- / categories / species / layers / labels / pins / thresholds.
  • No reduce(... + gap), no Math.abs(gap), no local SUM of counts.
  • No JS KHOP/ORPHAN/PHANTOM classification (that's v_count_drift's job).
  • No localStorage pins.

States

  • loading: skeleton cards per section.
  • error: per-section error card (one failed endpoint never blanks the page).
  • empty: valid empty list rendered as "0 items", not an error.
  • PIVOT_MISSING: explicit badge, never silent 0.
  • stale: show refreshed_at from pivot_results; net_gap flagged "live moving target".

Accessibility

Semantic table markup, scope on th, aria-labels on drill toggles and pin buttons, focus management on drill expand, color is never the only signal (status text + icon alongside the green/amber/red token).

Rollback

New route is additive; rollback = remove the route + components. Convergence/cutover of /knowledge/registries is a separate gated step (doc 09) with its own snapshot rollback.

Acceptance tests (Đ28 Test-4) — see doc 10

100% of rendered counts trace to a pivot or PIVOT_MISSING; 0 counts computed client-side; count_integrity_status shown honestly; CI lint blocks reduce(/Math.abs(gap)/hardcoded CAT-* in the shell.

Verdict

Nuxt render-shell pack COMPLETE. Route, components, contract, fetch, states, a11y, rollback, tests specified. No production Nuxt touched (gated to RG8, after views + API live).

Back to Knowledge Hub knowledge/dev/reports/architecture/registries-pivot-macro2-3-combined-ui-api-legacy-acceptance-2026-05-31/08-nuxt-render-shell-implementation-pack.md