- 5130 레거시 시스템 분석 (00_OVERVIEW ~ 08_SAM_COMPARISON) - MES 프로젝트 문서 - API/프론트엔드 스펙 문서 - 가이드 및 레퍼런스 문서
22 KiB
22 KiB
source, section, created, updated, bp_mes_phase, related, tags
| source | section | created | updated | bp_mes_phase | related | tags | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Phase 0 + 프론트엔드 가이드 통합 분석 | BP-MES 백엔드 개발 로드맵 (개정판) | 2025-11-13 | 2025-11-13 | Phase 0 완료, Phase 1 준비 |
|
|
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 개발에만 집중
핵심 방향
- 하이브리드 전략: 고정 필드 API (우선) + 메타데이터 API (선택)
- RESTful 설계: 프론트 가이드 엔드포인트 스펙 준수
- BOM 계산 강화: quantityFormula, 계층 구조, tree API
- 파일 관리: 절곡도, 시방서, 인정서 업로드
🎯 프론트엔드 요구사항 분석
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 구조
{
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 테이블 확장
현재 구조:
-- 기존 필드 (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
추가 필요 필드 (프론트 가이드 기반):
-- 공통
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 테이블 확장
현재 구조:
id, tenant_id
parent_product_id, child_product_id (또는 material_id)
quantity, unit, unit_price
note
created_by, updated_by, deleted_at, timestamps
추가 필요 필드:
-- 핵심 필드
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
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 (선택적)
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)
// 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)
// 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
{
"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 주석 예시
/**
* @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 설정
# 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 설정
// 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 기반 필터링 필수:
// 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:
// Product 모델
use Illuminate\Database\Eloquent\SoftDeletes;
class Product extends Model
{
use SoftDeletes, BelongsToTenant;
protected $dates = ['deleted_at'];
}
3. Audit Log
변경 이력 기록:
// 품목 수정 시
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. 파일 업로드 검증
// 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 문서
🎯 다음 단계
즉시 시작:
- Migration 파일 작성 (products, product_components 확장)
- ItemsController 리뷰 (기존 구현 확인)
- BOMController 설계 (tree API 구조)
협의 필요:
- 절곡품 계산 로직: 프론트 vs 백엔드?
- 파일 저장소: Local vs S3?
- BOM 계산 API 응답 형식 확정
- quantityFormula 수식 파싱 라이브러리 선택
준비 사항:
- 개발 서버 환경 확인
- PostgreSQL/MySQL 준비
- Postman 설치
- Git branch 전략
작성일: 2025-11-13 버전: 2.0 (프론트엔드 가이드 통합) 다음 업데이트: Migration 완료 후