Commit ecd7f66
authored
feat(admin): React + Vite SPA for the admin dashboard (P3) (#649)
## Summary
Phase **P3** of
[docs/design/2026_04_24_proposed_admin_dashboard.md](https://github.com/bootjp/elastickv/blob/main/docs/design/2026_04_24_proposed_admin_dashboard.md).
The Go side (auth / JWT / cluster handler / dynamo handler /
follower→leader forwarding / `embed.go` skeleton) shipped in earlier PRs
(#644 et al.) but `StaticFS` was wired as `nil`, so `/admin/*` answered
404 for any non-API path. This PR ships the React bundle and flips
`StaticFS` on.
- React 18 + TypeScript + Vite, Tailwind CSS for tokens (Section 5.1).
No UI framework dependency — bundle stays at **~60 KB gzip** vs the
doc's 150 KB ceiling (Section 7.2).
- `vite.config.ts` writes its build output straight into
`internal/admin/dist/` so `npm run build && go build` produces a
single-binary release.
- Five pages per Section 5.2: Login, Dashboard, DynamoDB list/detail
(with Create + Delete dialogs), S3 list/detail (placeholder — endpoints
not yet wired, the SPA renders a soft "endpoint pending" notice on the
404).
- Cookie-based session (Section 6): `admin_session` (HttpOnly) handled
by the browser; `admin_csrf` value echoed in `X-Admin-CSRF` for every
POST/PUT/DELETE per the double-submit pattern. Read-only sessions hide
write affordances; backend re-evaluates the role.
- `.gitignore` keeps the placeholder `internal/admin/dist/index.html`
committed (so `//go:embed all:dist` always has a match in a fresh clone)
and excludes the hashed Vite asset outputs and npm/vite caches —
committed bundles drift from source.
## Test plan
- [x] `cd web/admin && npm install && npm run build` — 192 KB JS / 60 KB
gzip + 14 KB CSS
- [x] `cd web/admin && npm run lint` — `tsc --strict --noUnusedLocals
--noUncheckedSideEffectImports`
- [x] `go build ./...` — clean (placeholder + built bundle both compile)
- [x] `go test -race -count=1 ./internal/admin/...`
- [x] `golangci-lint run ./internal/admin/...`
- [ ] Manual smoke: start admin listener with `--adminEnabled
--adminAllowInsecureDevCookie --adminListen 127.0.0.1:8080`, visit
`http://127.0.0.1:8080/admin/`, log in with a SigV4 access key, confirm
dashboard / dynamo list / dynamo detail / dynamo create / dynamo delete
+ see graceful "endpoint pending" on the S3 pages.
## Notes
- **Self-review (5 lenses)** — these changes only ship UI + 1 line of Go
wiring (`StaticFS` activation). No replication, MVCC, OCC, or HLC code
paths touched. Lenses 1 (data loss) / 2 (concurrency) / 4 (consistency)
→ no impact. Lens 3 (perf) → +1 cold read of `embed.FS` per startup, ~1
MB binary growth (under the doc's 1–2 MB target). Lens 5 (test coverage)
→ SPA-side Vitest is documented as a P4 follow-up in the design doc;
this PR does not regress any existing Go test.
- The S3 admin endpoints, follower→leader forwarding for write paths,
and the design-doc lifecycle rename (`proposed_` → `partial_`) are out
of scope here and are tracked elsewhere.31 files changed
Lines changed: 4607 additions & 1 deletion
File tree
- internal/admin
- dist
- web/admin
- src
- api
- components
- lib
- pages
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
445 | 445 | | |
446 | 446 | | |
447 | 447 | | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
448 | 452 | | |
449 | 453 | | |
450 | 454 | | |
| |||
453 | 457 | | |
454 | 458 | | |
455 | 459 | | |
456 | | - | |
| 460 | + | |
457 | 461 | | |
458 | 462 | | |
459 | 463 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
0 commit comments