fix(web,server): плейсхолдер dist для воспроизводимой сборки + /api без слэша → API

Коммитим internal/web/dist/index.html как минимальный плейсхолдер, чтобы
//go:embed all:dist находил совпадения на чистом клоне без npm/`make web`
(CRITICAL: go build ./... падал с "pattern all:dist: no matching files
found"). .gitignore теперь игнорирует только реальные build-ассеты
(internal/web/dist/* кроме index.html); `make web` перезаписывает
плейсхолдер настоящей сборкой.

Также чинит MEDIUM: голый /api (без хвостового слэша) уходил в
SPA-fallback вместо API-роутера — вынесен isAPIPath() с явной проверкой
path == "/api", покрыт TestIsAPIPath.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
This commit is contained in:
2026-07-03 18:24:24 +07:00
parent bba72cc70f
commit 4140847a15
4 changed files with 40 additions and 2 deletions
+9 -1
View File
@@ -18,6 +18,14 @@ import (
"github.com/vasyakrg/dns-autoresolver/internal/web"
)
// isAPIPath reports whether path must be routed to the API router rather
// than the SPA. "/api" (no trailing slash) counts as an API path too —
// only strings.HasPrefix(path, "/api/") would otherwise miss it and fall
// through to the SPA fallback.
func isAPIPath(path string) bool {
return path == "/api" || strings.HasPrefix(path, "/api/")
}
func main() {
ctx := context.Background()
cfg, err := config.Load()
@@ -52,7 +60,7 @@ func main() {
}
mux := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api/") {
if isAPIPath(r.URL.Path) {
apiRouter.ServeHTTP(w, r)
return
}