# React 코드 분석 요약 (Phase B.2)

**분석 일시:** 2025-11-12
**분석 범위:** mes_react 프로젝트
**분석 목적:** React 코드 구조, Atomic Design 패턴 적용 현황, 재사용 가능 컴포넌트 파악

---

## 🎯 Executive Summary

### 주요 발견 (Major Findings)

#### ✅ **Positive Findings**

1. **shadcn/ui 기반 Atomic Design 패턴 부분 적용**
   - Atoms (shadcn/ui): 47개 컴포넌트 완비
   - Molecules: 6개 컴포넌트 구축
   - Organisms: 8개 재사용 가능 컴포넌트 구축
   - 123개 파일에서 shadcn/ui 컴포넌트 활발히 사용

2. **재사용 가능한 Organisms 컴포넌트 구축**
   - PageLayout, PageHeader: 페이지 레이아웃 표준화
   - StatCards, SearchFilter: 대시보드 통계 카드, 검색 필터
   - DataTable: 범용 데이터 테이블 (molecules 통합)
   - EmptyState, MobileCard: 공통 UI 패턴

3. **BOM 기반 자동 견적 계산 로직 구현**
   - QuoteManagement3Write.tsx: 완전한 BOM 계산 엔진 구현
   - 수식 기반 수량 계산 (W, H 변수 지원)
   - 실시간 견적 산출 및 수식 편집 기능
   - 견적 수정 이력 관리 (Revision 시스템)

#### ❌ **Critical Issues**

1. **ItemManagement.tsx 과도한 파일 크기** 🔴 **Critical**
   - **6,521 lines** (310.4KB) - 관리 불가능한 수준
   - 품목 관리 화면 전체가 단일 파일에 집중
   - 리팩토링 긴급 필요 (Atomic Design 패턴 적용)

2. **Molecules/Organisms 재사용성 제한**
   - Molecules 6개만 존재 (확장 필요)
   - FormField, FormSection 등 폼 관련 재사용 컴포넌트 부족
   - 비즈니스 로직과 UI가 혼재된 파일 다수

3. **API 통합 현황 미확인**
   - 백엔드 API 연동 코드 분석 필요
   - ItemsController, BomCalculationController 활용 여부 확인 필요

---

## 📂 프로젝트 구조 분석

### 1. Atoms (shadcn/ui Components)

**총 47개 컴포넌트 발견** - `src/components/ui/`

| 카테고리 | 컴포넌트 | 비고 |
|----------|----------|------|
| **Form Controls** | button, input, textarea, checkbox, radio-group, select, label, switch, slider | 폼 입력 요소 완비 |
| **Data Display** | table, badge, card, avatar, separator, tooltip, skeleton | 데이터 표시 요소 |
| **Layout** | dialog, sheet, popover, dropdown-menu, tabs, accordion, collapsible, sidebar | 레이아웃 요소 |
| **Feedback** | alert, alert-dialog, toast (sonner), progress | 사용자 피드백 |
| **Navigation** | navigation-menu, menubar, breadcrumb, pagination, command | 네비게이션 |
| **Advanced** | calendar, carousel, chart, context-menu, drawer, form, hover-card, input-otp, resizable, scroll-area, toggle, toggle-group | 고급 UI 패턴 |

**핵심 발견:**
- ✅ shadcn/ui의 거의 모든 주요 컴포넌트 설치됨
- ✅ TypeScript로 타입 안전성 확보
- ✅ Tailwind CSS 기반 일관된 스타일링
- ✅ Radix UI 기반 접근성 확보

---

### 2. Molecules (조합 컴포넌트)

**총 6개 컴포넌트** - `src/components/molecules/`

#### 2.1 TableActions.tsx
```typescript
// 테이블 액션 버튼 그룹
interface TableAction {
  label: string;
  onClick: () => void;
  icon?: LucideIcon;
  variant?: "default" | "outline" | "destructive";
}

export function TableActions({ actions }: { actions: TableAction[] })
```
**용도:** 테이블 행별 액션 버튼 (보기, 수정, 삭제 등)

#### 2.2 StatusBadge.tsx
```typescript
// 상태 표시 배지
type StatusType = "active" | "inactive" | "pending" | "approved" | "rejected";

export function StatusBadge({ status, showDot }: StatusBadgeProps)
```
**용도:** 데이터 상태 시각화

#### 2.3 IconWithBadge.tsx
```typescript
// 아이콘 + 배지 조합
export function IconWithBadge({
  icon, label, badge, iconColor, iconBgColor, size
}: IconWithBadgeProps)
```
**용도:** 아이콘과 레이블/배지 결합 표시

#### 2.4 FormField.tsx
**용도:** 폼 필드 라벨 + 입력 요소 조합 (추정)

#### 2.5 StatCard.tsx
**용도:** 단일 통계 카드 (추정)

#### 2.6 SearchBar.tsx
**용도:** 검색 바 컴포넌트 (추정)

**분석:**
- ✅ 재사용 가능한 조합 컴포넌트 존재
- ⚠️ **개수 부족** - 확장 필요 (10-15개 권장)
- ⚠️ FormField 외 폼 관련 molecules 부족

---

### 3. Organisms (복합 컴포넌트)

**총 8개 컴포넌트** - `src/components/organisms/`

#### 3.1 PageLayout.tsx (42 lines)
```typescript
interface PageLayoutProps {
  children: ReactNode;
  maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "full";
  devMetadata?: ComponentMetadata;
}

export function PageLayout({ children, maxWidth = "full", devMetadata }: PageLayoutProps)
```
**핵심 기능:**
- 페이지 레이아웃 표준화
- 반응형 패딩 (모바일/데스크톱)
- maxWidth 옵션으로 콘텐츠 너비 제어
- 개발자 모드 메타데이터 지원

#### 3.2 PageHeader.tsx (34 lines)
```typescript
interface PageHeaderProps {
  title: string;
  description?: string;
  actions?: ReactNode;
  icon?: LucideIcon;
}

export function PageHeader({ title, description, actions, icon }: PageHeaderProps)
```
**핵심 기능:**
- 페이지 제목 + 설명 + 아이콘
- 우측 액션 버튼 영역
- 반응형 레이아웃 (모바일/데스크톱)

#### 3.3 StatCards.tsx (54 lines)
```typescript
interface StatCardData {
  label: string;
  value: string | number;
  icon?: LucideIcon;
  iconColor?: string;
  trend?: { value: string; isPositive: boolean; };
}

export function StatCards({ stats }: { stats: StatCardData[] })
```
**핵심 기능:**
- 대시보드 통계 카드 그리드 (1/2/4 columns)
- 아이콘 + 라벨 + 값 + 트렌드 표시
- 반응형 그리드 레이아웃

#### 3.4 SearchFilter.tsx (46 lines)
```typescript
interface SearchFilterProps {
  searchValue: string;
  onSearchChange: (value: string) => void;
  searchPlaceholder?: string;
  filterButton?: boolean;
  onFilterClick?: () => void;
  extraActions?: ReactNode;
}

export function SearchFilter({ ... }: SearchFilterProps)
```
**핵심 기능:**
- 검색 입력 (아이콘 포함)
- 필터 버튼 (선택적)
- 추가 액션 버튼 슬롯
- 반응형 레이아웃

#### 3.5 DataTable.tsx (314 lines) ⭐
```typescript
type CellType = "text" | "number" | "currency" | "date" | "datetime"
  | "status" | "badge" | "icon" | "iconBadge" | "actions" | "custom";

interface Column<T> {
  key: keyof T | string;
  label: string;
  type?: CellType;
  width?: string;
  align?: "left" | "center" | "right";
  sortable?: boolean;
  render?: (value: any, row: T) => ReactNode;
  format?: (value: any) => string | number;
  // ... 타입별 설정 (statusConfig, badgeConfig, iconConfig, etc.)
}

export function DataTable<T>({
  columns, data, keyField, onRowClick, loading, emptyMessage,
  pagination, striped, hoverable, compact
}: DataTableProps<T>)
```
**핵심 기능:**
- **Generic 타입 지원** (`<T>`)
- **11가지 셀 타입** 지원 (text, number, currency, date, status, badge, icon, actions, custom, etc.)
- **molecules 통합**: StatusBadge, IconWithBadge, TableActions 사용
- **페이지네이션** 내장
- **정렬, 포맷팅, 커스텀 렌더링** 지원
- **로딩 상태, 빈 상태** 처리
- **반응형** (데스크톱만 표시, 모바일은 별도 카드)

**분석:**
- ✅ **매우 강력한 범용 테이블 컴포넌트**
- ✅ Molecules 재사용 (StatusBadge, IconWithBadge, TableActions)
- ✅ TypeScript Generic으로 타입 안전성 확보

#### 3.6 EmptyState.tsx (36 lines)
```typescript
interface EmptyStateProps {
  icon?: LucideIcon;
  title: string;
  description?: string;
  action?: { label: string; onClick: () => void; };
}

export function EmptyState({ icon, title, description, action }: EmptyStateProps)
```
**핵심 기능:**
- 빈 상태 UI 표준화
- 아이콘 + 제목 + 설명 + 액션 버튼

#### 3.7 MobileCard.tsx (100 lines)
```typescript
interface MobileCardProps {
  title: string;
  subtitle?: string;
  icon?: ReactNode;
  badge?: { label: string; variant?: "default" | "secondary" | "destructive" | "outline"; };
  fields: Array<{ label: string; value: string; badge?: boolean; }>;
  actions?: Array<{ label: string; onClick: () => void; icon?: LucideIcon; }>;
}

export function MobileCard({ ... }: MobileCardProps)
```
**핵심 기능:**
- 모바일 전용 카드 UI
- 헤더 (title + subtitle + icon + badge)
- 필드 리스트 (라벨-값 쌍)
- 액션 버튼 그룹

