docs: [bom] BOM V2 범용 멀티테넌트 아키텍처 설계 문서 추가

- V1 한계점 진단 (3중 병렬, 버전 없음, 업종 종속)
- V2 관계형 BOM 구조 설계 (bom_headers, bom_lines, bom_substitutes)
- 10종 품목유형 확장 (SA, WIP, PH, BP, SV 추가)
- 버전/팬텀/대체품목/공정연동/유효기간 설계
- 업종별 프리셋 (블라인드, 전자, 식품, 가구, 단순조립)
- 4단계 마이그레이션 로드맵
- INDEX.md 등록
This commit is contained in:
김보곤
2026-03-22 19:49:36 +09:00
parent 4b465146de
commit 50f498c87d
2 changed files with 826 additions and 0 deletions

View File

@@ -20,6 +20,7 @@
| Blade+React | `dev/standards/blade-react-policy.md` | Blade JSX 이중 중괄호 충돌 방지 |
| 이메일 연동 | `dev/guides/tenant-email-integration-guide.md` | 테넌트 메일 연동, SMTP 프리셋, MNG 관리 |
| 품목관리 | `rules/item-policy.md` | 품목 정책 |
| BOM V2 설계 | `plans/bom-v2-universal-architecture-plan.md` | 범용 멀티테넌트 BOM V2 아키텍처 |
| 단가관리 | `rules/pricing-policy.md` | 6 Depth 단가 체계, 흐름도, 계산공식, 버전관리 개선방향 |
| 단가 버전관리 기획 | `dev/dev_plans/price-version-management-plan.md` | 단가 버전 그룹, 일괄변경, 영향분석, 적용 워크플로우 |
| 견적관리 | `features/quotes/README.md` | 견적 시스템, BOM 계산 |
@@ -375,6 +376,7 @@ DB 도메인별:
| [bom-tree-3level-react-request.md](plans/bom-tree-3level-react-request.md) | BOM 트리 3단계 그룹 표시 React 구현 요청 (API 완료, 카테고리 접힘/펼침) |
| [item-list-search-state-preservation.md](plans/item-list-search-state-preservation.md) | 품목관리 검색 상태 보존 UX 개선 요청 (router.back + URL searchParams 동기화) |
| [optimal-stock-management-plan.md](plans/optimal-stock-management-plan.md) | 적정재고 관리 기능 기획 (안전재고+최대재고 범위 기반, 상태 확장) |
| [bom-v2-universal-architecture-plan.md](plans/bom-v2-universal-architecture-plan.md) | BOM V2 범용 멀티테넌트 아키텍처 설계 (V1 한계 분석, 관계형 BOM, 버전/팬텀/대체/공정 연동) |
### frontend/integration/ — 프론트엔드 개발 가이드

View File

