- PermissionManagement externalSelection 콜백 함수 오류 수정 - setSelectedItems → onToggleSelection, onToggleSelectAll, getItemId 변경 - claudedocs 문서 폴더별 정리 (26개 파일) - dashboard/, guides/, settings/, construction/, sales/ 등 Co-Authored-By: Claude <noreply@anthropic.com>
9.7 KiB
9.7 KiB
CEO 대시보드 리팩토링 계획
작성일: 2026-01-10 대상 파일:
src/components/business/CEODashboard/목표: 파일 분리 + 모바일(344px) 대응
1. 현재 상태 분석
1.1 파일 구조
CEODashboard/
├── CEODashboard.tsx # 1,648줄 ⚠️ 분리 필요
├── components.tsx # 312줄 ✅ 적정
├── types.ts # ~100줄 ✅ 적정
├── sections/
│ ├── index.ts
│ ├── TodayIssueSection.tsx # 73줄 ✅
│ ├── DailyReportSection.tsx # 37줄 ✅
│ ├── MonthlyExpenseSection.tsx # 38줄 ✅
│ ├── CardManagementSection.tsx # ~50줄 ✅
│ ├── EntertainmentSection.tsx # ~50줄 ✅
│ ├── WelfareSection.tsx # ~50줄 ✅
│ ├── ReceivableSection.tsx # ~50줄 ✅
│ ├── DebtCollectionSection.tsx # ~50줄 ✅
│ ├── VatSection.tsx # ~50줄 ✅
│ └── CalendarSection.tsx # ~100줄 ✅
├── modals/
│ ├── ScheduleDetailModal.tsx # ~200줄 ✅
│ └── DetailModal.tsx # ~300줄 ✅
└── dialogs/
└── DashboardSettingsDialog.tsx # ~200줄 ✅
1.2 CEODashboard.tsx 내부 분석 (1,648줄)
| 줄 범위 | 내용 | 줄 수 | 분리 대상 |
|---|---|---|---|
| 1-26 | imports | 26 | - |
| 27-370 | mockData 객체 | 344 | ✅ 분리 |
| 371-748 | handleMonthlyExpenseCardClick (모달 config) | 378 | ✅ 분리 |
| 749-1019 | handleCardManagementCardClick (모달 config) | 271 | ✅ 분리 |
| 1020-1247 | handleEntertainmentCardClick (모달 config) | 228 | ✅ 분리 |
| 1248-1375 | handleWelfareCardClick (모달 config) | 128 | ✅ 분리 |
| 1376-1465 | handleVatClick (모달 config) | 90 | ✅ 분리 |
| 1466-1509 | 캘린더 관련 핸들러 | 44 | - |
| 1510-1648 | 컴포넌트 렌더링 | 139 | - |
분리 대상 총합: ~1,439줄 (87%) 분리 후 예상: ~210줄
2. 분리 계획
2.1 목표 구조
CEODashboard/
├── CEODashboard.tsx # ~250줄 (컴포넌트 + 핸들러)
├── components.tsx # 312줄 (유지)
├── types.ts # ~100줄 (유지)
├── mockData.ts # 🆕 ~350줄 (목데이터)
├── modalConfigs/ # 🆕 모달 설정 분리
│ ├── index.ts
│ ├── monthlyExpenseConfigs.ts # ~380줄
│ ├── cardManagementConfigs.ts # ~280줄
│ ├── entertainmentConfigs.ts # ~230줄
│ ├── welfareConfigs.ts # ~130줄
│ └── vatConfigs.ts # ~100줄
├── sections/ # (유지)
├── modals/ # (유지)
└── dialogs/ # (유지)
2.2 분리 파일 상세
A. mockData.ts (신규)
// mockData.ts
import type { CEODashboardData } from './types';
export const mockData: CEODashboardData = {
todayIssue: [...],
dailyReport: {...},
monthlyExpense: {...},
cardManagement: {...},
entertainment: {...},
welfare: {...},
receivable: {...},
debtCollection: {...},
vat: {...},
calendarSchedules: [...],
};
B. modalConfigs/index.ts (신규)
// modalConfigs/index.ts
export { getMonthlyExpenseModalConfig } from './monthlyExpenseConfigs';
export { getCardManagementModalConfig } from './cardManagementConfigs';
export { getEntertainmentModalConfig } from './entertainmentConfigs';
export { getWelfareModalConfig } from './welfareConfigs';
export { getVatModalConfig } from './vatConfigs';
C. 개별 모달 config 파일 예시
// modalConfigs/monthlyExpenseConfigs.ts
import type { DetailModalConfig } from '../types';
export function getMonthlyExpenseModalConfig(cardId: string): DetailModalConfig | null {
const configs: Record<string, DetailModalConfig> = {
me1: { title: '당월 매입 상세', ... },
me2: { title: '당월 카드 상세', ... },
me3: { title: '당월 발행어음 상세', ... },
me4: { title: '당월 지출 예상 상세', ... },
};
return configs[cardId] || null;
}
D. CEODashboard.tsx (리팩토링 후)
// CEODashboard.tsx (리팩토링 후 ~250줄)
import { mockData } from './mockData';
import {
getMonthlyExpenseModalConfig,
getCardManagementModalConfig,
getEntertainmentModalConfig,
getWelfareModalConfig,
getVatModalConfig,
} from './modalConfigs';
export function CEODashboard() {
// 상태 관리
const [data] = useState<CEODashboardData>(mockData);
const [detailModalConfig, setDetailModalConfig] = useState<DetailModalConfig | null>(null);
// ...
// 간소화된 핸들러
const handleMonthlyExpenseCardClick = useCallback((cardId: string) => {
const config = getMonthlyExpenseModalConfig(cardId);
if (config) {
setDetailModalConfig(config);
setIsDetailModalOpen(true);
}
}, []);
// 렌더링
return (...);
}
3. 모바일 대응 계획
3.1 적용 대상 컴포넌트
| 컴포넌트 | 현재 상태 | 변경 필요 |
|---|---|---|
| TodayIssueSection | grid-cols-2 md:grid-cols-4 |
✅ grid-cols-1 xs:grid-cols-2 md:grid-cols-4 |
| DailyReportSection | grid-cols-2 md:grid-cols-4 |
✅ 동일 |
| MonthlyExpenseSection | grid-cols-2 md:grid-cols-4 |
✅ 동일 |
| CardManagementSection | grid-cols-2 md:grid-cols-4 |
✅ 동일 |
| EntertainmentSection | grid-cols-2 md:grid-cols-4 |
✅ 동일 |
| WelfareSection | grid-cols-2 md:grid-cols-4 |
✅ 동일 |
| ReceivableSection | grid-cols-2 md:grid-cols-4 |
✅ 동일 |
| DebtCollectionSection | grid-cols-2 md:grid-cols-4 |
✅ 동일 |
| VatSection | grid-cols-2 md:grid-cols-4 |
✅ 동일 |
| AmountCardItem (공통) | 고정 텍스트 크기 | ✅ 반응형 텍스트 |
| IssueCardItem (공통) | 고정 텍스트 크기 | ✅ 반응형 텍스트 |
| PageHeader | 가로 배치 | ✅ 세로/가로 반응형 |
3.2 components.tsx 변경 사항
AmountCardItem
// Before
<p className="text-2xl md:text-3xl font-bold">
{formatCardAmount(card.amount)}
</p>
// After
<p className="text-lg xs:text-xl md:text-2xl lg:text-3xl font-bold truncate">
{formatCardAmount(card.amount)}
</p>
<p className="text-xs xs:text-sm font-medium mb-1 xs:mb-2 break-keep">
{card.label}
</p>
IssueCardItem
// Before
<p className="text-2xl md:text-3xl font-bold">
{typeof count === 'number' ? `${count}건` : count}
</p>
// After
<p className="text-lg xs:text-xl md:text-2xl lg:text-3xl font-bold">
{typeof count === 'number' ? `${count}건` : count}
</p>
3.3 섹션 공통 변경
// Before (모든 섹션)
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
// After
<div className="grid grid-cols-1 xs:grid-cols-2 md:grid-cols-4 gap-3 xs:gap-4">
3.4 CardContent 패딩
// Before
<CardContent className="p-6">
// After
<CardContent className="p-3 xs:p-4 md:p-6">
4. 실행 계획
Phase 1: 파일 분리 (예상 30분)
- 1.1
mockData.ts생성 및 데이터 이동 - 1.2
modalConfigs/폴더 생성 - 1.3
monthlyExpenseConfigs.ts생성 - 1.4
cardManagementConfigs.ts생성 - 1.5
entertainmentConfigs.ts생성 - 1.6
welfareConfigs.ts생성 - 1.7
vatConfigs.ts생성 - 1.8
modalConfigs/index.ts생성 - 1.9
CEODashboard.tsx리팩토링 - 1.10 import 정리 및 동작 확인
Phase 2: 모바일 대응 (예상 30분)
- 2.1
components.tsx- AmountCardItem 반응형 적용 - 2.2
components.tsx- IssueCardItem 반응형 적용 - 2.3
sections/*.tsx- 그리드 반응형 적용 (일괄) - 2.4
sections/*.tsx- CardContent 패딩 반응형 적용 - 2.5 PageHeader 반응형 확인
- 2.6 344px 테스트 및 미세 조정
Phase 3: 검증 (예상 15분)
- 3.1 빌드 확인 요청
- 3.2 데스크탑(1280px) 동작 확인
- 3.3 태블릿(768px) 동작 확인
- 3.4 모바일(375px) 동작 확인
- 3.5 Galaxy Fold(344px) 동작 확인
5. 예상 결과
5.1 파일 크기 변화
| 파일 | Before | After |
|---|---|---|
| CEODashboard.tsx | 1,648줄 | ~250줄 |
| mockData.ts | - | ~350줄 |
| modalConfigs/*.ts | - | ~1,100줄 (5개 파일) |
5.2 장점
- 유지보수성: 각 파일이 단일 책임 원칙 준수
- 재사용성: 모달 config를 다른 곳에서 재사용 가능
- 확장성: 새 모달 추가 시 별도 파일로 분리
- 가독성: 핵심 로직만 CEODashboard.tsx에 유지
- API 전환 용이: mockData.ts만 교체하면 됨
5.3 모바일 개선 효과
| 항목 | Before (344px) | After (344px) |
|---|---|---|
| 카드 배치 | 2열 (160px/카드) | 1열 (320px/카드) |
| 금액 표시 | 잘림 가능 | 완전 표시 |
| 라벨 표시 | 잘림 가능 | 줄바꿈/truncate |
| 패딩 | 과다 (24px) | 적정 (12px) |
6. 참고 문서
- 모바일 대응 가이드:
claudedocs/guides/[GUIDE] mobile-responsive-patterns.md - 기존 테스트 계획:
claudedocs/[PLAN] mobile-overflow-testing.md
7. 의사결정 사항
Q1: mockData를 별도 파일로?
- 결정: ✅ 분리
- 이유: 향후 API 연동 시 교체 용이
Q2: 모달 config를 폴더로?
- 결정: ✅ 폴더로 분리
- 이유: 각 config가 100줄 이상, 단일 파일은 여전히 큼
Q3: 모바일에서 1열 vs 2열?
- 결정: 344px 이하 1열, 375px 이상 2열
- 이유: Galaxy Fold 160px 카드는 너무 좁음
8. 시작 조건
- 계획서 작성 완료
- 모바일 가이드 작성 완료
- 사용자 승인
다음 단계: 계획 승인 후 Phase 1 (파일 분리) 시작