@@ -108,6 +108,85 @@ Common commands:
108108- Do not commit or push unless asked.
109109- Keep PRs focused. Explain non-obvious invariants and operational tradeoffs, not line-by-line implementation details.
110110
111+ ## The web interface (` ui/ ` )
112+
113+ A Vite single-page app. It is a static bundle served by nginx: there is no server
114+ process, so there are no server components, no server-side data fetching and no
115+ file-system routing.
116+
117+ ** Stack:** Vite + React 19, TypeScript, antd 6 for components, Emotion for styling
118+ (the ` css ` prop, via ` jsxImportSource ` ), SWR for reads, Yarn 4. React Router owns
119+ routing; there is no file-system routing and no server rendering.
120+
121+ ### Commands
122+
123+ Run these from ` ui/ ` :
124+
125+ | Task | Command |
126+ | ------| ---------|
127+ | Dev server | ` yarn dev ` |
128+ | Unit tests | ` yarn test ` |
129+ | End-to-end, no cluster needed | ` yarn test:pw ` (Chromium and Firefox) |
130+ | End-to-end against a real cluster | ` yarn test:pw:live ` |
131+ | Type check | ` yarn typecheck ` |
132+ | Lint | ` yarn lint ` |
133+
134+ Only lint ** errors** gate a change; a handful of warnings are pre-existing.
135+
136+ ` scripts/setup-cluster/setup-cluster.sh ` builds a Kind cluster with kagent on it in one
137+ command, for work that needs a real backend.
138+
139+ ### Settings reach the app at runtime, not at build time
140+
141+ Configuration is read from ` window.environmentVariables ` , which the container
142+ rewrites from its own environment on every start. So one image serves every
143+ deployment, and a setting is an operator's decision rather than something frozen
144+ into a build. Locally the same values come from ` ui/.env ` (git-ignored;
145+ ` ui/.env.example ` documents each one).
146+
147+ Two consequences worth knowing before touching that code:
148+
149+ - The script that supplies them is ** synchronous** in ` index.html ` . Several modules
150+ read settings at import time, so anything awaited would be read before it arrived.
151+ - ` import.meta.env ` is for build-time flags only. A value that an operator should be
152+ able to change belongs in ` window.environmentVariables ` .
153+
154+ ### Fixtures are opt-in
155+
156+ ` ENABLE_MOCK_UI=true ` serves the whole API from an in-browser mock (MSW) with no
157+ cluster at all, and ` ?mock=ok|empty|error|slow ` picks which scenario the fixtures
158+ play. ** It is off unless asked for** , in a dev server exactly as in a built image: a
159+ page that quietly serves fixtures when the backend is down looks healthy while
160+ showing data that was never real.
161+
162+ When mock mode is on it overrides every backend setting, and anything reporting who
163+ is signed in correctly reports nobody — there is no backend to have signed in to.
164+
165+ ### Extension points
166+
167+ One ` VendorExtensionConfig ` contributes navigation entries and overrides, routes and
168+ route handles, slots, form fields, table columns, API overrides, providers, theme
169+ tokens, shell regions, branding, provider icons and agent links. Components read
170+ every colour, radius and font from those tokens, so overriding them restyles
171+ components an extension never touches. When adding a feature, check whether it
172+ belongs behind an extension point rather than as a branch inside a shared component.
173+
174+ The full guide is [ ui/docs/vendor-extensions.md] ( ui/docs/vendor-extensions.md ) .
175+
176+ ### Conventions specific to this codebase
177+
178+ - ** Say when data is not real.** A page showing fixtures says so on the page. Never
179+ suppress an error because a mock flag is set — a broken backend must not render as
180+ healthy mock data.
181+ - ** Normalise at the client boundary.** Go marshals a nil slice as JSON ` null ` , so
182+ any collection the controller has nothing for arrives as null. Fix it once where the
183+ response is parsed, not at each use.
184+ - ** Fixtures must match the controller, not each other.** A fixture, a type and a
185+ test can agree perfectly and all three be wrong; that has happened here more than
186+ once and each time only a real cluster objected. Check the CRD.
187+ - ** Prefer a smaller honest test suite** over a green one that proves nothing.
188+ Coverage debt belongs in ` playwright/DEFERRED.md ` , not in skipped specs.
189+
111190## 9. References
112191
113192- [ STYLE.md] ( STYLE.md )
0 commit comments