ERP-node/docs/screen-designer-upgrade-pla...

1027 lines
37 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 화면 디자이너 V2 - 재설계 계획서
> 작성일: 2026-02-27
> 방향: 기존 기능 형태는 인정하되, 새로운 방식으로 재설립
> 핵심 철학: "컴포넌트를 계속 추가하는 시스템"에서 "소수의 강력한 컴포넌트로 유연하게 조합하는 시스템"으로
---
## 1. 현재 시스템의 근본적 문제
### 1.1 "컴포넌트 폭증" 문제
현재 등록된 컴포넌트 수: **70개 이상**
```
기본 입력 13종 + V2 입력 4종 + V2 데이터 5종
기존 레이아웃 8종 + V2 레이아웃 16종 + 특수 10종+
ConfigPanel 26개 + Renderer 21개 + 위젯 10종+
```
**문제**: 새 기능이 필요할 때마다 아래 작업을 반복해야 함
```
새 기능 요청 → ComponentDefinition 작성
→ Renderer 작성
→ ConfigPanel 작성
→ index.ts에 import 추가
→ 테스트
→ 약 5~8개 파일, 500~1500줄 추가
```
거래처별 품목정보? → `customer-item-mapping` 컴포넌트 추가
BOM 트리? → `v2-bom-tree` + `v2-bom-item-editor` 추가
세금계산서? → `tax-invoice-list` 추가
타임라인? → `v2-timeline-scheduler` 추가
**매번 개발자가 코드를 작성해야만 새 기능이 가능**하다.
### 1.2 설정 패널의 사용성 문제
ConfigPanel이 26개이고, 각각 UI 구조/용어/설정 방식이 다름:
| 패널 | 설정 항목 | 사용자 관점 |
|------|-----------|------------|
| TextConfigPanel | inputType, placeholder, maxLength... | "이게 뭐지?" |
| EntityConfigPanel | joinTable, joinColumn, displayColumn... | "조인? 컬럼?" |
| SelectConfigPanel | optionSource, staticOptions, dynamicApi... | "동적 API?" |
| FlowWidgetConfigPanel | flowDefinitionId, stepMapping... | "스텝 매핑?" |
| ButtonConfigPanel | actionType, dataFlow, targetScreen... | "데이터 플로우?" |
**사용자(현업 관리자)가 이 설정들을 이해하고 사용하기가 극히 어려움.**
### 1.3 컴포넌트 간 연결의 제한성
현재 컴포넌트들은 대부분 **독립적**으로 동작:
- 거래처를 선택하면 → 납품처가 자동으로 바뀌어야 하는데 → 별도 코드 필요
- 마스터 테이블에서 행을 선택하면 → 디테일 테이블이 자동 필터링 → SplitPanel로 하드코딩
- 버튼 클릭하면 → 특정 필드 값에 따라 다른 동작 → FlowWidget으로만 가능
**컴포넌트 간 동적 상호작용을 사용자가 설정할 방법이 없음.**
### 1.4 V1/V2/기존/신규 혼재
```typescript
// 같은 테이블 컴포넌트가 3종류
import "./table-list/TableListRenderer"; // 기존
import "./v2-table-list/TableListRenderer"; // V2
import "./v2-table-grouped/TableGroupedRenderer"; // V2 그룹화
```
동일 기능의 컴포넌트가 "기존 호환"이라는 이유로 중복 존재.
어떤 걸 써야 하는지 사용자도 개발자도 혼란.
---
## 2. 새로운 비전
### 2.1 핵심 원칙
```
❌ 기존: "기능 = 컴포넌트" → 기능이 늘어나면 컴포넌트가 늘어남
✅ 새롭게: "기능 = 설정" → 소수의 메타 컴포넌트 + 풍부한 설정으로 무한 확장
```
```
❌ 기존: "개발자가 만들어주는 화면" → 요청 → 개발 → 배포 → 1~3일
✅ 새롭게: "사용자가 조립하는 화면" → 드래그 → 설정 → 바로 사용 → 5분
```
### 2.2 메타 컴포넌트 체계
70개 이상의 컴포넌트를 **7개의 메타 컴포넌트**로 통합:
| 메타 컴포넌트 | 대체 범위 | 핵심 능력 |
|---------------|-----------|-----------|
| **Field** | text, number, date, select, entity, checkbox, radio, file, textarea, code, numbering | 테이블 컬럼의 webType에 따라 자동 변환 |
| **DataView** | table-list, repeater, card-display, pivot-grid, bom-tree, aggregation, timeline | 같은 데이터를 테이블/카드/트리/피벗/타임라인 등 뷰 모드 전환 |
| **Action** | button-primary, flow-widget, related-data-buttons | 클릭 시 저장/삭제/조회/이동/모달/API 호출 등 설정 |
| **Layout** | split-panel, tabs, section-card, section-paper, conditional-container, accordion | 영역 분할, 탭, 섹션, 조건부 표시 |
| **Display** | text-display, divider, badge, alert, stats-card, chart, image, progress | 읽기 전용 정보 표시 |
| **Search** | table-search, advanced-filters, autocomplete | 데이터 필터링/검색 |
| **Modal** | universal-form-modal, repeat-screen-modal | 데이터 입력/편집 팝업 |
### 2.3 "테이블 드롭 → 화면 완성" 흐름
**현재** (약 15분):
```
1. 테이블 컬럼을 하나씩 드래그
2. 각 컬럼마다 컴포넌트 타입 확인
3. entity 컬럼이면 → EntityConfigPanel에서 조인 테이블, 조인 컬럼 수동 설정
4. select 컬럼이면 → SelectConfigPanel에서 옵션 소스 수동 설정
5. 버튼 컴포넌트 별도 추가
6. 데이터 테이블 별도 추가
7. 각각 설정...
```
**새로운 방식** (약 2분):
```
1. 테이블을 통째로 드롭
2. 시스템이 자동으로:
- 컬럼 타입(webType) 분석 → Field 컴포넌트 자동 생성
- entity 컬럼 → 조인 정보 자동 감지 (FK 관계)
- select 컬럼 → 코드 테이블 자동 연결
- CRUD 버튼 자동 생성 (Action 컴포넌트)
- DataView(테이블 뷰) 자동 생성
3. 사용자는 세부 설정만 조정
```
---
## 3. 메타 컴포넌트 상세 설계
### 3.1 Field (통합 입력 컴포넌트)
**대체 대상**: text-input, number-input, date-input, select-basic, checkbox-basic, radio-basic, entity-search-input, file-upload, textarea, code-input, numbering-rule, v2-input, v2-select, v2-date, v2-file-upload, autocomplete-search-input, toggle-switch, slider
**핵심 개념**: 하나의 Field 컴포넌트가 `webType`에 따라 모양과 동작이 바뀜
```typescript
interface FieldConfig {
// 자동 결정 (테이블 컬럼 기반)
webType: "text" | "number" | "date" | "datetime" | "select" | "entity"
| "checkbox" | "radio" | "file" | "textarea" | "code" | "numbering"
| "email" | "tel" | "url" | "password" | "color" | "toggle" | "slider";
// 데이터 바인딩 (자동)
tableName: string;
columnName: string;
// 조인 정보 (entity 타입일 때 자동 감지)
join?: {
targetTable: string; // FK가 참조하는 테이블
targetColumn: string; // PK 컬럼
displayColumn: string; // 표시할 컬럼 (자동: name 또는 첫 번째 text 컬럼)
additionalColumns?: string[]; // 추가 표시 컬럼
searchable?: boolean; // 검색 가능 여부
filterBy?: Record<string, string>; // 다른 Field 값으로 필터링
};
// select 옵션 (자동 감지)
options?: {
source: "code_table" | "static" | "api";
codeCategory?: string; // code_table일 때
staticList?: { value: string; label: string }[];
apiEndpoint?: string;
};
// 공통 설정
label?: string;
placeholder?: string;
required?: boolean;
readonly?: boolean;
disabled?: boolean;
defaultValue?: any;
// 검증
validation?: {
min?: number;
max?: number;
minLength?: number;
maxLength?: number;
pattern?: string;
customMessage?: string;
};
// 연동 (다른 Field와의 관계)
linkedTo?: {
fieldId: string; // 연결된 Field의 ID
relationship: "filter" | "copy" | "calculate" | "show_hide";
expression?: string; // 계산식 또는 조건식
}[];
// 레이아웃
display?: {
width?: string; // "full" | "half" | "third" | "quarter" | 커스텀
labelPosition?: "top" | "left" | "hidden";
helpText?: string;
};
}
```
**사용자 설정 UI (새로운 방식)**:
```
┌─────────────────────────────────────┐
│ Field 설정 │
├─────────────────────────────────────┤
│ 표시 형태: [텍스트 ▼] │ ← 드롭다운 하나로 webType 전환
│ │
│ 라벨: [수주번호 ] │
│ 필수: [✓] 읽기전용: [ ] │
│ │
│ ─── 데이터 연결 ──── │
│ 테이블: sales_order_mng (자동) │
│ 컬럼: order_no (자동) │
│ │
│ ─── 연동 설정 ──── │
│ + 다른 필드와 연결 추가 │
│ [거래처] 변경 시 → [납품처] 필터링 │
│ [수량] × [단가] → [금액] 자동계산 │
│ │
│ ─── 표시 ──── │
│ 너비: [절반 ▼] │
│ 도움말: [주문 번호를 입력하세요] │
└─────────────────────────────────────┘
```
**핵심 차이점**:
- 기존: 컴포넌트 타입 선택 → 타입별 ConfigPanel → 복잡한 설정
- 새로운: Field 하나 놓으면 → webType 자동 감지 → 간단한 통합 설정
---
### 3.2 DataView (통합 데이터 뷰)
**대체 대상**: table-list, v2-table-list, v2-repeater, card-display, v2-card-display, pivot-grid, v2-pivot-grid, bom-tree, aggregation-widget, v2-aggregation-widget, v2-table-grouped, v2-timeline-scheduler, simple-repeater-table, modal-repeater-table
**핵심 개념**: 하나의 데이터 소스를 여러 뷰 모드로 전환
```typescript
interface DataViewConfig {
// 데이터 소스
dataSource: {
tableName: string;
columns: ColumnConfig[]; // 표시할 컬럼 목록
defaultSort?: { column: string; direction: "asc" | "desc" };
defaultFilter?: FilterConfig[];
pageSize?: number;
// 마스터-디테일 자동 연결
masterField?: string; // 상위 DataView의 어떤 컬럼과 연결
detailForeignKey?: string; // 하위 테이블의 FK 컬럼
};
// 뷰 모드 (사용자가 런타임에 전환 가능)
viewMode: "table" | "card" | "list" | "tree" | "pivot" | "timeline" | "kanban" | "calendar";
allowedViewModes?: string[]; // 허용된 뷰 모드 목록
// 테이블 뷰 설정
tableConfig?: {
showRowNumber?: boolean;
showCheckbox?: boolean;
stickyHeader?: boolean;
groupBy?: string[]; // 그룹화 컬럼
summaryColumns?: string[]; // 합계 표시 컬럼
editableColumns?: string[]; // 인라인 편집 가능 컬럼
frozenColumns?: number; // 고정 컬럼 수
};
// 카드 뷰 설정
cardConfig?: {
titleColumn: string;
descriptionColumn?: string;
imageColumn?: string;
columnsPerRow?: 2 | 3 | 4;
cardStyle?: "compact" | "standard" | "detailed";
};
// 트리 뷰 설정
treeConfig?: {
parentColumn: string;
childColumn: string;
labelColumn: string;
expandLevel?: number;
};
// 피벗 설정
pivotConfig?: {
rowFields: string[];
columnFields: string[];
valueFields: { column: string; aggregation: "sum" | "count" | "avg" | "min" | "max" }[];
};
// CRUD 동작 (Action 컴포넌트와 자동 연결)
actions?: {
create?: boolean;
read?: boolean;
update?: boolean;
delete?: boolean;
export?: boolean;
import?: boolean;
};
// 검색/필터 (Search 컴포넌트와 자동 연결)
searchable?: boolean;
filterColumns?: string[];
}
```
**사용자 설정 UI**:
```
┌─────────────────────────────────────┐
│ DataView 설정 │
├─────────────────────────────────────┤
│ 테이블: [sales_order_mng ▼] │
│ │
│ 뷰 모드: [테이블] [카드] [트리] │ ← 클릭 한 번으로 전환
│ ☑테이블 ☑카드 ☐트리 │ ← 허용 모드 체크
│ │
│ ─── 컬럼 선택 ──── │
│ ☑ 수주번호 표시명: 수주번호 │
│ ☑ 거래처 표시명: 거래처 │
│ ☑ 수주수량 표시명: 수량 합계☑│
│ ☐ 생성일 (숨김) │
│ [↕ 드래그로 순서 변경] │
│ │
│ ─── 기능 ──── │
│ ☑ 행 번호 ☑ 체크박스 ☑ 검색 │
│ ☑ 등록 ☑ 수정 ☑ 삭제 │
│ ☐ 엑셀 내보내기 ☐ 가져오기 │
│ │
│ ─── 연결 ──── │
│ 마스터: [없음 ▼] │ ← 다른 DataView 선택 시
│ 연결 키: [customer_code ▼] │ 자동 마스터-디테일
└─────────────────────────────────────┘
```
---
### 3.3 Action (통합 액션 컴포넌트)
**대체 대상**: button-primary, v2-button-primary, flow-widget, related-data-buttons
**핵심 개념**: 하나의 Action 컴포넌트에 여러 동작을 설정으로 정의
```typescript
interface ActionConfig {
// 표시
label: string;
variant: "default" | "outline" | "destructive" | "ghost";
icon?: string;
position?: "toolbar" | "inline" | "floating" | "context-menu";
// 동작 정의 (파이프라인 방식 - 순차 실행)
steps: ActionStep[];
// 실행 조건
enableCondition?: {
type: "always" | "selected" | "field_value" | "expression";
fieldId?: string;
operator?: "eq" | "ne" | "gt" | "lt" | "empty" | "not_empty";
value?: any;
expression?: string;
};
// 확인 대화상자
confirmDialog?: {
title: string;
message: string;
confirmText?: string;
cancelText?: string;
variant?: "default" | "destructive";
};
}
type ActionStep =
| { type: "save"; target: string } // 데이터 저장
| { type: "delete"; target: string } // 데이터 삭제
| { type: "refresh"; target: string } // 데이터 새로고침
| { type: "navigate"; screenId: number } // 화면 이동
| { type: "openModal"; modalId: string } // 모달 열기
| { type: "setField"; fieldId: string; value: any } // 필드 값 설정
| { type: "api"; method: string; endpoint: string; body?: any } // API 호출
| { type: "flowMove"; flowId: number; stepId: number } // 플로우 이동
| { type: "export"; format: "excel" | "csv" | "pdf" } // 내보내기
| { type: "validate"; target: string } // 유효성 검사
| { type: "toast"; message: string; variant: "success" | "error" | "warning" }; // 알림
```
**사용자 설정 UI**:
```
┌─────────────────────────────────────┐
│ Action 설정 │
├─────────────────────────────────────┤
│ 버튼명: [저장 ] │
│ 스타일: [기본●] [외곽] [위험] [고스트]│
│ 아이콘: [Save ▼] │
│ │
│ ─── 동작 순서 ──── │
│ 1. [유효성 검사 ▼] → 주문 폼 │
│ 2. [데이터 저장 ▼] → sales_order │
│ 3. [알림 ▼] → "저장 완료" │
│ 4. [새로고침 ▼] → 주문 목록 │
│ [+ 동작 추가] │
│ │
│ ─── 실행 조건 ──── │
│ [행 선택 시만 ▼] │
│ │
│ ─── 확인 ──── │
│ ☑ 실행 전 확인 대화상자 │
│ 제목: [저장 확인] │
│ 메시지: [변경사항을 저장합니다] │
└─────────────────────────────────────┘
```
---
### 3.4 Layout (통합 레이아웃)
**대체 대상**: split-panel-layout, v2-split-panel-layout, tabs, v2-tabs, section-card, v2-section-card, section-paper, v2-section-paper, conditional-container, accordion, screen-split-panel, repeat-container
```typescript
interface LayoutConfig {
mode: "columns" | "rows" | "tabs" | "accordion" | "card" | "conditional";
// columns/rows 모드
areas?: {
id: string;
label?: string;
size?: string; // "1fr", "300px", "auto"
minSize?: string;
maxSize?: string;
collapsible?: boolean;
resizable?: boolean; // 드래그로 크기 조절
}[];
// tabs 모드
tabs?: {
id: string;
label: string;
icon?: string;
closable?: boolean;
lazy?: boolean; // 탭 전환 시 지연 로드
}[];
// conditional 모드 (조건에 따라 영역 표시/숨김)
conditions?: {
areaId: string;
showWhen: {
fieldId: string;
operator: "eq" | "ne" | "in" | "not_in";
value: any;
};
}[];
// 공통
gap?: number;
padding?: number;
bordered?: boolean;
title?: string;
}
```
---
### 3.5 Display (통합 표시 컴포넌트)
**대체 대상**: text-display, v2-text-display, divider-line, v2-divider-line, badge, alert, stats-card, chart, image, progress-bar, v2-media, v2-split-line
```typescript
interface DisplayConfig {
displayType: "text" | "heading" | "divider" | "badge" | "alert" | "stat"
| "chart" | "image" | "progress" | "spacer" | "html";
// 데이터 바인딩 (선택)
dataBinding?: {
tableName?: string;
columnName?: string;
expression?: string; // 계산식: "{total_amount} / {quantity}"
format?: string; // 숫자/날짜 포맷
};
// 텍스트 설정
text?: {
content: string;
size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
weight?: "normal" | "medium" | "semibold" | "bold";
color?: string;
align?: "left" | "center" | "right";
};
// 차트 설정
chart?: {
chartType: "bar" | "line" | "pie" | "donut" | "area";
dataSource: string;
xAxis: string;
yAxis: string[];
colors?: string[];
};
// 통계 카드
stat?: {
value: string;
label: string;
change?: string;
changeType?: "increase" | "decrease" | "neutral";
icon?: string;
};
}
```
---
### 3.6 Search (통합 검색)
**대체 대상**: table-search-widget, v2-table-search-widget, AdvancedSearchFilters
```typescript
interface SearchConfig {
// 연결된 DataView
targetDataView: string;
// 검색 모드
mode: "simple" | "advanced" | "combined";
// 검색 필드
fields?: {
columnName: string;
label: string;
searchType: "text" | "exact" | "range" | "select" | "date_range" | "entity";
defaultExpanded?: boolean;
}[];
// 퀵 필터 (버튼 형태)
quickFilters?: {
label: string;
filter: { column: string; operator: string; value: any };
}[];
}
```
---
### 3.7 Modal (통합 모달)
**대체 대상**: universal-form-modal, repeat-screen-modal, selected-items-detail-input
```typescript
interface ModalConfig {
// 트리거
trigger: "button" | "row_click" | "row_double_click" | "action";
// 모달 내부
content: {
type: "form" | "screen" | "custom";
// form: 필드 자동 구성
formConfig?: {
tableName: string;
mode: "create" | "edit" | "view";
columns: string[]; // 표시할 컬럼
layout?: "single" | "two_column";
};
// screen: 다른 화면 임베딩
screenId?: number;
// 데이터 전달
passData?: {
from: string; // 현재 화면의 필드/컬럼
to: string; // 모달 내부의 필드/컬럼
}[];
};
// 크기
size?: "sm" | "md" | "lg" | "xl" | "full";
// 닫힐 때 동작
onClose?: ActionStep[];
}
```
---
## 4. 컴포넌트 간 동적 연동 시스템
### 4.1 현재의 한계
```
[거래처 Field] → 독립 동작 ← [납품처 Field]
연결 없음
```
### 4.2 새로운 연동 시스템: Reactive Bindings
```typescript
interface ReactiveBinding {
id: string;
source: {
componentId: string;
event: "change" | "select" | "click" | "load";
field?: string;
};
target: {
componentId: string;
action: "filter" | "setValue" | "show" | "hide" | "enable" | "disable" | "refresh";
field?: string;
};
transform?: {
type: "direct" | "lookup" | "calculate" | "condition";
expression?: string;
};
}
```
**사용자가 설정하는 방식**:
```
┌─────────────────────────────────────────────┐
│ 연동 설정 │
├─────────────────────────────────────────────┤
│ │
│ [거래처 ●]─── 변경 시 ───→[납품처 ●] │
│ └ 필터링: customer_code 일치 │
│ │
│ [수량 ●]──┐ │
│ ├─ 계산 ──→[금액 ●] │
│ [단가 ●]──┘ 수량 × 단가 │
│ │
│ [상태 ●]─── "출고완료" 일 때 ──→[삭제 ●] │
│ └ 비활성화 │
│ │
│ [+ 새 연동 추가] │
└─────────────────────────────────────────────┘
```
### 4.3 마스터-디테일 자동 연결
현재는 SplitPanel + 하드코딩된 이벤트 처리가 필요하지만,
새로운 시스템에서는:
```
DataView(마스터: 수주목록)
↕ 자동 연결 (FK: order_id)
DataView(디테일: 수주상세품목)
```
**설정 방법**: DataView의 `dataSource.masterField` 하나만 선택하면 자동 연결
---
## 5. 통합 설정 패널 재설계
### 5.1 현재 → 새로운 방식
**현재**: 26개의 각기 다른 ConfigPanel
**새로운**: 1개의 통합 설정 패널 (UnifiedConfigPanel)
```
┌─────────────────────────────────────┐
│ 📋 설정 [×] │
├─────────────────────────────────────┤
│ [기본] [데이터] [표시] [연동] [조건]│ ← 5개 탭으로 통일
├─────────────────────────────────────┤
│ │
│ ◆ 기본 탭 │
│ 컴포넌트 유형: Field │
│ 표시 형태: [텍스트 ▼] │
│ 라벨: [수주번호] │
│ 필수: ☑ 읽기전용: ☐ │
│ │
│ ◆ 데이터 탭 │
│ 테이블: sales_order_mng │
│ 컬럼: order_no │
│ 기본값: [자동생성] │
│ │
│ ◆ 표시 탭 │
│ 너비: [━━━━━━○━━] 50% │
│ 라벨 위치: [좌측 ▼] │
│ 도움말: [...] │
│ │
│ ◆ 연동 탭 │
│ 거래처 변경 시 → 납품처 필터링 │
│ [+ 연동 추가] │
│ │
│ ◆ 조건 탭 │
│ 표시 조건: [항상 ▼] │
│ 활성 조건: [항상 ▼] │
└─────────────────────────────────────┘
```
### 5.2 설정 난이도별 UI 분리
```
[간편 모드] ← 기본 (현업 관리자용)
라벨, 필수, 읽기전용, 너비 정도만
[상세 모드] ← 토글로 전환 (파워유저용)
검증 규칙, 계산식, 조건부 표시, API 연결 등
[개발자 모드] ← 숨겨진 모드 (개발자 전용)
커스텀 렌더러, 이벤트 훅, CSS 오버라이드
```
---
## 6. 캔버스/디자이너 UI 재설계
### 6.1 새로운 디자이너 레이아웃
```
┌─────────────────────────────────────────────────────┐
│ [← 목록] │ 수주관리 화면 │ 💾 자동저장 ON │ [미리보기]│
├──────────┼──────────────────────────────┼────────────┤
│ │ │ │
│ 컴포넌트 │ ┌──────────────────┐ │ 설정 │
│ --------│ │ │ │ -------- │
│ 📊 Data │ │ [캔버스 영역] │ │ [기본] │
│ 📝 Field│ │ │ │ [데이터] │
│ ▶ Action│ │ 드래그하여 │ │ [표시] │
│ 📐 Layout │ 컴포넌트 추가 │ │ [연동] │
│ 📄 Display │ │ │ [조건] │
│ 🔍 Search│ │ │ │ │
│ 📋 Modal │ └──────────────────┘ │ │
│ │ │ │
│ 테이블 │ ────────────────────────── │ │
│ --------│ [줌: 100%] [맞춤] [그리드] │ │
│ 수주관리 │ │ │
│ └ 컬럼들│ │ │
├──────────┼──────────────────────────────┼────────────┤
│ [연동 설정] 컴포넌트 간 연결 시각화 │
│ [거래처] ─── 변경 시 ──→ [납품처] 필터링 │
└─────────────────────────────────────────────────────┘
```
### 6.2 핵심 UX 개선 사항
| 항목 | 현재 | 새로운 |
|------|------|--------|
| 컴포넌트 패널 | 70개 위젯 나열 | 7개 메타 컴포넌트 + 테이블 컬럼 |
| 드롭 피드백 | 없음 | 스냅 가이드라인 + 드롭 영역 하이라이트 |
| 설정 패널 | 컴포넌트별 26개 | 통합 5탭 패널 (간편/상세/개발자 모드) |
| 빈 캔버스 | 빈 화면 | "테이블을 드래그하여 시작하세요" 가이드 |
| 줌 | 마우스 휠만 | 우하단 줌 컨트롤 (+/-/맞춤/100%) |
| 저장 | 수동만 | 자동 저장 + 수동 저장 |
| 연동 | 코드 필요 | 하단 연동 패널에서 시각적 설정 |
| 미리보기 | 새 창 | 인라인 미리보기 모드 (디자인↔미리보기 전환) |
### 6.3 "테이블 드롭" 자동 화면 생성
테이블을 캔버스에 드롭하면 자동으로 화면 구성:
```
[sales_order_mng 테이블 드롭]
┌─────────────────────────────────────┐
│ 🪄 화면 자동 생성 │
├─────────────────────────────────────┤
│ 어떤 형태로 만들까요? │
│ │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │목록형│ │폼형 │ │마디 │ │카드 │ │
│ │ │ │ │ │ │ │ │ │
│ │ ≡≡≡ │ │ □□ │ │≡≡│□│ │ ▦▦▦ │ │
│ │ ≡≡≡ │ │ □□ │ │≡≡│□│ │ ▦▦▦ │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ │
│ 테이블 입력폼 마스터 카드 그리드│
│ + CRUD + 저장 디테일 + 필터 │
│ │
│ 포함할 컬럼: │
│ ☑ order_no (수주번호) │
│ ☑ customer_code (거래처) → entity │
│ ☑ order_date (수주일) → date │
│ ☑ quantity (수량) → number │
│ ☐ created_by (생성자) [숨김 추천] │
│ ☐ updated_at (수정일) [숨김 추천] │
│ │
│ [생성하기] │
└─────────────────────────────────────┘
```
**생성 결과** (목록형 선택 시):
```
자동 생성되는 컴포넌트:
1. Search 컴포넌트 (검색바)
2. Action 컴포넌트 그룹 (등록/수정/삭제 버튼)
3. DataView 컴포넌트 (테이블 뷰, 선택한 컬럼 포함)
4. Modal 컴포넌트 (등록/수정용 폼 모달, Field 자동 구성)
```
---
## 7. 마이그레이션 전략
### 7.1 기존 레이아웃 호환
기존 1,407개 레이아웃(version: "2.0")은 유지하면서 새 시스템 도입:
```typescript
// 레이아웃 로드 시 자동 변환
function loadLayout(data: LayoutData): LayoutData {
if (data.version === "2.0") {
// 기존 컴포넌트 → 메타 컴포넌트 매핑
return migrateTo3_0(data);
}
return data;
}
function migrateTo3_0(data: LayoutData): LayoutData {
const newComponents = data.components.map(comp => {
// text-input, number-input, date-input 등 → Field
if (isInputComponent(comp.componentType)) {
return convertToField(comp);
}
// table-list, v2-table-list 등 → DataView
if (isDataComponent(comp.componentType)) {
return convertToDataView(comp);
}
// button-primary → Action
if (isButtonComponent(comp.componentType)) {
return convertToAction(comp);
}
return comp; // 변환 불가 시 기존 유지
});
return { ...data, version: "3.0", components: newComponents };
}
```
### 7.2 단계적 전환 계획
```
Phase A: 메타 컴포넌트 코어 개발 (3~4주)
- Field, DataView, Action 핵심 3개 먼저
- 통합 설정 패널 (UnifiedConfigPanel)
- Reactive Bindings 엔진
Phase B: 자동 생성 시스템 (2~3주)
- 테이블 드롭 → 화면 자동 생성
- 컬럼 webType → Field 자동 변환
- FK 관계 → 연동 자동 설정
Phase C: 나머지 메타 컴포넌트 (2~3주)
- Layout, Display, Search, Modal
- 뷰 모드 전환 (테이블↔카드↔트리)
Phase D: 마이그레이션 & 정리 (2주)
- 기존 레이아웃 자동 변환
- 레거시 컴포넌트 정리
- 사용자 가이드 작성
```
### 7.3 공존 기간
```
[현재] → [Phase A~C] → [Phase D] → [완료]
70개 위젯 70개 위젯 70개 위젯 7개 메타
+ 7개 메타 + 7개 메타 (기본) (기존 호환 유지)
(선택적 사용) (기존은 마이그레이션)
```
---
## 8. 기존 컴포넌트 → 메타 컴포넌트 매핑표
### 8.1 Field로 통합 (18개 → 1개)
| 기존 컴포넌트 | webType 매핑 | 비고 |
|---------------|-------------|------|
| text-input | text | |
| number-input | number | |
| date-input | date | |
| select-basic | select | options 자동 감지 |
| checkbox-basic | checkbox | |
| radio-basic | radio | |
| textarea-basic | textarea | |
| file-upload | file | |
| entity-search-input | entity | join 자동 감지 |
| autocomplete-search-input | entity | searchable: true |
| slider-basic | slider | |
| toggle-switch | toggle | |
| numbering-rule | numbering | autoGeneration 설정 |
| image-widget | file | accept: "image/*" |
| v2-input | text/number/email/tel/url | inputType에 따라 |
| v2-select | select | |
| v2-date | date/datetime | |
| v2-file-upload | file | |
### 8.2 DataView로 통합 (14개 → 1개)
| 기존 컴포넌트 | viewMode 매핑 | 비고 |
|---------------|-------------|------|
| table-list | table | |
| v2-table-list | table | |
| v2-table-grouped | table | groupBy 설정 |
| v2-repeater | table | editableColumns 설정 |
| simple-repeater-table | table | inline edit |
| modal-repeater-table | table + modal | |
| card-display | card | |
| v2-card-display | card | |
| pivot-grid | pivot | |
| v2-pivot-grid | pivot | |
| v2-bom-tree | tree | |
| aggregation-widget | table | summaryColumns 설정 |
| v2-aggregation-widget | table | summaryColumns 설정 |
| v2-timeline-scheduler | timeline | |
### 8.3 Action으로 통합 (4개 → 1개)
| 기존 컴포넌트 | 비고 |
|---------------|------|
| button-primary | steps 설정 |
| v2-button-primary | steps 설정 |
| flow-widget | flowMove step |
| related-data-buttons | navigate step |
### 8.4 Layout으로 통합 (12개 → 1개)
| 기존 컴포넌트 | mode 매핑 |
|---------------|-----------|
| split-panel-layout | columns |
| v2-split-panel-layout | columns |
| screen-split-panel | columns (화면 임베딩) |
| tabs | tabs |
| v2-tabs-widget | tabs |
| section-card | card |
| v2-section-card | card |
| section-paper | card (variant) |
| v2-section-paper | card (variant) |
| conditional-container | conditional |
| accordion-basic | accordion |
| repeat-container | rows (반복) |
| v2-repeat-container | rows (반복) |
### 8.5 Display로 통합 (12개 → 1개)
| 기존 컴포넌트 | displayType 매핑 |
|---------------|-----------------|
| text-display | text |
| v2-text-display | text |
| divider-line | divider |
| v2-divider-line | divider |
| v2-split-line | divider |
| badge | badge |
| alert | alert |
| stats-card | stat |
| chart | chart |
| image-display | image |
| progress-bar | progress |
| v2-media | image |
### 8.6 특수 컴포넌트 (별도 유지 또는 DataView 확장)
| 기존 컴포넌트 | 처리 방안 |
|---------------|-----------|
| v2-bom-item-editor | DataView(tree) + inline edit |
| rack-structure | 별도 유지 (특수 시각화) |
| v2-rack-structure | 별도 유지 |
| v2-location-swap-selector | 별도 유지 (특수 UI) |
| location-swap-selector | 별도 유지 |
| map | 별도 유지 (지도) |
| category-manager | DataView(tree) + Action 조합 |
| v2-category-manager | DataView(tree) + Action 조합 |
| customer-item-mapping | DataView + Search 조합 |
| tax-invoice-list | DataView + Action + Modal 조합 |
| mail-recipient-selector | 별도 유지 (특수 UI) |
| v2-process-work-standard | DataView + Modal 조합 |
| v2-item-routing | DataView(tree) + Action 조합 |
| repeater-field-group | Layout(rows) + Field 조합 |
---
## 9. 기술 스택 결정 사항
| 영역 | 선택 | 이유 |
|------|------|------|
| 상태 관리 | Zustand | 경량, 보일러플레이트 적음, React에 최적화 |
| DnD | @dnd-kit | 터치 지원, 커스텀 오버레이, 접근성 |
| 연동 엔진 | 자체 구현 (EventBus 확장) | 기존 EventBus 활용, 프로젝트 특화 |
| 설정 UI | Schema-driven form | configSchema 기반 자동 폼 생성 |
| 캔버스 | CSS Grid + 절대 좌표 하이브리드 | 기존 호환 + 반응형 전환 |
---
## 10. 성공 지표
| 지표 | 현재 | 목표 |
|------|------|------|
| 새 화면 만드는 시간 (현업) | 불가능 (개발자 필요) | 5~10분 |
| 새 화면 만드는 시간 (개발자) | 15~30분 | 2~5분 |
| 새 위젯 타입 추가 시 개발 공수 | 1~3일 (5~8파일) | 대부분 설정으로 해결, 특수한 경우만 개발 |
| 컴포넌트 패널 항목 수 | 70개+ (혼란) | 7개 메타 + 테이블 컬럼 |
| ConfigPanel 파일 수 | 26개 | 1개 (UnifiedConfigPanel) |
| 컴포넌트 간 연동 설정 | 코드 필요 | UI로 클릭 설정 |
| ScreenDesigner.tsx 줄 수 | 7,593줄 | 1,500줄 이하 (훅 분리) |
---
## 11. 위험 요소
| 위험 | 영향 | 완화 방안 |
|------|------|-----------|
| 기존 1,407개 레이아웃 마이그레이션 실패 | 운영 중단 | 자동 변환 + 수동 검증 + 롤백 가능 |
| 메타 컴포넌트가 모든 케이스를 커버 못 함 | 특수 기능 불가 | 특수 컴포넌트 별도 유지 (8.6 참고) |
| 통합 설정 패널이 오히려 복잡해질 수 있음 | UX 저하 | 간편/상세/개발자 3단계 모드 분리 |
| Reactive Bindings 디버깅 어려움 | 유지보수 | 연동 시각화 패널 + 로그 제공 |
| 개발 기간 장기화 | 일정 지연 | Phase별 독립 배포 가능하게 설계 |
---
## 12. 결론
**현재 시스템의 본질적 한계**: 기능 = 컴포넌트. 기능이 늘면 컴포넌트가 늘고, 코드가 늘고, 복잡도가 늘어남.
**새로운 방향**: 7개의 메타 컴포넌트(Field, DataView, Action, Layout, Display, Search, Modal)로 통합하고, 컴포넌트 간 Reactive Bindings로 동적 연동을 지원.
**사용자가 얻는 것**: 테이블 드롭 한 번으로 기본 화면 완성, 설정 몇 번으로 업무에 맞게 커스터마이징, 개발자 없이 화면 변경 가능.
**개발팀이 얻는 것**: 새 기능 요청 시 코드 작성 대신 설정 가이드 제공, ConfigPanel 26개 → 1개로 유지보수 대폭 감소, 7,593줄 거대 파일 분리.
전체 예상 기간: **9~12주** (Phase A~D)