#### 3.8 FormSection.tsx
**용도:** 폼 섹션 레이아웃 (추정)

**Organisms 분석:**
- ✅ **재사용성 높은 컴포넌트** 구축 완료
- ✅ PageLayout + PageHeader → 페이지 표준화
- ✅ StatCards + SearchFilter → 대시보드 표준화
- ✅ DataTable → 범용 테이블 (molecules 통합)
- ✅ EmptyState + MobileCard → 반응형 UI 표준화
- ⚠️ **FormSection, FormBuilder 등 폼 관련 organisms 확장 필요**

---

### 4. Pages (화면 컴포넌트)

---

#### 📈 코드 통계 (Code Statistics)

| 항목 | 수량 | 라인 범위 | 비고 |
|------|------|----------|------|
| **총 라인 수** | 6,521 lines | 1-6521 | 🔴 Critical Size |
| **Import 문** | 28개 | 1-31 | shadcn/ui 대량 사용 |
| **Interface 정의** | 5개 | 33-91 | ItemOption, PriceHistory, FileAttachment, BendingDetail, BOMLine |
| **상수 객체** | 5개 | 93-219 | ITEM_CATEGORIES, GUIDE_RAIL_CODE_SYSTEM, GUIDE_RAIL_OPTIONS, etc. |
| **useState 훅** | **40개** | 220-362 | 🔴 Critical - 성능 이슈 |
| **함수 정의** | ~75개 | 365-1586 | Helper functions, handlers, validators |
| **generateItemCode()** | 177 lines | 708-885 | 🔴 Long Method - 품목코드 생성 로직 |
| **handleSaveItem()** | 362 lines | 1097-1459 | 🔴 God Method - Validation + Create/Edit |
| **List View JSX** | 1,911 lines | 1589-3500 | 🔴 Massive - Desktop 7 tabs + Mobile 6 tabs |
| **View Mode JSX** | 1,003 lines | 3497-4500 | 상세 조회 화면 |
| **Form JSX** | 1,780 lines | 4220-6000 | 🔴 Massive - Dynamic form |
| **Bending Editor** | 303 lines | 5674-5977 | 절곡 전개도 + 데이터 테이블 |
| **BOM Editor** | 399 lines | 5979-6378 | Popover 검색 + Nested display |

---

#### 🔴 Critical Issues (구체적 라인 번호 포함)

##### 1. **God Component - 6,521 lines in Single File** 🚨
- **3개 View를 1개 컴포넌트에 집중** (list/view/form)
- **관리 불가능한 복잡도** (Cyclomatic Complexity 추정 200+)
- **테스트 불가능** - 단위 테스트 작성 불가능
- **성능 이슈** - 전체 리렌더링 위험

##### 2. **40개 useState Hooks (Lines 220-362)** 🚨
- **과도한 상태 관리** - 성능 저하 원인
- **React DevTools에서 추적 불가능**
- **상태 간 의존성 복잡도** 높음
- **리렌더링 폭증** - 하나의 상태 변경 시 전체 리렌더링

##### 3. **Long Methods** 🔴
- `handleSaveItem()`: **362 lines** (1097-1459)
  - Validation 100 lines
  - Create/Edit 로직 262 lines
  - 단일 함수 책임 원칙(SRP) 위반

- `generateItemCode()`: **177 lines** (708-885)
  - 12개 분기 조건 (FG, PT-ASSEMBLY 9종, PT-BENDING, PT-PURCHASED, RM, SM, CS)
  - Cyclomatic Complexity 추정 25+

##### 4. **Massive JSX Blocks** 🔴
- **List View**: 1,911 lines (1589-3500)
  - Desktop: 7개 탭 (전체, FG, PT(3 sub-tabs), SM, RM, CS)
  - Mobile: 6개 탭 (동일 구조 반복)
  - **Pagination 로직 7회 반복** (각 탭마다)
  - **Table 구조 10회 반복** (desktop 7 + mobile 3)

- **Form JSX**: 1,780 lines (4220-6000)
  - Dynamic form - itemType, partType에 따라 다른 필드
  - 12개 부품 타입별 개별 폼 (guide_rail, case, bottom_finish, rod, frame, bracket, cover, cap, endcap, stopper, safety, motor)

##### 5. **Code Duplication** 🔴
- **Table 구조 중복**: 10회 (각 탭마다 동일한 TableHeader, TableRow, Pagination)
- **Filter 로직 중복**: 7회 (각 탭별 필터링)
- **Badge 렌더링 중복**: 7회
- **액션 버튼 중복**: 7회 (보기/수정/삭제 버튼 그룹)

**Impact:**
- 유지보수 시 10곳 동시 수정 필요
- 버그 발생 시 10곳 동시 확인 필요
- 일관성 유지 어려움

##### 6. **No Organisms Reuse** ❌
- **DataTable organism (314 lines) 존재하지만 미사용**
- **수동 Table 코드 10회 작성** - DataTable 사용 시 1,911줄 → 약 200줄로 감소 가능

---

#### 💡 핵심 기능 분석

**함수:** `generateItemCode(itemName: string, specification: string): string`

**기능:** 품목유형, 부품유형, 카테고리에 따라 자동으로 품목코드 생성

**지원 품목 타입:**
1. **FG (제품)**: `{itemName}-{specification}` (기본)
2. **PT (부품) - ASSEMBLY (조립)**:
   - 가이드레일: `RM53` (벽면형 본체, 5.3M급)
   - 케이스: `CF` (프레임형)
   - 하단마감재: `BS` (스틸 사각형)
   - 봉: `ROD-25-3500` (직경 25mm, 길이 3500mm)
   - 프레임: `FRAME-L-3500` (좌측, 3500mm)
   - 브라켓: `BRACKET-W-150` (벽면형, 150mm)
   - 커버: `COVER-AL-3500` (알루미늄, 3500mm)
   - 캡: `CAP-TOP-25` (상단, 25mm)
   - 엔드캡: `ENDCAP-L-25` (좌측, 25mm)
   - 스토퍼: `STOPPER-AUTO-50` (자동형, 50kg)
   - 안전장치: `SAFETY-FALL-100` (낙하방지, 100kg)
   - 모터: `MOTOR-DC-50W` (DC모터, 50W)
3. **PT (부품) - BENDING (절곡)**:
   - 패턴 1: `{재질}-{두께}T-{폭}W` (예: STS-1.5T-100W)
   - 패턴 2: `BND-{category1}-{openSizeWidth}W-{openSizeHeight}H` (예: BND-FRAME-3500W-2000H)
4. **PT (부품) - PURCHASED (구매)**: `{category1}-{specification}` (예: BOLT-M10)
5. **RM/SM/CS (자재)**: `{itemName}-{specification}` (기본)

**코드 예시 (Lines 721-780):**
```typescript
// 가이드레일 코드 생성 로직
if (formData.category1 === "guide_rail" && formData.installationType && formData.assemblyType) {
  const typeCode = formData.installationType === "wall" ? "R" : "S";
  const kindCode = formData.assemblyType; // M, T, P, B, S

  // 사이즈 코드 계산
  const width = formData.sideSpecWidth || 0;
  const length = formData.assemblyLength || 0;
  const sizeCode = calculateSizeCode(width, length);

  return `${typeCode}${kindCode}${sizeCode}`; // 예: RM53
}

// 절곡품 코드 생성 로직 (Lines 812-838)
if (formData.partType === "BENDING") {
  const material = formData.material || "UNKNOWN";
  const thickness = formData.thickness || 0;
  const width = formData.sideSpecWidth || 0;

  if (formData.category1) {
    // 카테고리 기반 코드: BND-FRAME-3500W-2000H
    return `BND-${formData.category1.toUpperCase()}-${formData.openSizeWidth}W-${formData.openSizeHeight}H`;
  } else {
    // 재질 기반 코드: STS-1.5T-100W
    return `${material}-${thickness}T-${width}W`;
  }
}
```

**문제점:**
- 🔴 **177 lines** - Long Method (25+ Cyclomatic Complexity)
- 🔴 **12개 if-else 분기** - 복잡한 조건 로직
- ⚠️ **비즈니스 로직 집중** - 재사용 불가능

**리팩토링 제안:**
```typescript
// utils/itemCodeGenerators.ts
export const itemCodeGenerators = {
  FG: (data) => `${data.itemName}-${data.specification}`,
  PT_ASSEMBLY_GUIDE_RAIL: (data) => {
    const typeCode = data.installationType === "wall" ? "R" : "S";
    const kindCode = data.assemblyType;
    const sizeCode = calculateSizeCode(data.sideSpecWidth, data.assemblyLength);
    return `${typeCode}${kindCode}${sizeCode}`;
  },
  PT_ASSEMBLY_CASE: (data) => `C${data.assemblyType}`,
  PT_BENDING: (data) => {
    if (data.category1) {
      return `BND-${data.category1.toUpperCase()}-${data.openSizeWidth}W-${data.openSizeHeight}H`;
    }
    return `${data.material}-${data.thickness}T-${data.sideSpecWidth}W`;
  },
  // ... 나머지 생성기
};

// hooks/useItemCodeGenerator.ts
export function useItemCodeGenerator() {
  const generateCode = (itemType, partType, category1, data) => {
    const key = `${itemType}_${partType}_${category1}`.toUpperCase();
    const generator = itemCodeGenerators[key] || itemCodeGenerators.DEFAULT;
    return generator(data);
  };

  return { generateCode };
}
```

---

**100 lines** of inline validation logic

