Files
sam-docs/plans/archive/5130-bom-migration-plan.md
권혁성 28b69e5449 docs: archive 37개 + COMPLETED 3개 복원 - 향후 docs/ 정식 문서화 시 참조용
- 완료 문서의 상세 내용은 추후 docs/ 구조화 시 정식 문서에 반영 예정
- HISTORY.md는 요약 인덱스로 유지, 개별 파일은 상세 참조용 보관

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 22:32:20 +09:00

17 KiB

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 구조

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

SAM BOM JSON 형식 (FormulaEvaluatorService 호환):

[
  {
    "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):

[
  {"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'):

-- 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 템플릿:

[
  {"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 처리 로직

// 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 마이그레이션 스크립트 구조

// 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 검증 쿼리

-- 마이그레이션 전: 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)

// 순차적 로드
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 스킬로 생성되었습니다.