server: serve SPA index.html for /users, /agents, /forgot-password#137
Open
nickhodaly-ud wants to merge 1 commit intoInfisical:mainfrom
Open
server: serve SPA index.html for /users, /agents, /forgot-password#137nickhodaly-ud wants to merge 1 commit intoInfisical:mainfrom
nickhodaly-ud wants to merge 1 commit intoInfisical:mainfrom
Conversation
The SPA fallback in server.go is an explicit allow-list, not a true
catch-all. Three top-level frontend routes (/users, /agents,
/forgot-password) were missing from the list, so a hard refresh on
those pages 404'd while client-side navigation worked.
Add a regression test that hits every top-level route in
web/src/router.tsx through the real mux. /invite/{token} is excluded
because the more-specific API handler at GET /invite/{token} wins
over the SPA fallback at /invite/{token...}.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
internal/server/server.gois an explicit allow-list of frontend routes, not a true catch-all. Three top-level routes (/users,/agents,/forgot-password) were missing, so a hard refresh on those pages 404'd while client-side navigation worked.mux.HandleFunc("GET /...", s.handleSPA)entries. No behavior change for any path that already worked; unknown paths still 404 (the allow-list stays tight).TestSPACatchAllRoutesto lock the contract: every top-level route inweb/src/router.tsxis hit through the real mux and asserted non-404. The next missing route fails CI rather than shipping silently.Why this snuck in
/usersand/agentsare sibling tabs to/(vaults list) under the home layout, and/forgot-passwordis a sibling to/login. They were the only top-level frontend routes whose path didn't include a wildcard segment matched by an existing fallback (e.g./account/{path...},/vaults/{name...}), and client-side navigation hides the gap because the server is never asked.Test plan
go build ./...— cleango test -race -count=1 ./internal/server/...— green, including newTestSPACatchAllRoutes(13 path subtests + an unknown-path 404 sanity subtest)go vet ./internal/server/...— clean/users,/agents,/forgot-passwordto fail/users/agents/forgot-passwordreturn 200;/definitely-not-a-routereturns 404/usersin a deployed instance to confirm the original repro is resolvedOut of scope
/change-passwordis in the SPA allow-list but no longer exists inweb/src/router.tsx. Stale-but-harmless entry; not removed in this PR./accountand/manage(no trailing path) would still 404 because/{path...}requires ≥1 segment. The frontend redirects out of those paths immediately on mount, so user-impact is near-zero. Pre-existing.Test note: why /invite/{token} is excluded from the test
The API handler
GET /invite/{token}(server.go:627) is registered alongside the SPA fallbackGET /invite/{token...}(server.go:746). Go'sServeMuxprefers the single-segment pattern, so single-segment/invite/abcrequests route tohandleInviteRedeem(which 404s on an unknown token in the mock store), nothandleSPA. A 404 there wouldn't tell us anything about the SPA fallback being broken, so the test skips it with an inline comment.🤖 Generated with Claude Code