**검증 항목:**
1. **공통 필수 필드**: itemType
2. **FG (제품) 필수 필드**: productName, itemName, specification
3. **PT (부품) 필수 필드**:
   - partType (ASSEMBLY/BENDING/PURCHASED)
   - ASSEMBLY: category1, installationType, assemblyType, sideSpecWidth, assemblyLength
   - BENDING: material, thickness, bendingDiagram, bendingDetails
   - PURCHASED: category1, purchaseSource, specification
4. **RM/SM/CS (자재) 필수 필드**: material, specification, unit, purchasePrice

**코드 예시 (Lines 1097-1124):**
```typescript
const errors: ValidationErrors = {};

if (!formData.itemType) errors.itemType = "품목유형을 선택하세요";

if (formData.itemType === "FG") {
  if (!formData.productName) errors.productName = "상품명을 입력하세요";
  if (!formData.itemName) errors.itemName = "품목명을 입력하세요";
  if (!formData.specification) errors.specification = "규격을 입력하세요";
}

if (formData.itemType === "PT") {
  if (!formData.partType) errors.partType = "부품유형을 선택하세요";

  if (formData.partType === "ASSEMBLY") {
    if (!formData.category1) errors.category1 = "품목명을 선택하세요";
    if (formData.category1 === "guide_rail") {
      if (!formData.installationType) errors.installationType = "설치유형을 선택하세요";
      if (!formData.assemblyType) errors.assemblyType = "조립유형을 선택하세요";
      // ... 12개 카테고리별 검증
    }
  }

  if (formData.partType === "BENDING") {
    if (!formData.material) errors.material = "재질을 입력하세요";
    if (!formData.thickness) errors.thickness = "두께를 입력하세요";
    if (!formData.bendingDiagram) errors.bendingDiagram = "절곡 전개도를 입력하세요";
  }
}

if (Object.keys(errors).length > 0) {
  setValidationErrors(errors);
  return;
}
```

**문제점:**
- 🔴 **100 lines inline validation** - 재사용 불가능
- 🔴 **품목유형별 20개 이상 검증 규칙** - 복잡도 높음
- ⚠️ **에러 메시지 하드코딩** - i18n 미지원

**리팩토링 제안:**
```typescript
// hooks/useItemValidation.ts
export function useItemValidation() {
  const validate = (formData: Partial<ItemMaster>): ValidationErrors => {
    const validators = {
      FG: validateFG,
      PT: validatePT,
      RM: validateRM,
      SM: validateSM,
      CS: validateCS,
    };

    const validator = validators[formData.itemType as string];
    return validator ? validator(formData) : {};
  };

  return { validate };
}

// validators/itemValidators.ts
export const validateFG = (data: Partial<ItemMaster>): ValidationErrors => {
  const errors: ValidationErrors = {};
  if (!data.productName) errors.productName = "상품명을 입력하세요";
  if (!data.itemName) errors.itemName = "품목명을 입력하세요";
  return errors;
};

export const validatePT = (data: Partial<ItemMaster>): ValidationErrors => {
  const errors: ValidationErrors = {};
  if (!data.partType) errors.partType = "부품유형을 선택하세요";

  if (data.partType === "ASSEMBLY") {
    Object.assign(errors, validateAssemblyPart(data));
  } else if (data.partType === "BENDING") {
    Object.assign(errors, validateBendingPart(data));
  } else if (data.partType === "PURCHASED") {
    Object.assign(errors, validatePurchasedPart(data));
  }

  return errors;
};
```

---

##### 3. BOM Editor (Lines 5979-6378) - 399 lines

**핵심 기능:**
1. **Popover 기반 품목 검색** (Lines 6061-6165)
   - Command 컴포넌트 활용
   - 품목코드 또는 품목명으로 검색
   - 실시간 필터링
   - 선택 시 자동으로 품목 정보 채우기

2. **절곡품 자동 감지** (Lines 6087-6096)
   - 선택한 품목이 partType === "BENDING"이면 자동으로 isBending = true 설정
   - bendingDiagram, bendingDetails 자동 복사

3. **Nested BOM Display** (Lines 6260-6317)
   - 절곡품 선택 시 전개도 + 데이터 테이블 표시
   - 2-level nested structure (Parent BOM → Child bending details)

4. **재질별 폭 합계** (Lines 6327-6375)
   - BOM 라인 중 절곡품만 추출
   - 재질(material)별로 그룹화
   - bendingDetails의 sum 값 합산
   - 예: SPCC 1.5T → 12,345mm

**코드 예시 (Lines 6061-6120):**
```typescript
<Popover open={searchOpen} onOpenChange={(open) => setBomSearchStates({...bomSearchStates, [line.id]: {isOpen: open}})}>
  <PopoverTrigger>
    <Input
      placeholder="품목코드 또는 품목명 입력..."
      value={line.childItemCode || searchValue}
      onChange={(e) => setBomSearchStates({...bomSearchStates, [line.id]: {searchValue: e.target.value}})}
    />
  </PopoverTrigger>
  <PopoverContent className="w-96">
    <Command>
      <CommandInput placeholder="검색..." />
      <CommandList>
        <CommandEmpty>품목이 없습니다.</CommandEmpty>
        <CommandGroup heading="검색 결과">
          {availableItems.filter(item =>
            item.itemCode.toLowerCase().includes(searchValue.toLowerCase()) ||
            item.itemName.toLowerCase().includes(searchValue.toLowerCase())
          ).map(item => (
            <CommandItem
              key={item.id}
              onSelect={() => {
                // 절곡품 자동 감지
                const isBendingPart = item.partType === "BENDING";

                setBomLines(bomLines.map(l =>
                  l.id === line.id ? {
                    ...l,
                    childItemCode: item.itemCode,
                    childItemName: item.itemName,
                    specification: item.specification,
                    material: item.material,
                    unit: item.unit,
                    unitPrice: item.salesPrice || 0,
                    isBending: isBendingPart,
                    bendingDiagram: isBendingPart ? item.bendingDiagram : undefined,
                    bendingDetails: isBendingPart ? item.bendingDetails : undefined,
                  } : l
                ));

                // Popover 닫기
                setBomSearchStates({...bomSearchStates, [line.id]: {isOpen: false, searchValue: ''}});
              }}
            >
              <div>
                <div className="font-medium">{item.itemCode}</div>
                <div className="text-sm text-gray-500">{item.itemName}</div>
                {item.partType === "BENDING" && <Badge variant="secondary">절곡품</Badge>}
              </div>
            </CommandItem>
          ))}
        </CommandGroup>
      </CommandList>
    </Command>
  </PopoverContent>
</Popover>
```

**문제점:**
- 🔴 **399 lines** - Organism으로 분리 필요
- 🔴 **Popover 상태 관리 복잡** - 각 BOM 라인마다 개별 상태
- ⚠️ **재질별 폭 합계 로직** - 비즈니스 로직 분리 필요

**리팩토링 제안:**
```typescript
// organisms/BOMEditor.tsx (300-400 lines)
interface BOMEditorProps {
  bomLines: BOMLine[];
  onChange: (bomLines: BOMLine[]) => void;
  availableItems: ItemMaster[];
  editable?: boolean;
}

export function BOMEditor({ bomLines, onChange, availableItems, editable = true }: BOMEditorProps) {
  return (
    <>
      <BOMTable bomLines={bomLines} onChange={onChange} availableItems={availableItems} editable={editable} />
      <BOMSummaryTable bomLines={bomLines} />
    </>
  );
}

// molecules/BOMItemSearchPopover.tsx (100-150 lines)
interface BOMItemSearchPopoverProps {
  value: string;
  onSelect: (item: ItemMaster) => void;
  availableItems: ItemMaster[];
}

export function BOMItemSearchPopover({ value, onSelect, availableItems }: BOMItemSearchPopoverProps)
```

---

##### 4. Bending Diagram Editor (Lines 5674-5977) - 303 lines

**핵심 기능:**
1. **입력 방식 선택** (Lines 5689-5696)
   - File upload (이미지 파일 업로드)
   - Drawing input (Canvas 그리기 도구)

2. **Bending Detail Data Table** (Lines 5816-5974)
   - Editable table (7개 컬럼)
   - **실시간 계산** (연신율계산후, 합계)
   - **Row 추가/삭제** 버튼

**데이터 구조:**
```typescript
interface BendingDetail {
  id: string;
  no: number;                  // 번호
  input: number;               // 입력
  elongation: number;          // 연신율
  calculated: number;          // 연신율계산후 = input + elongation (자동 계산)
  sum: number;                 // 합계 = ∑(calculated) from row 1 to current (자동 계산)
  shaded: boolean;             // 음영
  aAngle: number;              // A각
}
```

**계산 로직 (Lines 5850-5865):**
```typescript
{formData.bendingDetails?.map((detail, idx) => {
  // 연신율계산후 = 입력 + 연신율
  const calculated = detail.input + detail.elongation;

  // 합계 = row 1부터 현재 row까지의 연신율계산후 누적 합
  let sum = 0;
  for (let i = 0; i <= idx; i++) {
    sum += formData.bendingDetails[i].input + formData.bendingDetails[i].elongation;
  }

  return (
    <TableRow className={detail.shaded ? "bg-gray-200" : ""}>
      <TableCell>{detail.no}</TableCell>
      <TableCell><Input type="number" value={detail.input} onChange={...} /></TableCell>
      <TableCell><Input type="number" value={detail.elongation} onChange={...} /></TableCell>
      <TableCell className="bg-blue-50 font-medium">{calculated}</TableCell>
      <TableCell className="bg-green-50 font-medium">{sum}</TableCell>
      <TableCell><Checkbox checked={detail.shaded} onCheckedChange={...} /></TableCell>
      <TableCell><Input type="number" value={detail.aAngle} onChange={...} /></TableCell>
    </TableRow>
  );
})}
```

