38 KiB
야드 관리 3D 기능 구현 계획서
1. 기능 개요
목적
대시보드에서 야드(Yard)의 자재 배치 상태를 3D로 시각화하고 관리하는 위젯
주요 특징
- 대시보드 위젯: 대시보드의 위젯 형태로 추가되는 기능
- 야드 레이아웃 관리: 여러 야드 레이아웃을 생성, 선택, 수정, 삭제 가능
- 3D 시각화: Three.js + React Three Fiber를 사용한 3D 렌더링
- 자재 배치: 3D 공간에서 자재를 직접 배치 및 이동 가능
- 자재 정보: 배치된 자재 클릭 시 상세 정보 표시 (읽기 전용 자재 정보 + 편집 가능한 배치 정보)
위젯 통합
- 위젯 타입:
yard-management-3d - 위치: 대시보드 관리 > 데이터 위젯 > 야드 관리 3D
- 표시 모드:
- 편집 모드: 플레이스홀더 표시
- 뷰 모드: 실제 야드 관리 기능 실행
2. 데이터베이스 설계
2.1. yard_layout 테이블
야드 레이아웃 정보 저장
CREATE TABLE yard_layout (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL, -- 야드 이름 (예: "A구역", "1번 야드")
description TEXT, -- 설명
created_by VARCHAR(50), -- 생성자
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
2.2. yard_material_placement 테이블
야드 내 자재 배치 정보 (외부 자재 데이터 참조)
CREATE TABLE yard_material_placement (
id SERIAL PRIMARY KEY,
yard_layout_id INTEGER REFERENCES yard_layout(id) ON DELETE CASCADE,
-- 외부 자재 참조 (API로 받아올 데이터)
external_material_id VARCHAR(100) NOT NULL, -- 외부 시스템 자재 ID
material_code VARCHAR(50) NOT NULL, -- 자재 코드 (캐시)
material_name VARCHAR(100) NOT NULL, -- 자재 이름 (캐시)
quantity INTEGER NOT NULL DEFAULT 1, -- 수량 (캐시)
unit VARCHAR(20) DEFAULT 'EA', -- 단위 (캐시)
-- 3D 위치 정보
position_x NUMERIC(10, 2) NOT NULL DEFAULT 0, -- X 좌표
position_y NUMERIC(10, 2) NOT NULL DEFAULT 0, -- Y 좌표 (높이)
position_z NUMERIC(10, 2) NOT NULL DEFAULT 0, -- Z 좌표
-- 3D 크기 정보
size_x NUMERIC(10, 2) NOT NULL DEFAULT 5, -- 너비
size_y NUMERIC(10, 2) NOT NULL DEFAULT 5, -- 높이
size_z NUMERIC(10, 2) NOT NULL DEFAULT 5, -- 깊이
-- 외관 정보
color VARCHAR(7) DEFAULT '#3b82f6', -- 색상 (HEX)
-- 추가 정보
status VARCHAR(20) DEFAULT 'normal', -- 상태 (normal, alert, warning)
memo TEXT, -- 메모
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 외부 자재 ID와 야드 레이아웃의 조합은 유니크해야 함 (중복 배치 방지)
CREATE UNIQUE INDEX idx_yard_material_unique
ON yard_material_placement(yard_layout_id, external_material_id);
2.3. temp_material_master 테이블 (임시 자재 마스터)
외부 API를 받기 전까지 사용할 임시 자재 데이터
CREATE TABLE temp_material_master (
id SERIAL PRIMARY KEY,
material_code VARCHAR(50) UNIQUE NOT NULL, -- 자재 코드
material_name VARCHAR(100) NOT NULL, -- 자재 이름
category VARCHAR(50), -- 카테고리
unit VARCHAR(20) DEFAULT 'EA', -- 기본 단위
default_color VARCHAR(7) DEFAULT '#3b82f6', -- 기본 색상
description TEXT, -- 설명
is_active BOOLEAN DEFAULT true, -- 사용 여부
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 임시 자재 마스터 샘플 데이터
INSERT INTO temp_material_master (material_code, material_name, category, unit, default_color, description) VALUES
('MAT-STEEL-001', '철판 A타입 (1200x2400)', '철강', 'EA', '#ef4444', '두께 10mm 철판'),
('MAT-STEEL-002', '철판 B타입 (1000x2000)', '철강', 'EA', '#dc2626', '두께 8mm 철판'),
('MAT-PIPE-001', '강관 파이프 (Φ100)', '파이프', 'EA', '#10b981', '길이 6m'),
('MAT-PIPE-002', '강관 파이프 (Φ150)', '파이프', 'EA', '#059669', '길이 6m'),
('MAT-BOLT-001', '볼트 세트 M12', '부품', 'BOX', '#f59e0b', '100개/박스'),
('MAT-BOLT-002', '볼트 세트 M16', '부품', 'BOX', '#d97706', '100개/박스'),
('MAT-ANGLE-001', '앵글 (75x75x6)', '형강', 'EA', '#8b5cf6', '길이 6m'),
('MAT-ANGLE-002', '앵글 (100x100x10)', '형강', 'EA', '#7c3aed', '길이 6m'),
('MAT-CHANNEL-001', '채널 (100x50x5)', '형강', 'EA', '#06b6d4', '길이 6m'),
('MAT-WIRE-001', '와이어 로프 (Φ12)', '케이블', 'M', '#ec4899', '롤 단위');
2.4. 초기 데이터 마이그레이션 스크립트
-- 샘플 야드 레이아웃
INSERT INTO yard_layout (name, description, created_by) VALUES
('A구역', '메인 야드 A구역', 'admin'),
('B구역', '메인 야드 B구역', 'admin'),
('C구역', '보조 야드 C구역', 'admin');
-- 샘플 자재 배치 (A구역) - 임시 자재 마스터 참조
INSERT INTO yard_material_placement (yard_layout_id, external_material_id, material_code, material_name,
quantity, unit, position_x, position_y, position_z, size_x, size_y, size_z, color, status) VALUES
(1, 'TEMP-1', 'MAT-STEEL-001', '철판 A타입 (1200x2400)', 50, 'EA', 10, 0, 10, 8, 4, 8, '#ef4444', 'normal'),
(1, 'TEMP-2', 'MAT-STEEL-002', '철판 B타입 (1000x2000)', 30, 'EA', 25, 0, 10, 8, 4, 8, '#dc2626', 'normal'),
(1, 'TEMP-3', 'MAT-PIPE-001', '강관 파이프 (Φ100)', 100, 'EA', 40, 0, 10, 6, 6, 6, '#10b981', 'normal'),
(1, 'TEMP-4', 'MAT-BOLT-001', '볼트 세트 M12', 500, 'BOX', 55, 0, 10, 4, 4, 4, '#f59e0b', 'warning');
2.5. 외부 자재 API 연동 구조
현재 (Phase 1): 임시 자재 마스터 사용
// temp_material_master 테이블에서 조회
GET / api / materials / temp;
향후 (Phase 2): 외부 API 연동
// 외부 시스템 자재 API
GET /api/external/materials
Response: [
{
id: "EXT-12345",
code: "MAT-STEEL-001",
name: "철판 A타입",
quantity: 150,
unit: "EA",
location: "창고A-1",
...
}
]
3. 백엔드 API 설계
3.1. YardLayoutService
경로: backend-node/src/services/YardLayoutService.ts
구현 완료
주요 메서드:
getAllLayouts(): 모든 야드 레이아웃 목록 조회 (배치 자재 개수 포함)getLayoutById(id): 특정 야드 레이아웃 상세 조회createLayout(data): 새 야드 레이아웃 생성updateLayout(id, data): 야드 레이아웃 수정 (이름, 설명만)deleteLayout(id): 야드 레이아웃 삭제 (CASCADE로 배치 자재도 함께 삭제)duplicateLayout(id, newName): 야드 레이아웃 복제 (배치 자재 포함)getPlacementsByLayoutId(layoutId): 특정 야드의 모든 배치 자재 조회addMaterialPlacement(layoutId, data): 야드에 자재 배치 추가updatePlacement(placementId, data): 배치 정보 수정 (위치, 크기, 색상, 메모만)removePlacement(placementId): 배치 해제batchUpdatePlacements(layoutId, placements): 여러 배치 일괄 업데이트 (트랜잭션 처리)
중요: 자재 마스터 데이터(코드, 이름, 수량, 단위)는 읽기 전용. 배치 정보만 수정 가능.
3.2. YardLayoutController
경로: backend-node/src/controllers/YardLayoutController.ts
구현 완료
엔드포인트:
GET /api/yard-layouts: 모든 레이아웃 목록 (배치 개수 포함)GET /api/yard-layouts/:id: 특정 레이아웃 상세POST /api/yard-layouts: 새 레이아웃 생성 (name, description)PUT /api/yard-layouts/:id: 레이아웃 수정 (이름, 설명만)DELETE /api/yard-layouts/:id: 레이아웃 삭제 (CASCADE)POST /api/yard-layouts/:id/duplicate: 레이아웃 복제 (name)GET /api/yard-layouts/:id/placements: 레이아웃의 배치 자재 목록POST /api/yard-layouts/:id/placements: 자재 배치 추가PUT /api/yard-layouts/placements/:id: 배치 정보 수정DELETE /api/yard-layouts/placements/:id: 배치 해제PUT /api/yard-layouts/:id/placements/batch: 배치 일괄 업데이트
모든 엔드포인트는 authMiddleware로 인증 보호됨
3.3. MaterialService
경로: backend-node/src/services/MaterialService.ts
구현 완료
주요 메서드:
getTempMaterials(params): 임시 자재 목록 조회 (검색, 카테고리 필터, 페이징)getTempMaterialByCode(code): 특정 자재 상세 조회getCategories(): 카테고리 목록 조회
3.4. MaterialController
경로: backend-node/src/controllers/MaterialController.ts
구현 완료
엔드포인트:
GET /api/materials/temp: 임시 자재 마스터 목록 (검색, 필터링, 페이징)GET /api/materials/temp/categories: 카테고리 목록GET /api/materials/temp/:code: 특정 자재 상세
향후: 외부 API 프록시로 변경 예정
3.5. Routes
경로:
backend-node/src/routes/yardLayoutRoutes.tsbackend-node/src/routes/materialRoutes.ts
구현 완료
app.ts에 등록:
app.use("/api/yard-layouts", yardLayoutRoutes)app.use("/api/materials", materialRoutes)
4. 프론트엔드 컴포넌트 설계
4.1. YardManagement3DWidget (메인 위젯)
경로: frontend/components/admin/dashboard/widgets/YardManagement3DWidget.tsx
구현 완료
주요 기능:
- 레이아웃 선택/생성 모드와 3D 편집 모드 전환
- 편집 모드와 뷰 모드 구분 (isEditMode props)
- API 연동 (yardLayoutApi)
상태 관리:
- layouts: YardLayout[] // 전체 레이아웃 목록
- selectedLayout: YardLayout | null // 선택된 레이아웃
- isCreateModalOpen: boolean // 생성 모달 표시 여부
- isLoading: boolean // 로딩 상태
하위 컴포넌트:
YardLayoutList: 레이아웃 목록 표시YardLayoutCreateModal: 새 레이아웃 생성 모달YardEditor: 3D 편집 화면
4.2. API 클라이언트
경로: frontend/lib/api/yardLayoutApi.ts
구현 완료
yardLayoutApi:
getAllLayouts(): 모든 레이아웃 목록getLayoutById(id): 레이아웃 상세createLayout(data): 레이아웃 생성updateLayout(id, data): 레이아웃 수정deleteLayout(id): 레이아웃 삭제duplicateLayout(id, name): 레이아웃 복제getPlacementsByLayoutId(layoutId): 배치 목록addMaterialPlacement(layoutId, data): 배치 추가updatePlacement(placementId, data): 배치 수정removePlacement(placementId): 배치 삭제batchUpdatePlacements(layoutId, placements): 일괄 업데이트
materialApi:
getTempMaterials(params): 임시 자재 목록getTempMaterialByCode(code): 자재 상세getCategories(): 카테고리 목록
4.3. YardLayoutList (레이아웃 목록)
경로: frontend/components/admin/dashboard/widgets/yard-3d/YardLayoutList.tsx
구현 예정
- 테이블 형식으로 레이아웃 목록 표시
- 검색 및 정렬 기능
- 행 클릭 시 레이아웃 선택 (편집 모드 진입)
- 작업 메뉴 (편집, 복제, 삭제)
4.4. YardLayoutCreateModal (레이아웃 생성 모달)
경로: frontend/components/admin/dashboard/widgets/yard-3d/YardLayoutCreateModal.tsx
구현 예정
- 야드 이름, 설명 입력
- Shadcn UI Dialog 사용
- 생성 완료 시 자동으로 편집 모드 진입
4.5. YardEditor (3D 편집 화면)
경로: frontend/components/admin/dashboard/widgets/yard-3d/YardEditor.tsx
구현 예정
주요 구성:
- 상단 툴바 (뒤로가기, 저장, 자재 추가 등)
- 좌측: 3D 캔버스
- 우측: 자재 정보 패널 (선택 시 표시)
기술 스택:
- React Three Fiber
- @react-three/drei (OrbitControls, Grid, Box)
- Three.js
주요 기능:
- 야드 바닥 그리드 표시
- 자재 3D 박스 렌더링
- 자재 클릭 이벤트 처리
- 자재 드래그 앤 드롭 (위치 이동)
- 카메라 컨트롤 (회전, 줌)
4.6. MaterialInfoPanel (자재 정보 패널)
경로: frontend/components/admin/dashboard/widgets/yard-3d/MaterialInfoPanel.tsx
구현 예정
읽기 전용 정보 (외부 자재 데이터):
- 자재 코드
- 자재 이름
- 수량
- 단위
- 카테고리
수정 가능 정보 (배치 데이터):
- 3D 위치 (X, Y, Z)
- 3D 크기 (너비, 높이, 깊이)
- 색상
- 메모
기능:
- 배치 정보 수정
- 배치 해제 (야드에서 자재 제거)
4.6. MaterialLibrary (자재 라이브러리)
경로: frontend/components/admin/dashboard/widgets/MaterialLibrary.tsx
- 사용 가능한 자재 목록 표시
- 자재 검색 기능
- 자재를 3D 캔버스로 드래그하여 배치
- 자재 마스터 데이터 조회 (기존 테이블 활용 가능)
5. UI/UX 설계
5.1. 초기 화면 (선택/생성 모드)
야드 레이아웃 목록을 테이블 형식으로 표시
┌──────────────────────────────────────────────────────────────────────────┐
│ 야드 관리 3D [+ 새 야드 생성] │
├──────────────────────────────────────────────────────────────────────────┤
│ │
│ [검색: ________________] [정렬: 최근순 ▼] │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ 야드명 │ 설명 │ 배치 자재 │ 최종 수정 │ 작업 │ │
│ ├────────────────────────────────────────────────────────────────────┤ │
│ │ A구역 │ 메인 야드 A구역 │ 15개 │ 2025-01-15 14:30 │ ⋮ │ │
│ │ │ │ │ │ │ │
│ ├────────────────────────────────────────────────────────────────────┤ │
│ │ B구역 │ 메인 야드 B구역 │ 8개 │ 2025-01-14 10:20 │ ⋮ │ │
│ │ │ │ │ │ │ │
│ ├────────────────────────────────────────────────────────────────────┤ │
│ │ C구역 │ 보조 야드 C구역 │ 3개 │ 2025-01-10 09:15 │ ⋮ │ │
│ │ │ │ │ │ │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ 총 3개 [1] 2 3 4 5 > │
│ │
└──────────────────────────────────────────────────────────────────────────┘
작업 메뉴 (⋮ 클릭 시):
┌─────────────┐
│ 편집 │
│ 복제 │
│ 삭제 │
└─────────────┘
5.2. 레이아웃 생성 모달
새 야드 레이아웃을 생성할 때 표시되는 모달
┌─────────────────────────────────────────────────┐
│ 새 야드 레이아웃 생성 [X] │
├─────────────────────────────────────────────────┤
│ │
│ 야드 이름 * │
│ [____________________________________] │
│ │
│ 설명 │
│ [____________________________________] │
│ [____________________________________] │
│ │
│ [취소] [생성] │
└─────────────────────────────────────────────────┘
5.3. 편집 모드 - 전체 레이아웃
야드 편집 화면의 전체 구성
┌─────────────────────────────────────────────────────────────────────────────┐
│ A구역 [저장] [미리보기] [취소] │
├───────────────────────────────────────┬─────────────────────────────────────┤
│ │ 도구 패널 [최소화] │
│ ├─────────────────────────────────────┤
│ │ │
│ │ 자재 라이브러리 │
│ │ ───────────────────── │
│ │ [검색: ____________] [카테고리 ▼] │
│ │ │
│ 3D 캔버스 │ ┌───────────────────────┐ │
│ │ │ MAT-STEEL-001 │ │
│ (야드 그리드 + 자재 배치) │ │ 철판 A타입 │ │
│ │ │ 50 EA 재고 있음 │ │
│ - 마우스 드래그: 카메라 회전 │ │ [배치] │ │
│ - 휠: 줌 인/아웃 │ └───────────────────────┘ │
│ - 자재 클릭: 선택 │ │
│ - 자재 드래그: 이동 │ ┌───────────────────────┐ │
│ │ │ MAT-STEEL-002 │ │
│ │ │ 철판 B타입 │ │
│ │ │ 30 EA 재고 있음 │ │
│ │ │ [배치] │ │
│ │ └───────────────────────┘ │
│ │ │
│ │ ┌───────────────────────┐ │
│ │ │ MAT-PIPE-001 │ │
│ │ │ 강관 파이프 │ │
│ │ │ 100 EA 재고 있음 │ │
│ │ │ [배치] │ │
│ │ └───────────────────────┘ │
│ │ │
│ │ ... (스크롤 가능) │
│ │ │
├───────────────────────────────────────┴─────────────────────────────────────┤
│ 자재 정보 │
│ ───────────────── │
│ 선택된 자재: MAT-STEEL-001 (철판 A타입) │
│ │
│ 기본 정보 (읽기 전용) │
│ 자재 코드: MAT-STEEL-001 │
│ 자재 이름: 철판 A타입 (1200x2400) │
│ 수량: 50 EA │
│ 카테고리: 철강 │
│ │
│ 배치 정보 (수정 가능) │
│ 3D 위치 │
│ X: [____10.00____] m Y: [____0.00____] m Z: [____10.00____] m │
│ │
│ 3D 크기 │
│ 너비: [____8.00____] m 높이: [____4.00____] m 깊이: [____8.00____] m │
│ │
│ 외관 │
│ 색상: [■ #ef4444] [색상 선택] │
│ │
│ 메모 │
│ [_____________________________________________________________________] │
│ │
│ [배치 해제] [변경 적용] [초기화] │
└─────────────────────────────────────────────────────────────────────────────┘
5.4. 3D 캔버스 상세
3D 캔버스 내부의 시각적 요소
┌─────────────────────────────────────────────────┐
│ 카메라 컨트롤 [리셋] │
│ 회전: 45° | 기울기: 30° | 줌: 100% │
├─────────────────────────────────────────────────┤
│ Y (높이) │
│ ↑ │
│ │ │
│ │ │
│ │ ┌───────┐ (자재) │
│ │ │ │ │
│ Z (깊이) │ │ MAT-1 │ (선택됨) │
│ ↗ │ │ │ │
│ / └────┴───────┴──→ X (너비) │
│ / │
│ / ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐ │
│ ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ (그리드) │
│ ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ │
│ ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ │
│ │ │ │ │ │ │□│ │ │ │ │ ← MAT-2 │
│ ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ │
│ ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ │
│ └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ │
│ │
│ 범례: │
│ ■ 선택된 자재 □ 일반 자재 │
│ ─ 그리드 라인 (5m 단위) │
│ │
│ 조작 가이드: │
│ • 마우스 왼쪽 드래그: 카메라 회전 │
│ • 마우스 휠: 줌 인/아웃 │
│ • 자재 클릭: 선택 │
│ • 선택된 자재 드래그: 위치 이동 │
└─────────────────────────────────────────────────┘
5.5. 자재 배치 플로우
자재를 배치하는 과정
1. 자재 라이브러리에서 자재 선택
┌─────────────────┐
│ MAT-STEEL-001 │ ← 클릭
│ 철판 A타입 │
│ [배치] │
└─────────────────┘
↓
2. 3D 캔버스에 자재가 임시로 표시됨 (투명)
┌─────────────────┐
│ 3D 캔버스 │
│ │
│ [반투명 박스] │ ← 마우스 커서 따라 이동
│ │
└─────────────────┘
↓
3. 원하는 위치에 클릭하여 배치
┌─────────────────┐
│ 3D 캔버스 │
│ │
│ [실제 박스] │ ← 배치 완료
│ │
└─────────────────┘
↓
4. 자재 정보 패널에 자동으로 선택됨
┌─────────────────────────┐
│ 자재 정보 패널 │
│ ─────────────────── │
│ 선택된 자재: │
│ MAT-STEEL-001 │
│ │
│ 수량: 50 EA │
│ 위치: X:10, Y:0, Z:10 │
│ ... │
└─────────────────────────┘
5.6. 반응형 레이아웃 (모바일/태블릿)
모바일에서는 패널을 접거나 탭으로 전환
모바일 (세로 모드):
┌───────────────────────┐
│ A구역 [저장] │
├───────────────────────┤
│ │
│ 3D 캔버스 │
│ (전체 화면) │
│ │
│ │
├───────────────────────┤
│ [자재 라이브러리] [정보]│ ← 탭 전환
├───────────────────────┤
│ 선택된 자재: │
│ MAT-STEEL-001 │
│ 수량: 50 EA │
│ ... │
└───────────────────────┘
태블릿 (가로 모드):
┌─────────────────────────────────────┐
│ A구역 [저장] │
├──────────────────┬──────────────────┤
│ │ 자재 라이브러리 │
│ 3D 캔버스 │ ────────────── │
│ │ [검색: ______] │
│ │ MAT-STEEL-001 │
│ │ ... │
├──────────────────┴──────────────────┤
│ 선택된 자재: MAT-STEEL-001 │
│ 수량: 50 EA | 위치: X:10, Z:10 │
└─────────────────────────────────────┘
6. 구현 단계
Phase 1: 데이터베이스 및 백엔드 API ✅ 완료
- ✅ 테이블 생성 스크립트 작성 (
create_yard_management_tables.sql) - ✅ 마이그레이션 실행
- ✅ Service, Controller, Routes 구현
- ✅ API 클라이언트 구현 (yardLayoutApi, materialApi)
Phase 2: 메인 위젯 및 레이아웃 관리 🔄 진행 중
- ✅ types.ts에 위젯 타입 추가
- ✅ DashboardTopMenu에 위젯 추가
- ✅ DashboardDesigner에 위젯 타이틀/컨텐츠 추가
- ✅ YardManagement3DWidget 메인 컴포넌트 구현
- ⏳ YardLayoutList 컴포넌트 구현
- ⏳ YardLayoutCreateModal 컴포넌트 구현
Phase 3: 3D 편집 화면 ⏳ 대기 중
- ⏳ YardEditor 메인 컴포넌트
- ⏳ 상단 툴바 (뒤로가기, 저장, 자재 추가)
- ⏳ 레이아웃 구성 (좌측 캔버스 + 우측 패널)
Phase 4: 3D 캔버스 기본 구조 ⏳ 대기 중
- ⏳ Yard3DCanvas 컴포넌트 기본 구조
- ⏳ React Three Fiber 설정
- ⏳ 야드 바닥 그리드 렌더링
- ⏳ 카메라 컨트롤 (OrbitControls)
- ⏳ 자재 3D 박스 렌더링
Phase 5: 자재 배치 및 인터랙션 ⏳ 대기 중
- ⏳ MaterialLibrary 컴포넌트 구현
- ⏳ 자재 선택 및 추가
- ⏳ 자재 드래그 앤 드롭 배치
- ⏳ 자재 클릭 선택
- ⏳ 자재 위치 이동 (드래그)
Phase 6: 자재 정보 패널 및 편집 ⏳ 대기 중
- ⏳ MaterialInfoPanel 컴포넌트 구현
- ⏳ 자재 정보 표시 (읽기 전용 + 편집 가능)
- ⏳ 자재 배치 정보 수정
- ⏳ 배치 해제 기능
- ⏳ 변경사항 저장
Phase 7: 통합 및 최적화 ⏳ 대기 중
- YardManagement3DWidget 통합
- 상태 관리 최적화
- 성능 최적화 (대량 자재 렌더링)
- 에러 처리 및 로딩 상태
- 모바일/반응형 대응 (선택사항)
Phase 7: 대시보드 위젯 등록
- types.ts에 위젯 타입 추가
- DashboardTopMenu에 위젯 추가
- CanvasElement에 위젯 렌더링 추가
- 위젯 설정 모달 (레이아웃 선택)
7. 기술적 고려사항
7.1. 3D 렌더링 최적화
- 자재 수가 많을 경우 인스턴싱 사용
- LOD (Level of Detail) 적용 고려
- 카메라 거리에 따른 렌더링 최적화
7.2. 드래그 앤 드롭
- 3D 공간에서의 레이캐스팅
- 그리드 스냅 기능
- 충돌 감지 (자재 간 겹침 방지)
7.3. 상태 관리
- 자재 위치 변경 시 실시간 업데이트
- Debounce를 사용한 API 호출 최적화
- 낙관적 업데이트 (Optimistic Update)
7.4. 데이터 동기화
- 여러 사용자가 동시에 편집하는 경우 충돌 처리
- WebSocket을 통한 실시간 동기화 (선택사항)
7.5. UI/UX 규칙
이모지 사용 금지
모달 사용 규칙
window.alert, window.confirm 사용 금지
모든 알림, 확인, 에러 메시지는 Shadcn UI 모달 컴포넌트 사용:
- 일반 알림:
Dialog컴포넌트 - 확인 필요:
AlertDialog컴포넌트 - 삭제/해제 확인:
AlertDialog(Destructive 스타일) - 성공 메시지:
Dialog또는Toast - 에러 메시지:
Dialog(Error 스타일)
예시:
// 잘못된 방법 ❌
window.alert("저장되었습니다");
if (window.confirm("삭제하시겠습니까?")) { ... }
// 올바른 방법 ✅
<AlertDialog open={isDeleteDialogOpen} onOpenChange={setIsDeleteDialogOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>배치 해제</AlertDialogTitle>
<AlertDialogDescription>
이 자재를 야드에서 제거하시겠습니까?
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>취소</AlertDialogCancel>
<AlertDialogAction onClick={handleRemove}>확인</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
8. API 명세서
8.1. 야드 레이아웃 API
GET /api/yard-layouts
설명: 모든 야드 레이아웃 목록 조회
응답:
{
"success": true,
"data": [
{
"id": 1,
"name": "A구역",
"description": "메인 야드 A구역",
"placement_count": 15,
"created_at": "2025-01-01T00:00:00Z"
}
]
}
GET /api/yard-layouts/:id
설명: 특정 야드 레이아웃 상세 조회
응답:
{
"success": true,
"data": {
"id": 1,
"name": "A구역",
"description": "메인 야드 A구역",
"created_at": "2025-01-01T00:00:00Z"
}
}
POST /api/yard-layouts
설명: 새 야드 레이아웃 생성
요청:
{
"name": "D구역",
"description": "신규 야드"
}
PUT /api/yard-layouts/:id
설명: 야드 레이아웃 수정 (이름, 설명만)
요청:
{
"name": "D구역 (수정)",
"description": "수정된 설명"
}
DELETE /api/yard-layouts/:id
설명: 야드 레이아웃 삭제
8.2. 자재 배치 API
GET /api/yard-layouts/:id/materials
설명: 특정 야드의 모든 자재 조회
응답:
{
"success": true,
"data": [
{
"id": 1,
"material_code": "MAT-001",
"material_name": "철판 A타입",
"quantity": 50,
"unit": "EA",
"position_x": 10,
"position_y": 0,
"position_z": 10,
"size_x": 8,
"size_y": 4,
"size_z": 8,
"color": "#ef4444",
"status": "normal",
"memo": null
}
]
}
POST /api/yard-layouts/:id/materials
설명: 야드에 자재 추가
요청:
{
"material_code": "MAT-005",
"material_name": "신규 자재",
"quantity": 10,
"unit": "EA",
"position_x": 20,
"position_y": 0,
"position_z": 20,
"size_x": 5,
"size_y": 5,
"size_z": 5,
"color": "#3b82f6"
}
PUT /api/yard-materials/:id
설명: 자재 정보 수정
요청:
{
"position_x": 25,
"position_z": 25,
"quantity": 55
}
DELETE /api/yard-materials/:id
설명: 자재 삭제
PUT /api/yard-layouts/:id/materials/batch
설명: 여러 자재 일괄 업데이트 (드래그로 여러 자재 이동 시)
요청:
{
"materials": [
{ "id": 1, "position_x": 15, "position_z": 15 },
{ "id": 2, "position_x": 30, "position_z": 15 }
]
}
9. 테스트 시나리오
9.1. 기본 기능 테스트
- 야드 레이아웃 목록 조회
- 야드 레이아웃 생성
- 야드 레이아웃 선택
- 3D 캔버스 렌더링
- 자재 목록 조회 및 표시
9.2. 자재 배치 테스트
- 자재 라이브러리에서 드래그하여 배치
- 배치된 자재 클릭하여 선택
- 선택된 자재 정보 패널 표시
- 자재 드래그하여 위치 이동
- 자재 정보 수정 (수량, 크기 등)
- 자재 삭제
9.3. 인터랙션 테스트
- 카메라 회전 (OrbitControls)
- 카메라 줌 인/아웃
- 그리드 스냅 기능
- 여러 자재 동시 이동
- 자재 간 충돌 방지
9.4. 저장 및 로드 테스트
- 자재 배치 후 저장
- 저장된 레이아웃 다시 로드
- 레이아웃 삭제
- 레이아웃 복제 (선택사항)
10. 향후 확장 가능성
- 자재 검색 및 필터링 (상태별, 자재 코드별)
- 자재 배치 히스토리 (변경 이력)
- 자재 배치 템플릿 (자주 사용하는 배치 저장)
- 자재 입출고 연동 (실시간 재고 반영)
- 자재 경로 최적화 (피킹 경로 표시)
- AR/VR 지원 (모바일 AR로 실제 야드 확인)
- 다중 사용자 동시 편집 (WebSocket)
- 자재 배치 분석 (공간 활용률, 접근성 등)
11. 파일 구조
backend-node/src/
├── services/
│ └── YardLayoutService.ts (신규)
├── controllers/
│ └── YardLayoutController.ts (신규)
├── routes/
│ └── yardLayoutRoutes.ts (신규)
└── app.ts (수정)
frontend/components/admin/dashboard/
├── widgets/
│ ├── YardManagement3DWidget.tsx (신규 - 메인)
│ ├── YardLayoutSelector.tsx (신규)
│ ├── YardLayoutCreator.tsx (신규)
│ ├── Yard3DCanvas.tsx (신규)
│ ├── MaterialInfoPanel.tsx (신규)
│ └── MaterialLibrary.tsx (신규)
├── types.ts (수정 - 위젯 타입 추가)
├── DashboardTopMenu.tsx (수정 - 메뉴 추가)
└── CanvasElement.tsx (수정 - 렌더링 추가)
db/
└── migrations/
└── create_yard_tables.sql (신규)
12. 예상 개발 기간
- Phase 1 (DB & API): 1일
- Phase 2 (선택/생성): 1일
- Phase 3 (3D 기본): 1일
- Phase 4 (배치 인터랙션): 2일
- Phase 5 (정보 패널): 1일
- Phase 6 (통합/최적화): 1일
- Phase 7 (대시보드 등록): 0.5일
총 예상 기간: 7.5일
13. 참고 자료
- React Three Fiber: https://docs.pmnd.rs/react-three-fiber
- @react-three/drei: https://github.com/pmndrs/drei
- Three.js: https://threejs.org/docs/