Skip to content

Latest commit

 

History

History
102 lines (80 loc) · 4.66 KB

File metadata and controls

102 lines (80 loc) · 4.66 KB

Admin console architecture

How the operator console is structured, kept faithful to the design, wired to the gateway, and verified. Public usage lives in reference/admin-ui.md; this is the design rationale + invariants for contributors.

Overview

app/<route>/page.tsx   ← one client page per route
        │ uses
        ▼
components/shell  (sidebar, topbar, app-shell)   components/ui (primitives, overlays, toaster)
components/shared (PageHeader, DataPanel, KV/JSON/YAML)   components/providers (theme + app ctx + toasts)
        │
        ▼
lib/use-live  ──(NEXT_PUBLIC_GATEWAY_URL?)──▶ lib/api (gateway fetch)
        └────────────────fallback────────────▶ lib/mock (typed seed)

The console is a client-rendered Next.js App Router app: the shell + every page are client components because the surface is heavily interactive (modals, sheets, dropdowns, toggles, optimistic mutations). It builds statically (output: standalone) and is configured with one env var.

Hand-rolled primitives, handoff tokens

The design target is shadcn/ui, but the primitives are hand-rolled in TypeScript rather than pulled via the shadcn CLI (ADR-0019): deterministic offline builds, a small fixed dependency set, and a 1:1 port of the handoff's own hand-rolled prototype. The shadcn CSS-variable tokens (light + dark), Geist fonts, animations, and YAML-highlight colors are copied verbatim from the handoff into app/globals.css + tailwind.config.ts, so the result is pixel-faithful.

cwd invariant: Tailwind's content glob is relative (./src/**/*.{ts,tsx}), so the dev server / build must run with the working directory at apps/admin-ui (the pnpm --filter scripts do this). Running next dev from the repo root yields an unstyled app.

The live-vs-seed hybrid

lib/use-live.ts is the seam: useLive(mockSelector, fetcher) seeds from local data scoped to the active tenant, and — when NEXT_PUBLIC_GATEWAY_URL is set and a fetcher is provided — replaces it with live data, falling back to the seed on any error and exposing a source: "live" | "mock" flag the page surfaces as a "Demo data" badge.

  • Corpora / Webhooks pass real fetchers (lib/api.tsGET /v1/corpora, /v1/webhooks/subscriptions …).
  • Everything else passes fetcher = null (seed only); API Keys / Tenants add a Preview marker.

This keeps the console always-renderable (CI, screenshots, no-backend preview) while real data lights up against a gateway, and makes the seed→live promotion a one-line change per resource as Phase 6 endpoints land.

Mutations on live pages (e.g. create/delete webhook, send test) call the gateway when source === "live" and fall back to optimistic local state otherwise. Writes that have no endpoint yet (corpus create/delete, connector setup, glossary edits, key/tenant CRUD) are local-only in v0.

State

components/providers.tsx holds the global client state: active tenant, sidebarCollapsed, a review viewState (the top-bar "State" control that previews loading/empty/error renders), and a toast queue — plus next-themes for dark mode. Per-page state (rows, selected row, dialog flags, filters) is local.

DataPanel (in shared.tsx) renders one of skeleton / empty / error / content; useResolvedState lets the global review control override a page's own status so every state is reviewable.

Verification

A frontend's correctness isn't only "tests pass", so the gates are layered (ADR-0019), all wired into a CI admin-ui job:

  • tsc --noEmit (strict) + next lint.
  • vitest + React Testing Library: shell nav coverage, the Corpora page against the no-gateway seed path (asserts rows + Demo-data badge + the new-corpus dialog), the Webhooks one-time-secret reveal flow, and Audit filtering.
  • Production next build (static export).
  • Visual fidelity confirmed by rendering the running app and diffing against the handoff screenshots.

Reviewer checklist

  • New page is a client component under app/<route>/, added to shell/nav.ts, reusing the primitives + DataPanel?
  • Live data via useLive(mockSelector, fetcher) with a seed fallback + source badge; seed-only via fetcher = null?
  • Pages whose backend doesn't exist carry a Preview marker?
  • Tokens come from globals.css / tailwind.config.ts (no ad-hoc colors)?
  • tsc + next lint + vitest + next build all green?

See also

  • reference/admin-ui.md — pages + config + running.
  • ADR-0019 — the decision + deferrals.
  • apps/admin-ui/design/handoff/README.md — the source design spec.