17 KiB
17 KiB
야드 관리 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
-- 기존 컬럼 변경
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 구조
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<string, string>;
queryParams?: Record<string, string>;
body?: string;
dataPath?: string; // 응답에서 데이터 배열 경로 (예: "data.items")
}
3.3 data_binding 구조
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에 새로운 인터페이스 추가YardElementDataSourceYardElementDataBindingYardPlacement업데이트
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 데이터 소스 + 필드 매핑 사용
{
"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 미설정 요소
{
"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. 장점
- 유연성: 다양한 데이터 소스 지원 (내부 DB, 외부 DB, REST API)
- 실시간성: 실제 시스템의 자재 데이터와 연동 가능
- 일관성: 차트/리스트 위젯과 동일한 데이터 소스 선택 방식
- 사용자 경험: 데이터 매핑 방식 선택 가능 (자동/수동)
- 확장성: 새로운 데이터 소스 타입 추가 용이
- 명확성: 미설정 요소를 시각적으로 구분
8. 마이그레이션 전략
8.1 기존 데이터 처리
- 기존
temp_material_master기반 배치 데이터를 수동 입력 모드로 전환 external_material_id→data_binding.mode = 'manual'로 변환
8.2 단계적 전환
- 새 스키마 적용 (기존 컬럼 유지)
- 새 UI/로직 구현 및 테스트
- 기존 데이터 마이그레이션
- 임시 테이블 및 구 코드 제거
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일