811 lines
28 KiB
Markdown
811 lines
28 KiB
Markdown
|
|
# 품목 마스터 API 갭 분석 보고서
|
||
|
|
|
||
|
|
**작성일**: 2025-11-20
|
||
|
|
**분석자**: Claude Code (Sequential Thinking)
|
||
|
|
**문서 버전**: v1.0
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📋 목차
|
||
|
|
|
||
|
|
1. [요약](#요약)
|
||
|
|
2. [DB 모델 비교 분석](#db-모델-비교-분석)
|
||
|
|
3. [API 갭 분석](#api-갭-분석)
|
||
|
|
4. [구현 전략](#구현-전략)
|
||
|
|
5. [상세 구현 로드맵](#상세-구현-로드맵)
|
||
|
|
6. [리스크 및 대응 방안](#리스크-및-대응-방안)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 요약
|
||
|
|
|
||
|
|
### 핵심 결론
|
||
|
|
|
||
|
|
**프론트 요구사항을 그대로 수용하여 신규 시스템 구축 권장**
|
||
|
|
|
||
|
|
- ✅ **기존 API 영향 없음**: `/v1/item-master/*` 별도 네임스페이스
|
||
|
|
- ✅ **SAM API Rules 완벽 준수**: Multi-tenant, Service-First, FormRequest 등
|
||
|
|
- ✅ **점진적 마이그레이션 가능**: 기존 Products/Materials와 병행 운영
|
||
|
|
- ⏱️ **예상 개발 기간**: 4-5주
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## DB 모델 비교 분석
|
||
|
|
|
||
|
|
### 1. 현재 DB 구조 (하이브리드 접근)
|
||
|
|
|
||
|
|
#### 핵심 테이블
|
||
|
|
|
||
|
|
| 테이블 | 모델 | 특징 | 용도 |
|
||
|
|
|--------|------|------|------|
|
||
|
|
| `products` | Product | 고정 필드 + attributes JSON | 제품 마스터 |
|
||
|
|
| `materials` | Material | 고정 필드 + attributes JSON | 자재 마스터 |
|
||
|
|
| `product_components` | ProductComponent | ref_type (PRODUCT/MATERIAL) | BOM 관계 |
|
||
|
|
| `categories` | Category | 계층 구조 | 카테고리 분류 |
|
||
|
|
| `category_fields` | CategoryField | 동적 필드 정의 | 카테고리별 필드 |
|
||
|
|
|
||
|
|
#### 특징
|
||
|
|
|
||
|
|
- **하이브리드 구조**: 고정 필드(최소화) + JSON attributes(동적 필드)
|
||
|
|
- **카테고리 기반**: category_id로 분류
|
||
|
|
- **BOM 통합**: ProductComponent에서 제품/자재 모두 관리
|
||
|
|
- **Multi-tenant**: BelongsToTenant 적용
|
||
|
|
- **Soft Delete**: 모든 테이블 적용
|
||
|
|
|
||
|
|
### 2. 프론트 제안 DB 구조 (완전 동적 구조)
|
||
|
|
|
||
|
|
#### 9개 테이블
|
||
|
|
|
||
|
|
| 테이블 | 용도 | 핵심 특징 |
|
||
|
|
|--------|------|-----------|
|
||
|
|
| `item_pages` | 품목 유형별 페이지 관리 | item_type (FG/PT/SM/RM/CS) |
|
||
|
|
| `item_sections` | 섹션 인스턴스 | type (fields/bom), order_no |
|
||
|
|
| `item_fields` | 필드 인스턴스 | field_type, validation_rules JSON |
|
||
|
|
| `item_bom_items` | BOM 항목 | item_code, quantity, unit |
|
||
|
|
| `section_templates` | 섹션 템플릿 | 재사용 가능 템플릿 |
|
||
|
|
| `item_master_fields` | 마스터 필드 풀 | 필드 라이브러리 |
|
||
|
|
| `custom_tabs` | 커스텀 탭 | 탭 정의 |
|
||
|
|
| `tab_columns` | 탭별 컬럼 설정 | columns JSON |
|
||
|
|
| `unit_options` | 단위 옵션 | 단위 관리 |
|
||
|
|
|
||
|
|
#### 특징
|
||
|
|
|
||
|
|
- **페이지-섹션-필드 구조**: 3단계 계층
|
||
|
|
- **메타 프로그래밍**: 완전 동적 UI 생성 지향
|
||
|
|
- **템플릿 시스템**: 섹션/필드 재사용
|
||
|
|
- **실시간 저장**: 모든 CUD 즉시 처리
|
||
|
|
- **노션 스타일**: 블록 기반 구조
|
||
|
|
|
||
|
|
### 3. 구조적 차이점
|
||
|
|
|
||
|
|
| 항목 | 현재 구조 | 프론트 제안 |
|
||
|
|
|------|-----------|-------------|
|
||
|
|
| **접근 방식** | 하이브리드 (고정+JSON) | 완전 동적 (메타) |
|
||
|
|
| **분류 체계** | Category 기반 | Page 기반 |
|
||
|
|
| **필드 정의** | CategoryField | ItemField (인스턴스) |
|
||
|
|
| **템플릿** | 없음 | SectionTemplate |
|
||
|
|
| **BOM 구조** | ProductComponent | ItemBomItem |
|
||
|
|
| **확장성** | 중간 | 매우 높음 |
|
||
|
|
| **복잡도** | 낮음 | 높음 |
|
||
|
|
|
||
|
|
### 4. 재설계 필요 여부
|
||
|
|
|
||
|
|
**❌ 기존 구조 확장으로는 불충분**
|
||
|
|
|
||
|
|
**이유**:
|
||
|
|
1. 페이지-섹션-필드 3단계 구조는 기존 카테고리 구조와 근본적으로 다름
|
||
|
|
2. 섹션 템플릿, 마스터 필드 풀 개념 없음
|
||
|
|
3. 커스텀 탭 시스템 완전 신규
|
||
|
|
4. 프론트가 요구하는 메타 프로그래밍 수준 미달
|
||
|
|
|
||
|
|
**✅ 신규 시스템 구축 권장**
|
||
|
|
|
||
|
|
**근거**:
|
||
|
|
- 기존 Products/Materials API는 단순 CRUD, 메타 구조 미지원
|
||
|
|
- 별도 네임스페이스로 구축하여 기존 시스템 영향 없음
|
||
|
|
- 점진적 마이그레이션 가능 (병행 운영)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## API 갭 분석
|
||
|
|
|
||
|
|
### 1. 기존 API 현황
|
||
|
|
|
||
|
|
#### Products API (`/v1/products/*`)
|
||
|
|
|
||
|
|
| 엔드포인트 | 메서드 | 기능 | 재사용 가능성 |
|
||
|
|
|------------|--------|------|---------------|
|
||
|
|
| `/v1/products` | GET | 목록 조회 | ❌ 메타 구조 없음 |
|
||
|
|
| `/v1/products` | POST | 생성 | ❌ 페이지 개념 없음 |
|
||
|
|
| `/v1/products/{id}` | GET/PATCH/DELETE | 단건 CRUD | ❌ 섹션/필드 미지원 |
|
||
|
|
| `/v1/products/{id}/bom/items` | GET/POST/PUT | BOM 관리 | 🔶 부분 재사용 가능 |
|
||
|
|
|
||
|
|
#### Categories API (`/v1/categories/*`)
|
||
|
|
|
||
|
|
| 엔드포인트 | 메서드 | 기능 | 재사용 가능성 |
|
||
|
|
|------------|--------|------|---------------|
|
||
|
|
| `/v1/categories` | GET/POST | 목록/생성 | 🔶 템플릿으로 활용 가능 |
|
||
|
|
| `/v1/categories/{id}/fields` | GET/POST | 필드 관리 | 🔶 마스터 필드로 활용 가능 |
|
||
|
|
| `/v1/categories/{id}/templates` | GET/POST | 템플릿 | ✅ 부분 재사용 가능 |
|
||
|
|
|
||
|
|
#### Items API (`/v1/items/*`)
|
||
|
|
|
||
|
|
| 엔드포인트 | 메서드 | 기능 | 재사용 가능성 |
|
||
|
|
|------------|--------|------|---------------|
|
||
|
|
| `/v1/items` | GET | 통합 목록 | ❌ 메타 구조 없음 |
|
||
|
|
| `/v1/items/{code}/bom` | GET/POST | BOM 관리 | 🔶 부분 재사용 가능 |
|
||
|
|
|
||
|
|
### 2. 요청 API 목록 (프론트 요구사항)
|
||
|
|
|
||
|
|
#### 초기화 API
|
||
|
|
|
||
|
|
| 엔드포인트 | 메서드 | 우선순위 | 신규 개발 |
|
||
|
|
|------------|--------|----------|-----------|
|
||
|
|
| `GET /v1/item-master/init` | GET | 🔴 필수 | ✅ 완전 신규 |
|
||
|
|
|
||
|
|
**특징**: 한 번의 API 호출로 전체 데이터 로드 (pages + sections + fields + bomItems)
|
||
|
|
|
||
|
|
#### 페이지 관리 API
|
||
|
|
|
||
|
|
| 엔드포인트 | 메서드 | 우선순위 | 신규 개발 |
|
||
|
|
|------------|--------|----------|-----------|
|
||
|
|
| `GET /v1/item-master/pages` | GET | 🔴 필수 | ✅ 완전 신규 |
|
||
|
|
| `POST /v1/item-master/pages` | POST | 🔴 필수 | ✅ 완전 신규 |
|
||
|
|
| `PUT /v1/item-master/pages/{id}` | PUT | 🔴 필수 | ✅ 완전 신규 |
|
||
|
|
| `DELETE /v1/item-master/pages/{id}` | DELETE | 🔴 필수 | ✅ 완전 신규 |
|
||
|
|
|
||
|
|
#### 섹션 관리 API
|
||
|
|
|
||
|
|
| 엔드포인트 | 메서드 | 우선순위 | 신규 개발 |
|
||
|
|
|------------|--------|----------|-----------|
|
||
|
|
| `POST /v1/item-master/pages/{pageId}/sections` | POST | 🔴 필수 | ✅ 완전 신규 |
|
||
|
|
| `PUT /v1/item-master/sections/{id}` | PUT | 🔴 필수 | ✅ 완전 신규 |
|
||
|
|
| `DELETE /v1/item-master/sections/{id}` | DELETE | 🔴 필수 | ✅ 완전 신규 |
|
||
|
|
| `PUT /v1/item-master/pages/{pageId}/sections/reorder` | PUT | 🟡 중요 | ✅ 완전 신규 |
|
||
|
|
|
||
|
|
#### 필드 관리 API
|
||
|
|
|
||
|
|
| 엔드포인트 | 메서드 | 우선순위 | 신규 개발 |
|
||
|
|
|------------|--------|----------|-----------|
|
||
|
|
| `POST /v1/item-master/sections/{sectionId}/fields` | POST | 🔴 필수 | ✅ 완전 신규 |
|
||
|
|
| `PUT /v1/item-master/fields/{id}` | PUT | 🔴 필수 | ✅ 완전 신규 |
|
||
|
|
| `DELETE /v1/item-master/fields/{id}` | DELETE | 🔴 필수 | ✅ 완전 신규 |
|
||
|
|
| `PUT /v1/item-master/sections/{sectionId}/fields/reorder` | PUT | 🟡 중요 | ✅ 완전 신규 |
|
||
|
|
|
||
|
|
#### BOM 관리 API
|
||
|
|
|
||
|
|
| 엔드포인트 | 메서드 | 우선순위 | 신규 개발 |
|
||
|
|
|------------|--------|----------|-----------|
|
||
|
|
| `POST /v1/item-master/sections/{sectionId}/bom-items` | POST | 🟡 중요 | ✅ 완전 신규 |
|
||
|
|
| `PUT /v1/item-master/bom-items/{id}` | PUT | 🟡 중요 | ✅ 완전 신규 |
|
||
|
|
| `DELETE /v1/item-master/bom-items/{id}` | DELETE | 🟡 중요 | ✅ 완전 신규 |
|
||
|
|
|
||
|
|
#### 부가 기능 API
|
||
|
|
|
||
|
|
| 엔드포인트 | 메서드 | 우선순위 | 신규 개발 |
|
||
|
|
|------------|--------|----------|-----------|
|
||
|
|
| `GET/POST/PUT/DELETE /v1/item-master/section-templates` | ALL | 🟢 부가 | ✅ 완전 신규 |
|
||
|
|
| `GET/POST/PUT/DELETE /v1/item-master/master-fields` | ALL | 🟢 부가 | ✅ 완전 신규 |
|
||
|
|
| `GET/POST/PUT/DELETE /v1/item-master/custom-tabs` | ALL | 🟢 부가 | ✅ 완전 신규 |
|
||
|
|
| `PUT /v1/item-master/custom-tabs/{id}/columns` | PUT | 🟢 부가 | ✅ 완전 신규 |
|
||
|
|
| `GET/POST/DELETE /v1/item-master/units` | ALL | 🟡 중요 | ✅ 완전 신규 |
|
||
|
|
|
||
|
|
### 3. API 갭 요약
|
||
|
|
|
||
|
|
**총 요청 API**: 약 35개 엔드포인트
|
||
|
|
|
||
|
|
**재사용 가능**: 0개 (완전 신규 개발 필요)
|
||
|
|
|
||
|
|
**이유**:
|
||
|
|
1. 페이지-섹션-필드 구조는 기존 API에 없음
|
||
|
|
2. 메타 프로그래밍 수준의 동적 구조 미지원
|
||
|
|
3. 초기화 API처럼 Nested 데이터 로드 패턴 없음
|
||
|
|
4. 순서 변경(reorder) API 패턴 일부만 존재
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 구현 전략
|
||
|
|
|
||
|
|
### 1. 권장 접근 방식
|
||
|
|
|
||
|
|
**✅ 옵션 C: 병행 운영 (신구 공존)**
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────┐
|
||
|
|
│ 기존 시스템 (유지) │
|
||
|
|
│ - /v1/products/* │
|
||
|
|
│ - /v1/materials/* │
|
||
|
|
│ - /v1/categories/* │
|
||
|
|
└─────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
│ (어댑터 레이어)
|
||
|
|
│
|
||
|
|
┌─────────────────────────────────────┐
|
||
|
|
│ 신규 시스템 (추가) │
|
||
|
|
│ - /v1/item-master/* │
|
||
|
|
│ - 완전 동적 메타 구조 │
|
||
|
|
└─────────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
**장점**:
|
||
|
|
- ✅ 기존 API 영향 없음 (별도 네임스페이스)
|
||
|
|
- ✅ 점진적 마이그레이션 가능
|
||
|
|
- ✅ 롤백 가능한 구조
|
||
|
|
- ✅ 프론트 요구사항 완벽 충족
|
||
|
|
|
||
|
|
**단점**:
|
||
|
|
- ⚠️ 중복 데이터 관리 (단기적)
|
||
|
|
- ⚠️ 동기화 이슈 (선택적 연동)
|
||
|
|
|
||
|
|
### 2. SAM API Development Rules 준수
|
||
|
|
|
||
|
|
| 규칙 | 적용 방법 | 상태 |
|
||
|
|
|------|-----------|------|
|
||
|
|
| **Service-First** | 모든 비즈니스 로직 → Service 클래스 | ✅ 필수 |
|
||
|
|
| **Multi-tenant** | BelongsToTenant 스코프, tenant_id | ✅ 필수 |
|
||
|
|
| **Soft Delete** | deleted_at, deleted_by | ✅ 필수 |
|
||
|
|
| **공통 컬럼** | tenant_id, created_by, updated_by, deleted_by | ✅ 필수 |
|
||
|
|
| **FormRequest** | Controller 검증 금지 | ✅ 필수 |
|
||
|
|
| **i18n** | __('message.xxx') 키만 사용 | ✅ 필수 |
|
||
|
|
| **감사 로그** | audit_logs 기록 | ✅ 필수 |
|
||
|
|
| **Swagger** | app/Swagger/v1/ItemMasterApi.php | ✅ 필수 |
|
||
|
|
|
||
|
|
### 3. 아키텍처 구조
|
||
|
|
|
||
|
|
```
|
||
|
|
┌──────────────────────────────────────────────┐
|
||
|
|
│ Controller Layer │
|
||
|
|
│ - ItemPageController │
|
||
|
|
│ - ItemSectionController │
|
||
|
|
│ - ItemFieldController (FormRequest 검증) │
|
||
|
|
└───────────────┬──────────────────────────────┘
|
||
|
|
│
|
||
|
|
↓
|
||
|
|
┌──────────────────────────────────────────────┐
|
||
|
|
│ Service Layer │
|
||
|
|
│ - ItemPageService │
|
||
|
|
│ - ItemSectionService (비즈니스 로직) │
|
||
|
|
│ - ItemFieldService │
|
||
|
|
└───────────────┬──────────────────────────────┘
|
||
|
|
│
|
||
|
|
↓
|
||
|
|
┌──────────────────────────────────────────────┐
|
||
|
|
│ Model Layer │
|
||
|
|
│ - ItemPage (BelongsToTenant) │
|
||
|
|
│ - ItemSection (SoftDeletes) │
|
||
|
|
│ - ItemField (ModelTrait) │
|
||
|
|
└───────────────┬──────────────────────────────┘
|
||
|
|
│
|
||
|
|
↓
|
||
|
|
┌──────────────────────────────────────────────┐
|
||
|
|
│ Database Layer │
|
||
|
|
│ - item_pages (tenant_id, indexes) │
|
||
|
|
│ - item_sections │
|
||
|
|
│ - item_fields │
|
||
|
|
└──────────────────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 상세 구현 로드맵
|
||
|
|
|
||
|
|
### Week 1: DB 설계 및 마이그레이션 (5일)
|
||
|
|
|
||
|
|
#### Day 1-2: 마이그레이션 파일 작성
|
||
|
|
|
||
|
|
**순서** (의존성 고려):
|
||
|
|
```
|
||
|
|
1. unit_options
|
||
|
|
2. section_templates
|
||
|
|
3. item_master_fields
|
||
|
|
4. item_pages
|
||
|
|
5. item_sections
|
||
|
|
6. item_fields
|
||
|
|
7. item_bom_items
|
||
|
|
8. custom_tabs
|
||
|
|
9. tab_columns
|
||
|
|
```
|
||
|
|
|
||
|
|
**각 마이그레이션 포함 사항**:
|
||
|
|
- ✅ tenant_id BIGINT NOT NULL, INDEX
|
||
|
|
- ✅ created_by, updated_by, deleted_by
|
||
|
|
- ✅ created_at, updated_at, deleted_at
|
||
|
|
- ✅ FK constraints (tenants 테이블)
|
||
|
|
- ✅ 컬럼 COMMENT 작성
|
||
|
|
- ✅ INDEX 설정 (tenant_id, order_no 등)
|
||
|
|
|
||
|
|
#### Day 3-4: Model 클래스 작성
|
||
|
|
|
||
|
|
**app/Models/ItemMaster/** 디렉토리 생성
|
||
|
|
|
||
|
|
**각 모델 필수 요소**:
|
||
|
|
```php
|
||
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Models\ItemMaster;
|
||
|
|
|
||
|
|
use App\Traits\BelongsToTenant;
|
||
|
|
use App\Traits\ModelTrait;
|
||
|
|
use Illuminate\Database\Eloquent\Model;
|
||
|
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||
|
|
|
||
|
|
class ItemPage extends Model
|
||
|
|
{
|
||
|
|
use BelongsToTenant, ModelTrait, SoftDeletes;
|
||
|
|
|
||
|
|
protected $fillable = [
|
||
|
|
'tenant_id', 'page_name', 'item_type',
|
||
|
|
'absolute_path', 'is_active',
|
||
|
|
'created_by', 'updated_by', 'deleted_by',
|
||
|
|
];
|
||
|
|
|
||
|
|
protected $casts = [
|
||
|
|
'is_active' => 'boolean',
|
||
|
|
];
|
||
|
|
|
||
|
|
// Relationships
|
||
|
|
public function sections()
|
||
|
|
{
|
||
|
|
return $this->hasMany(ItemSection::class, 'page_id')
|
||
|
|
->orderBy('order_no');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Day 5: 테스트 데이터 시드 작성
|
||
|
|
|
||
|
|
**database/seeders/ItemMasterSeeder.php**
|
||
|
|
|
||
|
|
- 샘플 페이지 (FG, PT, SM, RM, CS)
|
||
|
|
- 샘플 섹션 (기본 정보, 치수 정보, BOM)
|
||
|
|
- 샘플 필드 (제품명, 규격, 수량 등)
|
||
|
|
- 샘플 템플릿
|
||
|
|
- 샘플 단위 (kg, EA, m 등)
|
||
|
|
|
||
|
|
### Week 2-3: Core API 개발 (10일)
|
||
|
|
|
||
|
|
#### 우선순위 1: 필수 API (6일)
|
||
|
|
|
||
|
|
**Day 1: 초기화 API**
|
||
|
|
|
||
|
|
**파일 생성**:
|
||
|
|
- `app/Services/ItemMaster/ItemMasterService.php`
|
||
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/ItemMasterController.php`
|
||
|
|
|
||
|
|
**구현 내용**:
|
||
|
|
```php
|
||
|
|
// ItemMasterService.php
|
||
|
|
public function init(): array
|
||
|
|
{
|
||
|
|
$pages = ItemPage::with([
|
||
|
|
'sections.fields',
|
||
|
|
'sections.bomItems'
|
||
|
|
])
|
||
|
|
->where('tenant_id', $this->tenantId())
|
||
|
|
->where('is_active', true)
|
||
|
|
->orderBy('id')
|
||
|
|
->get();
|
||
|
|
|
||
|
|
$templates = SectionTemplate::where('tenant_id', $this->tenantId())->get();
|
||
|
|
$masterFields = ItemMasterField::where('tenant_id', $this->tenantId())->get();
|
||
|
|
$customTabs = CustomTab::where('tenant_id', $this->tenantId())->orderBy('order_no')->get();
|
||
|
|
$unitOptions = UnitOption::where('tenant_id', $this->tenantId())->get();
|
||
|
|
|
||
|
|
return [
|
||
|
|
'pages' => $pages,
|
||
|
|
'sectionTemplates' => $templates,
|
||
|
|
'masterFields' => $masterFields,
|
||
|
|
'customTabs' => $customTabs,
|
||
|
|
'unitOptions' => $unitOptions,
|
||
|
|
];
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Day 2-3: 페이지 CRUD**
|
||
|
|
|
||
|
|
**파일 생성**:
|
||
|
|
- `app/Services/ItemMaster/ItemPageService.php`
|
||
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/ItemPageController.php`
|
||
|
|
- `app/Http/Requests/ItemMaster/ItemPageStoreRequest.php`
|
||
|
|
- `app/Http/Requests/ItemMaster/ItemPageUpdateRequest.php`
|
||
|
|
|
||
|
|
**구현 메서드**:
|
||
|
|
- `index()` - 목록 조회 (with sections, fields)
|
||
|
|
- `store()` - 페이지 생성
|
||
|
|
- `show()` - 단건 조회
|
||
|
|
- `update()` - 수정
|
||
|
|
- `destroy()` - Soft Delete (Cascade)
|
||
|
|
|
||
|
|
**Day 4-5: 섹션 CRUD**
|
||
|
|
|
||
|
|
**파일 생성**:
|
||
|
|
- `app/Services/ItemMaster/ItemSectionService.php`
|
||
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/ItemSectionController.php`
|
||
|
|
- `app/Http/Requests/ItemMaster/ItemSectionStoreRequest.php`
|
||
|
|
- `app/Http/Requests/ItemMaster/ItemSectionUpdateRequest.php`
|
||
|
|
|
||
|
|
**특수 로직**:
|
||
|
|
- `order_no` 자동 계산 (해당 페이지의 마지막 섹션 + 1)
|
||
|
|
- `reorder()` 메서드 (순서 일괄 변경)
|
||
|
|
|
||
|
|
**Day 6: 필드 CRUD**
|
||
|
|
|
||
|
|
**파일 생성**:
|
||
|
|
- `app/Services/ItemMaster/ItemFieldService.php`
|
||
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/ItemFieldController.php`
|
||
|
|
- `app/Http/Requests/ItemMaster/ItemFieldStoreRequest.php`
|
||
|
|
- `app/Http/Requests/ItemMaster/ItemFieldUpdateRequest.php`
|
||
|
|
|
||
|
|
**JSON 필드 처리**:
|
||
|
|
- `display_condition` JSON 검증
|
||
|
|
- `validation_rules` JSON 검증
|
||
|
|
- `options` JSON 검증
|
||
|
|
- `properties` JSON 검증
|
||
|
|
|
||
|
|
#### 우선순위 2: 중요 API (4일)
|
||
|
|
|
||
|
|
**Day 7: BOM 관리**
|
||
|
|
|
||
|
|
**파일 생성**:
|
||
|
|
- `app/Services/ItemMaster/ItemBomService.php`
|
||
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/ItemBomItemController.php`
|
||
|
|
- `app/Http/Requests/ItemMaster/ItemBomStoreRequest.php`
|
||
|
|
- `app/Http/Requests/ItemMaster/ItemBomUpdateRequest.php`
|
||
|
|
|
||
|
|
**Day 8: 순서 변경 API**
|
||
|
|
|
||
|
|
**구현**:
|
||
|
|
- 섹션 순서 변경 (`ItemSectionService::reorder()`)
|
||
|
|
- 필드 순서 변경 (`ItemFieldService::reorder()`)
|
||
|
|
- 트랜잭션 처리 필수
|
||
|
|
|
||
|
|
**Day 9: 단위 관리**
|
||
|
|
|
||
|
|
**파일 생성**:
|
||
|
|
- `app/Services/ItemMaster/UnitOptionService.php`
|
||
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/UnitOptionController.php`
|
||
|
|
- `app/Http/Requests/ItemMaster/UnitOptionStoreRequest.php`
|
||
|
|
|
||
|
|
**Day 10: 통합 테스트**
|
||
|
|
|
||
|
|
- Postman Collection 작성
|
||
|
|
- 우선순위 1+2 API 전체 테스트
|
||
|
|
- 버그 수정
|
||
|
|
|
||
|
|
### Week 4: 부가 기능 (5일)
|
||
|
|
|
||
|
|
#### Day 1-2: 템플릿 관리
|
||
|
|
|
||
|
|
**파일 생성**:
|
||
|
|
- `app/Services/ItemMaster/SectionTemplateService.php`
|
||
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/SectionTemplateController.php`
|
||
|
|
- FormRequest 클래스
|
||
|
|
|
||
|
|
#### Day 3: 마스터 필드 관리
|
||
|
|
|
||
|
|
**파일 생성**:
|
||
|
|
- `app/Services/ItemMaster/ItemMasterFieldService.php`
|
||
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/ItemMasterFieldController.php`
|
||
|
|
- FormRequest 클래스
|
||
|
|
|
||
|
|
#### Day 4-5: 커스텀 탭 관리
|
||
|
|
|
||
|
|
**파일 생성**:
|
||
|
|
- `app/Services/ItemMaster/CustomTabService.php`
|
||
|
|
- `app/Http/Controllers/Api/V1/ItemMaster/CustomTabController.php`
|
||
|
|
- `app/Http/Requests/ItemMaster/TabColumnUpdateRequest.php`
|
||
|
|
|
||
|
|
**특수 기능**:
|
||
|
|
- 탭 순서 변경 (`reorder()`)
|
||
|
|
- 컬럼 설정 (`updateColumns()`)
|
||
|
|
|
||
|
|
### Week 5: 문서화 및 테스트 (5일)
|
||
|
|
|
||
|
|
#### Day 1-2: Swagger 문서화
|
||
|
|
|
||
|
|
**파일 생성**: `app/Swagger/v1/ItemMasterApi.php`
|
||
|
|
|
||
|
|
**포함 내용**:
|
||
|
|
```php
|
||
|
|
<?php
|
||
|
|
namespace App\Swagger\v1;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @OA\Tag(
|
||
|
|
* name="ItemMaster",
|
||
|
|
* description="품목 기준 관리 API"
|
||
|
|
* )
|
||
|
|
*
|
||
|
|
* @OA\Schema(
|
||
|
|
* schema="ItemPage",
|
||
|
|
* type="object",
|
||
|
|
* required={"page_name", "item_type"},
|
||
|
|
* @OA\Property(property="id", type="integer"),
|
||
|
|
* @OA\Property(property="page_name", type="string"),
|
||
|
|
* @OA\Property(property="item_type", type="string", enum={"FG", "PT", "SM", "RM", "CS"}),
|
||
|
|
* ...
|
||
|
|
* )
|
||
|
|
*/
|
||
|
|
class ItemMasterApi
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* @OA\Get(
|
||
|
|
* path="/api/v1/item-master/init",
|
||
|
|
* tags={"ItemMaster"},
|
||
|
|
* summary="초기화 API",
|
||
|
|
* description="화면 진입 시 전체 데이터 로드",
|
||
|
|
* security={{"BearerAuth": {}}},
|
||
|
|
* @OA\Response(
|
||
|
|
* response=200,
|
||
|
|
* description="성공",
|
||
|
|
* @OA\JsonContent(
|
||
|
|
* @OA\Property(property="success", type="boolean", example=true),
|
||
|
|
* @OA\Property(property="message", type="string", example="message.fetched"),
|
||
|
|
* @OA\Property(property="data", type="object",
|
||
|
|
* @OA\Property(property="pages", type="array", @OA\Items(ref="#/components/schemas/ItemPage")),
|
||
|
|
* @OA\Property(property="sectionTemplates", type="array", @OA\Items(ref="#/components/schemas/SectionTemplate")),
|
||
|
|
* ...
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
* )
|
||
|
|
*/
|
||
|
|
public function init() {}
|
||
|
|
|
||
|
|
// ... 나머지 엔드포인트
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Swagger 생성**:
|
||
|
|
```bash
|
||
|
|
php artisan l5-swagger:generate
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Day 3: 단위 테스트 작성
|
||
|
|
|
||
|
|
**tests/Unit/Services/ItemMaster/**
|
||
|
|
- `ItemPageServiceTest.php`
|
||
|
|
- `ItemSectionServiceTest.php`
|
||
|
|
- `ItemFieldServiceTest.php`
|
||
|
|
|
||
|
|
**커버리지 목표**: 80% 이상
|
||
|
|
|
||
|
|
#### Day 4: 통합 테스트
|
||
|
|
|
||
|
|
**tests/Feature/ItemMaster/**
|
||
|
|
- `ItemMasterInitTest.php`
|
||
|
|
- `ItemPageCrudTest.php`
|
||
|
|
- `ItemSectionCrudTest.php`
|
||
|
|
|
||
|
|
#### Day 5: 성능 최적화
|
||
|
|
|
||
|
|
**Eager Loading 최적화**:
|
||
|
|
```php
|
||
|
|
ItemPage::with([
|
||
|
|
'sections' => function ($query) {
|
||
|
|
$query->orderBy('order_no');
|
||
|
|
},
|
||
|
|
'sections.fields' => function ($query) {
|
||
|
|
$query->orderBy('order_no');
|
||
|
|
},
|
||
|
|
'sections.bomItems'
|
||
|
|
])->get();
|
||
|
|
```
|
||
|
|
|
||
|
|
**INDEX 확인**:
|
||
|
|
- `tenant_id` INDEX
|
||
|
|
- `(page_id, order_no)` COMPOSITE INDEX
|
||
|
|
- `(section_id, order_no)` COMPOSITE INDEX
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 리스크 및 대응 방안
|
||
|
|
|
||
|
|
### 1. 기술적 리스크
|
||
|
|
|
||
|
|
| 리스크 | 영향도 | 대응 방안 |
|
||
|
|
|--------|--------|-----------|
|
||
|
|
| **Nested 데이터 성능 이슈** | 🟡 중간 | Eager Loading, INDEX 최적화, 페이지네이션 |
|
||
|
|
| **JSON 필드 검증 복잡도** | 🟡 중간 | FormRequest 규칙 체계화, JSON Schema 활용 |
|
||
|
|
| **Cascade 삭제 오류** | 🔴 높음 | 트랜잭션 처리, 테스트 케이스 강화 |
|
||
|
|
| **순서 변경 동시성 이슈** | 🟡 중간 | Lock 메커니즘, 트랜잭션 격리 수준 상향 |
|
||
|
|
|
||
|
|
### 2. 일정 리스크
|
||
|
|
|
||
|
|
| 리스크 | 영향도 | 대응 방안 |
|
||
|
|
|--------|--------|-----------|
|
||
|
|
| **API 개발 지연** | 🟡 중간 | 우선순위별 단계 개발, 최소 기능 먼저 완성 |
|
||
|
|
| **프론트 연동 지연** | 🟢 낮음 | Swagger 문서 먼저 제공, Mock API 활용 |
|
||
|
|
| **버그 수정 시간 부족** | 🟡 중간 | Week 5 버퍼 시간 활용 |
|
||
|
|
|
||
|
|
### 3. 데이터 리스크
|
||
|
|
|
||
|
|
| 리스크 | 영향도 | 대응 방안 |
|
||
|
|
|--------|--------|-----------|
|
||
|
|
| **기존 데이터 마이그레이션** | 🟢 낮음 | 선택적 마이그레이션 (필요시) |
|
||
|
|
| **중복 데이터 동기화** | 🟢 낮음 | 초기에는 병행 운영, 추후 통합 고려 |
|
||
|
|
|
||
|
|
### 4. 운영 리스크
|
||
|
|
|
||
|
|
| 리스크 | 영향도 | 대응 방안 |
|
||
|
|
|--------|--------|-----------|
|
||
|
|
| **API 버전 관리** | 🟢 낮음 | v1 네임스페이스 유지 |
|
||
|
|
| **감사 로그 볼륨 증가** | 🟡 중간 | 13개월 자동 정리, 아카이빙 전략 |
|
||
|
|
| **Swagger 문서 유지보수** | 🟢 낮음 | 별도 파일 관리, 자동 생성 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 부록
|
||
|
|
|
||
|
|
### A. 파일 구조
|
||
|
|
|
||
|
|
```
|
||
|
|
api/
|
||
|
|
├── app/
|
||
|
|
│ ├── Models/
|
||
|
|
│ │ └── ItemMaster/
|
||
|
|
│ │ ├── ItemPage.php
|
||
|
|
│ │ ├── ItemSection.php
|
||
|
|
│ │ ├── ItemField.php
|
||
|
|
│ │ ├── ItemBomItem.php
|
||
|
|
│ │ ├── SectionTemplate.php
|
||
|
|
│ │ ├── ItemMasterField.php
|
||
|
|
│ │ ├── CustomTab.php
|
||
|
|
│ │ ├── TabColumn.php
|
||
|
|
│ │ └── UnitOption.php
|
||
|
|
│ ├── Services/
|
||
|
|
│ │ └── ItemMaster/
|
||
|
|
│ │ ├── ItemMasterService.php
|
||
|
|
│ │ ├── ItemPageService.php
|
||
|
|
│ │ ├── ItemSectionService.php
|
||
|
|
│ │ ├── ItemFieldService.php
|
||
|
|
│ │ ├── ItemBomService.php
|
||
|
|
│ │ ├── SectionTemplateService.php
|
||
|
|
│ │ ├── ItemMasterFieldService.php
|
||
|
|
│ │ ├── CustomTabService.php
|
||
|
|
│ │ └── UnitOptionService.php
|
||
|
|
│ ├── Http/
|
||
|
|
│ │ ├── Controllers/
|
||
|
|
│ │ │ └── Api/
|
||
|
|
│ │ │ └── V1/
|
||
|
|
│ │ │ └── ItemMaster/
|
||
|
|
│ │ │ ├── ItemMasterController.php
|
||
|
|
│ │ │ ├── ItemPageController.php
|
||
|
|
│ │ │ ├── ItemSectionController.php
|
||
|
|
│ │ │ ├── ItemFieldController.php
|
||
|
|
│ │ │ ├── ItemBomItemController.php
|
||
|
|
│ │ │ ├── SectionTemplateController.php
|
||
|
|
│ │ │ ├── ItemMasterFieldController.php
|
||
|
|
│ │ │ ├── CustomTabController.php
|
||
|
|
│ │ │ └── UnitOptionController.php
|
||
|
|
│ │ └── Requests/
|
||
|
|
│ │ └── ItemMaster/
|
||
|
|
│ │ ├── ItemPageStoreRequest.php
|
||
|
|
│ │ ├── ItemPageUpdateRequest.php
|
||
|
|
│ │ ├── ItemSectionStoreRequest.php
|
||
|
|
│ │ ├── ItemSectionUpdateRequest.php
|
||
|
|
│ │ ├── ItemFieldStoreRequest.php
|
||
|
|
│ │ ├── ItemFieldUpdateRequest.php
|
||
|
|
│ │ ├── ItemBomStoreRequest.php
|
||
|
|
│ │ ├── ItemBomUpdateRequest.php
|
||
|
|
│ │ ├── SectionTemplateStoreRequest.php
|
||
|
|
│ │ ├── ItemMasterFieldStoreRequest.php
|
||
|
|
│ │ ├── CustomTabStoreRequest.php
|
||
|
|
│ │ ├── TabColumnUpdateRequest.php
|
||
|
|
│ │ └── UnitOptionStoreRequest.php
|
||
|
|
│ └── Swagger/
|
||
|
|
│ └── v1/
|
||
|
|
│ └── ItemMasterApi.php
|
||
|
|
├── database/
|
||
|
|
│ ├── migrations/
|
||
|
|
│ │ ├── 2025_11_20_100000_create_unit_options_table.php
|
||
|
|
│ │ ├── 2025_11_20_100001_create_section_templates_table.php
|
||
|
|
│ │ ├── 2025_11_20_100002_create_item_master_fields_table.php
|
||
|
|
│ │ ├── 2025_11_20_100003_create_item_pages_table.php
|
||
|
|
│ │ ├── 2025_11_20_100004_create_item_sections_table.php
|
||
|
|
│ │ ├── 2025_11_20_100005_create_item_fields_table.php
|
||
|
|
│ │ ├── 2025_11_20_100006_create_item_bom_items_table.php
|
||
|
|
│ │ ├── 2025_11_20_100007_create_custom_tabs_table.php
|
||
|
|
│ │ └── 2025_11_20_100008_create_tab_columns_table.php
|
||
|
|
│ └── seeders/
|
||
|
|
│ └── ItemMasterSeeder.php
|
||
|
|
└── tests/
|
||
|
|
├── Unit/
|
||
|
|
│ └── Services/
|
||
|
|
│ └── ItemMaster/
|
||
|
|
│ ├── ItemPageServiceTest.php
|
||
|
|
│ ├── ItemSectionServiceTest.php
|
||
|
|
│ └── ItemFieldServiceTest.php
|
||
|
|
└── Feature/
|
||
|
|
└── ItemMaster/
|
||
|
|
├── ItemMasterInitTest.php
|
||
|
|
├── ItemPageCrudTest.php
|
||
|
|
└── ItemSectionCrudTest.php
|
||
|
|
```
|
||
|
|
|
||
|
|
### B. i18n 메시지 키
|
||
|
|
|
||
|
|
**lang/ko/message.php 추가**:
|
||
|
|
```php
|
||
|
|
return [
|
||
|
|
// 기존 키...
|
||
|
|
|
||
|
|
// 품목 마스터
|
||
|
|
'item_master' => [
|
||
|
|
'fetched' => '품목 기준 정보가 조회되었습니다.',
|
||
|
|
'page_created' => '페이지가 생성되었습니다.',
|
||
|
|
'page_updated' => '페이지가 수정되었습니다.',
|
||
|
|
'page_deleted' => '페이지가 삭제되었습니다.',
|
||
|
|
'section_created' => '섹션이 생성되었습니다.',
|
||
|
|
'section_updated' => '섹션이 수정되었습니다.',
|
||
|
|
'section_deleted' => '섹션이 삭제되었습니다.',
|
||
|
|
'section_reordered' => '섹션 순서가 변경되었습니다.',
|
||
|
|
'field_created' => '필드가 생성되었습니다.',
|
||
|
|
'field_updated' => '필드가 수정되었습니다.',
|
||
|
|
'field_deleted' => '필드가 삭제되었습니다.',
|
||
|
|
'field_reordered' => '필드 순서가 변경되었습니다.',
|
||
|
|
'bom_created' => 'BOM 항목이 생성되었습니다.',
|
||
|
|
'bom_updated' => 'BOM 항목이 수정되었습니다.',
|
||
|
|
'bom_deleted' => 'BOM 항목이 삭제되었습니다.',
|
||
|
|
'template_created' => '템플릿이 생성되었습니다.',
|
||
|
|
'unit_created' => '단위가 생성되었습니다.',
|
||
|
|
'unit_deleted' => '단위가 삭제되었습니다.',
|
||
|
|
'tab_created' => '탭이 생성되었습니다.',
|
||
|
|
'tab_updated' => '탭이 수정되었습니다.',
|
||
|
|
'tab_deleted' => '탭이 삭제되었습니다.',
|
||
|
|
'tab_reordered' => '탭 순서가 변경되었습니다.',
|
||
|
|
'columns_updated' => '컬럼 설정이 업데이트되었습니다.',
|
||
|
|
],
|
||
|
|
];
|
||
|
|
```
|
||
|
|
|
||
|
|
### C. 체크리스트
|
||
|
|
|
||
|
|
**개발 완료 전 확인사항**:
|
||
|
|
|
||
|
|
```
|
||
|
|
□ Service-First 패턴 적용 (Controller는 DI + Service 호출만)
|
||
|
|
□ BelongsToTenant scope 모든 모델에 적용
|
||
|
|
□ SoftDeletes 모든 모델에 적용
|
||
|
|
□ 공통 컬럼 (tenant_id, created_by, updated_by, deleted_by) 포함
|
||
|
|
□ 감사 로그 생성/수정/삭제 시 기록
|
||
|
|
□ i18n 메시지 키 사용 (__('message.item_master.xxx'))
|
||
|
|
□ FormRequest 검증
|
||
|
|
□ Swagger 문서화 (app/Swagger/v1/ItemMasterApi.php)
|
||
|
|
□ Cascade 삭제 정책 적용
|
||
|
|
□ Nested 조회 최적화 (Eager Loading)
|
||
|
|
□ order_no 자동 계산 로직
|
||
|
|
□ 실시간 저장 지원 (일괄 저장 없음)
|
||
|
|
□ JSON 필드 검증 (display_condition, validation_rules, options, properties)
|
||
|
|
□ INDEX 최적화 (tenant_id, order_no 등)
|
||
|
|
□ 트랜잭션 처리 (reorder, cascade delete)
|
||
|
|
□ 단위 테스트 80% 이상
|
||
|
|
□ 통합 테스트 주요 플로우 커버
|
||
|
|
□ Postman Collection 작성
|
||
|
|
□ 프론트 연동 테스트 완료
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 결론
|
||
|
|
|
||
|
|
**✅ 프론트 요구사항 수용 → 신규 시스템 구축 권장**
|
||
|
|
|
||
|
|
**예상 기간**: 4-5주
|
||
|
|
**예상 리소스**: 백엔드 개발자 1명 (풀타임)
|
||
|
|
**리스크 수준**: 🟡 중간 (관리 가능)
|
||
|
|
|
||
|
|
**다음 단계**:
|
||
|
|
1. ✅ 분석 보고서 검토 및 승인
|
||
|
|
2. 📋 Week 1 마이그레이션 작업 시작
|
||
|
|
3. 🔧 Core API 개발 착수
|
||
|
|
|
||
|
|
**문의 사항**:
|
||
|
|
- 백엔드 개발팀: [연락처]
|
||
|
|
- 프론트엔드 개발팀: [연락처]
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**문서 버전**: v1.0
|
||
|
|
**작성일**: 2025-11-20
|
||
|
|
**다음 리뷰 예정일**: DB 마이그레이션 완료 후
|