**문제점:**
- 🔴 **303 lines** - Organism으로 분리 필요
- ⚠️ **계산 로직 inline** - 성능 이슈 (map 내부에서 루프)
- ⚠️ **상태 관리 복잡** - bendingDetails 배열 업데이트

**리팩토링 제안:**
```typescript
// organisms/BendingDiagramEditor.tsx (200-300 lines)
interface BendingDiagramEditorProps {
  bendingDiagram?: string;
  bendingDetails?: BendingDetail[];
  onChange: (diagram: string | undefined, details: BendingDetail[]) => void;
  editable?: boolean;
}

export function BendingDiagramEditor({ bendingDiagram, bendingDetails, onChange, editable = true }: BendingDiagramEditorProps) {
  return (
    <>
      <BendingDiagramInput diagram={bendingDiagram} onDiagramChange={...} editable={editable} />
      <BendingDataTable details={bendingDetails} onChange={...} editable={editable} />
    </>
  );
}

// hooks/useBendingCalculation.ts
export function useBendingCalculation(bendingDetails: BendingDetail[]) {
  const calculated = useMemo(() => {
    return bendingDetails.map((detail, idx) => ({
      ...detail,
      calculated: detail.input + detail.elongation,
      sum: bendingDetails.slice(0, idx + 1).reduce((acc, d) => acc + d.input + d.elongation, 0),
    }));
  }, [bendingDetails]);

  return calculated;
}
```

---

**From:** ItemManagement.tsx (6,521 lines) - Single God Component

**To:** 15+ files (100-400 lines each) - Atomic Design Pattern

```
ItemManagement.tsx (6,521 lines) 🔴
↓
├── 📁 pages/
│   └── ItemManagementPage.tsx (100-150 lines) ✅
│       - PageLayout + Organisms 조합
│       - 3 views (list/view/form) 라우팅
│       - useState → Custom Hooks로 위임
│
├── 📁 organisms/
│   ├── ItemListView.tsx (200-300 lines) ✅
│   │   - DataTable organism 활용 (1,911 줄 → 200 줄로 감소)
│   │   - 탭 기반 필터링 (7개 탭 → 1개 DataTable + filter prop)
│   │   - 페이지네이션 (내장)
│   │
│   ├── ItemDetailView.tsx (200-300 lines) ✅
│   │   - 상세 조회 화면
│   │   - BOM nested display
│   │   - 가격 이력, 첨부파일 표시
│   │
│   ├── ItemFormDialog.tsx (300-400 lines) ✅
│   │   - Dynamic form (itemType, partType에 따라 다른 폼)
│   │   - ItemTypeSelector, CategorySelector, OptionEditor 조합
│   │   - useItemForm hook 활용
│   │
│   ├── BOMEditor.tsx (300-400 lines) ⭐
│   │   - BOM 라인 편집
│   │   - BOMItemSearchPopover 활용
│   │   - Nested bending display
│   │   - 재질별 폭 합계
│   │
│   ├── BendingDiagramEditor.tsx (200-300 lines) ⭐
│   │   - 절곡 전개도 입력 (File/Drawing)
│   │   - Bending detail data table
│   │   - useBendingCalculation hook
│   │
│   ├── PriceHistoryManager.tsx (150-200 lines)
│   │   - 가격 이력 조회/추가
│   │   - 시계열 차트
│   │
│   └── FileManager.tsx (100-150 lines)
│       - 첨부파일 업로드/다운로드/삭제
│
├── 📁 molecules/
│   ├── ItemTypeSelector.tsx (50-100 lines)
│   │   - 품목유형 선택 (FG, PT, RM, SM, CS)
│   │   - Badge + Icon
│   │
│   ├── CategorySelector.tsx (100-150 lines)
│   │   - 품목명/카테고리 선택
│   │   - 계층형 Select (category1 → category2 → category3)
│   │
│   ├── OptionEditor.tsx (100-150 lines)
│   │   - 품목 옵션 편집 (ItemOption[])
│   │   - Dynamic field rendering
│   │
│   ├── BOMItemSearchPopover.tsx (100-150 lines) ⭐
│   │   - Popover + Command 조합
│   │   - 품목코드/품목명 검색
│   │   - 절곡품 자동 감지
│   │
│   └── PartTypeForm.tsx (150-200 lines)
│       - 부품유형별 폼 필드
│       - ASSEMBLY/BENDING/PURCHASED
│
├── 📁 hooks/
│   ├── useItemForm.ts (200-300 lines) ⭐
│   │   - 40개 useState → 단일 reducer
│   │   - formData 상태 관리
│   │   - handleChange, handleSave 로직
│   │
│   ├── useItemValidation.ts (150-200 lines) ⭐
│   │   - 품목유형별 validation
│   │   - 100줄 inline → 재사용 가능 validators
│   │
│   ├── useItemCodeGenerator.ts (100-150 lines) ⭐
│   │   - generateItemCode 함수 분리
│   │   - 177줄 → 100줄 + 재사용 가능
│   │
│   ├── useBOMCalculation.ts (150-200 lines)
│   │   - BOM 계산 로직
│   │   - 재질별 폭 합계
│   │
│   └── useBendingCalculation.ts (100-150 lines) ⭐
│       - 연신율계산후, 합계 자동 계산
│       - useMemo로 성능 최적화
│
└── 📁 constants/
    ├── itemCategories.ts (200-300 lines)
    │   - ITEM_CATEGORIES
    │   - GUIDE_RAIL_CODE_SYSTEM
    │   - PART_TYPE_CATEGORIES
    │
    └── itemCodeGenerators.ts (100-150 lines)
        - generateItemCode 로직 분리
        - 품목유형별 코드 생성 함수
```

**예상 효과:**
- ✅ **파일당 100-400줄** - 관리 가능한 크기
- ✅ **관심사 분리** - UI / 비즈니스 로직 / 데이터 분리
- ✅ **재사용성** - BOMEditor, BendingDiagramEditor 등 다른 화면에서도 활용
- ✅ **테스트 가능** - 각 컴포넌트/훅 단위 테스트
- ✅ **성능 개선** - 부분 리렌더링 (40개 useState → reducer + useMemo)
- ✅ **코드 감소** - 1,911줄 List View → 200줄 (DataTable organism 활용)

**우선순위:**
1. 🔴 **P0 (긴급)**: useState 40개 → useItemForm hook (성능 이슈)
2. 🔴 **P0 (긴급)**: List View 1,911줄 → DataTable organism 활용
3. 🟡 **P1 (높음)**: BOMEditor, BendingDiagramEditor organism 분리
4. 🟡 **P1 (높음)**: generateItemCode, validation 로직 분리
5. 🟢 **P2 (중간)**: 나머지 molecules, organisms 분리

**예상 작업 기간:**
- P0 (긴급): 1-2주
- P1 (높음): 2-3주
- P2 (중간): 1-2주
- **총 예상**: 4-7주

---

#### 4.1 ItemManagement.tsx - 최종 평가

##### ✅ Strengths
1. **완전한 품목 관리 기능** - FG, PT (3 sub-types), RM, SM, CS 모두 지원
2. **품목코드 자동 생성** - 12개 부품 타입별 자동 생성 로직
3. **BOM 편집 + Nested Display** - 2-level BOM 구조 지원
4. **절곡품 특수 처리** - 전개도 + 데이터 테이블 + 재질별 폭 합계
5. **반응형 UI** - Desktop (Table 7 tabs) + Mobile (Card 6 tabs)

##### ❌ Critical Weaknesses
1. 🔴 **6,521 lines God Component** - 유지보수 불가능
2. 🔴 **40개 useState** - 성능 저하, 리렌더링 폭증
3. 🔴 **handleSaveItem 362 lines** - God Method
4. 🔴 **generateItemCode 177 lines** - Long Method (25+ Complexity)
5. 🔴 **List View 1,911 lines** - Massive JSX, 10회 중복
6. 🔴 **Form 1,780 lines** - Dynamic but monolithic
7. ❌ **DataTable organism 미사용** - 수동 Table 코드 10회 작성
8. ❌ **비즈니스 로직 집중** - 재사용 불가능

##### 🚨 Immediate Actions Required
1. **useState 40개 → useReducer + Custom Hooks** (P0 - 성능)
2. **List View → DataTable organism 활용** (P0 - 1,711줄 감소)
3. **BOMEditor, BendingDiagramEditor organism 분리** (P1 - 재사용)
4. **generateItemCode, validation 로직 분리** (P1 - 복잡도)

**결론:** 기능은 완전하지만 구조가 심각하게 문제. **긴급 리팩토링 필요** 🔴

---

#### 4.2 QuoteManagement3List.tsx (788 lines)

