# 야드 관리 3D - 데이터 바인딩 시스템 재설계 ## 1. 개요 ### 현재 방식의 문제점 - 고정된 임시 자재 마스터(`temp_material_master`) 테이블에 의존 - 실제 외부 시스템의 자재 데이터와 연동 불가 - 자재 목록이 제한적이고 유연성 부족 - 사용자가 직접 데이터를 선택하거나 입력할 수 없음 ### 새로운 방식의 목표 - 차트/리스트 위젯과 동일한 데이터 소스 선택 방식 적용 - DB 커넥션 또는 REST API를 통해 실제 자재 데이터 연동 - 사용자가 자재명, 수량 등을 직접 매핑 및 입력 가능 - 설정되지 않은 요소는 뷰어에서 명확히 표시 --- ## 2. 핵심 변경사항 ### 2.1 요소(Element) 개념 도입 - 기존: 자재 목록에서 클릭 → 즉시 배치 - 변경: [+ 요소 추가] 버튼 클릭 → 3D 캔버스에 즉시 빈 요소 배치 → 우측 패널이 데이터 바인딩 설정 화면으로 전환 ### 2.2 데이터 소스 선택 - 현재 DB (내부 PostgreSQL) - 외부 DB 커넥션 - REST API ### 2.3 데이터 매핑 - 자재명 필드 선택 (데이터 소스에서) - 수량 필드 선택 (데이터 소스에서) - 단위 직접 입력 (예: EA, BOX, KG 등) - 색상 선택 --- ## 3. 데이터베이스 스키마 변경 ### 3.1 기존 테이블 수정: `yard_material_placement` ```sql -- 기존 컬럼 변경 ALTER TABLE yard_material_placement -- 기존 컬럼 제거 (외부 자재 ID 관련) DROP COLUMN IF EXISTS external_material_id, -- 데이터 소스 정보 추가 ADD COLUMN data_source_type VARCHAR(20), -- 'database', 'external_db', 'rest_api' ADD COLUMN data_source_config JSONB, -- 데이터 소스 설정 -- 데이터 바인딩 정보 추가 ADD COLUMN data_binding JSONB, -- 필드 매핑 정보 -- 자재 정보를 NULL 허용으로 변경 (설정 전에는 NULL) ALTER COLUMN material_code DROP NOT NULL, ALTER COLUMN material_name DROP NOT NULL, ALTER COLUMN quantity DROP NOT NULL; ``` ### 3.2 data_source_config 구조 ```typescript interface DataSourceConfig { type: "database" | "external_db" | "rest_api"; // type === 'database' (현재 DB) query?: string; // type === 'external_db' (외부 DB) connectionId?: number; query?: string; // type === 'rest_api' url?: string; method?: "GET" | "POST"; headers?: Record; queryParams?: Record; body?: string; dataPath?: string; // 응답에서 데이터 배열 경로 (예: "data.items") } ``` ### 3.3 data_binding 구조 ```typescript interface DataBinding { // 데이터 소스의 특정 행 선택 selectedRowIndex?: number; // 필드 매핑 (데이터 소스에서 선택) materialNameField?: string; // 자재명이 들어있는 컬럼명 quantityField?: string; // 수량이 들어있는 컬럼명 // 단위는 사용자가 직접 입력 unit: string; // 예: "EA", "BOX", "KG", "M" 등 } ``` --- ## 4. UI/UX 설계 ### 4.1 편집 모드 (YardEditor) ``` ┌─────────────────────────────────────────────────────────────┐ │ [← 목록으로] 야드명: A구역 [저장] │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌───────────────────────────┐ ┌──────────────────────────┐│ │ │ │ │ ││ │ │ │ │ [+ 요소 추가] ││ │ │ │ │ ││ │ │ 3D 캔버스 │ │ ┌────────────────────┐ ││ │ │ │ │ │ □ 요소 1 │ ││ │ │ │ │ │ 자재: 철판 A │ ││ │ │ │ │ │ 수량: 50 EA │ ││ │ │ │ │ │ [편집] [삭제] │ ││ │ │ │ │ └────────────────────┘ ││ │ │ │ │ ││ │ │ │ │ ┌────────────────────┐ ││ │ │ │ │ │ □ 요소 2 (미설정) │ ││ │ │ │ │ │ 데이터 바인딩 │ ││ │ │ │ │ │ 설정 필요 │ ││ │ │ │ │ │ [설정] [삭제] │ ││ │ │ │ │ └────────────────────┘ ││ │ │ │ │ ││ │ └───────────────────────────┘ └──────────────────────────┘│ │ │ └─────────────────────────────────────────────────────────────┘ ``` #### 4.1.1 요소 목록 (우측 패널) - **[+ 요소 추가]** 버튼: 새 요소 생성 - **요소 카드**: - 설정 완료: 자재명, 수량 표시 + [편집] [삭제] 버튼 - 미설정: "데이터 바인딩 설정 필요" + [설정] [삭제] 버튼 #### 4.1.2 요소 추가 흐름 ``` 1. [+ 요소 추가] 클릭 ↓ 2. 3D 캔버스의 기본 위치(0,0,0)에 회색 반투명 박스로 빈 요소 즉시 배치 ↓ 3. 요소가 자동 선택됨 ↓ 4. 우측 패널이 "데이터 바인딩 설정" 화면으로 자동 전환 (요소 목록에서 [설정] 버튼을 클릭해도 동일한 화면) ``` ### 4.2 데이터 바인딩 설정 패널 (우측) **[+ 요소 추가] 버튼 클릭 시 또는 [설정] 버튼 클릭 시 우측 패널이 아래와 같이 변경됩니다:** ``` ┌──────────────────────────────────────┐ │ 데이터 바인딩 설정 [← 목록]│ ├──────────────────────────────────────┤ │ │ │ ┌─ 1단계: 데이터 소스 선택 ─────────────────────────┐ │ │ │ │ │ │ │ ○ 현재 DB ○ 외부 DB ○ REST API │ │ │ │ │ │ │ │ [현재 DB 선택 시] │ │ │ │ ┌────────────────────────────────────────────┐ │ │ │ │ │ SELECT material_name, quantity, unit │ │ │ │ │ │ FROM inventory │ │ │ │ │ │ WHERE status = 'available' │ │ │ │ │ └────────────────────────────────────────────┘ │ │ │ │ [실행] 버튼 │ │ │ │ │ │ │ │ [외부 DB 선택 시] │ │ │ │ - 외부 커넥션 선택 드롭다운 │ │ │ │ - SQL 쿼리 입력 │ │ │ │ - [실행] 버튼 │ │ │ │ │ │ │ │ [REST API 선택 시] │ │ │ │ - URL 입력 │ │ │ │ - Method 선택 (GET/POST) │ │ │ │ - Headers, Query Params 설정 │ │ │ │ - [실행] 버튼 │ │ │ │ │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ ┌─ 2단계: 쿼리 결과 및 필드 매핑 ──────────────────────┐ │ │ │ │ │ │ │ 쿼리 결과 (5행): │ │ │ │ ┌────────────────────────────────────────────┐ │ │ │ │ │ material_name │ quantity │ status │ │ │ │ │ │ 철판 A │ 50 │ available │ ○ │ │ │ │ │ 강관 파이프 │ 100 │ available │ ○ │ │ │ │ │ 볼트 세트 │ 500 │ in_stock │ ○ │ │ │ │ └────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ 필드 매핑: │ │ │ │ 자재명: [material_name ▼] │ │ │ │ 수량: [quantity ▼] │ │ │ │ │ │ │ │ 단위 입력: │ │ │ │ 단위: [EA_____________] │ │ │ │ (예: EA, BOX, KG, M, L 등) │ │ │ │ │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ ┌─ 3단계: 배치 설정 ──────────────────────────────────┐ │ │ │ │ │ │ │ 색상: [🎨 #3b82f6] │ │ │ │ │ │ │ │ 크기: │ │ │ │ 너비: [5] 높이: [5] 깊이: [5] │ │ │ │ │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ [← 목록으로] [저장] │ └──────────────────────────────────────┘ ``` **참고:** - [← 목록으로] 버튼: 요소 목록 화면으로 돌아갑니다 - [저장] 버튼: 데이터 바인딩 설정을 저장하고 요소 목록 화면으로 돌아갑니다 - 저장하지 않고 나가면 요소는 "미설정" 상태로 남습니다 ### 4.3 뷰어 모드 (Yard3DViewer) #### 4.3.1 설정된 요소 - 정상적으로 3D 박스 렌더링 - 클릭 시 자재명, 수량 정보 표시 #### 4.3.2 미설정 요소 ``` ┌─────────────────────┐ │ │ │ ⚠️ │ │ │ │ 설정되지 않은 │ │ 요소입니다 │ │ │ └─────────────────────┘ ``` - 반투명 회색 박스로 표시 - 클릭 시 "데이터 바인딩이 설정되지 않았습니다" 메시지 --- ## 5. 구현 단계 ### Phase 1: 데이터베이스 스키마 변경 - [ ] `yard_material_placement` 테이블 수정 - [ ] 마이그레이션 스크립트 작성 - [ ] 기존 데이터 호환성 처리 ### Phase 2: 백엔드 API 수정 - [ ] `YardLayoutService.ts` 수정 - `addMaterialPlacement`: 데이터 소스/바인딩 정보 저장 - `updatePlacement`: 데이터 바인딩 업데이트 - `getPlacementsByLayoutId`: 새 필드 포함하여 조회 - [ ] 데이터 소스 실행 로직 추가 - DB 쿼리 실행 - 외부 DB 쿼리 실행 - REST API 호출 ### Phase 3: 프론트엔드 타입 정의 - [ ] `types.ts`에 새로운 인터페이스 추가 - `YardElementDataSource` - `YardElementDataBinding` - `YardPlacement` 업데이트 ### Phase 4: 요소 추가 및 관리 - [ ] `YardEditor.tsx` 수정 - [+ 요소 추가] 버튼 구현 - 빈 요소 생성 로직 (즉시 3D 캔버스에 배치) - 요소 추가 시 자동으로 해당 요소 선택 - 우측 패널 상태 관리 (요소 목록 ↔ 데이터 바인딩 설정) - 요소 목록 UI - 설정/미설정 상태 구분 표시 ### Phase 5: 데이터 바인딩 패널 - [ ] `YardElementConfigPanel.tsx` 생성 (우측 패널 컴포넌트) - [← 목록으로] 버튼으로 요소 목록으로 복귀 - 1단계: 데이터 소스 선택 (DatabaseConfig, ExternalDbConfig, RestApiConfig 재사용) - 2단계: 쿼리 결과 테이블 + 행 선택 + 필드 매핑 - 자재명 필드 선택 (드롭다운) - 수량 필드 선택 (드롭다운) - 단위 직접 입력 (Input) - 3단계: 배치 설정 (색상, 크기) - [저장] 버튼으로 설정 저장 및 목록으로 복귀 ### Phase 6: 3D 캔버스 렌더링 수정 - [ ] `Yard3DCanvas.tsx` 수정 - 설정된 요소: 기존 렌더링 - 미설정 요소: 회색 반투명 박스 + 경고 아이콘 ### Phase 7: 뷰어 모드 수정 - [ ] `Yard3DViewer.tsx` 수정 - 미설정 요소 감지 - 미설정 요소 클릭 시 안내 메시지 ### Phase 8: 임시 테이블 제거 - [ ] `temp_material_master` 테이블 삭제 - [ ] 관련 API 및 UI 코드 정리 --- ## 6. 데이터 구조 예시 ### 6.1 데이터 소스 + 필드 매핑 사용 ```json { "id": 1, "yard_layout_id": 1, "material_code": null, "material_name": "철판 A타입", "quantity": 50, "unit": "EA", "data_source_type": "database", "data_source_config": { "type": "database", "query": "SELECT material_name, quantity FROM inventory WHERE material_id = 'MAT-001'" }, "data_binding": { "selectedRowIndex": 0, "materialNameField": "material_name", "quantityField": "quantity", "unit": "EA" }, "position_x": 10, "position_y": 0, "position_z": 10, "size_x": 5, "size_y": 5, "size_z": 5, "color": "#ef4444" } ``` ### 6.2 미설정 요소 ```json { "id": 3, "yard_layout_id": 1, "material_code": null, "material_name": null, "quantity": null, "unit": null, "data_source_type": null, "data_source_config": null, "data_binding": null, "position_x": 30, "position_y": 0, "position_z": 30, "size_x": 5, "size_y": 5, "size_z": 5, "color": "#9ca3af" } ``` --- ## 7. 장점 1. **유연성**: 다양한 데이터 소스 지원 (내부 DB, 외부 DB, REST API) 2. **실시간성**: 실제 시스템의 자재 데이터와 연동 가능 3. **일관성**: 차트/리스트 위젯과 동일한 데이터 소스 선택 방식 4. **사용자 경험**: 데이터 매핑 방식 선택 가능 (자동/수동) 5. **확장성**: 새로운 데이터 소스 타입 추가 용이 6. **명확성**: 미설정 요소를 시각적으로 구분 --- ## 8. 마이그레이션 전략 ### 8.1 기존 데이터 처리 - 기존 `temp_material_master` 기반 배치 데이터를 수동 입력 모드로 전환 - `external_material_id` → `data_binding.mode = 'manual'`로 변환 ### 8.2 단계적 전환 1. 새 스키마 적용 (기존 컬럼 유지) 2. 새 UI/로직 구현 및 테스트 3. 기존 데이터 마이그레이션 4. 임시 테이블 및 구 코드 제거 --- ## 9. 기술 스택 - **백엔드**: PostgreSQL JSONB, Node.js/TypeScript - **프론트엔드**: React, TypeScript, Shadcn UI - **3D 렌더링**: React Three Fiber, Three.js - **데이터 소스**: 기존 `DatabaseConfig`, `ExternalDbConfig`, `RestApiConfig` 컴포넌트 재사용 --- ## 10. 예상 개발 기간 - Phase 1-2 (DB/백엔드): 1일 - Phase 3-4 (프론트엔드 구조): 1일 - Phase 5 (데이터 바인딩 모달): 2일 - Phase 6-7 (3D 렌더링/뷰어): 1일 - Phase 8 (정리 및 테스트): 0.5일 **총 예상 기간: 약 5.5일**