Topic Axis — 07 UI/API Axis Patch Packet
07 — UI/API Axis Patch Packet (Workstream F)
Status: PATCH-READY (no redeploy performed; operator-gated)
The backend surface needed by the UI is already live and read-only (v_registries_pivot_axis_surface, v_axis_topic_pivots, fn_topic_node_substrate). The UI/API work is an additive patch on top; the existing RP tree path stays intact for non-axis pivots.
New API routes (mirror existing registries-pivot route pattern)
Existing routes live at web/server/api/registries-pivot/{summary,rows,node}.get.ts (Nuxt server API; counts computed in PG, never in Nuxt). Add a sibling axes/ group:
GET /api/axes→ list axes from axis_registry (axis_code, axis_name, domain, status, owner_governance_ref). Today returns AX-TOPIC (CANDIDATE).GET /api/axes/:axis_code→ axis header + its pivots from v_axis_topic_pivots (pivot_code, name, count_value, classification).GET /api/axes/:axis_code/nodes→ rows from v_registries_pivot_axis_surface filtered by axis_code (root layer = parent_codes empty; child layers via parent_codes). Returns parent_codes[], has_multiple_parents, count_value, lifecycle_status, governance_status, warning_flags, grouping_status, pin_state.GET /api/axes/:axis_code/node/:node_code/substrate→ passthrough of fn_topic_node_substrate(node_code) jsonb.
Each handler is a thin SELECT passthrough — no Nuxt math (the firewall rule from prior RP UI work). All counts already exist in PG.
Frontend changes (additive component set)
- Axis selector — dropdown over /api/axes (today: Topic Axis [candidate]).
- Root topic layer — nodes with empty parent_codes.
- Child topic layer — expand by parent_code; because parent_codes is an array, a node can appear under multiple parents.
- Multi-parent breadcrumb — when has_multiple_parents, render each parent path; never collapse to a single tree path.
- Lifecycle badges — candidate / provisional / active (from lifecycle_status); plus governance_status badge (UNGOVERNED_CANDIDATE vs TAXONOMY_BACKED).
- Grouping warning — show when grouping_status = GROUPING_REQUIRED.
- Pin support — bind pin_state to the existing registry_pin mechanism (axis pin = future step).
- Substrate panel — render the resolver jsonb: linked IUs, documents, workflows, DOTs, evidence tags, parents.
Link from existing RP page
/knowledge/registries-pivot gains an "Axes" entry pointing at the axis surface. The legacy tree (v_registries_pivot_surface) and all non-axis pivots are unchanged — the axis surface is a parallel DAG view, not a replacement.
Redeploy checklist (operator)
- Add the four
axes/*.get.tshandlers (copy the registries-pivot handlers, swap the view names above). - Add the axis selector + node/substrate components.
- Build + redeploy the Nuxt container (operator-gated — not done here).
- Smoke test: /api/axes returns AX-TOPIC; /api/axes/AX-TOPIC/nodes returns 7 candidate rows; substrate for TOPIC-CAND:knowledge_graph returns 10 IUs.
Forbidden-action compliance
No Nuxt-side count math; legacy tree untouched; DAG never forced into a single tree path; no redeploy executed without operator action.