---
source: api/ Laravel 프로젝트 코드 분석
section: 코드 분석
created: 2025-11-12
bp_mes_phase: Phase B.1 - 코드 분석
related:
  - api_item_analysis_summary.md
  - api_gap_validation_report.md
  - document_cross_reference_map.md
tags: [api, laravel, code-analysis, models, controllers]
---

# Laravel API 코드 분석 요약

**분석일:** 2025-11-12
**Phase:** B.1 - Laravel API 코드 분석
**분석 범위:** 품목, BOM, 가격, 견적 관련 코드

---

## Executive Summary

### 🎉 주요 발견사항 (긍정적)

**문서 분석에서 예상했던 것보다 훨씬 더 많이 구현되어 있습니다!**

1. ✅ **통합 품목 조회 API 이미 구현됨!** (Gap #1 해결)
   - `ItemsController` 존재
   - `GET /api/v1/items` - materials + products 통합 조회
   - 타입 필터링, 검색, 카테고리 필터 지원

2. ✅ **품목-가격 통합 조회 API 이미 구현됨!** (Gap #7 해결)
   - `ItemsController.show()`
   - `include_price=true&client_id=1&price_date=2025-01-10` 파라미터 지원
   - PricingService와 완전 통합

3. ✅ **BOM 계산 API 구현됨!** (Gap #3 부분 해결)
   - `BomCalculationController` 존재
   - 설계 BOM 기반 실시간 계산 지원
   - 회사별 공식 관리 기능 포함

4. ✅ **가격 시스템 완전 구현!**
   - `PricingController` (5개 엔드포인트)
   - `PriceHistory` 모델 (시계열, 고객별 가격)
   - 문서 분석 결과와 100% 일치

5. ⚠️ **Material 모델에 attributes + options 필드 존재!** (Gap #6 부분 해결)
   - `Material.php`: attributes, options (array 캐스팅)
   - `Product.php`: attributes만 존재 (options 없음)

---

### ❌ 여전히 존재하는 Gap

1. **Gap #2**: 치수 연결 매핑 시스템 부재 (🔴 Critical)
   - dimension_mappings 테이블 없음
   - 상위 치수 → 하위 치수 자동 전달 기능 없음

2. **Gap #4**: product_components에 formula 필드 없음 (🔴 Critical)
   - bom_templates에는 calculation_schema 존재
   - 실제 제품 BOM에는 계산식 지원 안됨

3. **Gap #5**: product_components에 condition 필드 없음 (🔴 Critical)
   - 조건부 BOM 지원 안됨

4. **Gap #8**: material_type 필드 없음 (🟡 Important)
   - category_id로만 구분

---

## 1. 품목 관리 (Item Management)

### 1.1 Product 모델 (`app/Models/Products/Product.php`)

**Fillable 필드:**
```php
[
    'tenant_id', 'code', 'name', 'unit', 'category_id',
    'product_type', // 라벨/분류용
    'attributes', // JSON (확장 필드)
    'description',
    'is_sellable', 'is_purchasable', 'is_producible', 'is_active',
    'created_by', 'updated_by',
]
```

**Casts:**
- `attributes` → array
- Boolean 플래그 4개 (is_sellable, is_purchasable, is_producible, is_active)

**Relationships:**
- `category()` - Category
- `componentLines()` - ProductComponent (하위 BOM)
- `parentLines()` - ProductComponent (상위 BOM)
- `children()`, `parents()` - self-referencing (BelongsToMany)
- `files()`, `tags()` - polymorphic

**Gap #6 검증:**
- ✅ `attributes` 필드 존재 (JSON)
- ❌ `dimensions` 필드 없음
- ❌ `options` 필드 없음

---

### 1.2 Material 모델 (`app/Models/Materials/Material.php`)

**Fillable 필드:**
```php
[
    'tenant_id', 'category_id',
    'name', 'item_name', 'specification', 'material_code', 'unit',
    'is_inspection', 'search_tag', 'remarks',
    'attributes', // JSON (확장 필드)
    'options',    // JSON (확장 필드) ⭐
    'created_by', 'updated_by',
]
```

**Casts:**
- `attributes` → array
- `options` → array ⭐

**Relationships:**
- `receipts()` - MaterialReceipt
- `lots()` - Lot
- `files()`, `tags()` - polymorphic

**Gap #6 검증:**
- ✅ `attributes` 필드 존재
- ✅ `options` 필드 존재 ⭐ (Product에는 없음!)

**Gap #8 검증:**
- ❌ `material_type` 필드 없음
- category_id로만 구분

---

### 1.3 ProductController (`app/Http/Controllers/Api/V1/ProductController.php`)

**엔드포인트:**
```
GET    /api/v1/products          - index (목록)
POST   /api/v1/products          - store (등록)
GET    /api/v1/products/{id}     - show (상세)
PATCH  /api/v1/products/{id}     - update (수정)
DELETE /api/v1/products/{id}     - destroy (삭제)
GET    /api/v1/products/search   - search (검색) ✅
POST   /api/v1/products/{id}/toggle - toggle (활성화/비활성화)
```

**특징:**
- ProductService 의존성 주입 (Service-First)
- ApiResponse::handle() 사용
- FormRequest 사용 (ProductStoreRequest, ProductUpdateRequest)

---

### 1.4 MaterialController (`app/Http/Controllers/Api/V1/MaterialController.php`)

**엔드포인트:**
```
GET    /api/v1/materials         - index
POST   /api/v1/materials         - store
GET    /api/v1/materials/{id}    - show
PATCH  /api/v1/materials/{id}    - update
DELETE /api/v1/materials/{id}    - destroy
```

**Gap 검증:**
- ❌ search 엔드포인트 없음 (문서 분석과 일치)

---

### 1.5 ItemsController (`app/Http/Controllers/Api/V1/ItemsController.php`) ⭐ 발견!

**엔드포인트:**
```php
/**
 * 통합 품목 목록 조회 (materials + products)
 * GET /api/v1/items
 */
public function index(Request $request)
{
    $filters = $request->only(['type', 'search', 'q', 'category_id']);
    $perPage = (int) ($request->input('size') ?? 20);

    return $this->service->getItems($filters, $perPage);
}

/**
 * 단일 품목 조회
 * GET /api/v1/items/{id}?item_type=PRODUCT|MATERIAL&include_price=true&client_id=1&price_date=2025-01-10
 */
public function show(Request $request, int $id)
{
    $itemType = strtoupper($request->input('item_type', 'PRODUCT'));
    $includePrice = filter_var($request->input('include_price', false), FILTER_VALIDATE_BOOLEAN);
    $clientId = $request->input('client_id') ? (int) $request->input('client_id') : null;
    $priceDate = $request->input('price_date');

    return $this->service->getItem($itemType, $id, $includePrice, $clientId, $priceDate);
}
```

**Gap #1 검증: ✅ 통합 품목 조회 API 이미 구현됨!**
**Gap #7 검증: ✅ 품목-가격 통합 조회 이미 구현됨!**

**특징:**
- materials + products 통합 조회
- 타입 필터링 (`type` 파라미터)
- 검색 지원 (`search`, `q`)
- 카테고리 필터링 (`category_id`)
- **가격 포함 조회 지원** (`include_price`, `client_id`, `price_date`) ⭐

---

## 2. BOM 시스템 (Bill of Materials)

### 2.1 ProductComponent 모델 (`app/Models/Products/ProductComponent.php`)

**Fillable 필드:**
```php
[
    'tenant_id',
    'parent_product_id',
    'category_id', 'category_name',
    'ref_type',    // 'PRODUCT' | 'MATERIAL'
    'ref_id',      // 다형성 참조 ID
    'quantity',    // decimal(18,6)
    'sort_order',
    'created_by', 'updated_by',
]
```

**Casts:**
- `quantity` → decimal:6

**Relationships:**
- `parentProduct()` - Product
- `referencedItem()` - Product 또는 Material (동적)
- `product()` - Product (ref_type = PRODUCT)
- `material()` - Material (ref_type = MATERIAL)

**Query Scopes:**
- `products()` - PRODUCT만
- `materials()` - MATERIAL만
- `forParent($parentProductId)` - 특정 상위 제품

**Gap #4 검증: ❌ formula 필드 없음!**
- quantity는 고정 수량만 지원
- 계산식 지원 안됨

**Gap #5 검증: ❌ condition 필드 없음!**
- 조건부 BOM 지원 안됨

---

### 2.2 BomTemplate 모델 (`app/Models/Design/BomTemplate.php`)

**Fillable 필드:**
```php
[
    'tenant_id', 'model_version_id', 'name', 'is_primary', 'notes',
    'calculation_schema', // JSON ⭐
    'company_type', 'formula_version',
]
```

**Casts:**
- `calculation_schema` → array ⭐

**Relationships:**
- `modelVersion()` - ModelVersion
- `items()` - BomTemplateItem

**특징:**
- ✅ `calculation_schema` JSON 필드 존재!
- 설계 BOM용 (model_version_id 기반)
- 실제 제품 BOM (product_components)과는 별도

**Gap #4 참고:**
- bom_templates에는 calculation_schema 있음
- product_components에는 없음
- **두 시스템이 분리되어 있음**

---

### 2.3 BomCalculationController (`app/Http/Controllers/Api/V1/Design/BomCalculationController.php`) ⭐ 발견!

**엔드포인트:**

```php
/**
 * 견적 파라미터 조회
 * GET /api/v1/design/models/{id}/parameters?company_name=xxx
 */
public function getEstimateParameters(GetEstimateParametersRequest $request, int $modelId)

/**
 * BOM 계산 (견적 산출)
 * POST /api/v1/design/bom-templates/{id}/calculate
 */
public function calculateBom(CalculateBomRequest $request, int $bomTemplateId)
{
    $result = $this->bomCalculationService->calculateBomEstimate(
        $bomTemplateId,
        $data['parameters'],     // 입력 파라미터 (W, H 등)
        $data['company_name']
    );
}

/**
 * 회사별 공식 조회
 * GET /api/v1/design/company-formulas/{companyName}
 */
public function getCompanyFormulas(string $companyName)

/**
 * 회사별 공식 저장
 * POST /api/v1/design/company-formulas/{companyName}/{formulaType}
 */
public function saveCompanyFormula(SaveCompanyFormulaRequest $request, ...)

/**
 * 공식 테스트
 * POST /api/v1/design/formulas/test
 */
public function testFormula(Request $request)
{
    $parser = app(\App\Services\Calculation\FormulaParser::class);
    $result = $parser->execute(
        $request->input('formula_expression'),
        $request->input('test_parameters')
    );
}
```

**Gap #3 검증: ⚠️ 부분 구현됨!**
- ✅ BOM 계산 API 존재
- ✅ 실시간 계산 지원
- ✅ FormulaParser 존재 (공식 파싱 엔진)
- ⚠️ 설계 BOM (bom_templates) 기반
- ❌ 실제 Order/Quote 기반 견적 계산 API는 없음

**특징:**
- 설계 도메인 (Design)
- 회사별 맞춤 공식 관리
- 파라미터 기반 동적 계산
- FormulaParser 사용

---

## 3. 가격 시스템 (Pricing System)

### 3.1 PriceHistory 모델 (`app/Models/Products/PriceHistory.php`)

**Fillable 필드:**
```php
[
    'tenant_id',
    'item_type_code',   // 'PRODUCT' | 'MATERIAL'
    'item_id',          // 다형성 참조
    'price_type_code',  // 'SALE' | 'PURCHASE'
    'client_group_id',  // NULL = 기본, 값 = 그룹별
    'price',            // decimal(18,4)
    'started_at',       // 시계열 시작
    'ended_at',         // 시계열 종료 (NULL = 현재)
    'created_by', 'updated_by', 'deleted_by',
]
```

**Casts:**
- `price` → decimal:4
- `started_at`, `ended_at` → date

**Relationships:**
- `clientGroup()` - ClientGroup
- `item()` - Product 또는 Material (동적)

**Query Scopes:**
- `forItem($itemType, $itemId)` - 특정 품목
- `forClientGroup($clientGroupId)` - 특정 고객그룹
- `validAt($date)` - 특정 날짜에 유효한 가격
- `salePrice()` - 판매가만
- `purchasePrice()` - 매입가만

**Gap #7 검증: ✅ 완전 구현됨!**
- 다형성 가격 관리
- 고객별 차별 가격
- 시계열 이력 관리
- 가격 유형 구분

---

### 3.2 PricingController (`app/Http/Controllers/Api/V1/PricingController.php`)

**엔드포인트:**

```php
/**
 * 가격 이력 목록 조회
 * GET /api/v1/pricing
 */
public function index(Request $request)
{
    $filters = $request->only([
        'item_type_code', 'item_id', 'price_type_code',
        'client_group_id', 'date',
    ]);
    $perPage = (int) ($request->input('size') ?? 15);
}

/**
 * 단일 항목 가격 조회
 * GET /api/v1/pricing/show
 */
public function show(Request $request)
{
    $itemType = $request->input('item_type');    // PRODUCT | MATERIAL
    $itemId = (int) $request->input('item_id');
    $clientId = $request->input('client_id') ? (int) $request->input('client_id') : null;
    $date = $request->input('date') ?? null;

    return $this->service->getItemPrice($itemType, $itemId, $clientId, $date);
}

/**
 * 여러 항목 일괄 가격 조회
 * POST /api/v1/pricing/bulk
 */
public function bulk(Request $request)
{
    $items = $request->input('items'); // [['item_type' => 'PRODUCT', 'item_id' => 1], ...]
    $clientId = $request->input('client_id') ? (int) $request->input('client_id') : null;
    $date = $request->input('date') ?? null;

    return $this->service->getBulkItemPrices($items, $clientId, $date);
}

/**
 * 가격 등록/수정
 * POST /api/v1/pricing/upsert
 */
public function upsert(Request $request)

/**
 * 가격 삭제
 * DELETE /api/v1/pricing/{id}
 */
public function destroy(int $id)
```

**Gap #7 검증: ✅ 완전 구현됨!**
- 5개 엔드포인트 모두 존재
- 단일/일괄 조회 지원
- 고객별, 날짜별 가격 조회 지원
- Upsert 패턴 사용

---

## 4. 견적 시스템 (Quotation System)

### 4.1 Order 모델 (`app/Models/Orders/Order.php`)

**Fillable 필드:**
```php
[
    'tenant_id', 'order_no', 'order_type_code', 'status_code',
    'category_code', 'product_id',
    'received_at', 'writer_id', 'client_id', 'client_contact',
    'site_name', 'quantity', 'delivery_date',
    'delivery_method_code', 'memo',
]
```

**Relationships:**
- `items()` - OrderItem (상세 라인)
- `histories()` - OrderHistory (이력)
- `versions()` - OrderVersion (버전 관리)

**특징:**
- order_type_code로 견적/수주/발주 구분
- 버전 관리 지원
- 이력 추적

---

### 4.2 OrderController - ❌ 존재하지 않음!

**Gap #3 검증:**
- ⚠️ BomCalculationController는 존재 (설계 BOM 기반)
- ❌ OrderController 없음
- ❌ QuoteController 없음
- ❌ Order 기반 견적 계산 API 없음

**존재하는 것:**
- Order 모델 (견적/수주 데이터)
- BomCalculationController (설계 BOM 계산)

**없는 것:**
- Order 생성/조회/수정/삭제 API
- Order 기반 실시간 견적 계산 API
- 치수 입력 → Order 생성 → BOM 전개 → 원가 계산 Flow

---

## Gap 검증 최종 결과

| Gap # | 항목 | 문서 분석 | 코드 분석 | 최종 결과 |
|-------|------|----------|----------|----------|
| #1 | 통합 품목 조회 API | ❌ 부재 | ✅ **존재!** | ✅ ItemsController |
| #2 | 치수 연결 매핑 | ❌ 부재 | ❌ 부재 | 🔴 신규 개발 필요 |
| #3 | 실시간 견적 계산 | ❌ 부재 | ⚠️ **부분!** | 🟡 BomCalculation (설계 BOM만) |
| #4 | BOM 계산식 필드 | ❓ 미확인 | ❌ 부재 | 🔴 product_components에 formula 없음 |
| #5 | 조건부 BOM 필드 | ❓ 미확인 | ❌ 부재 | 🔴 product_components에 condition 없음 |
| #6 | 치수/옵션 필드 | ❓ 미확인 | ⚠️ **부분!** | 🟡 Material에만 options 있음 |
| #7 | 가격 매핑 | ❌ 불일치 | ✅ **존재!** | ✅ ItemsController.show() |
| #8 | 품목 타입 구분 | ⚠️ 불명확 | ❌ 부재 | 🟡 material_type 없음 |

---

## 주요 발견 요약

### ✅ 긍정적 발견 (예상보다 더 많이 구현됨!)

1. **ItemsController 완전 구현**
   - 통합 품목 조회 (materials + products)
   - 가격 포함 조회 (include_price 파라미터)
   - 문서에서는 "부재"로 분석했지만 실제로는 존재!

2. **가격 시스템 100% 완성**
   - PriceHistory 모델 완전 구현
   - PricingController 5개 엔드포인트
   - ItemsController와 통합
   - 문서 분석과 정확히 일치

3. **BOM 계산 엔진 존재**
   - BomCalculationController
   - FormulaParser (공식 파싱 엔진)
   - 회사별 맞춤 공식 관리
   - 설계 BOM 기반 계산 지원

4. **Material 모델 확장성 우수**
   - attributes + options 모두 지원
   - Product보다 더 풍부한 필드 구조

### ❌ 여전히 필요한 개발

1. **치수 연결 매핑 시스템** (🔴 Critical)
   - dimension_mappings 테이블 신설
   - 상위 치수 → 하위 치수 자동 전달 로직

2. **product_components 확장** (🔴 Critical)
   - formula 필드 추가 (계산식)
   - condition 필드 추가 (조건부 BOM)

3. **Order 기반 견적 API** (🟡 Important)
   - OrderController 신규 개발
   - Order 생성/조회/수정 API
   - Order → BOM 전개 → 가격 계산 Flow

4. **Product 모델 확장** (🟡 Important)
   - options 필드 추가 (Material처럼)
   - dimensions 필드 추가 (또는 attributes 활용)

5. **material_type 필드** (🟢 Nice to Have)
   - RM/SM/CS 구분 컬럼

---

## 다음 단계

**Phase B.2: React 코드 분석**
- ItemManagement.tsx 상세 분석
- QuoteManagement3List/Write.tsx 분석
- shadcn/ui 활용 현황
- 재사용 가능 컴포넌트 매핑

**Phase B.3: Gap 검증 보고서 작성**
- 최종 Gap 분석
- 우선순위 재조정
- 개발 로드맵 업데이트

---

**문서 버전:** v1.0
**작성일:** 2025-11-12
**BP-MES Phase:** B.1 완료
**다음 단계:** Phase B.2 (React 코드 분석)
