# 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": { ... },
  
  // 신규 필드 추가
  "v2Type": "V2Input",        // 새로운 통합 컴포넌트 타입
  "v2Config": {                    // 새로운 설정 구조
    "type": "text",
    "format": "none",
    "placeholder": "텍스트를 입력하세요"
  },
  
  // 마이그레이션 메타데이터
  "_migration": {
    "version": "2.0",
    "migratedAt": "2024-12-19T00:00:00Z",
    "migratedBy": "system",
    "originalType": "text-input"
  }
}
```

### 2.2 렌더링 로직 수정

```typescript
// 렌더러에서 v2Type 우선 사용
function renderComponent(props: ComponentProps) {
  // 신규 타입이 있으면 V2 컴포넌트 사용
  if (props.v2Type) {
    return <V2ComponentRenderer 
      type={props.v2Type} 
      config={props.v2Config} 
    />;
  }
  
  // 없으면 기존 레거시 컴포넌트 사용
  return <LegacyComponentRenderer 
    type={props.componentType} 
    config={props.componentConfig} 
  />;
}
```

---

## 3. 컴포넌트별 매핑 규칙

### 3.1 text-input → V2Input

```typescript
// AS-IS
{
  "componentType": "text-input",
  "componentConfig": {
    "type": "text-input",
    "format": "none",
    "webType": "text",
    "multiline": false,
    "placeholder": "텍스트를 입력하세요"
  }
}

// TO-BE
{
  "v2Type": "V2Input",
  "v2Config": {
    "type": "text",           // componentConfig.webType 또는 "text"
    "format": "none",         // componentConfig.format
    "placeholder": "..."      // componentConfig.placeholder
  }
}
```

### 3.2 number-input → V2Input

```typescript
// AS-IS
{
  "componentType": "number-input",
  "componentConfig": {
    "type": "number-input",
    "webType": "number",
    "min": 0,
    "max": 100,
    "step": 1
  }
}

// TO-BE
{
  "v2Type": "V2Input",
  "v2Config": {
    "type": "number",
    "min": 0,
    "max": 100,
    "step": 1
  }
}
```

### 3.3 select-basic → V2Select

```typescript
// AS-IS (code 타입)
{
  "componentType": "select-basic",
  "codeCategory": "ORDER_STATUS",
  "componentConfig": {
    "type": "select-basic",
    "webType": "code",
    "codeCategory": "ORDER_STATUS"
  }
}

// TO-BE
{
  "v2Type": "V2Select",
  "v2Config": {
    "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
{
  "v2Type": "V2Select",
  "v2Config": {
    "mode": "dropdown",
    "source": "entity",
    "searchable": true,
    "valueField": "id",
    "displayField": "name"
  }
}
```

### 3.4 date-input → V2Date

```typescript
// AS-IS
{
  "componentType": "date-input",
  "componentConfig": {
    "type": "date-input",
    "webType": "date",
    "format": "YYYY-MM-DD"
  }
}

// TO-BE
{
  "v2Type": "V2Date",
  "v2Config": {
    "type": "date",
    "format": "YYYY-MM-DD"
  }
}
```

---

## 4. 마이그레이션 스크립트

### 4.1 자동 마이그레이션 함수

```typescript
// lib/migration/componentMigration.ts

interface MigrationResult {
  success: boolean;
  v2Type: string;
  v2Config: Record<string, any>;
}

export function migrateToV2(
  componentType: string,
  componentConfig: Record<string, any>
): MigrationResult {
  
  switch (componentType) {
    case 'text-input':
      return {
        success: true,
        v2Type: 'V2Input',
        v2Config: {
          type: componentConfig.webType || 'text',
          format: componentConfig.format || 'none',
          placeholder: componentConfig.placeholder
        }
      };
      
    case 'number-input':
      return {
        success: true,
        v2Type: 'V2Input',
        v2Config: {
          type: 'number',
          min: componentConfig.min,
          max: componentConfig.max,
          step: componentConfig.step
        }
      };
      
    case 'select-basic':
      return {
        success: true,
        v2Type: 'V2Select',
        v2Config: {
          mode: 'dropdown',
          source: componentConfig.webType || 'static',
          codeGroup: componentConfig.codeCategory,
          searchable: componentConfig.searchable,
          valueField: componentConfig.valueField,
          displayField: componentConfig.displayField
        }
      };
      
    case 'date-input':
      return {
        success: true,
        v2Type: 'V2Date',
        v2Config: {
          type: componentConfig.webType || 'date',
          format: componentConfig.format
        }
      };
      
    default:
      return {
        success: false,
        v2Type: '',
        v2Config: {}
      };
  }
}
```

### 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(
  'v2Type', 'V2Input',
  'v2Config', 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 - 'v2Type' - 'v2Config' - '_migration';
```

### 5.2 단계적 롤백

```typescript
// 특정 화면만 롤백
async function rollbackScreen(screenId: number) {
  await db.query(`
    UPDATE screen_layouts sl
    SET properties = properties - 'v2Type' - 'v2Config' - '_migration'
    WHERE screen_id = $1
  `, [screenId]);
}
```

---

## 6. 마이그레이션 일정

| 단계 | 작업 | 대상 | 시점 |
|:---:|:---|:---|:---|
| 1 | 백업 테이블 생성 | 전체 | Phase 1 시작 전 |
| 2 | V2Input 마이그레이션 | text-input, number-input | Phase 1 중 |
| 3 | V2Select 마이그레이션 | select-basic | Phase 1 중 |
| 4 | V2Date 마이그레이션 | date-input | Phase 1 중 |
| 5 | 검증 및 테스트 | 전체 | Phase 1 완료 후 |
| 6 | 레거시 필드 제거 | 전체 | Phase 5 (추후) |

---

## 7. 주의사항

1. **항상 백업 먼저**: 마이그레이션 전 반드시 백업 테이블 생성
2. **점진적 전환**: 한 번에 모든 컴포넌트를 마이그레이션하지 않음
3. **하위 호환성**: 기존 필드 유지로 롤백 가능하게
4. **테스트 필수**: 각 마이그레이션 단계별 화면 테스트


