# 화면 디자이너 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; // 다른 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)