feat(api): serve SPA from wwwroot with fallback for client routes

This commit is contained in:
VolcanicCore
2026-08-27 13:08:27 +00:00
parent 69f87e19ee
commit 71caaf467b
2 changed files with 20 additions and 1 deletions

View File

@@ -33,5 +33,8 @@ public sealed class AdminAuthMiddleware
}
private static bool IsPublic(string path) =>
path == "/api/login" || path == "/api/health" || path == "/api/health/ready";
path == "/api/login" ||
path == "/api/health" ||
path == "/api/health/ready" ||
!path.StartsWith("/api");
}

View File

@@ -134,6 +134,8 @@ if (!File.Exists(natsConfigPath))
// ── pipeline ─────────────────────────────────────────────────────────────
app.UseWebSockets(new WebSocketOptions { KeepAliveInterval = TimeSpan.FromSeconds(30) });
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMiddleware<AdminAuthMiddleware>();
AuthEndpoints.Map(app);
@@ -145,4 +147,18 @@ AssignmentsEndpoints.Map(app);
GraphEndpoints.Map(app);
AdminHub.Map(app);
app.MapFallback(async (HttpContext ctx) =>
{
var path = ctx.Request.Path.Value ?? "";
if (path.StartsWith("/api")) { ctx.Response.StatusCode = 404; return; }
// Try published layout first (wwwroot next to the DLL under Docker), then dev layout
// (WebRootPath under the project source dir when running via `dotnet run`).
var indexFile = Path.Combine(AppContext.BaseDirectory, "wwwroot", "index.html");
if (!File.Exists(indexFile))
indexFile = Path.Combine(app.Environment.WebRootPath ?? "", "index.html");
if (!File.Exists(indexFile)) { ctx.Response.StatusCode = 404; return; }
ctx.Response.ContentType = "text/html";
await ctx.Response.SendFileAsync(indexFile);
});
app.Run();