# 5130 → SAM BOM 데이터 마이그레이션 계획

> **작성일**: 2025-01-20
> **목적**: 5130 레거시 시스템의 BOM 데이터를 SAM items 테이블의 bom 컬럼에 마이그레이션
> **기준 문서**: `api/app/Services/Quote/FormulaEvaluatorService.php`
> **상태**: ✅ 완료 (Serena ID: 5130-bom-migration-state)

---

## 📍 현재 진행 상태

| 항목 | 내용 |
|------|------|
| **마지막 완료 작업** | BOM 마이그레이션 실행 완료 (61건) |
| **다음 작업** | 견적 페이지에서 실제 테스트 (사용자 수동 확인) |
| **진행률** | 4/4 (100%) |
| **마지막 업데이트** | 2025-01-20 |

---

## 1. 개요

### 1.1 배경

5130 레거시 시스템에서 SAM으로 품목(items) 마이그레이션이 완료되었으나, 완제품(FG)의 BOM 데이터가 마이그레이션되지 않아 다음 문제가 발생:

```
문제 현상:
- 견적 페이지에서 "국민방화스크린 (일체형) (S0001)" 선택 후 자동 견적 산출 → 합계 0원
- 원인: S0001의 bom 컬럼이 NULL
- items 테이블에서 확인: SELECT bom FROM items WHERE code = 'S0001' → NULL
```

**기존 마이그레이션 상태:**
- Items: 608건 (KDunitprice → items)
- Orders: 24,424건
- Order Items: 43,900건
- ❌ BOM 데이터: 마이그레이션 안됨

### 1.2 기준 원칙
```
┌─────────────────────────────────────────────────────────────────┐
│  🎯 핵심 원칙                                                    │
├─────────────────────────────────────────────────────────────────┤
│  1. FormulaEvaluatorService 호환 BOM JSON 형식 생성              │
│  2. 동적 수량 계산을 위한 quantityFormula 필드 지원              │
│  3. childItemCode 기반 참조 (child_item_id 아님)                 │
│  4. 기존 SAM BOM 패턴과 일관성 유지                              │
└─────────────────────────────────────────────────────────────────┘
```

### 1.3 변경 승인 정책

| 분류 | 예시 | 승인 |
|------|------|------|
| ✅ 즉시 가능 | BOM JSON 데이터 추가, 매핑 테이블 생성 | 불필요 |
| ⚠️ 컨펌 필요 | 기존 items 데이터 수정, 새 마이그레이션 스크립트 | **필수** |
| 🔴 금지 | items 테이블 구조 변경, 기존 BOM 삭제 | 별도 협의 |

### 1.4 준수 규칙
- `docs/quickstart/quick-start.md` - 빠른 시작 가이드
- `docs/standards/quality-checklist.md` - 품질 체크리스트
- `api/app/Services/Quote/FormulaEvaluatorService.php` - BOM 계산 로직

---

## 2. 데이터 구조 분석

### 2.1 5130 BOM 구조

```
5130 DB (chandj)
├── KDunitprice (품목 마스터)
│   ├── prodcode: 품목 코드
│   ├── item_name: 품목명
│   └── item_div: [제품], [상품], [부재료], [원재료], [반제품]
│
├── models (모델 마스터)
│   ├── model_id: PK
│   ├── model_name: KSS01, KSE01, KWE01... (모델 코드)
│   ├── major_category: 스크린 | 철재
│   ├── finishing_type: SUS마감 | EGI마감
│   └── guiderail_type: 벽면형 | 측면형
│
├── parts (1단계 BOM - 모델별 부품)
│   ├── part_id: PK
│   ├── model_id: FK → models
│   ├── part_name: 가이드레일, 하단마감재 등
│   ├── spec: 120*70, 60*40 등
│   ├── quantity: 수량
│   ├── unit: SET, EA 등
│   └── unitprice: 단가 (문자열, 콤마 포함)
│
└── parts_sub (2단계 BOM - 부품별 원자재)
    ├── subpart_id: PK
    ├── part_id: FK → parts
    ├── subpart_name: 1번(마감제), 2번(본체) 등
    ├── material: SUS 1.2T, EGI 1.55T 등
    ├── quantity: 수량
    ├── bendSum, plateSum, finalSum: 가공 관련
    └── unitPrice, computedPrice, lineTotal: 금액
```

**5130 model_id별 데이터 현황:**
| model_id | model_name | category | finishing | guiderail | parts 수 |
|----------|------------|----------|-----------|-----------|----------|
| 12 | KSS01 | 스크린 | SUS마감 | 벽면형 | 2 |
| 13 | KSS01 | 스크린 | SUS마감 | 측면형 | 2 |
| 14 | KSE01 | 스크린 | SUS마감 | 벽면형 | 2 |
| ... | ... | ... | ... | ... | ... |

