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