497 lines
20 KiB
Markdown
497 lines
20 KiB
Markdown
|
|
# 컴포넌트 관리 시스템 리팩토링 제안서
|
|||
|
|
|
|||
|
|
## 1. 현재 문제점
|
|||
|
|
|
|||
|
|
### 1.1 핵심 문제
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
컴포넌트 오류 발생 시 → 코드 수정 → 해당 컴포넌트 사용하는 모든 화면에 영향
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
현재 구조에서는:
|
|||
|
|
- 컴포넌트 코드가 **프론트엔드에 하드코딩**되어 있음
|
|||
|
|
- 설정이 **JSONB로 각 화면마다 중복 저장**됨
|
|||
|
|
- 컴포넌트 수정 시 **개별 화면 데이터 마이그레이션 필요**
|
|||
|
|
|
|||
|
|
### 1.2 구체적 문제 사례
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
예: v2-table-list 컴포넌트의 pagination 구조 변경 시
|
|||
|
|
|
|||
|
|
현재 방식:
|
|||
|
|
1. 프론트엔드 코드 수정
|
|||
|
|
2. screen_layouts 테이블의 모든 해당 컴포넌트 JSON 수정 필요
|
|||
|
|
3. 100개 화면에서 사용 중이면 100개 레코드 마이그레이션
|
|||
|
|
4. 테스트 및 검증 공수 발생
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 개선 방안 비교
|
|||
|
|
|
|||
|
|
### 방안 1: URL 기반 코드 참조 + 설정 분리
|
|||
|
|
|
|||
|
|
#### 개념
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 컴포넌트 코드 (URL 참조) │
|
|||
|
|
├─────────────────────────────────────────────────────────────┤
|
|||
|
|
│ 경로: /lib/registry/components/v2-table-list/ │
|
|||
|
|
│ - 상대경로: ./v2-table-list │
|
|||
|
|
│ - 절대경로: @/lib/registry/components/v2-table-list │
|
|||
|
|
└─────────────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 설정 분리 저장 │
|
|||
|
|
├────────────────────────┬────────────────────────────────────┤
|
|||
|
|
│ 공용 설정 (1개) │ 회사별 설정 (N개) │
|
|||
|
|
│ │ │
|
|||
|
|
│ - 기본 pagination │ - A회사: pageSize=20 │
|
|||
|
|
│ - 기본 toolbar │ - B회사: pageSize=50 │
|
|||
|
|
│ - 기본 columns 구조 │ - C회사: 특수 컬럼 추가 │
|
|||
|
|
└────────────────────────┴────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 데이터베이스 구조 (예시)
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
-- 1. 컴포넌트 정의 테이블 (공용)
|
|||
|
|
CREATE TABLE component_definitions (
|
|||
|
|
component_id VARCHAR(50) PRIMARY KEY, -- 'v2-table-list'
|
|||
|
|
component_path VARCHAR(200) NOT NULL, -- '@/lib/registry/components/v2-table-list'
|
|||
|
|
component_name VARCHAR(100), -- '테이블 리스트'
|
|||
|
|
category VARCHAR(50), -- 'display'
|
|||
|
|
version VARCHAR(20), -- '2.1.0'
|
|||
|
|
default_config JSONB, -- 기본 설정 (공용)
|
|||
|
|
is_active CHAR(1) DEFAULT 'Y'
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 2. 회사별 컴포넌트 설정 오버라이드
|
|||
|
|
CREATE TABLE company_component_config (
|
|||
|
|
id SERIAL PRIMARY KEY,
|
|||
|
|
company_code VARCHAR(50) NOT NULL,
|
|||
|
|
component_id VARCHAR(50) REFERENCES component_definitions(component_id),
|
|||
|
|
config_override JSONB, -- 회사별 오버라이드 설정
|
|||
|
|
UNIQUE(company_code, component_id)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 3. 화면 레이아웃 (간소화)
|
|||
|
|
CREATE TABLE screen_layouts (
|
|||
|
|
layout_id SERIAL PRIMARY KEY,
|
|||
|
|
screen_id INTEGER,
|
|||
|
|
component_id VARCHAR(50) REFERENCES component_definitions(component_id),
|
|||
|
|
position_x INTEGER,
|
|||
|
|
position_y INTEGER,
|
|||
|
|
width INTEGER,
|
|||
|
|
height INTEGER,
|
|||
|
|
instance_config JSONB -- 해당 인스턴스만의 설정 (최소화)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 설정 병합 로직
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 설정 우선순위: 인스턴스 설정 > 회사 설정 > 공용 기본 설정
|
|||
|
|
function getComponentConfig(componentId: string, companyCode: string, instanceConfig: any) {
|
|||
|
|
const defaultConfig = await getDefaultConfig(componentId); // 공용
|
|||
|
|
const companyConfig = await getCompanyConfig(componentId, companyCode); // 회사별
|
|||
|
|
|
|||
|
|
return deepMerge(defaultConfig, companyConfig, instanceConfig);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 장점
|
|||
|
|
|
|||
|
|
| 장점 | 설명 |
|
|||
|
|
|-----|-----|
|
|||
|
|
| **코드 단일 관리** | 컴포넌트 코드는 한 곳에서만 관리 (URL 참조) |
|
|||
|
|
| **설정 계층화** | 공용 → 회사 → 인스턴스 순으로 설정 상속 |
|
|||
|
|
| **유연한 커스터마이징** | 회사별로 다른 기본값 설정 가능 |
|
|||
|
|
| **마이그레이션 최소화** | 공용 설정 변경 시 한 곳만 수정 |
|
|||
|
|
| **버전 관리** | 컴포넌트 버전별 호환성 관리 가능 |
|
|||
|
|
|
|||
|
|
#### 단점
|
|||
|
|
|
|||
|
|
| 단점 | 설명 |
|
|||
|
|
|-----|-----|
|
|||
|
|
| **복잡한 병합 로직** | 3단계 설정 병합 로직 필요 |
|
|||
|
|
| **런타임 오버헤드** | 설정 조회 시 여러 테이블 JOIN |
|
|||
|
|
| **디버깅 어려움** | 최종 설정이 어디서 온 것인지 추적 필요 |
|
|||
|
|
| **기존 데이터 마이그레이션** | 기존 JSONB 데이터를 분리 저장 필요 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 방안 2: 정형화된 테이블 (컬럼 파싱)
|
|||
|
|
|
|||
|
|
#### 개념
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 컴포넌트별 전용 테이블 생성 │
|
|||
|
|
└─────────────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
┌─────────────────────┼─────────────────────┐
|
|||
|
|
▼ ▼ ▼
|
|||
|
|
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
|||
|
|
│ table_list │ │ button_config │ │ split_panel │
|
|||
|
|
│ _components │ │ _components │ │ _components │
|
|||
|
|
├───────────────┤ ├───────────────┤ ├───────────────┤
|
|||
|
|
│ id │ │ id │ │ id │
|
|||
|
|
│ screen_id │ │ screen_id │ │ screen_id │
|
|||
|
|
│ table_name │ │ action_type │ │ left_table │
|
|||
|
|
│ page_size │ │ target_screen │ │ right_table │
|
|||
|
|
│ show_checkbox │ │ button_text │ │ split_ratio │
|
|||
|
|
│ show_excel │ │ icon │ │ transfer_type │
|
|||
|
|
│ ... │ │ ... │ │ ... │
|
|||
|
|
└───────────────┘ └───────────────┘ └───────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 데이터베이스 구조 (예시)
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
-- 1. 공통 컴포넌트 메타 테이블
|
|||
|
|
CREATE TABLE component_instances (
|
|||
|
|
instance_id SERIAL PRIMARY KEY,
|
|||
|
|
screen_id INTEGER NOT NULL,
|
|||
|
|
component_type VARCHAR(50) NOT NULL, -- 'table-list', 'button', 'split-panel'
|
|||
|
|
position_x INTEGER,
|
|||
|
|
position_y INTEGER,
|
|||
|
|
width INTEGER,
|
|||
|
|
height INTEGER,
|
|||
|
|
company_code VARCHAR(50)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 2. 테이블 리스트 컴포넌트 전용 테이블
|
|||
|
|
CREATE TABLE component_table_list (
|
|||
|
|
id SERIAL PRIMARY KEY,
|
|||
|
|
instance_id INTEGER REFERENCES component_instances(instance_id),
|
|||
|
|
table_name VARCHAR(100),
|
|||
|
|
page_size INTEGER DEFAULT 20,
|
|||
|
|
show_checkbox BOOLEAN DEFAULT true,
|
|||
|
|
checkbox_multiple BOOLEAN DEFAULT true,
|
|||
|
|
show_excel BOOLEAN DEFAULT true,
|
|||
|
|
show_refresh BOOLEAN DEFAULT true,
|
|||
|
|
show_search BOOLEAN DEFAULT true,
|
|||
|
|
header_style VARCHAR(20) DEFAULT 'default',
|
|||
|
|
row_height VARCHAR(20) DEFAULT 'normal',
|
|||
|
|
auto_load BOOLEAN DEFAULT true
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 3. 테이블 리스트 컬럼 설정 테이블
|
|||
|
|
CREATE TABLE component_table_list_columns (
|
|||
|
|
id SERIAL PRIMARY KEY,
|
|||
|
|
table_list_id INTEGER REFERENCES component_table_list(id),
|
|||
|
|
column_name VARCHAR(100) NOT NULL,
|
|||
|
|
display_name VARCHAR(100),
|
|||
|
|
visible BOOLEAN DEFAULT true,
|
|||
|
|
sortable BOOLEAN DEFAULT true,
|
|||
|
|
searchable BOOLEAN DEFAULT false,
|
|||
|
|
width INTEGER,
|
|||
|
|
align VARCHAR(10) DEFAULT 'left',
|
|||
|
|
format VARCHAR(20) DEFAULT 'text',
|
|||
|
|
display_order INTEGER DEFAULT 0,
|
|||
|
|
fixed VARCHAR(10), -- 'left', 'right', null
|
|||
|
|
editable BOOLEAN DEFAULT true
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 4. 버튼 컴포넌트 전용 테이블
|
|||
|
|
CREATE TABLE component_button (
|
|||
|
|
id SERIAL PRIMARY KEY,
|
|||
|
|
instance_id INTEGER REFERENCES component_instances(instance_id),
|
|||
|
|
button_text VARCHAR(100),
|
|||
|
|
action_type VARCHAR(50), -- 'save', 'delete', 'navigate', 'popup'
|
|||
|
|
target_screen_id INTEGER,
|
|||
|
|
target_url VARCHAR(500),
|
|||
|
|
numbering_rule_id VARCHAR(100),
|
|||
|
|
variant VARCHAR(20) DEFAULT 'default',
|
|||
|
|
size VARCHAR(10) DEFAULT 'md',
|
|||
|
|
icon VARCHAR(50)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 5. 분할 패널 컴포넌트 전용 테이블
|
|||
|
|
CREATE TABLE component_split_panel (
|
|||
|
|
id SERIAL PRIMARY KEY,
|
|||
|
|
instance_id INTEGER REFERENCES component_instances(instance_id),
|
|||
|
|
left_table_name VARCHAR(100),
|
|||
|
|
right_table_name VARCHAR(100),
|
|||
|
|
split_ratio INTEGER DEFAULT 50,
|
|||
|
|
transfer_enabled BOOLEAN DEFAULT true,
|
|||
|
|
transfer_button_label VARCHAR(100)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 장점
|
|||
|
|
|
|||
|
|
| 장점 | 설명 |
|
|||
|
|
|-----|-----|
|
|||
|
|
| **타입 안정성** | 각 컬럼이 명확한 데이터 타입 |
|
|||
|
|
| **SQL 쿼리 용이** | `WHERE page_size > 50` 같은 직접 쿼리 가능 |
|
|||
|
|
| **인덱스 최적화** | 특정 컬럼에 인덱스 생성 가능 |
|
|||
|
|
| **데이터 무결성** | 외래키, CHECK 제약 조건 적용 가능 |
|
|||
|
|
| **일괄 수정 용이** | `UPDATE component_table_list SET page_size = 30 WHERE ...` |
|
|||
|
|
| **명확한 스키마** | 어떤 설정이 있는지 테이블 구조로 명확히 파악 |
|
|||
|
|
|
|||
|
|
#### 단점
|
|||
|
|
|
|||
|
|
| 단점 | 설명 |
|
|||
|
|
|-----|-----|
|
|||
|
|
| **테이블 폭발** | 70+ 컴포넌트 × 하위 설정 = 100개 이상 테이블 |
|
|||
|
|
| **스키마 변경 필수** | 새 설정 추가 시 ALTER TABLE 필요 |
|
|||
|
|
| **JOIN 복잡도** | 화면 로드 시 여러 테이블 JOIN |
|
|||
|
|
| **유연성 저하** | 임시/실험적 설정 저장 어려움 |
|
|||
|
|
| **마이그레이션 대규모** | 기존 JSONB → 정형 테이블 대규모 작업 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 상세 비교 분석
|
|||
|
|
|
|||
|
|
### 3.1 개발 공수 비교
|
|||
|
|
|
|||
|
|
| 항목 | 방안 1 (URL + 설정 분리) | 방안 2 (정형 테이블) |
|
|||
|
|
|-----|------------------------|-------------------|
|
|||
|
|
| 초기 설계 | 중간 | 높음 (테이블 설계) |
|
|||
|
|
| 마이그레이션 | 중간 | 매우 높음 |
|
|||
|
|
| 프론트엔드 수정 | 중간 | 높음 (쿼리 변경) |
|
|||
|
|
| 백엔드 수정 | 중간 | 높음 (ORM/쿼리) |
|
|||
|
|
| 테스트 | 중간 | 높음 |
|
|||
|
|
|
|||
|
|
### 3.2 유지보수 비교
|
|||
|
|
|
|||
|
|
| 항목 | 방안 1 | 방안 2 |
|
|||
|
|
|-----|-------|-------|
|
|||
|
|
| 컴포넌트 버그 수정 | 쉬움 (코드만) | 쉬움 (코드만) |
|
|||
|
|
| 새 설정 추가 | 쉬움 (JSON 확장) | 어려움 (ALTER TABLE) |
|
|||
|
|
| 일괄 설정 변경 | 중간 (JSON 쿼리) | 쉬움 (SQL UPDATE) |
|
|||
|
|
| 디버깅 | 중간 | 쉬움 (명확한 컬럼) |
|
|||
|
|
|
|||
|
|
### 3.3 성능 비교
|
|||
|
|
|
|||
|
|
| 항목 | 방안 1 | 방안 2 |
|
|||
|
|
|-----|-------|-------|
|
|||
|
|
| 읽기 성능 | 중간 (설정 병합) | 좋음 (직접 조회) |
|
|||
|
|
| 쓰기 성능 | 좋음 (단일 JSONB) | 중간 (여러 테이블) |
|
|||
|
|
| 검색 성능 | 나쁨 (JSONB 검색) | 좋음 (인덱스) |
|
|||
|
|
| 캐싱 | 좋음 (계층 캐싱) | 중간 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 하이브리드 방안 제안
|
|||
|
|
|
|||
|
|
두 방안의 장점을 결합한 **하이브리드 접근법**:
|
|||
|
|
|
|||
|
|
### 4.1 구조
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 컴포넌트 메타 (정형 테이블) │
|
|||
|
|
├─────────────────────────────────────────────────────────────┤
|
|||
|
|
│ component_id | path | name | category | version │
|
|||
|
|
└─────────────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 설정 계층 (공용 → 회사 → 인스턴스) │
|
|||
|
|
├────────────────────────┬────────────────────────────────────┤
|
|||
|
|
│ 공용 기본 설정 (JSONB) │ 회사별 오버라이드 (JSONB) │
|
|||
|
|
└────────────────────────┴────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 핵심 설정만 정형 컬럼 (자주 검색/수정) │
|
|||
|
|
├─────────────────────────────────────────────────────────────┤
|
|||
|
|
│ table_name | page_size | is_active | ... │
|
|||
|
|
│ + extra_config JSONB (나머지 설정) │
|
|||
|
|
└─────────────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 데이터베이스 구조
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
-- 1. 컴포넌트 정의 (공용)
|
|||
|
|
CREATE TABLE component_definitions (
|
|||
|
|
component_id VARCHAR(50) PRIMARY KEY,
|
|||
|
|
component_path VARCHAR(200) NOT NULL,
|
|||
|
|
component_name VARCHAR(100),
|
|||
|
|
category VARCHAR(50),
|
|||
|
|
version VARCHAR(20),
|
|||
|
|
default_config JSONB, -- 기본 설정
|
|||
|
|
schema_version INTEGER DEFAULT 1, -- 설정 스키마 버전
|
|||
|
|
is_active CHAR(1) DEFAULT 'Y'
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 2. 컴포넌트 인스턴스 (핵심 필드 정형화 + 나머지 JSONB)
|
|||
|
|
CREATE TABLE component_instances (
|
|||
|
|
instance_id SERIAL PRIMARY KEY,
|
|||
|
|
screen_id INTEGER NOT NULL,
|
|||
|
|
company_code VARCHAR(50) NOT NULL,
|
|||
|
|
component_id VARCHAR(50) REFERENCES component_definitions(component_id),
|
|||
|
|
|
|||
|
|
-- 공통 정형 필드 (자주 검색/수정)
|
|||
|
|
position_x INTEGER,
|
|||
|
|
position_y INTEGER,
|
|||
|
|
width INTEGER,
|
|||
|
|
height INTEGER,
|
|||
|
|
is_visible BOOLEAN DEFAULT true,
|
|||
|
|
display_order INTEGER DEFAULT 0,
|
|||
|
|
|
|||
|
|
-- 컴포넌트 타입별 핵심 필드 (자주 검색/수정)
|
|||
|
|
target_table VARCHAR(100), -- table-list, split-panel 등
|
|||
|
|
action_type VARCHAR(50), -- button
|
|||
|
|
|
|||
|
|
-- 나머지 상세 설정 (유연성)
|
|||
|
|
config_override JSONB, -- 인스턴스별 설정 오버라이드
|
|||
|
|
|
|||
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|||
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 3. 회사별 컴포넌트 기본 설정
|
|||
|
|
CREATE TABLE company_component_defaults (
|
|||
|
|
id SERIAL PRIMARY KEY,
|
|||
|
|
company_code VARCHAR(50) NOT NULL,
|
|||
|
|
component_id VARCHAR(50) REFERENCES component_definitions(component_id),
|
|||
|
|
config_override JSONB, -- 회사별 기본값 오버라이드
|
|||
|
|
UNIQUE(company_code, component_id)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 인덱스 최적화
|
|||
|
|
CREATE INDEX idx_instances_screen ON component_instances(screen_id);
|
|||
|
|
CREATE INDEX idx_instances_company ON component_instances(company_code);
|
|||
|
|
CREATE INDEX idx_instances_component ON component_instances(component_id);
|
|||
|
|
CREATE INDEX idx_instances_target_table ON component_instances(target_table);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 설정 조회 로직
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
async function getComponentFullConfig(
|
|||
|
|
instanceId: number,
|
|||
|
|
companyCode: string
|
|||
|
|
): Promise<ComponentConfig> {
|
|||
|
|
// 1. 인스턴스 + 컴포넌트 정의 조회 (단일 쿼리)
|
|||
|
|
const result = await query(`
|
|||
|
|
SELECT
|
|||
|
|
i.*,
|
|||
|
|
d.default_config,
|
|||
|
|
c.config_override as company_override
|
|||
|
|
FROM component_instances i
|
|||
|
|
JOIN component_definitions d ON i.component_id = d.component_id
|
|||
|
|
LEFT JOIN company_component_defaults c
|
|||
|
|
ON c.component_id = i.component_id
|
|||
|
|
AND c.company_code = i.company_code
|
|||
|
|
WHERE i.instance_id = $1
|
|||
|
|
`, [instanceId]);
|
|||
|
|
|
|||
|
|
// 2. 설정 병합 (공용 → 회사 → 인스턴스)
|
|||
|
|
return deepMerge(
|
|||
|
|
result.default_config, // 공용 기본값
|
|||
|
|
result.company_override, // 회사별 오버라이드
|
|||
|
|
result.config_override // 인스턴스별 오버라이드
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.4 일괄 수정 예시
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
-- 특정 테이블을 사용하는 모든 컴포넌트의 page_size 변경
|
|||
|
|
UPDATE component_instances
|
|||
|
|
SET config_override = jsonb_set(
|
|||
|
|
COALESCE(config_override, '{}'),
|
|||
|
|
'{pagination,pageSize}',
|
|||
|
|
'30'
|
|||
|
|
)
|
|||
|
|
WHERE target_table = 'user_info';
|
|||
|
|
|
|||
|
|
-- 특정 회사의 모든 테이블 리스트 기본값 변경
|
|||
|
|
UPDATE company_component_defaults
|
|||
|
|
SET config_override = jsonb_set(
|
|||
|
|
COALESCE(config_override, '{}'),
|
|||
|
|
'{pagination,pageSize}',
|
|||
|
|
'50'
|
|||
|
|
)
|
|||
|
|
WHERE company_code = 'COMPANY_A'
|
|||
|
|
AND component_id = 'v2-table-list';
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 권장사항
|
|||
|
|
|
|||
|
|
### 5.1 단기 (1-2주)
|
|||
|
|
|
|||
|
|
**방안 1 (URL + 설정 분리)** 권장
|
|||
|
|
|
|||
|
|
이유:
|
|||
|
|
- 현재 JSONB 구조와 호환성 유지
|
|||
|
|
- 마이그레이션 공수 최소화
|
|||
|
|
- 점진적 적용 가능
|
|||
|
|
|
|||
|
|
### 5.2 장기 (1-2개월)
|
|||
|
|
|
|||
|
|
**하이브리드 방안** 권장
|
|||
|
|
|
|||
|
|
이유:
|
|||
|
|
- 자주 검색/수정되는 핵심 필드만 정형화
|
|||
|
|
- 나머지는 JSONB로 유연성 유지
|
|||
|
|
- 성능과 유연성의 균형
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 마이그레이션 로드맵
|
|||
|
|
|
|||
|
|
### Phase 1: 컴포넌트 정의 분리 (1주)
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
-- 기존 컴포넌트를 component_definitions로 추출
|
|||
|
|
INSERT INTO component_definitions (component_id, component_path, default_config)
|
|||
|
|
SELECT DISTINCT
|
|||
|
|
componentType,
|
|||
|
|
CONCAT('@/lib/registry/components/', componentType),
|
|||
|
|
'{}' -- 기본값은 코드에서 정의
|
|||
|
|
FROM (
|
|||
|
|
SELECT properties->>'componentType' as componentType
|
|||
|
|
FROM screen_layouts
|
|||
|
|
WHERE properties->>'componentType' IS NOT NULL
|
|||
|
|
) t;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Phase 2: 회사별 설정 분리 (1주)
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 각 회사별 공통 패턴 분석 후 company_component_defaults 생성
|
|||
|
|
async function extractCompanyDefaults(companyCode: string) {
|
|||
|
|
// 해당 회사의 컴포넌트 사용 패턴 분석
|
|||
|
|
// 가장 많이 사용되는 설정을 기본값으로 추출
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Phase 3: 인스턴스 설정 최소화 (2주)
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 인스턴스별 설정에서 기본값과 동일한 부분 제거
|
|||
|
|
async function minimizeInstanceConfig(instanceId: number) {
|
|||
|
|
const fullConfig = currentConfig;
|
|||
|
|
const defaultConfig = getDefaultConfig();
|
|||
|
|
const companyConfig = getCompanyConfig();
|
|||
|
|
|
|||
|
|
// 차이나는 부분만 저장
|
|||
|
|
const minimalConfig = getDiff(fullConfig, merge(defaultConfig, companyConfig));
|
|||
|
|
await saveInstanceConfig(instanceId, minimalConfig);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 결론
|
|||
|
|
|
|||
|
|
| 방안 | 적합한 상황 |
|
|||
|
|
|-----|-----------|
|
|||
|
|
| **방안 1 (URL + 설정 분리)** | 빠른 개선이 필요하고, 현재 구조와의 호환성 중요 시 |
|
|||
|
|
| **방안 2 (정형 테이블)** | 완전한 재설계가 가능하고, 장기적 유지보수 최우선 시 |
|
|||
|
|
| **하이브리드** | 두 방안의 장점을 모두 원하고, 충분한 개발 리소스 있을 시 |
|
|||
|
|
|
|||
|
|
**권장**: 단기적으로 **방안 1**을 적용하고, 안정화 후 **하이브리드**로 전환
|