diff --git a/docs/화면관리_시스템_설계.md b/docs/화면관리_시스템_설계.md
new file mode 100644
index 00000000..d39421a8
--- /dev/null
+++ b/docs/화면관리_시스템_설계.md
@@ -0,0 +1,1550 @@
+# 화면관리 시스템 설계 문서
+
+## 📋 목차
+
+1. [시스템 개요](#시스템-개요)
+2. [아키텍처 구조](#아키텍처-구조)
+3. [핵심 기능](#핵심-기능)
+4. [데이터베이스 설계](#데이터베이스-설계)
+5. [화면 구성 요소](#화면-구성-요소)
+6. [드래그앤드롭 설계](#드래그앤드롭-설계)
+7. [테이블 타입 연계](#테이블-타입-연계)
+8. [API 설계](#api-설계)
+9. [프론트엔드 구현](#프론트엔드-구현)
+10. [백엔드 구현](#백엔드-구현)
+11. [사용 시나리오](#사용-시나리오)
+12. [개발 계획](#개발-계획)
+
+## 🎯 시스템 개요
+
+### 화면관리 시스템이란?
+
+화면관리 시스템은 실제 서비스되는 화면을 드래그앤드롭으로 설계하고 관리할 수 있는 시스템입니다. 테이블 타입관리와 연계하여 각 필드가 웹에서 어떻게 표시될지를 정의하고, 사용자가 직관적으로 화면을 구성할 수 있습니다.
+
+### 주요 특징
+
+- **드래그앤드롭 인터페이스**: 직관적인 화면 설계
+- **테이블 타입 연계**: 컬럼의 웹 타입에 따른 자동 위젯 생성
+- **실시간 미리보기**: 설계한 화면을 즉시 확인 가능
+- **반응형 디자인**: 다양한 화면 크기에 대응
+- **템플릿 시스템**: 재사용 가능한 화면 템플릿 제공
+
+### 🎯 **현재 테이블 구조와 100% 호환**
+
+**기존 테이블 타입관리 시스템과 완벽 연계:**
+
+- ✅ **`table_labels`**: 테이블 메타데이터와 연계
+- ✅ **`column_labels`**: 컬럼 웹 타입 및 상세 설정과 연계
+- ✅ **웹 타입 지원**: text, number, date, code, entity, textarea, select, checkbox, radio, file
+- ✅ **상세 설정**: JSON 형태로 유연한 설정 저장
+- ✅ **코드 연계**: 공통코드 시스템과 완벽 연동
+- ✅ **엔티티 참조**: 참조 테이블 시스템 완벽 지원
+
+**별도의 테이블 구조 변경 없이 바로 개발 가능!** 🚀
+
+### 지원하는 웹 타입
+
+테이블 타입관리에서 각 컬럼별로 설정할 수 있는 웹 타입입니다:
+
+- **text**: 일반 텍스트 입력
+- **number**: 숫자 입력
+- **date**: 날짜 선택기
+- **code**: 코드 선택 (공통코드)
+- **entity**: 엔티티 참조 (참조테이블)
+- **textarea**: 여러 줄 텍스트
+- **select**: 드롭다운 선택
+- **checkbox**: 체크박스
+- **radio**: 라디오 버튼
+- **file**: 파일 업로드
+
+> **구현 완료**: 테이블 타입관리 시스템에서 위의 모든 웹 타입을 지정할 수 있으며, 웹 타입별로 적절한 상세 설정을 자동으로 제공합니다.
+
+### 웹 타입 관리 기능
+
+#### 1. 웹 타입 설정
+
+- **자동 상세 설정**: 웹 타입 선택 시 해당 타입에 맞는 기본 상세 설정을 자동으로 제공
+- **실시간 저장**: 웹 타입 변경 시 즉시 백엔드 데이터베이스에 저장
+- **오류 복구**: 저장 실패 시 원래 상태로 자동 복원
+
+#### 2. 웹 타입별 상세 설정
+
+| 웹 타입 | 기본 상세 설정 | 추가 설정 옵션 |
+| ------------ | ---------------------------- | --------------------- |
+| **text** | 최대 길이: 255자 | 사용자 정의 설정 |
+| **number** | 숫자 입력 (정수/실수) | 범위, 정밀도 설정 |
+| **date** | 날짜 형식: YYYY-MM-DD | 날짜 범위, 형식 설정 |
+| **textarea** | 여러 줄 텍스트 (최대 1000자) | 행 수, 최대 길이 설정 |
+| **select** | 드롭다운 선택 옵션 | 옵션 목록 설정 |
+| **checkbox** | 체크박스 (Y/N) | 기본값, 라벨 설정 |
+| **radio** | 라디오 버튼 그룹 | 옵션 그룹 설정 |
+| **file** | 파일 업로드 (최대 10MB) | 파일 형식, 크기 설정 |
+| **code** | 공통코드 선택 | 코드 카테고리 지정 |
+| **entity** | 엔티티 참조 | 참조 테이블/컬럼 지정 |
+
+#### 3. 사용 방법
+
+1. **테이블 선택**: 테이블 타입관리에서 관리할 테이블 선택
+2. **컬럼 확인**: 해당 테이블의 모든 컬럼 정보 표시
+3. **웹 타입 설정**: 각 컬럼의 웹 타입을 드롭다운에서 선택
+4. **자동 저장**: 선택 즉시 백엔드에 저장되고 상세 설정 자동 적용
+5. **추가 설정**: 필요시 상세 설정을 사용자 정의로 수정
+
+## 🏗️ 아키텍처 구조
+
+### 전체 구조도
+
+```
+┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
+│ Frontend │ │ Backend │ │ Database │
+│ │ │ │ │ │
+│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
+│ │ Screen │ │ │ │ Screen │ │ │ │ screen_ │ │
+│ │ Designer │ │ │ │ Management │ │ │ │ definitions │ │
+│ │ (React) │ │ │ │ Controller │ │ │ │ Table │ │
+│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
+│ │ │ │ │ │
+│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
+│ │ Drag & │ │ │ │ Screen │ │ │ │ screen_ │ │
+│ │ Drop │ │ │ │ Management │ │ │ │ layouts │ │
+│ │ Components │ │ │ │ Service │ │ │ │ Table │ │
+│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
+│ │ │ │ │ │
+│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
+│ │ Preview │ │ │ │ Table │ │ │ │ table_ │ │
+│ │ Generator │ │ │ │ Type │ │ │ │ labels │ │
+│ │ (Runtime) │ │ │ │ Service │ │ │ │ Table │ │
+│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
+└─────────────────┘ └─────────────────┘ └─────────────────┘
+```
+
+### 데이터 흐름
+
+1. **테이블 타입 정의**: 테이블 타입관리에서 컬럼의 웹 타입 설정
+2. **화면 설계**: 드래그앤드롭으로 화면 레이아웃 구성
+3. **위젯 매핑**: 컬럼과 화면 위젯을 연결
+4. **설정 저장**: 화면 정의를 데이터베이스에 저장
+5. **런타임 생성**: 실제 서비스 화면을 동적으로 생성
+
+## 🚀 핵심 기능
+
+### 1. 화면 설계기 (Screen Designer)
+
+- **드래그앤드롭 인터페이스**: 컴포넌트를 캔버스에 배치
+- **그리드 시스템**: 12컬럼 그리드 기반 레이아웃
+- **반응형 설정**: 화면 크기별 레이아웃 조정
+- **실시간 미리보기**: 설계한 화면을 즉시 확인
+
+### 2. 컴포넌트 라이브러리
+
+- **입력 컴포넌트**: text, number, date, textarea 등
+- **선택 컴포넌트**: select, checkbox, radio 등
+- **표시 컴포넌트**: label, display, image 등
+- **레이아웃 컴포넌트**: container, row, column 등
+
+### 3. 테이블 연계 시스템
+
+- **자동 위젯 생성**: 컬럼의 웹 타입에 따른 위젯 자동 생성
+- **데이터 바인딩**: 컬럼과 위젯의 자동 연결
+- **유효성 검증**: 컬럼 설정에 따른 자동 검증 규칙 적용
+
+### 4. 템플릿 시스템
+
+- **기본 템플릿**: CRUD, 목록, 상세 등 기본 패턴
+- **사용자 정의 템플릿**: 자주 사용하는 레이아웃 저장
+- **템플릿 공유**: 팀원 간 템플릿 공유 및 재사용
+
+## 🗄️ 데이터베이스 설계
+
+### 1. 기존 테이블 구조 (테이블 타입관리)
+
+#### table_labels (테이블 메타데이터)
+
+```sql
+CREATE TABLE table_labels (
+ table_name varchar(100) NOT NULL,
+ table_label varchar(200) NULL,
+ description text NULL,
+ created_date timestamp DEFAULT now() NULL,
+ updated_date timestamp DEFAULT now() NULL,
+ CONSTRAINT table_labels_pkey PRIMARY KEY (table_name)
+);
+```
+
+#### column_labels (컬럼 메타데이터 + 웹 타입)
+
+```sql
+CREATE TABLE column_labels (
+ id serial4 NOT NULL,
+ table_name varchar(100) NULL,
+ column_name varchar(100) NULL,
+ column_label varchar(200) NULL,
+ web_type varchar(50) NULL, -- 🎯 핵심: 웹 타입 정의
+ detail_settings text NULL, -- 🎯 핵심: 웹 타입별 상세 설정 (JSON)
+ description text NULL,
+ display_order int4 DEFAULT 0 NULL,
+ is_visible bool DEFAULT true NULL,
+ code_category varchar(100) NULL, -- 🎯 code 타입용: 공통코드 카테고리
+ code_value varchar(100) NULL,
+ reference_table varchar(100) NULL, -- 🎯 entity 타입용: 참조 테이블
+ reference_column varchar(100) NULL, -- 🎯 entity 타입용: 참조 컬럼
+ created_date timestamp DEFAULT now() NULL,
+ updated_date timestamp DEFAULT now() NULL,
+ CONSTRAINT column_labels_pkey PRIMARY KEY (id),
+ CONSTRAINT column_labels_table_name_column_name_key UNIQUE (table_name, column_name)
+);
+
+-- 외래키 제약조건
+ALTER TABLE column_labels ADD CONSTRAINT column_labels_table_name_fkey
+ FOREIGN KEY (table_name) REFERENCES table_labels(table_name);
+```
+
+**권장 인덱스 추가:**
+
+```sql
+-- 자주 조회되는 컬럼 조합에 인덱스 추가
+CREATE INDEX idx_column_labels_web_type ON column_labels(web_type);
+CREATE INDEX idx_column_labels_code_category ON column_labels(code_category);
+CREATE INDEX idx_column_labels_reference ON column_labels(reference_table, reference_column);
+
+-- JSON 필드 검색을 위한 GIN 인덱스 (PostgreSQL)
+CREATE INDEX idx_column_labels_detail_settings ON column_labels USING GIN (detail_settings);
+```
+
+### 2. 화면관리 시스템 테이블 구조
+
+#### screen_definitions (화면 정의)
+
+```sql
+CREATE TABLE screen_definitions (
+ screen_id SERIAL PRIMARY KEY,
+ screen_name VARCHAR(100) NOT NULL,
+ screen_code VARCHAR(50) UNIQUE NOT NULL,
+ table_name VARCHAR(100) NOT NULL, -- 🎯 table_labels와 연계
+ description TEXT,
+ is_active CHAR(1) DEFAULT 'Y',
+ created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ created_by VARCHAR(50),
+ updated_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_by VARCHAR(50),
+
+ -- 외래키 제약조건
+ CONSTRAINT fk_screen_definitions_table_name
+ FOREIGN KEY (table_name) REFERENCES table_labels(table_name)
+);
+```
+
+#### screen_layouts (화면 레이아웃)
+
+```sql
+CREATE TABLE screen_layouts (
+ layout_id SERIAL PRIMARY KEY,
+ screen_id INTEGER REFERENCES screen_definitions(screen_id),
+ component_type VARCHAR(50) NOT NULL, -- container, row, column, widget
+ component_id VARCHAR(100) UNIQUE NOT NULL,
+ parent_id VARCHAR(100), -- 부모 컴포넌트 ID
+ position_x INTEGER NOT NULL, -- X 좌표 (그리드)
+ position_y INTEGER NOT NULL, -- Y 좌표 (그리드)
+ width INTEGER NOT NULL, -- 너비 (그리드 컬럼 수: 1-12)
+ height INTEGER NOT NULL, -- 높이 (픽셀)
+ properties JSONB, -- 컴포넌트별 속성
+ display_order INTEGER DEFAULT 0,
+ created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+```
+
+#### screen_widgets (화면 위젯)
+
+```sql
+CREATE TABLE screen_widgets (
+ widget_id SERIAL PRIMARY KEY,
+ layout_id INTEGER REFERENCES screen_layouts(layout_id),
+ table_name VARCHAR(100) NOT NULL, -- 🎯 column_labels와 연계
+ column_name VARCHAR(100) NOT NULL, -- 🎯 column_labels와 연계
+ widget_type VARCHAR(50) NOT NULL, -- 🎯 column_labels.web_type과 동기화
+ label VARCHAR(200), -- 표시 라벨 (column_labels.column_label 사용)
+ placeholder VARCHAR(200), -- 플레이스홀더
+ is_required BOOLEAN DEFAULT FALSE,
+ is_readonly BOOLEAN DEFAULT FALSE,
+ validation_rules JSONB, -- 유효성 검증 규칙 (column_labels.detail_settings에서 자동 생성)
+ display_properties JSONB, -- 표시 속성 (column_labels.detail_settings에서 자동 생성)
+ created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+
+ -- 외래키 제약조건
+ CONSTRAINT fk_screen_widgets_column_labels
+ FOREIGN KEY (table_name, column_name) REFERENCES column_labels(table_name, column_name)
+);
+```
+
+#### screen_templates (화면 템플릿)
+
+```sql
+CREATE TABLE screen_templates (
+ template_id SERIAL PRIMARY KEY,
+ template_name VARCHAR(100) NOT NULL,
+ template_type VARCHAR(50) NOT NULL, -- CRUD, LIST, DETAIL 등
+ description TEXT,
+ layout_data JSONB, -- 레이아웃 데이터
+ is_public BOOLEAN DEFAULT FALSE, -- 공개 여부
+ created_by VARCHAR(50),
+ created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+```
+
+### 3. 테이블 간 연계 관계
+
+```
+table_labels (테이블 메타데이터)
+ ↓ (1:N)
+column_labels (컬럼 메타데이터 + 웹 타입)
+ ↓ (1:N)
+screen_definitions (화면 정의)
+ ↓ (1:N)
+screen_layouts (화면 레이아웃)
+ ↓ (1:N)
+screen_widgets (화면 위젯)
+```
+
+**핵심 연계 포인트:**
+
+- ✅ `screen_definitions.table_name` ↔ `table_labels.table_name`
+- ✅ `screen_widgets.table_name, column_name` ↔ `column_labels.table_name, column_name`
+- ✅ `screen_widgets.widget_type` ↔ `column_labels.web_type` (자동 동기화)
+
+## 🎨 화면 구성 요소
+
+### 1. 레이아웃 컴포넌트
+
+#### Container (컨테이너)
+
+```typescript
+interface ContainerProps {
+ id: string;
+ type: "container";
+ width: number; // 1-12
+ height: number;
+ padding: number;
+ margin: number;
+ backgroundColor?: string;
+ border?: string;
+}
+```
+
+#### Row (행)
+
+```typescript
+interface RowProps {
+ id: string;
+ type: "row";
+ columns: number; // 1-12
+ gap: number;
+ alignItems: "start" | "center" | "end";
+ justifyContent: "start" | "center" | "end" | "space-between";
+}
+```
+
+#### Column (컬럼)
+
+```typescript
+interface ColumnProps {
+ id: string;
+ type: "column";
+ width: number; // 1-12
+ offset: number; // 오프셋
+ order: number; // 순서
+}
+```
+
+### 2. 입력 위젯
+
+#### Text Input
+
+```typescript
+interface TextInputProps {
+ id: string;
+ type: "text";
+ label: string;
+ placeholder?: string;
+ required: boolean;
+ maxLength?: number;
+ pattern?: string;
+ columnName: string; // 연결된 테이블 컬럼
+}
+```
+
+#### Select Dropdown
+
+```typescript
+interface SelectProps {
+ id: string;
+ type: "select";
+ label: string;
+ options: Array<{ value: string; label: string }>;
+ multiple: boolean;
+ searchable: boolean;
+ columnName: string;
+}
+```
+
+#### Date Picker
+
+```typescript
+interface DatePickerProps {
+ id: string;
+ type: "date";
+ label: string;
+ format: string; // YYYY-MM-DD, MM/DD/YYYY 등
+ minDate?: string;
+ maxDate?: string;
+ columnName: string;
+}
+```
+
+### 3. 표시 위젯
+
+#### Label
+
+```typescript
+interface LabelProps {
+ id: string;
+ type: "label";
+ text: string;
+ fontSize: number;
+ fontWeight: "normal" | "bold";
+ color: string;
+ alignment: "left" | "center" | "right";
+}
+```
+
+#### Display Field
+
+```typescript
+interface DisplayFieldProps {
+ id: string;
+ type: "display";
+ label: string;
+ columnName: string;
+ format?: string; // 날짜, 숫자 포맷
+ alignment: "left" | "center" | "right";
+}
+```
+
+## 🖱️ 드래그앤드롭 설계
+
+### 1. 드래그앤드롭 아키텍처
+
+```typescript
+// 드래그 상태 관리
+interface DragState {
+ isDragging: boolean;
+ draggedItem: ComponentData | null;
+ dragSource: "toolbox" | "canvas";
+ dropTarget: string | null;
+}
+
+// 드롭 영역 정의
+interface DropZone {
+ id: string;
+ accepts: string[]; // 허용되는 컴포넌트 타입
+ position: { x: number; y: number };
+ size: { width: number; height: number };
+}
+```
+
+### 2. 컴포넌트 배치 로직
+
+```typescript
+// 그리드 기반 배치
+function calculateGridPosition(
+ mouseX: number,
+ mouseY: number,
+ gridSize: number
+): GridPosition {
+ return {
+ x: Math.floor(mouseX / gridSize),
+ y: Math.floor(mouseY / gridSize),
+ };
+}
+
+// 컴포넌트 크기 조정
+function resizeComponent(
+ component: ComponentData,
+ newWidth: number,
+ newHeight: number
+): ComponentData {
+ return {
+ ...component,
+ width: Math.max(1, Math.min(12, newWidth)),
+ height: Math.max(50, newHeight),
+ };
+}
+```
+
+### 3. 실시간 미리보기
+
+```typescript
+// 캔버스 상태를 실제 컴포넌트로 변환
+function generatePreview(layout: LayoutData): React.ReactElement {
+ return (
+
+ {layout.components.map((component) => renderComponent(component))}
+
+ );
+}
+
+// 컴포넌트 렌더링
+function renderComponent(component: ComponentData): React.ReactElement {
+ switch (component.type) {
+ case "text":
+ return ;
+ case "select":
+ return ;
+ case "date":
+ return ;
+ default:
+ return Unknown component
;
+ }
+}
+```
+
+## 🔗 테이블 타입 연계
+
+### 1. 웹 타입 설정 방법
+
+#### 테이블 타입관리에서 웹 타입 설정
+
+**현재 테이블 구조 기반 설정:**
+
+```typescript
+// 컬럼별 웹 타입 설정 인터페이스 (현재 테이블 구조와 완벽 일치)
+interface ColumnWebTypeSetting {
+ tableName: string; // column_labels.table_name
+ columnName: string; // column_labels.column_name
+ webType: WebType; // column_labels.web_type
+ columnLabel?: string; // column_labels.column_label
+ detailSettings?: string; // column_labels.detail_settings (JSON)
+ codeCategory?: string; // column_labels.code_category
+ referenceTable?: string; // column_labels.reference_table
+ referenceColumn?: string; // column_labels.reference_column
+ isVisible?: boolean; // column_labels.is_visible
+ displayOrder?: number; // column_labels.display_order
+ description?: string; // column_labels.description
+}
+
+// 웹 타입 설정 API (column_labels 테이블에 직접 저장)
+async function setColumnWebType(setting: ColumnWebTypeSetting): Promise {
+ await api.post("/table-management/columns/web-type", setting);
+}
+
+// 웹 타입 조회 API (column_labels 테이블에서 직접 조회)
+async function getColumnWebType(
+ tableName: string,
+ columnName: string
+): Promise {
+ return api.get(
+ `/table-management/columns/${tableName}/${columnName}/web-type`
+ );
+}
+
+// 테이블의 모든 컬럼 웹 타입 조회
+async function getTableColumnWebTypes(
+ tableName: string
+): Promise {
+ return api.get(`/table-management/tables/${tableName}/columns/web-types`);
+}
+```
+
+#### 웹 타입별 추가 설정 (현재 테이블 구조 기반)
+
+**`column_labels.detail_settings` 필드에 JSON 형태로 저장:**
+
+| 웹 타입 | detail_settings JSON 구조 | 설명 |
+| ------------ | --------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
+| **text** | `{"maxLength": 255, "pattern": "regex"}` | 최대 길이, 정규식 패턴 |
+| **number** | `{"min": 0, "max": 999, "step": 1}` | 최소값, 최대값, 증감 단위 |
+| **date** | `{"format": "YYYY-MM-DD", "minDate": "", "maxDate": ""}` | 날짜 형식, 범위 제한 |
+| **code** | `{"codeCategory": "USER_STATUS"}` | 공통코드 카테고리 (code_category 필드와 연계) |
+| **entity** | `{"referenceTable": "users", "referenceColumn": "id"}` | 참조 테이블 및 컬럼 (reference_table, reference_column 필드와 연계) |
+| **textarea** | `{"rows": 3, "maxLength": 1000}` | 행 수, 최대 길이 |
+| **select** | `{"options": [{"value": "Y", "label": "예"}, {"value": "N", "label": "아니오"}]}` | 옵션 목록, 다중 선택 |
+| **checkbox** | `{"defaultChecked": false, "label": "동의함"}` | 기본 체크 상태, 라벨 |
+| **radio** | `{"options": [{"value": "M", "label": "남성"}, {"value": "F", "label": "여성"}]}` | 라디오 옵션 목록 |
+| **file** | `{"accept": ".jpg,.png,.pdf", "maxSize": 10485760}` | 허용 파일 형식, 최대 크기 |
+
+**실제 데이터베이스 저장 예시:**
+
+```sql
+-- text 타입 컬럼 설정
+UPDATE column_labels
+SET detail_settings = '{"maxLength": 255, "pattern": "^[a-zA-Z0-9가-힣]+$"}'
+WHERE table_name = 'user_info' AND column_name = 'user_name';
+
+-- code 타입 컬럼 설정 (code_category와 연계)
+UPDATE column_labels
+SET web_type = 'code',
+ code_category = 'USER_STATUS',
+ detail_settings = '{"displayFormat": "label"}'
+WHERE table_name = 'user_info' AND column_name = 'status';
+
+-- entity 타입 컬럼 설정 (reference_table, reference_column과 연계)
+UPDATE column_labels
+SET web_type = 'entity',
+ reference_table = 'dept_info',
+ reference_column = 'dept_code',
+ detail_settings = '{"searchable": true, "multiple": false}'
+WHERE table_name = 'user_info' AND column_name = 'dept_code';
+```
+
+### 2. 자동 위젯 생성
+
+```typescript
+// 컬럼 정보를 기반으로 위젯 자동 생성 (현재 테이블 구조 기반)
+function generateWidgetFromColumn(column: ColumnInfo): WidgetData {
+ const baseWidget = {
+ id: generateId(),
+ tableName: column.table_name, // 🎯 column_labels.table_name
+ columnName: column.column_name, // 🎯 column_labels.column_name
+ label: column.column_label || column.column_name, // 🎯 column_labels.column_label
+ required: column.is_nullable === "N",
+ readonly: false,
+ };
+
+ // detail_settings JSON 파싱
+ const detailSettings = column.detail_settings
+ ? JSON.parse(column.detail_settings)
+ : {};
+
+ switch (column.web_type) {
+ case "text":
+ return {
+ ...baseWidget,
+ type: "text",
+ maxLength: detailSettings.maxLength || column.character_maximum_length,
+ placeholder: `Enter ${column.column_label || column.column_name}`,
+ pattern: detailSettings.pattern,
+ validationRules: {
+ maxLength: detailSettings.maxLength,
+ pattern: detailSettings.pattern,
+ },
+ };
+
+ case "number":
+ return {
+ ...baseWidget,
+ type: "number",
+ min: detailSettings.min,
+ max:
+ detailSettings.max ||
+ (column.numeric_precision
+ ? Math.pow(10, column.numeric_precision) - 1
+ : undefined),
+ step:
+ detailSettings.step ||
+ (column.numeric_scale > 0 ? Math.pow(10, -column.numeric_scale) : 1),
+ validationRules: {
+ min: detailSettings.min,
+ max: detailSettings.max,
+ step: detailSettings.step,
+ },
+ };
+
+ case "date":
+ return {
+ ...baseWidget,
+ type: "date",
+ format: detailSettings.format || "YYYY-MM-DD",
+ minDate: detailSettings.minDate,
+ maxDate: detailSettings.maxDate,
+ validationRules: {
+ minDate: detailSettings.minDate,
+ maxDate: detailSettings.maxDate,
+ },
+ };
+
+ case "code":
+ return {
+ ...baseWidget,
+ type: "select",
+ options: [], // 코드 카테고리에서 로드
+ codeCategory: column.code_category, // 🎯 column_labels.code_category
+ multiple: detailSettings.multiple || false,
+ searchable: detailSettings.searchable || false,
+ };
+
+ case "entity":
+ return {
+ ...baseWidget,
+ type: "entity-select",
+ referenceTable: column.reference_table, // 🎯 column_labels.reference_table
+ referenceColumn: column.reference_column, // 🎯 column_labels.reference_column
+ searchable: detailSettings.searchable || true,
+ multiple: detailSettings.multiple || false,
+ };
+
+ case "textarea":
+ return {
+ ...baseWidget,
+ type: "textarea",
+ rows: detailSettings.rows || 3,
+ maxLength: detailSettings.maxLength || column.character_maximum_length,
+ validationRules: {
+ maxLength: detailSettings.maxLength,
+ },
+ };
+
+ case "select":
+ return {
+ ...baseWidget,
+ type: "select",
+ options: detailSettings.options || [],
+ multiple: detailSettings.multiple || false,
+ searchable: detailSettings.searchable || false,
+ };
+
+ case "checkbox":
+ return {
+ ...baseWidget,
+ type: "checkbox",
+ defaultChecked: detailSettings.defaultChecked || false,
+ label: detailSettings.label || column.column_label,
+ };
+
+ case "radio":
+ return {
+ ...baseWidget,
+ type: "radio",
+ options: detailSettings.options || [],
+ inline: detailSettings.inline || false,
+ };
+
+ case "file":
+ return {
+ ...baseWidget,
+ type: "file",
+ accept: detailSettings.accept || "*/*",
+ maxSize: detailSettings.maxSize || 10485760, // 10MB
+ multiple: detailSettings.multiple || false,
+ };
+
+ default:
+ return {
+ ...baseWidget,
+ type: "text",
+ };
+ }
+}
+```
+
+### 2. 데이터 바인딩
+
+```typescript
+// 위젯과 컬럼 연결
+interface DataBinding {
+ widgetId: string;
+ columnName: string;
+ tableName: string;
+ bindingType: "input" | "output" | "bidirectional";
+ transformFunction?: string; // 데이터 변환 함수
+}
+
+// 바인딩 정보 저장
+function saveDataBinding(binding: DataBinding): Promise {
+ return api.post("/screen-management/bindings", binding);
+}
+```
+
+### 3. 유효성 검증 규칙
+
+```typescript
+// 컬럼 설정에 따른 자동 검증 규칙
+function generateValidationRules(column: ColumnInfo): ValidationRule[] {
+ const rules: ValidationRule[] = [];
+
+ // 필수 입력 검증
+ if (column.isNullable === "N") {
+ rules.push({
+ type: "required",
+ message: `${column.displayName}은(는) 필수 입력 항목입니다.`,
+ });
+ }
+
+ // 길이 제한 검증
+ if (column.maxLength) {
+ rules.push({
+ type: "maxLength",
+ value: column.maxLength,
+ message: `${column.displayName}은(는) ${column.maxLength}자 이하여야 합니다.`,
+ });
+ }
+
+ // 숫자 범위 검증
+ if (column.webType === "number") {
+ if (column.numericPrecision && column.numericScale) {
+ const maxValue =
+ Math.pow(10, column.numericPrecision - column.numericScale) - 1;
+ rules.push({
+ type: "max",
+ value: maxValue,
+ message: `${column.displayName}은(는) ${maxValue} 이하여야 합니다.`,
+ });
+ }
+ }
+
+ return rules;
+}
+```
+
+## 🌐 API 설계
+
+### 1. 화면 정의 API
+
+#### 화면 목록 조회
+
+```typescript
+GET /api/screen-management/screens
+Response: {
+ success: boolean;
+ data: ScreenDefinition[];
+ total: number;
+}
+```
+
+#### 화면 생성
+
+```typescript
+POST /api/screen-management/screens
+Body: {
+ screenName: string;
+ screenCode: string;
+ tableName: string;
+ description?: string;
+}
+```
+
+#### 화면 수정
+
+```typescript
+PUT /api/screen-management/screens/:screenId
+Body: {
+ screenName?: string;
+ description?: string;
+ isActive?: boolean;
+}
+```
+
+#### 화면 삭제
+
+```typescript
+DELETE /api/screen-management/screens/:screenId
+```
+
+### 2. 레이아웃 API
+
+#### 레이아웃 조회
+
+```typescript
+GET /api/screen-management/screens/:screenId/layout
+Response: {
+ success: boolean;
+ data: LayoutData;
+}
+```
+
+#### 레이아웃 저장
+
+```typescript
+POST /api/screen-management/screens/:screenId/layout
+Body: {
+ components: ComponentData[];
+ gridSettings: GridSettings;
+}
+```
+
+#### 레이아웃 복사
+
+```typescript
+POST /api/screen-management/screens/:screenId/layout/copy
+Body: {
+ targetScreenId: number;
+}
+```
+
+### 3. 위젯 API
+
+#### 위젯 속성 조회
+
+```typescript
+GET /api/screen-management/widgets/:widgetId/properties
+Response: {
+ success: boolean;
+ data: WidgetProperties;
+}
+```
+
+#### 위젯 속성 수정
+
+```typescript
+PUT /api/screen-management/widgets/:widgetId/properties
+Body: {
+ label?: string;
+ placeholder?: string;
+ required?: boolean;
+ readonly?: boolean;
+ validationRules?: ValidationRule[];
+}
+```
+
+### 4. 템플릿 API
+
+#### 템플릿 목록 조회
+
+```typescript
+GET /api/screen-management/templates
+Query: {
+ type?: string;
+ isPublic?: boolean;
+ createdBy?: string;
+}
+```
+
+#### 템플릿 적용
+
+```typescript
+POST /api/screen-management/screens/:screenId/apply-template
+Body: {
+ templateId: number;
+ overrideExisting: boolean;
+}
+```
+
+## 🎭 프론트엔드 구현
+
+### 1. 화면 설계기 컴포넌트
+
+```typescript
+// ScreenDesigner.tsx
+export default function ScreenDesigner() {
+ const [layout, setLayout] = useState({ components: [] });
+ const [selectedComponent, setSelectedComponent] = useState(
+ null
+ );
+ const [dragState, setDragState] = useState({
+ isDragging: false,
+ draggedItem: null,
+ dragSource: "toolbox",
+ dropTarget: null,
+ });
+
+ // 컴포넌트 추가
+ const addComponent = (component: ComponentData) => {
+ setLayout((prev) => ({
+ ...prev,
+ components: [...prev.components, component],
+ }));
+ };
+
+ // 컴포넌트 삭제
+ const removeComponent = (componentId: string) => {
+ setLayout((prev) => ({
+ ...prev,
+ components: prev.components.filter((c) => c.id !== componentId),
+ }));
+ };
+
+ // 컴포넌트 이동
+ const moveComponent = (componentId: string, newPosition: Position) => {
+ setLayout((prev) => ({
+ ...prev,
+ components: prev.components.map((c) =>
+ c.id === componentId ? { ...c, position: newPosition } : c
+ ),
+ }));
+ };
+
+ return (
+
+
+
+
c.id === selectedComponent)}
+ onPropertyChange={updateComponentProperty}
+ />
+
+
+ );
+}
+```
+
+### 2. 드래그앤드롭 구현
+
+```typescript
+// useDragAndDrop.ts
+export function useDragAndDrop() {
+ const [dragState, setDragState] = useState({
+ isDragging: false,
+ draggedItem: null,
+ dragSource: "toolbox",
+ dropTarget: null,
+ });
+
+ const startDrag = (item: ComponentData, source: "toolbox" | "canvas") => {
+ setDragState({
+ isDragging: true,
+ draggedItem: item,
+ dragSource: source,
+ dropTarget: null,
+ });
+ };
+
+ const endDrag = () => {
+ setDragState({
+ isDragging: false,
+ draggedItem: null,
+ dragSource: "toolbox",
+ dropTarget: null,
+ });
+ };
+
+ const updateDropTarget = (targetId: string | null) => {
+ setDragState((prev) => ({ ...prev, dropTarget: targetId }));
+ };
+
+ return {
+ dragState,
+ startDrag,
+ endDrag,
+ updateDropTarget,
+ };
+}
+```
+
+### 3. 그리드 시스템
+
+```typescript
+// GridSystem.tsx
+export default function GridSystem({ children, columns = 12 }) {
+ const gridStyle = {
+ display: "grid",
+ gridTemplateColumns: `repeat(${columns}, 1fr)`,
+ gap: "16px",
+ padding: "16px",
+ };
+
+ return (
+
+ {children}
+
+ );
+}
+
+// GridItem.tsx
+interface GridItemProps {
+ width: number; // 1-12
+ offset?: number;
+ children: React.ReactNode;
+}
+
+export default function GridItem({
+ width,
+ offset = 0,
+ children,
+}: GridItemProps) {
+ const gridColumn =
+ offset > 0 ? `${offset + 1} / span ${width}` : `span ${width}`;
+
+ const style = {
+ gridColumn,
+ minHeight: "50px",
+ };
+
+ return (
+
+ {children}
+
+ );
+}
+```
+
+## ⚙️ 백엔드 구현
+
+### 1. 화면 관리 서비스
+
+```typescript
+// screenManagementService.ts
+export class ScreenManagementService {
+ // 화면 정의 생성
+ async createScreen(
+ screenData: CreateScreenRequest
+ ): Promise {
+ const screen = await prisma.screen_definitions.create({
+ data: {
+ screen_name: screenData.screenName,
+ screen_code: screenData.screenCode,
+ table_name: screenData.tableName,
+ description: screenData.description,
+ created_by: screenData.createdBy,
+ },
+ });
+
+ return this.mapToScreenDefinition(screen);
+ }
+
+ // 레이아웃 저장
+ async saveLayout(screenId: number, layoutData: LayoutData): Promise {
+ // 기존 레이아웃 삭제
+ await prisma.screen_layouts.deleteMany({
+ where: { screen_id: screenId },
+ });
+
+ // 새 레이아웃 저장
+ const layoutPromises = layoutData.components.map((component) =>
+ prisma.screen_layouts.create({
+ data: {
+ screen_id: screenId,
+ component_type: component.type,
+ component_id: component.id,
+ parent_id: component.parentId,
+ position_x: component.position.x,
+ position_y: component.position.y,
+ width: component.width,
+ height: component.height,
+ properties: component.properties,
+ display_order: component.displayOrder,
+ },
+ })
+ );
+
+ await Promise.all(layoutPromises);
+ }
+
+ // 화면 미리보기 생성
+ async generatePreview(screenId: number): Promise {
+ const screen = await prisma.screen_definitions.findUnique({
+ where: { screen_id: screenId },
+ include: {
+ layouts: {
+ include: { widgets: true },
+ orderBy: { display_order: "asc" },
+ },
+ },
+ });
+
+ if (!screen) {
+ throw new Error("Screen not found");
+ }
+
+ return this.buildPreviewData(screen);
+ }
+
+ private buildPreviewData(screen: any): PreviewData {
+ // 레이아웃을 트리 구조로 변환
+ const componentTree = this.buildComponentTree(screen.layouts);
+
+ // 위젯 데이터 바인딩
+ const boundWidgets = this.bindWidgetData(componentTree, screen.table_name);
+
+ return {
+ screenId: screen.screen_id,
+ screenName: screen.screen_name,
+ tableName: screen.table_name,
+ components: boundWidgets,
+ metadata: this.getTableMetadata(screen.table_name),
+ };
+ }
+}
+```
+
+### 2. 테이블 타입 연계 서비스
+
+```typescript
+// tableTypeIntegrationService.ts
+export class TableTypeIntegrationService {
+ // 컬럼 정보 조회 (웹 타입 포함) - 현재 테이블 구조 기반
+ async getColumnInfo(tableName: string): Promise {
+ const columns = await prisma.$queryRaw`
+ SELECT
+ c.column_name,
+ COALESCE(cl.column_label, c.column_name) as column_label,
+ c.data_type,
+ COALESCE(cl.web_type, 'text') as web_type,
+ c.is_nullable,
+ c.column_default,
+ c.character_maximum_length,
+ c.numeric_precision,
+ c.numeric_scale,
+ cl.detail_settings, -- 🎯 column_labels.detail_settings
+ cl.code_category, -- 🎯 column_labels.code_category
+ cl.reference_table, -- 🎯 column_labels.reference_table
+ cl.reference_column, -- 🎯 column_labels.reference_column
+ cl.is_visible, -- 🎯 column_labels.is_visible
+ cl.display_order, -- 🎯 column_labels.display_order
+ cl.description -- 🎯 column_labels.description
+ FROM information_schema.columns c
+ LEFT JOIN column_labels cl ON c.table_name = cl.table_name
+ AND c.column_name = cl.column_name
+ WHERE c.table_name = ${tableName}
+ ORDER BY COALESCE(cl.display_order, c.ordinal_position)
+ `;
+
+ return columns as ColumnInfo[];
+ }
+
+ // 웹 타입 설정 - 현재 테이블 구조 기반
+ async setColumnWebType(
+ tableName: string,
+ columnName: string,
+ webType: string,
+ additionalSettings?: any
+ ): Promise {
+ await prisma.column_labels.upsert({
+ where: {
+ table_name_column_name: {
+ table_name: tableName,
+ column_name: columnName,
+ },
+ },
+ update: {
+ web_type: webType,
+ column_label: additionalSettings?.columnLabel,
+ detail_settings: additionalSettings?.detailSettings
+ ? JSON.stringify(additionalSettings.detailSettings)
+ : null,
+ code_category: additionalSettings?.codeCategory,
+ reference_table: additionalSettings?.referenceTable,
+ reference_column: additionalSettings?.referenceColumn,
+ is_visible: additionalSettings?.isVisible ?? true,
+ display_order: additionalSettings?.displayOrder ?? 0,
+ description: additionalSettings?.description,
+ updated_date: new Date(),
+ },
+ create: {
+ table_name: tableName,
+ column_name: columnName,
+ column_label: additionalSettings?.columnLabel,
+ web_type: webType,
+ detail_settings: additionalSettings?.detailSettings
+ ? JSON.stringify(additionalSettings.detailSettings)
+ : null,
+ code_category: additionalSettings?.codeCategory,
+ reference_table: additionalSettings?.referenceTable,
+ reference_column: additionalSettings?.referenceColumn,
+ is_visible: additionalSettings?.isVisible ?? true,
+ display_order: additionalSettings?.displayOrder ?? 0,
+ description: additionalSettings?.description,
+ created_date: new Date(),
+ },
+ });
+ }
+
+ // 웹 타입 조회 - 현재 테이블 구조 기반
+ async getColumnWebType(
+ tableName: string,
+ columnName: string
+ ): Promise {
+ const columnLabel = await prisma.column_labels.findUnique({
+ where: {
+ table_name_column_name: {
+ table_name: tableName,
+ column_name: columnName,
+ },
+ },
+ });
+
+ if (!columnLabel) {
+ return {
+ tableName,
+ columnName,
+ webType: "text", // 기본값
+ columnLabel: columnName,
+ detailSettings: {},
+ codeCategory: null,
+ referenceTable: null,
+ referenceColumn: null,
+ isVisible: true,
+ displayOrder: 0,
+ description: null,
+ };
+ }
+
+ return {
+ tableName,
+ columnName,
+ webType: columnLabel.web_type || "text",
+ columnLabel: columnLabel.column_label,
+ detailSettings: columnLabel.detail_settings
+ ? JSON.parse(columnLabel.detail_settings)
+ : {},
+ codeCategory: columnLabel.code_category,
+ referenceTable: columnLabel.reference_table,
+ referenceColumn: columnLabel.reference_column,
+ isVisible: columnLabel.is_visible ?? true,
+ displayOrder: columnLabel.display_order ?? 0,
+ description: columnLabel.description,
+ };
+ }
+
+ // 웹 타입별 위젯 생성 - 현재 테이블 구조 기반
+ generateWidgetFromColumn(column: ColumnInfo): WidgetData {
+ const baseWidget = {
+ id: generateId(),
+ tableName: column.table_name, // 🎯 column_labels.table_name
+ columnName: column.column_name, // 🎯 column_labels.column_name
+ label: column.column_label || column.column_name, // 🎯 column_labels.column_label
+ required: column.is_nullable === "N",
+ readonly: false,
+ };
+
+ // detail_settings JSON 파싱
+ const detailSettings = column.detail_settings
+ ? JSON.parse(column.detail_settings)
+ : {};
+
+ switch (column.web_type) {
+ case "text":
+ return {
+ ...baseWidget,
+ type: "text",
+ maxLength:
+ detailSettings.maxLength || column.character_maximum_length,
+ placeholder: `Enter ${column.column_label || column.column_name}`,
+ pattern: detailSettings.pattern,
+ };
+
+ case "number":
+ return {
+ ...baseWidget,
+ type: "number",
+ min: detailSettings.min,
+ max:
+ detailSettings.max ||
+ (column.numeric_precision
+ ? Math.pow(10, column.numeric_precision) - 1
+ : undefined),
+ step:
+ detailSettings.step ||
+ (column.numeric_scale > 0
+ ? Math.pow(10, -column.numeric_scale)
+ : 1),
+ };
+
+ case "date":
+ return {
+ ...baseWidget,
+ type: "date",
+ format: detailSettings.format || "YYYY-MM-DD",
+ minDate: detailSettings.minDate,
+ maxDate: detailSettings.maxDate,
+ };
+
+ case "code":
+ return {
+ ...baseWidget,
+ type: "select",
+ options: [], // 코드 카테고리에서 로드
+ codeCategory: column.code_category, // 🎯 column_labels.code_category
+ multiple: detailSettings.multiple || false,
+ searchable: detailSettings.searchable || false,
+ };
+
+ case "entity":
+ return {
+ ...baseWidget,
+ type: "entity-select",
+ referenceTable: column.reference_table, // 🎯 column_labels.reference_table
+ referenceColumn: column.reference_column, // 🎯 column_labels.reference_column
+ searchable: detailSettings.searchable || true,
+ multiple: detailSettings.multiple || false,
+ };
+
+ case "textarea":
+ return {
+ ...baseWidget,
+ type: "textarea",
+ rows: detailSettings.rows || 3,
+ maxLength:
+ detailSettings.maxLength || column.character_maximum_length,
+ };
+
+ case "select":
+ return {
+ ...baseWidget,
+ type: "select",
+ options: detailSettings.options || [],
+ multiple: detailSettings.multiple || false,
+ searchable: detailSettings.searchable || false,
+ };
+
+ case "checkbox":
+ return {
+ ...baseWidget,
+ type: "checkbox",
+ defaultChecked: detailSettings.defaultChecked || false,
+ label: detailSettings.label || column.column_label,
+ };
+
+ case "radio":
+ return {
+ ...baseWidget,
+ type: "radio",
+ options: detailSettings.options || [],
+ inline: detailSettings.inline || false,
+ };
+
+ case "file":
+ return {
+ ...baseWidget,
+ type: "file",
+ accept: detailSettings.accept || "*/*",
+ maxSize: detailSettings.maxSize || 10485760, // 10MB
+ multiple: detailSettings.multiple || false,
+ };
+
+ default:
+ return {
+ ...baseWidget,
+ type: "text",
+ };
+ }
+ }
+
+ // 코드 카테고리 옵션 로드
+ async loadCodeOptions(codeCategory: string): Promise {
+ const codes = await prisma.code_info.findMany({
+ where: { code_category: codeCategory, is_active: "Y" },
+ select: { code_value: true, code_name: true },
+ orderBy: { sort_order: "asc" },
+ });
+
+ return codes.map((code) => ({
+ value: code.code_value,
+ label: code.code_name,
+ }));
+ }
+
+ // 참조 테이블 옵션 로드
+ async loadReferenceOptions(
+ referenceTable: string
+ ): Promise {
+ const records = await prisma.$queryRaw`
+ SELECT DISTINCT ${referenceTable}.id, ${referenceTable}.name
+ FROM ${referenceTable}
+ ORDER BY ${referenceTable}.name
+ `;
+
+ return records.map((record: any) => ({
+ value: record.id,
+ label: record.name,
+ }));
+ }
+}
+```
+
+## 🎬 사용 시나리오
+
+### 1. 웹 타입 설정 (테이블 타입관리)
+
+1. **테이블 선택**: 테이블 타입관리에서 웹 타입을 설정할 테이블 선택
+2. **컬럼 관리**: 해당 테이블의 컬럼 목록에서 웹 타입을 설정할 컬럼 선택
+3. **웹 타입 선택**: 컬럼의 용도에 맞는 웹 타입 선택 (text, number, date, code, entity 등)
+4. **추가 설정**: 웹 타입별 필요한 추가 설정 구성
+ - **code 타입**: 공통코드 카테고리 선택
+ - **entity 타입**: 참조 테이블 및 컬럼 지정
+ - **validation**: 유효성 검증 규칙 설정
+ - **display**: 표시 속성 설정
+5. **저장**: 웹 타입 설정을 데이터베이스에 저장
+6. **연계 확인**: 화면관리 시스템에서 자동 위젯 생성 확인
+
+### 2. 새로운 화면 설계
+
+1. **테이블 선택**: 테이블 타입관리에서 설계할 테이블 선택
+2. **웹 타입 확인**: 각 컬럼의 웹 타입 설정 상태 확인
+3. **화면 생성**: 화면명과 코드를 입력하여 새 화면 생성
+4. **자동 위젯 생성**: 컬럼의 웹 타입에 따라 자동으로 위젯 생성
+5. **컴포넌트 배치**: 드래그앤드롭으로 컴포넌트를 캔버스에 배치
+6. **속성 설정**: 각 컴포넌트의 속성을 Properties 패널에서 설정
+7. **미리보기**: 실시간으로 설계한 화면 확인
+8. **저장**: 완성된 화면 레이아웃을 데이터베이스에 저장
+
+### 2. 기존 화면 수정
+
+1. **화면 선택**: 수정할 화면을 목록에서 선택
+2. **레이아웃 로드**: 기존 레이아웃을 캔버스에 로드
+3. **컴포넌트 수정**: 컴포넌트 추가/삭제/이동/수정
+4. **속성 변경**: 컴포넌트 속성 변경
+5. **변경사항 확인**: 미리보기로 변경사항 확인
+6. **저장**: 수정된 레이아웃 저장
+
+### 3. 템플릿 활용
+
+1. **템플릿 선택**: 적합한 템플릿을 목록에서 선택
+2. **템플릿 적용**: 선택한 템플릿을 현재 화면에 적용
+3. **커스터마이징**: 템플릿을 기반으로 필요한 부분 수정
+4. **저장**: 커스터마이징된 화면 저장
+
+### 4. 화면 배포
+
+1. **화면 활성화**: 설계 완료된 화면을 활성 상태로 변경
+2. **권한 설정**: 화면 접근 권한 설정
+3. **메뉴 연결**: 메뉴 시스템에 화면 연결
+4. **테스트**: 실제 환경에서 화면 동작 테스트
+5. **배포**: 운영 환경에 화면 배포
+
+## 📅 개발 계획
+
+### Phase 1: 기본 구조 및 데이터베이스 (2주)
+
+- [ ] 데이터베이스 스키마 설계 및 생성
+- [ ] 기본 API 구조 설계
+- [ ] 화면 정의 및 레이아웃 테이블 생성
+- [ ] 기본 CRUD API 구현
+
+### Phase 2: 드래그앤드롭 핵심 기능 (3주)
+
+- [ ] 드래그앤드롭 라이브러리 선택 및 구현
+- [ ] 그리드 시스템 구현
+- [ ] 컴포넌트 배치 및 이동 로직 구현
+- [ ] 컴포넌트 크기 조정 기능 구현
+
+### Phase 3: 컴포넌트 라이브러리 (2주)
+
+- [ ] 기본 입력 컴포넌트 구현
+- [ ] 선택 컴포넌트 구현
+- [ ] 표시 컴포넌트 구현
+- [ ] 레이아웃 컴포넌트 구현
+
+### Phase 4: 테이블 타입 연계 (2주)
+
+- [ ] 테이블 타입관리와 연계 API 구현
+- [ ] 웹 타입 설정 및 관리 기능 구현
+- [ ] 웹 타입별 추가 설정 관리 기능 구현
+- [ ] 자동 위젯 생성 로직 구현
+- [ ] 데이터 바인딩 시스템 구현
+- [ ] 유효성 검증 규칙 자동 적용
+
+### Phase 5: 미리보기 및 템플릿 (2주)
+
+- [ ] 실시간 미리보기 시스템 구현
+- [ ] 기본 템플릿 구현
+- [ ] 템플릿 저장 및 적용 기능 구현
+- [ ] 템플릿 공유 시스템 구현
+
+### Phase 6: 통합 및 테스트 (1주)
+
+- [ ] 전체 시스템 통합 테스트
+- [ ] 성능 최적화
+- [ ] 사용자 테스트 및 피드백 반영
+- [ ] 문서화 및 사용자 가이드 작성
+
+## 🎯 결론
+
+화면관리 시스템은 테이블 타입관리와 연계하여 사용자가 직관적으로 웹 화면을 설계할 수 있는 강력한 도구입니다. 드래그앤드롭 인터페이스와 자동 위젯 생성 기능을 통해 개발자가 아닌 사용자도 전문적인 웹 화면을 쉽게 구성할 수 있습니다.
+
+이 시스템을 통해 ERP 시스템의 화면 개발 생산성을 크게 향상시키고, 사용자 요구사항에 따른 빠른 화면 구성이 가능해질 것입니다.