docs: 5130 레거시 분석 문서 및 기존 문서 초기 커밋
- 5130 레거시 시스템 분석 (00_OVERVIEW ~ 08_SAM_COMPARISON) - MES 프로젝트 문서 - API/프론트엔드 스펙 문서 - 가이드 및 레퍼런스 문서
This commit is contained in:
989
projects/mes/00_baseline/BACKEND_DEVELOPMENT_ROADMAP_V2.md
Normal file
989
projects/mes/00_baseline/BACKEND_DEVELOPMENT_ROADMAP_V2.md
Normal file
@@ -0,0 +1,989 @@
|
||||
---
|
||||
source: Phase 0 + 프론트엔드 가이드 통합 분석
|
||||
section: BP-MES 백엔드 개발 로드맵 (개정판)
|
||||
created: 2025-11-13
|
||||
updated: 2025-11-13
|
||||
bp_mes_phase: Phase 0 완료, Phase 1 준비
|
||||
related:
|
||||
- ITEM_MANAGEMENT_MIGRATION_GUIDE.md (프론트엔드 가이드)
|
||||
- PHASE_0_FINAL_REPORT.md
|
||||
- api_gap_validation_report.md
|
||||
tags: [backend, roadmap, api, database, laravel]
|
||||
---
|
||||
|
||||
# BP-MES 백엔드 개발 로드맵 V2
|
||||
|
||||
**작성일:** 2025-11-13
|
||||
**기반:** Next.js 15 프론트엔드 가이드 + Phase 0 분석
|
||||
**대상:** 백엔드 개발자 (프론트엔드 작업 제외)
|
||||
**프레임워크:** Laravel 12 + PHP 8.2+
|
||||
|
||||
---
|
||||
|
||||
## 📋 Executive Summary
|
||||
|
||||
### 변경 사항
|
||||
- ✅ **프론트엔드 가이드 통합:** Next.js 15 마이그레이션 가이드 기반 API 요구사항 반영
|
||||
- ✅ **우선순위 재조정:** 프론트엔드 80% 물리적 페이지 → 백엔드 고정 필드 우선
|
||||
- ✅ **선택적 확장:** 동적 템플릿 시스템 2차 목표로 후순위
|
||||
- ⚠️ **프론트엔드 작업 제외:** 백엔드 API 개발에만 집중
|
||||
|
||||
### 핵심 방향
|
||||
1. **하이브리드 전략:** 고정 필드 API (우선) + 메타데이터 API (선택)
|
||||
2. **RESTful 설계:** 프론트 가이드 엔드포인트 스펙 준수
|
||||
3. **BOM 계산 강화:** quantityFormula, 계층 구조, tree API
|
||||
4. **파일 관리:** 절곡도, 시방서, 인정서 업로드
|
||||
|
||||
---
|
||||
|
||||
## 🎯 프론트엔드 요구사항 분석
|
||||
|
||||
### 1. 데이터 구조 (프론트엔드 가이드 기준)
|
||||
|
||||
#### 1.1 ItemMaster 필드 구성
|
||||
|
||||
**공통 필드 (ALL):**
|
||||
```
|
||||
필수:
|
||||
- id, itemCode, itemName, itemType, unit
|
||||
- specification, isActive
|
||||
|
||||
분류:
|
||||
- category1, category2, category3
|
||||
|
||||
가격:
|
||||
- purchasePrice, salesPrice, marginRate
|
||||
- processingCost, laborCost, installCost
|
||||
|
||||
BOM:
|
||||
- bom[] (BOMLine 배열)
|
||||
- bomCategories[]
|
||||
|
||||
메타:
|
||||
- safetyStock, leadTime, isVariableSize
|
||||
- revisions[]
|
||||
- createdAt, updatedAt
|
||||
```
|
||||
|
||||
**FG (제품) 전용:**
|
||||
```
|
||||
- productCategory: 'SCREEN' | 'STEEL'
|
||||
- lotAbbreviation: string (예: "KD")
|
||||
- note: string
|
||||
```
|
||||
|
||||
**PT (부품) 전용:**
|
||||
```
|
||||
기본:
|
||||
- partType: 'ASSEMBLY' | 'BENDING' | 'PURCHASED'
|
||||
- partUsage: 'GUIDE_RAIL' | 'BOTTOM_FINISH' | 'CASE' | 'DOOR' | 'BRACKET' | 'GENERAL'
|
||||
|
||||
조립 부품:
|
||||
- installationType, assemblyType
|
||||
- sideSpecWidth, sideSpecHeight, assemblyLength
|
||||
- guideRailModelType, guideRailModel (가이드레일)
|
||||
|
||||
절곡품:
|
||||
- bendingDiagram: string (이미지 URL)
|
||||
- bendingDetails: BendingDetail[] (전개도 데이터)
|
||||
- material, length, bendingLength
|
||||
```
|
||||
|
||||
**인증 정보 (FG/PT):**
|
||||
```
|
||||
- certificationNumber
|
||||
- certificationStartDate, certificationEndDate
|
||||
- specificationFile, specificationFileName
|
||||
- certificationFile, certificationFileName
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 1.2 BOMLine 구조
|
||||
|
||||
```
|
||||
필수:
|
||||
- id, childItemCode, childItemName
|
||||
- quantity, unit, unitPrice
|
||||
- note
|
||||
|
||||
핵심:
|
||||
- quantityFormula: string // 🔴 "W * 2", "H + 100", "G/1000*1.02"
|
||||
|
||||
절곡품:
|
||||
- isBending: boolean
|
||||
- bendingDiagram: string
|
||||
- bendingDetails: BendingDetail[]
|
||||
```
|
||||
|
||||
**백엔드 요구:**
|
||||
- ✅ quantityFormula 저장 (text 컬럼)
|
||||
- ✅ 계산 로직 (수식 파싱 및 실행)
|
||||
|
||||
---
|
||||
|
||||
#### 1.3 BendingDetail 구조
|
||||
|
||||
```typescript
|
||||
{
|
||||
id: string
|
||||
no: number // 순서
|
||||
input: number // 입력값
|
||||
elongation: number // 연신율 (-1 기본)
|
||||
calculated: number // 계산 후 값
|
||||
sum: number // 합계
|
||||
shaded: boolean // 음영 여부
|
||||
aAngle?: number // A각
|
||||
}
|
||||
```
|
||||
|
||||
**백엔드 요구:**
|
||||
- ✅ JSON 컬럼으로 저장
|
||||
- ⚠️ 계산 로직: 프론트 vs 백엔드 협의 필요
|
||||
|
||||
---
|
||||
|
||||
### 2. API 엔드포인트 (프론트엔드 가이드)
|
||||
|
||||
#### 2.1 품목 CRUD (필수)
|
||||
|
||||
```
|
||||
GET /api/items
|
||||
Query Parameters:
|
||||
- itemType?: string (FG,PT,SM,RM,CS)
|
||||
- search?: string
|
||||
- category1?: string
|
||||
|
||||
Response:
|
||||
{
|
||||
data: ItemMaster[]
|
||||
meta: { total, page, perPage }
|
||||
}
|
||||
|
||||
GET /api/items/:itemCode
|
||||
Response:
|
||||
{
|
||||
data: ItemMaster (BOM 포함)
|
||||
}
|
||||
|
||||
POST /api/items
|
||||
Body: Partial<ItemMaster>
|
||||
Response: { data: ItemMaster }
|
||||
|
||||
PUT /api/items/:itemCode
|
||||
Body: Partial<ItemMaster>
|
||||
Response: { data: ItemMaster }
|
||||
|
||||
DELETE /api/items/:itemCode
|
||||
Response: { message: "Deleted" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 2.2 BOM 관리 (필수)
|
||||
|
||||
```
|
||||
GET /api/items/:itemCode/bom
|
||||
Response:
|
||||
{
|
||||
data: BOMLine[] (flat list)
|
||||
}
|
||||
|
||||
GET /api/items/:itemCode/bom/tree
|
||||
🔴 Phase 0에서 부재 확인
|
||||
Response:
|
||||
{
|
||||
data: {
|
||||
item: ItemMaster
|
||||
children: [
|
||||
{
|
||||
bomLine: BOMLine
|
||||
item: ItemMaster
|
||||
children: [...] // 재귀
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
POST /api/items/:itemCode/bom
|
||||
Body: Partial<BOMLine>
|
||||
Response: { data: BOMLine }
|
||||
|
||||
PUT /api/items/:itemCode/bom/:lineId
|
||||
Body: Partial<BOMLine>
|
||||
Response: { data: BOMLine }
|
||||
|
||||
DELETE /api/items/:itemCode/bom/:lineId
|
||||
Response: { message: "Deleted" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 2.3 파일 관리 (필수)
|
||||
|
||||
```
|
||||
POST /api/items/:itemCode/files
|
||||
Body: FormData
|
||||
- type: 'specification' | 'certification' | 'bending_diagram'
|
||||
- file: File
|
||||
|
||||
Response:
|
||||
{
|
||||
data: {
|
||||
url: string
|
||||
fileName: string
|
||||
type: string
|
||||
}
|
||||
}
|
||||
|
||||
DELETE /api/items/:itemCode/files/:type
|
||||
Response: { message: "Deleted" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 2.4 동적 템플릿 (선택적, 2차 목표)
|
||||
|
||||
```
|
||||
GET /api/item-templates
|
||||
GET /api/item-templates/:pageId
|
||||
POST /api/item-templates
|
||||
PUT /api/item-templates/:pageId
|
||||
DELETE /api/item-templates/:pageId
|
||||
```
|
||||
|
||||
**우선순위:** 🟡 중간 (Phase 2-3 이후)
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Phase 0 Gap 통합 분석
|
||||
|
||||
### 기존 구현 현황 (Phase 0 검증 결과)
|
||||
|
||||
| Gap | 설명 | 상태 | 영향 |
|
||||
|-----|------|------|------|
|
||||
| #1 | 통합 품목 조회 API | ✅ 해결 | ItemsController 존재 |
|
||||
| #2 | 치수 연결 매핑 | ❌ 미해결 | dimension_mappings 테이블 필요 |
|
||||
| #3 | 실시간 견적 계산 | ⚠️ 부분 | BomCalculationController (설계만) |
|
||||
| #4 | BOM formula 필드 | ❌ 미해결 | product_components.formula 추가 |
|
||||
| #5 | 조건부 BOM | ❌ 미해결 | product_components.condition 추가 |
|
||||
| #6 | options/dimensions | ⚠️ 부분 | Material만, Product 없음 |
|
||||
| #7 | 가격 통합 조회 | ✅ 해결 | PricingService 완성 |
|
||||
|
||||
---
|
||||
|
||||
### 프론트엔드 가이드 vs Phase 0 Gap
|
||||
|
||||
| 프론트 요구사항 | Phase 0 Gap | 우선순위 |
|
||||
|----------------|-------------|---------|
|
||||
| ItemMaster 필드 | #6 (options) | 🔴 P0 |
|
||||
| BOMLine.quantityFormula | #4 (formula) | 🔴 P0 |
|
||||
| BOM tree API | 신규 발견 | 🔴 P0 |
|
||||
| 파일 업로드 | 기존 존재 | 🟢 완료 |
|
||||
| 치수 연결 | #2 | 🟡 P1 |
|
||||
| 견적 계산 API | #3 | 🟡 P1 |
|
||||
| 조건부 BOM | #5 | 🟡 P1 |
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ 데이터베이스 설계
|
||||
|
||||
### 1. products 테이블 확장
|
||||
|
||||
**현재 구조:**
|
||||
```sql
|
||||
-- 기존 필드 (Phase 0 분석)
|
||||
id, tenant_id, item_code, item_name, item_type
|
||||
specification, unit, category1, category2, category3
|
||||
purchase_price, sales_price
|
||||
attributes (JSON)
|
||||
created_by, updated_by, deleted_at, timestamps
|
||||
```
|
||||
|
||||
**추가 필요 필드 (프론트 가이드 기반):**
|
||||
```sql
|
||||
-- 공통
|
||||
is_active BOOLEAN DEFAULT true
|
||||
margin_rate DECIMAL(5,2)
|
||||
processing_cost DECIMAL(10,2)
|
||||
labor_cost DECIMAL(10,2)
|
||||
install_cost DECIMAL(10,2)
|
||||
safety_stock INT
|
||||
lead_time INT
|
||||
is_variable_size BOOLEAN DEFAULT false
|
||||
|
||||
-- FG 전용
|
||||
product_category VARCHAR(20) -- SCREEN, STEEL
|
||||
lot_abbreviation VARCHAR(10)
|
||||
note TEXT
|
||||
|
||||
-- PT 전용
|
||||
part_type VARCHAR(20) -- ASSEMBLY, BENDING, PURCHASED
|
||||
part_usage VARCHAR(30) -- GUIDE_RAIL, BOTTOM_FINISH, ...
|
||||
installation_type VARCHAR(20)
|
||||
assembly_type VARCHAR(20)
|
||||
side_spec_width VARCHAR(20)
|
||||
side_spec_height VARCHAR(20)
|
||||
assembly_length VARCHAR(20)
|
||||
guide_rail_model_type VARCHAR(50)
|
||||
guide_rail_model VARCHAR(50)
|
||||
|
||||
-- 절곡품
|
||||
bending_diagram VARCHAR(255) -- 이미지 URL
|
||||
bending_details JSON -- BendingDetail[]
|
||||
material VARCHAR(50)
|
||||
length VARCHAR(20)
|
||||
bending_length VARCHAR(20)
|
||||
|
||||
-- 인증
|
||||
certification_number VARCHAR(50)
|
||||
certification_start_date DATE
|
||||
certification_end_date DATE
|
||||
specification_file VARCHAR(255)
|
||||
specification_file_name VARCHAR(255)
|
||||
certification_file VARCHAR(255)
|
||||
certification_file_name VARCHAR(255)
|
||||
|
||||
-- 동적 확장 (기존 유지)
|
||||
options JSON -- 🔴 신규 추가 필요
|
||||
```
|
||||
|
||||
**Migration 작업량:** 2-3일
|
||||
|
||||
---
|
||||
|
||||
### 2. product_components 테이블 확장
|
||||
|
||||
**현재 구조:**
|
||||
```sql
|
||||
id, tenant_id
|
||||
parent_product_id, child_product_id (또는 material_id)
|
||||
quantity, unit, unit_price
|
||||
note
|
||||
created_by, updated_by, deleted_at, timestamps
|
||||
```
|
||||
|
||||
**추가 필요 필드:**
|
||||
```sql
|
||||
-- 핵심 필드
|
||||
quantity_formula TEXT -- 🔴 "W * 2", "H + 100", "G/1000*1.02"
|
||||
condition TEXT -- 🔴 "MOTOR='Y'", "WIDTH > 3000"
|
||||
|
||||
-- 절곡품
|
||||
is_bending BOOLEAN DEFAULT false
|
||||
bending_diagram VARCHAR(255)
|
||||
bending_details JSON
|
||||
```
|
||||
|
||||
**Migration 작업량:** 1일
|
||||
|
||||
---
|
||||
|
||||
### 3. 신규 테이블: dimension_mappings
|
||||
|
||||
```sql
|
||||
CREATE TABLE dimension_mappings (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id BIGINT NOT NULL,
|
||||
|
||||
parent_item_code VARCHAR(50) NOT NULL, -- 부모 품목 (예: 세트)
|
||||
child_item_code VARCHAR(50) NOT NULL, -- 자식 품목 (예: 가이드레일)
|
||||
|
||||
source_dimension VARCHAR(20) NOT NULL, -- 부모 치수명 (예: "W", "H")
|
||||
target_dimension VARCHAR(20) NOT NULL, -- 자식 치수명 (예: "G", "length")
|
||||
|
||||
mapping_formula VARCHAR(100), -- 변환 공식 (예: "W - 100")
|
||||
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
|
||||
created_by BIGINT,
|
||||
updated_by BIGINT,
|
||||
deleted_at TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
|
||||
INDEX idx_parent_item (tenant_id, parent_item_code),
|
||||
INDEX idx_child_item (tenant_id, child_item_code)
|
||||
);
|
||||
```
|
||||
|
||||
**Migration 작업량:** 1일
|
||||
|
||||
---
|
||||
|
||||
### 4. 신규 테이블: item_templates (선택적)
|
||||
|
||||
```sql
|
||||
CREATE TABLE item_templates (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id BIGINT NOT NULL,
|
||||
|
||||
page_name VARCHAR(100) NOT NULL,
|
||||
item_type VARCHAR(10) NOT NULL, -- FG, PT, SM, RM, CS
|
||||
|
||||
sections JSON NOT NULL, -- ItemSection[]
|
||||
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
absolute_path VARCHAR(255),
|
||||
|
||||
created_by BIGINT,
|
||||
updated_by BIGINT,
|
||||
deleted_at TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
|
||||
INDEX idx_item_type (tenant_id, item_type, is_active)
|
||||
);
|
||||
```
|
||||
|
||||
**우선순위:** 🟡 Phase 2-3 (선택적)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 백엔드 개발 작업 분류
|
||||
|
||||
### Priority 0 (즉시 시작, 1-2주)
|
||||
|
||||
#### Task 1.1: products 테이블 Migration
|
||||
- [ ] Migration 파일 작성
|
||||
- [ ] 프론트 가이드 필드 추가 (공통 + FG + PT + 인증)
|
||||
- [ ] options JSON 컬럼 추가
|
||||
- [ ] Rollback 스크립트 준비
|
||||
|
||||
**예상 시간:** 1일
|
||||
|
||||
---
|
||||
|
||||
#### Task 1.2: product_components 테이블 Migration
|
||||
- [ ] quantity_formula TEXT 컬럼 추가
|
||||
- [ ] condition TEXT 컬럼 추가
|
||||
- [ ] is_bending, bending_diagram, bending_details 추가
|
||||
- [ ] Rollback 스크립트
|
||||
|
||||
**예상 시간:** 0.5일
|
||||
|
||||
---
|
||||
|
||||
#### Task 1.3: ItemsController 확장
|
||||
- [ ] GET /api/items - 필터링 (itemType, search, category1)
|
||||
- [ ] GET /api/items/:itemCode - BOM 포함 응답
|
||||
- [ ] POST /api/items - 유형별 검증 (FG/PT/SM/RM/CS)
|
||||
- [ ] PUT /api/items/:itemCode
|
||||
- [ ] DELETE /api/items/:itemCode (Soft Delete)
|
||||
|
||||
**예상 시간:** 3일
|
||||
|
||||
---
|
||||
|
||||
#### Task 1.4: BOMController 신규 개발
|
||||
- [ ] GET /api/items/:itemCode/bom - flat list
|
||||
- [ ] GET /api/items/:itemCode/bom/tree - 계층 구조 (재귀)
|
||||
- [ ] POST /api/items/:itemCode/bom
|
||||
- [ ] PUT /api/items/:itemCode/bom/:lineId
|
||||
- [ ] DELETE /api/items/:itemCode/bom/:lineId
|
||||
|
||||
**예상 시간:** 3-4일
|
||||
|
||||
---
|
||||
|
||||
#### Task 1.5: FileController 확장
|
||||
- [ ] POST /api/items/:itemCode/files
|
||||
- type: specification, certification, bending_diagram
|
||||
- 파일 검증 (확장자, 크기)
|
||||
- Storage 저장 (local or S3)
|
||||
- URL 반환
|
||||
- [ ] DELETE /api/items/:itemCode/files/:type
|
||||
|
||||
**예상 시간:** 2일
|
||||
|
||||
---
|
||||
|
||||
### Priority 1 (2주차, 1-2주)
|
||||
|
||||
#### Task 2.1: dimension_mappings 테이블
|
||||
- [ ] Migration 작성
|
||||
- [ ] DimensionMapping 모델 생성
|
||||
- [ ] API: GET/POST/PUT/DELETE /api/dimension-mappings
|
||||
|
||||
**예상 시간:** 2일
|
||||
|
||||
---
|
||||
|
||||
#### Task 2.2: BOM 계산 로직 강화
|
||||
- [ ] quantityFormula 파싱 (수식 계산)
|
||||
- [ ] 변수 지원 (W, H, G, length 등)
|
||||
- [ ] 에러 핸들링 (잘못된 수식)
|
||||
- [ ] POST /api/quotes/calculate
|
||||
- 입력: itemCode + dimensions (W, H)
|
||||
- 출력: BOM 전개 + 수량 계산 + 원가
|
||||
|
||||
**예상 시간:** 3-4일
|
||||
|
||||
---
|
||||
|
||||
#### Task 2.3: 조건부 BOM
|
||||
- [ ] condition 필드 파싱 (조건 평가)
|
||||
- [ ] 조건부 BOM 필터링 로직
|
||||
- [ ] API 통합
|
||||
|
||||
**예상 시간:** 2-3일
|
||||
|
||||
---
|
||||
|
||||
### Priority 2 (3-4주차, 선택적)
|
||||
|
||||
#### Task 3.1: 동적 템플릿 시스템
|
||||
- [ ] item_templates 테이블
|
||||
- [ ] ItemTemplateController
|
||||
- [ ] GET/POST/PUT/DELETE /api/item-templates
|
||||
|
||||
**예상 시간:** 3-4일
|
||||
|
||||
---
|
||||
|
||||
#### Task 3.2: 성능 최적화
|
||||
- [ ] BOM tree 조회 성능 (N+1 문제 해결)
|
||||
- [ ] Eager Loading
|
||||
- [ ] Cache 전략 (Redis)
|
||||
- [ ] 인덱싱 최적화
|
||||
|
||||
**예상 시간:** 2-3일
|
||||
|
||||
---
|
||||
|
||||
## 📅 백엔드 개발 타임라인
|
||||
|
||||
### Week 1-2: 핵심 API 개발 (P0)
|
||||
|
||||
```
|
||||
Day 1-2:
|
||||
✅ products 테이블 Migration
|
||||
✅ product_components Migration
|
||||
✅ Migration 실행 및 검증
|
||||
|
||||
Day 3-5:
|
||||
✅ ItemsController 확장
|
||||
- GET /api/items (필터링)
|
||||
- GET /api/items/:itemCode (BOM 포함)
|
||||
- POST/PUT/DELETE
|
||||
|
||||
Day 6-9:
|
||||
✅ BOMController 신규
|
||||
- CRUD API
|
||||
- Tree 구조 조회 (재귀)
|
||||
|
||||
Day 10-12:
|
||||
✅ FileController 확장
|
||||
- 파일 업로드 (3가지 타입)
|
||||
- 파일 삭제
|
||||
- Storage 연동
|
||||
|
||||
Day 13-14:
|
||||
✅ 통합 테스트
|
||||
✅ Postman Collection 작성
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Week 3-4: BOM 계산 및 매핑 (P1)
|
||||
|
||||
```
|
||||
Day 15-16:
|
||||
✅ dimension_mappings 테이블
|
||||
✅ DimensionMappingController
|
||||
|
||||
Day 17-20:
|
||||
✅ BOM 계산 로직
|
||||
- quantityFormula 파싱
|
||||
- 변수 지원 (W, H, G)
|
||||
- POST /api/quotes/calculate
|
||||
|
||||
Day 21-23:
|
||||
✅ 조건부 BOM
|
||||
- condition 필드 파싱
|
||||
- 조건 평가 로직
|
||||
|
||||
Day 24-28:
|
||||
✅ 통합 테스트
|
||||
✅ 성능 테스트
|
||||
✅ 버그 수정
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Week 5-6: 선택적 확장 (P2)
|
||||
|
||||
```
|
||||
Day 29-32:
|
||||
🎯 동적 템플릿 시스템 (선택)
|
||||
- item_templates 테이블
|
||||
- Template API
|
||||
|
||||
Day 33-35:
|
||||
🎯 성능 최적화
|
||||
- Eager Loading
|
||||
- Cache
|
||||
- 인덱싱
|
||||
|
||||
Day 36-42:
|
||||
🎯 문서화
|
||||
🎯 배포 준비
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 테스트 전략
|
||||
|
||||
### Unit Test (PHPUnit)
|
||||
|
||||
```php
|
||||
// tests/Unit/Services/BomCalculationServiceTest.php
|
||||
class BomCalculationServiceTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function it_calculates_formula_with_variables()
|
||||
{
|
||||
$service = new BomCalculationService();
|
||||
|
||||
$formula = "W * 2 + H";
|
||||
$variables = ['W' => 3500, 'H' => 2000];
|
||||
|
||||
$result = $service->evaluateFormula($formula, $variables);
|
||||
|
||||
$this->assertEquals(9000, $result); // 3500*2 + 2000
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_builds_bom_tree_recursively()
|
||||
{
|
||||
$item = Product::factory()->create();
|
||||
// ...
|
||||
|
||||
$tree = $service->buildBomTree($item->item_code);
|
||||
|
||||
$this->assertArrayHasKey('children', $tree);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### API Test (Feature Test)
|
||||
|
||||
```php
|
||||
// tests/Feature/Api/ItemsControllerTest.php
|
||||
class ItemsControllerTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function it_lists_items_with_filtering()
|
||||
{
|
||||
$response = $this->getJson('/api/items?itemType=FG&search=test');
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertJsonStructure([
|
||||
'data' => [
|
||||
'*' => ['id', 'itemCode', 'itemName', 'itemType']
|
||||
],
|
||||
'meta' => ['total', 'page', 'perPage']
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_creates_item_with_validation()
|
||||
{
|
||||
$data = [
|
||||
'itemName' => 'Test Product',
|
||||
'itemType' => 'FG',
|
||||
'unit' => 'EA',
|
||||
// ...
|
||||
];
|
||||
|
||||
$response = $this->postJson('/api/items', $data);
|
||||
|
||||
$response->assertStatus(201)
|
||||
->assertJsonFragment(['itemName' => 'Test Product']);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Postman Collection
|
||||
|
||||
```json
|
||||
{
|
||||
"info": {
|
||||
"name": "BP-MES Items API",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "품목 목록 조회",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "{{baseUrl}}/api/items?itemType=FG&search=&category1="
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "품목 상세 조회",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "{{baseUrl}}/api/items/:itemCode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "BOM Tree 조회",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "{{baseUrl}}/api/items/:itemCode/bom/tree"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 API 문서화 (Swagger)
|
||||
|
||||
### Swagger 주석 예시
|
||||
|
||||
```php
|
||||
/**
|
||||
* @OA\Get(
|
||||
* path="/api/items",
|
||||
* summary="품목 목록 조회",
|
||||
* tags={"Items"},
|
||||
* security={{"sanctum":{}}},
|
||||
* @OA\Parameter(
|
||||
* name="itemType",
|
||||
* in="query",
|
||||
* description="품목 유형 (FG,PT,SM,RM,CS)",
|
||||
* required=false,
|
||||
* @OA\Schema(type="string", enum={"FG","PT","SM","RM","CS"})
|
||||
* ),
|
||||
* @OA\Parameter(
|
||||
* name="search",
|
||||
* in="query",
|
||||
* description="검색어 (품목명, 품목코드)",
|
||||
* required=false,
|
||||
* @OA\Schema(type="string")
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="성공",
|
||||
* @OA\JsonContent(
|
||||
* @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/ItemMaster")),
|
||||
* @OA\Property(property="meta", ref="#/components/schemas/PaginationMeta")
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 개발 환경 설정
|
||||
|
||||
### .env 설정
|
||||
|
||||
```bash
|
||||
# Laravel API
|
||||
APP_NAME="BP-MES API"
|
||||
APP_ENV=local
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost:8000
|
||||
|
||||
# Database
|
||||
DB_CONNECTION=pgsql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=5432
|
||||
DB_DATABASE=bp_mes
|
||||
DB_USERNAME=postgres
|
||||
DB_PASSWORD=
|
||||
|
||||
# File Storage
|
||||
FILESYSTEM_DISK=local
|
||||
# FILESYSTEM_DISK=s3
|
||||
# AWS_ACCESS_KEY_ID=
|
||||
# AWS_SECRET_ACCESS_KEY=
|
||||
# AWS_DEFAULT_REGION=
|
||||
# AWS_BUCKET=
|
||||
|
||||
# CORS (Next.js 프론트엔드)
|
||||
CORS_ALLOWED_ORIGINS=http://localhost:3000,https://your-frontend-domain.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CORS 설정
|
||||
|
||||
```php
|
||||
// config/cors.php
|
||||
return [
|
||||
'paths' => ['api/*', 'sanctum/csrf-cookie'],
|
||||
'allowed_methods' => ['*'],
|
||||
'allowed_origins' => explode(',', env('CORS_ALLOWED_ORIGINS', '*')),
|
||||
'allowed_origins_patterns' => [],
|
||||
'allowed_headers' => ['*'],
|
||||
'exposed_headers' => [],
|
||||
'max_age' => 0,
|
||||
'supports_credentials' => true,
|
||||
];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 주의사항
|
||||
|
||||
### 1. Multi-tenancy
|
||||
|
||||
**모든 API는 tenant_id 기반 필터링 필수:**
|
||||
|
||||
```php
|
||||
// ItemsController.php
|
||||
public function index(Request $request)
|
||||
{
|
||||
$tenantId = auth()->user()->tenant_id;
|
||||
|
||||
$items = Product::where('tenant_id', $tenantId)
|
||||
->when($request->itemType, fn($q, $v) => $q->where('item_type', $v))
|
||||
->when($request->search, fn($q, $v) => $q->where('item_name', 'like', "%{$v}%"))
|
||||
->get();
|
||||
|
||||
return response()->json(['data' => $items]);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Soft Delete
|
||||
|
||||
**삭제는 항상 Soft Delete:**
|
||||
|
||||
```php
|
||||
// Product 모델
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Product extends Model
|
||||
{
|
||||
use SoftDeletes, BelongsToTenant;
|
||||
|
||||
protected $dates = ['deleted_at'];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Audit Log
|
||||
|
||||
**변경 이력 기록:**
|
||||
|
||||
```php
|
||||
// 품목 수정 시
|
||||
AuditLog::create([
|
||||
'tenant_id' => $tenantId,
|
||||
'user_id' => auth()->id(),
|
||||
'action' => 'update',
|
||||
'model' => 'Product',
|
||||
'model_id' => $product->id,
|
||||
'changes' => [
|
||||
'before' => $product->getOriginal(),
|
||||
'after' => $product->getAttributes(),
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. 파일 업로드 검증
|
||||
|
||||
```php
|
||||
// FileController.php
|
||||
public function upload(Request $request, $itemCode)
|
||||
{
|
||||
$request->validate([
|
||||
'type' => 'required|in:specification,certification,bending_diagram',
|
||||
'file' => 'required|file|max:10240|mimes:pdf,jpg,jpeg,png',
|
||||
]);
|
||||
|
||||
$type = $request->type;
|
||||
$file = $request->file('file');
|
||||
|
||||
// 파일 저장
|
||||
$path = $file->store("items/{$itemCode}/{$type}", 'public');
|
||||
$url = Storage::url($path);
|
||||
|
||||
// DB 업데이트
|
||||
$item = Product::where('item_code', $itemCode)->firstOrFail();
|
||||
|
||||
if ($type === 'specification') {
|
||||
$item->specification_file = $url;
|
||||
$item->specification_file_name = $file->getClientOriginalName();
|
||||
} elseif ($type === 'certification') {
|
||||
$item->certification_file = $url;
|
||||
$item->certification_file_name = $file->getClientOriginalName();
|
||||
} elseif ($type === 'bending_diagram') {
|
||||
$item->bending_diagram = $url;
|
||||
}
|
||||
|
||||
$item->save();
|
||||
|
||||
return response()->json([
|
||||
'data' => [
|
||||
'url' => $url,
|
||||
'fileName' => $file->getClientOriginalName(),
|
||||
'type' => $type,
|
||||
]
|
||||
]);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 참고 문서
|
||||
|
||||
### 프로젝트 문서
|
||||
- **프론트엔드 가이드:** `ITEM_MANAGEMENT_MIGRATION_GUIDE.md`
|
||||
- **Phase 0 보고서:** `PHASE_0_FINAL_REPORT.md`
|
||||
- **Gap 검증:** `api_gap_validation_report.md`
|
||||
- **아키텍처 옵션:** `ARCHITECTURE_OPTIONS_CORE.md`
|
||||
|
||||
### Laravel 문서
|
||||
- [Laravel 12 Documentation](https://laravel.com/docs/12.x)
|
||||
- [Eloquent ORM](https://laravel.com/docs/12.x/eloquent)
|
||||
- [API Resources](https://laravel.com/docs/12.x/eloquent-resources)
|
||||
- [File Storage](https://laravel.com/docs/12.x/filesystem)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 다음 단계
|
||||
|
||||
### 즉시 시작:
|
||||
1. **Migration 파일 작성** (products, product_components 확장)
|
||||
2. **ItemsController 리뷰** (기존 구현 확인)
|
||||
3. **BOMController 설계** (tree API 구조)
|
||||
|
||||
### 협의 필요:
|
||||
- [ ] 절곡품 계산 로직: 프론트 vs 백엔드?
|
||||
- [ ] 파일 저장소: Local vs S3?
|
||||
- [ ] BOM 계산 API 응답 형식 확정
|
||||
- [ ] quantityFormula 수식 파싱 라이브러리 선택
|
||||
|
||||
### 준비 사항:
|
||||
- [ ] 개발 서버 환경 확인
|
||||
- [ ] PostgreSQL/MySQL 준비
|
||||
- [ ] Postman 설치
|
||||
- [ ] Git branch 전략
|
||||
|
||||
---
|
||||
|
||||
**작성일:** 2025-11-13
|
||||
**버전:** 2.0 (프론트엔드 가이드 통합)
|
||||
**다음 업데이트:** Migration 완료 후
|
||||
Reference in New Issue
Block a user