From 21edc932d9fb580085b598d04b2615ca7f7c6f68 Mon Sep 17 00:00:00 2001 From: byeongcheolryu Date: Tue, 18 Nov 2025 14:05:29 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20localStorage=20SSR=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20=EC=9E=91=EC=97=85=20=EC=84=B8=EC=85=98=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ItemMasterDataManagement.tsx SSR 호환성 작업 계획 수립 - 6곳의 localStorage useState 초기화 수정 대상 파악 - 대용량 파일 작업 전략 및 세션 재개 방법 문서화 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../[ANALYSIS] item-master-data-management.md | 2584 +++++++++++++++++ claudedocs/[GUIDE] CSS-MIGRATION-WORKFLOW.md | 412 +++ ...d => [GUIDE] ITEM-MANAGEMENT-MIGRATION.md} | 0 claudedocs/[GUIDE] LARGE-FILE-WORKFLOW.md | 550 ++++ .../[GUIDE] ZOD-VALIDATION-TROUBLESHOOTING.md | 662 +++++ ... => [IMPL-2025-11-07] auth-guard-usage.md} | 0 ...25-11-12] modal-select-layout-shift-fix.md | 612 ++++ .../[IMPL-2025-11-17] item-list-css-sync.md | 280 ++ claudedocs/[INDEX] DOCUMENTATION-MAP.md | 260 ++ .../{00_INDEX.md => [LEGACY] 00_INDEX.md} | 0 ...n.md => [LEGACY] authentication-design.md} | 0 ... [PLAN] httponly-cookie-implementation.md} | 0 claudedocs/[REF] api-requirements-items.md | 918 ++++++ ...s.md => [REF] component-usage-analysis.md} | 0 ...d => [REF] dashboard-migration-summary.md} | 0 ...s15-middleware-authentication-research.md} | 0 ....md => [REF] session-migration-backend.md} | 0 ...md => [REF] session-migration-frontend.md} | 0 ....md => [REF] session-migration-summary.md} | 0 ...[REF] token-security-nextjs15-research.md} | 0 ...-11-18] localStorage-ssr-fix-checkpoint.md | 164 ++ src/components/ui/command.tsx | 0 src/components/ui/popover.tsx | 0 23 files changed, 6442 insertions(+) create mode 100644 claudedocs/[ANALYSIS] item-master-data-management.md create mode 100644 claudedocs/[GUIDE] CSS-MIGRATION-WORKFLOW.md rename claudedocs/{ITEM_MANAGEMENT_MIGRATION_GUIDE.md => [GUIDE] ITEM-MANAGEMENT-MIGRATION.md} (100%) create mode 100644 claudedocs/[GUIDE] LARGE-FILE-WORKFLOW.md create mode 100644 claudedocs/[GUIDE] ZOD-VALIDATION-TROUBLESHOOTING.md rename claudedocs/{[PARTIAL-2025-11-07] auth-guard-usage.md => [IMPL-2025-11-07] auth-guard-usage.md} (100%) create mode 100644 claudedocs/[IMPL-2025-11-17] item-list-css-sync.md create mode 100644 claudedocs/[INDEX] DOCUMENTATION-MAP.md rename claudedocs/{00_INDEX.md => [LEGACY] 00_INDEX.md} (100%) rename claudedocs/{[REF-Legacy] authentication-design.md => [LEGACY] authentication-design.md} (100%) rename claudedocs/{[REF-Future] httponly-cookie-implementation.md => [PLAN] httponly-cookie-implementation.md} (100%) create mode 100644 claudedocs/[REF] api-requirements-items.md rename claudedocs/{[REF-2025-11-12] component-usage-analysis.md => [REF] component-usage-analysis.md} (100%) rename claudedocs/{[REF-2025-11-10] dashboard-migration-summary.md => [REF] dashboard-migration-summary.md} (100%) rename claudedocs/{[REF-2025-11-07] research_nextjs15_middleware_authentication.md => [REF] nextjs15-middleware-authentication-research.md} (100%) rename claudedocs/{[REF-2025-11-12] session-migration-backend.md => [REF] session-migration-backend.md} (100%) rename claudedocs/{[REF-2025-11-12] session-migration-frontend.md => [REF] session-migration-frontend.md} (100%) rename claudedocs/{[REF-2025-11-12] session-migration-summary.md => [REF] session-migration-summary.md} (100%) rename claudedocs/{[REF-2025-11-07] research_token_security_nextjs15.md => [REF] token-security-nextjs15-research.md} (100%) create mode 100644 claudedocs/[SESSION-2025-11-18] localStorage-ssr-fix-checkpoint.md create mode 100644 src/components/ui/command.tsx create mode 100644 src/components/ui/popover.tsx diff --git a/claudedocs/[ANALYSIS] item-master-data-management.md b/claudedocs/[ANALYSIS] item-master-data-management.md new file mode 100644 index 00000000..e449dbe4 --- /dev/null +++ b/claudedocs/[ANALYSIS] item-master-data-management.md @@ -0,0 +1,2584 @@ +1# 품목기준관리 시스템 분석 및 구현 계획 + +> **작성일**: 2025-11-17 +> **소스**: React 프로젝트 ItemMasterDataManagement.tsx (1,413줄) +> **타겟**: Next.js 15 마이그레이션 +> **상태**: 📊 분석 완료, 구현 대기 + +--- + +## 📑 목차 + +1. [프로젝트 배경 및 목표](#1-프로젝트-배경-및-목표) +2. [시스템 개요](#2-시스템-개요) +3. [데이터 구조 분석](#3-데이터-구조-분석) +4. [기능 분석](#4-기능-분석) +5. [API 요구사항](#5-api-요구사항) +6. [버전관리 시스템](#6-버전관리-시스템) +7. [멀티테넌시 및 데이터 로딩 전략](#7-멀티테넌시-및-데이터-로딩-전략) +8. [Next.js 15 마이그레이션 계획](#8-nextjs-15-마이그레이션-계획) +9. [구현 우선순위](#9-구현-우선순위) +10. [다음 단계](#10-다음-단계) + +--- + +## 1. 프로젝트 배경 및 목표 + +### 1.1 배경 + +현재 구현된 **품목등록 화면** (`ItemForm.tsx`)은 고정된 값(템플릿)으로 구성되어 있습니다. +실제 운영 환경에서는 이 고정값들을 **동적으로 설정/편집**할 수 있어야 하며, +이를 위한 별도의 **품목기준관리 페이지**가 필요합니다. + +``` +품목기준관리 페이지 (ItemMasterDataManagement) + ↓ 설정/편집 +품목등록 화면 (ItemForm) + ↓ 사용자 입력 +실제 품목 데이터 +``` + +### 1.2 핵심 요구사항 + +1. ✅ **드롭다운 옵션 관리**: 단위, 재질, 표면처리 등 +2. ✅ **페이지 구조 관리**: 섹션, 하위섹션, 항목 계층 구조 +3. ✅ **마스터 항목 템플릿**: 재사용 가능한 항목 정의 +4. ✅ **조건부 표시 로직**: 특정 값에 따라 항목 표시/숨김 +5. ✅ **품목 코드 자동생성 규칙**: 동적으로 설정 가능한 규칙 체계 +6. ✅ **다양한 업종 지원**: 고객사별 자유로운 페이지 구성 +7. ✅ **버전관리 시스템**: 품목 수정 이력 추적 및 이전 버전 조회 + +### 1.3 목표 + +**1차 목표**: 품목기준관리 페이지 구축 및 Laravel API 연동 +**2차 목표**: 품목등록 화면을 동적 템플릿 시스템으로 전환 (선택적) + +--- + +## 2. 시스템 개요 + +### 2.1 React 프로젝트 파일 정보 + +**파일 경로**: `/sma-react-v2.0/src/components/ItemMasterDataManagement.tsx` +**파일 크기**: 1,413줄 +**주요 의존성**: +- `DataContext` - 전역 상태 관리 (6,697줄) +- `SpecificationManagement` - 규격 관리 서브 컴포넌트 +- `DraggableField` - 드래그 앤 드롭 항목 + +### 2.2 6개 탭 구조 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 품목기준관리 메인 화면 │ +└─────────────────────────────────────────────────────────────┘ + │ + ├─ 📊 계층구조 (hierarchy) + │ └─ 섹션 > 하위섹션 > 항목 트리 구조 + │ + ├─ 📋 항목 (items) + │ └─ 마스터 항목 템플릿 (제품/부품/부자재/원자재별) + │ + ├─ 📏 단위 (units) + │ └─ EA, SET, KG, M, L, BOX, PCS 등 + │ + ├─ 🧱 재질 (materials) + │ └─ EGI 1.2T, SUS 1.2T, SPHC-SD 등 + │ + ├─ 🎨 표면처리 (surface) + │ └─ 무도장, 파우더도장, 아연도금 등 + │ + └─ 📐 규격 (specifications) + └─ 별도 SpecificationManagement 컴포넌트 +``` + +### 2.3 데이터 흐름 + +``` +사용자 + ↓ +품목기준관리 페이지 + ↓ 설정 저장 +Laravel API (DB) + ↓ 조회 +품목등록 화면 (ItemForm) + ↓ 드롭다운, 필드 옵션 표시 +사용자 입력 +``` + +--- + +## 3. 데이터 구조 분석 + +### 3.1 계층구조 데이터 + +#### ItemPage (섹션) + +```typescript +interface ItemPage { + id: string; // 예: "PAGE-1234567890" + pageName: string; // 예: "품목 등록" + itemType: 'FG' | 'PT' | 'SM' | 'RM' | 'CS'; // 품목 유형 + sections: ItemSection[]; // 하위섹션 배열 + isActive: boolean; // 활성 여부 + absolutePath?: string; // 절대경로 (선택적) + createdAt: string; // 생성일 + updatedAt?: string; // 수정일 +} +``` + +**예시**: +```json +{ + "id": "PAGE-001", + "pageName": "제품(FG) 등록", + "itemType": "FG", + "sections": [...], + "isActive": true, + "createdAt": "2025-01-10" +} +``` + +#### ItemSection (하위섹션) + +```typescript +interface ItemSection { + id: string; // 예: "SECTION-1234567890" + title: string; // 예: "기본정보" + description?: string; // 설명 (선택) + category?: string[]; // 카테고리 조건 (선택) + fields: ItemField[]; // 항목 배열 + type?: 'fields' | 'bom'; // 섹션 타입 (선택) + order: number; // 표시 순서 + isCollapsible: boolean; // 접기/펼치기 가능 여부 + isCollapsed: boolean; // 기본 접힘 상태 + createdAt: string; // 생성일 +} +``` + +**예시**: +```json +{ + "id": "SECTION-001", + "title": "기본정보", + "description": "품목의 기본 정보를 입력합니다", + "fields": [...], + "order": 1, + "isCollapsible": true, + "isCollapsed": false, + "createdAt": "2025-01-10" +} +``` + +#### ItemField (항목) + +```typescript +interface ItemField { + id: string; // 예: "FIELD-1234567890" + name: string; // 예: "품목코드" + fieldKey: string; // 예: "itemCode" + property: ItemFieldProperty; // 입력 속성 + description?: string; // 설명 (선택) + displayCondition?: FieldDisplayCondition; // 조건부 표시 (선택) + masterFieldId?: string; // 마스터 항목 ID (선택) + order?: number; // 표시 순서 (선택) + createdAt: string; // 생성일 +} +``` + +**예시**: +```json +{ + "id": "FIELD-001", + "name": "품목코드", + "fieldKey": "itemCode", + "property": { + "inputType": "textbox", + "required": true, + "row": 1, + "col": 1 + }, + "description": "품목을 식별하는 고유 코드", + "createdAt": "2025-01-10" +} +``` + +#### ItemFieldProperty (입력 속성) + +```typescript +interface ItemFieldProperty { + inputType: 'textbox' | 'dropdown' | 'checkbox' | 'number' | 'date' | 'textarea'; + required: boolean; // 필수 여부 + row: number; // 레이아웃 행 + col: number; // 레이아웃 열 + options?: string[]; // 드롭다운 옵션 (dropdown일 때) +} +``` + +**예시 (드롭다운)**: +```json +{ + "inputType": "dropdown", + "required": true, + "row": 1, + "col": 1, + "options": ["EA", "SET", "KG", "M"] +} +``` + +#### FieldDisplayCondition (조건부 표시) + +```typescript +interface FieldDisplayCondition { + fieldKey: string; // 조건 필드 키 + expectedValue: string; // 기대 값 +} +``` + +**예시**: +```json +{ + "fieldKey": "itemType", + "expectedValue": "FG" +} +``` +**의미**: `itemType` 필드 값이 `"FG"`일 때만 이 항목을 표시 + +--- + +### 3.2 마스터 항목 데이터 + +#### ItemMasterField + +```typescript +interface ItemMasterField { + id: string; // 예: "MASTER-1234567890" + name: string; // 예: "품목코드" + fieldKey: string; // 예: "itemCode" + property: ItemFieldProperty; // 입력 속성 + category?: string; // 카테고리 (예: "공통", "제품", "부품") + description?: string; // 설명 + isActive: boolean; // 활성 여부 + createdAt: string; // 생성일 +} +``` + +**역할**: +- 재사용 가능한 항목 템플릿 +- 여러 섹션/페이지에서 참조 가능 +- 품목 분류별로 관리 (공통, 제품, 부품, 부자재, 원자재) + +**예시**: +```json +{ + "id": "MASTER-001", + "name": "품목코드", + "fieldKey": "itemCode", + "property": { + "inputType": "textbox", + "required": true, + "row": 1, + "col": 1 + }, + "category": "공통", + "description": "모든 품목에 공통으로 사용되는 품목코드", + "isActive": true, + "createdAt": "2025-01-10" +} +``` + +--- + +### 3.3 옵션 데이터 (단위/재질/표면처리) + +#### MasterOption + +```typescript +interface MasterOption { + id: string; // 예: "unit-1", "mat-1", "surf-1" + value: string; // 코드 값 (예: "EA", "EGI 1.2T") + label: string; // 표시명 (예: "EA (개)", "EGI 1.2T") + isActive: boolean; // 활성 여부 +} +``` + +**관리 대상**: +1. **단위 (units)**: `EA`, `SET`, `KG`, `M`, `L`, `BOX`, `PCS` +2. **재질 (materials)**: `EGI 1.2T`, `EGI 2.0T`, `SUS 1.2T`, `SPHC-SD 1.6T` +3. **표면처리 (surface)**: `무도장`, `파우더도장`, `아연도금` + +**예시 (단위)**: +```json +[ + { "id": "unit-1", "value": "EA", "label": "EA (개)", "isActive": true }, + { "id": "unit-2", "value": "SET", "label": "SET (세트)", "isActive": true }, + { "id": "unit-3", "value": "KG", "label": "KG (킬로그램)", "isActive": true } +] +``` + +--- + +### 3.4 로컬스토리지 키 구조 + +React 프로젝트에서는 로컬스토리지를 사용하지만, +Next.js에서는 **Laravel API**로 대체합니다. + +**현재 (React)**: +```javascript +const UNIT_OPTIONS_KEY = 'unit-options'; +const MATERIAL_OPTIONS_KEY = 'material-options'; +const SURFACE_TREATMENT_OPTIONS_KEY = 'surface-treatment-options'; +const ITEM_CLASSIFICATIONS_KEY = 'item-classifications'; +``` + +**목표 (Next.js + Laravel)**: +``` +GET /api/master-data/units +GET /api/master-data/materials +GET /api/master-data/surface-treatments +GET /api/master-data/pages +GET /api/master-data/fields +``` + +--- + +## 4. 기능 분석 + +### 4.1 계층구조 탭 + +**주요 기능**: +1. ✅ **섹션 생성**: 품목 유형별 페이지 생성 (FG/PT/SM/RM/CS) +2. ✅ **하위섹션 추가**: 섹션 내 그룹 추가 (기본정보, BOM, 가격정보 등) +3. ✅ **항목 추가/편집**: 입력 필드 정의 및 수정 +4. ✅ **드래그 앤 드롭**: 항목 순서 변경 +5. ✅ **조건부 표시**: 특정 값에 따라 항목 표시/숨김 +6. ✅ **마스터 항목 연동**: 마스터 항목 템플릿 선택 + +**UI 구조**: +``` +┌─────────────────────────────────────────────────────┐ +│ 섹션 목록 (좌측) │ 계층구조 상세 (우측) │ +│ │ │ +│ - 제품(FG) 등록 │ ┌─ 기본정보 섹션 │ +│ - 부품(PT) 등록 │ │ - 품목코드 │ +│ - 부자재(SM) 등록 │ │ - 품목명 │ +│ - 원자재(RM) 등록 │ │ - 단위 │ +│ - 소모품(CS) 등록 │ │ [+ 항목 추가] │ +│ │ │ │ +│ [+ 섹션 추가] │ └─ BOM 섹션 │ +│ │ - 하위 품목코드 │ +│ │ - 수량 │ +│ │ [+ 항목 추가] │ +└─────────────────────────────────────────────────────┘ +``` + +**항목 추가 다이얼로그**: +- 마스터 항목에서 불러오기 (토글) +- 항목명, 필드 키 +- 입력 방식 (텍스트박스, 드롭다운, 체크박스, 숫자, 날짜, 텍스트영역) +- 필수 항목 여부 +- 드롭다운 옵션 (쉼표로 구분) +- 조건부 항목 설정 (조건 필드, 조건 값) +- 설명 + +--- + +### 4.2 항목 탭 + +**주요 기능**: +1. ✅ **마스터 항목 추가/편집/삭제** +2. ✅ **품목 분류별 필터링**: 공통, 제품, 부품, 부자재, 원자재 +3. ✅ **재사용 가능한 템플릿 관리** + +**UI 구조**: +``` +┌─────────────────────────────────────────────────────┐ +│ 마스터 항목 관리 [+ 항목 추가] │ +├─────────────────────────────────────────────────────┤ +│ [제품] [부품] [부자재] [원자재] (서브 탭) │ +├─────────────────────────────────────────────────────┤ +│ ┌─────────────────────────────────────────────┐ │ +│ │ 품목코드 [텍스트박스] [필수] [공통] │ │ +│ │ 필드키: itemCode [편집][삭제]│ +│ └─────────────────────────────────────────────┘ │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ 단위 [드롭다운] [필수] [공통] │ │ +│ │ 필드키: unit [편집][삭제]│ +│ │ 옵션: EA, SET, KG, M │ │ +│ └─────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────┘ +``` + +--- + +### 4.3 단위/재질/표면처리 탭 + +**공통 기능**: +1. ✅ **옵션 추가**: 값(코드), 라벨(표시명) +2. ✅ **옵션 삭제** +3. ✅ **활성/비활성 관리** + +**UI 구조** (단위 탭 예시): +``` +┌─────────────────────────────────────────────────────┐ +│ 단위 관리 [+ 추가] │ +├─────────────────────────────────────────────────────┤ +│ 번호 │ 값 (Value) │ 라벨 (Label) │ 작업 │ +│ 1 │ EA │ EA (개) │ [삭제] │ +│ 2 │ SET │ SET (세트) │ [삭제] │ +│ 3 │ KG │ KG (킬로그램) │ [삭제] │ +└─────────────────────────────────────────────────────┘ +``` + +--- + +### 4.4 규격 탭 + +**구현**: +- 별도 `SpecificationManagement` 컴포넌트 +- React 프로젝트에서 추가 분석 필요 + +--- + +## 5. API 요구사항 + +### 5.1 계층구조 관리 API + +#### 섹션 (ItemPage) 관리 + +```typescript +// 섹션 목록 조회 +GET /api/master-data/pages +Response: { + success: true, + data: ItemPage[] +} + +// 섹션 생성 +POST /api/master-data/pages +Request: { + pageName: string, + itemType: 'FG' | 'PT' | 'SM' | 'RM' | 'CS' +} +Response: { + success: true, + data: ItemPage +} + +// 섹션 수정 +PUT /api/master-data/pages/:pageId +Request: { + pageName?: string, + isActive?: boolean +} + +// 섹션 삭제 +DELETE /api/master-data/pages/:pageId +``` + +#### 하위섹션 (ItemSection) 관리 + +```typescript +// 하위섹션 추가 +POST /api/master-data/pages/:pageId/sections +Request: { + title: string, + description?: string, + order: number, + isCollapsible: boolean, + isCollapsed: boolean +} +Response: { + success: true, + data: ItemSection +} + +// 하위섹션 수정 +PUT /api/master-data/pages/:pageId/sections/:sectionId +Request: { + title?: string, + description?: string, + order?: number +} + +// 하위섹션 삭제 +DELETE /api/master-data/pages/:pageId/sections/:sectionId +``` + +#### 항목 (ItemField) 관리 + +```typescript +// 항목 추가 +POST /api/master-data/pages/:pageId/sections/:sectionId/fields +Request: { + name: string, + fieldKey: string, + property: ItemFieldProperty, + description?: string, + displayCondition?: FieldDisplayCondition, + masterFieldId?: string, + order?: number +} +Response: { + success: true, + data: ItemField +} + +// 항목 수정 +PUT /api/master-data/pages/:pageId/sections/:sectionId/fields/:fieldId +Request: { + name?: string, + fieldKey?: string, + property?: ItemFieldProperty, + description?: string, + displayCondition?: FieldDisplayCondition +} + +// 항목 순서 변경 +PUT /api/master-data/pages/:pageId/sections/:sectionId/fields/reorder +Request: { + fieldIds: string[] // 새로운 순서의 필드 ID 배열 +} + +// 항목 삭제 +DELETE /api/master-data/pages/:pageId/sections/:sectionId/fields/:fieldId +``` + +--- + +### 5.2 마스터 항목 API + +```typescript +// 마스터 항목 목록 조회 (카테고리별) +GET /api/master-data/fields?category=공통 +GET /api/master-data/fields?category=제품 +GET /api/master-data/fields?category=부품 +Response: { + success: true, + data: ItemMasterField[] +} + +// 마스터 항목 생성 +POST /api/master-data/fields +Request: { + name: string, + fieldKey: string, + property: ItemFieldProperty, + category?: string, + description?: string +} +Response: { + success: true, + data: ItemMasterField +} + +// 마스터 항목 수정 +PUT /api/master-data/fields/:fieldId +Request: { + name?: string, + fieldKey?: string, + property?: ItemFieldProperty, + category?: string, + description?: string +} + +// 마스터 항목 삭제 +DELETE /api/master-data/fields/:fieldId +``` + +--- + +### 5.3 옵션 관리 API + +```typescript +// 단위 목록 조회 +GET /api/master-data/units +Response: { + success: true, + data: MasterOption[] +} + +// 단위 추가 +POST /api/master-data/units +Request: { + value: string, + label: string +} + +// 단위 삭제 +DELETE /api/master-data/units/:unitId + +// 재질 목록 조회 +GET /api/master-data/materials +Response: { + success: true, + data: MasterOption[] +} + +// 재질 추가 +POST /api/master-data/materials +Request: { + value: string, + label: string +} + +// 재질 삭제 +DELETE /api/master-data/materials/:materialId + +// 표면처리 목록 조회 +GET /api/master-data/surface-treatments +Response: { + success: true, + data: MasterOption[] +} + +// 표면처리 추가 +POST /api/master-data/surface-treatments +Request: { + value: string, + label: string +} + +// 표면처리 삭제 +DELETE /api/master-data/surface-treatments/:surfaceId +``` + +--- + +### 5.4 통합 조회 API + +품목등록 화면에서 사용할 마스터 데이터를 한 번에 조회: + +```typescript +GET /api/master-data +Response: { + success: true, + data: { + units: MasterOption[], + materials: MasterOption[], + surfaceTreatments: MasterOption[], + pages: ItemPage[], + masterFields: ItemMasterField[] + } +} +``` + +--- + +## 6. 버전관리 시스템 + +### 6.1 시스템 개요 + +품목기준관리 시스템은 **포괄적인 버전관리 시스템**을 포함하여 모든 데이터 수정 이력을 추적합니다. +이는 단순한 감사 로그가 아니라, 이전 버전으로의 롤백과 변경 이력 비교가 가능한 **완전한 버전 관리** 시스템입니다. + +**핵심 특징**: +- ✅ **전체 데이터 스냅샷**: 수정 시마다 이전 상태 전체를 저장 +- ✅ **필수 수정 사유**: 모든 수정 작업에 사유(revision reason) 입력 강제 +- ✅ **버전 번호 자동 증가**: currentRevision 필드로 현재 버전 추적 +- ✅ **이력 조회**: 특정 품목의 전체 수정 이력 확인 +- ✅ **이전 버전 복원**: previousData를 활용한 롤백 기능 +- ✅ **다중 엔티티 지원**: 품목, 견적, 수주, 계산식, 단가 등 시스템 전반 적용 + +**버전관리 대상 엔티티**: +``` +✅ ItemMaster (품목) +✅ Quote (견적) +✅ Order (수주) +✅ CalculationFormula (계산식) +✅ PricingData (단가) +✅ FormulaRule (수식 규칙) +``` + +--- + +### 6.2 데이터 구조 + +#### ItemRevision (품목 수정 이력) + +```typescript +export interface ItemRevision { + revisionNumber: number; // 수정 버전 번호 (1부터 시작) + revisionDate: string; // 수정 날짜 (ISO 8601 형식) + revisionBy: string; // 수정자 (사용자 ID 또는 이름) + revisionReason?: string; // 수정 사유 (필수) + changedFields?: string[]; // 변경된 필드 목록 (선택) + previousData: any; // 이전 상태 전체 스냅샷 +} +``` + +**예시**: +```json +{ + "revisionNumber": 3, + "revisionDate": "2025-01-15T10:30:00Z", + "revisionBy": "admin@example.com", + "revisionReason": "품목코드 생성 규칙 변경", + "changedFields": ["autoGenerationRule", "codePattern"], + "previousData": { + "id": "PAGE-001", + "pageName": "제품(FG) 등록", + "itemType": "FG", + "sections": [...], + "currentRevision": 2, + "revisions": [...] + } +} +``` + +--- + +### 6.3 버전관리 필드 + +모든 버전관리 대상 엔티티는 다음 필드를 포함합니다: + +```typescript +interface VersionedEntity { + // ... 기본 필드들 + + // 버전관리 필드 + currentRevision: number; // 현재 버전 번호 (기본값: 0) + revisions: ItemRevision[]; // 수정 이력 배열 + isFinal?: boolean; // 최종 확정 여부 (선택) +} +``` + +**예시 (ItemPage with Version)**: +```typescript +export interface ItemPage { + id: string; + pageName: string; + itemType: 'FG' | 'PT' | 'SM' | 'RM' | 'CS'; + sections: ItemSection[]; + isActive: boolean; + absolutePath?: string; + createdAt: string; + updatedAt?: string; + + // 버전관리 필드 + currentRevision: number; // 현재 버전 (예: 3) + revisions: ItemRevision[]; // 수정 이력 배열 + isFinal?: boolean; // 최종 확정 여부 +} +``` + +--- + +### 6.4 버전관리 워크플로우 + +#### 수정 프로세스 + +``` +사용자가 수정 요청 + ↓ +수정 사유 다이얼로그 표시 (필수) + ↓ +사용자가 수정 사유 입력 + ↓ +현재 데이터 전체를 previousData로 저장 + ↓ +currentRevision 증가 (예: 2 → 3) + ↓ +revisions 배열에 새 ItemRevision 추가 + ↓ +수정된 데이터 저장 + ↓ +성공 메시지 표시 +``` + +**React 프로젝트 코드 예시** (ItemManagement.tsx:1637-1651): +```typescript +// 버전 관리 - 수정 시 이력 저장 +const currentRevision = selectedItem.currentRevision || 0; +const newRevisionNumber = currentRevision + 1; + +const revision = { + revisionNumber: newRevisionNumber, + revisionDate: new Date().toISOString().split("T")[0], + revisionBy: "관리자", // TODO: 실제 사용자 정보로 교체 + revisionReason: revisionReason, + previousData: { ...selectedItem } +}; + +pendingUpdates.currentRevision = newRevisionNumber; +pendingUpdates.revisions = [...(selectedItem.revisions || []), revision]; +``` + +--- + +### 6.5 UI/UX 구성 + +#### 수정 사유 입력 다이얼로그 + +```tsx + + + 수정 사유 입력 + + 데이터를 수정하는 이유를 입력해주세요. 이 정보는 수정 이력에 기록됩니다. + + + +
+