ERP-node/docs/screen-management-dynamic-s...

1013 lines
34 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.

# 화면관리 시스템 동적 설정 관리 계획서
> 하드코딩된 웹타입과 버튼 기능을 동적으로 관리할 수 있는 시스템 구축 계획
## 📋 목차
- [개요](#개요)
- [현재 상황 분석](#현재-상황-분석)
- [목표 시스템 아키텍처](#목표-시스템-아키텍처)
- [단계별 구현 계획](#단계별-구현-계획)
- [기대 효과](#기대-효과)
- [실행 일정](#실행-일정)
## 개요
### 🎯 목표
현재 화면관리 시스템에서 하드코딩되어 있는 웹타입과 버튼 기능을 동적으로 관리할 수 있는 설정 페이지를 구축하여, 개발자는 컴포넌트만 작성하고 비개발자는 관리 페이지에서 타입을 추가/수정할 수 있는 유연한 시스템으로 전환
### 🔧 핵심 과제
- 25개의 하드코딩된 웹타입을 데이터베이스 기반 동적 관리로 전환
- 11개의 하드코딩된 버튼 액션을 설정 가능한 시스템으로 변경
- 플러그인 방식의 컴포넌트 아키텍처 구축
- 비개발자도 사용 가능한 설정 관리 인터페이스 제공
## 현재 상황 분석
### 📊 하드코딩된 부분들
#### 1. 웹타입 (25개)
**위치**: `frontend/types/screen.ts`
```typescript
export type WebType =
| "text"
| "number"
| "date"
| "code"
| "entity"
| "textarea"
| "select"
| "checkbox"
| "radio"
| "file"
| "email"
| "tel"
| "datetime"
| "dropdown"
| "text_area"
| "boolean"
| "decimal"
| "button";
```
#### 2. 버튼 액션 (11개)
**위치**: `frontend/types/screen.ts`
```typescript
export type ButtonActionType =
| "save"
| "delete"
| "edit"
| "add"
| "search"
| "reset"
| "submit"
| "close"
| "popup"
| "navigate"
| "custom";
```
#### 3. 렌더링 로직
**위치**: `frontend/components/screen/RealtimePreview.tsx`
- 970줄의 switch-case 문으로 웹타입별 렌더링 처리
- 각 웹타입별 고정된 렌더링 로직
#### 4. 설정 패널
**위치**: `frontend/components/screen/panels/ButtonConfigPanel.tsx`
- 45줄의 하드코딩된 액션타입 옵션 배열
- 각 액션별 고정된 기본값 설정
### ⚠️ 현재 시스템의 문제점
- 새로운 웹타입 추가 시 여러 파일 수정 필요
- 타입별 설정 변경을 위해 코드 수정 및 배포 필요
- 회사별/프로젝트별 커스텀 타입 관리 어려움
- 비개발자의 시스템 설정 변경 불가능
## 목표 시스템 아키텍처
### 🎨 전체 시스템 구조
```
┌─────────────────────────────────────────────────────────────┐
│ 관리자 설정 페이지 │
├─────────────────────────────────────────────────────────────┤
│ 웹타입 관리 │ 버튼액션 관리 │ 스타일템플릿 │ 격자설정 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ API Layer │
├─────────────────────────────────────────────────────────────┤
│ /api/admin/web-types │ /api/admin/button-actions │
│ /api/admin/style-templates │ /api/admin/grid-standards │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Database Layer │
├─────────────────────────────────────────────────────────────┤
│ web_type_standards │ button_action_standards │
│ style_templates │ grid_standards │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 웹타입 레지스트리 시스템 │
├─────────────────────────────────────────────────────────────┤
│ WebTypeRegistry.register() │ DynamicRenderer │
│ 플러그인 방식 컴포넌트 등록 │ 동적 컴포넌트 렌더링 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 화면관리 시스템 │
├─────────────────────────────────────────────────────────────┤
│ ScreenDesigner │ RealtimePreview │
│ PropertiesPanel │ InteractiveScreenViewer │
└─────────────────────────────────────────────────────────────┘
```
### 🔌 플러그인 방식 컴포넌트 시스템
#### 웹타입 정의 인터페이스
```typescript
interface WebTypeDefinition {
webType: string; // 웹타입 식별자
name: string; // 표시명
category: string; // 카테고리 (input, select, display, special)
defaultConfig: any; // 기본 설정
validationRules: any; // 유효성 검사 규칙
defaultStyle: any; // 기본 스타일
inputProperties: any; // HTML input 속성
component: React.ComponentType; // 렌더링 컴포넌트
configPanel: React.ComponentType; // 설정 패널 컴포넌트
icon?: React.ComponentType; // 아이콘 컴포넌트
sortOrder?: number; // 정렬 순서
isActive?: boolean; // 활성화 여부
}
```
#### 웹타입 레지스트리
```typescript
class WebTypeRegistry {
private static types = new Map<string, WebTypeDefinition>();
// 웹타입 등록
static register(definition: WebTypeDefinition) {
this.types.set(definition.webType, definition);
}
// 웹타입 조회
static get(webType: string): WebTypeDefinition | undefined {
return this.types.get(webType);
}
// 모든 웹타입 조회
static getAll(): WebTypeDefinition[] {
return Array.from(this.types.values())
.filter((type) => type.isActive)
.sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0));
}
// 카테고리별 조회
static getByCategory(category: string): WebTypeDefinition[] {
return this.getAll().filter((type) => type.category === category);
}
}
```
#### 동적 컴포넌트 렌더러
```typescript
const DynamicWebTypeRenderer: React.FC<{
widgetType: string;
component: WidgetComponent;
[key: string]: any;
}> = ({ widgetType, component, ...props }) => {
const definition = WebTypeRegistry.get(widgetType);
if (!definition) {
return (
<div className="flex items-center justify-center p-4 border-2 border-dashed border-red-300 bg-red-50">
<span className="text-red-600"> 없는 웹타입: {widgetType}</span>
</div>
);
}
const Component = definition.component;
return <Component component={component} {...props} />;
};
```
## 단계별 구현 계획
### 📅 Phase 1: 기반 구조 구축 (1-2주)
#### 1.1 데이터베이스 스키마 적용
-**이미 준비됨**: `db/08-create-webtype-standards.sql`
- 4개 테이블: `web_type_standards`, `button_action_standards`, `style_templates`, `grid_standards`
- 기본 데이터 25개 웹타입, 12개 버튼액션 포함
#### 1.2 Backend API 개발
```
backend-node/src/routes/admin/
├── web-types.ts # 웹타입 CRUD API
├── button-actions.ts # 버튼액션 CRUD API
├── style-templates.ts # 스타일템플릿 CRUD API
└── grid-standards.ts # 격자설정 CRUD API
```
**주요 API 엔드포인트:**
```typescript
// 웹타입 관리
GET /api/admin/web-types # 목록 조회
POST /api/admin/web-types # 생성
PUT /api/admin/web-types/:webType # 수정
DELETE /api/admin/web-types/:webType # 삭제
// 버튼액션 관리
GET /api/admin/button-actions # 목록 조회
POST /api/admin/button-actions # 생성
PUT /api/admin/button-actions/:actionType # 수정
DELETE /api/admin/button-actions/:actionType # 삭제
// 화면관리에서 사용할 조회 API
GET /api/screen/web-types?active=Y&category=input
GET /api/screen/button-actions?active=Y&category=crud
```
#### 1.3 프론트엔드 기반 구조
```
frontend/lib/registry/
├── WebTypeRegistry.ts # 웹타입 레지스트리
├── ButtonActionRegistry.ts # 버튼액션 레지스트리
└── types.ts # 레지스트리 관련 타입 정의
frontend/components/screen/dynamic/
├── DynamicWebTypeRenderer.tsx # 동적 웹타입 렌더러
├── DynamicConfigPanel.tsx # 동적 설정 패널
└── DynamicActionHandler.tsx # 동적 액션 핸들러
frontend/hooks/
├── useWebTypes.ts # 웹타입 관리 훅
├── useButtonActions.ts # 버튼액션 관리 훅
├── useStyleTemplates.ts # 스타일템플릿 관리 훅
└── useGridStandards.ts # 격자설정 관리 훅
```
### 📅 Phase 2: 설정 관리 페이지 개발 (2-3주)
#### 2.1 관리 페이지 라우팅 구조
```
frontend/app/(dashboard)/admin/system-settings/
├── page.tsx # 메인 설정 페이지
├── layout.tsx # 설정 페이지 레이아웃
├── web-types/
│ ├── page.tsx # 웹타입 목록
│ ├── new/
│ │ └── page.tsx # 새 웹타입 생성
│ ├── [webType]/
│ │ ├── page.tsx # 웹타입 상세/편집
│ │ └── preview/
│ │ └── page.tsx # 웹타입 미리보기
│ └── components/
│ ├── WebTypeList.tsx # 웹타입 목록 컴포넌트
│ ├── WebTypeForm.tsx # 웹타입 생성/편집 폼
│ ├── WebTypePreview.tsx # 웹타입 미리보기
│ └── WebTypeCard.tsx # 웹타입 카드
├── button-actions/
│ ├── page.tsx # 버튼액션 목록
│ ├── new/page.tsx # 새 액션 생성
│ ├── [actionType]/page.tsx # 액션 상세/편집
│ └── components/
│ ├── ActionList.tsx # 액션 목록
│ ├── ActionForm.tsx # 액션 생성/편집 폼
│ └── ActionPreview.tsx # 액션 미리보기
├── style-templates/
│ ├── page.tsx # 스타일 템플릿 목록
│ └── components/
│ ├── TemplateList.tsx # 템플릿 목록
│ ├── TemplateEditor.tsx # 템플릿 편집기
│ └── StylePreview.tsx # 스타일 미리보기
└── grid-standards/
├── page.tsx # 격자 설정 목록
└── components/
├── GridList.tsx # 격자 목록
├── GridEditor.tsx # 격자 편집기
└── GridPreview.tsx # 격자 미리보기
```
#### 2.2 웹타입 관리 페이지 주요 기능
**목록 페이지 (`web-types/page.tsx`)**
- 📋 웹타입 목록 조회 (카테고리별 필터링)
- 🔍 검색 및 정렬 기능
- ✅ 활성화/비활성화 토글
- 🎯 정렬 순서 드래그앤드롭 변경
- 새 웹타입 추가 버튼
**생성/편집 페이지 (`web-types/[webType]/page.tsx`)**
- 📝 기본 정보 입력 (이름, 설명, 카테고리)
- ⚙️ 기본 설정 JSON 편집기
- 🔒 유효성 검사 규칙 설정
- 🎨 기본 스타일 설정
- 🏷️ HTML 속성 설정
- 👀 실시간 미리보기
**미리보기 페이지 (`web-types/[webType]/preview/page.tsx`)**
- 📱 다양한 화면 크기별 미리보기
- 🎭 여러 테마 적용 테스트
- 📊 설정값별 렌더링 결과 확인
#### 2.3 버튼액션 관리 페이지 주요 기능
**목록 페이지 (`button-actions/page.tsx`)**
- 📋 액션 목록 조회 (카테고리별 필터링)
- 🏷️ 액션별 기본 설정 미리보기
- ✅ 활성화/비활성화 관리
- 🎯 정렬 순서 관리
**생성/편집 페이지 (`button-actions/[actionType]/page.tsx`)**
- 📝 기본 정보 (이름, 설명, 카테고리)
- 🎨 기본 스타일 (텍스트, 아이콘, 색상, 변형)
- ⚠️ 확인 메시지 설정
- 🔒 실행 조건 및 검증 규칙
- ⚙️ 액션별 추가 설정 (JSON)
### 📅 Phase 3: 컴포넌트 분리 및 등록 (3-4주)
#### 3.1 기존 웹타입 컴포넌트 분리
**Before (기존 구조)**:
```typescript
// RealtimePreview.tsx - 970줄의 거대한 switch문
const renderWidget = (component: ComponentData) => {
switch (widgetType) {
case "text":
return <Input type="text" {...commonProps} />;
case "number":
return <Input type="number" {...commonProps} />;
case "date":
return <Input type="date" {...commonProps} />;
// ... 25개 케이스
}
};
```
**After (새로운 구조)**:
```
frontend/components/screen/widgets/
├── base/
│ ├── BaseWebTypeComponent.tsx # 기본 웹타입 컴포넌트
│ ├── WebTypeProps.ts # 공통 프로퍼티 인터페이스
│ └── WebTypeHooks.ts # 공통 훅
├── input/
│ ├── TextWidget.tsx # 텍스트 입력
│ ├── NumberWidget.tsx # 숫자 입력
│ ├── DecimalWidget.tsx # 소수 입력
│ ├── DateWidget.tsx # 날짜 입력
│ ├── DateTimeWidget.tsx # 날짜시간 입력
│ ├── EmailWidget.tsx # 이메일 입력
│ ├── TelWidget.tsx # 전화번호 입력
│ └── TextareaWidget.tsx # 텍스트영역
├── select/
│ ├── SelectWidget.tsx # 선택박스
│ ├── DropdownWidget.tsx # 드롭다운
│ ├── RadioWidget.tsx # 라디오버튼
│ ├── CheckboxWidget.tsx # 체크박스
│ └── BooleanWidget.tsx # 불린 선택
├── special/
│ ├── FileWidget.tsx # 파일 업로드
│ ├── CodeWidget.tsx # 공통코드
│ ├── EntityWidget.tsx # 엔티티 참조
│ └── ButtonWidget.tsx # 버튼
└── registry/
├── index.ts # 모든 웹타입 등록
└── registerWebTypes.ts # 웹타입 등록 함수
```
**개별 컴포넌트 예시**:
```typescript
// TextWidget.tsx
import React from "react";
import { Input } from "@/components/ui/input";
import { BaseWebTypeComponent } from "../base/BaseWebTypeComponent";
import { TextTypeConfig } from "@/types/screen";
interface TextWidgetProps {
component: WidgetComponent;
value?: string;
onChange?: (value: string) => void;
readonly?: boolean;
}
export const TextWidget: React.FC<TextWidgetProps> = ({
component,
value,
onChange,
readonly = false,
}) => {
const config = component.webTypeConfig as TextTypeConfig;
return (
<BaseWebTypeComponent component={component}>
<Input
type="text"
value={value || ""}
onChange={(e) => onChange?.(e.target.value)}
placeholder={component.placeholder || config?.placeholder}
disabled={readonly}
maxLength={config?.maxLength}
minLength={config?.minLength}
pattern={config?.pattern}
className="w-full h-full"
/>
</BaseWebTypeComponent>
);
};
```
#### 3.2 설정 패널 분리
```
frontend/components/screen/config-panels/
├── base/
│ ├── BaseConfigPanel.tsx # 기본 설정 패널
│ ├── ConfigPanelProps.ts # 공통 프로퍼티
│ └── ConfigPanelHooks.ts # 공통 훅
├── input/
│ ├── TextConfigPanel.tsx # 텍스트 설정
│ ├── NumberConfigPanel.tsx # 숫자 설정
│ ├── DateConfigPanel.tsx # 날짜 설정
│ └── TextareaConfigPanel.tsx # 텍스트영역 설정
├── select/
│ ├── SelectConfigPanel.tsx # 선택박스 설정
│ ├── RadioConfigPanel.tsx # 라디오 설정
│ └── CheckboxConfigPanel.tsx # 체크박스 설정
├── special/
│ ├── FileConfigPanel.tsx # 파일 설정
│ ├── CodeConfigPanel.tsx # 코드 설정
│ ├── EntityConfigPanel.tsx # 엔티티 설정
│ └── ButtonConfigPanel.tsx # 버튼 설정 (기존 이전)
└── registry/
└── registerConfigPanels.ts # 설정 패널 등록
```
#### 3.3 웹타입 등록 시스템
```typescript
// frontend/lib/registry/registerWebTypes.ts
import { WebTypeRegistry } from "./WebTypeRegistry";
// 입력 타입 등록
import { TextWidget } from "@/components/screen/widgets/input/TextWidget";
import { TextConfigPanel } from "@/components/screen/config-panels/input/TextConfigPanel";
export const registerAllWebTypes = async () => {
// 데이터베이스에서 웹타입 설정 조회
const webTypeSettings = await fetch("/api/screen/web-types?active=Y").then(
(r) => r.json()
);
// 각 웹타입별 컴포넌트 매핑
const componentMap = {
text: { component: TextWidget, configPanel: TextConfigPanel },
number: { component: NumberWidget, configPanel: NumberConfigPanel },
// ... 기타 매핑
};
// 웹타입 등록
webTypeSettings.forEach((setting) => {
const components = componentMap[setting.webType];
if (components) {
WebTypeRegistry.register({
webType: setting.webType,
name: setting.typeName,
category: setting.category,
defaultConfig: setting.defaultConfig,
validationRules: setting.validationRules,
defaultStyle: setting.defaultStyle,
inputProperties: setting.inputProperties,
component: components.component,
configPanel: components.configPanel,
sortOrder: setting.sortOrder,
isActive: setting.isActive === "Y",
});
}
});
};
```
### 📅 Phase 4: 화면관리 시스템 연동 (2-3주)
#### 4.1 화면 설계 시 동적 웹타입 사용
**ScreenDesigner.tsx 수정**:
```typescript
const ScreenDesigner = () => {
// 동적 웹타입/버튼액션 조회
const { data: webTypes } = useWebTypes({ active: "Y" });
const { data: buttonActions } = useButtonActions({ active: "Y" });
// 웹타입 드롭다운 옵션 동적 생성
const webTypeOptions = useMemo(() => {
return (
webTypes?.map((type) => ({
value: type.webType,
label: type.typeName,
category: type.category,
icon: type.icon,
})) || []
);
}, [webTypes]);
// 카테고리별 그룹화
const webTypesByCategory = useMemo(() => {
return webTypeOptions.reduce((acc, type) => {
if (!acc[type.category]) acc[type.category] = [];
acc[type.category].push(type);
return acc;
}, {});
}, [webTypeOptions]);
// 버튼 액션 옵션 동적 생성
const buttonActionOptions = useMemo(() => {
return (
buttonActions?.map((action) => ({
value: action.actionType,
label: action.actionName,
category: action.category,
icon: action.defaultIcon,
color: action.defaultColor,
})) || []
);
}, [buttonActions]);
// ...기존 로직
};
```
**PropertiesPanel.tsx 수정**:
```typescript
const PropertiesPanel = ({ component, onUpdateComponent }) => {
const webTypes = WebTypeRegistry.getAll();
return (
<div>
{/* 웹타입 선택 드롭다운 */}
<Select
value={component.widgetType}
onValueChange={(value) => onUpdateComponent({ widgetType: value })}
>
{Object.entries(
webTypes.reduce((acc, type) => {
if (!acc[type.category]) acc[type.category] = [];
acc[type.category].push(type);
return acc;
}, {})
).map(([category, types]) => (
<SelectGroup key={category}>
<SelectLabel>{category}</SelectLabel>
{types.map((type) => (
<SelectItem key={type.webType} value={type.webType}>
<div className="flex items-center gap-2">
{type.icon && <type.icon className="h-4 w-4" />}
{type.name}
</div>
</SelectItem>
))}
</SelectGroup>
))}
</Select>
{/* 동적 설정 패널 */}
<DynamicConfigPanel
component={component}
onUpdateComponent={onUpdateComponent}
/>
</div>
);
};
```
#### 4.2 동적 렌더링 시스템 적용
**RealtimePreview.tsx 대폭 간소화**:
```typescript
// Before: 970줄의 거대한 switch문
const renderWidget = (component: ComponentData) => {
switch (widgetType) {
case "text": /* 복잡한 로직 */
case "number": /* 복잡한 로직 */
// ... 25개 케이스
}
};
// After: 간단한 동적 렌더링
const renderWidget = (component: ComponentData) => {
if (component.type !== "widget") {
return <div className="text-xs text-gray-500">위젯이 아닙니다</div>;
}
return (
<DynamicWebTypeRenderer
widgetType={component.widgetType}
component={component}
isSelected={isSelected}
onClick={onClick}
/>
);
};
```
**InteractiveScreenViewer.tsx 업데이트**:
```typescript
const InteractiveScreenViewer = ({ component, formData, onFormDataChange }) => {
const renderInteractiveWidget = (comp) => {
if (comp.type !== "widget") return null;
return (
<DynamicWebTypeRenderer
widgetType={comp.widgetType}
component={comp}
value={formData[comp.columnName]}
onChange={(value) => onFormDataChange(comp.columnName, value)}
readonly={comp.readonly}
/>
);
};
// 기존 switch문 제거, 동적 렌더링으로 대체
return renderInteractiveWidget(component);
};
```
### 📅 Phase 5: 테스트 및 최적화 (1-2주)
#### 5.1 기능 테스트 체크리스트
**관리 페이지 테스트**:
- [ ] 웹타입 생성/수정/삭제 기능
- [ ] 버튼액션 생성/수정/삭제 기능
- [ ] 활성화/비활성화 토글 기능
- [ ] 정렬 순서 변경 기능
- [ ] 설정값 변경 시 실시간 미리보기
- [ ] JSON 설정 유효성 검사
- [ ] 다국어 지원 테스트
**화면관리 시스템 테스트**:
- [ ] 동적 웹타입 드롭다운 표시
- [ ] 새로 추가된 웹타입 정상 렌더링
- [ ] 설정 변경 시 실시간 반영
- [ ] 기존 화면과의 호환성 확인
- [ ] 웹타입별 설정 패널 정상 동작
- [ ] 버튼 액션 동적 처리 확인
**성능 테스트**:
- [ ] 웹타입 정보 로딩 속도
- [ ] 대량 컴포넌트 렌더링 성능
- [ ] 메모리 사용량 최적화
- [ ] 불필요한 리렌더링 방지
#### 5.2 성능 최적화
**웹타입 정보 캐싱**:
```typescript
// React Query를 활용한 캐싱
const useWebTypes = (params = {}) => {
return useQuery({
queryKey: ["webTypes", params],
queryFn: () => fetchWebTypes(params),
staleTime: 5 * 60 * 1000, // 5분간 캐시 유지
cacheTime: 10 * 60 * 1000, // 10분간 메모리 보관
});
};
```
**컴포넌트 Lazy Loading**:
```typescript
// 웹타입 컴포넌트 지연 로딩
const LazyTextWidget = React.lazy(() => import("./widgets/input/TextWidget"));
const LazyNumberWidget = React.lazy(
() => import("./widgets/input/NumberWidget")
);
const DynamicWebTypeRenderer = ({ widgetType, ...props }) => {
const Component = useMemo(() => {
const definition = WebTypeRegistry.get(widgetType);
return definition?.component;
}, [widgetType]);
if (!Component) return <div> 없는 웹타입</div>;
return (
<Suspense fallback={<div>로딩 ...</div>}>
<Component {...props} />
</Suspense>
);
};
```
**불필요한 리렌더링 방지**:
```typescript
// React.memo를 활용한 최적화
export const DynamicWebTypeRenderer = React.memo(
({ widgetType, component, ...props }) => {
// 렌더링 로직
},
(prevProps, nextProps) => {
// 얕은 비교로 리렌더링 최소화
return (
prevProps.widgetType === nextProps.widgetType &&
prevProps.component.id === nextProps.component.id &&
JSON.stringify(prevProps.component.webTypeConfig) ===
JSON.stringify(nextProps.component.webTypeConfig)
);
}
);
```
## 기대 효과
### 🚀 개발자 경험 개선
#### Before (기존 방식)
새로운 웹타입 '전화번호' 추가 시:
1. `types/screen.ts`에 타입 추가
2. `RealtimePreview.tsx`에 switch case 추가 (50줄)
3. `InteractiveScreenViewer.tsx`에 switch case 추가 (30줄)
4. `PropertiesPanel.tsx`에 설정 로직 추가 (100줄)
5. `ButtonConfigPanel.tsx`에 옵션 추가 (20줄)
6. 다국어 파일 업데이트
7. 테스트 코드 작성
8. **총 200줄+ 코드 수정, 7개 파일 변경**
#### After (새로운 방식)
새로운 웹타입 '전화번호' 추가 시:
1. **관리 페이지에서 웹타입 등록** (클릭만으로!)
2. **컴포넌트 파일 1개만 작성** (20줄):
```typescript
// PhoneWidget.tsx
export const PhoneWidget = ({ component, value, onChange, readonly }) => {
const config = component.webTypeConfig as PhoneTypeConfig;
return (
<Input
type="tel"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={config.placeholder || "전화번호를 입력하세요"}
pattern={config.pattern || "[0-9]{3}-[0-9]{4}-[0-9]{4}"}
disabled={readonly}
/>
);
};
// 등록 (앱 초기화 시)
WebTypeRegistry.register({
webType: "phone",
name: "전화번호",
component: PhoneWidget,
configPanel: PhoneConfigPanel,
defaultConfig: { placeholder: "전화번호를 입력하세요" },
});
```
3. **총 20줄 코드 작성, 1개 파일 생성**
### 📈 비개발자 업무 효율성
#### 시스템 관리자 / 기획자가 할 수 있는 일
- ✅ 새로운 웹타입 추가 (개발자 도움 없이)
- ✅ 웹타입별 기본 설정 변경
- ✅ 버튼 액션 커스터마이징
- ✅ 스타일 템플릿 관리
- ✅ 회사별/프로젝트별 커스텀 설정
- ✅ A/B 테스트를 위한 임시 설정 변경
#### 실시간 설정 변경 시나리오
```
시나리오: 고객사 요청으로 '이메일' 입력 필드의 기본 검증 규칙 변경
Before (기존):
1. 개발자가 코드 수정
2. 테스트 환경 배포
3. 검수 후 운영 배포
4. 소요 시간: 1-2일
After (새로운):
1. 관리자가 웹타입 관리 페이지 접속
2. '이메일' 웹타입 편집
3. 검증 규칙 JSON 수정
4. 저장 → 즉시 반영
5. 소요 시간: 2-3분
```
### 🔧 확장성 및 유지보수성
#### 플러그인 방식의 장점
- **독립적 개발**: 각 웹타입별 독립적인 개발 및 테스트
- **점진적 확장**: 필요에 따른 점진적 기능 추가
- **버전 관리**: 웹타입별 버전 관리 가능
- **A/B 테스트**: 다른 구현체로 쉬운 교체 가능
- **재사용성**: 다른 프로젝트에서 컴포넌트 재사용
#### 코드 품질 향상
- **관심사 분리**: 각 웹타입별 로직 분리
- **테스트 용이성**: 작은 단위 컴포넌트 테스트
- **코드 리뷰**: 작은 단위로 리뷰 가능
- **문서화**: 웹타입별 독립적인 문서화
### ⚡ 성능 최적화
#### 지연 로딩 (Lazy Loading)
- 사용하지 않는 웹타입 컴포넌트는 로딩하지 않음
- 초기 번들 크기 50% 이상 감소 예상
- 화면 로딩 속도 향상
#### 효율적인 캐싱
- 웹타입 설정 정보는 앱 시작 시 한 번만 로딩
- 변경 시에만 갱신하는 무효화 정책
- 메모리 사용량 최적화
#### 렌더링 최적화
- 웹타입별 최적화된 렌더링 로직
- 불필요한 리렌더링 방지
- Virtual DOM 업데이트 최소화
## 실행 일정
### 📅 전체 일정표
| Phase | 기간 | 주요 작업 | 담당자 | 산출물 |
| ----------- | ---------- | ---------------- | ----------------- | ---------------------- |
| **Phase 1** | 1-2주 | 기반 구조 구축 | 백엔드/프론트엔드 | API, 레지스트리 시스템 |
| **Phase 2** | 2-3주 | 설정 관리 페이지 | 프론트엔드 | 관리 페이지 UI |
| **Phase 3** | 3-4주 | 컴포넌트 분리 | 프론트엔드 | 웹타입 컴포넌트들 |
| **Phase 4** | 2-3주 | 화면관리 연동 | 프론트엔드 | 동적 렌더링 시스템 |
| **Phase 5** | 1-2주 | 테스트/최적화 | 전체 팀 | 완성된 시스템 |
| **총 기간** | **9-14주** | | | |
### 🎯 마일스톤
#### Milestone 1 (2주 후)
- ✅ 데이터베이스 스키마 적용
- ✅ Backend API 완성
- ✅ 웹타입 레지스트리 시스템 구축
- ✅ 기본 관리 페이지 프레임워크
#### Milestone 2 (5주 후)
- ✅ 웹타입 관리 페이지 완성
- ✅ 버튼액션 관리 페이지 완성
- ✅ 스타일 템플릿 관리 페이지 완성
- ✅ 실시간 미리보기 기능
#### Milestone 3 (9주 후)
- ✅ 모든 웹타입 컴포넌트 분리 완성
- ✅ 설정 패널 분리 완성
- ✅ 웹타입 등록 시스템 완성
- ✅ 기존 화면과의 호환성 확보
#### Milestone 4 (12주 후)
- ✅ 화면관리 시스템 동적 연동 완성
- ✅ RealtimePreview/InteractiveScreenViewer 개선
- ✅ PropertiesPanel 동적 업데이트
- ✅ 성능 최적화 적용
#### Final Release (14주 후)
- ✅ 전체 시스템 통합 테스트 완료
- ✅ 성능 최적화 완료
- ✅ 문서화 완료
- ✅ 운영 배포 준비 완료
### 🚀 우선순위별 실행 전략
#### 🔥 즉시 시작 가능 (우선순위 High)
1. **데이터베이스 스키마 적용**
- 이미 준비된 SQL 파일 실행
- 기본 데이터 확인 및 검증
2. **Backend API 개발**
- 표준적인 CRUD API 구현
- 기존 패턴 재사용 가능
3. **웹타입 레지스트리 시스템**
- 핵심 아키텍처 구성요소
- 다른 모든 기능의 기반
#### 📋 병렬 진행 가능 (우선순위 Medium)
1. **관리 페이지 UI 개발**
- Backend API와 독립적으로 개발 가능
- 목업 데이터로 프로토타입 제작
2. **기존 컴포넌트 분석 및 분리 계획**
- 현재 RealtimePreview 분석
- 컴포넌트 분리 전략 수립
#### ⏳ 순차 진행 필요 (우선순위 Low)
1. **화면관리 시스템 연동**
- 웹타입 컴포넌트 분리 완료 후 진행
- 레지스트리 시스템 안정화 후 진행
2. **성능 최적화**
- 전체 시스템 완성 후 진행
- 실제 사용 패턴 분석 후 최적화
### 💡 성공을 위한 핵심 요소
#### 기술적 성공 요소
- **점진적 마이그레이션**: 기존 시스템과의 호환성 유지
- **철저한 테스트**: 각 단계별 충분한 테스트
- **성능 모니터링**: 성능 저하 없는 기능 확장
- **에러 핸들링**: 견고한 에러 처리 로직
#### 조직적 성공 요소
- **명확한 역할 분담**: 개발자/기획자/관리자 역할 정의
- **충분한 교육**: 새로운 시스템 사용법 교육
- **단계적 도입**: 파일럿 테스트 후 전면 도입
- **피드백 수집**: 사용자 피드백 기반 개선
---
## 🎉 결론
이 계획을 통해 화면관리 시스템은 **하드코딩된 정적 시스템**에서 **유연하고 확장 가능한 동적 시스템**으로 진화할 것입니다.
### 핵심 성과 지표
- **개발 효율성**: 새 웹타입 추가 시간 **95% 단축** (2일 → 2시간)
- **시스템 유연성**: **비개발자도 설정 변경 가능**
- **코드 품질**: **관심사 분리**로 유지보수성 **대폭 향상**
- **성능**: **지연 로딩**으로 초기 로딩 시간 **50% 이상 개선**
### 장기적 비전
- **플러그인 생태계**: 커뮤니티 기반 웹타입 확장
- **AI 기반 최적화**: 사용 패턴 기반 자동 설정 추천
- **마켓플레이스**: 웹타입/템플릿 공유 플랫폼
- **다중 플랫폼**: 모바일/데스크톱 앱에서도 동일한 시스템 사용
**이제 미래 지향적이고 확장 가능한 화면관리 시스템을 구축할 준비가 완료되었습니다!** 🚀