37 KiB
화면 디자이너 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/기존/신규 혼재
// 같은 테이블 컴포넌트가 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에 따라 모양과 동작이 바뀜
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
핵심 개념: 하나의 데이터 소스를 여러 뷰 모드로 전환
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 컴포넌트에 여러 동작을 설정으로 정의
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
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
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
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
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
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")은 유지하면서 새 시스템 도입:
// 레이아웃 로드 시 자동 변환
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)