Add a dev launch profile and a no-cache header for static files - #53
Merged
Conversation
Two housekeeping items from docs/backlog.md, both about the local development loop rather than the product. launchSettings.json: the app reads its connection string only in the Development environment, so every run needed ASPNETCORE_ENVIRONMENT set by hand first. Forgetting it fails with "ConnectionStrings:WendDb is not configured", which reads as a missing user-secret rather than a missing environment variable, and has cost that confusion more than once. The profile sets the environment and nothing else. Deliberately no applicationUrl: Program.cs binds Kestrel explicitly with ListenLocalhost(Wend:Port), and an explicit Listen call overrides ASPNETCORE_URLS, so an applicationUrl would be dead config that only logs an override warning. The address stays owned by the Wend:Port seam. Static files: UseStaticFiles sends no Cache-Control at all, so the browser applies its own heuristic and a normal reload keeps serving JS and CSS from an earlier :5174 session - two "bugs" in the 2026-07-08 accessibility sweep were cache ghosts, and the standing workaround was to hard-reload before every browser check. Development now sends no-cache, which still stores the response but revalidates, so an unchanged file costs a 304 rather than a resend. Production keeps the default. MapFallbackToFile takes the same options because it serves index.html through its own static-file pipeline, not the middleware above; without that the shell alone would still come back from cache. Two guards in ApiSmokeTests, one for a static asset and one for the shell, both verified red against this branch with Program.cs reverted. 255/255 green, and the count in the README moves with them. The README's Run it section documented the manual environment step and stated there is no launchSettings.json, so it is corrected in the same commit.
The backlog is the source of truth for what is knowingly deferred, so an item this branch closes should not still read as open. The entry keeps the trap that made it worth writing down and gains what was done about it, the two guards, and the launchSettings.json half of the same housekeeping pass.
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.
Two housekeeping items from
docs/backlog.md, both about the local development loop rather than the product. Neither touches the API surface, Identity, or the frontend.launchSettings.json
Wend.Apireads its connection string only in the Development environment, so every run neededASPNETCORE_ENVIRONMENTset by hand first. Forgetting it fails withConnectionStrings:WendDb is not configured, which reads as a missing user-secret rather than a missing environment variable. The profile sets the environment and nothing else.No
applicationUrlon purpose.Program.csbinds Kestrel explicitly withListenLocalhost(Wend:Port), and an explicitListencall overridesASPNETCORE_URLS, so anapplicationUrlwould be dead config that only logs an override warning. The address stays owned by theWend:Portseam.The app still refuses to boot outside Development (no production email sender), so the profile makes the intended run easier without weakening that guard.
Dev-only
Cache-Control: no-cacheon static filesUseStaticFilessends noCache-Controlat all, so the browser applies its own heuristic and a normal reload keeps serving JS and CSS from an earlier:5174session. Two "bugs" in the 2026-07-08 accessibility sweep were cache ghosts, and the standing workaround has been to hard-reload before every browser check.Development now sends
no-cache— which still stores the response but revalidates, so an unchanged file costs a 304 rather than a resend. Production keeps the default, where caching static assets is the point.MapFallbackToFiletakes the same options because it servesindex.htmlthrough its own static-file pipeline rather than the middleware above; without that the shell alone would still come back from cache.What to check
staticFiles.OnPrepareResponseis set only insideif (app.Environment.IsDevelopment())— the production path must keep the defaultStaticFileOptions.UseStaticFilesandMapFallbackToFilereceive the same options object.ApiSmokeTests—Static_files_are_no_cache_in_developmentandThe_shell_is_no_cache_in_development. Both were verified red on this branch withProgram.csreverted (2 failed / 0 passed), then green with it back.WendApiFactorypinsUseEnvironment("Development"), so the production branch is not covered by a test. It is a one-lineifwith no behaviour of its own; flag it if you would rather see it exercised.Verification
dotnet test→ 255 passed, 0 failed (253 before, +2 new). The README's test count moves with it.dotnet run --project Wend.Apiin a shell with noASPNETCORE_ENVIRONMENTset: boots,/api/health200,/css/app.cssand/boards/42both answerCache-Control: no-cacheagainst the running server.README
The Run it section documented the manual environment step and stated "There is no
launchSettings.json", so it is corrected here rather than left to drift — that coupling was the reason these two items were queued together.