Scaffold SvelteKit 2 + Svelte 5 + Tailwind SPA at web/ with Vitest smoke test
Embed the SvelteKit build output in the Go binary via //go:embed all:build, with SPA fallback for deep links and a prefix carve-out so /api/* and /rest/* never return HTML
Rewrite Dockerfile as a three-stage build (node → golang → debian:slim) and update Forgejo CI to install Node, build the SPA, and run Vitest before Go steps
Document the two-process dev workflow (Vite on :5173 proxying to Go on :4533) in the README
Test Plan
go test -short -race ./... passes
golangci-lint run ./... clean
cd web && npm test && npm run build passes
docker build -t minstrel:scaffold-final . succeeds; binary is -x in the final image
docker compose up -d end-to-end:
GET / → 200 text/html (SPA)
GET /artists/<uuid> → 200 text/html (SPA deep-link fallback)
GET /healthz → 200 application/json
GET /api/nonexistent → 404 application/json (no HTML leaked)
GET /rest/nonexistent → 200 application/json (subsonic error shape, still JSON)
Forgejo CI green on this PR
## Summary
- Scaffold SvelteKit 2 + Svelte 5 + Tailwind SPA at `web/` with Vitest smoke test
- Embed the SvelteKit build output in the Go binary via `//go:embed all:build`, with SPA fallback for deep links and a prefix carve-out so `/api/*` and `/rest/*` never return HTML
- Rewrite `Dockerfile` as a three-stage build (node → golang → debian:slim) and update Forgejo CI to install Node, build the SPA, and run Vitest before Go steps
- Document the two-process dev workflow (Vite on `:5173` proxying to Go on `:4533`) in the README
## Test Plan
- [x] `go test -short -race ./...` passes
- [x] `golangci-lint run ./...` clean
- [x] `cd web && npm test && npm run build` passes
- [x] `docker build -t minstrel:scaffold-final .` succeeds; binary is `-x` in the final image
- [x] `docker compose up -d` end-to-end:
- `GET /` → 200 `text/html` (SPA)
- `GET /artists/<uuid>` → 200 `text/html` (SPA deep-link fallback)
- `GET /healthz` → 200 `application/json`
- `GET /api/nonexistent` → 404 `application/json` (no HTML leaked)
- `GET /rest/nonexistent` → 200 `application/json` (subsonic error shape, still JSON)
- [ ] Forgejo CI green on this PR
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
web/with Vitest smoke test//go:embed all:build, with SPA fallback for deep links and a prefix carve-out so/api/*and/rest/*never return HTMLDockerfileas a three-stage build (node → golang → debian:slim) and update Forgejo CI to install Node, build the SPA, and run Vitest before Go steps:5173proxying to Go on:4533) in the READMETest Plan
go test -short -race ./...passesgolangci-lint run ./...cleancd web && npm test && npm run buildpassesdocker build -t minstrel:scaffold-final .succeeds; binary is-xin the final imagedocker compose up -dend-to-end:GET /→ 200text/html(SPA)GET /artists/<uuid>→ 200text/html(SPA deep-link fallback)GET /healthz→ 200application/jsonGET /api/nonexistent→ 404application/json(no HTML leaked)GET /rest/nonexistent→ 200application/json(subsonic error shape, still JSON)