**구조 분석:**
```typescript
// Import (1-28)
import { Card, Table, Dialog, Badge, Button, ... } from "./ui/*";
import { PageLayout, PageHeader, StatCards, SearchFilter, EmptyState, MobileCard } from "./organisms";
import { QuoteData } from "./QuoteManagement3Write";
import { QuoteCalculationReport } from "./QuoteCalculationReport";

// 컴포넌트 함수 (30-787)
export function QuoteManagement3List({ quotes, onNew, onView, onEdit, onDelete, onFinalize }) {
  // useState (45-50) - 6개 상태
  const [searchTerm, setSearchTerm] = useState("");
  const [selectedQuote, setSelectedQuote] = useState<QuoteData | null>(null);
  const [isDetailDialogOpen, setIsDetailDialogOpen] = useState(false);
  const [isRevisionHistoryOpen, setIsRevisionHistoryOpen] = useState(false);
  const [isCalculationReportOpen, setIsCalculationReportOpen] = useState(false);
  const [selectedRevisionNumber, setSelectedRevisionNumber] = useState<number | null>(null);

  // 샘플 데이터 (62-137)
  const sampleQuotes: QuoteData[] = [ ... ];

  // 이벤트 핸들러 (142-161)
  const handleViewDetail = (quote) => { ... };
  const handleViewRevisionHistory = (quote) => { ... };
  const handleViewCalculationReport = (quote) => { ... };

  // 필터링 및 통계 (164-202)
  const filteredQuotes = allQuotes.filter(...);
  const stats = [ ... ];

  // 금액 포맷팅 (205-207)
  const formatAmount = (amount) => { ... };

  // 수정 차수 Badge (210-227)
  const getRevisionBadge = (quote) => { ... };

  // 렌더링 (229-787)
  return (
    <PageLayout>
      <PageHeader title="견적 관리" icon={FileText} actions={<Button>견적 작성</Button>} />
      <SearchFilter searchValue={searchTerm} onSearchChange={setSearchTerm} />
      <StatCards stats={stats} />

      {/* 데스크톱 테이블 (268-419) */}
      <Card>
        <Table> ... </Table>
      </Card>

      {/* 모바일 카드 (421-488) */}
      <div className="md:hidden">
        {filteredQuotes.map(quote => <MobileCard ... />)}
      </div>

      {/* 상세 보기 다이얼로그 (492-671) */}
      <Dialog> ... </Dialog>

      {/* 수정 이력 다이얼로그 (673-776) */}
      <Dialog> ... </Dialog>

      {/* 산출내역서 (778-784) */}
      {isCalculationReportOpen && <QuoteCalculationReport ... />}
    </PageLayout>
  );
}
```

**핵심 기능:**
1. **견적 목록 표시**
   - 데스크톱: Table (13개 컬럼)
   - 모바일: MobileCard

2. **검색 및 필터링**
   - SearchFilter 컴포넌트 사용
   - 견적번호, 발주처, 담당자, 제품코드, 현장명 검색

3. **통계 카드**
   - 총 견적서, 수주 전환, 최종 확정, 총 견적금액
   - StatCards 컴포넌트 사용

4. **견적 수정 이력 관리** ⭐
   - currentRevision: 현재 수정 차수
   - revisions: 수정 이력 배열 (QuoteRevision[])
   - 이력 선택 및 조회 기능 (Select 드롭다운)
   - 수정 사유 표시

5. **액션 버튼**
   - 이력 보기 (History 아이콘)
   - 산출내역서 보기 (Calculator 아이콘)
   - 상세 보기 (Eye)
   - 수정 (Edit)
   - 최종 확정 (CheckCircle)
   - 삭제 (Trash2)

**Organisms 활용:**
- ✅ PageLayout, PageHeader
- ✅ StatCards, SearchFilter
- ✅ EmptyState, MobileCard
- ⚠️ Table은 직접 구현 (DataTable organism 미사용)

**분석:**
- ✅ **적절한 파일 크기** (788 lines)
- ✅ **Organisms 재사용** (6/8 사용)
- ✅ **반응형 UI** (데스크톱/모바일 분리)
- ✅ **수정 이력 관리** 구현
- ⚠️ DataTable organism 활용 시 더 간결해질 수 있음

---

#### 4.3 QuoteManagement3Write.tsx (1,644 lines)

**구조 분석:**
```typescript
// Import (1-24)
import { Card, Input, Label, Textarea, Select, Button, Dialog, ... } from "./ui/*";
import { PageLayout, PageHeader } from "./organisms";
import { useData, ItemMaster, BOMLine } from "./contexts/DataContext";
import { toast } from "sonner";

// 인터페이스 정의 (27-113)
interface CalculationRow { ... }
interface BOMCalculationRow { ... }
export interface QuoteRevision { ... }
export interface QuoteData { ... }

// 컴포넌트 함수 (115-1643)
export function QuoteManagement3Write({ onSave, onCancel, editingQuote }) {
  const { itemMasters, sites, clients, quotes, addClient, addSite } = useData();

  // useState (128-192) - 약 40개 상태 관리
  const [receiptDate, setReceiptDate] = useState(...);
  const [author, setAuthor] = useState(...);
  const [client, setClient] = useState(...);
  const [site, setSite] = useState(...);
  const [productCategory, setProductCategory] = useState<'SCREEN' | 'STEEL'>(...);
  const [selectedProductId, setSelectedProductId] = useState(...);
  const [openSizeWidth, setOpenSizeWidth] = useState(...);
  const [openSizeHeight, setOpenSizeHeight] = useState(...);
  const [bomCalculations, setBomCalculations] = useState<BOMCalculationRow[]>(...);
  const [totalAmount, setTotalAmount] = useState(...);
  const [isRevisionDialogOpen, setIsRevisionDialogOpen] = useState(false);
  const [revisionReason, setRevisionReason] = useState("");
  const [selectedRevisionNumber, setSelectedRevisionNumber] = useState<number | null>(null);
  const [isViewingHistory, setIsViewingHistory] = useState(false);
  // ... 약 30개 더

  // 함수 정의 (197-626)
  const updateDeliveryDate = (bomId, deliveryDate) => { ... };
  const updateFormula = (bomId, newFormula) => { ... };
  const validateFormula = (formula) => { ... };
  const calculateQuantity = (formula, baseQty, W, H) => { ... }; // 수식 계산 엔진
  const handleRevisionSelect = (value) => { ... };
  const resetToCurrentData = () => { ... };
  const loadRevisionData = (revisionNumber) => { ... };
  const generateQuoteNumber = (category) => { ... };
  const handleSaveClick = () => { ... };
  const handleSave = (isRevision) => { ... };

  // useEffect (385-626) - 5개
  useEffect(() => { /* editingQuote 초기화 */ }, [editingQuote]);
  useEffect(() => { /* BOM 자동 계산 */ }, [selectedProduct, openSizeWidth, openSizeHeight, quantity]);
  useEffect(() => { /* bomCalculations 변경 시 총 금액 재계산 */ }, [bomCalculations]);
  useEffect(() => { /* 제품 카테고리 변경 시 초기화 */ }, [productCategory]);
  useEffect(() => { /* 견적번호 자동 생성 */ }, [productCategory]);

  // 렌더링 (791-1641)
  return (
    <PageLayout>
      <PageHeader title="견적 산출하기" icon={FileEdit} actions={...} />

      {/* 히스토리 뷰어 (815-895) */}
      {editingQuote && editingQuote.revisions && (
        <Card className="border-purple-200">
          <Select value={...} onValueChange={handleRevisionSelect}>
            <SelectItem value="current">현재 버전</SelectItem>
            {revisions.map(r => <SelectItem>V{r.revisionNumber}</SelectItem>)}
          </Select>
        </Card>
      )}

      {/* 기본 정보 (896-1130) */}
      <Card>
        <Label>등록일</Label>
        <Input type="date" value={registrationDate} />
        <Label>견적번호</Label>
        <Input value={quoteNumber} />
        <Label>발주처</Label>
        <Select>
          <SelectItem value="direct">직접 입력</SelectItem>
          {clients.map(c => <SelectItem>{c.name}</SelectItem>)}
        </Select>
        {/* ... 약 15개 필드 */}
      </Card>

      {/* 제품 선택 (1132-1256) */}
      <Card>
        <Label>제품 유형</Label>
        <Select value={productCategory} onValueChange={setProductCategory}>
          <SelectItem value="SCREEN">스크린</SelectItem>
          <SelectItem value="STEEL">철재</SelectItem>
        </Select>
        <Label>제품</Label>
        <Select value={selectedProductId} onValueChange={setSelectedProductId}>
          {filteredProducts.map(p => <SelectItem>{p.itemName}</SelectItem>)}
        </Select>
        <Label>오픈사이즈 - 폭 (W)</Label>
        <Input type="number" value={openSizeWidth} />
        <Label>오픈사이즈 - 높이 (H)</Label>
        <Input type="number" value={openSizeHeight} />
      </Card>

      {/* BOM 자동 계산 결과 (1258-1485) */}
      {bomCalculations.length > 0 ? (
        <Card className="border-2 border-green-200">
          <CardHeader className="bg-green-50">
            <Badge>W: {openSizeWidth}mm × H: {openSizeHeight}mm</Badge>
            <Badge>🎯 BOM 템플릿 적용</Badge>
          </CardHeader>
          <Table>
            <TableHeader>
              <TableHead>품목코드</TableHead>
              <TableHead>품목명</TableHead>
              <TableHead>기준수량</TableHead>
              <TableHead>계산식 (편집 가능)</TableHead> {/* ⭐ 핵심 */}
              <TableHead>계산수량</TableHead>
              <TableHead>단가</TableHead>
              <TableHead>금액</TableHead>
              <TableHead>납기일</TableHead>
            </TableHeader>
            <TableBody>
              {bomCalculations.map(calc => (
                <TableRow>
                  <TableCell>{calc.itemCode}</TableCell>
                  <TableCell>{calc.itemName}</TableCell>
                  <TableCell>{calc.baseQuantity}</TableCell>
                  <TableCell>
                    {/* ⭐ 수식 편집 가능 */}
                    <Input
                      value={calc.formula || ''}
                      onChange={e => updateFormula(calc.id, e.target.value)}
                      placeholder="예: W*H/1000000"
                    />
                    {calc.formula && (
                      <div>
                        <div>= {calc.formula.replace(/W/g, openSizeWidth).replace(/H/g, openSizeHeight)}</div>
                        <div>= {calc.calculatedQuantity.toFixed(2)}</div>
                      </div>
                    )}
                  </TableCell>
                  <TableCell>{calc.calculatedQuantity.toFixed(2)}</TableCell>
                  <TableCell>{calc.unitPrice.toLocaleString()}</TableCell>
                  <TableCell>{calc.totalPrice.toLocaleString()}</TableCell>
                  <TableCell>
                    <Input
                      type="date"
                      value={calc.deliveryDate}
                      onChange={e => updateDeliveryDate(calc.id, e.target.value)}
                    />
                  </TableCell>
                </TableRow>
              ))}
              <TableRow className="bg-gray-50">
                <TableCell colSpan={6}>자재비 합계</TableCell>
                <TableCell>{materialCost.toLocaleString()}원</TableCell>
              </TableRow>
              <TableRow>
                <TableCell colSpan={6}>노무비</TableCell>
                <TableCell>{laborCost.toLocaleString()}원</TableCell>
              </TableRow>
              <TableRow>
                <TableCell colSpan={6}>설치비</TableCell>
                <TableCell>{installCost.toLocaleString()}원</TableCell>
              </TableRow>
              <TableRow className="bg-blue-100">
                <TableCell colSpan={6}>총 견적 금액</TableCell>
                <TableCell className="text-blue-600">{totalAmount.toLocaleString()}원</TableCell>
              </TableRow>
            </TableBody>
          </Table>
        </Card>
      ) : (
        {/* 안내 메시지 (1524-1594) */}
        <Card className="border-dashed border-blue-200">
          <p>제품을 선택하고 오픈사이즈를 입력하면 자동으로 계산됩니다</p>
          <div>
            <div>1. 제품 유형 선택</div>
            <div>2. 제품 선택</div>
            <div>3. 오픈사이즈 입력 (W, H)</div>
          </div>
          <p>✓ 부품 자동 계산: 프레임, 레일, 모터 등 자동 계산</p>
          <p>✓ 계산식 투명 공개: W×2, H×2, (W+H)×2 등 표시</p>
          <p>✓ 정확한 견적 산출: 자재비 + 노무비 + 설치비</p>
        </Card>
      )}

      {/* 비고 (1596-1610) */}
      <Card>
        <Textarea value={remarks} onChange={e => setRemarks(e.target.value)} />
      </Card>

      {/* 수정 사유 입력 다이얼로그 (1613-1640) */}
      <Dialog open={isRevisionDialogOpen}>
        <Label>수정 사유</Label>
        <Textarea value={revisionReason} onChange={e => setRevisionReason(e.target.value)} />
        <Button onClick={() => handleSave(true)}>수정 사유 저장</Button>
      </Dialog>
    </PageLayout>
  );
}
```

