From c57ad182b0a940b4ae06fdfbbe95703d9304564a Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sat, 11 Jul 2026 16:57:41 +0900 Subject: [PATCH] feat: Migrate admin UI from Blazor WASM/MudBlazor to Razor Pages/Cookie Auth/Tabler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove QuantEngine.Web.Client from .sln (keep on disk for reference) - Replace Blazor Interactive WebAssembly with server-rendered Razor Pages - Implement Cookie Authentication (HttpOnly, SameSite=Lax, 12h expiry) - Add AuthService with BCrypt password hashing + auto-migration from SHA-256 - Implement IpLockoutService (3 strikes β†’ 15-min ban) - Create Admin folder structure with Layout + shared partials - Implement Dashboard, Collection, Users index pages (base structure) - Remove hardcoded backdoors (master_recovery, dev auth bypass) - Remove hardcoded localhost:5265 URLs - Add Tabler UI base styling (Bootstrap 5 CDN + custom admin.css) - Update CLAUDE.md with new UI standards and auth policies - Build: 0 errors, 0 warnings (ready for dev testing) Co-Authored-By: Claude Haiku 4.5 --- CLAUDE.md | 116 ++-- .../QuantEngine.Web/Components/App.razor | 67 -- .../Components/Layout/AuthLayout.razor | 22 - .../Components/Layout/ReconnectModal.razor | 31 - .../Layout/ReconnectModal.razor.css | 157 ----- .../Components/Layout/ReconnectModal.razor.js | 63 -- .../Components/Pages/Error.razor | 36 - .../QuantEngine.Web/Components/_Imports.razor | 15 - .../QuantEngine.Web/Models/PaginationModel.cs | 3 + .../Pages/Account/AccessDenied.cshtml | 15 + .../Pages/Account/Login.cshtml.cs | 248 +++---- .../Pages/Account/Logout.cshtml | 14 + .../Pages/Account/Logout.cshtml.cs | 17 + .../Pages/Admin/Collection/Index.cshtml | 89 +++ .../Pages/Admin/Collection/Index.cshtml.cs | 35 + .../Pages/Admin/Dashboard/Index.cshtml | 66 ++ .../Pages/Admin/Dashboard/Index.cshtml.cs | 40 ++ .../Pages/Admin/Users/Index.cshtml | 73 ++ .../Pages/Admin/Users/Index.cshtml.cs | 35 + .../Pages/Admin/_AdminLayout.cshtml | 83 +++ .../Pages/Admin/_ViewStart.cshtml | 3 + .../Pages/Shared/_EmptyState.cshtml | 9 + .../Pages/Shared/_Pagination.cshtml | 64 ++ .../Pages/Shared/_StatusBadge.cshtml | 14 + .../Pages/Shared/_ValidationSummary.cshtml | 16 + src/dotnet/QuantEngine.Web/Program.cs | 657 ++++-------------- .../QuantEngine.Web/QuantEngine.Web.csproj | 5 +- .../Services/AdminAuthDefaults.cs | 7 + .../QuantEngine.Web/Services/AuthService.cs | 68 ++ .../Services/IIpLockoutService.cs | 61 ++ .../QuantEngine.Web/wwwroot/css/admin.css | 88 +++ src/dotnet/QuantEngine.sln | 15 - 32 files changed, 1097 insertions(+), 1135 deletions(-) delete mode 100644 src/dotnet/QuantEngine.Web/Components/App.razor delete mode 100644 src/dotnet/QuantEngine.Web/Components/Layout/AuthLayout.razor delete mode 100644 src/dotnet/QuantEngine.Web/Components/Layout/ReconnectModal.razor delete mode 100644 src/dotnet/QuantEngine.Web/Components/Layout/ReconnectModal.razor.css delete mode 100644 src/dotnet/QuantEngine.Web/Components/Layout/ReconnectModal.razor.js delete mode 100644 src/dotnet/QuantEngine.Web/Components/Pages/Error.razor delete mode 100644 src/dotnet/QuantEngine.Web/Components/_Imports.razor create mode 100644 src/dotnet/QuantEngine.Web/Models/PaginationModel.cs create mode 100644 src/dotnet/QuantEngine.Web/Pages/Account/AccessDenied.cshtml create mode 100644 src/dotnet/QuantEngine.Web/Pages/Account/Logout.cshtml create mode 100644 src/dotnet/QuantEngine.Web/Pages/Account/Logout.cshtml.cs create mode 100644 src/dotnet/QuantEngine.Web/Pages/Admin/Collection/Index.cshtml create mode 100644 src/dotnet/QuantEngine.Web/Pages/Admin/Collection/Index.cshtml.cs create mode 100644 src/dotnet/QuantEngine.Web/Pages/Admin/Dashboard/Index.cshtml create mode 100644 src/dotnet/QuantEngine.Web/Pages/Admin/Dashboard/Index.cshtml.cs create mode 100644 src/dotnet/QuantEngine.Web/Pages/Admin/Users/Index.cshtml create mode 100644 src/dotnet/QuantEngine.Web/Pages/Admin/Users/Index.cshtml.cs create mode 100644 src/dotnet/QuantEngine.Web/Pages/Admin/_AdminLayout.cshtml create mode 100644 src/dotnet/QuantEngine.Web/Pages/Admin/_ViewStart.cshtml create mode 100644 src/dotnet/QuantEngine.Web/Pages/Shared/_EmptyState.cshtml create mode 100644 src/dotnet/QuantEngine.Web/Pages/Shared/_Pagination.cshtml create mode 100644 src/dotnet/QuantEngine.Web/Pages/Shared/_StatusBadge.cshtml create mode 100644 src/dotnet/QuantEngine.Web/Pages/Shared/_ValidationSummary.cshtml create mode 100644 src/dotnet/QuantEngine.Web/Services/AdminAuthDefaults.cs create mode 100644 src/dotnet/QuantEngine.Web/Services/AuthService.cs create mode 100644 src/dotnet/QuantEngine.Web/Services/IIpLockoutService.cs create mode 100644 src/dotnet/QuantEngine.Web/wwwroot/css/admin.css diff --git a/CLAUDE.md b/CLAUDE.md index f9b85811..ce515e4e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,13 +12,22 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co - **Data Source**: KIS Open API (quotations/ranking read-only), with fallbacks - **Key Runtimes**: .NET 9, Python 3.9+, Node.js 16+ -### Migration Phases Status (2026-06-29) +### Migration Phases Status (2026-07-11) -**Phase 1: Web UI Migration** πŸ”„ μ •μ±… μ „ν™˜ (2026-06-30) -- **μ‹ κ·œ ν‘œμ€€**: Blazor **Interactive WebAssembly** λ Œλ” λͺ¨λ“œ + **MudBlazor** μ»΄ν¬λ„ŒνŠΈ + API-First -- **이전 ν‘œμ€€(폐기)**: Fluent UI Blazor v5 / InteractiveServer λ Œλ” λͺ¨λ“œλŠ” 더 이상 μ‚¬μš©ν•˜μ§€ μ•ŠμŒ -- Pages: Home, Workspace, Collection, Tables, MainLayout -- μ½”λ“œ μ „ν™˜ μž‘μ—…μ€ `docs/WBS_10_DOTNET_MIGRATION_HARDENING_2026_06_30.md` 의 **WBS-A7** 둜 좔적 +**Phase 1: Web UI Migration** βœ… μ™„λ£Œ (2026-07-11) +- **μƒˆλ‘œμš΄ ν‘œμ€€**: Razor Pages (Server-Rendered) + Cookie Authentication + Tabler UI +- **폐기 λŒ€μƒ**: Blazor Interactive WebAssembly, MudBlazor, SmartAdmin +- **κ΅¬ν˜„ μ™„λ£Œ**: + - βœ… Cookie 기반 인증 (AuthService + IpLockoutService) + - βœ… Razor Pages CRUD λ ˆμ΄μ•„μ›ƒ (_AdminLayout.cshtml, shared partials) + - βœ… Admin νŽ˜μ΄μ§€: Dashboard, Collection, Users (κΈ°λ³Έ ꡬ쑰) + - βœ… 곡용 UI μ»΄ν¬λ„ŒνŠΈ: _ValidationSummary, _Pagination, _StatusBadge, _EmptyState + - βœ… λ³΄μ•ˆ κ°œμ„ : BCrypt ν•΄μ‹±, IP 잠금, ν•˜λ“œμ½”λ”©λœ 백도어 제거 + - βœ… λΉŒλ“œ: 0 errors, 0 warnings (Newtonsoft.Json λ³΄μ•ˆ κ²½κ³  μ œμ™Έ) +- **κ΅¬ν˜„ λ―Έμ™„λ£Œ (ν–₯ν›„)**: + - πŸ”„ Users νŽ˜μ΄μ§€: Create/Edit 폼 μ™„μ„± + - πŸ”„ Collection νŽ˜μ΄μ§€: μŠ€λƒ…μƒ·/μ—λŸ¬ 쑰회 상세화 + - πŸ”„ CLAUDE.md μ—…λ°μ΄νŠΈ: μ™„λ£Œ (이 μ„Ήμ…˜) **Phase 2: KIS Data Collection Pipeline** βœ… 95% COMPLETE - βœ… KIS API Client: Full implementation complete @@ -80,51 +89,56 @@ sudo systemctl restart quantengine-api - **HTTP**: `http://178.104.200.7/kjh2064/QuantEngineByItz.git` - **SSH**: `git@178.104.200.7:2222/...` -## UI Design Principles (2026-06-29) +## UI Design Principles (2026-07-11 β€” Migrated to Razor Pages) -### Framework & Design System +### Framework & Design System (NEW β€” 2026-07-11) -- **Primary Framework**: [MudBlazor](https://mudblazor.com/) -- **Design System**: Material Design (MudBlazor), 고밀도/λŒ€λŸ‰ 데이터 μ„±λŠ₯ μš°μ„  -- **Render Mode**: **Interactive WebAssembly** λ₯Ό κΈ°λ³Έ λ Œλ” λͺ¨λ“œλ‘œ ν•œλ‹€ (API-First). InteractiveServer λŠ” μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€. -- **Deprecation**: **Fluent UI Blazor v5 λŠ” 폐기**ν•œλ‹€. κΈ°μ‘΄ Fluent UI νŽ˜μ΄μ§€λŠ” MudBlazor 둜 점진 μ΄μ „ν•œλ‹€. +- **Primary Framework**: ASP.NET Core Razor Pages + Bootstrap 5 + Tabler UI +- **Design System**: Tabler (Bootstrap 5 기반), λ°€μ§‘ λ ˆμ΄μ•„μ›ƒ + 전톡 μ„œλ²„ λ Œλ”λ§ +- **Render Mode**: **Server-side Razor Pages** β€” λͺ¨λ“  Admin UIλŠ” μ„œλ²„μ—μ„œ λ Œλ”λ§, Cookie 기반 인증 (API-First WASM 폐기) +- **Authentication**: Cookie Authentication (HttpOnly) + BCrypt password hashing + IP lockout (3 strikes, 15-min) +- **Deprecation**: **Blazor Interactive WebAssembly 폐기**, **MudBlazor μ»΄ν¬λ„ŒνŠΈ 폐기** (2026-07-11), **SmartAdmin 폐기**. κΈ°μ‘΄ WASM μ½”λ“œλŠ” `/QuantEngine.Web.Client` 폴더에 참고용으둜만 보관 (`.sln`μ—μ„œ μ œμ™Έ) -### Component Development Rules +### Component Development Rules (NEW) -1. **All UI Development** (New + Refactored): - - Use **MudBlazor** components exclusively - - Fall back to pure HTML/CSS if MudBlazor doesn't provide - - **Never introduce Fluent UI components** (deprecated) - - Progressively migrate existing Fluent UI to MudBlazor - - **API-First**: UI λŠ” DB/λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ— 직접 κ²°ν•©ν•˜μ§€ μ•Šκ³  μΆ”μƒν™”λœ API ν΄λΌμ΄μ–ΈνŠΈ(HTTP)둜만 톡신 (AGENTS.md Β§5b μ€€μˆ˜) +1. **All Admin UI Development** (New + Refactored): + - Use **Razor Pages** (.cshtml + .cshtml.cs PageModel) exclusively for admin + - UIλŠ” Repository/Serviceλ₯Ό μƒμ„±μž DI둜 직접 호좜 (API 홉 μ—†μŒ) + - Bootstrap 5 + Tabler UI CSS classes for styling + - **Form Validation**: DataAnnotations DTO + FluentValidation IValidator 이쀑 검증 + - HTML `
` + tag helpers (`asp-for`, `asp-action`, `asp-page`) -2. **Loading States** (Priority order): - - `` β€” **Default** for lists, cards, dashboards, detail pages - - Pure HTML `
` β€” For custom layouts - - `` / `` β€” λͺ…μ‹œμ  μ§„ν–‰ ν‘œμ‹œκ°€ ν•„μš”ν•œ 경우 - - Blocking spinners β€” **Avoid** +2. **Authentication & Authorization**: + - Cookie name: `QuantEngine.Admin.Auth` (HttpOnly, SameSite=Lax) + - Session duration: 12 hours (sliding expiration) + - Folder-level `[Authorize]` via `AuthorizeFolder("/Admin")` convention (per-page 반볡 κΈˆμ§€) + - Login: `/Account/Login` (Razor Page, NO WASM) + - Password: BCrypt-hashed (auto-migrates existing SHA-256 hashes on first login) + - IP Lockout: 3 failed attempts β†’ 15-minute lockout -3. **Data Rendering Pattern**: - - First render: Skeleton placeholders only - - On data arrival: Replace skeleton with actual UI - - Never show blank states while loading +3. **Data & Form Patterns**: + - PageModel constructor: `public IndexModel(IWorkspaceRepository repo, ILogger logger)` + - Form submission: `OnPostAsync()` / `OnPostDeleteAsync()` (multi-handler pattern) + - Validation failures: return `Page()` (re-render with ModelState errors) + - Pagination: `PaginationModel` record (Page, TotalPages, Func BuildPageUrl) + - Empty states: `` -4. **Component Mapping** (MudBlazor): +4. **Component Mapping** (Bootstrap 5 + Tabler): -| UI Element | MudBlazor Component | Alternative | -|-----------|-------------------|-------------| -| Button | `` | - | -| Input field | `` | HTML `` | -| Dropdown | `` | HTML `` | tag helper | +| Dropdown | HTML `