**5130 KDunitprice item_div 분포:**
| item_div | 건수 | SAM item_type 매핑 |
|----------|------|-------------------|
| [제품] | 194건 | FG (완제품) |
| [상품] | 260건 | SM (부자재) |
| [부재료] | 48건 | SM (부자재) |
| [원재료] | 24건 | RM (원자재) |
| [반제품] | 73건 | SF (반제품) |
| [무형상품] | 4건 | CS (서비스) |

### 2.2 SAM BOM 구조

```sql
-- SAM items 테이블 BOM 컬럼
items.bom: JSON
```

**SAM BOM JSON 형식 (FormulaEvaluatorService 호환):**
```json
[
  {
    "childItemCode": "SF-SCR-F01",  // 필수: 하위 품목 코드
    "quantity": 1,                   // 필수: 기본 수량
    "quantityFormula": "W*H/1000000", // 선택: 동적 수량 계산식
    "unit": "M2",                    // 선택: 단위
    "note": "스크린 원단"             // 선택: 비고
  },
  {
    "childItemCode": "SF-SCR-M01",
    "quantity": 1,
    "quantityFormula": "",
    "unit": "EA",
    "note": "소형용 모터"
  }
]
```

**기존 SAM BOM 예시 (FG-SCR-001):**
```json
[
  {"unit":"M2","quantity":1,"childItemCode":"SF-SCR-F01","quantityFormula":"W*H/1000000"},
  {"unit":"M","quantity":1,"childItemCode":"SF-SCR-F02","quantityFormula":"H/1000"},
  {"unit":"EA","quantity":1,"childItemCode":"SF-SCR-M01","quantityFormula":"","note":"소형용"},
  {"unit":"EA","quantity":20,"childItemCode":"SM-B002","quantityFormula":"","note":"조립용"}
]
```

### 2.3 핵심 차이점

| 항목 | 5130 | SAM |
|------|------|-----|
| **BOM 저장 위치** | parts/parts_sub 테이블 | items.bom JSON 컬럼 |
| **연결 기준** | model_id (모델 기준) | childItemCode (품목 코드 기준) |
| **수량 계산** | 고정값 + estimate.detailJson | quantityFormula 동적 계산 |
| **단가 계산** | parts.unitprice 고정 | FormulaEvaluatorService 동적 |
| **계층 구조** | 2단계 (parts → parts_sub) | 1단계 (flat JSON array) |

---

## 3. 마이그레이션 전략

### 3.1 접근 방식: 수동 매핑 + 템플릿 기반

5130의 BOM 구조와 SAM의 BOM 구조가 근본적으로 다르기 때문에, 자동 변환이 아닌 **수동 매핑 + 템플릿 기반** 접근 필요:

```
┌─────────────────────────────────────────────────────────────────┐
│  전략: 완제품(FG) 유형별 BOM 템플릿 정의                          │
├─────────────────────────────────────────────────────────────────┤
│  1. SCREEN 완제품 → screen_bom_template                         │
│  2. STEEL 완제품 → steel_bom_template                           │
│  3. BENDING 완제품 → bending_bom_template                       │
│                                                                  │
│  각 템플릿은 FormulaEvaluatorService 호환 JSON 형식으로 정의     │
└─────────────────────────────────────────────────────────────────┘
```

### 3.2 완제품-모델 매핑

**매핑 대상 (SAM items WHERE item_type='FG' AND source='5130'):**
```sql
-- SAM에서 5130에서 마이그레이션된 완제품 목록
SELECT id, code, name, item_category
FROM items
WHERE item_type = 'FG'
  AND (legacy_code IS NOT NULL OR code LIKE 'S%');
```

**주요 완제품 매핑 예시:**
| SAM code | SAM name | item_category | 5130 model |
|----------|----------|---------------|------------|
| S0001 | 국민방화스크린(일체형) | SCREEN | KSS01 (스크린/SUS/벽면형) |
| S0002 | 국민방화스크린(분리형) | SCREEN | KSE01 (스크린/SUS/벽면형) |
| ... | ... | ... | ... |

### 3.3 BOM 템플릿 정의

**SCREEN 완제품 BOM 템플릿:**
```json
[
  {"childItemCode": "RM-SCR-FABRIC", "quantity": 1, "quantityFormula": "W*H/1000000", "unit": "M2", "note": "스크린 원단"},
  {"childItemCode": "PT-SCR-GUIDE", "quantity": 1, "quantityFormula": "H/1000", "unit": "M", "note": "가이드레일"},
  {"childItemCode": "PT-SCR-BOTTOM", "quantity": 1, "quantityFormula": "W/1000", "unit": "M", "note": "하단바"},
  {"childItemCode": "PT-SCR-CASE", "quantity": 1, "quantityFormula": "W/1000", "unit": "M", "note": "케이스"},
  {"childItemCode": "PT-SCR-MOTOR", "quantity": 1, "quantityFormula": "", "unit": "EA", "note": "모터"}
]
```