**핵심 기능:**

#### 1. BOM 기반 자동 견적 계산 ⭐⭐⭐
```typescript
// useEffect에서 자동 계산
useEffect(() => {
  if (!selectedProduct || !openSizeWidth || !openSizeHeight) return;

  const W = parseFloat(openSizeWidth);
  const H = parseFloat(openSizeHeight);

  // BOM 템플릿 또는 제품 BOM 사용
  const matchingTemplate = bomTemplates.find(...);

  if (matchingTemplate) {
    // BOM 템플릿 기반 계산
    calculations = matchingTemplate.bomRules.map(rule => {
      const calcQty = calculateQuantity(rule.quantityFormula, 1, W, H);
      // 반올림 규칙 적용
      let finalQty = calcQty;
      if (rule.roundingRule === 'ceil') finalQty = Math.ceil(calcQty);
      else if (rule.roundingRule === 'floor') finalQty = Math.floor(calcQty);
      else if (rule.roundingRule === 'round') finalQty = Math.round(calcQty);

      // 최소/최대값 적용
      if (rule.minValue && finalQty < rule.minValue) finalQty = rule.minValue;
      if (rule.maxValue && finalQty > rule.maxValue) finalQty = rule.maxValue;

      return {
        itemCode: rule.partCode,
        itemName: rule.partName,
        baseQuantity: 1,
        calculatedQuantity: finalQty,
        unit: rule.unit,
        unitPrice: partItem?.salesPrice || 0,
        totalPrice: finalQty * (partItem?.salesPrice || 0),
        formula: rule.quantityFormula,
        note: rule.description
      };
    });
  } else if (selectedProduct.bom) {
    // 제품 BOM 기반 계산
    calculations = selectedProduct.bom.map(bomLine => {
      const calcQty = calculateQuantity(bomLine.quantityFormula, bomLine.quantity, W, H);
      return {
        itemCode: bomLine.childItemCode,
        itemName: bomLine.childItemName,
        baseQuantity: bomLine.quantity,
        calculatedQuantity: calcQty,
        unit: bomLine.unit,
        unitPrice: bomLine.unitPrice || 0,
        totalPrice: calcQty * (bomLine.unitPrice || 0),
        formula: bomLine.quantityFormula,
        note: bomLine.note
      };
    });
  }

  setBomCalculations(calculations);

  // 총 금액 계산
  const materialCost = calculations.reduce((sum, calc) => sum + calc.totalPrice, 0);
  const laborCost = selectedProduct.laborCost || 0;
  const installCost = selectedProduct.installCost || 0;
  const subtotal = materialCost + laborCost + installCost;
  const total = subtotal * quantity;

  setTotalAmount(total);
}, [selectedProduct, openSizeWidth, openSizeHeight, quantity]);
```

#### 2. 수식 계산 엔진 ⭐
```typescript
const calculateQuantity = (formula: string | undefined, baseQty: number, W: number, H: number): number => {
  if (!formula) return baseQty;

  try {
    // W와 H를 실제 값으로 치환
    const expression = formula.replace(/W/g, W.toString()).replace(/H/g, H.toString());
    // 수식 계산 (eval 대신 안전한 Function 사용)
    const result = Function(`"use strict"; return (${expression})`)();
    // 소수점 셋째 자리에서 반올림
    return Math.round(result * 100) / 100;
  } catch (error) {
    console.error('수식 계산 오류:', formula, error);
    return baseQty;
  }
};

// 수식 검증
const validateFormula = (formula: string): { isValid: boolean; error?: string } => {
  if (!formula.trim()) return { isValid: true };

  try {
    const W = 1000, H = 2000;
    const testExpression = formula.replace(/W/g, W.toString()).replace(/H/g, H.toString());
    const result = Function(`"use strict"; return (${testExpression})`)();

    if (typeof result !== 'number' || isNaN(result)) {
      return { isValid: false, error: '수식 결과가 숫자가 아닙니다' };
    }

    return { isValid: true };
  } catch (error) {
    return { isValid: false, error: '수식 구문 오류' };
  }
};
```

**지원 수식 예시:**
- `W * 2` - 폭의 2배
- `H * 2` - 높이의 2배
- `(W + H) * 2` - 둘레
- `W * H / 1000000` - 면적 (m²)
- `W / 1000 * 1.02` - 연신율 반영

#### 3. 수식 편집 UI ⭐
```typescript
<TableCell>
  {/* 수식 입력 필드 */}
  <Input
    value={calc.formula || ''}
    onChange={e => updateFormula(calc.id, e.target.value)}
    placeholder="예: W*H/1000000"
    className="font-mono"
  />
  {/* 수식 미리보기 */}
  {calc.formula && (
    <div>
      <div>= {calc.formula.replace(/W/g, openSizeWidth).replace(/H/g, openSizeHeight)}</div>
      <div>= {calc.calculatedQuantity.toFixed(2)}</div>
    </div>
  )}
</TableCell>
```

#### 4. 견적 수정 이력 관리 ⭐
```typescript
interface QuoteRevision {
  revisionNumber: number;
  revisionDate: string;
  revisionBy: string;
  revisionReason?: string;
  previousData: any; // 이전 버전 데이터 전체 저장
}

interface QuoteData {
  currentRevision?: number; // 현재 수정 차수
  isFinal?: boolean; // 최종 확정 여부
  revisions?: QuoteRevision[]; // 수정 이력 배열
  finalizedDate?: string;
  finalizedBy?: string;
  status?: 'draft' | 'sent' | 'approved' | 'rejected' | 'converted' | 'finalized';
}

// 히스토리 선택 및 조회
const handleRevisionSelect = (value: string) => {
  if (value === 'current') {
    setIsViewingHistory(false);
    setSelectedRevisionNumber(null);
    resetToCurrentData();
  } else {
    const revisionNumber = parseInt(value);
    setSelectedRevisionNumber(revisionNumber);
    setIsViewingHistory(true);
    loadRevisionData(revisionNumber);
  }
};

// 히스토리 데이터 로드
const loadRevisionData = (revisionNumber: number) => {
  const revision = initialData.revisions.find(r => r.revisionNumber === revisionNumber);
  if (!revision || !revision.previousData) return;

  const data = revision.previousData;
  setReceiptDate(data.receiptDate || "");
  setAuthor(data.author || "");
  // ... 모든 필드 복원
  setBomCalculations(data.bomCalculations || []);
  setTotalAmount(data.amount || 0);
};
```

#### 5. 견적번호 자동 생성 ⭐
```typescript
const generateQuoteNumber = (category: 'SCREEN' | 'STEEL') => {
  const now = new Date();
  const productTypeCode = category === 'SCREEN' ? 'SC' : 'PR';
  const dateStr = `${String(now.getFullYear()).slice(2)}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}`;

  // 오늘 날짜의 동일한 제품 타입 견적 개수 확인
  const today = new Date().toISOString().split('T')[0];
  const todayQuotes = quotes.filter(q => {
    const qDate = q.registrationDate || q.quoteDate || '';
    const qType = q.productCategory || (q.type === '스크린' ? 'SCREEN' : 'STEEL');
    return qDate === today && qType === category;
  });

  // 순번 생성 (01부터 시작)
  const sequenceNum = String(todayQuotes.length + 1).padStart(2, '0');

  return `KD-${productTypeCode}-${dateStr}-${sequenceNum}`;
  // 예: KD-PR-250717-02 (2025년 7월 17일, 철재 제품, 당일 2번째 견적)
};
```

