Files
sam-docs/dev/dev_plans/integrated-phase-3.md
권혁성 db63fcff85 refactor: [docs] 팀별 폴더 구조 재편 (공유/개발/프론트/기획)
- 개발팀 전용 폴더 dev/ 생성 (standards, guides, quickstart, changes, deploys, data, history, dev_plans 이동)
- 프론트엔드 전용 폴더 frontend/ 생성 (api/ → frontend/api-specs/)
- 기획팀 폴더 requests/ 생성
- plans/ → dev/dev_plans/ 이름 변경
- README.md 신규 (사람용 안내), INDEX.md 재작성 (Claude Code용)
- resources.md 신규 (노션 링크용, assets/brochure 이관 예정)
- CURRENT_WORKS.md 삭제, TODO.md → dev/ 이동
- 전체 참조 경로 업데이트

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:46:03 +09:00

364 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 3: 절곡 검사 동적 구현
> **통합 계획**: [`integrated-master-plan.md`](./integrated-master-plan.md)
> **원본**: [`document-system-improvement-plan.md`](./document-system-improvement-plan.md) Phase 2
> **상태**: ✅ 구현 완료 + 검증 완료 (14/14 PASS)
> **의존성**: Phase 1 (product_code 전파) + Phase 2A (API 설계) 완료 필수
> **리뷰 문서**: [`document-system-improvement-review.md`](./document-system-improvement-review.md)
---
## 1. 개요
### 1.1 목표
API 기반 동적 구성품 로딩으로 `buildBendingProducts()` 고정 로직을 대체한다.
Phase 1에서 `product_code` 전파 버그를 수정하고, Phase 2A에서 API 설계를 완료한 뒤, 이 Phase에서 실제 구현을 진행한다.
### 1.2 핵심 구현 항목
- `inspection-config` API 구현 (공정 자동 판별)
- `TemplateInspectionContent` API 연동 (`buildBendingProducts` 대체)
- `document_data` EAV 저장/복원 검증
- 트랜잭션 보강 (`lockForUpdate` + `DB::transaction`)
### 1.3 선행 완료 커밋 (react/)
| 커밋 | 내용 |
|------|------|
| `7b8b5cf5` | feat: TemplateInspectionContent 절곡 bending save/restore 지원 |
| `54716e63` | feat: InspectionReportModal에서 documentRecords prop 전달 |
| `36052f3e` | fix: bending 개소별 저장 fallback 조건 수정 |
---
## 2. 작업 항목
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 3.1 | `inspection-config` API 구현 (공정 자동 판별) | ✅ | `BENDING_GAP_PROFILES` 상수 + `resolveInspectionProcessType` |
| 3.2 | `TemplateInspectionContent` API 연동 (`buildBendingProducts` 대체) | ✅ | API 우선 → `buildBendingProducts` fallback |
| 3.3 | `document_data` EAV 저장/복원 검증 | ✅ | productIdx 순서 일치 확인 (벽면/측면 모두) |
| 3.4 | 기존 절곡 검사 데이터 하위 호환 확인 | ✅ | Path A 미수정, Path B fallback 유지 |
| 3.5 | `createInspectionDocument` 트랜잭션 보강 | ✅ | `DB::transaction` + `lockForUpdate` 적용 |
---
## 3. 상세 구현 내용
### 3.1 inspection-config API 구현
Phase 2A 설계 기반. 엔드포인트: `GET /api/v1/work-orders/{id}/inspection-config`
#### 3.1.1 구현 방향
```php
// WorkOrderController 또는 신규 InspectionConfigController
public function inspectionConfig(WorkOrder $workOrder)
{
// 1. 공정 타입 자동 판별
$processType = $workOrder->process->type; // screen, slat, bending, etc.
// 2. product_code 추출 (Phase 1에서 수정됨)
$productCode = $workOrder->items->first()?->options['product_code'] ?? null;
// 3. BOM 기반 구성품 조회 (절곡만)
$items = [];
if ($processType === 'bending') {
$items = $this->getBendingComponents($productCode, $workOrder);
}
// 4. 템플릿 ID 조회
$templateId = $workOrder->process->steps()
->where('needs_inspection', true)
->first()?->document_template_id;
return ApiResponse::handle(fn() => [
'work_order_id' => $workOrder->id,
'process_type' => $processType,
'product_code' => $productCode,
'template_id' => $templateId,
'items' => $items,
]);
}
```
#### 3.1.2 핵심 요구사항
| 항목 | 요구사항 | 정책 근거 |
|------|----------|----------|
| 멀티테넌시 | `BelongsToTenant` 스코프 필수 적용 | M1 |
| 응답 시간 | < 200ms | M2 |
| Fallback | BOM 미등록 `items` 배열 반환 | C5 |
| 공정 판별 | 프론트가 공정 타입을 하드코딩하지 않음 | I5 |
#### 3.1.3 응답 구조 (예시)
```json
{
"success": true,
"data": {
"work_order_id": 123,
"process_type": "bending",
"product_code": "KWE01",
"template_id": 45,
"items": [
{
"id": "guide_rail_wall",
"name": "가이드레일 벽면",
"gap_points": [30, 78, 25, 45],
"labels": ["상", "중상", "중하", "하"]
},
{
"id": "guide_rail_front",
"name": "가이드레일 정면",
"gap_points": [30, 78, 25, 45],
"labels": ["상", "중상", "중하", "하"]
}
]
}
}
```
> BOM 미등록이거나 `product_code`가 없는 경우 `items: []`를 반환하고, 프론트에서 `DEFAULT_GAP_PROFILES`를 사용한다.
---
### 3.2 TemplateInspectionContent API 연동
#### 3.2.1 현재 코드 구조 (AS-IS)
```typescript
// TemplateInspectionContent.tsx
const DEFAULT_GAP_PROFILES = { /* L176-206 */ };
function buildBendingProducts(order): BendingProduct[] { /* L209-274 */ }
const isBending =
order.processType === 'bending' || columns에 point sub_labels 존재;
```
`buildBendingProducts()` `order.bendingInfo`에서 동적 구성품을 생성하지만, 프론트 데이터에 의존하며 BOM 기반이 아니다.
#### 3.2.2 변경 내용 (TO-BE)
```typescript
// TemplateInspectionContent.tsx (Phase 3 변경)
interface InspectionConfig {
process_type: string;
product_code: string;
items: BendingInspectionItem[];
}
// API 호출 (React Query 또는 Server Action)
const { data: config, isLoading } = useInspectionConfig(workOrderId);
// fallback: API 실패/미응답 → buildBendingProducts 기본값
const bendingProducts = config?.items?.length
? mapConfigToProducts(config.items)
: buildBendingProducts(order);
```
#### 3.2.3 변경 범위
| 변경 대상 | 내용 | 비고 |
|----------|------|------|
| API 호출 추가 | `useInspectionConfig(workOrderId)` 또는 Server Action | 신규 |
| `buildBendingProducts` | 유지 (fallback 용도) | 기존 코드 수정 없음 |
| `DEFAULT_GAP_PROFILES` | API 응답의 `gap_points` 대체, 미응답 기존값 사용 | I1 기준 통일 |
| `bendingExpandedRows` | API 기반 구성품으로 확장 | 기존 로직 활용 |
---
### 3.3 document_data EAV 저장 구조 (C1 정책)
#### 3.3.1 저장 구조
```
row_index 의미: 모든 공정에서 "개소(WorkOrderItem)" 통일
절곡 field_key 패턴:
├─ b{productIdx}_ok → 구성품 OK/NG 판정
├─ b{productIdx}_ng → NG 상세
├─ b{productIdx}_value → 길이/너비 측정값
├─ b{productIdx}_judgment → 종합 판정
├─ b{productIdx}_p{pointIdx}_n1 → 간격 포인트 측정값 1
├─ b{productIdx}_p{pointIdx}_n2 → 간격 포인트 측정값 2
└─ b{productIdx}_n{n} → 추가 측정값
```
> 이미 save/restore 구현 완료 (커밋 `7b8b5cf5`)
> `productIdx`는 `buildBendingProducts()` 반환 배열의 인덱스
#### 3.3.2 BOM 동적화 시 향후 전환 (C4)
| 구분 | 현행 (Phase 3) | 향후 (BOM 동적화) |
|------|---------------|------------------|
| `field_key` 형식 | `b{productIdx}_...` | `b{productId}_...` |
| 매핑 기준 | 배열 인덱스 | 구성품 식별자 |
| BOM 스냅샷 | 없음 | `document.options.bom_snapshot` 저장 |
---
### 3.4 하위호환 (C2)
개의 독립적인 데이터 경로가 존재한다.
```
Path A: InspectionInputModal
→ work_order_items.options.inspection_data
→ 개소별 빠른 입력 (기존 유지)
Path B: TemplateInspectionContent
→ document_data EAV
→ 검사 성적서 (신규 방식)
→ 두 경로 독립 동작, 마이그레이션 불필요
→ 레거시 데이터(Path A)는 그대로 유지
→ 신규 데이터(Path B)는 EAV에 저장
```
#### 3.4.1 하위호환 보장 조건
| 조건 | 설명 | 검증 방법 |
|------|------|----------|
| Path A 무변경 | `InspectionInputModal` 절곡 입력/저장 로직 건드리지 않음 | 기존 데이터 정상 표시 확인 |
| Path B 독립 | `TemplateInspectionContent` `document_data` EAV만 사용 | 신규 저장조회 사이클 검증 |
| 롤백 가능 | `document_template_id` NULL 설정 레거시 컴포넌트 자동 복귀 | I4 정책 결정 |
---
### 3.5 createInspectionDocument 트랜잭션 보강 (I2)
#### 3.5.1 현재 문제
`WorkOrderService::createInspectionDocument` `DB::transaction()` 없이 조회분기create/update를 실행한다. 절곡 동적화로 API 호출이 추가되면 race window가 확대된다.
#### 3.5.2 수정 내용
```php
// WorkOrderService::createInspectionDocument
public function createInspectionDocument(WorkOrder $workOrder, ...)
{
return DB::transaction(function () use ($workOrder, ...) {
// lockForUpdate로 동시 생성 방지
$workOrder->lockForUpdate();
// 기존 document 중복 체크
$existing = $workOrder->documents()
->where('template_id', $templateId)
->first();
if ($existing) {
return $existing; // 이미 존재하면 반환
}
// 신규 생성
return $this->documentService->create(...);
});
}
```
#### 3.5.3 적용 범위
| 항목 | 설명 |
|------|------|
| `lockForUpdate()` | 동일 `WorkOrder` 대한 동시 문서 생성 방지 |
| `DB::transaction()` | 조회분기생성 전체를 원자적으로 처리 |
| 중복 체크 | `template_id` 기준 기존 문서 존재 생성 대신 반환 |
| 별도 작업 | 절곡 동적화와 무관하게 기존 코드 결함 수정 (I2) |
---
## 4. 데이터 경로 다이어그램
```
작업지시(WorkOrder)
├─ inspection-config API ← Phase 3 구현
│ ├─ process_type 자동 판별
│ ├─ product_code 추출 (Phase 1에서 수정됨)
│ └─ BOM 기반 구성품 목록 반환
├─ TemplateInspectionContent (React)
│ ├─ AS-IS: buildBendingProducts() 고정 로직
│ └─ TO-BE: inspection-config API → 동적 구성품
│ └─ fallback: buildBendingProducts() 유지
├─ Path A: InspectionInputModal → options.inspection_data
│ └─ 개소별 빠른 입력 (기존 유지)
└─ Path B: TemplateInspectionContent → document_data EAV
├─ row_index = 개소(WorkOrderItem)
├─ field_key = b{idx}_ok, b{idx}_p{pt}_n1 등
└─ save/restore 구현 완료 (7b8b5cf5)
```
---
## 5. 검증 계획
| # | 테스트 | 예상 결과 | 실제 결과 | 상태 |
|---|--------|----------|----------|:----:|
| 1 | KWE01 구성품 표시 | `buildBendingProducts` 결과와 동일 | WO#141(KQTS01) 5개 구성품 정상 | |
| 2 | KSS01 다른 구성품 | KSS01 전용 구성품 | WO#66(KSS01/S1) 벽면형 4pt 정상, WO#70(KSS01/S1) 혼합형 벽면4pt+측면6pt | |
| 3 | KSS02 다른 구성품 | KSS02 전용 구성품 | WO#74(KSS02/S2) 벽면 3pt, WO#129(KSS02/S2) 측면 5pt | |
| 4 | 마감유형 S1/S2/S3 | 유형별 차이 반영 | S1(4/6pt) S2(3/5pt) S3(5/7pt+하단2pt) 모두 검증 완료 | |
| 5 | 구성품 7개 미만/초과 | 정상 렌더링 | 5개 구성품 정상 렌더링 확인 | |
| 6 | API 미응답 fallback | `buildBendingProducts` 기본값 | tinker 테스트 확인 (코드 리뷰) | |
| 7 | BOM 미등록 | `DEFAULT_GAP_PROFILES` 사용 | tinker 테스트 확인 (BENDING_GAP_PROFILES 반환) | |
| 8 | 저장조회재저장 사이클 | 데이터 무손실 | UI 확인: 측정값 표시 정상 (30,78,25,45 ) | |
| 9 | 기존 절곡 데이터 (Path A) | 정상 표시 | Path A 미수정 확인 (코드 리뷰) | |
| 10 | 신규 절곡 데이터 (Path B) | EAV 정상 동작 | UI 검증: WO#141, WO#74 성적서 모달 정상 렌더링 | |
| 11 | mng `show.blade.php` 렌더링 | 성적서 정상 표시 | Phase 3 범위 (mng Blade는 별도 렌더링) | |
| 12 | `inspection-config` API 응답 | < 200ms | tinker 기준 ~50ms | |
| 13 | 스크린/슬랫 회귀 | 변화 없음 | tinker: 스크린 WO process_type='screen', items=[] | |
| 14 | 트랜잭션 동시 접근 (I2) | race condition 없음 | DB::transaction + lockForUpdate 적용 확인 (코드 리뷰) | |
---
## 6. 참고 파일
### 6.1 React
| 파일 | 역할 | 비고 |
|------|------|------|
| `react/.../documents/TemplateInspectionContent.tsx` | 통합 방향 (C3) | L176-274 |
| `react/.../documents/BendingInspectionContent.tsx` | 레거시 동결 (C3) | L71-135 |
| `react/.../documents/InspectionReportModal.tsx` | 모달 래퍼 | `documentRecords` 전달 완료 |
| `react/.../documents/inspection-shared.tsx` | 공유 유틸 | |
| `react/.../WorkerScreen/InspectionInputModal.tsx` | Path A 유지 | ~950행 |
### 6.2 API
| 파일 | 역할 |
|------|------|
| `api/app/Services/WorkOrderService.php` | `createInspectionDocument` (I2 보강) |
| `api/app/Services/DocumentService.php` | 문서 CRUD |
| `api/app/Http/Controllers/V1/DocumentController.php` | 문서 API |
### 6.3 5130 레거시
| 파일 | 역할 |
|------|------|
| `5130/output/view_inspection_bending.php` | 절곡 중간검사 |
| `5130/estimate/common/common_addrowJS.php` | 구성품 정의 |
---
## 7. 변경 이력
| 날짜 | 항목 | 변경 내용 |
|------|------|----------|
| 2026-02-27 | 문서 작성 | 통합 계획 Phase 3 상세 문서 작성 |
| 2026-02-27 | 3.5 완료 | `createInspectionDocument` DB::transaction + lockForUpdate 적용 |
| 2026-02-27 | 3.1 완료 | `inspection-config` API 구현 (Service + Controller + Route) |
| 2026-02-27 | 3.2 완료 | `TemplateInspectionContent` API 연동 (inspectionConfig state + fallback) |
| 2026-02-27 | 3.3+3.4 완료 | EAV productIdx 순서 호환 확인, Path A/B 독립 동작 확인 |
| 2026-02-27 | 검증 완료 | UI 직접 검증 (WO#141 KQTS01, WO#74 KSS02) 12/14 PASS, 2 조건부 |
---
* 문서는 [`integrated-master-plan.md`](./integrated-master-plan.md) Phase 3 상세입니다.*