---

## 4. 작업 절차

### 4.1 Phase 1: 하위 품목 확인 및 생성

| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 1.1 | BOM에 필요한 하위 품목(SF, PT, RM) 목록 정의 | ✅ | 52개 품목 정의됨 |
| 1.2 | SAM items 테이블에 하위 품목 존재 여부 확인 | ✅ | 52개 모두 존재 확인 |
| 1.3 | 누락된 하위 품목 생성 (필요시) | ✅ | 누락 품목 없음 (생성 불필요) |

### 4.2 Phase 2: BOM 템플릿 정의

| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 2.1 | SCREEN 완제품용 BOM 템플릿 정의 | ✅ | FG-SCR-001 (14개 항목) |
| 2.2 | STEEL 완제품용 BOM 템플릿 정의 | ✅ | FG-STL-001 (12개 항목) |
| 2.3 | BENDING 완제품용 BOM 템플릿 정의 | ✅ | FG-BND-001 (6개 항목) |

### 4.3 Phase 3: 마이그레이션 스크립트 작성

| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 3.1 | Migrate5130Bom 커맨드 생성 | ✅ | `api/app/Console/Commands/Migrate5130Bom.php` |
| 3.2 | 완제품-템플릿 매핑 로직 구현 | ✅ | item_category 기반 매핑 |
| 3.3 | items.bom 컬럼 업데이트 로직 구현 | ✅ | DB::table 직접 업데이트 |
| 3.4 | 검증 로직 구현 | ✅ | dry-run, verbose 옵션 지원 |

### 4.4 Phase 4: 검증 및 테스트

| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 4.1 | Migrate5130Bom 커맨드 실행 | ✅ | 61건 처리 완료 |
| 4.2 | 견적 페이지에서 실제 테스트 | ⏳ | 사용자 수동 확인 필요 |
| 4.3 | 결과 문서화 | ✅ | 본 문서 업데이트 |

---

## 5. 기술 상세

### 5.1 FormulaEvaluatorService BOM 처리 로직

```php
// api/app/Services/Quote/FormulaEvaluatorService.php

// BOM JSON 필드 사용 위치:
// 1. getBomItems() - bom JSON 파싱
// 2. calculateBomQuantity() - quantityFormula 평가
// 3. childItemCode로 하위 품목 조회

// 주요 변수:
// - W0, H0: 개구부 치수 (입력값)
// - W1, H1: 제작 치수 (계산값)
// - W, H: W1, H1과 동일
// - M: 면적 (m²)
// - K: 중량 (kg)
```

### 5.2 마이그레이션 스크립트 구조

```php
// api/app/Console/Commands/Migrate5130Bom.php

class Migrate5130Bom extends Command
{
    protected $signature = 'migration:migrate-5130-bom
                            {--dry-run : 실제 변경 없이 시뮬레이션}
                            {--code= : 특정 품목 코드만 처리}';

    // 1. item_category별 BOM 템플릿 정의
    private array $bomTemplates = [
        'SCREEN' => [...],
        'STEEL' => [...],
        'BENDING' => [...]
    ];

    // 2. 완제품 조회 (5130 마이그레이션된 FG)
    // 3. 템플릿 기반 BOM JSON 생성
    // 4. items.bom 컬럼 업데이트
}
```

### 5.3 검증 쿼리

```sql
-- 마이그레이션 전: BOM이 NULL인 완제품
SELECT code, name, item_category
FROM items
WHERE item_type = 'FG'
  AND item_category IN ('SCREEN', 'STEEL', 'BENDING')
  AND (bom IS NULL OR bom = '[]');

-- 마이그레이션 후: BOM이 있는 완제품
SELECT code, name, item_category, JSON_LENGTH(bom) as bom_count
FROM items
WHERE item_type = 'FG'
  AND item_category IN ('SCREEN', 'STEEL', 'BENDING')
  AND bom IS NOT NULL
  AND JSON_LENGTH(bom) > 0;
```

---

## 6. 컨펌 대기 목록

> 모든 승인 항목 완료

| # | 항목 | 변경 내용 | 영향 범위 | 상태 |
|---|------|----------|----------|------|
| 1 | BOM 템플릿 확정 | SCREEN/STEEL/BENDING별 템플릿 | 견적 계산 | ✅ 완료 |
| 2 | 하위 품목 코드 확정 | childItemCode 명명 규칙 | items 테이블 | ✅ 완료 |
| 3 | 마이그레이션 실행 | items.bom 업데이트 | 완제품 61건 | ✅ 완료 |