#### 6. 거래처/현장 자동 등록 ⭐
```typescript
// 직접 입력된 거래처 자동 등록
if (isDirectInputClient && directClientName.trim()) {
  const newClient = {
    id: `CLI-${Date.now()}`,
    code: `C${Date.now().toString().slice(-6)}`,
    name: directClientName.trim(),
    type: '매출',
    phone: contact || '',
    managerName: manager || '',
    memo: `견적 ${quoteNumber || '신규'} 작성 시 자동 등록`,
    // ...
  };
  addClient(newClient);
  toast.success(`거래처 "${directClientName.trim()}"가 자동으로 등록되었습니다.`);
}

// 직접 입력된 현장 자동 등록
if (isDirectInputSite && directSiteName.trim()) {
  const newSite = {
    id: `SITE-${Date.now()}`,
    siteCode: directSiteCode.trim() || `PJ-${new Date().getFullYear()}${String(Date.now()).slice(-6)}`,
    siteName: directSiteName.trim(),
    clientName: finalClientName || '',
    salesManager: manager || '',
    memo: `견적 ${quoteNumber || '신규'} 작성 시 자동 등록`,
    // ...
  };
  addSite(newSite);
  toast.success(`현장 "${directSiteName.trim()}"이 자동으로 등록되었습니다.`);
}
```

**분석:**
- ✅ **BOM 기반 자동 계산 완전 구현**
- ✅ **수식 편집 UI 제공** (W, H 변수 지원)
- ✅ **견적 수정 이력 관리**
- ✅ **견적번호 자동 생성** (날짜 기반)
- ✅ **거래처/현장 자동 등록**
- ⚠️ **파일 크기 1,644 lines** - 관리 가능하지만 리팩토링 권장
- ⚠️ **40개 이상의 useState** - 커스텀 훅으로 분리 권장
- ⚠️ **비즈니스 로직과 UI 혼재** - 관심사 분리 권장

**리팩토링 제안:**
```
QuoteManagement3Write.tsx (1,644 lines)
↓ 리팩토링
├── pages/QuoteWritePage.tsx (100-150 lines)
├── organisms/QuoteFormSection.tsx (200-300 lines)
├── organisms/ProductSelectionSection.tsx (200-300 lines)
├── organisms/BOMCalculationTable.tsx (300-400 lines) ⭐
├── hooks/useQuoteForm.ts (200-300 lines)
├── hooks/useBOMCalculation.ts (200-300 lines) ⭐
├── hooks/useFormulaCalculator.ts (100-150 lines) ⭐
├── hooks/useQuoteRevision.ts (150-200 lines)
└── utils/quoteNumberGenerator.ts (50-100 lines)
```

---

## 🔧 Atomic Design 패턴 적용 현황

### 1. Atoms (47개) - shadcn/ui

✅ **완비**: 모든 기본 UI 요소 구축 완료

| 카테고리 | 개수 | 컴포넌트 |
|----------|------|----------|
| Form Controls | 9 | button, input, textarea, checkbox, radio-group, select, label, switch, slider |
| Data Display | 7 | table, badge, card, avatar, separator, tooltip, skeleton |
| Layout | 9 | dialog, sheet, popover, dropdown-menu, tabs, accordion, collapsible, sidebar |
| Feedback | 4 | alert, alert-dialog, sonner (toast), progress |
| Navigation | 5 | navigation-menu, menubar, breadcrumb, pagination, command |
| Advanced | 13 | calendar, carousel, chart, context-menu, drawer, form, hover-card, input-otp, resizable, scroll-area, toggle, toggle-group, aspect-ratio |

### 2. Molecules (6개) - 조합 컴포넌트

⚠️ **부족**: 10-15개 권장, 현재 6개

| 컴포넌트 | 용도 | 평가 |
|----------|------|------|
| TableActions | 테이블 액션 버튼 그룹 | ✅ 좋음 |
| StatusBadge | 상태 표시 배지 | ✅ 좋음 |
| IconWithBadge | 아이콘 + 배지 | ✅ 좋음 |
| FormField | 폼 필드 (라벨 + 입력) | ⚠️ 확인 필요 |
| StatCard | 단일 통계 카드 | ⚠️ 확인 필요 |
| SearchBar | 검색 바 | ⚠️ 확인 필요 |

**확장 필요:**
- FieldGroup (여러 필드 그룹)
- DateRangePicker (날짜 범위 선택)
- NumericInput (숫자 입력 + 포맷팅)
- FileUpload (파일 업로드 + 미리보기)
- PriceInput (가격 입력 + 통화 표시)
- QuantityInput (수량 입력 + 단위)
- FormulaInput (수식 입력 + 검증) ⭐
- TagInput (태그 입력)

### 3. Organisms (8개) - 복합 컴포넌트

✅ **양호**: 재사용성 높은 컴포넌트 구축

| 컴포넌트 | 크기 | 용도 | 평가 |
|----------|------|------|------|
| PageLayout | 42 lines | 페이지 레이아웃 | ✅ 우수 |
| PageHeader | 34 lines | 페이지 헤더 | ✅ 우수 |
| StatCards | 54 lines | 통계 카드 그리드 | ✅ 우수 |
| SearchFilter | 46 lines | 검색 + 필터 | ✅ 우수 |
| DataTable | 314 lines | 범용 테이블 | ✅ **매우 우수** ⭐ |
| EmptyState | 36 lines | 빈 상태 UI | ✅ 우수 |
| MobileCard | 100 lines | 모바일 카드 | ✅ 우수 |
| FormSection | ? lines | 폼 섹션 | ⚠️ 확인 필요 |

**확장 필요:**
- FormBuilder (동적 폼 생성기) ⭐
- BOMCalculationTable (BOM 계산 테이블) ⭐
- RevisionHistoryViewer (수정 이력 뷰어) ⭐
- PriceHistoryManager (가격 이력 관리)
- FileManager (파일 관리)
- OptionEditor (옵션 편집기)

### 4. Templates (0개) - 템플릿

❌ **부재**: 템플릿 레이어 없음

**필요한 템플릿:**
- ListPageTemplate (목록 페이지)
- FormPageTemplate (폼 페이지)
- DetailPageTemplate (상세 페이지)
- DashboardTemplate (대시보드)

### 5. Pages (123개)

⚠️ **과도**: 단일 파일 크기 문제

**문제 파일:**
- ItemManagement.tsx: 6,521 lines 🔴 **Critical**
- QuoteManagement3Write.tsx: 1,644 lines ⚠️ **Large**
- QuoteManagement3List.tsx: 788 lines ✅ **Acceptable**

---

## 📊 재사용 가능 컴포넌트 분석

### 1. 재사용성 높은 컴포넌트 ✅

#### Organisms Level
| 컴포넌트 | 재사용 가능성 | 활용 예시 |
|----------|--------------|----------|
| **DataTable** ⭐⭐⭐ | 매우 높음 | 모든 목록 화면 (품목, 견적, 주문, 재고, etc.) |
| **PageLayout** | 매우 높음 | 모든 페이지 |
| **PageHeader** | 매우 높음 | 모든 페이지 |
| **StatCards** | 높음 | 대시보드, 통계 화면 |
| **SearchFilter** | 높음 | 목록 화면 |
| **EmptyState** | 높음 | 빈 상태 표시 |
| **MobileCard** | 높음 | 모바일 목록 화면 |

#### Molecules Level
| 컴포넌트 | 재사용 가능성 | 활용 예시 |
|----------|--------------|----------|
| **TableActions** | 높음 | 테이블 액션 버튼 |
| **StatusBadge** | 높음 | 상태 표시 |
| **IconWithBadge** | 중간 | 아이콘 + 배지 |

### 2. 확장 필요 컴포넌트 ⚠️

#### BOM 관련 재사용 컴포넌트 (현재 QuoteManagement3Write.tsx에만 존재)

**BOMCalculationTable**
```typescript
// 현재: QuoteManagement3Write.tsx 내부 (1258-1485 lines)
// 제안: organisms/BOMCalculationTable.tsx (300-400 lines)

interface BOMCalculationTableProps {
  bomCalculations: BOMCalculationRow[];
  onFormulaChange: (bomId: string, formula: string) => void;
  onDeliveryDateChange: (bomId: string, date: string) => void;
  openSizeWidth: string;
  openSizeHeight: string;
  selectedProduct: ItemMaster | null;
  quantity: number;
  totalAmount: number;
  editable?: boolean;
}

export function BOMCalculationTable({ ... }: BOMCalculationTableProps)
```

**활용 가능 화면:**
- 견적 작성 ✅ (현재 사용 중)
- 견적 조회 (읽기 전용)
- 주문 확인 (BOM 조회)
- 생산 계획 (BOM 조회)
- 원가 계산 (BOM + 가격)

---

**FormulaCalculator (수식 계산 엔진)**
```typescript
// 현재: QuoteManagement3Write.tsx 내부 (369-383 lines)
// 제안: hooks/useFormulaCalculator.ts (100-150 lines)

export function useFormulaCalculator() {
  const calculateQuantity = (formula: string | undefined, baseQty: number, W: number, H: number): number => {
    // ... 수식 계산 로직
  };

  const validateFormula = (formula: string): { isValid: boolean; error?: string } => {
    // ... 수식 검증 로직
  };

  return { calculateQuantity, validateFormula };
}
```

