From 925e8f13ffcf08cd93d843269982d72c4f3ade9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Sat, 31 Jan 2026 02:41:29 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=ED=92=88=EB=AA=A9=20=EA=B8=B0=EC=A4=80?= =?UTF-8?q?=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=95=EB=B9=84=20Phase=202?= =?UTF-8?q?=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 분석 + Phase 2 실행 결과를 포함한 계획 문서. DB 변경 사항 (tenant_id=287): - item_fields 4건 생성 (id:177-180, FG attributes 매핑) - item_fields 10건 비활성화 (섀도잉/null key/미연결 정리) - item_fields 9건 options 갱신 (RM/SM/PT 실데이터) - entity_relationships 7건 삭제, 8건 추가 (is_active 통합 + FG 필드 연결) - item_details 18건 생성 (id:524-541, FG 제품 상세) Co-Authored-By: Claude Opus 4.5 --- plans/item-master-data-alignment-plan.md | 831 +++++++++++++++++++++++ 1 file changed, 831 insertions(+) create mode 100644 plans/item-master-data-alignment-plan.md diff --git a/plans/item-master-data-alignment-plan.md b/plans/item-master-data-alignment-plan.md new file mode 100644 index 0000000..f04932d --- /dev/null +++ b/plans/item-master-data-alignment-plan.md @@ -0,0 +1,831 @@ +# 품목 기준 데이터 정비 계획 + +> **작성일**: 2026-01-31 +> **목적**: 5130 레거시 시스템에서 이관된 품목 데이터가 SAM 품목기준관리(item-master-data-management)에서 올바르게 표시되고, 견적 문서에 정확히 반영되도록 설정을 정비한다. +> **기준 문서**: `docs/specs/database-schema.md`, `docs/rules/item-policy.md` +> **상태**: 🔄 진행중 + +--- + +## 📍 현재 진행 상태 + +| 항목 | 내용 | +|------|------| +| **마지막 완료 작업** | Phase 2 전체 완료 (6/6) | +| **다음 작업** | 프론트엔드 표시 검증 | +| **진행률** | Phase 1 완료, Phase 2 완료 (6/6) | +| **마지막 업데이트** | 2026-01-31 | + +--- + +## 1. 개요 + +### 1.1 배경 + +5130 레거시 시스템(chandj DB)의 품목 데이터를 SAM으로 이관 완료하였으나, SAM의 품목기준관리(item-master-data-management) 설정이 이관된 데이터 구조와 맞지 않아 프론트엔드에서 품목 정보가 올바르게 표시되지 않는다. 품목 데이터가 정확히 표시되어야 견적 문서에 데이터를 뿌려줄 수 있다. + +**핵심 문제:** +- `item_pages/item_sections/item_fields`의 현재 필드 정의가 이관된 데이터의 실제 `attributes` JSON 구조와 불일치 +- `item_details` 테이블에 FG 18개 품목의 상세 정보가 없음 (PT 129개만 존재) +- 드롭다운 필드의 `options` 값이 실제 데이터와 매핑되지 않음 +- `setting_field_defs`와 `tenant_field_settings` 테이블이 비어있음 + +### 1.2 기준 원칙 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 🎯 핵심 원칙 │ +├─────────────────────────────────────────────────────────────────┤ +│ 1. 견적 로직(FormulaEvaluatorService)에 영향 없는 범위에서만 수정 │ +│ 2. items.bom JSON 구조, items.code 체계는 변경 금지 │ +│ 3. item_pages/sections/fields 설정만 조정하여 데이터 표시 정합성 확보│ +│ 4. 5130 데이터와 SAM 데이터 간 매핑 관계를 명확히 문서화 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.3 변경 승인 정책 + +| 분류 | 예시 | 승인 | +|------|------|------| +| ✅ 즉시 가능 | item_fields options 값 수정, field_name 변경, 필드 순서 변경 | 불필요 | +| ⚠️ 컨펌 필요 | item_fields 추가/삭제, item_sections 구조 변경, entity_relationships 변경 | **필수** | +| 🔴 금지 | items.bom JSON 구조 변경, items.code 체계 변경, FormulaEvaluatorService 수정 | 별도 협의 | + +### 1.4 준수 규칙 +- `docs/specs/database-schema.md` - DB 스키마 참조 +- `docs/rules/item-policy.md` - 품목 정책 +- `docs/standards/quality-checklist.md` - 품질 체크리스트 + +--- + +## 2. 대상 범위 + +### 2.1 Phase 1: 분석 (4단계) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1.1 | 품목기준관리 구조 파악 | ✅ | 아래 섹션 4.1 참조 | +| 1.2 | 현재 설정 현황 분석 | ✅ | 아래 섹션 4.2 참조 | +| 1.3 | 이관된 제품 데이터 구조 분석 | ✅ | 아래 섹션 4.3 참조 | +| 1.4 | BOM 관계 구조 분석 | ✅ | 아래 섹션 4.4 참조 | + +### 2.2 Phase 2: 설정 수정 (견적 영향 없는 범위) + +| # | 작업 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 2.1 | FG(제품) 필드 설정 정비 | ✅ | 완료: 4개 필드 추가(id:177-180), section 102 연결, order_no 정렬 | +| 2.2 | PT(부품) 필드 설정 정비 | ✅ | 완료: Part_type options 갱신(BD부품 추가, 라벨 간소화). display_condition은 5.6.4로 이관 | +| 2.3 | SM/RM/CS 필드 설정 정비 | ✅ | 완료: RM options 실데이터(SUS/EGI/두께/폭/길이), SM 11개 카테고리, SM규격 빈 배열 | +| 2.4 | FG item_details 데이터 보완 | ✅ | 완료: 18건 INSERT (id:524-541), product_category/item_name/specification 설정 | +| 2.5 | 드롭다운 options 실데이터 매핑 | ✅ | 완료: 2.1~2.3에서 함께 처리 (FG 4개, PT Part_type, RM 5개, SM 3개) | +| 2.6 | 고정컬럼-동적필드 섀도잉 정리 | ✅ | 완료: null key 1건, 미연결 5건 비활성화, is_active 중복 4건 통합 | + +--- + +## 3. 작업 절차 + +### 3.1 단계별 절차 + +``` +Step 1: 구조 분석 (Phase 1.1) +├── item_pages → item_sections → item_fields 계층 구조 파악 +├── entity_relationships 연결 관계 매핑 +└── React 프론트엔드 렌더링 로직 확인 + +Step 2: 현재 설정 현황 (Phase 1.2) +├── 5개 item_pages (CS/RM/SM/PT/FG) 설정 현황 +├── 26개 page→section, 66개 section→field 관계 확인 +└── 각 필드의 options, validation_rules 점검 + +Step 3: 이관 데이터 구조 (Phase 1.3) +├── items 테이블 780건 (FG:18, PT:669, SM:61, RM:28, CS:4) +├── items.attributes JSON 구조 분석 +├── item_details 129건 (PT만 존재) 분석 +└── 5130 원본 데이터와 대조 + +Step 4: BOM 관계 구조 (Phase 1.4) +├── FG→PT BOM JSON 관계 매핑 +├── 5130 models→parts→parts_sub 3계층 대응 +├── BD계열(가이드레일, 하단마감재, L-BAR) 매핑 +└── 견적 FormulaEvaluatorService 의존성 확인 + +Step 5: 설정 수정 (Phase 2) +├── FG 필드: attributes 키와 item_fields 매핑 +├── PT 필드: part_type별 분기 필드 정의 +├── 드롭다운 options: 실제 사용 값으로 갱신 +├── FG item_details 18건 생성 +├── 고정컬럼-동적필드 섀도잉 정리 (is_active 중복 통합, null key, 미연결 필드) +└── 프론트엔드 표시 검증 +``` + +--- + +## 4. 상세 분석 결과 + +### 4.1 Phase 1.1: 품목기준관리 구조 + +#### 아키텍처 개요 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ item_pages (품목유형별 폼 정의) │ +│ - CS/RM/SM/PT/FG 각 1개 페이지 │ +│ - tenant_id=287, group_id=1 │ +├─────────────────────────────────────────────────────────────────┤ +│ entity_relationships (parent_type='page' → child_type='section')│ +│ - 26개 관계 (페이지→섹션) │ +│ - 66개 관계 (섹션→필드) │ +├─────────────────────────────────────────────────────────────────┤ +│ item_sections (섹션) │ +│ - type: 'fields' (일반 필드 그룹) │ +│ - type: 'bom' (BOM 구성 섹션) │ +├─────────────────────────────────────────────────────────────────┤ +│ item_fields (필드 정의) │ +│ - field_type: textbox/number/dropdown/checkbox/date/textarea │ +│ - storage_type: 'column' (items 컬럼) / 'json' (attributes) │ +│ - options: JSON [{label, value}] (드롭다운용) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +#### 테이블 스키마 + +**item_pages**: `id, tenant_id, group_id, page_name, item_type(ENUM), source_table, absolute_path, is_active` + +**item_sections**: `id, tenant_id, group_id, title, type(ENUM: fields/bom), order_no, is_template, is_default, description` + +**item_fields**: `id, tenant_id, group_id, field_name, field_key, field_type(ENUM), order_no, is_required, default_value, placeholder, display_condition(JSON), validation_rules(JSON), options(JSON), properties(JSON), source_table, source_column, storage_type(ENUM: column/json), json_path, category, description, is_common, is_active, is_locked` + +**entity_relationships**: `id, tenant_id, group_id, parent_type, parent_id, child_type, child_id, order_no, metadata(JSON), is_locked` + +--- + +### 4.2 Phase 1.2: 현재 설정 현황 + +#### 4.2.1 페이지별 구조 + +**CS (소모품) - page id:1015** +``` +└ Section: 기본정보 (id:92, type:fields) + ├ 품목명 (key:item_name, textbox) + ├ 규격(사양) (key:specification, textbox) + ├ 단위 (key:unit, dropdown) + └ 비고 (key:note1, textbox) +``` + +**RM (원자재) - page id:1016** +``` +└ Section: 기본 정보 (id:93, type:fields) + ├ 품목명 (key:100_item_name, dropdown) → options: [철판, 알루미늄, 스테인리스, 아연도금강판] + ├ 규격 (key:101_specification_1, dropdown) → options: [옵션1-1, 옵션1-2, 옵션1-3, 옵션120] + ├ 규격 (key:102_specification_2, dropdown) → options: [옵션2-1, 옵션2-2] + ├ 규격 (key:103_specification_3, dropdown) → options: [옵션3-1, 옵션3-2, 옵션3-3] + ├ 규격 (key:104_specification_4, dropdown) + ├ 활성 여부 (key:is_active, dropdown) + ├ 단위 (key:unit, dropdown) + └ 비고 (key:note1, textbox) +``` + +**SM (부자재) - page id:1017** +``` +└ Section: 기본 정보 (id:94, type:fields) + ├ 품목명 (key:107_item_name, dropdown) + ├ 규격 (key:108_specification_1, dropdown) + ├ 규격 (key:109_specification_2, dropdown) + ├ 활성 여부 (key:field_163, dropdown) + ├ 단위 (key:unit, dropdown) + └ 비고 (key:note1, textbox) +``` + +**PT (부품) - page id:1018** +``` +├ Section: 기본 정보 (id:95, type:fields) +│ ├ 부품 유형 (key:Part_type, dropdown) +│ ├ 품목명 (key:itemNameAssemblyPart, dropdown) +│ ├ 설치유형 (key:119~121_Installation_type_1~3, dropdown x3) +│ ├ 마감 (key:112_deadline, dropdown) +│ ├ 품목명 (key:122_bending_parts, dropdown) +│ ├ 종류 (key:123~125_type_1~3, dropdown x3) +│ ├ 재질 (key:126_texture, dropdown) +│ ├ 폭 합계 (key:127_width_total, number) +│ ├ 모양&길이 (key:128_Shape_Length, dropdown) +│ ├ 비고 (key:note2, textbox) +│ ├ 품목명 (key:132_PurchasedItemName, dropdown) +│ ├ 품목상태 (key:138_state, dropdown) +│ ├ 전원 (key:134_power, dropdown) +│ ├ 용량 (key:135_capacity, dropdown) +│ ├ 비고 (key:note3, textbox) +│ ├ 품목상태 (key:, dropdown) ← ⚠️ key 비어있음 +│ └ 단위 (key:unit, dropdown) +├ Section: 측면 규격 및 길이 (id:99, type:fields) +│ ├ 측면 규격 (가로) (key:113_side_dimensions_horizontal, number) +│ ├ 측면 규격 (세로) (key:114_side_dimensions_vertical, number) +│ ├ 길이 (key:115_length, dropdown) +│ ├ 품목 상태 (key:105_state, dropdown) +│ └ 품목상태 (key:133_state, dropdown) +├ Section: BOM (id:100, type:fields) +│ └ 부품구성 (BOM) 필요 (key:118_bom, checkbox) +└ Section: 부품 구성 (BOM) (id:101, type:bom) +``` + +**FG (제품) - page id:1019** +``` +├ Section: 기본 정보 (id:102, type:fields) +│ ├ 상품명 (key:139_productName, textbox) +│ ├ 품목명 (key:140_field_96, textbox) +│ ├ 로트 약자 (key:141_lotNum, textbox) +│ ├ 품목상태 (key:138_state, dropdown) +│ ├ 비고 (key:note3, textbox) +│ ├ 인정번호 (key:142_accreditationNumber, textbox) +│ ├ 인정 유효기간 시작일 (key:143_accreditationStart, date) +│ ├ 인정 유효기간 종료일 (key:144_accreditationEnd, date) +│ └ 비고 (key:145_field_137, textbox) +├ Section: BOM (id:100, type:fields) ← PT와 공유 +│ └ 부품구성 (BOM) 필요 (key:118_bom, checkbox) +└ Section: 부품 구성 (BOM) (id:101, type:bom) ← PT와 공유 +``` + +#### 4.2.2 발견된 문제점 + +| # | 문제 | 영향 | 심각도 | +|---|------|------|--------| +| 1 | FG 필드의 field_key가 이관 데이터의 attributes 키와 불일치 | FG 품목 표시 불가 | 🔴 | +| 2 | PT 필드에 field_key가 빈 필드 존재 | 데이터 매핑 실패 | 🟡 | +| 3 | RM/SM 드롭다운 options가 플레이스홀더 값 (옵션1-1 등) | 실제 데이터와 불일치 | 🟡 | +| 4 | FG item_details 0건 (18개 FG 품목 상세 없음) | 제품 상세 표시 불가 | 🔴 | +| 5 | `setting_field_defs`, `tenant_field_settings` 테이블 비어있음 | 필드 커스터마이징 미설정 | 🟢 | +| 6 | FG attributes에 `model_name`, `finishing_type` 등 레거시 키 사용 | 필드 매핑 필요 | 🟡 | +| 7 | 고정컬럼과 동적필드 간 섀도잉 중복 다수 존재 | 향후 일괄 기능 오작동 위험 | 🔴 | + +#### 4.2.3 고정컬럼-동적필드 섀도잉 분석 + +`is_common=1` 필드 11개가 `items` 테이블 고정 컬럼과 직접 매핑됨. +`is_common=0` 동적 필드 중 고정 컬럼과 **의미적으로 동일한** 필드가 별도 key로 생성되어 있어, 고정 컬럼 기반 기능(필터링, 일괄 변경 등)이 이 동적 필드를 사용하는 품목에 적용되지 않는 위험 존재. + +##### 고정 컬럼 매핑 현황 (is_common=1, 정상) + +| field id | field_key | source_column | 비고 | +|----------|-----------|---------------|------| +| 153 | `item_type` | `items.item_type` | | +| 154 | `code` | `items.code` | | +| 155 | `name` | `items.name` | | +| 156 | `items_unit` | `items.unit` | | +| 157 | `category_id` | `items.category_id` | | +| 158 | `bom` | `items.bom` | | +| 159 | `attributes` | `items.attributes` | | +| 160 | `attributes_archive` | `items.attributes_archive` | | +| 161 | `options` | `items.options` | | +| 162 | `description` | `items.description` | | +| 163 | `is_active` | `items.is_active` | | + +##### 섀도잉 유형 A: `is_active` 중복 (6건) — 🔴 이번에 정리 + +| field id | field_key | field_name | 소속 page | 섀도잉 대상 | +|----------|-----------|-----------|-----------|------------| +| 163 | `is_active` | 활성 여부 | 공통(is_common=1) | `items.is_active` (정상 매핑) | +| **164** | `field_163` | 활성 여부 | **SM** | `items.is_active` 중복 | +| **105** | `105_state` | 품목 상태 | **PT** (측면규격 섹션) | `items.is_active` 중복 | +| **131** | `131_state` | 품목 상태 | **미연결** | `items.is_active` 중복 | +| **133** | `133_state` | 품목상태 | **PT** (측면규격 섹션) | `items.is_active` 중복 | +| **138** | `138_state` | 품목상태 | **PT, FG** | `items.is_active` 중복 | +| **152** | (null) | 품목상태 | **PT** | `items.is_active` 중복 + key 없음 | + +**위험:** `items.is_active` 기반 비활성 필터링 시 동적 필드 `138_state` 등을 사용하는 품목은 필터 미적용 + +##### 섀도잉 유형 B: null key 필드 (1건) — 🔴 이번에 정리 + +| field id | field_key | field_name | 소속 page | +|----------|-----------|-----------|-----------| +| **152** | **(null)** | 품목상태 | PT | + +**위험:** field_key가 없어서 데이터 저장/조회 자체 불가. 폼에 표시는 되지만 값 매핑 실패. + +##### 섀도잉 유형 C: 미연결 필드 (5건) — 🟡 이번에 정리 + +어떤 page에도 entity_relationship으로 연결되지 않아 사용 불가 상태인 필드: + +| field id | field_key | field_name | 비고 | +|----------|-----------|-----------|------| +| **116** | `116_bending_parts` | 품목명 | 미연결, 122와 중복 | +| **117** | `117_purchase_parts` | 품목명 | 미연결, 132와 중복 | +| **129** | `unit_2` | 단위_2 | 미연결, 98(unit)과 중복 | +| **131** | `131_state` | 품목 상태 | 미연결, is_active 중복 | +| **136** | `unit_3` | 단위_3 | 미연결, 98(unit)과 중복 | + +**위험:** 미연결 상태이므로 즉각적 문제는 없으나, 향후 혼동 유발 가능. + +##### 섀도잉 유형 D: name/unit/specification/description 중복 — 📌 다음에 정리 + +| 고정 컬럼 | 동적 필드 중복 수 | 소속 pages | 다음에 정리하는 이유 | +|----------|------------------|------------|---------------------| +| `items.name` | 8건 (id:96,100,107,111,122,132,139,140) | CS,RM,SM,PT,FG | PT 부품유형별 분기 UI와 맞물림. 렌더링 로직 변경 필요 | +| `items.unit` | 2건 (id:98,129,136) | CS,RM,SM,PT + 미연결 | unit(id:98)은 4개 page에서 활발히 사용 중 | +| `item_details.specification` | 6건 (id:97,101~104,108~109) | CS,RM,SM | 원자재 4단 규격은 의도된 설계. 통합 시 정책 결정 필요 | +| `items.description` | 4건 (id:99,130,137,145) | CS,RM,SM,PT,FG | 용도별 비고 분리가 의도된 것일 수 있음 | +| `item_details.part_type` | 1건 (id:110) | PT | 현재 정상 사용 중 | +| `item_details.certification_*` | 3건 (id:142~144) | FG | FG item_details 생성 후 연계 검토 | + +--- + +### 4.3 Phase 1.3: 이관된 제품 데이터 구조 + +#### 4.3.1 SAM items 테이블 현황 (tenant_id=287) + +| item_type | 건수 | 설명 | +|-----------|------|------| +| FG (완제품) | 18 | 5130 models 18개와 1:1 매핑 | +| PT (부품) | 669 | 5130 parts/parts_sub + BDmodels 이관 | +| SM (부자재) | 61 | 5130 item_list 중 부자재 | +| RM (원자재) | 28 | 5130 item_list 중 원자재 | +| CS (소모품) | 4 | 소모품 | +| **합계** | **780** | | + +#### 4.3.2 FG 품목 attributes 구조 + +FG 18개 품목의 `attributes` JSON 구조 (예: FG-KSS01-벽면형-SUS): +```json +{ + "model_name": "KSS01", // 5130 모델명 + "legacy_source": "models", // 원본 출처 + "finishing_type": "SUS마감", // 마감 유형 + "guiderail_type": "벽면형", // 가이드레일 유형 (설치유형) + "major_category": "스크린", // 대분류 (스크린/철재) + "legacy_model_id": 12 // 5130 model_id +} +``` + +**FG attributes 키 ↔ FG item_fields 매핑 현황:** + +| attributes 키 | 현재 FG field_key | 매핑 상태 | +|---------------|-------------------|-----------| +| `model_name` | `139_productName` (상품명) | ❌ 불일치 - textbox로 직접 입력 | +| `major_category` | 없음 | ❌ 필드 없음 | +| `finishing_type` | 없음 | ❌ 필드 없음 | +| `guiderail_type` | 없음 | ❌ 필드 없음 | +| `legacy_model_id` | 없음 | 내부 참조용, 표시 불필요 | +| `legacy_source` | 없음 | 내부 참조용, 표시 불필요 | + +#### 4.3.3 PT 품목 attributes 구조 + +PT 품목의 `attributes` JSON (예: PT-가이드레일): +```json +{ + "base_price": "25000.00", // 기본 단가 + "legacy_num": 6, // 5130 번호 + "legacy_source": "item_list" // 원본 출처 +} +``` + +#### 4.3.4 item_details 현황 + +| item_type | item_details 건수 | 비고 | +|-----------|-------------------|------| +| FG | 0 | ⚠️ 없음 - 생성 필요 | +| PT | 129 | BD계열 부품 (마구리, 케이스 등) | +| SM | 0 | | +| RM | 0 | | +| CS | 0 | | + +PT item_details 예시 (BD-마구리-505*355): +``` +part_type: 마구리 +item_name: 마구리 505*355 +specification: 505*355 +is_sellable: 1, is_purchasable: 1, is_producible: 0 +``` + +--- + +### 4.4 Phase 1.4: BOM 관계 구조 + +#### 4.4.1 SAM BOM 구조 + +FG 품목의 `bom` JSON 형태: +```json +// FG-KSE01-벽면형-EGI (스크린, bom_items: 3) +[ + {"quantity": 2, "child_item_id": 13170}, // PT-가이드레일 + {"quantity": 1, "child_item_id": 13174}, // PT-하단마감재 + {"quantity": 2, "child_item_id": 13175} // PT-L-BAR +] +``` + +**BOM 패턴 요약:** + +| 대분류 | FG 품목 수 | BOM 구성 | +|--------|-----------|----------| +| 스크린 (KSS01/KSE01/KWE01/KSS02) | 12 | PT 3개 (가이드레일×2 + 하단마감재×1 + L-BAR×2) | +| 철재 (KQTS01/KTE01) | 6 | PT 2개 (가이드레일×2 + 하단마감재×1) | + +#### 4.4.2 5130 레거시 구조 비교 + +**5130 models (18개 활성):** +| 모델명 | 대분류 | 마감 유형 | 가이드레일 | +|--------|--------|-----------|-----------| +| KSS01 | 스크린 | SUS마감 | 벽면형/측면형 | +| KSE01 | 스크린 | SUS마감/EGI마감 | 벽면형/측면형 | +| KWE01 | 스크린 | SUS마감/EGI마감 | 벽면형/측면형 | +| KQTS01 | 철재 | SUS마감 | 벽면형/측면형 | +| KTE01 | 철재 | SUS마감/EGI마감 | 벽면형/측면형 | +| KSS02 | 스크린 | SUS마감 | 벽면형/측면형 | + +**5130 BDmodels (59개 활성):** +| model_name | 건수 | 설명 | +|-----------|------|------| +| KSS01 | 4 | 가이드레일/하단마감재/L-BAR 등 | +| KSE01 | 8 | | +| KWE01 | 7 | | +| KQTS01 | 3 | | +| KTE01 | 6 | | +| KSS02 | 4 | | +| KDSS01 | 4 | | +| (빈값) | 23 | 공용 부품 | + +#### 4.4.3 견적 의존성 분석 + +**FormulaEvaluatorService가 의존하는 데이터:** +1. `items.bom` JSON → `child_item_id`로 PT 품목 조회 → PT의 `item_category`로 `CategoryGroup` 매핑 +2. `items.code` → 품목 식별에 사용 +3. `items.item_category` → 카테고리 그룹 가격 산출에 사용 + +**⚠️ 수정 금지 영역:** +- `items.bom` JSON 구조 (`[{child_item_id, quantity}]`) +- `items.code` 체계 (`FG-모델명-가이드레일-마감`, `PT-부품명`) +- `items.item_category` 값 (`스크린`, `철재`) +- `FormulaEvaluatorService` 로직 + +**✅ 안전한 수정 영역:** +- `item_pages/item_sections/item_fields` (폼 표시 설정) +- `entity_relationships` (폼 구성 관계) +- `item_fields.options` (드롭다운 선택 값) +- `item_details` (표시용 상세 정보) +- `items.attributes` JSON (프론트엔드 표시용, 견적 미사용) + +--- + +## 5. Phase 2 수정 계획 + +### 5.1 FG(제품) 필드 설정 정비 + +**현재 문제:** FG의 `attributes` 키(`model_name`, `finishing_type`, `guiderail_type`, `major_category`)와 FG page의 `item_fields` field_key가 매핑되지 않음 + +**수정 방안:** + +| 순서 | 작업 | field_key | field_type | options | +|------|------|-----------|-----------|---------| +| 1 | 모델명 필드 추가/수정 | `model_name` | dropdown | KSS01, KSE01, KWE01, KQTS01, KTE01, KSS02 | +| 2 | 대분류 필드 추가 | `major_category` | dropdown | 스크린, 철재 | +| 3 | 마감유형 필드 추가 | `finishing_type` | dropdown | SUS마감, EGI마감 | +| 4 | 설치유형 필드 추가 | `guiderail_type` | dropdown | 벽면형, 측면형 | +| 5 | 기존 필드 유지 | `139_productName` → 상품명 | textbox | - | +| 6 | 기존 필드 유지 | `141_lotNum` → 로트 약자 | textbox | - | +| 7 | 인정 관련 필드 유지 | `142~145_*` | textbox/date | - | + +**storage_type 설정:** `json` (attributes JSON에서 읽기) + +### 5.2 PT(부품) 필드 설정 정비 + +**현재 문제:** 빈 field_key 필드 존재, 부품유형별 조건부 필드가 복잡 + +**수정 방안:** +- 빈 field_key 필드 수정 또는 비활성화 +- `Part_type` 드롭다운 options를 실제 부품 유형으로 갱신 +- 부품유형별 `display_condition` JSON 설정으로 조건부 표시 + +### 5.3 RM/SM/CS 필드 설정 정비 + +**현재 문제:** 드롭다운 options가 플레이스홀더 값 + +**수정 방안:** +- RM: `100_item_name` options → 실제 원자재명 (철판, 알루미늄, 스테인리스, 아연도금강판 등) +- RM: `101~104_specification_*` options → 실제 규격 값으로 교체 +- SM: `107_item_name` options → 실제 부자재명 +- SM: `108~109_specification_*` options → 실제 규격 값 + +### 5.4 FG item_details 데이터 보완 + +**현재 문제:** FG 18개 품목의 `item_details` 레코드 없음 + +**수정 방안:** FG 18개 품목에 대해 `item_details` 생성 +``` +item_id: (각 FG item id) +is_sellable: 1 +is_purchasable: 0 +is_producible: 1 +product_category: (스크린/철재) +item_name: (SAM name) +specification: (마감유형-가이드레일유형) +``` + +### 5.5 드롭다운 options 실데이터 매핑 + +**5130 데이터 기반으로 매핑할 값:** + +| 필드 | 현재 options | 목표 options | +|------|-------------|-------------| +| FG model_name | 없음 | KSS01, KSE01, KWE01, KQTS01, KTE01, KSS02 | +| FG major_category | 없음 | 스크린, 철재 | +| FG finishing_type | 없음 | SUS마감, EGI마감 | +| FG guiderail_type | 없음 | 벽면형, 측면형 | +| PT Part_type | 확인 필요 | 조립부품, 벤딩부품, 구매부품, BD부품 | +| RM 100_item_name | 기존값 유지 | 철판, 알루미늄, 스테인리스, 아연도금강판 | +| RM 규격 101~104 | 옵션1-1 등 (임시값) | 실제 규격 값으로 교체 필요 | + +### 5.6 고정컬럼-동적필드 섀도잉 정리 + +> 상세 분석: 섹션 4.2.3 참조 + +#### 5.6.1 is_active 중복 정리 (⚠️ 컨펌 필요) + +**목표:** `items.is_active` 고정 컬럼만으로 활성/비활성 상태를 관리하도록 통합 + +**방안 A (권장): 동적 필드를 is_common=1 공통필드(id:163)로 교체** + +각 page에서 중복 동적 필드를 제거하고, 공통 필드 `is_active`(id:163)를 entity_relationship으로 연결: + +| 대상 page | 제거할 동적 필드 | 대체 | 작업 내용 | +|-----------|-----------------|------|----------| +| SM (id:1017) | id:164 (`field_163`) | id:163 (`is_active`) | 1) section(id:94)→field(id:164) 관계 삭제 2) section(id:94)→field(id:163) 관계 추가 | +| PT 측면규격 (id:99) | id:105 (`105_state`) | id:163 (`is_active`) | 1) section(id:99)→field(id:105) 관계 삭제 2) section(id:99)→field(id:163) 관계 추가 | +| PT 측면규격 (id:99) | id:133 (`133_state`) | id:163 (`is_active`) | 1) section(id:99)→field(id:133) 관계 삭제 (id:163 이미 추가됨) | +| PT 기본정보 (id:95) | id:138 (`138_state`) | id:163 (`is_active`) | 1) section(id:95)→field(id:138) 관계 삭제 2) section(id:95)→field(id:163) 관계 추가 | +| FG 기본정보 (id:102) | id:138 (`138_state`) | id:163 (`is_active`) | 1) section(id:102)→field(id:138) 관계 삭제 2) section(id:102)→field(id:163) 관계 추가 | +| PT 기본정보 (id:95) | id:152 (`null` key) | id:163 (`is_active`) | 1) section(id:95)→field(id:152) 관계 삭제 (id:163 이미 추가됨) | + +**추가 작업:** +- 제거된 동적 필드(id:105,131,133,138,152,164)는 `is_active=0`으로 비활성화 (삭제 대신 비활성화하여 안전) +- 기존 `items.attributes` JSON에 `105_state`, `138_state` 등의 키로 저장된 값이 있다면, 해당 값을 `items.is_active` 컬럼과 동기화 필요 여부 확인 + +**방안 B (보수적): 동적 필드의 field_key를 is_active로 변경만** + +동적 필드를 유지하되, `source_column`을 `is_active`로, `storage_type`을 `column`으로 변경하여 같은 컬럼을 가리키게 함. 관계 변경 없이 안전하지만, 불필요한 필드가 잔존함. + +**실행 전 확인 사항:** +```sql +-- 동적 필드에 실제 데이터가 저장되어 있는지 확인 +SELECT id, code, name, + JSON_EXTRACT(attributes, '$.105_state') as s105, + JSON_EXTRACT(attributes, '$.131_state') as s131, + JSON_EXTRACT(attributes, '$.133_state') as s133, + JSON_EXTRACT(attributes, '$.138_state') as s138, + JSON_EXTRACT(attributes, '$.field_163') as f163 +FROM items +WHERE tenant_id = 287 AND deleted_at IS NULL +AND ( + JSON_EXTRACT(attributes, '$.105_state') IS NOT NULL + OR JSON_EXTRACT(attributes, '$.131_state') IS NOT NULL + OR JSON_EXTRACT(attributes, '$.133_state') IS NOT NULL + OR JSON_EXTRACT(attributes, '$.138_state') IS NOT NULL + OR JSON_EXTRACT(attributes, '$.field_163') IS NOT NULL +); +``` + +#### 5.6.2 null key 필드 비활성화 (✅ 즉시 가능) + +```sql +-- item_fields id:152 (field_key=NULL, 품목상태, PT page) +-- key가 없어서 데이터 매핑 불가. 비활성화 처리. +UPDATE item_fields SET is_active = 0 WHERE id = 152 AND tenant_id = 287; +``` + +#### 5.6.3 미연결 필드 비활성화 (✅ 즉시 가능) + +entity_relationship에 연결되지 않아 어떤 폼에도 표시되지 않는 필드: + +```sql +-- 미연결 필드 5건 비활성화 +UPDATE item_fields SET is_active = 0 +WHERE id IN (116, 117, 129, 131, 136) AND tenant_id = 287; + +-- 확인: 이 필드들이 실제 미연결인지 재검증 +SELECT f.id, f.field_key, f.field_name, er.id as rel_id +FROM item_fields f +LEFT JOIN entity_relationships er + ON er.child_type = 'field' AND er.child_id = f.id AND er.tenant_id = 287 +WHERE f.id IN (116, 117, 129, 131, 136) AND f.tenant_id = 287; +-- rel_id가 모두 NULL이면 확실히 미연결 +``` + +| field id | field_key | 비활성화 이유 | +|----------|-----------|--------------| +| 116 | `116_bending_parts` | 미연결. id:122(`122_bending_parts`)와 중복 | +| 117 | `117_purchase_parts` | 미연결. id:132(`132_PurchasedItemName`)와 중복 | +| 129 | `unit_2` | 미연결. id:98(`unit`)과 중복 | +| 131 | `131_state` | 미연결. is_active 중복 | +| 136 | `unit_3` | 미연결. id:98(`unit`)과 중복 | + +#### 5.6.4 다음에 정리할 항목 (이번 범위 밖) + +| 유형 | 건수 | 다음에 정리하는 이유 | +|------|------|---------------------| +| `name` (품목명) 중복 | 8건 | PT 부품유형별 분기 UI(조립부품명/벤딩부품명/구매부품명)와 맞물림. `display_condition` 기반 렌더링 로직 변경 필요 | +| `unit` (단위) 중복 | 2건 (활성) | id:98이 4개 page에서 사용 중. 공통필드(id:156)와의 역할 분담 정책 결정 필요 | +| `specification` (규격) 중복 | 6건 | 원자재 4단 규격은 의도된 설계. `item_details.specification`과의 동기화 정책 필요 | +| `description` (비고) 중복 | 4건 | `note1/note2/note3` 용도별 분리가 의도일 수 있음 | +| `certification_*` 중복 | 3건 | FG item_details 생성(5.4) 후 연계 검토 | +| `part_type` 중복 | 1건 | PT에서 정상 사용 중 | + +--- + +## 6. 컨펌 대기 목록 + +| # | 항목 | 변경 내용 | 영향 범위 | 상태 | +|---|------|----------|----------|------| +| 1 | FG 필드 추가 | model_name, major_category, finishing_type, guiderail_type 4개 필드 추가 | item_fields, entity_relationships | ⏳ 대기 | +| 2 | PT 빈 field_key 처리 | id:152 비활성화 | item_fields | ⏳ 대기 | +| 3 | RM/SM options 교체 | 플레이스홀더 → 실제 값 | item_fields.options | ⏳ 대기 | +| 4 | FG item_details 생성 | 18건 INSERT | item_details | ⏳ 대기 | +| 5 | is_active 중복 필드 통합 | 6개 동적필드 → 공통필드(id:163)로 교체 | entity_relationships, item_fields | ⏳ 대기 | +| 6 | 미연결 필드 비활성화 | id:116,117,129,131,136 비활성화 | item_fields | ⏳ 대기 | + +--- + +## 7. 변경 이력 + +| 날짜 | 항목 | 변경 내용 | 파일 | 승인 | +|------|------|----------|------|------| +| 2026-01-31 | - | 문서 초안 작성 및 Phase 1 분석 완료 | - | - | +| 2026-01-31 | 4.2.3 | 고정컬럼-동적필드 섀도잉 분석 추가 (is_active 6건, null key 1건, 미연결 5건) | - | - | +| 2026-01-31 | 5.6 | Phase 2에 섀도잉 정리 작업(2.6) 추가. 구체적 SQL, field id, entity_relationship 변경 계획 명시 | - | - | +| 2026-01-31 | 2.6 | Phase 2.6 실행 완료: null key(id:152) 비활성화, 미연결 5건(id:116,117,129,131,136) 비활성화, is_active 중복 통합(rel 7건 삭제, 공통필드 163을 section 94/95/99/102에 연결, 동적필드 105/133/138/164 비활성화). id:116,117은 계획과 달리 고아 section(97,98)에 연결 확인됨 | - | ✅ | +| 2026-01-31 | 2.1 | FG 필드 4개 추가(id:177-180: model_name/major_category/finishing_type/guiderail_type), section 102 연결, order_no 정렬 | item_fields, entity_relationships | ✅ | +| 2026-01-31 | 2.2 | PT Part_type options 갱신: BD부품 추가, 라벨 간소화 (4개: 조립/벤딩/구매/BD) | item_fields id:110 | ✅ | +| 2026-01-31 | 2.3 | RM options 실데이터 교체(재질4종, 두께7종, 폭1종, 길이6종), SM options 11개 카테고리. SM 규격 빈 배열 설정 | item_fields id:100-104,107-109 | ✅ | +| 2026-01-31 | 2.5 | 드롭다운 options 매핑 2.1~2.3에서 함께 완료 | - | ✅ | +| 2026-01-31 | 2.4 | FG item_details 18건 생성(id:524-541). is_sellable=1, is_producible=1, product_category/item_name/specification 설정 | item_details | ✅ | + +--- + +## 8. 참고 문서 + +- **DB 스키마**: `docs/specs/database-schema.md` +- **품목 정책**: `docs/rules/item-policy.md` +- **품질 체크리스트**: `docs/standards/quality-checklist.md` +- **빠른 시작**: `docs/quickstart/quick-start.md` +- **API 규칙**: `docs/standards/api-rules.md` +- **기존 이관 계획**: `docs/plans/items-migration-kyungdong-plan.md` +- **MNG 필드 관리 계획**: `docs/plans/mng-item-field-management-plan.md` + +--- + +## 9. 새 세션 작업 시작 가이드 + +### 9.0 이 문서만으로 작업을 시작하는 방법 + +**1단계: 현재 상태 확인** +- 이 문서의 "📍 현재 진행 상태" 섹션에서 마지막 완료 작업과 다음 작업 확인 +- Phase 2 대상 범위(섹션 2.2) 테이블에서 ⏳/✅ 상태 확인 + +**2단계: 환경 확인** +```bash +# Docker 컨테이너 실행 확인 +docker ps | grep sam + +# 테넌트 데이터 접근 확인 (tenant_id=287) +docker exec sam-api-1 php artisan tinker --execute="echo DB::table('items')->where('tenant_id', 287)->count();" +# 기대값: 780 +``` + +**3단계: 작업 실행 순서 (Phase 2)** + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Phase 2 실행 순서 (권장) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 2.6 섀도잉 정리 (안전, 선행 작업) │ +│ ├─ 5.6.2 null key 비활성화 (즉시 가능) │ +│ ├─ 5.6.3 미연결 필드 비활성화 (즉시 가능) │ +│ └─ 5.6.1 is_active 중복 통합 (⚠️ 컨펌 필요) │ +│ └─ 사전: 5.6.1 확인 SQL 실행하여 기존 데이터 유무 확인 │ +│ │ +│ 2.1 FG 필드 설정 정비 (⚠️ 컨펌 필요) │ +│ └─ 섹션 5.1 참조: 4개 필드 추가 + entity_relationship 연결 │ +│ │ +│ 2.2 PT 필드 설정 정비 (⚠️ 컨펌 필요) │ +│ └─ 섹션 5.2 참조 │ +│ │ +│ 2.3 SM/RM/CS 필드 설정 정비 │ +│ └─ 섹션 5.3 참조 │ +│ │ +│ 2.5 드롭다운 options 실데이터 매핑 │ +│ └─ 섹션 5.5 참조: FG 4개 + PT/RM 교체 │ +│ │ +│ 2.4 FG item_details 데이터 보완 │ +│ └─ 섹션 5.4 참조: 18건 INSERT │ +│ │ +│ 검증 │ +│ └─ 섹션 10 테스트 케이스 실행 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**4단계: 작업 대상 테이블/ID 빠른 참조** + +| 테이블 | tenant_id | 주요 ID 범위 | 용도 | +|--------|-----------|-------------|------| +| `item_pages` | 287 | 1015~1019 (CS/RM/SM/PT/FG) | 품목유형별 폼 | +| `item_sections` | 287 | 92~102 | 섹션 그룹 | +| `item_fields` | 287 | 96~164 | 필드 정의 | +| `entity_relationships` | 287 | page→section 26건, section→field 66건 | 계층 연결 | +| `items` | 287 | 13147~13164 (FG 18건) | 품목 데이터 | +| `item_details` | - | PT 129건, FG 0건 | 품목 상세 | + +**5단계: 수정 금지 영역 (반드시 확인)** +- `items.bom` JSON 구조 변경 금지 +- `items.code` 체계 변경 금지 +- `items.item_category` 값 변경 금지 +- `FormulaEvaluatorService` 수정 금지 +- 위 항목은 견적 로직에 직접 영향. 상세: 섹션 4.4.3 + +--- + +## 10. Serena 메모리 관리 정책 + +### 10.1 세션 시작 시 (Load Strategy) +```javascript +read_memory("item-data-alignment-state") // 1. 상태 파악 +read_memory("item-data-alignment-snapshot") // 2. 사고 흐름 복구 +read_memory("item-data-alignment-active-symbols") // 3. 작업 대상 파악 +``` + +### 10.2 작업 중 관리 (Context Defense) +| 컨텍스트 잔량 | Action | 내용 | +|--------------|--------|------| +| **30% 이하** | Snapshot | `write_memory("item-data-alignment-snapshot", "코드변경+논의요약")` | +| **20% 이하** | Context Purge | `write_memory("item-data-alignment-active-symbols", "주요 수정 파일/함수")` | +| **10% 이하** | Stop & Save | 최종 상태 저장 후 세션 교체 권고 | + +### 10.3 Serena 메모리 구조 +- `item-data-alignment-state`: { phase, progress, next_step, last_decision } (JSON 구조) +- `item-data-alignment-snapshot`: 현재까지의 논의 및 코드 변경점 요약 (Text) +- `item-data-alignment-rules`: 견적 영향 금지 등 불변 규칙 (Text) +- `item-data-alignment-active-symbols`: 현재 수정 중인 파일/심볼 리스트 (List) + +--- + +## 11. 검증 결과 + +> 작업 완료 후 이 섹션에 검증 결과 추가 + +### 11.1 테스트 케이스 + +| 입력값 | 예상 결과 | 실제 결과 | 상태 | +|--------|----------|----------|------| +| FG-KSE01-벽면형-EGI 조회 | model_name=KSE01, finishing_type=EGI마감 등 표시 | - | ⏳ | +| PT-가이드레일 조회 | base_price, 부품유형 등 표시 | - | ⏳ | +| FG BOM 표시 | 가이드레일×2, 하단마감재×1, L-BAR×2 표시 | - | ⏳ | +| 견적 생성 (수정 후) | 기존과 동일한 견적 금액 산출 | - | ⏳ | +| SM 품목 활성 여부 | `items.is_active` 컬럼 값 표시 (field_163 아님) | - | ⏳ | +| PT 품목상태 필드 | `items.is_active` 공통 필드로 통합 표시 | - | ⏳ | +| FG 품목상태 필드 | `items.is_active` 공통 필드로 통합 표시 | - | ⏳ | +| id:152 (null key) | 폼에 표시되지 않음 (비활성화) | - | ⏳ | +| 미연결 필드 5건 | 폼에 표시되지 않음 (비활성화) | - | ⏳ | + +### 11.2 성공 기준 달성 현황 + +| 기준 | 달성 | 비고 | +|------|------|------| +| FG 18개 품목이 모든 필드 정상 표시 | ⏳ | | +| PT 부품유형별 조건부 필드 정상 작동 | ⏳ | | +| RM/SM 드롭다운 실제 값 표시 | ⏳ | | +| 견적 금액 변동 없음 (회귀 테스트) | ⏳ | | +| 품목 목록 → 상세 → 문서 데이터 흐름 정상 | ⏳ | | +| is_active 중복 필드 통합 완료 (6건 → 공통필드 1개) | ⏳ | | +| null key 필드(id:152) 비활성화 | ⏳ | | +| 미연결 필드(id:116,117,129,131,136) 비활성화 | ⏳ | | + +--- + +## 12. 자기완결성 점검 결과 + +### 12.1 체크리스트 검증 + +| # | 검증 항목 | 상태 | 비고 | +|---|----------|:----:|------| +| 1 | 작업 목적이 명확한가? | ✅ | 섹션 1.1 배경 | +| 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 11.2 | +| 3 | 작업 범위가 구체적인가? | ✅ | 섹션 2 대상 범위 | +| 4 | 의존성이 명시되어 있는가? | ✅ | 견적 금지 영역 명시 (4.4.3), 수정금지 (9.0 5단계) | +| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 8 | +| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 9.0 (새 세션 가이드), 섹션 5 (상세 수정 계획) | +| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 11.1 | +| 8 | 모호한 표현이 없는가? | ✅ | 구체적 테이블/필드/ID, SQL 쿼리 명시 | + +### 12.2 새 세션 시뮬레이션 테스트 + +| 질문 | 답변 가능 | 참조 섹션 | +|------|:--------:|----------| +| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | +| Q2. 어디서부터 시작해야 하는가? | ✅ | 9.0 3단계 (실행 순서 다이어그램) | +| Q3. 어떤 데이터를 수정해야 하는가? | ✅ | 5.1~5.6 (상세 수정 계획 + SQL) | +| Q4. 절대 건드리면 안 되는 것은? | ✅ | 9.0 5단계 + 4.4.3 (수정 금지 영역) | +| Q5. 작업 완료 확인 방법은? | ✅ | 11.1 테스트 케이스, 11.2 성공 기준 | +| Q6. 막혔을 때 참고 문서는? | ✅ | 8. 참고 문서 | +| Q7. DB 접속/환경 세팅은? | ✅ | 9.0 2단계 (환경 확인 명령어) | +| Q8. 테이블/ID 범위는? | ✅ | 9.0 4단계 (빠른 참조 테이블) | + +**결과**: 8/8 통과 → ✅ 자기완결성 확보 + +--- + +*이 문서는 /sc:plan 스킬로 생성되었습니다.* \ No newline at end of file