docs: 5130 레거시 분석 문서 및 기존 문서 초기 커밋

- 5130 레거시 시스템 분석 (00_OVERVIEW ~ 08_SAM_COMPARISON)
- MES 프로젝트 문서
- API/프론트엔드 스펙 문서
- 가이드 및 레퍼런스 문서
This commit is contained in:
2025-12-04 18:47:19 +09:00
commit 08a8259313
135 changed files with 32721 additions and 0 deletions

View 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 완료 후