---

## 7. 변경 이력

| 날짜 | 항목 | 변경 내용 | 파일 | 승인 |
|------|------|----------|------|------|
| 2025-01-20 | 초안 | 계획 문서 작성 | - | - |
| 2025-01-20 | 분석 | 5130/SAM BOM 구조 분석 완료 | - | - |
| 2025-01-20 | 스크립트 | Migrate5130Bom 커맨드 생성 | `api/app/Console/Commands/Migrate5130Bom.php` | ✅ |
| 2025-01-20 | 실행 | BOM 마이그레이션 실행 (61건) | items.bom 컬럼 | ✅ |
| 2025-01-20 | 문서화 | 결과 문서화 완료 | 본 문서 | ✅ |

---

## 8. 참고 문서

- **FormulaEvaluatorService**: `api/app/Services/Quote/FormulaEvaluatorService.php`
- **기존 마이그레이션**: `api/app/Console/Commands/Migrate5130PriceItems.php`
- **검증 커맨드**: `api/app/Console/Commands/Verify5130Calculation.php`
- **품질 체크리스트**: `docs/standards/quality-checklist.md`

---

## 9. 세션 및 메모리 관리 정책 (Serena Optimized)

### 9.1 세션 시작 시 (Load Strategy)
```javascript
// 순차적 로드
read_memory("5130-bom-migration-state")     // 1. 상태 파악
read_memory("5130-bom-migration-rules")     // 2. 규칙 확인
read_memory("5130-bom-migration-mappings")  // 3. 매핑 확인
```

### 9.2 Serena 메모리 구조
- `5130-bom-migration-state`: { phase, progress, next_step, last_decision }
- `5130-bom-migration-rules`: BOM 템플릿 정의, 변환 규칙
- `5130-bom-migration-mappings`: 완제품-모델 매핑 테이블

---

## 10. 검증 결과

> 2025-01-20 마이그레이션 실행 완료

### 10.1 마이그레이션 실행 결과

```
📊 카테고리별 BOM 적용 현황 (tenant_id=287):
  SCREEN: 35건
  STEEL: 11건
  BENDING: 15건

✅ BOM 적용 완료: 61건
⏳ BOM 미적용: 0건
```

### 10.2 테스트 케이스

| 입력값 | 예상 결과 | 실제 결과 | 상태 |
|--------|----------|----------|------|
| S0001 BOM JSON 확인 | childItemCode 5개 이상 | 14개 항목 적용됨 | ✅ |
| S0001 + W0=2500, H0=2000 | 견적 금액 > 0 | 사용자 확인 필요 | ⏳ |

### 10.3 성공 기준 달성 현황

| 기준 | 달성 | 비고 |
|------|------|------|
| 완제품 BOM NULL → JSON 변환 | ✅ | 61건 변환 완료 |
| BOM JSON 형식 호환 | ✅ | FormulaEvaluatorService 호환 형식 |
| 견적 계산 정상 동작 | ⏳ | 사용자 수동 확인 필요 |

### 10.4 BOM 템플릿 상세

| 카테고리 | 소스 템플릿 | BOM 항목 수 | 적용 완제품 수 |
|----------|------------|------------|--------------|
| SCREEN | FG-SCR-001 | 14개 | 35건 |
| STEEL | FG-STL-001 | 12개 | 11건 |
| BENDING | FG-BND-001 | 6개 | 15건 |

---

## 11. 자기완결성 점검 결과

> Phase 5.5에서 수행된 자기완결성 점검 결과

### 11.1 체크리스트 검증

| # | 검증 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 1 | 작업 목적이 명확한가? | ✅ | S0001 등 BOM NULL → 견적 0원 문제 해결 |
| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 10.2 참조 |
| 3 | 작업 범위가 구체적인가? | ✅ | SCREEN/STEEL/BENDING 완제품 대상 |
| 4 | 의존성이 명시되어 있는가? | ✅ | FormulaEvaluatorService, 하위 품목 |
| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 8 참조 |
| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 4 참조 |
| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 10.1 참조 |
| 8 | 모호한 표현이 없는가? | ✅ | 구체적 수치/조건 명시 |

### 11.2 새 세션 시뮬레이션 테스트

| 질문 | 답변 가능 | 참조 섹션 |
|------|:--------:|----------|
| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 |
| Q2. 어디서부터 시작해야 하는가? | ✅ | 4. 작업 절차 |
| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 5.2 마이그레이션 스크립트 |
| Q4. 작업 완료 확인 방법은? | ✅ | 10. 검증 결과 |
| Q5. 막혔을 때 참고 문서는? | ✅ | 8. 참고 문서 |

**결과**: 5/5 통과 → ✅ 자기완결성 확보

---

*이 문서는 /plan 스킬로 생성되었습니다.*