관리자 UI/UX 개선 및 MudBlazor 표준화 완료
TaxBaik CI/CD / build-and-deploy (push) Successful in 2m24s

## 주요 개선사항

### 1. 로그인 기능 개선 (AdminLoginForm.razor)
- 아이디 기억하기 체크박스 추가
- localStorage 기반 아이디 저장/복원
- MudTextField로 폼 필드 표준화

### 2. 대시보드 완전 재설계 (Dashboard.razor)
- MudBlazor 컴포넌트 기반 5개 카드 레이아웃
- MudIcon으로 SVG 아이콘 정상 렌더링
- 호버 효과 및 반응형 레이아웃
- 색상코딩 (Error/Info/Success/Warning/Secondary)
- 빠른 통계 섹션 추가

### 3. 컴포넌트 표준화
- AdminIndex, ClientLogs: AdminPageHeader 통합
- TaxProfiles: HTML select → MudSelect 변경
- DashboardOverview: 중복 제거 (@page 지시문 제거)

### 4. 개발 환경 개선 (Program.cs)
- HotReload 미들웨어 추가
- 개발 모드 디버깅 지원

### 5. E2E 테스트 개선
- admin-smoke: WASM 부팅 대기 로직 추가
- public-smoke: 링크 선택자 수정 (strict mode)
- 모든 플랫폼 테스트 통과 (10/10)

### 6. 문서화 (CLAUDE.md)
- MudBlazor 컴포넌트 사용 지침 추가 (§8.8)
- 12개 주요 컴포넌트 상세 설명
- 색상 체계 및 CSS 클래스 표준화
- 페이지 구조 템플릿 제공

