Retire the Tracks list view; promote the Releases view to /releases with
medium tabs (ALL/CUTS/SESSIONS/MIXES). Migrate bulk profile/high-res
backfill and per-track waveform columns into the releases grids. Point
catalogue cards at the three mediums. Remove dead BrowseMode/ViewModel.
GET api/track/waveform-status and POST api/track/{id}/waveform (ApiKey);
CmsTrackService methods; TrackPreProcessing page with per-row and
sequential bulk generation; nav links from TrackList and Index.
AddAuthBlocks installs JwtBearer as the default challenge scheme; the
authorization middleware 401s unauthenticated nav requests before the
Blazor router runs. Tokens live in localStorage and are only readable
via JS interop after the SignalR circuit is live.
- Program.cs: MapRazorComponents .AllowAnonymous() so nav reaches the
Blazor router; API surfaces (MapAuthBlocks, MapControllers) still
enforce JWT. Fix middleware order to UseAuthentication -> UseAntiforgery
-> UseAuthorization per Blazor Web App template.
- App.razor: InteractiveServerRenderMode(prerender:false) on Routes and
HeadOutlet so AuthorizeRouteView evaluates after JS interop is ready;
extract to static field (was two inline allocations per render cycle).
- CmsLayout/Pages: drop conflicting per-component @rendermode directives
(parent now owns the render mode).
- Routes.razor: break authenticated-but-wrong-role redirect loop; split
NotAuthorized into unauthenticated -> RedirectToLogin and
authenticated-wrong-role -> RedirectToAccessDenied (new component).
- Pages/Index.razor: deleted — NavigateTo('/cms') was unreachable for
unauthenticated users and racey for authorized ones.