# Phase 0: 데이터 마이그레이션 전략 ## 1. 현재 데이터 구조 분석 ### screen_layouts.properties 구조 ```jsonc { // 기본 정보 "type": "component", "componentType": "text-input", // 기존 컴포넌트 타입 // 위치/크기 "position": { "x": 68, "y": 80, "z": 1 }, "size": { "width": 324, "height": 40 }, // 라벨 및 스타일 "label": "품목코드", "style": { "labelColor": "#000000", "labelDisplay": true, "labelFontSize": "14px", "labelFontWeight": "500", "labelMarginBottom": "8px" }, // 데이터 바인딩 "tableName": "order_table", "columnName": "part_code", // 필드 속성 "required": true, "readonly": false, // 컴포넌트별 설정 "componentConfig": { "type": "text-input", "format": "none", "webType": "text", "multiline": false, "placeholder": "텍스트를 입력하세요" }, // 그리드 레이아웃 "gridColumns": 5, "gridRowIndex": 0, "gridColumnStart": 1, "gridColumnSpan": "third", // 기타 "parentId": null } ``` --- ## 2. 마이그레이션 전략: 하이브리드 방식 ### 2.1 비파괴적 전환 (권장) 기존 필드를 유지하면서 새로운 필드를 추가하는 방식 ```jsonc { // 기존 필드 유지 (하위 호환성) "componentType": "text-input", "componentConfig": { ... }, // 신규 필드 추가 "unifiedType": "UnifiedInput", // 새로운 통합 컴포넌트 타입 "unifiedConfig": { // 새로운 설정 구조 "type": "text", "format": "none", "placeholder": "텍스트를 입력하세요" }, // 마이그레이션 메타데이터 "_migration": { "version": "2.0", "migratedAt": "2024-12-19T00:00:00Z", "migratedBy": "system", "originalType": "text-input" } } ``` ### 2.2 렌더링 로직 수정 ```typescript // 렌더러에서 unifiedType 우선 사용 function renderComponent(props: ComponentProps) { // 신규 타입이 있으면 Unified 컴포넌트 사용 if (props.unifiedType) { return ; } // 없으면 기존 레거시 컴포넌트 사용 return ; } ``` --- ## 3. 컴포넌트별 매핑 규칙 ### 3.1 text-input → UnifiedInput ```typescript // AS-IS { "componentType": "text-input", "componentConfig": { "type": "text-input", "format": "none", "webType": "text", "multiline": false, "placeholder": "텍스트를 입력하세요" } } // TO-BE { "unifiedType": "UnifiedInput", "unifiedConfig": { "type": "text", // componentConfig.webType 또는 "text" "format": "none", // componentConfig.format "placeholder": "..." // componentConfig.placeholder } } ``` ### 3.2 number-input → UnifiedInput ```typescript // AS-IS { "componentType": "number-input", "componentConfig": { "type": "number-input", "webType": "number", "min": 0, "max": 100, "step": 1 } } // TO-BE { "unifiedType": "UnifiedInput", "unifiedConfig": { "type": "number", "min": 0, "max": 100, "step": 1 } } ``` ### 3.3 select-basic → UnifiedSelect ```typescript // AS-IS (code 타입) { "componentType": "select-basic", "codeCategory": "ORDER_STATUS", "componentConfig": { "type": "select-basic", "webType": "code", "codeCategory": "ORDER_STATUS" } } // TO-BE { "unifiedType": "UnifiedSelect", "unifiedConfig": { "mode": "dropdown", "source": "code", "codeGroup": "ORDER_STATUS" } } // AS-IS (entity 타입) { "componentType": "select-basic", "componentConfig": { "type": "select-basic", "webType": "entity", "searchable": true, "valueField": "id", "displayField": "name" } } // TO-BE { "unifiedType": "UnifiedSelect", "unifiedConfig": { "mode": "dropdown", "source": "entity", "searchable": true, "valueField": "id", "displayField": "name" } } ``` ### 3.4 date-input → UnifiedDate ```typescript // AS-IS { "componentType": "date-input", "componentConfig": { "type": "date-input", "webType": "date", "format": "YYYY-MM-DD" } } // TO-BE { "unifiedType": "UnifiedDate", "unifiedConfig": { "type": "date", "format": "YYYY-MM-DD" } } ``` --- ## 4. 마이그레이션 스크립트 ### 4.1 자동 마이그레이션 함수 ```typescript // lib/migration/componentMigration.ts interface MigrationResult { success: boolean; unifiedType: string; unifiedConfig: Record; } export function migrateToUnified( componentType: string, componentConfig: Record ): MigrationResult { switch (componentType) { case 'text-input': return { success: true, unifiedType: 'UnifiedInput', unifiedConfig: { type: componentConfig.webType || 'text', format: componentConfig.format || 'none', placeholder: componentConfig.placeholder } }; case 'number-input': return { success: true, unifiedType: 'UnifiedInput', unifiedConfig: { type: 'number', min: componentConfig.min, max: componentConfig.max, step: componentConfig.step } }; case 'select-basic': return { success: true, unifiedType: 'UnifiedSelect', unifiedConfig: { mode: 'dropdown', source: componentConfig.webType || 'static', codeGroup: componentConfig.codeCategory, searchable: componentConfig.searchable, valueField: componentConfig.valueField, displayField: componentConfig.displayField } }; case 'date-input': return { success: true, unifiedType: 'UnifiedDate', unifiedConfig: { type: componentConfig.webType || 'date', format: componentConfig.format } }; default: return { success: false, unifiedType: '', unifiedConfig: {} }; } } ``` ### 4.2 DB 마이그레이션 스크립트 ```sql -- 마이그레이션 백업 테이블 생성 CREATE TABLE screen_layouts_backup_v2 AS SELECT * FROM screen_layouts; -- 마이그레이션 실행 (text-input 예시) UPDATE screen_layouts SET properties = properties || jsonb_build_object( 'unifiedType', 'UnifiedInput', 'unifiedConfig', jsonb_build_object( 'type', COALESCE(properties->'componentConfig'->>'webType', 'text'), 'format', COALESCE(properties->'componentConfig'->>'format', 'none'), 'placeholder', properties->'componentConfig'->>'placeholder' ), '_migration', jsonb_build_object( 'version', '2.0', 'migratedAt', NOW(), 'originalType', 'text-input' ) ) WHERE properties->>'componentType' = 'text-input'; ``` --- ## 5. 롤백 전략 ### 5.1 롤백 스크립트 ```sql -- 마이그레이션 전 상태로 복원 UPDATE screen_layouts sl SET properties = slb.properties FROM screen_layouts_backup_v2 slb WHERE sl.layout_id = slb.layout_id; -- 또는 신규 필드만 제거 UPDATE screen_layouts SET properties = properties - 'unifiedType' - 'unifiedConfig' - '_migration'; ``` ### 5.2 단계적 롤백 ```typescript // 특정 화면만 롤백 async function rollbackScreen(screenId: number) { await db.query(` UPDATE screen_layouts sl SET properties = properties - 'unifiedType' - 'unifiedConfig' - '_migration' WHERE screen_id = $1 `, [screenId]); } ``` --- ## 6. 마이그레이션 일정 | 단계 | 작업 | 대상 | 시점 | |:---:|:---|:---|:---| | 1 | 백업 테이블 생성 | 전체 | Phase 1 시작 전 | | 2 | UnifiedInput 마이그레이션 | text-input, number-input | Phase 1 중 | | 3 | UnifiedSelect 마이그레이션 | select-basic | Phase 1 중 | | 4 | UnifiedDate 마이그레이션 | date-input | Phase 1 중 | | 5 | 검증 및 테스트 | 전체 | Phase 1 완료 후 | | 6 | 레거시 필드 제거 | 전체 | Phase 5 (추후) | --- ## 7. 주의사항 1. **항상 백업 먼저**: 마이그레이션 전 반드시 백업 테이블 생성 2. **점진적 전환**: 한 번에 모든 컴포넌트를 마이그레이션하지 않음 3. **하위 호환성**: 기존 필드 유지로 롤백 가능하게 4. **테스트 필수**: 각 마이그레이션 단계별 화면 테스트