@@ -0,0 +1,824 @@
# BOM V2 범용 멀티테넌트 아키텍처 설계
> **작성일**: 2026-03-22
> **상태**: 설계 중
> **담당**: R&D실
> **목표**: 어떤 업종/회사도 수용 가능한 확장형 BOM 시스템
---
## 1. V1 현황 진단
### 1.1 현재 구조 (3중 병렬)
```
V1 BOM 시스템
├── Product BOM (product_components) ← 레거시, 폐기 진행 중
├── Design BOM (bom_templates) ← 수식 산출용 (활성)
└── Item BOM (items.bom JSON) ← 현재 표준
```
| 시스템 | 저장 방식 | 계층 | 버전 | 상태 |
|--------|---------|:----:|:----:|------|
| Product BOM | 관계형 (product_components) | N-Level | 없음 | 폐기 중 |
| Design BOM | 관계형 (bom_template_items) | 1-Level | 모델 버전 | 수식 전용 |
| Item BOM | JSON (items.bom) | 1-Level* | 없음 | **표준** |
> *Item BOM은 저장이 1-Level이지만, 자식의 BOM을 재귀 탐색하여 트리를 구성한다.
### 1.2 V1 한계점
| 분류 | 한계 | 영향 |
|------|------|------|
| **구조** | BOM이 JSON 평탄 저장 → 다단계 재귀 탐색 필요 | 성능 저하, 순환 참조 위험 |
| **구조** | 3개 BOM 시스템 병렬 → 데이터 일관성 유지 어려움 | 유지보수 비용 |
| **버전** | BOM 버전/리비전 없음 (덮어쓰기) | 변경 이력 추적 불가 |
| **유형** | item_type 5종 고정 (FG/PT/SM/RM/CS) | 반제품(WIP), 팬텀 등 미지원 |
| **수식** | 산출 수식이 경동기업 제품에 하드코딩 | 다른 업종 적용 불가 |
| **공정** | BOM-공정(Routing) 연동 없음 | 공정별 자재 투입 관리 불가 |
| **대체** | 대체품목(Substitute) 미지원 | 자재 부족 시 대응 불가 |
| **유효** | BOM 유효기간(Effectivity) 없음 | 설계 변경 시점 관리 불가 |
| **수율** | 수율/로스율이 Design BOM에만 존재 | Item BOM에서 로스 관리 불가 |
| **원가** | BOM 기반 원가 계산 구조 없음 | 표준원가 산출 불가 |
| **승인** | BOM 승인 워크플로우 없음 | 무검증 BOM 변경 가능 |
| **비교** | BOM 간 diff/비교 기능 제한적 | 설계 변경 영향 분석 어려움 |
### 1.3 V1에서 유지할 것
| 항목 | 이유 |
|------|------|
| `items` 통합 테이블 | Products+Materials 단일화 완료, 역행 불필요 |
| `tenant_id` + `BelongsToTenant` | 멀티테넌시 기반 확립 |
| `options` JSON 정책 | 확장성 확보 |
| `BomTemplate` 수식 엔진 | 파라미터 기반 산출 유지 |
| Category 계층 분류 | 기존 카테고리 시스템 활용 |
---
## 2. V2 설계 원칙
### 2.1 핵심 원칙
```
P1. 모든 업종 수용 — 이산/공정/조립/혼합 제조 전부 지원
P2. 테넌트별 자율 — BOM 깊이, 유형, 수식을 테넌트가 정의
P3. 단일 BOM 엔진 — 3중 병렬 → 1개 통합 BOM 테이블
P4. 버전 필수 — 모든 BOM 변경은 리비전으로 관리
P5. 하위 호환 — V1 JSON BOM 데이터 무손실 마이그레이션
```
### 2.2 지원 대상 업종
| 업종 | BOM 특성 | V2 대응 |
|------|---------|---------|
| **블라인드/스크린** (현재) | 수식 기반, 가변 사이즈 | 수식 엔진 유지 |
| **기계 부품** | 다단계 조립, 가공 공정 | N-Level + Routing |
| **전자/반도체** | 대체품목, ECN 관리 | Substitute + Effectivity |
| **식품/화학** | 배합비, 수율, 부산물 | Formula BOM + Co-product |
| **건설/플랜트** | 프로젝트별 BOM, 대량 자재 | Project BOM + Bulk |
| **가구/인테리어** | 옵션 조합, 커스텀 | Configurable BOM |
| **의류/섬유** | 사이즈별 BOM, 색상별 원단 | Variant BOM |
---
## 3. V2 데이터 모델
### 3.1 핵심 테이블 설계
```
V2 BOM 테이블 구조
items (기존 유지 + 확장)
├── item_type 확장: FG, SA, PT, WIP, PH, SM, RM, CS, BP, SV
└── bom 컬럼: 제거 (관계형으로 이관)
bom_headers (신규 — BOM 헤더/버전)
├── item_id → items
├── revision (REV.01, REV.02 ...)
├── status (DRAFT → PENDING → APPROVED → ACTIVE → OBSOLETE)
├── effective_from / effective_to
└── bom_type (STANDARD | ENGINEERING | CONFIGURABLE | FORMULA)
bom_lines (신규 — BOM 라인/구성품)
├── bom_header_id → bom_headers
├── child_item_id → items
├── quantity + quantity_formula
├── waste_rate (로스율)
├── operation_id → operations (공정 연결)
├── effective_from / effective_to (라인별 유효기간)
└── options JSON (확장 속성)
bom_substitutes (신규 — 대체품목)
├── bom_line_id → bom_lines
├── substitute_item_id → items
├── priority (대체 우선순위)
└── conversion_factor (환산 계수)
operations (신규 — 공정/라우팅)
├── item_id → items
├── sequence (공정 순서)
├── process_id → processes (공정 마스터)
├── setup_time, run_time, wait_time
└── work_center_id (작업장)
```
### 3.2 ERD 관계
```
items ─────────────────────────────────────────────────
│ (1:N) │
▼ │
bom_headers ────────────────────────── │
│ (1:N) │ │
▼ │ │
bom_lines ─── (N:1) ──→ items ◄─────┘ │
│ (1:N) │ │
▼ │ (N:1) │
bom_substitutes ▼ │
operations ─── (N:1) ──→ processes │
│ │
└── (N:1) ──→ work_centers │
bom_templates (기존 유지) │
└── 수식 산출 → bom_headers 자동 생성 ───────────────┘
```
### 3.3 items.item_type 확장
| 코드 | 한글 | 설명 | V1 | V2 |
|------|------|------|:--:|:--:|
| `FG` | 완제품 | 판매 가능한 최종 제품 | O | O |
| `SA` | 반조립품 | 중간 조립품 (재고 관리됨) | - | **신규** |
| `PT` | 부품 | 구성 부품 | O | O |
| `WIP` | 재공품 | 가공 중인 중간 산출물 | - | **신규** |
| `PH` | 팬텀 | 가상 그룹 (재고 없음, BOM 전개 시 투과) | - | **신규** |
| `SM` | 부자재 | 보조 자재 | O | O |
| `RM` | 원자재 | 주요 원료 | O | O |
| `CS` | 소모품 | 일회성 소모 자재 | O | O |
| `BP` | 부산물 | 생산 시 발생하는 부산물 | - | **신규** |
| `SV` | 서비스 | 외주 가공, 검사비 등 비물리 항목 | - | **신규** |
> 테넌트별로 사용할 유형을 선택할 수 있다. 블라인드 업체는 FG/PT/SM/RM/CS만, 전자업체는 SA/PH까지 활성화.
### 3.4 bom_headers 상세
```sql
CREATE TABLE bom_headers (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT UNSIGNED NOT NULL,
item_id BIGINT UNSIGNED NOT NULL, -- 부모 품목
revision VARCHAR(20) NOT NULL DEFAULT 'REV.01',
bom_type VARCHAR(20) NOT NULL DEFAULT 'STANDARD',
-- STANDARD: 일반 BOM
-- ENGINEERING: 설계용 (비생산)
-- CONFIGURABLE: 옵션 조합 BOM
-- FORMULA: 배합/수식 BOM
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
-- DRAFT → PENDING → APPROVED → ACTIVE → OBSOLETE
effective_from DATE NULL, -- 유효 시작
effective_to DATE NULL, -- 유효 종료
base_qty DECIMAL(18,6) NOT NULL DEFAULT 1, -- 기준 수량
base_unit VARCHAR(20) NULL, -- 기준 단위
description TEXT NULL,
approved_by BIGINT UNSIGNED NULL, -- 승인자
approved_at DATETIME NULL,
source_template_id BIGINT UNSIGNED NULL, -- Design BOM 연결
options JSON NULL, -- 확장 속성
created_by BIGINT UNSIGNED NULL,
updated_by BIGINT UNSIGNED NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
UNIQUE KEY uq_bom_tenant_item_rev (tenant_id, item_id, revision, deleted_at),
INDEX idx_bom_tenant_item (tenant_id, item_id),
INDEX idx_bom_tenant_status (tenant_id, status),
INDEX idx_bom_effective (tenant_id, effective_from, effective_to)
);
```
### 3.5 bom_lines 상세
```sql
CREATE TABLE bom_lines (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT UNSIGNED NOT NULL,
bom_header_id BIGINT UNSIGNED NOT NULL,
child_item_id BIGINT UNSIGNED NOT NULL, -- 자식 품목
quantity DECIMAL(18,6) NOT NULL DEFAULT 1, -- 소요량
quantity_formula VARCHAR(500) NULL, -- 수식 (예: "W1 * H1 / 1000000")
unit VARCHAR(20) NULL,
waste_rate DECIMAL(9,6) NOT NULL DEFAULT 0, -- 로스율 (0.05 = 5%)
category VARCHAR(100) NULL, -- 카테고리 그룹명
operation_id BIGINT UNSIGNED NULL, -- 공정 연결
effective_from DATE NULL, -- 라인별 유효 시작
effective_to DATE NULL, -- 라인별 유효 종료
is_phantom TINYINT(1) NOT NULL DEFAULT 0, -- 팬텀 여부 (BOM 전개 시 투과)
supply_type VARCHAR(20) DEFAULT 'STOCK', -- STOCK | PURCHASE | SUBCONTRACT
sort_order INT NOT NULL DEFAULT 0,
notes VARCHAR(500) NULL,
options JSON NULL, -- 확장 속성
created_by BIGINT UNSIGNED NULL,
updated_by BIGINT UNSIGNED NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
INDEX idx_bl_tenant_header (tenant_id, bom_header_id),
INDEX idx_bl_child (child_item_id),
INDEX idx_bl_operation (operation_id),
INDEX idx_bl_effective (effective_from, effective_to)
);
```
### 3.6 bom_substitutes 상세
```sql
CREATE TABLE bom_substitutes (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT UNSIGNED NOT NULL,
bom_line_id BIGINT UNSIGNED NOT NULL,
substitute_item_id BIGINT UNSIGNED NOT NULL, -- 대체 품목
priority INT NOT NULL DEFAULT 1, -- 대체 우선순위 (1=최우선)
conversion_factor DECIMAL(12,6) NOT NULL DEFAULT 1, -- 환산 계수
effective_from DATE NULL,
effective_to DATE NULL,
notes VARCHAR(255) NULL,
options JSON NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
INDEX idx_bs_tenant_line (tenant_id, bom_line_id),
UNIQUE KEY uq_bs_line_sub (bom_line_id, substitute_item_id)
);
```
---
## 4. BOM 유형별 동작
### 4.1 STANDARD BOM (표준 BOM)
가장 일반적인 형태. 고정 수량 기반.
```
FG-001 (스크린 제품) [REV.02, ACTIVE, 2026-01-01~]
├── [주자재] RM-001 스크린 원단 x10.65 m² (로스 5%)
├── [모터] PT-001 모터 150K x1 EA
├── [제어기] PT-002 제어기 노출형 x1 EA
├── [절곡품] WIP-001 케이스 500*380 x3.22 m → 공정: 절곡
├── [절곡품] WIP-002 마구리 505*385 x1 EA → 공정: 절곡
├── [부자재] SM-001 감기샤프트 x1 EA
├── [검사비] SV-001 검사비 x1 EA
└── [대체] PT-001 → PT-001-B 모터 200K (priority=1, factor=1.0)
```
### 4.2 FORMULA BOM (수식 BOM)
파라미터 입력 → 수식 평가 → 수량 자동 계산. 기존 Design BOM의 발전형.
```
FG-KSS02 (스크린 SUS 측면형) [FORMULA]
├── 파라미터: W0=3000, H0=3000, QTY=1, MP=single
├── 변수계산: W1=W0+140, H1=H0+350, M=W1*H1/1e6, K=M*2+(W0/1000)*14.17
├── RM-슬랫 qty_formula="M" → 10.65 m²
├── PT-모터 qty_formula="1" → 1 EA
├── WIP-케이스 qty_formula="W1/1000" → 3.14 m
├── SM-샤프트 qty_formula="CEIL(H1/2000)" → 2 EA
└── SV-검사 qty_formula="1" → 1 EA
```
> 수식 평가 후 결과를 STANDARD BOM으로 스냅샷 저장 가능 (V1의 "BOM 저장" 기능 유지).
### 4.3 CONFIGURABLE BOM (구성형 BOM)
옵션 조합에 따라 구성이 달라지는 BOM. 가구/의류/맞춤 제품에 적합.
```
FG-DESK (사무용 책상) [CONFIGURABLE]
├── [공통] PT-프레임 x1 EA — 항상 포함
├── [공통] SM-나사세트 x1 SET — 항상 포함
├── [옵션: 상판 재질]
│ ├── 원목 → RM-원목상판 x1 EA
│ ├── MDF → RM-MDF상판 x1 EA
│ └── 유리 → RM-유리상판 x1 EA + SM-흡착패드 x4 EA
└── [옵션: 다리 높이]
├── 표준(720mm) → PT-다리-720 x4 EA
└── 높은(900mm) → PT-다리-900 x4 EA
```
### 4.4 ENGINEERING BOM (설계 BOM)
생산 투입 전 설계 단계 BOM. 승인 후 STANDARD로 전환.
```
ENGINEERING BOM (설계팀)
│ 검토 → 승인
STANDARD BOM (생산팀)
│ ECN (설계 변경)
새 REVISION 생성 (REV.02)
```
---
## 5. BOM 버전 관리
### 5.1 리비전 워크플로우
```
REV.01 (DRAFT)
│ 편집 완료
REV.01 (PENDING) ← 승인 요청
│ 승인자 확인
REV.01 (APPROVED) ← 승인 완료
│ 유효기간 도래
REV.01 (ACTIVE) ← 생산에 사용
│ 설계 변경 발생
REV.01 (OBSOLETE) ← 비활성화
REV.02 (DRAFT) 생성 ← 새 리비전
```
### 5.2 유효기간 관리
```
REV.01 ────────[2025-01-01 ~ 2026-06-30]────────
REV.02 [2026-07-01 ~ ]──────────────
설계 변경 적용일
```
- 특정 날짜에 유효한 BOM 조회: `WHERE effective_from <= ? AND (effective_to IS NULL OR effective_to >= ?)`
- 라인별 유효기간: 부품 단종/교체 시 개별 라인 종료
### 5.3 BOM 비교 (Diff)
```json
{
"comparison": "REV.01 vs REV.02",
"added": [
{ "item": "PT-003 신규부품", "qty": 2 }
],
"removed": [
{ "item": "PT-002 구부품", "qty": 1 }
],
"changed": [
{ "item": "RM-001 원단", "qty_before": 10.0, "qty_after": 10.65, "reason": "로스율 반영" }
]
}
```
---
## 6. 팬텀(Phantom) 품목
### 6.1 개념
팬텀 품목은 **재고로 관리하지 않는 가상 그룹**이다. BOM 전개(Explosion) 시 팬텀은 "투과"되어 하위 구성품이 직접 상위로 올라간다.
### 6.2 V1 → V2 매핑
V1의 `item_type: CAT` (카테고리 그룹)가 V2의 팬텀에 해당한다.
```
V1 (가상 CAT 노드):
FG-001
├── [CAT] 주자재 (가상 — DB에 없음, 코드로 생성)
│ └── RM-001 스크린 원단
└── [CAT] 모터 (가상)
└── PT-001 모터
V2 (팬텀 품목):
FG-001
├── PH-주자재 (팬텀 — items 테이블에 실체 있음)
│ └── RM-001 스크린 원단
└── PH-모터 (팬텀)
└── PT-001 모터
BOM 전개 결과 (MRP):
FG-001 → RM-001, PT-001 (팬텀 투과)
```
### 6.3 팬텀 활용
| 용도 | 설명 |
|------|------|
| **그룹화** | V1의 카테고리 그룹을 구조화 |
| **중간조립 생략** | 재고 불필요한 중간 단계 |
| **공통 부품군** | 여러 FG에서 공유하는 부품 묶음 |
---
## 7. 공정-BOM 연동 (Routing)
### 7.1 공정 마스터
```sql
CREATE TABLE processes (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT UNSIGNED NOT NULL,
code VARCHAR(50) NOT NULL,
name VARCHAR(255) NOT NULL,
type VARCHAR(50) NULL, -- FABRICATION | ASSEMBLY | INSPECTION | SUBCONTRACT
options JSON NULL,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
UNIQUE KEY uq_process_tenant_code (tenant_id, code, deleted_at)
);
```
### 7.2 공정 라우팅
```sql
CREATE TABLE operations (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT UNSIGNED NOT NULL,
item_id BIGINT UNSIGNED NOT NULL, -- 대상 품목
bom_header_id BIGINT UNSIGNED NULL, -- BOM과 연결 (선택)
sequence INT NOT NULL, -- 공정 순서 (10, 20, 30...)
process_id BIGINT UNSIGNED NOT NULL, -- 공정 마스터
work_center_id BIGINT UNSIGNED NULL, -- 작업장/설비
setup_time DECIMAL(10,2) DEFAULT 0, -- 준비 시간 (분)
run_time DECIMAL(10,2) DEFAULT 0, -- 가동 시간 (분/단위)
wait_time DECIMAL(10,2) DEFAULT 0, -- 대기 시간 (분)
description VARCHAR(500) NULL,
options JSON NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
INDEX idx_op_tenant_item (tenant_id, item_id),
INDEX idx_op_sequence (item_id, sequence)
);
```
### 7.3 공정별 자재 투입
```
FG-001 스크린 제품
공정 10: 원단 재단 → RM-001 원단 (이 공정에서 투입)
공정 20: 절곡 가공 → WIP-001 케이스, WIP-002 마구리
공정 30: 조립 → PT-001 모터, PT-002 제어기, SM-001 샤프트
공정 40: 검사 → SV-001 검사비
공정 50: 포장 → SM-002 포장재
```
`bom_lines.operation_id`로 각 자재가 어느 공정에서 투입되는지 연결한다.
---
## 8. 테넌트별 BOM 설정
### 8.1 테넌트 BOM 설정 (tenant_bom_settings)
```sql
CREATE TABLE tenant_bom_settings (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT UNSIGNED NOT NULL UNIQUE,
-- 활성화할 품목 유형
enabled_item_types JSON NOT NULL DEFAULT '["FG","PT","SM","RM","CS"]',
-- 활성화할 BOM 유형
enabled_bom_types JSON NOT NULL DEFAULT '["STANDARD"]',
-- BOM 최대 깊이
max_bom_depth INT NOT NULL DEFAULT 10,
-- 승인 워크플로우 사용 여부
require_approval BOOLEAN NOT NULL DEFAULT FALSE,
-- 유효기간 관리 사용 여부
use_effectivity BOOLEAN NOT NULL DEFAULT FALSE,
-- 대체품목 사용 여부
use_substitutes BOOLEAN NOT NULL DEFAULT FALSE,
-- 공정(Routing) 연동 여부
use_routing BOOLEAN NOT NULL DEFAULT FALSE,
-- 로스율 관리 여부
use_waste_rate BOOLEAN NOT NULL DEFAULT FALSE,
-- 팬텀 품목 사용 여부
use_phantom BOOLEAN NOT NULL DEFAULT FALSE,
-- 수식 BOM 사용 여부
use_formula_bom BOOLEAN NOT NULL DEFAULT FALSE,
-- 카테고리 그룹 표시 방식
category_display VARCHAR(20) DEFAULT 'FOLDER', -- FOLDER | FLAT | NONE
-- 커스텀 BOM 라인 필드 (테넌트별 확장)
custom_line_fields JSON NULL,
options JSON NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL
);
```
### 8.2 업종별 프리셋
```json
{
"presets": {
"blind_screen": {
"label": "블라인드/스크린 제조",
"enabled_item_types": ["FG", "PT", "WIP", "SM", "RM", "CS", "SV"],
"enabled_bom_types": ["STANDARD", "FORMULA"],
"max_bom_depth": 5,
"use_formula_bom": true,
"use_waste_rate": true,
"use_routing": true,
"category_display": "FOLDER"
},
"electronics": {
"label": "전자/반도체",
"enabled_item_types": ["FG", "SA", "PT", "PH", "SM", "RM", "CS"],
"enabled_bom_types": ["STANDARD", "ENGINEERING"],
"max_bom_depth": 15,
"require_approval": true,
"use_effectivity": true,
"use_substitutes": true,
"use_phantom": true
},
"food_chemical": {
"label": "식품/화학",
"enabled_item_types": ["FG", "PT", "RM", "CS", "BP"],
"enabled_bom_types": ["STANDARD", "FORMULA"],
"use_formula_bom": true,
"use_waste_rate": true,
"category_display": "FLAT"
},
"furniture": {
"label": "가구/인테리어",
"enabled_item_types": ["FG", "SA", "PT", "SM", "RM"],
"enabled_bom_types": ["STANDARD", "CONFIGURABLE"],
"max_bom_depth": 5
},
"simple_assembly": {
"label": "단순 조립",
"enabled_item_types": ["FG", "PT", "SM", "RM", "CS"],
"enabled_bom_types": ["STANDARD"],
"max_bom_depth": 3,
"category_display": "FLAT"
}
}
}
```
---
## 9. API 설계
### 9.1 엔드포인트 구조
```
/api/v2/items/{itemId}/bom/
├── GET / BOM 헤더 목록 (리비전 이력)
├── POST / BOM 헤더 생성 (새 리비전)
├── GET /{bomId} BOM 상세 (헤더 + 라인)
├── PUT /{bomId} BOM 헤더 수정
├── DELETE /{bomId} BOM 삭제 (DRAFT만)
├── GET /{bomId}/lines BOM 라인 목록
├── POST /{bomId}/lines 라인 추가
├── PUT /{bomId}/lines/bulk 라인 일괄 업서트
├── PUT /{bomId}/lines/{id} 라인 수정
├── DELETE /{bomId}/lines/{id} 라인 삭제
├── GET /{bomId}/tree BOM 트리 (재귀, 팬텀 투과 옵션)
├── GET /{bomId}/flat BOM 전개 (Explosion, 평탄화)
├── GET /{bomId}/where-used 역전개 (이 품목을 사용하는 BOM)
├── POST /{bomId}/approve 승인 요청
├── POST /{bomId}/activate 활성화
├── POST /{bomId}/obsolete 비활성화
├── POST /{bomId}/clone 복제 (새 리비전)
├── GET /{bomId}/diff/{otherId} BOM 비교
├── GET /{bomId}/substitutes 대체품목 목록
├── POST /{bomId}/lines/{id}/substitutes 대체품목 추가
└── POST /{bomId}/calculate 수식 BOM 계산 (FORMULA 타입)
/api/v2/bom/
├── GET /settings 테넌트 BOM 설정 조회
├── PUT /settings 테넌트 BOM 설정 변경
├── GET /search BOM 검색 (품목코드, 구성품 등)
└── POST /mass-replace 품목 일괄 대체 (ECN)
```
### 9.2 BOM 트리 응답 (V2)
```json
{
"bom_header": {
"id": 1,
"item_id": 100,
"revision": "REV.02",
"status": "ACTIVE",
"bom_type": "STANDARD",
"effective_from": "2026-07-01",
"base_qty": 1
},
"tree": {
"id": 100,
"code": "FG-KSS02",
"name": "KSS02 스크린 SUS 측면형",
"item_type": "FG",
"depth": 0,
"children": [
{
"bom_line_id": 10,
"id": 0,
"name": "주자재",
"item_type": "PH",
"is_phantom": true,
"depth": 1,
"children": [
{
"bom_line_id": 11,
"id": 201,
"code": "RM-슬랫-방화",
"name": "스크린 실리카",
"item_type": "RM",
"quantity": 10.65,
"unit": "m²",
"waste_rate": 0.05,
"effective_quantity": 11.18,
"operation": { "sequence": 10, "name": "원단 재단" },
"substitutes": [
{ "item_code": "RM-슬랫-일반", "priority": 1, "factor": 1.0 }
],
"depth": 2,
"children": []
}
]
}
]
},
"summary": {
"total_items": 17,
"total_groups": 6,
"max_depth": 3,
"has_substitutes": true,
"has_formulas": false
}
}
```
---
## 10. V1 → V2 마이그레이션
### 10.1 마이그레이션 전략
```
Phase 1: 테이블 생성 (V2 테이블 추가, V1 유지)
Phase 2: 데이터 이관 (items.bom JSON → bom_headers + bom_lines)
Phase 3: API 전환 (V1 API 유지 + V2 API 추가)
Phase 4: 프론트엔드 전환 (MNG/React V2 UI)
Phase 5: V1 폐기 (items.bom 컬럼 제거, V1 API 제거)
```
### 10.2 데이터 이관 스크립트
```php
// items.bom JSON → bom_headers + bom_lines 변환
foreach (Item::whereNotNull('bom')->cursor() as $item) {
$header = BomHeader::create([
'tenant_id' => $item->tenant_id,
'item_id' => $item->id,
'revision' => 'REV.01',
'bom_type' => 'STANDARD',
'status' => 'ACTIVE',
'base_qty' => 1,
]);
foreach ($item->bom as $i => $bomLine) {
BomLine::create([
'tenant_id' => $item->tenant_id,
'bom_header_id' => $header->id,
'child_item_id' => $bomLine['child_item_id'],
'quantity' => $bomLine['quantity'] ?? 1,
'unit' => $bomLine['unit'] ?? null,
'category' => $bomLine['category'] ?? null,
'sort_order' => $i,
]);
}
}
```
### 10.3 하위 호환
| V1 API | V2 대응 | 전환 방식 |
|--------|---------|---------|
| `GET /v1/items/{id}/bom/tree` | `GET /v2/items/{id}/bom/{activeId}/tree` | V1 래퍼 → V2 호출 |
| `POST /v1/items/{id}/save-bom` | `POST /v2/items/{id}/bom` + lines | V1 래퍼 유지 |
| `POST /v1/quotes/calculate/bom` | `POST /v2/items/{id}/bom/{id}/calculate` | V1 래퍼 유지 |
---
## 11. 구현 로드맵
### Phase 1: 기반 구축 (2~3주)
- [ ] `bom_headers`, `bom_lines`, `bom_substitutes` 마이그레이션 생성
- [ ] `tenant_bom_settings` 테이블 및 프리셋
- [ ] `BomHeader`, `BomLine`, `BomSubstitute` 모델 생성
- [ ] `BomService` 핵심 CRUD (생성, 조회, 수정, 삭제)
- [ ] V1 items.bom → V2 데이터 이관 스크립트
- [ ] V2 BOM API 기본 엔드포인트
### Phase 2: 핵심 기능 (2~3주)
- [ ] BOM 트리 빌더 (재귀, 팬텀 투과, 깊이 제한)
- [ ] BOM 전개 (Explosion) — 평탄화 조회
- [ ] 역전개 (Where-Used) — 이 부품을 사용하는 상위 BOM
- [ ] BOM 버전 관리 (리비전 생성, 복제)
- [ ] BOM 비교 (Diff)
- [ ] items.item_type 확장 (SA, WIP, PH, BP, SV)
### Phase 3: 확장 기능 (3~4주)
- [ ] 수식 BOM (FORMULA) — Design BOM 연동 개선
- [ ] 대체품목 관리
- [ ] 유효기간(Effectivity) 관리
- [ ] 공정(Routing) 테이블 및 BOM-공정 연동
- [ ] BOM 승인 워크플로우
- [ ] 원가 계산 연동 (BOM 기반 표준원가)
### Phase 4: UI 및 통합 (2~3주)
- [ ] MNG BOM 관리 UI 전환 (V2 API)
- [ ] React BOM 트리 뷰어 V2 연동
- [ ] 테넌트 BOM 설정 관리 화면
- [ ] V1 API 래퍼 → V2 전환 완료
- [ ] V1 items.bom 컬럼 제거
---
## 12. 업종별 시나리오 검증
### 12.1 블라인드/스크린 (현재)
```
설정: STANDARD + FORMULA, WIP 사용, 카테고리 FOLDER
검증:
✓ 수식 산출 → BOM 자동 생성
✓ 절곡품(WIP) BOM 트리
✓ 카테고리 그룹 표시
✓ V1 데이터 100% 호환
```
### 12.2 전자부품 제조
```
설정: STANDARD + ENGINEERING, SA/PH 사용, 승인 필수, 대체품목, ECN
검증:
✓ 15단계 BOM 깊이
✓ 팬텀 품목 투과 전개
✓ ECN 시 일괄 품목 대체
✓ 리비전별 유효기간 관리
```
### 12.3 식품 제조
```
설정: FORMULA, 수율 관리, 부산물(BP)
검증:
✓ 배합비 수식 (A원료 30% + B원료 70%)
✓ 로스율 반영 투입량
✓ 부산물 자동 등록
```
### 12.4 가구 주문제작
```
설정: CONFIGURABLE, 옵션 조합
검증:
✓ 상판/다리/마감 옵션별 BOM 분기
✓ 주문 시 옵션 선택 → BOM 확정
```
---
## 관련 문서
| 문서 | 경로 |
|------|------|
| 품목 정책 | `rules/item-policy.md` |
| 견적 시스템 | `features/quotes/README.md` |
| 제품/품목/설계 DB | `system/database/products.md` |
| BOM 아이템 매핑 | `dev/dev_plans/bom-item-mapping-plan.md` |
| BOM 트리 3단계 | `changes/20260318_item-management-bom-tree.md` |
| 재공품 생산 정책 | `rules/wip-production-policy.md` |
| options JSON 정책 | `standards/options-column-policy.md` |
---
**최종 업데이트**: 2026-03-22