fix: per-page WASM render mode, Contact checkbox binding, Telegram inquiry channel
TaxBaik CI/CD / build-and-deploy (push) Successful in 2m11s

- Admin: replace the global @rendermode on <Routes>/<Router> with per-page
  render mode. Login.razor now prerenders (form visible before WASM loads);
  every other [Authorize] page stays prerender: false to avoid the
  AuthorizeRouteView blank-render regression from earlier attempts. Adds a
  "준비 중" -> "로그인" splash tied to WASM boot completion, and lets the
  authenticated-shell loading overlay stay up until AdminShell actually renders.
- Contact.cshtml: fix the "Agree" checkbox missing value="true" - a checked
  box sent the browser-default "on", which bool model binding can't parse,
  so ModelState.IsValid silently went false and OnPostAsync returned a blank
  form with no visible error on every submission. Validation summary widened
  from ModelOnly to All so this class of failure isn't silent again.
- TelegramInquiryNotificationService: read Telegram:InquiryChatId (falling
  back to ChatId) instead of only ChatId, matching the channel routing
  CLAUDE.md documents and deploy.yml already provisions as separate secrets.
- Reconcile CLAUDE.md's self-contradicting Phase 8 prerender notes (Phase 9),
  rewrite validate_admin_render.sh for the per-page design, and add a
  SmartAdmin 5.5 design reference section to DOUZONE_UX_GUIDE.md for future
  admin screens (existing screens unchanged, tracked as WBS P4-03).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 10:15:27 +09:00
parent d015bb6c92
commit e5981769b9
42 changed files with 198 additions and 77 deletions
+51 -33
View File
@@ -1,57 +1,75 @@
#!/usr/bin/env bash
set -euo pipefail
# Phase 8: WebAssembly 마이그레이션 - 기능 우선 아키텍처 (2026-07-03)
# Phase 9: 어드민 페이지별 렌더모드 정상화 (2026-07-03)
#
# DESIGN DECISION: prerender: false (not true)
# DESIGN: Router/Routes에는 렌더모드를 지정하지 않고, 페이지별로 개별 지정한다.
#
# RATIONALE:
# - prerender: true = SSR (Server-Side Rendering) - 서버가 정적 HTML 미리 생성
# - InteractiveWebAssembly = CSR (Client-Side Rendering) - 클라이언트에서 동적 렌더링
# - These are contradictory: cannot prerender interactive WebAssembly content
# - Blazor Web App은 "전역 렌더모드"와 "페이지별 렌더모드" 중 하나만 선택할 수 있다.
# - Router/Routes에 @rendermode를 지정하면 하위 모든 페이지의 개별 @rendermode는 무시된다.
# - 로그인만 prerender: true가 필요하고(흰 화면 방지), 나머지 [Authorize] 페이지는
# prerender: false가 필요하다(인증 컨텍스트 없이 prerender 시 AuthorizeRouteView가
# 빈 화면을 그리는 문제를 피하기 위함). 이 둘을 동시에 만족하려면 전역 지정을 버리고
# 페이지별 지정으로 가야 한다.
#
# OBSERVED PROBLEM with prerender: true:
# 1. Unauthenticated users see prerendered HTML (no auth context)
# 2. AuthorizeRouteView renders nothing (authorized content cannot prerender)
# 3. After login, WebAssembly tries to render same component differently
# 4. Conflict: static prerendered HTML vs. dynamic WASM runtime
#
# SOLUTION: prerender: false
# - App boots to blank screen briefly (WebAssembly loading ~0.5-2s)
# - After load: all protected pages render correctly with auth
# - No conflicting render modes
# - Functional > Performance optimization
#
# See CLAUDE.md Phase 8 for architecture details.
# See CLAUDE.md Phase 9 for architecture details.
app_file="TaxBaik.Web.Client/Components/Admin/App.razor"
routes_file="TaxBaik.Web.Client/Components/Admin/Routes.razor"
login_file="TaxBaik.Web.Client/Components/Admin/Pages/Login.razor"
for file in "$app_file" "$login_file"; do
for file in "$app_file" "$routes_file" "$login_file"; do
if [ ! -f "$file" ]; then
echo "Missing admin render file: $file" >&2
exit 1
fi
done
# Require WebAssemblyRenderMode (regardless of prerender value)
if ! grep -nE "InteractiveWebAssemblyRenderMode" "$app_file" >/dev/null; then
echo "Admin shell must use InteractiveWebAssemblyRenderMode." >&2
exit 1
fi
# Reject InteractiveServerRenderMode (Blazor Server architecture forbidden)
if grep -nE "InteractiveServerRenderMode" "$app_file" >/dev/null; then
# Reject InteractiveServerRenderMode anywhere (Blazor Server architecture forbidden)
if grep -rnE "InteractiveServerRenderMode" "$app_file" "$routes_file" >/dev/null; then
echo "Admin shell must NOT use InteractiveServerRenderMode (Blazor Server)." >&2
exit 1
fi
# Login page also requires WebAssembly mode
# Accept both: @rendermode InteractiveWebAssembly OR @rendermode @(new InteractiveWebAssemblyRenderMode(...))
if ! grep -nE "InteractiveWebAssembly" "$login_file" >/dev/null; then
echo "Login page must use InteractiveWebAssemblyRenderMode or @rendermode InteractiveWebAssembly." >&2
# Router/Routes must NOT declare a global rendermode boundary.
# A global rendermode on <Routes> or <Router> overrides every per-page @rendermode
# directive beneath it, which is exactly the bug this design fixes.
if grep -nE "@rendermode" "$app_file" >/dev/null; then
echo "App.razor's <Routes> must not declare a global @rendermode (breaks per-page prerender control)." >&2
exit 1
fi
echo "✅ Admin render harness passed (WebAssembly mode verified)."
echo " ️ Note: prerender: false by design (protects @Authorize content from SSR conflicts)"
if grep -nE "@rendermode" "$routes_file" >/dev/null; then
echo "Routes.razor's <Router> must not declare a global @rendermode (breaks per-page prerender control)." >&2
exit 1
fi
# Login page must explicitly prerender (shows the login form in the first HTML response).
if ! grep -nE "InteractiveWebAssemblyRenderMode\(\s*prerender:\s*true\s*\)" "$login_file" >/dev/null; then
echo "Login page must use InteractiveWebAssemblyRenderMode(prerender: true) so the form renders before WASM loads." >&2
exit 1
fi
# Only routable pages (files with a @page directive) need their own render mode.
# Child components (e.g. BlogForm.razor, FilingTable.razor) inherit the render
# mode of whichever page hosts them and must NOT declare their own.
missing_rendermode=0
while IFS= read -r -d '' page; do
[ "$page" = "$login_file" ] && continue
if ! grep -qE "^@page " "$page"; then
continue
fi
if ! grep -nE "@rendermode" "$page" >/dev/null; then
echo "⚠️ $page has no @rendermode directive (will not be interactive)." >&2
missing_rendermode=1
fi
done < <(find TaxBaik.Web.Client/Components/Admin/Pages -name "*.razor" -print0)
if [ "$missing_rendermode" -ne 0 ]; then
echo "One or more admin pages are missing an explicit @rendermode directive." >&2
exit 1
fi
echo "✅ Admin render harness passed (per-page render mode verified)."
echo " ️ Login: prerender: true (visible before WASM loads). Other pages: WebAssembly-interactive."