Fix admin WASM bootstrap and dashboard render
TaxBaik CI/CD / build-and-deploy (push) Successful in 6m10s

This commit is contained in:
2026-07-08 01:45:55 +09:00
parent f2f4769460
commit 8bd100707a
5 changed files with 13 additions and 62 deletions
+9 -3
View File
@@ -15,8 +15,8 @@ const files = [
const required = [ const required = [
{ {
file: 'src/TaxBaik.Web/Program.cs', file: 'src/TaxBaik.Web/Program.cs',
pattern: 'MapGroup("/taxbaik/admin")', pattern: 'app.MapFallbackToFile("admin/{*path:nonfile}", "admin/index.html");',
message: '관리자 Razor Components는 /taxbaik/admin 그룹에만 매핑되어야 합니다.' message: '관리자 SPA 폴백은 admin/index.html로만 연결되어야 합니다.'
}, },
{ {
file: 'tests/e2e/route-isolation.spec.ts', file: 'tests/e2e/route-isolation.spec.ts',
@@ -48,12 +48,18 @@ const adminFiles = files
for (const file of adminFiles) { for (const file of adminFiles) {
const fullPath = path.join(root, file); const fullPath = path.join(root, file);
const text = fs.readFileSync(fullPath, 'utf8'); const text = fs.readFileSync(fullPath, 'utf8');
if (file === 'src/TaxBaik.Web/Program.cs') continue;
if (text.includes('ToBaseRelativePath(Navigation.Uri)')) { if (text.includes('ToBaseRelativePath(Navigation.Uri)')) {
console.error(`[route-lint] FAIL ${file}: unsafe ToBaseRelativePath(Navigation.Uri) usage detected.`); console.error(`[route-lint] FAIL ${file}: unsafe ToBaseRelativePath(Navigation.Uri) usage detected.`);
failed = true; failed = true;
} }
if (file === 'src/TaxBaik.Web.Client/Components/Admin/App.razor') {
if (text.includes('<html') || text.includes('<body') || text.includes('blazor.webassembly.js')) {
console.error('[route-lint] FAIL App.razor: host HTML or Blazor bootstrap script must not live in the root component.');
failed = true;
}
}
} }
if (failed) process.exit(1); if (failed) process.exit(1);
@@ -1,50 +1 @@
@using Microsoft.AspNetCore.Components.Web
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>백원숙 세무회계 - 관리자</title>
<base href="/taxbaik/admin/" />
<link rel="icon" type="image/svg+xml" href="/taxbaik/favicon.svg" />
<link rel="alternate icon" href="/taxbaik/favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<script>
window.taxbaikAdminBuildVersion = 'unknown';
window.taxbaikAdminComponent = 'AdminApp';
document.documentElement.classList.toggle(
'admin-login-route',
window.location.pathname.toLowerCase().endsWith('/admin/login'));
</script>
<link rel="stylesheet" href="css/admin.css" />
</head>
<body>
<div id="components-reconnect-modal" class="admin-reconnect-modal">
<div class="admin-reconnect-card">
<strong>연결 재설정 중...</strong>
<span>새로운 버전으로 업데이트되었습니다.</span>
<span style="font-size: 0.85rem; margin-top: 0.5rem; opacity: 0.8;">자동으로 페이지를 새로고침합니다. 잠시만 기다려주세요.</span>
</div>
</div>
<div id="blazor-loading" class="blazor-loading-overlay">
<div class="blazor-loading-spinner">
<div class="spinner"></div>
<p>로드 중...</p>
</div>
</div>
<Routes @rendermode="@(new InteractiveWebAssemblyRenderMode(prerender: false))" /> <Routes @rendermode="@(new InteractiveWebAssemblyRenderMode(prerender: false))" />
<script src="js/admin-session.js"></script>
<script src="_framework/blazor.webassembly.js"></script>
<script>
if (document.documentElement.classList.contains('admin-login-route') &&
window.taxbaikAdminSession &&
typeof window.taxbaikAdminSession.bindLoginForm === 'function') {
window.taxbaikAdminSession.bindLoginForm();
}
</script>
</body>
</html>
@code {
}
@@ -1,6 +1,5 @@
@inherits LayoutComponentBase @inherits LayoutComponentBase
<AdminShell> <div class="admin-layout-shell">
<AdminTelemetryContext />
@Body @Body
</AdminShell> </div>
+1
View File
@@ -5,6 +5,7 @@ using TaxBaik.Web.Services;
using TaxBaik.Web.Services.AdminClients; using TaxBaik.Web.Services.AdminClients;
var builder = WebAssemblyHostBuilder.CreateDefault(args); var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<TaxBaik.WasmClient.Components.Admin.App>("#app");
// API Base Url: Admin SPA is hosted under /taxbaik/admin/, while APIs live under /taxbaik/api/. // API Base Url: Admin SPA is hosted under /taxbaik/admin/, while APIs live under /taxbaik/api/.
var hostBase = new Uri(builder.HostEnvironment.BaseAddress); var hostBase = new Uri(builder.HostEnvironment.BaseAddress);
-6
View File
@@ -476,12 +476,6 @@ app.MapHealthChecks("/healthz");
app.MapRazorPages(); // Sitemap.cshtml, Rss.cshtml, Feed.cshtml app.MapRazorPages(); // Sitemap.cshtml, Rss.cshtml, Feed.cshtml
app.MapStaticAssets(); app.MapStaticAssets();
// Blazor WebAssembly - 관리자 앱은 /taxbaik/admin 아래에서만 렌더링
app.MapGroup("/taxbaik/admin")
.MapRazorComponents<TaxBaik.WasmClient.Components.Admin.App>()
.AddInteractiveWebAssemblyRenderMode()
.AllowAnonymous();
// SPA 라우팅 폴백 // SPA 라우팅 폴백
app.MapFallbackToFile("admin/{*path:nonfile}", "admin/index.html"); app.MapFallbackToFile("admin/{*path:nonfile}", "admin/index.html");
app.MapFallbackToFile("portal/{*path:nonfile}", "portal/index.html"); app.MapFallbackToFile("portal/{*path:nonfile}", "portal/index.html");