1013 lines
34 KiB
Markdown
1013 lines
34 KiB
Markdown
|
|
# 화면관리 시스템 동적 설정 관리 계획서
|
|||
|
|
|
|||
|
|
> 하드코딩된 웹타입과 버튼 기능을 동적으로 관리할 수 있는 시스템 구축 계획
|
|||
|
|
|
|||
|
|
## 📋 목차
|
|||
|
|
|
|||
|
|
- [개요](#개요)
|
|||
|
|
- [현재 상황 분석](#현재-상황-분석)
|
|||
|
|
- [목표 시스템 아키텍처](#목표-시스템-아키텍처)
|
|||
|
|
- [단계별 구현 계획](#단계별-구현-계획)
|
|||
|
|
- [기대 효과](#기대-효과)
|
|||
|
|
- [실행 일정](#실행-일정)
|
|||
|
|
|
|||
|
|
## 개요
|
|||
|
|
|
|||
|
|
### 🎯 목표
|
|||
|
|
|
|||
|
|
현재 화면관리 시스템에서 하드코딩되어 있는 웹타입과 버튼 기능을 동적으로 관리할 수 있는 설정 페이지를 구축하여, 개발자는 컴포넌트만 작성하고 비개발자는 관리 페이지에서 타입을 추가/수정할 수 있는 유연한 시스템으로 전환
|
|||
|
|
|
|||
|
|
### 🔧 핵심 과제
|
|||
|
|
|
|||
|
|
- 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 기반 최적화**: 사용 패턴 기반 자동 설정 추천
|
|||
|
|
- **마켓플레이스**: 웹타입/템플릿 공유 플랫폼
|
|||
|
|
- **다중 플랫폼**: 모바일/데스크톱 앱에서도 동일한 시스템 사용
|
|||
|
|
|
|||
|
|
**이제 미래 지향적이고 확장 가능한 화면관리 시스템을 구축할 준비가 완료되었습니다!** 🚀
|