Commit ca45c5e
committed
feat(admin): React + Vite SPA for the admin dashboard
Phase P3 of 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 but
StaticFS was wired as nil, leaving /admin/* answering 404 for any
non-API path. This PR adds the React bundle + flips StaticFS on.
Source layout (web/admin/):
- React 18 + TypeScript + Vite per design doc Section 5.1
- Tailwind CSS for tokens; no UI framework dependency (kept the
bundle at ~60 KB gzip per Section 7.2's ~150 KB target)
- vite.config.ts writes the build output straight into
internal/admin/dist so `npm run build && go build` produces a
single binary with the latest SPA
Pages (Section 5.2):
- /login - SigV4 access-key + secret-key form, server-side JWT
Cookie issued, status-specific error messages for 401/403/429
- / (dashboard) - cluster overview, raft groups, summary cards
- /dynamo - table list + Create dialog (full role only)
- /dynamo/:name - schema + GSIs + Delete confirmation modal
- /s3 - bucket list + Create dialog (endpoint pending, renders
graceful "endpoint pending" notice on 404)
- /s3/:name - bucket meta + ACL toggle + Delete (same)
Auth (Section 6):
- Cookie-based session (admin_session, HttpOnly) handled by browser
- CSRF double-submit: admin_csrf cookie value echoed in
X-Admin-CSRF header on every POST/PUT/DELETE (apiFetch in
src/api/client.ts)
- Read-only sessions hide Create/Delete affordances and surface a
RequireFullAccess notice; backend re-evaluates the role
- Session expiry tracked in sessionStorage; expires_at trip clears
in-memory state and redirects to /login
Backend wiring:
- main_admin.go: load admin.StaticFS() and pass to ServerDeps so
/admin/assets/* and the SPA fallback start serving real files
- internal/admin/embed.go: //go:embed all:dist on the build output
- .gitignore: keep the placeholder index.html committed (so
go:embed always has at least one file in a fresh clone), exclude
hashed Vite assets and the npm/vite caches - committed bundles
invariably drift from source
Verification:
- npm run build: 192 KB JS / 60 KB gzip + 14 KB CSS
- npm run lint (tsc strict, noUnusedLocals, noUncheckedSideEffects)
- go build ./...
- go test -race ./internal/admin/...
- golangci-lint run ./internal/admin/...
S3 admin endpoints (CreateBucket / ListBuckets / PutBucketAcl /
DeleteBucket) are not yet wired on the Go side; the SPA pages render
a soft "endpoint pending" notice on the 404 they currently get and
will populate transparently once the handlers ship.1 parent 76cb788 commit ca45c5e
31 files changed
Lines changed: 4600 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