- 완료 문서의 상세 내용은 추후 docs/ 구조화 시 정식 문서에 반영 예정 - HISTORY.md는 요약 인덱스로 유지, 개별 파일은 상세 참조용 보관 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
17 KiB
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 스킬로 생성되었습니다.