Skip to main content

ADR-0148: Portal frontend stack (design system, charts, graphs, forms, API client)

Context​

The architecture reference (A4.4) names for the portal Next.js + React + TypeScript, MUI, an API client generated from OpenAPI, SSE or WebSocket, Monaco, React Hook Form + Zod, React Flow, Apache ECharts and OIDC Keycloak. The client decided not to use MUI.

Decision​

  • Design system: Tailwind CSS + radix primitives (@radix-ui/*) + webui tokens (portal/src/app/globals.css, portal/tailwind.config.ts), components in portal/src/components. MUI is never added (client decision: one visual system, shared with the navin-manager console).
  • Forms: React Hook Form + Zod 4 (portal/src/components/common/field-form.tsx, portal/src/lib/zod.ts); configuration forms are generated from a JSON Schema of contracts/v1 (schemaFields, portal/src/lib/components.ts).
  • API client: the typed operation table portal/src/lib/api/operations.gen.ts is generated from docs/api/openapi-v1.json by portal/src/lib/api/generate-operations.mjs (--check run by portal/tests/openapi-client.test.ts); callOperation calls an operation by its operationId. The domain wrappers of resources.ts stay readable helpers, checked against the specification by portal/tests/api-conformance.test.ts.
  • Charts: Recharts (MIT, already present and used by FinOps) instead of Apache ECharts. Both are OSI; Recharts avoids a second chart library and covers the time series and bar charts of the portal. ECharts (Apache-2.0) may be added, pinned, when a view needs a chart type Recharts lacks.
  • Graphs: DependencyGraph draws a layered graph (Kahn algorithm, cycles listed apart) from GET /v1/lineage/graph, without React Flow. React Flow (MIT) stays reserved to topology and execution views if it becomes needed; the Developer Studio stays code first (Monaco).
  • Editor: Monaco (monaco-editor 0.52.2, bundled locally, no CDN) for Python, TypeScript, JSON, YAML and Rego.
  • Authentication: OIDC with Keycloak through oidc-client-ts (portal/src/lib/auth.ts).

Consequences​

No non OSI dependency; no library added by this decision. Any OpenAPI change requires regenerating operations.gen.ts, otherwise the test fails.

Evidence​

portal/tests/openapi-client.test.ts, portal/tests/components.test.ts, portal/tests/api-conformance.test.ts, npm run typecheck, npm run lint.