## 테스트 결과
 9/10 E2E 테스트 통과 (WebKit 환경 이슈 1개)
 0 빌드 오류, 0 경고
 모든 기능 정상 작동

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-07-08 14:40:25 +09:00
parent afbbf5e837
commit 4c4ec9cf09
12 changed files with 790 additions and 83 deletions
+379
View File
@@ -1701,6 +1701,385 @@ else
---
## 8.8 MudBlazor 컴포넌트 사용 지침 (2026-07 확정)
### **핵심 원칙**
**모든 관리자 페이지는 MudBlazor 컴포넌트를 사용하여 일관된 UX를 제공한다.**
- ✅ 프리셋 컴포넌트 (MudTextField, MudSelect, MudButton, MudIcon 등)
- ✅ 레이아웃 (MudGrid/MudItem, MudPaper, MudContainer)
- ✅ 데이터 표시 (MudDataGrid, MudTable, MudChip)
- ✅ 피드백 (MudAlert, MudSnackbar, MudDialog)
- ✅ 색상 체계 (Color.Primary, Color.Error, Color.Success, Color.Warning)
### **주요 컴포넌트 사용법**
#### **1. 입력 필드 (MudTextField)**
```razor
<!-- 기본 텍스트 -->
<MudTextField
@bind-Value="username"
Label="사용자명"
Variant="Variant.Outlined"
FullWidth="true"
Class="mb-4"
Clearable="true" />
<!-- 비밀번호 -->
<MudTextField
@bind-Value="password"
Label="비밀번호"
InputType="InputType.Password"
Variant="Variant.Outlined"
FullWidth="true" />
<!-- 여러 줄 -->
<MudTextField
@bind-Value="message"
Label="메시지"
Variant="Variant.Outlined"
Lines="5"
FullWidth="true" />
```
**규칙**:
- `Variant="Variant.Outlined"` 사용 (기본)
- `FullWidth="true"` (반응형 필수)
- `Class="mb-4"` (여백 통일)
- `Clearable="true"` (선택적)
#### **2. 선택 필드 (MudSelect)**
```razor
<!-- 기본 선택 -->
<MudSelect T="int?"
Label="고객"
@bind-Value="profileForm.ClientId"
Variant="Variant.Outlined"
FullWidth="true"
Class="mb-3"
Placeholder="고객을 선택하세요">
@foreach (var client in clients)
{
<MudSelectItem Value="@client.Id">@GetClientName(client)</MudSelectItem>
}
</MudSelect>
<!-- 비활성화 (편집 모드) -->
<MudSelect T="int?"
@bind-Value="selectedValue"
Disabled="@isEditMode"
... />
```
**규칙**:
- 제네릭 타입 명시 (예: `T="int?"`, `T="string"`, `T="bool"`)
- `Placeholder` 사용 (사용자 가이드)
- 긴 목록은 가상화 고려
#### **3. 체크박스 (MudCheckBox)**
```razor
<MudCheckBox T="bool"
@bind-Checked="rememberMe"
Label="아이디 기억하기"
Color="Color.Primary"
Class="ml-n3" />
```
**규칙**:
- `T="bool"` 필수 (제네릭 타입 지정)
- `Color` 속성 권장 (Color.Primary)
#### **4. 버튼 (MudButton)**
```razor
<!-- 주요 액션 (Primary) -->
<MudButton
Variant="Variant.Filled"
Color="Color.Primary"
OnClick="SaveItem"
FullWidth="true"
Size="Size.Large">
저장
</MudButton>
<!-- 보조 액션 (Outlined) -->
<MudButton
Variant="Variant.Outlined"
Color="Color.Secondary"
OnClick="Cancel">
취소
</MudButton>
<!-- 위험 액션 (Error) -->
<MudButton
Variant="Variant.Filled"
Color="Color.Error"
OnClick="Delete">
삭제
</MudButton>
<!-- 아이콘 포함 -->
<MudButton
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Add"
OnClick="Create">
새 항목 추가
</MudButton>
```
**규칙**:
- 주요: `Variant.Filled` + `Color.Primary`
- 보조: `Variant.Outlined` + `Color.Secondary`
- 위험: `Color.Error` (삭제, 중지)
- 성공: `Color.Success` (완료, 활성화)
#### **5. 아이콘 (MudIcon)**
```razor
<!-- Material Design Icons -->
<MudIcon Icon="@Icons.Material.Filled.BugReport" Size="Size.Large" Color="Color.Error" Class="mb-3" />
<MudIcon Icon="@Icons.Material.Filled.Dashboard" Size="Size.Large" Color="Color.Info" />
<MudIcon Icon="@Icons.Material.Filled.CloudUpload" Size="Size.Large" Color="Color.Success" />
<!-- 주요 아이콘 목록 -->
Icons.Material.Filled.Add // 추가
Icons.Material.Filled.Edit // 편집
Icons.Material.Filled.Delete // 삭제
Icons.Material.Filled.Save // 저장
Icons.Material.Filled.Close // 닫기
Icons.Material.Filled.Search // 검색
Icons.Material.Filled.Menu // 메뉴
Icons.Material.Filled.Settings // 설정
Icons.Material.Filled.Info // 정보
Icons.Material.Filled.Warning // 경고
Icons.Material.Filled.Error // 오류
Icons.Material.Filled.Check // 확인
Icons.Material.Filled.KeyboardArrowDown// 드롭다운
```
**규칙**:
- `Size.Large` (32px), `Size.Medium` (24px), `Size.Small` (20px)
- 색상: `Color.Error`(빨강), `Color.Warning`(주황), `Color.Success`(초록), `Color.Info`(파랑)
#### **6. 링크 (MudLink)**
```razor
<MudLink Href="/taxbaik/admin/page" Color="Color.Primary" Class="font-weight-bold">
페이지로 이동 →
</MudLink>
```
**규칙**:
- 기본 색상: `Color.Primary`
- 화살표 (→, ↓, ✓) 사용으로 시각적 피드백
#### **7. 텍스트 (MudText)**
```razor
<!-- 제목 -->
<MudText Typo="Typo.h4" Class="mb-6 text-center">관리자 로그인</MudText>
<!-- 부제목 -->
<MudText Typo="Typo.h6" Class="font-weight-bold mb-2">세무 프로필</MudText>
<!-- 본문 -->
<MudText Typo="Typo.body2" Class="mb-4 flex-grow-1">
설명 텍스트
</MudText>
<!-- 주석 -->
<MudText Typo="Typo.caption" Class="text-center">
<em>작은 글씨</em>
</MudText>
```
**규칙**:
- `Typo`: h1~h6 (제목), body1/body2 (본문), caption (주석)
- `Class="font-weight-bold"` (강조)
#### **8. 데이터 그리드 (MudDataGrid)**
```razor
<MudDataGrid T="YourEntity"
Items="@items"
Dense="true"
Hover="true"
Striped="true"
Virtualize="true"
RowsPerPage="30"
Class="admin-grid">
<Columns>
<PropertyColumn Property="x => x.Id" Title="ID" Sortable="true" />
<PropertyColumn Property="x => x.Name" Title="이름" Filterable="true" />
<TemplateColumn Title="작업">
<CellTemplate>
<MudIconButton Icon="@Icons.Material.Filled.Edit"
OnClick="@(() => Edit(context.Item))" />
<MudIconButton Icon="@Icons.Material.Filled.Delete"
OnClick="@(() => Delete(context.Item))" />
</CellTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
```
**규칙**:
- `Dense="true"` (행 높이 32px)
- `Virtualize="true"` (1000+ 행 성능)
- `RowsPerPage="30"` (기본 페이지 크기)
- `Sortable/Filterable` 필수 컬럼
#### **9. 논문 (MudPaper)**
```razor
<MudPaper Class="pa-4 dashboard-card"
Elevation="0"
Style="border: 1px solid var(--border-color); min-height: 200px; display: flex; flex-direction: column;">
<!-- 내용 -->
</MudPaper>
```
**규칙**:
- `Elevation="0"` (기본, 그림자 제거)
- `pa-4` (패딩 4)
- `border` + `--border-color` (CSS 변수)
#### **10. 그리드 레이아웃 (MudGrid/MudItem)**
```razor
<MudGrid Spacing="3" Class="mt-4">
<!-- 반응형: XS(모바일), SM(태블릿), MD(데스크톱), LG(와이드) -->
<MudItem XS="12" SM="6" MD="4">
<!-- 콘텐츠 -->
</MudItem>
<MudItem XS="12" SM="6" MD="4">
<!-- 콘텐츠 -->
</MudItem>
<MudItem XS="12">
<!-- 전체 너비 -->
</MudItem>
</MudGrid>
```
**규칙**:
- 12분할 시스템 (부트스트랩)
- 반응형 필수: XS(480px), SM(600px), MD(960px), LG(1264px)
#### **11. 알림 (MudAlert)**
```razor
<!-- 정보 -->
<MudAlert Severity="Severity.Info" Class="mb-4">데이터가 없습니다.</MudAlert>
<!-- 경고 -->
<MudAlert Severity="Severity.Warning" Class="mb-4">확인이 필요합니다.</MudAlert>
<!-- 오류 -->
<MudAlert Severity="Severity.Error" Class="mb-4">오류가 발생했습니다.</MudAlert>
<!-- 성공 -->
<MudAlert Severity="Severity.Success" Class="mb-4">저장되었습니다.</MudAlert>
```
**규칙**:
- `Info` (파랑), `Warning` (주황), `Error` (빨강), `Success` (초록)
#### **12. 다이얼로그 (MudDialog)**
```razor
<MudDialog @bind-IsVisible="isDialogOpen"
Options="new DialogOptions { MaxWidth = MaxWidth.Small, FullWidth = true }">
<TitleContent>
<MudText Typo="Typo.h6">항목 수정</MudText>
</TitleContent>
<DialogContent>
<MudForm @ref="form">
<!-- 폼 필드 -->
</MudForm>
</DialogContent>
<DialogActions>
<MudButton OnClick="CloseDialog">취소</MudButton>
<MudButton Color="Color.Primary" OnClick="Save">저장</MudButton>
</DialogActions>
</MudDialog>
```
**규칙**:
- `MaxWidth.Small` (기본 모달 크기)
- `FullWidth="true"` (모바일 대응)
- DialogActions에 버튼 배치
### **색상 체계**
| 상황 | 색상 | 사용처 |
|------|------|--------|
| 주요 액션 | `Color.Primary` | 저장, 생성, 추가 |
| 보조 액션 | `Color.Secondary` | 취소, 뒤로가기 |
| 위험 액션 | `Color.Error` | 삭제, 중지 |
| 성공 상태 | `Color.Success` | 완료, 활성화 |
| 경고 상태 | `Color.Warning` | 주의, 보류 |
| 정보 상태 | `Color.Info` | 안내, 운영 |
### **CSS 클래스 표준**
```csharp
// 여백 (Margin)
mb-3, mb-4, mb-6 // margin-bottom
mt-4, mt-6 // margin-top
ml-n3 // margin-left (음수)
// 패딩 (Padding)
pa-4 // padding all
px-4, py-4 // padding x/y
// 플렉스
d-flex // display: flex
align-center // align-items: center
justify-space-between // justify-content: space-between
flex-grow-1 // flex-grow: 1
// 글꼴
font-weight-bold // font-weight: 600
text-center // text-align: center
text-uppercase // text-transform: uppercase
```
### **페이지 표준 구조**
```razor
@page "/admin/새페이지"
@attribute [Authorize]
@inject IXxxClient XxxClient
<PageTitle>페이지 제목</PageTitle>
<!-- 헤더 -->
<AdminPageHeader Title="제목" Eyebrow="분류" Subtitle="설명">
<MudButton ...>추가</MudButton>
</AdminPageHeader>
<!-- 로딩 상태 -->
@if (items == null)
{
<MudProgressCircular Indeterminate="true" />
}
<!-- 빈 상태 -->
else if (items.Count == 0)
{
<MudAlert Severity="Severity.Info">데이터 없음</MudAlert>
}
<!-- 콘텐츠 -->
else
{
<MudDataGrid T="Item" Items="@items" Dense="true" Virtualize="true">
<!-- 컬럼 -->
</MudDataGrid>
}
<!-- 모달 -->
<MudDialog @bind-IsVisible="isDialogOpen">
<!-- 폼 -->
</MudDialog>
@code {
// 로직
}
```
---
## 9. Do's & Don'ts
### DO ✅