From 5b024d9b9ca52da26e85845b1ae9848012f9cc3a Mon Sep 17 00:00:00 2001 From: GA Pro Date: Sun, 10 May 2026 21:21:13 +0900 Subject: [PATCH] =?UTF-8?q?docs:=2009=5FUI=5FDESIGN.md=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=8B=9C=EC=8A=A4?= =?UTF-8?q?=ED=85=9C)=20+=20=EC=B0=B8=EC=A1=B0=20=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 09_UI_DESIGN.md 신규: Ant Design 테마 토큰, 글로벌 CSS 변수, 레이아웃 규격(Header 48px / Sider 220px), 페이지 표준 3종(목록/상세/대시보드), 공통 컴포넌트 스타일(CodeBadge/MoneyText/SearchForm/DataTable/DataGrid), 등록·수정 폼 규칙(Drawer), 화면별 와이어프레임 6종, 신입 체크리스트 - 00_PROMPTS.md: 프롬프트 3 frontend-developer 가 09_UI_DESIGN.md 도 함께 참조 - 06_FRONTEND_SPEC.md: 상단에 디자인 시스템 참조 추가 Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/00_PROMPTS.md | 3 +- docs/06_FRONTEND_SPEC.md | 1 + docs/09_UI_DESIGN.md | 625 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 628 insertions(+), 1 deletion(-) create mode 100644 docs/09_UI_DESIGN.md diff --git a/docs/00_PROMPTS.md b/docs/00_PROMPTS.md index 929bda3..6eda9cd 100644 --- a/docs/00_PROMPTS.md +++ b/docs/00_PROMPTS.md @@ -91,7 +91,8 @@ Agent Teams 5명을 병렬로 스폰해줘. 1) core-architect → docs/03_CORE_SPEC.md → ga-core (VO/Mapper/XML) 2) batch-engineer → docs/04_BATCH_SPEC.md → ga-batch (8 Step) 3) api-developer → docs/05_API_SPEC.md → ga-api (Controller/Service) -4) frontend-developer → docs/06_FRONTEND_SPEC.md → ga-frontend (13 화면) +4) frontend-developer → docs/06_FRONTEND_SPEC.md + + docs/09_UI_DESIGN.md → ga-frontend (13 화면 + 디자인 시스템) 5) dba-architect → docs/08_DBA_SPEC.md → V13~V15 + 인덱스/파티션/뷰 의존성: diff --git a/docs/06_FRONTEND_SPEC.md b/docs/06_FRONTEND_SPEC.md index 1c0738d..15acebe 100644 --- a/docs/06_FRONTEND_SPEC.md +++ b/docs/06_FRONTEND_SPEC.md @@ -2,6 +2,7 @@ > Vite + React 18 + TypeScript + Ant Design 5 + AG Grid Community + React Query + Zustand. > ga-common 에서 작성한 공통 컴포넌트(02_COMMON_SPEC §10)를 반드시 재사용. +> **디자인 시스템**: `docs/09_UI_DESIGN.md` 함께 참조 (테마 토큰, 레이아웃 규격, 화면별 와이어프레임) ## 패키지 구조 diff --git a/docs/09_UI_DESIGN.md b/docs/09_UI_DESIGN.md new file mode 100644 index 0000000..007c140 --- /dev/null +++ b/docs/09_UI_DESIGN.md @@ -0,0 +1,625 @@ +# UI 디자인 시스템 (UI_DESIGN.md) + +> GA 수수료 정산 솔루션의 UI 표준. 모든 화면은 이 규칙을 따른다. +> 기술: React 18 + Ant Design 5.x + AG Grid Community +> 신입 개발자가 복붙으로 일관된 UI를 만들 수 있도록 설계. + +--- + +## 1. Ant Design 테마 커스터마이징 + +### ConfigProvider 설정 (App.tsx) +```tsx +import { ConfigProvider } from 'antd'; +import koKR from 'antd/locale/ko_KR'; + +const theme = { + token: { + // 브랜드 컬러 + colorPrimary: '#1677FF', + colorSuccess: '#0F6E56', + colorWarning: '#BA7517', + colorError: '#E24B4A', + colorInfo: '#1677FF', + + // 폰트 + fontFamily: "'Pretendard', -apple-system, sans-serif", + fontSize: 13, + fontSizeHeading1: 22, + fontSizeHeading2: 18, + fontSizeHeading3: 16, + + // 라운딩 + borderRadius: 6, + borderRadiusLG: 8, + + // 간격 + padding: 16, + paddingLG: 24, + margin: 16, + + // 배경 + colorBgContainer: '#ffffff', + colorBgLayout: '#f5f5f5', + colorBgElevated: '#ffffff', + + // 테이블 + tablePaddingHorizontal: 12, + tablePaddingVertical: 10, + tableHeaderBg: '#fafafa', + tableRowHoverBg: '#f5f7fa', + tableBorderColor: '#f0f0f0', + }, + components: { + // 사이드 메뉴 + Menu: { + itemHeight: 40, + itemMarginInline: 8, + itemBorderRadius: 6, + subMenuItemBg: 'transparent', + itemSelectedBg: '#e6f1fb', + itemSelectedColor: '#185fa5', + }, + // 테이블 + Table: { + headerBg: '#fafafa', + rowHoverBg: '#f5f7fa', + cellPaddingBlock: 10, + cellPaddingInline: 12, + headerSplitColor: '#f0f0f0', + }, + // 버튼 + Button: { + controlHeight: 32, + controlHeightSM: 28, + paddingInline: 16, + }, + // 입력 + Input: { + controlHeight: 32, + paddingInline: 10, + }, + Select: { + controlHeight: 32, + }, + // 카드 + Card: { + paddingLG: 16, + }, + }, +}; + + + + +``` + +### 폰트 설치 (index.html) +```html + +``` + +### 아이콘: Tabler Icons +```bash +pnpm add @tabler/icons-react +``` +```tsx +import { IconUsers, IconCalculator, IconDownload } from '@tabler/icons-react'; + +``` + +--- + +## 2. 글로벌 CSS 변수 (styles/variables.css) + +```css +:root { + /* 브랜드 */ + --ga-primary: #1677FF; + --ga-primary-light: #E6F1FB; + --ga-primary-dark: #0C447C; + + /* 상태 색상 (CodeBadge 등) */ + --ga-success: #0F6E56; + --ga-success-bg: #E1F5EE; + --ga-warning: #BA7517; + --ga-warning-bg: #FAEEDA; + --ga-danger: #E24B4A; + --ga-danger-bg: #FCEBEB; + --ga-info: #185FA5; + --ga-info-bg: #E6F1FB; + + /* 금액 */ + --ga-money-plus: #0F6E56; + --ga-money-minus: #E24B4A; + + /* 레이아웃 */ + --ga-sider-width: 220px; + --ga-sider-collapsed-width: 64px; + --ga-header-height: 48px; + --ga-content-padding: 20px; + --ga-page-max-width: 1400px; + + /* 간격 단위 */ + --ga-spacing-xs: 4px; + --ga-spacing-sm: 8px; + --ga-spacing-md: 12px; + --ga-spacing-lg: 16px; + --ga-spacing-xl: 24px; + + /* 그림자 (최소한만 사용) */ + --ga-shadow-card: 0 1px 2px rgba(0,0,0,0.03); + --ga-shadow-dropdown: 0 4px 12px rgba(0,0,0,0.08); +} +``` + +--- + +## 3. 레이아웃 규칙 + +### MainLayout 구조 +``` +┌─────────────────────────────────────────────┐ +│ Header (48px) │ +│ [☰] GA 정산시스템 [2026-05 ▼] [🔔3] [관리자]│ +├──────┬──────────────────────────────────────┤ +│Sider │ Content │ +│220px │ Breadcrumb │ +│ │ ┌─────────────────────────────────┐ │ +│ 메뉴 │ │ 페이지 내용 │ │ +│ │ │ │ │ +│ │ └─────────────────────────────────┘ │ +└──────┴──────────────────────────────────────┘ +``` + +### Header +- 높이: 48px, 배경: 흰색, 하단 border +- 왼쪽: 햄버거 메뉴(접기/펼치기) + 로고 "GA 정산시스템" +- 오른쪽: 정산월 MonthPicker + 알림벨(미읽음 숫자뱃지) + 사용자 Dropdown + +### Sider (사이드 메뉴) +- 너비: 220px (접으면 64px, 아이콘만) +- 배경: 흰색 +- 메뉴 아이템: 높이 40px, 좌측 아이콘 16px + 텍스트 13px +- 활성 메뉴: 배경 #E6F1FB, 텍스트 #185FA5, font-weight 500 +- 서브메뉴: 좌측 30px 인덴트 +- 메뉴 데이터: API에서 동적 로드 (GET /api/menus/my) + +### Content +- Breadcrumb: 상단 (홈 > 조직관리 > 설계사목록) +- 패딩: 20px +- 최대 너비: 1400px (중앙 정렬) + +--- + +## 4. 페이지 표준 레이아웃 (3가지) + +### 타입 A: 목록 페이지 (가장 많이 사용) +``` +┌──── 검색 폼 (SearchForm) ─────────────────┐ +│ [설계사명 ___] [상태 ▼전체] [기간 ___~___] [조회] [초기화] │ +└────────────────────────────────────────────┘ +┌──── 버튼 영역 ─────────────────────────────┐ +│ [+ 등록] [⬇ 엑셀] │ +└────────────────────────────────────────────┘ +┌──── 데이터 테이블 ─────────────────────────┐ +│ □ 설계사명 소속 직급 수수료합계 상태│ +│ □ 김영수 서울1팀 수석 12,450,000 위촉│ +│ □ 이미영 경기2팀 설계사 8,320,000 위촉│ +├────────────────────────────────────────────┤ +│ 총 1,234건 ‹ 1 2 3 ... › │ +└────────────────────────────────────────────┘ +``` +- 검색 폼: 회색 배경(#fafafa), border-radius 8px, padding 12px 16px +- 검색 조건: 한 줄에 3~4개, 버튼은 우측 +- 버튼 영역: 우측 정렬, 테이블 바로 위 margin-bottom 12px +- 등록 버튼: Primary(파란색), 엑셀: Default(흰색) +- 테이블: antd Table 또는 AG Grid + +### 타입 B: 상세 페이지 +``` +┌──── 기본 정보 카드 ─────────────────────────┐ +│ 설계사명: 김영수 소속: 서울1팀 상태: [위촉] │ +│ 전화번호: 010-****-5678 이메일: kim@ga.com │ +│ [수정] [삭제] │ +└─────────────────────────────────────────────┘ +┌──── 탭 영역 ────────────────────────────────┐ +│ [기본정보] [실적현황] [소속이력] [변경이력] │ +├─────────────────────────────────────────────┤ +│ 탭 내용... │ +└─────────────────────────────────────────────┘ +``` +- 상단 카드: 흰색 배경, border, border-radius 8px +- 탭: antd Tabs, 카드 안에 포함 +- 버튼: 카드 우상단 + +### 타입 C: 대시보드 +``` +┌──── 지표 카드 (4열) ───────────────────────┐ +│ [모집 2.4억] [유지 8,200만] [환수 1,350만] [순 3.1억]│ +└────────────────────────────────────────────┘ +┌─── 차트 (2:1) ──────┬─── 현황 ────────────┐ +│ 월별 추이 (recharts) │ 배치 진행 상태 │ +│ ▆▆▆▇█ │ ● 수신 완료 │ +│ │ ● 계산 진행중... │ +└─────────────────────┴──────────────────────┘ +┌──── 알림/오류 ──────────────────────────────┐ +│ [대사불일치] 삼성생명 5월 3건 차이 10분 전 │ +│ [파싱에러] 한화생명 12행 형식 오류 1시간 전 │ +└────────────────────────────────────────────┘ +``` +- 지표 카드: 배경 #fafafa, border-radius 8px, padding 12px +- 숫자: 20~22px, weight 500 +- 증감: ▲ 초록(양수), ▼ 빨강(음수) +- 차트: recharts, 높이 200~240px + +--- + +## 5. 공통 컴포넌트 스타일 규칙 + +### CodeBadge (상태 뱃지) +```tsx +// 상태값 → 색상 자동 매핑 +const COLOR_MAP = { + // 초록 (긍정적 완료 상태) + CONFIRMED: 'success', APPROVED: 'success', ACTIVE: 'success', + PAID: 'success', COMPLETED: 'success', MATCH: 'success', + + // 파랑 (진행 중) + CALCULATED: 'info', PENDING: 'info', PROCESSING: 'info', + REVIEWED: 'info', NEW: 'info', + + // 주황 (주의) + HOLD: 'warning', SUSPEND: 'warning', MISMATCH: 'warning', + PARTIAL: 'warning', + + // 빨강 (부정적) + REJECTED: 'danger', LEAVE: 'danger', CANCEL: 'danger', + FAILED: 'danger', LAPSED: 'danger', + + // 회색 (기본) + DRAFT: 'default', READY: 'default', +}; + +// 렌더링 +{codeName} +``` + +### MoneyText (금액 표시) +```tsx +// 양수: 초록, 음수: 빨강, 0: 회색 +// 항상 천 단위 콤마, 정수 표시 + 0 ? '#0F6E56' : amount < 0 ? '#E24B4A' : '#888' }}> + {amount >= 0 ? '' : '-'}{Math.abs(amount).toLocaleString()} + +``` + +### SearchForm (검색 폼) +```tsx +// 스타일 규칙 +// 배경: #fafafa, border-radius: 8px, padding: 12px 16px +// 조건: Row + Col (span 기준) +// - 텍스트 입력: span=6 (4개/행) +// - Select: span=4 (6개/행까지) +// - DateRange: span=8 +// - 버튼: 우측 정렬 + +
+ + +
설계사명
+ + + +
상태
+ + + + + + + + +
+
+``` + +### DataTable (목록 테이블) +```tsx +// 스타일 규칙 +// 행 높이: 42px (compact) +// 헤더: 배경 #fafafa, font-weight 500, font-size 12px +// 본문: font-size 13px +// hover: 배경 #f5f7fa +// 금액 컬럼: 우측 정렬, MoneyText +// 상태 컬럼: 중앙 정렬, CodeBadge +// 이름 컬럼: font-weight 500, 클릭 시 상세 이동 +// 페이지네이션: 우측, "총 N건" 좌측 + + `총 ${total.toLocaleString()}건`, + showSizeChanger: true, + pageSizeOptions: [20, 50, 100], + defaultPageSize: 20, + }} +/> +``` + +### DataGrid (AG Grid 래퍼) +```tsx +// AG Grid 공통 설정 +const defaultColDef = { + sortable: true, + resizable: true, + filter: true, + minWidth: 80, +}; + +const gridOptions = { + rowHeight: 36, + headerHeight: 38, + // 한글 로케일 + localeText: AG_GRID_LOCALE_KO, + // 합계행 + pinnedBottomRowData: [summaryRow], + // 셀 스타일 + getRowStyle: (params) => { + if (params.node.rowPinned) return { background: '#fafafa', fontWeight: 500 }; + }, +}; + +// AG Grid 사용 화면: 원장관리, 정산결과, 수수료율편집, 대사현황 +// 나머지는 Ant Design Table +``` + +--- + +## 6. 등록/수정 폼 규칙 + +```tsx +// 폼 레이아웃 규칙 +// 2열 배치 (Row > Col span=12) +// 레이블: 12px, color #999, 필수 표시 빨간 * +// 입력: height 32px +// Select: 공통코드는 CodeSelect 사용 +// 하단 버튼: 우측 정렬 [취소] [저장] + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + +``` + +--- + +## 7. 모달/드로워 규칙 + +``` +// 등록/수정 폼 → Drawer (우측에서 슬라이드) +// 너비: 600px (2열 폼), 400px (단순 폼) +// 제목: "설계사 등록" / "설계사 수정" +// 하단: 취소 + 저장 버튼 + +// 상세 보기 → Modal +// 너비: 720px +// Descriptions 컴포넌트로 상세 표시 + +// 확인/경고 → Modal.confirm() +// "정산을 확정하시겠습니까?" [취소] [확정] + +// 삭제 → Modal.confirm({ type: 'warning' }) +// "삭제하면 복구할 수 없습니다" [취소] [삭제] +``` + +--- + +## 8. 화면별 상세 와이어프레임 + +### 8.1 대시보드 (/) +``` +레이아웃: 타입 C (대시보드) +├── 지표 카드 4열: 모집수수료, 유지수수료, 환수금, 순지급액 +│ - 이번 달 금액 (억/만 단위 자동) +│ - 전월 대비 증감률 (▲초록/▼빨강) +│ - 카드 클릭 → 해당 원장 페이지 이동 +├── 2열 영역 +│ ├── 왼쪽(60%): 월별 추이 차트 (recharts BarChart) +│ │ - X축: 최근 6개월, Y축: 금액 +│ │ - 시리즈: 모집(파랑), 유지(초록), 환수(빨강) +│ └── 오른쪽(40%): 배치 현황 카드 +│ - Step별 상태: ● 완료(초록), ● 진행중(파랑+pulse), ○ 대기(회색) +│ - 각 Step: 이름 + 완료시간/진행시간 +│ - 에러 시: ● 빨강 + 에러 메시지 +└── 알림/오류 패널 + - 대사 불일치, 파싱 에러, 승인 대기 등 + - 뱃지 색상: 에러=빨강, 경고=주황, 정보=파랑 + - 클릭 → 해당 화면 이동 +``` + +### 8.2 조직관리 (/org) +``` +레이아웃: 2열 (좌 300px 트리 + 우 나머지 목록) +├── 좌측: 조직 트리 (antd Tree) +│ - 본사 > 지역본부 > 지점 > 팀 +│ - 드래그앤드롭 정렬 (관리자만) +│ - 노드 클릭 → 우측 설계사 목록 필터링 +│ - 우클릭 → 추가/수정/삭제 컨텍스트메뉴 +└── 우측: 설계사 목록 (타입 A) + - 검색: 이름, 상태, 직급 + - 테이블 컬럼: 설계사명, 직급, 상태, 위촉일, 수수료합계 + - 행 클릭 → 상세 (타입 B, 탭: 기본정보/실적/이력) +``` + +### 8.3 원장관리 (/ledger) +``` +레이아웃: 탭 3개 (모집/유지/예외) +├── 공통 검색: 정산월, 보험사, 설계사, 상태 +├── AG Grid (DataGrid) 사용 ← 대량 데이터 +│ - 서버사이드 페이징/정렬/필터 +│ - 컬럼 고정: 왼쪽(증권번호, 설계사명), 오른쪽(수수료합계) +│ - 합계행: 하단 고정 (pinnedBottomRow) +│ - 금액 셀: 우측 정렬, MoneyText 스타일 +│ - 상태 셀: CodeBadge +├── 예외금액 탭 추가 기능: +│ - [+ 등록] → Drawer (예외유형, 금액, 방향, 설명) +│ - 승인 워크플로우: 작성→대기→승인/반려 +│ - 승인 버튼: PermissionButton(permCode="APPROVE") +└── 엑셀 다운로드: ExcelExportButton (100만건, 진행률) +``` + +### 8.4 정산관리 (/settle) +``` +레이아웃: 탭 4개 (배치실행/정산결과/정산상세/대사) + +[배치실행 탭] +├── 정산월 선택 + [정산실행] 버튼 +├── 진행 상태: Steps 컴포넌트 (8단계) +│ - 각 Step: 이름 + 처리건수 + 소요시간 + 상태아이콘 +│ - 진행 중: 폴링으로 실시간 업데이트 (3초 간격) +│ - 에러: Step 클릭 → 에러 상세 모달 +└── 완료 시: 결과 요약 카드 (총건수, 성공, 에러, 소요시간) + +[정산결과 탭] +├── AG Grid: 설계사별 정산 결과 +│ - 컬럼: 설계사명, 소속, 모집, 유지, 예외가산, 예외차감, 오버라이드, 환수, 세전, 세금, 순지급 +│ - 합계행 +│ - 상태별 필터: 계산완료/검토/확정/지급/보류 +│ - 행 클릭 → 정산상세 탭으로 이동 +└── 버튼: [일괄확정] [엑셀다운로드] + +[정산상세 탭] +├── 설계사 선택 (상단) +├── 요약 카드 4열: 모집합계, 유지합계, 예외합계, 순지급액 +└── 탭 5개: 모집수수료 / 유지수수료 / 예외금액 / 오버라이드 / 환수 + - 각 탭 AG Grid로 상세 내역 표시 + +[대사 탭] +├── 보험사별 대사 결과 테이블 +│ - 보험사, 보험사건수, 시스템건수, 차이, 보험사금액, 시스템금액, 차이, 상태 +│ - 상태: MATCH(초록), MISMATCH(빨강) +└── 불일치 행 클릭 → 상세 모달 (건별 차이 목록) +``` + +### 8.5 수수료규정 (/rules) +``` +레이아웃: 탭 4개 (수수료율/지급률/오버라이드/환수) + +각 탭 공통: +├── 검색: 보험사/보험종류/적용기간 +├── AG Grid: 셀 편집 가능 (인라인 수정) +│ - 수정된 셀: 노란색 배경 강조 +│ - 하단: [저장] [취소] 버튼 +├── 버전 관리: +│ - 규정 수정 시 → version 자동 증가 + 기존 규정 effective_to 설정 +│ - [이력보기] 버튼 → 버전별 변경 내역 타임라인 +└── 신규 등록: [+ 규정 등록] → Drawer +``` + +### 8.6 시스템관리 (/system) + +#### 역할관리 (/system/roles) +``` +├── 역할 목록 테이블 +└── 역할 클릭 → 권한 매트릭스 + ┌──────────┬──────┬──────┬──────┬──────┬──────┬──────┐ + │ 메뉴 │ 조회 │ 등록 │ 수정 │ 삭제 │ 승인 │ 엑셀 │ + ├──────────┼──────┼──────┼──────┼──────┼──────┼──────┤ + │ 조직관리 │ ☑ │ ☑ │ ☑ │ ☐ │ ☐ │ ☑ │ + │ 정산관리 │ ☑ │ ☐ │ ☐ │ ☐ │ ☑ │ ☑ │ + │ 시스템관리 │ ☑ │ ☑ │ ☑ │ ☑ │ ☐ │ ☐ │ + └──────────┴──────┴──────┴──────┴──────┴──────┴──────┘ + [전체선택/해제 토글] [저장] +``` + +#### 공통코드관리 (/system/codes) +``` +2열 레이아웃: +├── 좌측 (300px): 코드 그룹 리스트 +│ - 선택 시 우측에 상세 코드 표시 +│ - 시스템 코드: 🔒 아이콘 + 수정 불가 +└── 우측: 상세 코드 테이블 + - 코드값, 코드명, 영문명, 정렬순서, 활성여부 + - 인라인 편집 가능 (시스템코드 제외) +``` + +#### 업로드 템플릿 관리 (/system/upload-templates) +``` +2열 레이아웃: +├── 좌측 (300px): 템플릿 목록 (카테고리별 필터) +└── 우측: 컬럼 매핑 편집기 + - 각 행: [엑셀 컬럼 입력] → [DB 필드 Select] → [변환규칙 Select] → [파라미터] + - 드래그앤드롭 순서 변경 + - [+ 행 추가] [미리보기] [저장] + - 미리보기: 샘플 엑셀 업로드 → 첫 5행 매핑 결과 테이블 +``` + +--- + +## 9. 반응형 규칙 + +``` +// 이 솔루션은 데스크톱 전용 (1280px 이상) +// 모바일 대응 불필요 (사내 관리 시스템) +// 최소 해상도: 1280 x 720 +// 권장 해상도: 1920 x 1080 + +// 1280px 미만: Sider 자동 접힘 (아이콘만) +// 1920px 이상: Content 최대 너비 1400px 중앙 정렬 +``` + +--- + +## 10. 신입 개발자 UI 체크리스트 + +새 화면 만들 때 아래 항목 확인: +- [ ] 검색 폼: SearchForm 컴포넌트 사용, 배경 #fafafa +- [ ] 목록: 단순이면 DataTable, 대량/편집이면 DataGrid +- [ ] 상태 컬럼: CodeBadge 사용 (하드코딩 색상 금지) +- [ ] 금액 컬럼: MoneyText 사용 (양수 초록, 음수 빨강) +- [ ] Select: CodeSelect 사용 (공통코드 연동) +- [ ] 버튼: PermissionButton 사용 (권한 제어) +- [ ] 엑셀: ExcelExportButton 사용 +- [ ] 등록/수정: Drawer 사용 (모달 아님) +- [ ] 삭제: Modal.confirm 사용 +- [ ] 폼: antd Form + 2열(Col span=12) + layout="vertical" +- [ ] 금액 입력: InputNumber + formatter (천단위 콤마) +- [ ] 날짜: DatePicker + dayjs +- [ ] 정산월: MonthPicker 공통 컴포넌트