feat(auth): implement option 3 architecture - server InteractiveServer login + client WASM dashboard

- Add Server.AddInteractiveServerComponents() + AddInteractiveServerRenderMode()
- Create Server AuthLayout for login form (MudBlazor)
- Implement LoginSimple.razor with @rendermode InteractiveServer in Server project
- Update App.razor: CascadingAuthenticationState + Router with AppAssembly=Server
- Fix Client MudBlazor Providers in MainLayout + AuthLayout
- Update Playwright tests: use dynamic selectors for MudTextField (auto-generated IDs)
- Build: 0 errors, 0 warnings
- API: /api/auth/login fully operational (200 OK confirmed)
- Playwright E2E test: 1 passed

Architecture:
/login    → Server InteractiveServer (MudBlazor form)
/         → Client WebAssembly (Dashboard)
/api/*    → Server Endpoints

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-07-05 23:10:54 +09:00
parent 98501c0d2f
commit 53db2f63e3
27 changed files with 1012 additions and 296 deletions
+76
View File
@@ -0,0 +1,76 @@
import { test } from '@playwright/test';
test('WASM 페이지 HTML 디버깅', async ({ page }) => {
console.log('\n╔════════════════════════════════════════════════════╗');
console.log('║ WASM 페이지 HTML 디버깅 ║');
console.log('╚════════════════════════════════════════════════════╝\n');
await page.goto('http://localhost:5265/wasm-test');
await page.waitForLoadState('networkidle');
await page.waitForTimeout(2000);
// 전체 HTML 가져오기
const html = await page.content();
// blazor.web.js 로드 확인
if (html.includes('blazor.web.js')) {
console.log('✅ blazor.web.js 스크립트 태그 found');
} else {
console.log('❌ blazor.web.js 스크립트 태그 NOT found');
}
// MudBlazor 로드 확인
if (html.includes('MudBlazor.min.js')) {
console.log('✅ MudBlazor.min.js 스크립트 태그 found');
} else {
console.log('❌ MudBlazor.min.js 스크립트 태그 NOT found');
}
// MudContainer 확인
if (html.includes('mud-container')) {
console.log('✅ MudContainer 컴포넌트 렌더링됨');
} else {
console.log('❌ MudContainer 컴포넌트 NOT 렌더링됨');
}
// app div 확인
if (html.includes('id="app"')) {
console.log('✅ id="app" div found');
} else {
console.log('❌ id="app" div NOT found');
}
// MudPaper 확인
if (html.includes('mud-paper')) {
console.log('✅ MudPaper 컴포넌트 렌더링됨');
} else {
console.log('❌ MudPaper 컴포넌트 NOT 렌더링됨');
}
// Blazor 스크립트 로드 확인
if (html.includes('_framework/blazor.web.js')) {
console.log('✅ _framework/blazor.web.js 로드 경로 correct');
} else {
console.log('❌ _framework/blazor.web.js 로드 경로 NOT correct');
}
// HTML 일부 출력
console.log('\n📝 <body> 태그 일부:');
const bodyMatch = html.match(/<body[^>]*>/i);
if (bodyMatch) {
console.log(bodyMatch[0]);
}
console.log('\n📝 스크립트 태그들:');
const scriptMatches = html.match(/<script[^>]*src="[^"]*"[^>]*><\/script>/gi);
if (scriptMatches) {
scriptMatches.forEach((script, i) => {
if (script.includes('blazor') || script.includes('MudBlazor') || script.includes('_framework')) {
console.log(` [${i}] ${script}`);
}
});
}
console.log('\nHTML 길이:', html.length);
console.log('첫 3000자:', html.substring(0, 3000));
});