**활용 가능 화면:**
- 견적 작성 ✅ (현재 사용 중)
- BOM 템플릿 관리 (수식 편집)
- 생산 계획 (수량 계산)
- 재고 계산 (소요량 계산)

---

**RevisionHistoryViewer**
```typescript
// 현재: QuoteManagement3List.tsx, QuoteManagement3Write.tsx 각각 구현
// 제안: organisms/RevisionHistoryViewer.tsx (200-300 lines)

interface RevisionHistoryViewerProps<T> {
  currentData: T;
  revisions: Array<{
    revisionNumber: number;
    revisionDate: string;
    revisionBy: string;
    revisionReason: string;
    previousData: T;
  }>;
  onRevisionSelect: (revisionNumber: number | null) => void;
  selectedRevisionNumber: number | null;
  editable?: boolean;
}

export function RevisionHistoryViewer<T>({ ... }: RevisionHistoryViewerProps<T>)
```

**활용 가능 화면:**
- 견적 관리 ✅ (현재 개별 구현)
- 주문 관리 (수정 이력)
- 품목 관리 (가격 이력)
- 거래처 관리 (정보 변경 이력)

---

### 3. 리팩토링 우선순위

| 우선순위 | 파일 | 문제 | 해결 방안 |
|----------|------|------|----------|
| 🔴 **P0** | ItemManagement.tsx | 6,521 lines | Atomic Design 패턴 적용, 10-15개 파일로 분리 |
| 🟡 **P1** | QuoteManagement3Write.tsx | 1,644 lines, 40개 useState | 커스텀 훅 분리, Organisms 추출 |
| 🟢 **P2** | 공통 컴포넌트 확장 | Molecules 6개 부족 | FormField, FormulaInput, PriceInput 등 추가 |
| 🟢 **P2** | 공통 컴포넌트 확장 | Organisms 부족 | BOMCalculationTable, RevisionHistoryViewer 등 추가 |
| 🟢 **P3** | Template 레이어 | 템플릿 부재 | ListPageTemplate, FormPageTemplate 등 추가 |

---

## 🎨 shadcn/ui 활용 현황

### 1. 사용 빈도 높은 컴포넌트

**모든 화면에서 사용:**
- Button, Input, Label, Card, Table, Badge

**견적 관리에서 사용 (QuoteManagement3List, QuoteManagement3Write):**
- Dialog, Select, Textarea, Separator
- Tabs (QuoteManagement3Write - 히스토리 뷰어)

**품목 관리에서 사용 (ItemManagement.tsx 추정):**
- AlertDialog, Checkbox, Popover, Command, Collapsible, Pagination

### 2. 사용되지 않는 컴포넌트

**거의 사용되지 않는 것으로 추정:**
- Calendar, Chart, Carousel
- Menubar, NavigationMenu, HoverCard
- Drawer, Sheet (Dialog 선호)
- Skeleton (로딩 상태 미사용)
- Progress, Slider, Switch
- Toggle, ToggleGroup
- InputOTP, AspectRatio, Resizable

**제안:**
- 사용되지 않는 컴포넌트 제거 고려
- 또는 활용 방안 검토 (예: Chart → 대시보드 통계)

---

## 🔗 API 통합 분석

### 1. 백엔드 API 활용 가능성

**Phase B.1 (Laravel API 분석) 결과:**

| API | 구현 여부 | 프론트엔드 활용 |
|-----|----------|---------------|
| ItemsController (통합 품목 조회) | ✅ 존재 | ⚠️ **확인 필요** |
| BomCalculationController (BOM 계산) | ✅ 존재 (설계 BOM만) | ❌ **미사용** (프론트에서 계산) |
| PricingController (가격 조회) | ✅ 존재 | ⚠️ **확인 필요** |

### 2. Gap #3 (실시간 견적 계산 API) 재검증 필요

**문서 분석 (Phase A):**
- ❌ POST /api/v1/quotes/calculate 부재

**코드 분석 (Phase B.1):**
- ✅ POST /api/v1/design/bom-templates/{id}/calculate 존재 (설계 BOM만)

**React 코드 분석 (Phase B.2):**
- ❌ **프론트엔드에서 BOM 계산 직접 수행** (QuoteManagement3Write.tsx)
- ❌ **백엔드 BOM 계산 API 미사용**

**결론:**
- Gap #3은 여전히 존재
- 프론트엔드에서 BOM 계산 로직 중복 구현 중
- **백엔드 API 통합 필요** (주문 기반 견적 계산 API)

**제안:**
```
POST /api/v1/quotes/calculate
Request:
{
  "product_id": 123,
  "open_size_width": 3500,
  "open_size_height": 2000,
  "quantity": 1,
  "customer_id": 456
}

Response:
{
  "bom_calculations": [
    {
      "item_code": "GR-001",
      "item_name": "가이드레일",
      "base_quantity": 1,
      "formula": "W * 2",
      "calculated_quantity": 7.0,
      "unit": "M",
      "unit_price": 50000,
      "total_price": 350000
    },
    ...
  ],
  "material_cost": 1500000,
  "labor_cost": 300000,
  "install_cost": 200000,
  "subtotal": 2000000,
  "total_amount": 2000000
}
```

---

## 💡 핵심 발견 요약

### ✅ Positive Findings

1. **shadcn/ui 기반 Atomic Design 부분 적용**
   - Atoms (47개) 완비
   - Organisms (8개) 재사용성 높음
   - DataTable organism 매우 강력 ⭐

2. **BOM 기반 자동 견적 계산 완전 구현**
   - 수식 기반 수량 계산 (W, H 변수)
   - 실시간 견적 산출
   - 수식 편집 UI 제공 ⭐

3. **견적 수정 이력 관리 구현**
   - Revision 시스템 완성
   - 이력 조회 및 복원 기능

4. **반응형 UI 구현**
   - 데스크톱/모바일 분리 (Table vs MobileCard)

### ❌ Critical Issues

1. **ItemManagement.tsx 6,521 lines** 🔴 **Critical**
   - 유지보수 불가능한 수준
   - 긴급 리팩토링 필요

2. **Molecules/Organisms 재사용성 제한**
   - Molecules 6개 → 10-15개 필요
   - BOMCalculationTable, RevisionHistoryViewer 등 추출 필요

3. **백엔드 API 통합 부족**
   - BOM 계산 로직 프론트엔드 중복 구현
   - 주문 기반 견적 계산 API 부재

4. **Template 레이어 부재**
   - ListPageTemplate, FormPageTemplate 등 필요

---

## 📈 개선 로드맵

### Phase 1: 긴급 리팩토링 (P0)

**ItemManagement.tsx 분해** (예상 1-2주)
```
ItemManagement.tsx (6,521 lines)
→ 10-15개 파일로 분해
  - pages/ItemManagementPage.tsx (100-150 lines)
  - organisms/ItemFormDialog.tsx (200-300 lines)
  - organisms/BOMEditor.tsx (200-300 lines)
  - organisms/PriceHistoryManager.tsx (150-200 lines)
  - hooks/useItemForm.ts (150-200 lines)
  - hooks/useItemValidation.ts (100-150 lines)
  - constants/itemCategories.ts (200-300 lines)
```

### Phase 2: 공통 컴포넌트 확장 (P1)

**Molecules 확장** (예상 1주)
- FormulaInput (수식 입력 + 검증) ⭐
- PriceInput (가격 입력 + 통화 표시)
- QuantityInput (수량 입력 + 단위)
- DateRangePicker (날짜 범위 선택)
- FileUpload (파일 업로드 + 미리보기)

**Organisms 확장** (예상 2주)
- BOMCalculationTable (BOM 계산 테이블) ⭐
- RevisionHistoryViewer (수정 이력 뷰어) ⭐
- FormBuilder (동적 폼 생성기)
- PriceHistoryManager (가격 이력 관리)

### Phase 3: API 통합 (P1)

**백엔드 API 통합** (예상 1주)
- POST /api/v1/quotes/calculate 구현 (백엔드)
- BomCalculationController 활용 (프론트엔드)
- 중복 로직 제거

### Phase 4: Template 레이어 구축 (P2)

**Template 추가** (예상 1주)
- ListPageTemplate
- FormPageTemplate
- DetailPageTemplate
- DashboardTemplate

---

## 🏁 결론

### 종합 평가

**강점:**
- ✅ shadcn/ui 기반 Atomic Design 부분 적용 (Atoms, Organisms)
- ✅ BOM 기반 자동 견적 계산 완전 구현 (수식 엔진 포함) ⭐
- ✅ 재사용 가능한 Organisms 컴포넌트 구축 (DataTable 우수)
- ✅ 반응형 UI 구현 (데스크톱/모바일)

**약점:**
- ❌ ItemManagement.tsx 6,521 lines (긴급 리팩토링 필요) 🔴
- ❌ Molecules/Organisms 재사용성 제한 (확장 필요)
- ❌ 백엔드 API 통합 부족 (BOM 계산 중복)
- ❌ Template 레이어 부재

**우선순위:**
1. 🔴 **P0:** ItemManagement.tsx 리팩토링 (긴급)
2. 🟡 **P1:** 공통 컴포넌트 확장 (BOMCalculationTable, RevisionHistoryViewer)
3. 🟡 **P1:** 백엔드 API 통합 (BOM 계산 API)
4. 🟢 **P2:** Template 레이어 구축

**다음 단계:**
→ Phase B.3: Gap 검증 및 통합 분석
→ Phase C: 최종 갭 분석 및 개발 범위 정의

---

**분석 완료일:** 2025-11-12
**다음 작업:** "Phase C 시작해줘" 또는 "Gap 검증 보고서 작성해줘"
