Files
fancy-dns/web/README.md
T
developer e8c5b414d9
build / build-push (push) Failing after 23s
half broken
2026-09-27 17:17:53 +00:00

64 lines
3.0 KiB
Markdown

# The console
Vite + React + TypeScript + Tailwind, built into `internal/web/dist` and served
by the Go binary from an `//go:embed`. There is no separate deployment: the
binary *is* the console.
## Day-to-day
```sh
make web-check # npx tsc -b --noEmit && npm run build (what CI runs)
make web-dev # Vite dev server, proxying /api to 127.0.0.1:8080
make web # production build into internal/web/dist
```
For `make web-dev` to show anything, a `fancy-dns` has to be listening on
127.0.0.1:8080 with the API key the console sends. `deploy/config.example.yaml`
binds there, but on port 53; rewrite the ports (or use `make smoke`, which does
it for you) before starting it.
Two traps that have cost time, both from `AGENTS.md`:
- **`tsc -b` replays cached diagnostics** from `node_modules/.tmp/*.tsbuildinfo`.
After a large edit `rm -f node_modules/.tmp/*.tsbuildinfo`, or you will read
errors that no longer exist and miss ones that do.
- **`npm run build` empties `internal/web/dist` and deletes its `.gitkeep`.**
Restore it (`git checkout -- internal/web/dist/.gitkeep`). The Go build still
works while the directory is empty, so a console rebuild in the middle of
someone else's `go build` is not fatal — but the commit is.
## The API contract
`src/lib/types.ts` is a **hand-written mirror** of the Go `json` tags in
`internal/api` and `internal/app/hooks.go`. `apiFetch` ends in
`JSON.parse(text) as T`, so the compiler checks the console against its own
declarations and nothing else: a field that loses its `json` tag, or a response
a struct never had, shows up as an empty table in a browser and nowhere else.
That is not hypothetical — a round of this found the Sources table, the ACL
group cards and both Save buttons broken exactly that way.
So, when you touch either side:
- **Go**: add or keep the `json` tag. `internal/app` has contract tests that
assert the exact key set of every admin endpoint; they are the spec, and a
rename fails them.
- **Console**: change the interface in the same commit. If the server is wrong,
fix the server — do not "adapt" in the client, and do not paper a mismatch
over with `as any`, an optional field or a `?? 0` default. Those casts are
precisely what hides drift.
- Never rename a field on one side only. The dashboard, the ServiceMonitor
queries and the Grafana panels are consumers of the same JSON.
The durable fix is to generate `types.ts` from the Go structs, or to publish an
OpenAPI document from the server and generate from that. It is in the plan at
the end of `STATUS.md`.
## What is checked
`npx tsc -b --noEmit` (strict, with `noUnusedLocals`) and `oxlint` (two rules:
`react/rules-of-hooks` and `react/only-export-components`). There is **no test
runner** and no component test — the console's correctness rests entirely on its
types, which are only as good as the mirror above. Adding vitest and a handful
of tests for `lib/format.ts` (the percent/latency/duration formatters, which
have already shipped a units bug) is cheap and worth doing.