554 lines
17 KiB
Markdown
554 lines
17 KiB
Markdown
|
|
# 본서버 → 개발서버 마이그레이션 가이드
|
||
|
|
|
||
|
|
## 개요
|
||
|
|
|
||
|
|
본 문서는 **본서버(Production)**의 `screen_layouts` (V1) 데이터를 **개발서버(Development)**의 `screen_layouts_v2` 시스템으로 마이그레이션하는 절차를 정의합니다.
|
||
|
|
|
||
|
|
### 마이그레이션 방향
|
||
|
|
```
|
||
|
|
본서버 (Production) 개발서버 (Development)
|
||
|
|
┌─────────────────────┐ ┌─────────────────────┐
|
||
|
|
│ screen_layouts (V1) │ → │ screen_layouts_v2 │
|
||
|
|
│ - 컴포넌트별 레코드 │ │ - 화면당 1개 레코드 │
|
||
|
|
│ - properties JSONB │ │ - layout_data JSONB │
|
||
|
|
└─────────────────────┘ └─────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
### 최종 목표
|
||
|
|
개발서버에서 완성 후 **개발서버 → 본서버**로 배포
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. V1 vs V2 구조 차이
|
||
|
|
|
||
|
|
### 1.1 screen_layouts (V1) - 본서버
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 컴포넌트별 1개 레코드
|
||
|
|
CREATE TABLE screen_layouts (
|
||
|
|
layout_id SERIAL PRIMARY KEY,
|
||
|
|
screen_id INTEGER,
|
||
|
|
component_type VARCHAR(50),
|
||
|
|
component_id VARCHAR(100),
|
||
|
|
properties JSONB, -- 모든 설정값 포함
|
||
|
|
...
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
**특징:**
|
||
|
|
- 화면당 N개 레코드 (컴포넌트 수만큼)
|
||
|
|
- `properties`에 모든 설정 저장 (defaults + overrides 구분 없음)
|
||
|
|
- `menu_objid` 기반 채번/카테고리 관리
|
||
|
|
|
||
|
|
### 1.2 screen_layouts_v2 - 개발서버
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 화면당 1개 레코드
|
||
|
|
CREATE TABLE screen_layouts_v2 (
|
||
|
|
layout_id SERIAL PRIMARY KEY,
|
||
|
|
screen_id INTEGER NOT NULL,
|
||
|
|
company_code VARCHAR(20) NOT NULL,
|
||
|
|
layout_data JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||
|
|
UNIQUE(screen_id, company_code)
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
**layout_data 구조:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"version": "2.0",
|
||
|
|
"components": [
|
||
|
|
{
|
||
|
|
"id": "comp_xxx",
|
||
|
|
"url": "@/lib/registry/components/v2-table-list",
|
||
|
|
"position": { "x": 0, "y": 0 },
|
||
|
|
"size": { "width": 100, "height": 50 },
|
||
|
|
"displayOrder": 0,
|
||
|
|
"overrides": {
|
||
|
|
"tableName": "inspection_standard",
|
||
|
|
"columns": ["id", "name"]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"updatedAt": "2026-02-03T12:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**특징:**
|
||
|
|
- 화면당 1개 레코드
|
||
|
|
- `url` + `overrides` 방식 (Zod 스키마 defaults와 병합)
|
||
|
|
- `table_name + column_name` 기반 채번/카테고리 관리 (전역)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. 데이터 타입 관리 구조 (V2)
|
||
|
|
|
||
|
|
### 2.1 핵심 테이블 관계
|
||
|
|
|
||
|
|
```
|
||
|
|
table_type_columns (컬럼 타입 정의)
|
||
|
|
├── input_type = 'category' → category_values
|
||
|
|
├── input_type = 'numbering' → numbering_rules
|
||
|
|
└── input_type = 'text', 'date', 'number', etc.
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.2 table_type_columns
|
||
|
|
|
||
|
|
각 테이블의 컬럼별 입력 타입을 정의합니다.
|
||
|
|
|
||
|
|
```sql
|
||
|
|
SELECT table_name, column_name, input_type, column_label
|
||
|
|
FROM table_type_columns
|
||
|
|
WHERE input_type IN ('category', 'numbering');
|
||
|
|
```
|
||
|
|
|
||
|
|
**주요 input_type:**
|
||
|
|
| input_type | 설명 | 연결 테이블 |
|
||
|
|
|------------|------|-------------|
|
||
|
|
| text | 텍스트 입력 | - |
|
||
|
|
| number | 숫자 입력 | - |
|
||
|
|
| date | 날짜 입력 | - |
|
||
|
|
| category | 카테고리 드롭다운 | category_values |
|
||
|
|
| numbering | 자동 채번 | numbering_rules |
|
||
|
|
| entity | 엔티티 검색 | - |
|
||
|
|
|
||
|
|
### 2.3 category_values (카테고리 관리)
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 카테고리 값 조회
|
||
|
|
SELECT value_id, table_name, column_name, value_code, value_label,
|
||
|
|
parent_value_id, depth, company_code
|
||
|
|
FROM category_values
|
||
|
|
WHERE table_name = 'inspection_standard'
|
||
|
|
AND column_name = 'inspection_method'
|
||
|
|
AND company_code = 'COMPANY_7';
|
||
|
|
```
|
||
|
|
|
||
|
|
**V1 vs V2 차이:**
|
||
|
|
| 구분 | V1 | V2 |
|
||
|
|
|------|----|----|
|
||
|
|
| 키 | menu_objid | table_name + column_name |
|
||
|
|
| 범위 | 화면별 | 전역 (테이블.컬럼별) |
|
||
|
|
| 계층 | 단일 | 3단계 (대/중/소분류) |
|
||
|
|
|
||
|
|
### 2.4 numbering_rules (채번 규칙)
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 채번 규칙 조회
|
||
|
|
SELECT rule_id, rule_name, table_name, column_name, separator,
|
||
|
|
reset_period, current_sequence, company_code
|
||
|
|
FROM numbering_rules
|
||
|
|
WHERE company_code = 'COMPANY_7';
|
||
|
|
```
|
||
|
|
|
||
|
|
**연결 방식:**
|
||
|
|
```
|
||
|
|
table_type_columns.detail_settings = '{"numberingRuleId": "rule-xxx"}'
|
||
|
|
↓
|
||
|
|
numbering_rules.rule_id = "rule-xxx"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. 컴포넌트 매핑
|
||
|
|
|
||
|
|
### 3.1 기본 컴포넌트 매핑
|
||
|
|
|
||
|
|
| V1 (본서버) | V2 (개발서버) | 비고 |
|
||
|
|
|-------------|---------------|------|
|
||
|
|
| table-list | v2-table-list | 테이블 목록 |
|
||
|
|
| button-primary | v2-button-primary | 버튼 |
|
||
|
|
| text-input | v2-text-input | 텍스트 입력 |
|
||
|
|
| select-basic | v2-select | 드롭다운 |
|
||
|
|
| date-input | v2-date-input | 날짜 입력 |
|
||
|
|
| entity-search-input | v2-entity-search | 엔티티 검색 |
|
||
|
|
| tabs-widget | v2-tabs-widget | 탭 |
|
||
|
|
|
||
|
|
### 3.2 특수 컴포넌트 매핑
|
||
|
|
|
||
|
|
| V1 (본서버) | V2 (개발서버) | 마이그레이션 방식 |
|
||
|
|
|-------------|---------------|-------------------|
|
||
|
|
| category-manager | v2-category-manager | table_name 기반으로 변경 |
|
||
|
|
| numbering-rule | v2-numbering-rule | table_name 기반으로 변경 |
|
||
|
|
| 모달 화면 | overlay 통합 | 부모 화면에 통합 |
|
||
|
|
|
||
|
|
### 3.3 모달 처리 방식 변경
|
||
|
|
|
||
|
|
**V1 (본서버):**
|
||
|
|
```
|
||
|
|
화면 A (screen_id: 142) - 검사장비관리
|
||
|
|
└── 버튼 클릭 → 화면 B (screen_id: 143) - 검사장비 등록모달
|
||
|
|
```
|
||
|
|
|
||
|
|
**V2 (개발서버):**
|
||
|
|
```
|
||
|
|
화면 A (screen_id: 142) - 검사장비관리
|
||
|
|
└── v2-dialog-form 컴포넌트로 모달 통합
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. 마이그레이션 절차
|
||
|
|
|
||
|
|
### 4.1 사전 분석
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 1. 본서버 화면 목록 확인
|
||
|
|
SELECT sd.screen_id, sd.screen_code, sd.screen_name, sd.table_name,
|
||
|
|
COUNT(sl.layout_id) as component_count
|
||
|
|
FROM screen_definitions sd
|
||
|
|
LEFT JOIN screen_layouts sl ON sd.screen_id = sl.screen_id
|
||
|
|
WHERE sd.screen_code LIKE 'COMPANY_7_%'
|
||
|
|
AND sd.screen_name LIKE '%품질%'
|
||
|
|
GROUP BY sd.screen_id, sd.screen_code, sd.screen_name, sd.table_name;
|
||
|
|
|
||
|
|
-- 2. 개발서버 V2 화면 현황 확인
|
||
|
|
SELECT sd.screen_id, sd.screen_code, sd.screen_name,
|
||
|
|
sv2.layout_data IS NOT NULL as has_v2_layout
|
||
|
|
FROM screen_definitions sd
|
||
|
|
LEFT JOIN screen_layouts_v2 sv2 ON sd.screen_id = sv2.screen_id
|
||
|
|
WHERE sd.company_code = 'COMPANY_7';
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.2 Step 1: screen_definitions 동기화
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 본서버에만 있는 화면을 개발서버에 추가
|
||
|
|
INSERT INTO screen_definitions (screen_code, screen_name, table_name, company_code, ...)
|
||
|
|
SELECT screen_code, screen_name, table_name, company_code, ...
|
||
|
|
FROM [본서버].screen_definitions
|
||
|
|
WHERE screen_code NOT IN (SELECT screen_code FROM screen_definitions);
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.3 Step 2: V1 → V2 레이아웃 변환
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// 변환 로직 (pseudo-code)
|
||
|
|
async function convertV1toV2(screenId: number, companyCode: string) {
|
||
|
|
// 1. V1 레이아웃 조회
|
||
|
|
const v1Layouts = await getV1Layouts(screenId);
|
||
|
|
|
||
|
|
// 2. V2 형식으로 변환
|
||
|
|
const v2Layout = {
|
||
|
|
version: "2.0",
|
||
|
|
components: v1Layouts.map(v1 => ({
|
||
|
|
id: v1.component_id,
|
||
|
|
url: mapComponentUrl(v1.component_type),
|
||
|
|
position: { x: v1.position_x, y: v1.position_y },
|
||
|
|
size: { width: v1.width, height: v1.height },
|
||
|
|
displayOrder: v1.display_order,
|
||
|
|
overrides: extractOverrides(v1.properties)
|
||
|
|
})),
|
||
|
|
updatedAt: new Date().toISOString()
|
||
|
|
};
|
||
|
|
|
||
|
|
// 3. V2 테이블에 저장
|
||
|
|
await saveV2Layout(screenId, companyCode, v2Layout);
|
||
|
|
}
|
||
|
|
|
||
|
|
function mapComponentUrl(v1Type: string): string {
|
||
|
|
const mapping = {
|
||
|
|
'table-list': '@/lib/registry/components/v2-table-list',
|
||
|
|
'button-primary': '@/lib/registry/components/v2-button-primary',
|
||
|
|
'category-manager': '@/lib/registry/components/v2-category-manager',
|
||
|
|
'numbering-rule': '@/lib/registry/components/v2-numbering-rule',
|
||
|
|
// ... 기타 매핑
|
||
|
|
};
|
||
|
|
return mapping[v1Type] || `@/lib/registry/components/v2-${v1Type}`;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.4 Step 3: 카테고리 데이터 마이그레이션
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 본서버 카테고리 데이터 → 개발서버 category_values
|
||
|
|
INSERT INTO category_values (
|
||
|
|
table_name, column_name, value_code, value_label,
|
||
|
|
value_order, parent_value_id, depth, company_code
|
||
|
|
)
|
||
|
|
SELECT
|
||
|
|
-- V1 카테고리 데이터를 table_name + column_name 기반으로 변환
|
||
|
|
'inspection_standard' as table_name,
|
||
|
|
'inspection_method' as column_name,
|
||
|
|
value_code,
|
||
|
|
value_label,
|
||
|
|
sort_order,
|
||
|
|
NULL as parent_value_id,
|
||
|
|
1 as depth,
|
||
|
|
'COMPANY_7' as company_code
|
||
|
|
FROM [본서버_카테고리_데이터];
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.5 Step 4: 채번 규칙 마이그레이션
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 본서버 채번 규칙 → 개발서버 numbering_rules
|
||
|
|
INSERT INTO numbering_rules (
|
||
|
|
rule_id, rule_name, table_name, column_name,
|
||
|
|
separator, reset_period, current_sequence, company_code
|
||
|
|
)
|
||
|
|
SELECT
|
||
|
|
rule_id,
|
||
|
|
rule_name,
|
||
|
|
'inspection_standard' as table_name,
|
||
|
|
'inspection_code' as column_name,
|
||
|
|
separator,
|
||
|
|
reset_period,
|
||
|
|
0 as current_sequence, -- 시퀀스 초기화
|
||
|
|
'COMPANY_7' as company_code
|
||
|
|
FROM [본서버_채번_규칙];
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.6 Step 5: table_type_columns 설정
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 카테고리 컬럼 설정
|
||
|
|
UPDATE table_type_columns
|
||
|
|
SET input_type = 'category'
|
||
|
|
WHERE table_name = 'inspection_standard'
|
||
|
|
AND column_name = 'inspection_method'
|
||
|
|
AND company_code = 'COMPANY_7';
|
||
|
|
|
||
|
|
-- 채번 컬럼 설정
|
||
|
|
UPDATE table_type_columns
|
||
|
|
SET
|
||
|
|
input_type = 'numbering',
|
||
|
|
detail_settings = '{"numberingRuleId": "rule-xxx"}'
|
||
|
|
WHERE table_name = 'inspection_standard'
|
||
|
|
AND column_name = 'inspection_code'
|
||
|
|
AND company_code = 'COMPANY_7';
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. 품질관리 메뉴 마이그레이션 현황
|
||
|
|
|
||
|
|
### 5.1 화면 매핑 현황
|
||
|
|
|
||
|
|
| 본서버 코드 | 화면명 | 테이블 | 개발서버 상태 | 비고 |
|
||
|
|
|-------------|--------|--------|---------------|------|
|
||
|
|
| COMPANY_7_126 | 검사정보 관리 | inspection_standard | ✅ V2 존재 | 컴포넌트 수 확인 필요 |
|
||
|
|
| COMPANY_7_127 | 품목옵션 설정 | - | ✅ V2 존재 | v2-category-manager 사용중 |
|
||
|
|
| COMPANY_7_138 | 카테고리 설정 | inspection_standard | ❌ 누락 | V2: table_name 기반으로 변경 |
|
||
|
|
| COMPANY_7_139 | 코드 설정 | inspection_standard | ❌ 누락 | V2: table_name 기반으로 변경 |
|
||
|
|
| COMPANY_7_142 | 검사장비 관리 | inspection_equipment_mng | ❌ 누락 | 모달 통합 필요 |
|
||
|
|
| COMPANY_7_143 | 검사장비 등록모달 | inspection_equipment_mng | ❌ 누락 | COMPANY_7_142에 통합 |
|
||
|
|
| COMPANY_7_144 | 불량기준 정보 | defect_standard_mng | ❌ 누락 | 모달 통합 필요 |
|
||
|
|
| COMPANY_7_145 | 불량기준 등록모달 | defect_standard_mng | ❌ 누락 | COMPANY_7_144에 통합 |
|
||
|
|
|
||
|
|
### 5.2 카테고리/채번 컬럼 현황
|
||
|
|
|
||
|
|
**inspection_standard:**
|
||
|
|
| 컬럼 | input_type | 라벨 |
|
||
|
|
|------|------------|------|
|
||
|
|
| inspection_method | category | 검사방법 |
|
||
|
|
| unit | category | 단위 |
|
||
|
|
| apply_type | category | 적용구분 |
|
||
|
|
| inspection_type | category | 유형 |
|
||
|
|
|
||
|
|
**inspection_equipment_mng:**
|
||
|
|
| 컬럼 | input_type | 라벨 |
|
||
|
|
|------|------------|------|
|
||
|
|
| equipment_type | category | 장비유형 |
|
||
|
|
| installation_location | category | 설치장소 |
|
||
|
|
| equipment_status | category | 장비상태 |
|
||
|
|
|
||
|
|
**defect_standard_mng:**
|
||
|
|
| 컬럼 | input_type | 라벨 |
|
||
|
|
|------|------------|------|
|
||
|
|
| defect_type | category | 불량유형 |
|
||
|
|
| severity | category | 심각도 |
|
||
|
|
| inspection_type | category | 검사유형 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. 자동화 스크립트
|
||
|
|
|
||
|
|
### 6.1 마이그레이션 실행 스크립트
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// backend-node/src/scripts/migrateV1toV2.ts
|
||
|
|
import { getPool } from "../database/db";
|
||
|
|
|
||
|
|
interface MigrationResult {
|
||
|
|
screenCode: string;
|
||
|
|
success: boolean;
|
||
|
|
message: string;
|
||
|
|
componentCount?: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
async function migrateScreenToV2(
|
||
|
|
screenCode: string,
|
||
|
|
companyCode: string
|
||
|
|
): Promise<MigrationResult> {
|
||
|
|
const pool = getPool();
|
||
|
|
|
||
|
|
try {
|
||
|
|
// 1. V1 레이아웃 조회 (본서버에서)
|
||
|
|
const v1Result = await pool.query(`
|
||
|
|
SELECT sl.*, sd.table_name, sd.screen_name
|
||
|
|
FROM screen_layouts sl
|
||
|
|
JOIN screen_definitions sd ON sl.screen_id = sd.screen_id
|
||
|
|
WHERE sd.screen_code = $1
|
||
|
|
ORDER BY sl.display_order
|
||
|
|
`, [screenCode]);
|
||
|
|
|
||
|
|
if (v1Result.rows.length === 0) {
|
||
|
|
return { screenCode, success: false, message: "V1 레이아웃 없음" };
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. V2 형식으로 변환
|
||
|
|
const components = v1Result.rows
|
||
|
|
.filter(row => row.component_type !== '_metadata')
|
||
|
|
.map(row => ({
|
||
|
|
id: row.component_id || `comp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||
|
|
url: mapComponentUrl(row.component_type),
|
||
|
|
position: { x: row.position_x || 0, y: row.position_y || 0 },
|
||
|
|
size: { width: row.width || 100, height: row.height || 50 },
|
||
|
|
displayOrder: row.display_order || 0,
|
||
|
|
overrides: extractOverrides(row.properties, row.component_type)
|
||
|
|
}));
|
||
|
|
|
||
|
|
const layoutData = {
|
||
|
|
version: "2.0",
|
||
|
|
components,
|
||
|
|
migratedFrom: "V1",
|
||
|
|
migratedAt: new Date().toISOString()
|
||
|
|
};
|
||
|
|
|
||
|
|
// 3. 개발서버 V2 테이블에 저장
|
||
|
|
const screenId = v1Result.rows[0].screen_id;
|
||
|
|
|
||
|
|
await pool.query(`
|
||
|
|
INSERT INTO screen_layouts_v2 (screen_id, company_code, layout_data)
|
||
|
|
VALUES ($1, $2, $3)
|
||
|
|
ON CONFLICT (screen_id, company_code)
|
||
|
|
DO UPDATE SET layout_data = $3, updated_at = NOW()
|
||
|
|
`, [screenId, companyCode, JSON.stringify(layoutData)]);
|
||
|
|
|
||
|
|
return {
|
||
|
|
screenCode,
|
||
|
|
success: true,
|
||
|
|
message: "마이그레이션 완료",
|
||
|
|
componentCount: components.length
|
||
|
|
};
|
||
|
|
} catch (error: any) {
|
||
|
|
return { screenCode, success: false, message: error.message };
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function mapComponentUrl(v1Type: string): string {
|
||
|
|
const mapping: Record<string, string> = {
|
||
|
|
'table-list': '@/lib/registry/components/v2-table-list',
|
||
|
|
'button-primary': '@/lib/registry/components/v2-button-primary',
|
||
|
|
'text-input': '@/lib/registry/components/v2-text-input',
|
||
|
|
'select-basic': '@/lib/registry/components/v2-select',
|
||
|
|
'date-input': '@/lib/registry/components/v2-date-input',
|
||
|
|
'entity-search-input': '@/lib/registry/components/v2-entity-search',
|
||
|
|
'category-manager': '@/lib/registry/components/v2-category-manager',
|
||
|
|
'numbering-rule': '@/lib/registry/components/v2-numbering-rule',
|
||
|
|
'tabs-widget': '@/lib/registry/components/v2-tabs-widget',
|
||
|
|
'textarea-basic': '@/lib/registry/components/v2-textarea',
|
||
|
|
};
|
||
|
|
return mapping[v1Type] || `@/lib/registry/components/v2-${v1Type}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
function extractOverrides(properties: any, componentType: string): Record<string, any> {
|
||
|
|
if (!properties) return {};
|
||
|
|
|
||
|
|
// V2 Zod 스키마 defaults와 비교하여 다른 값만 추출
|
||
|
|
// (실제 구현 시 각 컴포넌트의 defaultConfig와 비교)
|
||
|
|
const overrides: Record<string, any> = {};
|
||
|
|
|
||
|
|
// 필수 설정만 추출
|
||
|
|
if (properties.tableName) overrides.tableName = properties.tableName;
|
||
|
|
if (properties.columns) overrides.columns = properties.columns;
|
||
|
|
if (properties.label) overrides.label = properties.label;
|
||
|
|
if (properties.onClick) overrides.onClick = properties.onClick;
|
||
|
|
|
||
|
|
return overrides;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. 검증 체크리스트
|
||
|
|
|
||
|
|
### 7.1 마이그레이션 전
|
||
|
|
|
||
|
|
- [ ] 본서버 화면 목록 확인
|
||
|
|
- [ ] 개발서버 기존 V2 데이터 백업
|
||
|
|
- [ ] 컴포넌트 매핑 테이블 검토
|
||
|
|
- [ ] 카테고리/채번 데이터 분석
|
||
|
|
|
||
|
|
### 7.2 마이그레이션 후
|
||
|
|
|
||
|
|
- [ ] screen_definitions 동기화 확인
|
||
|
|
- [ ] screen_layouts_v2 데이터 생성 확인
|
||
|
|
- [ ] 컴포넌트 렌더링 테스트
|
||
|
|
- [ ] 카테고리 드롭다운 동작 확인
|
||
|
|
- [ ] 채번 규칙 동작 확인
|
||
|
|
- [ ] 저장/수정/삭제 기능 테스트
|
||
|
|
|
||
|
|
### 7.3 모달 통합 확인
|
||
|
|
|
||
|
|
- [ ] 기존 모달 화면 → overlay 통합 완료
|
||
|
|
- [ ] 부모-자식 데이터 연동 확인
|
||
|
|
- [ ] 모달 열기/닫기 동작 확인
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 8. 롤백 계획
|
||
|
|
|
||
|
|
마이그레이션 실패 시 롤백 절차:
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 1. V2 레이아웃 롤백
|
||
|
|
DELETE FROM screen_layouts_v2
|
||
|
|
WHERE screen_id IN (
|
||
|
|
SELECT screen_id FROM screen_definitions
|
||
|
|
WHERE screen_code LIKE 'COMPANY_7_%'
|
||
|
|
);
|
||
|
|
|
||
|
|
-- 2. 추가된 screen_definitions 롤백
|
||
|
|
DELETE FROM screen_definitions
|
||
|
|
WHERE screen_code IN ('신규_추가된_코드들')
|
||
|
|
AND company_code = 'COMPANY_7';
|
||
|
|
|
||
|
|
-- 3. category_values 롤백
|
||
|
|
DELETE FROM category_values
|
||
|
|
WHERE company_code = 'COMPANY_7'
|
||
|
|
AND created_at > '[마이그레이션_시작_시간]';
|
||
|
|
|
||
|
|
-- 4. numbering_rules 롤백
|
||
|
|
DELETE FROM numbering_rules
|
||
|
|
WHERE company_code = 'COMPANY_7'
|
||
|
|
AND created_at > '[마이그레이션_시작_시간]';
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 9. 참고 자료
|
||
|
|
|
||
|
|
### 관련 코드 파일
|
||
|
|
|
||
|
|
- **V2 Category Manager**: `frontend/lib/registry/components/v2-category-manager/`
|
||
|
|
- **V2 Numbering Rule**: `frontend/lib/registry/components/v2-numbering-rule/`
|
||
|
|
- **Category Service**: `backend-node/src/services/categoryTreeService.ts`
|
||
|
|
- **Numbering Service**: `backend-node/src/services/numberingRuleService.ts`
|
||
|
|
|
||
|
|
### 관련 문서
|
||
|
|
|
||
|
|
- [V2 컴포넌트 분석 가이드](../V2_컴포넌트_분석_가이드.md)
|
||
|
|
- [V2 컴포넌트 연동 가이드](../V2_컴포넌트_연동_가이드.md)
|
||
|
|
- [화면 개발 표준 가이드](../screen-implementation-guide/SCREEN_DEVELOPMENT_STANDARD.md)
|
||
|
|
- [컴포넌트 레이아웃 V2 아키텍처](./COMPONENT_LAYOUT_V2_ARCHITECTURE.md)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 변경 이력
|
||
|
|
|
||
|
|
| 날짜 | 작성자 | 내용 |
|
||
|
|
|------|--------|------|
|
||
|
|
| 2026-02-03 | DDD1542 | 초안 작성 |
|