# 중간검사 성적서 시스템 구현 계획 > **작성일**: 2026-02-07 > **목적**: 작업자 화면에서 개소별 중간검사 데이터를 저장하고, 검사성적서보기 시 문서 템플릿 기반 성적서로 합쳐서 표시하는 시스템 구축 > **기준 문서**: `docs/plans/document-management-system-plan.md`, `docs/specs/database-schema.md` > **상태**: 📋 계획 수립 완료 → 사용자 검토 대기 --- ## 🚀 새 세션 시작 가이드 > **이 섹션은 새 세션에서 이 문서만 보고 작업을 시작할 수 있도록 작성되었습니다.** ### 프로젝트 정보 | 항목 | 내용 | |------|------| | **작업 프로젝트** | `react` (프론트엔드) + `api` (백엔드) | | **react 절대 경로** | `/Users/kent/Works/@KD_SAM/SAM/react/` | | **api 절대 경로** | `/Users/kent/Works/@KD_SAM/SAM/api/` | | **mng 절대 경로** | `/Users/kent/Works/@KD_SAM/SAM/mng/` (양식 관리 참조) | | **기술 스택** | Next.js 15 (react) / Laravel 12 (api) | | **로컬 URL** | `https://dev.sam.kr/production/worker-screen` | | **관련 계획서** | `docs/plans/document-management-system-plan.md` (문서관리 시스템 80% 완료) | ### Git 저장소 ```bash # react (프론트엔드) - 독립 Git 저장소 cd /Users/kent/Works/@KD_SAM/SAM/react git status && git branch # api (백엔드) - 독립 Git 저장소 cd /Users/kent/Works/@KD_SAM/SAM/api git status && git branch ``` > **주의**: SAM/ 루트는 Git 저장소가 아님. api/, mng/, react/ 각각 독립 Git 저장소. ### 세션 시작 체크리스트 ``` 1. 이 문서를 읽는다 (📍 현재 진행 상태 섹션 확인) 2. react/CLAUDE.md 를 읽는다 (프론트엔드 프로젝트 규칙) 3. 마지막 완료 작업 확인 → 다음 작업 결정 4. 해당 Phase의 상세 절차(섹션 5)를 읽는다 5. 작업 시작 전 사용자에게 "Phase X.X 시작할까요?" 확인 ``` ### 핵심 파일 (작업 빈도순) **Frontend (react)** | 파일 | 설명 | |------|------| | `react/src/components/production/WorkerScreen/index.tsx` | 작업자 화면 메인 (중간검사 버튼 핸들러) | | `react/src/components/production/WorkerScreen/InspectionInputModal.tsx` | 중간검사 입력 모달 (개소별 데이터 입력) | | `react/src/components/production/WorkerScreen/types.ts` | InspectionData, WorkItemData, InspectionDataMap 타입 | | `react/src/components/production/WorkerScreen/actions.ts` | 작업자 화면 서버 액션 | | `react/src/components/production/WorkOrders/documents/InspectionReportModal.tsx` | 중간검사 성적서 모달 (문서 래퍼) | | `react/src/components/production/WorkOrders/documents/ScreenInspectionContent.tsx` | 스크린 검사 성적서 콘텐츠 | | `react/src/components/production/WorkOrders/documents/SlatInspectionContent.tsx` | 슬랫 검사 성적서 콘텐츠 | | `react/src/components/production/WorkOrders/documents/BendingInspectionContent.tsx` | 절곡 검사 성적서 콘텐츠 | | `react/src/components/production/WorkOrders/actions.ts` | saveInspectionData 서버 액션 (628-668줄) | | `react/src/components/document-system/configs/qms/index.ts` | QMS 문서 Config 6종 | **Backend (api)** | 파일 | 설명 | |------|------| | `api/app/Http/Controllers/Api/V1/InspectionController.php` | 검사 CRUD API (89줄) | | `api/app/Services/InspectionService.php` | 검사 비즈니스 로직 (402줄) | | `api/routes/api/v1/production.php` | 생산 관련 라우트 | **MNG (양식 관리)** | 파일 | 설명 | |------|------| | `mng/app/Models/DocumentTemplate.php` | 양식 템플릿 모델 | | `mng/app/Models/Documents/Document.php` | 문서 인스턴스 모델 | | `mng/resources/views/document-templates/edit.blade.php` | 양식 편집 UI | ### 현재 코드 구조 (핵심 타입/인터페이스) **InspectionData (프론트 - 검사 입력 데이터)** ```typescript // react/src/components/production/WorkerScreen/InspectionInputModal.tsx:35-56 export type InspectionProcessType = 'screen' | 'slat' | 'slat_jointbar' | 'bending' | 'bending_wip'; export interface InspectionData { productName: string; specification: string; bendingStatus?: 'good' | 'bad' | null; // 절곡상태 processingStatus?: 'good' | 'bad' | null; // 가공상태 sewingStatus?: 'good' | 'bad' | null; // 재봉상태 assemblyStatus?: 'good' | 'bad' | null; // 조립상태 length?: number | null; width?: number | null; height1?: number | null; height2?: number | null; length3?: number | null; gap4?: number | null; gapStatus?: 'ok' | 'ng' | null; gapPoints?: { left: number | null; right: number | null }[]; judgment: 'pass' | 'fail' | null; nonConformingContent: string; } ``` **InspectionDataMap (프론트 - 아이템별 검사 데이터 맵)** ```typescript // react/src/components/production/WorkOrders/documents/InspectionReportModal.tsx:37 export type InspectionDataMap = Map; // key: workItem.id (또는 selectedOrder.id), value: InspectionData ``` **WorkItemData (프론트 - 작업 아이템)** ```typescript // react/src/components/production/WorkerScreen/types.ts:32-58 export interface WorkItemData { id: string; itemNo: number; itemCode: string; itemName: string; floor: string; code: string; width: number; height: number; quantity: number; processType: ProcessTab; // 'screen' | 'slat' | 'bending' steps: WorkStepData[]; isWip?: boolean; isJointBar?: boolean; cuttingInfo?: CuttingInfo; // 스크린 전용 slatInfo?: SlatInfo; // 슬랫 전용 slatJointBarInfo?: SlatJointBarInfo; // 조인트바 전용 bendingInfo?: BendingInfo; // 절곡 전용 wipInfo?: WipInfo; // 재공품 전용 materialInputs?: MaterialListItem[]; } ``` **WorkOrderItem 모델 (백엔드)** ```php // api/app/Models/Production/WorkOrderItem.php class WorkOrderItem extends Model { use Auditable, BelongsToTenant; protected $fillable = [ 'tenant_id', 'work_order_id', 'source_order_item_id', 'item_id', 'item_name', 'specification', 'quantity', 'unit', 'sort_order', 'status', 'options', ]; protected $casts = ['options' => 'array']; // ← JSON 컬럼, inspection_data 저장 대상 // options['result'] 패턴이 이미 존재 (작업 완료 결과 저장) // 동일 패턴으로 options['inspection_data'] 추가 예정 public function getResult(): ?array { return $this->options['result'] ?? null; } public function setResult(array $result): void { $options = $this->options ?? []; $options['result'] = array_merge($options['result'] ?? [], $result); $this->options = $options; } } ``` **InspectionReportModal - 공정별 라우팅 로직** ```typescript // react/src/components/production/WorkOrders/documents/InspectionReportModal.tsx:185-201 switch (processType) { case 'screen': return ; case 'slat': if (isJointBar || order.items?.some(item => item.productName?.includes('조인트바'))) { return ; } return ; case 'bending': return ; case 'bending_wip': return ; } ``` **WorkerScreen - 검사 핸들러 (핵심 흐름)** ```typescript // react/src/components/production/WorkerScreen/index.tsx // 1) 중간검사 입력: handleInspectionClick (802줄) → InspectionInputModal 오픈 // 2) 검사 완료: handleInspectionComplete (862줄) → inspectionDataMap에 저장 (메모리만!) // 3) 성적서 보기: handleInspection (851줄) → InspectionReportModal 오픈 // - workItems + inspectionDataMap을 props로 전달 const [inspectionDataMap, setInspectionDataMap] = useState>(new Map()); const handleInspectionComplete = useCallback((data: InspectionData) => { if (selectedOrder) { setInspectionDataMap((prev) => { const next = new Map(prev); next.set(selectedOrder.id, data); // ← 현재: 메모리에만 저장, API 호출 없음! return next; }); } }, [selectedOrder]); ``` **기존 saveInspectionData 서버 액션 (미완성)** ```typescript // react/src/components/production/WorkOrders/actions.ts:628-668 export async function saveInspectionData( workOrderId: string, processType: string, data: unknown ): Promise<{ success: boolean; error?: string }> { // POST /api/v1/work-orders/{workOrderId}/inspection // ⚠️ 문제: 백엔드에 이 엔드포인트가 존재하지 않음! // production.php 라우트에 /work-orders/{id}/inspection 없음 } ``` ### 백엔드 라우트 구조 (현재) ```php // api/routes/api/v1/production.php (43-74줄) Route::prefix('work-orders')->group(function () { // 기본 CRUD: index, stats, store, show, update, destroy // 상태 관리: updateStatus, assign, toggleBendingField // 이슈: addIssue, resolveIssue // 품목: updateItemStatus // 자재: materials, registerMaterialInput, materialInputHistory // 단계 진행: stepProgress, toggleStepProgress // ⚠️ 검사(inspection) 관련 라우트 없음 → Phase 1에서 추가 필요 }); // 별도 검사 API (InspectionController) - 범용 검사, 작업지시와 직접 연결 아님 Route::prefix('inspections')->group(function () { Route::get('', [InspectionController::class, 'index']); // 목록 Route::post('', [InspectionController::class, 'store']); // 생성 Route::get('/{id}', [InspectionController::class, 'show']); // 상세 // ... }); ``` ### 백엔드 컨트롤러/서비스 구조 (현재) ```php // WorkOrderController: 18개 메서드 (inspection 관련 없음) // WorkOrderService: 16개 메서드 (1493줄, inspection 관련 없음) // → Phase 1에서 3개 메서드 추가 필요: // storeItemInspection, getInspectionData, getInspectionReport ``` ### 문서 템플릿 DB 구조 (이미 존재) ``` document_templates # 양식 마스터 ├── document_template_approval_lines # 결재라인 (작성/검토/승인) ├── document_template_basic_fields # 기본필드 (품명, LOT NO 등) ├── document_template_sections # 섹션 (검사기준서 섹션) │ └── document_template_section_items # 섹션 항목 (검사항목) └── document_template_columns # 데이터 테이블 컬럼 documents # 문서 인스턴스 ├── document_approvals # 결재 이력 ├── document_data # 필드 데이터 (EAV, field_key/field_value) └── document_attachments # 첨부 파일 ``` --- ## 📍 현재 진행 상태 | 항목 | 내용 | |------|------| | **마지막 완료 작업** | 분석 완료 - 중간검사 모달/문서관리 시스템/성적서 컴포넌트 전체 분석 | | **다음 작업** | Phase 1.1 - 백엔드 API 설계 | | **진행률** | 0/14 (0%) | | **마지막 업데이트** | 2026-02-07 | --- ## 1. 개요 ### 1.1 배경 현재 중간검사 시스템은 다음 상태입니다: **개소별 검사 입력 (InspectionInputModal)** - 스타일 수입검사 모달과 통일 완료 (2026-02-07) - 공정별 입력 항목: 스크린(6항목), 슬랫(5항목), 조인트바(6항목), 절곡(3항목+간격5포인트), 재공품(3항목+간격) - 데이터 저장: **프론트 메모리(InspectionDataMap)에만 보관**, 백엔드 저장 미구현 **검사 성적서 보기 (InspectionReportModal)** - 4종 하드코딩 컴포넌트: Screen/Slat/Bending/BendingWip InspectionContent - 조인트바 자동 감지 (SlatJointBarInspectionContent) - 문서 템플릿 시스템 미활용 (레이아웃 코드 내 고정) - workItems 기반 동적 행 생성 + inspectionDataMap에서 데이터 매핑 **문서관리 시스템 (80% 완료)** - mng.sam.kr/document-templates에서 양식 CRUD 가능 - API: documents/resolve (카테고리+아이템 기반 조회), documents/upsert (저장) - EAV 패턴: document_data 테이블 (field_key/field_value) - 수입검사 성적서는 이미 문서관리 시스템 연동 완료 **문제점** 1. 개소별 검사 데이터가 프론트 메모리에만 존재 → 새로고침 시 소실 2. 성적서 레이아웃이 하드코딩 → 양식 변경 시 코드 수정 필요 3. 검사 이력 관리 불가 → 언제 누가 어떤 데이터를 입력했는지 추적 불가 ### 1.2 핵심 원칙 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 🎯 하이브리드 방식 │ ├─────────────────────────────────────────────────────────────────┤ │ 1. 개소별 데이터 → work_order_items.options JSON에 저장 │ │ 2. 성적서 레이아웃 → 문서 템플릿 시스템(mng)에서 관리 │ │ 3. 성적서 보기 → 템플릿 레이아웃 + 개소 데이터 결합하여 렌더링 │ │ 4. 기존 InspectionContent 컴포넌트 → Config 기반으로 점진 전환 │ └─────────────────────────────────────────────────────────────────┘ ``` ### 1.3 수입검사 성적서와의 비교 | 구분 | 수입검사 성적서 | 중간검사 성적서 (목표) | |------|----------------|----------------------| | **데이터 소스** | 1입고 = 1문서 | N개소 = 1문서 (합산) | | **데이터 수집** | 한 번에 입력 | 개소별로 따로 입력 후 합산 | | **데이터 저장** | document_data (EAV) | work_order_items.options (JSON) | | **레이아웃** | 문서 템플릿 시스템 | 문서 템플릿 시스템 (동일) | | **측정 항목** | 자재별 고정 | 공정별 다름 (스크린/슬랫/절곡/조인트바) | | **자동 판정** | 있음 (N1~Nn 탭) | 있음 (행별 + 종합) | | **문서 유형** | 1종 | 5종 (스크린/슬랫/조인트바/절곡/재공품) | ### 1.4 변경 승인 정책 | 분류 | 예시 | 승인 | |------|------|------| | ✅ 즉시 가능 | 프론트 컴포넌트 수정, 서버 액션 추가, 타입 정의 | 불필요 | | ⚠️ 컨펌 필요 | API 엔드포인트 추가, work_order_items.options 구조 변경, 문서 템플릿 등록 | **필수** | | 🔴 금지 | 테이블 구조 변경, 기존 API 삭제, 수입검사 로직 변경 | 별도 협의 | ### 1.5 준수 규칙 - `docs/quickstart/quick-start.md` - 빠른 시작 가이드 - `docs/standards/quality-checklist.md` - 품질 체크리스트 - `react/CLAUDE.md` - 프론트엔드 프로젝트 규칙 - `docs/plans/document-management-system-plan.md` - 문서관리 시스템 계획서 --- ## 2. 현황 분석 ### 2.1 현재 동작하는 검사 흐름 (문제점 포함) ``` [현재 흐름 - 데이터가 메모리에만 존재] 1. 작업자 화면 진입 (dev.sam.kr/production/worker-screen) ↓ 2. 작업지시 선택 → 개소(아이템) 카드 목록 표시 ↓ 3. 개소 카드의 "중간검사" 단계(pill) 클릭 ↓ handleInspectionClick (index.tsx:802) 4. InspectionInputModal 오픈 (공정별 입력 항목) ↓ 작업자가 검사 데이터 입력 후 "검사 완료" 5. handleInspectionComplete (index.tsx:862) ↓ inspectionDataMap.set(selectedOrder.id, data) ⚠️ 메모리에만 저장! → 새로고침하면 소실 ↓ 6. "검사성적서 보기" 버튼 클릭 ↓ handleInspection (index.tsx:851) 7. InspectionReportModal 오픈 - workItems + inspectionDataMap props 전달 - 공정별 InspectionContent 컴포넌트 렌더링 ↓ 8. DocumentViewer로 문서 형태 표시/인쇄 ``` ### 2.2 기존 코드에서 활용할 수 있는 패턴 | 패턴 | 위치 | 설명 | |------|------|------| | `options['result']` 패턴 | WorkOrderItem.php:119-132 | options JSON에 구조화된 데이터 저장/조회 | | `saveInspectionData` 서버 액션 | WorkOrders/actions.ts:628-668 | POST 구조 이미 존재 (백엔드 미구현) | | `InspectionDataMap` | InspectionReportModal.tsx:37 | 아이템ID→검사데이터 Map 구조 | | `InspectionContentRef.getInspectionData()` | InspectionReportModal.tsx:143 | 성적서에서 데이터 추출 인터페이스 | | `DocumentViewer` preset="inspection" | InspectionReportModal.tsx:216 | 검사 문서 뷰어 프리셋 | ### 2.3 관련 API 현황 | API | 상태 | 비고 | |-----|------|------| | `GET /work-orders` | ✅ 존재 | 목록 조회 | | `GET /work-orders/{id}` | ✅ 존재 | 상세 (items 포함) | | `PATCH /work-orders/{id}/items/{itemId}/status` | ✅ 존재 | 품목 상태 변경 | | `POST /work-orders/{id}/inspection` | ❌ 없음 | saveInspectionData가 호출하려는 URL | | `POST /work-orders/{id}/items/{itemId}/inspection` | ❌ 없음 | Phase 1.2에서 구현 | | `GET /work-orders/{id}/inspection-data` | ❌ 없음 | Phase 1.3에서 구현 | | `GET /work-orders/{id}/inspection-report` | ❌ 없음 | Phase 1.4에서 구현 | | `GET /documents/resolve` | ✅ 존재 | 문서 템플릿 조회 (Phase 1.4에서 활용) | --- ## 3. 대상 범위 ### Phase 의존 관계 ``` Phase 1 (백엔드 API) ↓ Phase 2가 Phase 1에 의존 (API가 있어야 프론트 연동) Phase 2 (프론트 저장 연동) ↓ Phase 3은 Phase 1-2와 독립 (mng에서 양식 등록) Phase 3 (mng 템플릿 등록) ↓ Phase 4가 Phase 1+3에 의존 (API + 템플릿 모두 필요) Phase 4 (프론트 성적서 연동) ``` ### Phase 1: 백엔드 - 개소별 검사 데이터 저장 API | # | 작업 항목 | 상태 | 완료 기준 | 비고 | |---|----------|:----:|----------|------| | 1.1 | API 엔드포인트 설계 | ⏳ | 엔드포인트 목록 + 요청/응답 스키마 확정 | ⚠️ 컨펌 필요 | | 1.2 | 개소별 검사 데이터 저장 API 구현 | ⏳ | POST /work-orders/{id}/items/{itemId}/inspection 동작 | work_order_items.options에 inspection_data 필드 추가 | | 1.3 | 개소별 검사 데이터 조회 API 구현 | ⏳ | GET /work-orders/{id}/inspection-data 동작 | 전체 개소 검사 데이터 한번에 반환 | | 1.4 | 성적서 문서 데이터 조회 API 구현 | ⏳ | GET /work-orders/{id}/inspection-report 동작 | 템플릿 + 개소 데이터 결합 응답 | ### Phase 2: 프론트 - 개소별 검사 데이터 저장 연동 | # | 작업 항목 | 상태 | 완료 기준 | 비고 | |---|----------|:----:|----------|------| | 2.1 | 서버 액션 추가 (저장/조회) | ⏳ | saveItemInspection, getInspectionData 서버 액션 동작 | | | 2.2 | InspectionInputModal - 저장 연동 | ⏳ | "검사 완료" 클릭 시 API 호출 + 성공/실패 피드백 | | | 2.3 | WorkerScreen - 저장된 데이터 로드 | ⏳ | 화면 진입 시 기존 검사 데이터 자동 로드 | inspectionDataMap 초기화 | | 2.4 | InspectionInputModal - 기존 데이터 표시 | ⏳ | 이미 검사한 개소 재클릭 시 저장된 데이터 표시 | | ### Phase 3: 문서 템플릿 등록 (mng) | # | 작업 항목 | 상태 | 완료 기준 | 비고 | |---|----------|:----:|----------|------| | 3.1 | 스크린 중간검사 양식 등록 | ⏳ | mng.sam.kr/document-templates에서 양식 확인 | ⚠️ 컨펌 필요 | | 3.2 | 슬랫 중간검사 양식 등록 | ⏳ | 위와 동일 | | | 3.3 | 절곡 중간검사 양식 등록 | ⏳ | 위와 동일 | | | 3.4 | 조인트바 중간검사 양식 등록 | ⏳ | 위와 동일 | | ### Phase 4: 프론트 - 성적서 보기 템플릿 연동 | # | 작업 항목 | 상태 | 완료 기준 | 비고 | |---|----------|:----:|----------|------| | 4.1 | InspectionReportModal - API 연동 | ⏳ | 템플릿 + 검사 데이터 API에서 로드 | | | 4.2 | InspectionContent 컴포넌트 리팩토링 | ⏳ | Config 기반으로 전환 (기존 하드코딩 제거) | 점진적 전환 | --- ## 4. 아키텍처 설계 ### 3.1 데이터 흐름 ``` [개소별 중간검사] [검사 성적서 보기] 작업자 화면 작업자 화면 ↓ "중간검사" 클릭 ↓ "검사성적서보기" 클릭 InspectionInputModal InspectionReportModal ↓ 검사 완료 ↓ POST /work-orders/{id}/ GET /work-orders/{id}/ items/{itemId}/inspection inspection-report ↓ ↓ work_order_items.options { .inspection_data = { template: { 레이아웃 JSON }, processingStatus: 'good', items: [ sewingStatus: 'good', { itemId, itemName, inspectionData }, length: 1200, { itemId, itemName, inspectionData }, judgment: 'pass', ... ... ], } summary: { total, pass, fail } } ↓ 공정별 InspectionContent 렌더링 (템플릿 레이아웃 + 개소 데이터 결합) ``` ### 3.2 work_order_items.options JSON 구조 (확장) ```json { "floor": "3F", "code": "SC-001", "width": 1200, "height": 800, "cutting_info": { ... }, "slat_info": { ... }, "bending_info": { ... }, "wip_info": { ... }, "inspection_data": { "inspected_at": "2026-02-07T14:30:00Z", "inspected_by": "user_id", "inspected_by_name": "홍길동", "process_type": "screen", "data": { "processingStatus": "good", "sewingStatus": "good", "assemblyStatus": "good", "length": 1200, "width": 800, "gapStatus": "ok", "gapPoints": [ { "left": 5.0, "right": 5.0 } ] }, "judgment": "pass", "non_conforming_content": "" } } ``` ### 3.3 API 설계 **1) 개소별 검사 데이터 저장** ``` POST /api/v1/work-orders/{workOrderId}/items/{itemId}/inspection Request: { "process_type": "screen", "inspection_data": { "processingStatus": "good", "sewingStatus": "good", "assemblyStatus": "good", "length": 1200, "width": 800, "gapStatus": "ok", "gapPoints": [{ "left": 5.0, "right": 5.0 }] }, "judgment": "pass", "non_conforming_content": "" } Response: { "success": true, "data": { "item_id": "item-uuid", "inspection_data": { ... }, "inspected_at": "2026-02-07T14:30:00Z" } } ``` **2) 작업지시 전체 검사 데이터 조회** ``` GET /api/v1/work-orders/{workOrderId}/inspection-data Response: { "success": true, "data": { "work_order_id": "wo-uuid", "process_type": "screen", "items": [ { "item_id": "item-1", "item_name": "SC-001-3F", "has_inspection": true, "inspection_data": { ... }, "judgment": "pass", "inspected_at": "2026-02-07T14:30:00Z", "inspected_by_name": "홍길동" }, { "item_id": "item-2", "item_name": "SC-002-3F", "has_inspection": false, "inspection_data": null, "judgment": null, "inspected_at": null, "inspected_by_name": null } ], "summary": { "total": 6, "inspected": 4, "pass": 3, "fail": 1, "pending": 2 } } } ``` **3) 검사 성적서 데이터 조회 (문서 형태)** ``` GET /api/v1/work-orders/{workOrderId}/inspection-report Response: { "success": true, "data": { "work_order_id": "wo-uuid", "process_type": "screen", "template": { "id": "template-uuid", "title": "스크린 중간검사 성적서", "approval_lines": [...], "basic_fields": [...], "sections": [...], "columns": [...] }, "document_data": { "basic_fields": { "product_name": "블라인드 A형", "specification": "1200x800", "lot_no": "LOT-2026-001", "inspection_date": "2026-02-07", "inspector": "홍길동" }, "inspection_rows": [ { "row_no": 1, "item_id": "item-1", "item_name": "SC-001-3F", "processing_status": "양호", "sewing_status": "양호", "assembly_status": "양호", "length_design": 1200, "length_measured": 1200, "width_design": 800, "width_measured": 800, "gap_standard": "5±1", "gap_result": "OK", "judgment": "적" } ], "summary": { "total": 6, "pass": 5, "fail": 1, "overall_judgment": "합격", "non_conforming_content": "item-3: 길이 규격 초과" } }, "inspection_setting": { "schematic_image": "/img/inspection/screen-schematic.png", "inspection_standard_image": "/img/inspection/screen-standard.png" } } } ``` ### 3.4 공정별 검사 항목 매핑 **스크린 (screen)** | 검사항목 | 입력 타입 | options.inspection_data 키 | 성적서 컬럼 | |---------|----------|---------------------------|------------| | 가공상태 결모양 | good/bad | processingStatus | 가공상태 | | 재봉상태 결모양 | good/bad | sewingStatus | 재봉상태 | | 조립상태 | good/bad | assemblyStatus | 조립상태 | | 길이 | number | length | 길이 (도면치수 vs 측정값) | | 나비 | number | width | 나비 (도면치수 vs 측정값) | | 간격 | ok/ng | gapStatus | 간격 (기준치 vs OK/NG) | **슬랫 (slat)** | 검사항목 | 입력 타입 | options.inspection_data 키 | 성적서 컬럼 | |---------|----------|---------------------------|------------| | 가공상태 | good/bad | processingStatus | 가공상태 | | 조립상태 | good/bad | assemblyStatus | 조립상태 | | ① 높이 | number | height1 | 높이① (16.5±1) | | ② 높이 | number | height2 | 높이② (14.5±1) | | 길이 | number | length | 길이 | **조인트바 (slat_jointbar)** | 검사항목 | 입력 타입 | options.inspection_data 키 | 성적서 컬럼 | |---------|----------|---------------------------|------------| | 가공상태 | good/bad | processingStatus | 가공상태 | | 조립상태 | good/bad | assemblyStatus | 조립상태 | | ① 높이 | number | height1 | 높이① | | ② 높이 | number | height2 | 높이② | | ③ 길이 | number | length | 길이 | | ④ 간격 | number | gapValue | 간격 | **절곡 (bending)** | 검사항목 | 입력 타입 | options.inspection_data 키 | 성적서 컬럼 | |---------|----------|---------------------------|------------| | 절곡상태 | good/bad | bendingStatus | 절곡상태 | | 길이 | number | length | 길이 | | 간격 (5포인트) | number x 10 | gapPoints[].left/right | 간격 좌1~좌5, 우1~우5 | **재공품 (bending_wip)** | 검사항목 | 입력 타입 | options.inspection_data 키 | 성적서 컬럼 | |---------|----------|---------------------------|------------| | 절곡상태 | good/bad | bendingStatus | 절곡상태 | | 길이 | number | length | 길이 | | 나비 | number | width | 나비 | | 간격 | ok/ng | gapStatus | 간격 | --- ## 5. 기술 결정사항 ### 4.1 확정 결정 | # | 결정 사항 | 선택 | 근거 | |---|----------|------|------| | 1 | 데이터 저장 위치 | work_order_items.options JSON | 이미 공정별 데이터(cutting_info, slat_info 등) 저장에 사용 중, 추가 테이블 불필요 | | 2 | 레이아웃 관리 | 문서 템플릿 시스템 (mng) | 문서관리 시스템 80% 완료, 양식 변경 시 코드 수정 없이 가능 | | 3 | 성적서 렌더링 | 기존 InspectionContent 컴포넌트 유지 + API 데이터 주입 | 이미 동작하는 렌더링 로직 활용, 점진적으로 Config 기반 전환 | | 4 | 자동 판정 로직 | 프론트엔드에서 계산 (현재 방식 유지) | 공정별 판정 기준이 프론트에 이미 구현됨 | | 5 | 검사 이력 | inspection_data에 inspected_at, inspected_by 포함 | 별도 이력 테이블 불필요, JSON 내에서 추적 | ### 4.2 검토 필요 항목 | # | 항목 | 선택지 | 현재 판단 | 비고 | |---|------|--------|----------|------| | 1 | Phase 3 (템플릿 등록) 시점 | A) Phase 1-2와 병행 / B) Phase 1-2 완료 후 | B | Phase 1-2로 데이터 저장/조회 먼저 안정화 | | 2 | 검사 기준 이미지 관리 | A) mng에서 등록 / B) API에서 등록 | A | 문서관리 시스템 계획서 Phase 3.4에서 이미 처리 | | 3 | 기존 하드코딩 컴포넌트 전환 범위 | A) 전체 전환 / B) 점진적 전환 | B | Phase 4에서 점진적 전환, 기존 기능 유지 우선 | --- ## 6. 상세 작업 절차 ### Phase 1: 백엔드 - 개소별 검사 데이터 저장 API #### 1.1 API 엔드포인트 설계 **작업 내용:** 1. `api/routes/api/v1/production.php`에 라우트 추가: - `POST /work-orders/{workOrderId}/items/{itemId}/inspection` - `GET /work-orders/{workOrderId}/inspection-data` - `GET /work-orders/{workOrderId}/inspection-report` 2. 요청/응답 스키마 확정 (섹션 3.3 참조) 3. FormRequest 클래스 생성 **관련 파일:** - `api/routes/api/v1/production.php` (라우트 추가) - `api/app/Http/Requests/Api/V1/` (FormRequest 생성) #### 1.2 개소별 검사 데이터 저장 API 구현 **작업 내용:** 1. WorkOrderController에 `storeItemInspection` 메서드 추가 2. WorkOrderService에 `saveItemInspection` 메서드 추가: - work_order_items 조회 (workOrderId + itemId) - options JSON에서 기존 데이터 읽기 - inspection_data 필드 추가/업데이트 - inspected_at, inspected_by 자동 기록 3. 유효성 검증: process_type 필수, inspection_data 공정별 스키마 검증 **관련 파일:** - `api/app/Http/Controllers/Api/V1/WorkOrderController.php` - `api/app/Services/WorkOrderService.php` #### 1.3 개소별 검사 데이터 조회 API 구현 **작업 내용:** 1. WorkOrderController에 `getInspectionData` 메서드 추가 2. WorkOrderService에 `getInspectionData` 메서드 추가: - 해당 작업지시의 모든 work_order_items 조회 - 각 item의 options.inspection_data 추출 - 요약 정보 계산 (total, inspected, pass, fail, pending) #### 1.4 성적서 문서 데이터 조회 API 구현 **작업 내용:** 1. WorkOrderController에 `getInspectionReport` 메서드 추가 2. WorkOrderService에 `getInspectionReport` 메서드 추가: - 공정 타입에 맞는 문서 템플릿 조회 (documents/resolve API 활용) - work_order_items의 inspection_data 수집 - 템플릿 레이아웃 + 검사 데이터 + 기본 정보 결합 - inspection_setting (도해/검사기준 이미지) 포함 ### Phase 2: 프론트 - 개소별 검사 데이터 저장 연동 #### 2.1 서버 액션 추가 **작업 내용:** 1. `react/src/components/production/WorkerScreen/actions.ts`에 추가: - `saveItemInspection(workOrderId, itemId, data)` - 개소별 저장 - `getWorkOrderInspectionData(workOrderId)` - 전체 검사 데이터 조회 - `getInspectionReport(workOrderId)` - 성적서 데이터 조회 **관련 파일:** - `react/src/components/production/WorkerScreen/actions.ts` #### 2.2 InspectionInputModal - 저장 연동 **작업 내용:** 1. onComplete 콜백에서 saveItemInspection 서버 액션 호출 2. 저장 성공/실패 toast 알림 3. 저장 중 로딩 상태 표시 4. 에러 시 재시도 가능 **관련 파일:** - `react/src/components/production/WorkerScreen/InspectionInputModal.tsx` - `react/src/components/production/WorkerScreen/index.tsx` (handleInspectionClick) #### 2.3 WorkerScreen - 저장된 데이터 로드 **작업 내용:** 1. 화면 진입 시 getWorkOrderInspectionData 호출 2. 응답 데이터로 inspectionDataMap 초기화 3. 이미 검사 완료된 개소 시각적 표시 (아이콘/배지) **관련 파일:** - `react/src/components/production/WorkerScreen/index.tsx` #### 2.4 InspectionInputModal - 기존 데이터 표시 **작업 내용:** 1. inspectionDataMap에 해당 itemId 데이터가 있으면 폼에 자동 채움 2. 기존 검사 데이터 수정 가능 (재검사) 3. 최초 검사 vs 재검사 구분 표시 **관련 파일:** - `react/src/components/production/WorkerScreen/InspectionInputModal.tsx` ### Phase 3: 문서 템플릿 등록 (mng) #### 3.1~3.4 공정별 양식 등록 **작업 내용 (공정별 동일 패턴):** 1. mng.sam.kr/document-templates에서 새 양식 생성 2. 카테고리: `intermediate-inspection` / 서브카테고리: `screen` (또는 slat/bending/jointbar) 3. 결재라인 설정: 작성자 → 검토 → 승인 4. 기본필드: 제품명, 규격, 수주처, 현장명, LOT NO, 검사일자, 검사자 5. 섹션1: 중간검사 기준서 (도해 이미지 + 검사항목 테이블) 6. 섹션2: 중간검사 DATA (동적 행, 공정별 컬럼 정의) 7. 섹션3: 부적합 내용 + 종합 판정 8. 도해/검사기준 이미지 등록 ### Phase 4: 프론트 - 성적서 보기 템플릿 연동 #### 4.1 InspectionReportModal - API 연동 **작업 내용:** 1. getInspectionReport 서버 액션으로 데이터 로드 2. 템플릿 레이아웃 정보 활용 (결재라인, 기본필드, 섹션 구조) 3. 기존 props 기반 데이터 → API 응답 데이터로 전환 4. 로딩/에러 상태 처리 **관련 파일:** - `react/src/components/production/WorkOrders/documents/InspectionReportModal.tsx` #### 4.2 InspectionContent 컴포넌트 리팩토링 **작업 내용:** 1. 기존 하드코딩된 레이아웃을 템플릿 데이터 기반으로 전환 2. 공통 렌더링 로직 추출 (테이블 생성, 판정 로직, 결재란) 3. 공정별 차이점만 Config로 분리 4. 기존 기능 100% 유지 (회귀 방지) **관련 파일:** - `react/src/components/production/WorkOrders/documents/ScreenInspectionContent.tsx` - `react/src/components/production/WorkOrders/documents/SlatInspectionContent.tsx` - `react/src/components/production/WorkOrders/documents/BendingInspectionContent.tsx` - `react/src/components/production/WorkOrders/documents/BendingWipInspectionContent.tsx` - `react/src/components/production/WorkOrders/documents/SlatJointBarInspectionContent.tsx` --- ## 7. 컨펌 대기 목록 | # | 항목 | 변경 내용 | 영향 범위 | 상태 | |---|------|----------|----------|------| | 1 | API 엔드포인트 3개 추가 | work-orders/{id}/items/{itemId}/inspection, inspection-data, inspection-report | api | ⏳ Phase 1.1에서 확정 | | 2 | work_order_items.options 구조 확장 | inspection_data 필드 추가 | api, react | ⏳ Phase 1.2에서 확정 | | 3 | 중간검사 문서 템플릿 4종 등록 | mng 양식 관리에서 등록 | mng | ⏳ Phase 3에서 확정 | --- ## 8. 변경 이력 | 날짜 | 항목 | 변경 내용 | 파일 | 승인 | |------|------|----------|------|------| | 2026-02-07 | 초안 | 계획 문서 초안 작성 | - | - | | 2026-02-07 | 보완 | 자기완결성 보강: Git 정보, 코드 스니펫(타입/모델/라우트/핸들러), 현황 분석(동작 흐름/활용 패턴/API 현황), Phase 의존 관계 추가 | - | - | --- ## 9. 참고 문서 - **문서관리 시스템 계획**: `docs/plans/document-management-system-plan.md` (80% 완료) - **수입검사 양식 계획**: `docs/plans/incoming-inspection-templates-plan.md` - **수입검사 연동 계획**: `docs/plans/incoming-inspection-document-integration-plan.md` - **DB 스키마**: `docs/specs/database-schema.md` - **빠른 시작**: `docs/quickstart/quick-start.md` - **품질 체크리스트**: `docs/standards/quality-checklist.md` ### 기존 코드 참조 - **수입검사 성적서 (참고 모델)**: `react/src/components/material/ReceivingManagement/ImportInspectionInputModal.tsx` - **문서 뷰어**: `react/src/components/document-system/DocumentViewer.tsx` - **QMS Config**: `react/src/components/document-system/configs/qms/index.ts` - **검사 서비스**: `api/app/Services/InspectionService.php` --- ## 10. 검증 결과 > 작업 완료 후 이 섹션에 검증 결과 추가 ### 9.1 테스트 케이스 | # | 시나리오 | 입력 | 예상 결과 | 실제 결과 | 상태 | |---|---------|------|----------|----------|------| | 1 | 스크린 개소 검사 저장 | 모든 항목 양호 입력 | API 200, options.inspection_data 저장됨 | | ⏳ | | 2 | 저장된 검사 데이터 로드 | 화면 재진입 | inspectionDataMap에 기존 데이터 표시 | | ⏳ | | 3 | 이미 검사한 개소 재클릭 | 검사 완료된 item 클릭 | 기존 데이터 폼에 표시 | | ⏳ | | 4 | 검사성적서보기 | 모든 개소 검사 완료 후 클릭 | 템플릿 레이아웃 + 전체 데이터 표시 | | ⏳ | | 5 | 일부 개소만 검사 후 성적서 | 6개 중 3개만 검사 | 검사된 3개만 데이터, 3개는 빈 행 | | ⏳ | | 6 | 종합 판정 자동 계산 | 1개 부적 + 나머지 적합 | 종합: 불합격, 부적합 내용 표시 | | ⏳ | ### 9.2 성공 기준 | 기준 | 달성 | 비고 | |------|------|------| | 개소별 검사 데이터가 서버에 저장됨 | ⏳ | 새로고침 후에도 유지 | | 저장된 데이터가 InspectionInputModal에 자동 로드됨 | ⏳ | | | 검사성적서보기에서 모든 개소 데이터가 합쳐져 표시됨 | ⏳ | | | 문서 템플릿 레이아웃 적용됨 | ⏳ | 결재란, 기본정보, 섹션 구조 | | 기존 하드코딩 성적서와 동일한 출력물 | ⏳ | 회귀 방지 | | 자동 판정 로직 정상 동작 | ⏳ | 행별 + 종합 | --- ## 11. 자기완결성 점검 결과 ### 10.1 체크리스트 검증 | # | 검증 항목 | 상태 | 비고 | |---|----------|:----:|------| | 1 | 작업 목적이 명확한가? | ✅ | 섹션 1.1 배경에 명시 | | 2 | 성공 기준이 정의되어 있는가? | ✅ | 섹션 10.2 성공 기준 6개 | | 3 | 작업 범위가 구체적인가? | ✅ | Phase 1-4, 14개 작업 항목 | | 4 | 의존성이 명시되어 있는가? | ✅ | Phase 의존 관계 + 문서관리 시스템 80% 완료 전제 | | 5 | 참고 파일 경로가 정확한가? | ✅ | 절대 경로 포함 핵심 파일 목록 | | 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 6 상세 작업 절차 | | 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 10.1 테스트 케이스 6개 | | 8 | 모호한 표현이 없는가? | ✅ | API 스키마, 데이터 구조, 검사 항목 매핑, 코드 스니펫 모두 구체적 | | 9 | 현재 코드 구조가 이해 가능한가? | ✅ | 핵심 타입/인터페이스 + 백엔드 모델/라우트 코드 포함 | | 10 | 현재 동작 흐름이 파악 가능한가? | ✅ | 섹션 2.1 현재 흐름도 + 문제점 명시 | ### 11.2 새 세션 시뮬레이션 테스트 | 질문 | 답변 가능 | 참조 섹션 | |------|:--------:|----------| | Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 | | Q2. 현재 시스템이 어떻게 동작하는가? | ✅ | 2.1 현재 동작 흐름 + 코드 스니펫 | | Q3. 어디서부터 시작해야 하는가? | ✅ | 📍 현재 진행 상태 + 6. 상세 작업 절차 | | Q4. 어떤 파일을 수정해야 하는가? | ✅ | 핵심 파일 목록 + Phase별 관련 파일 | | Q5. 기존 코드의 타입/인터페이스는? | ✅ | 현재 코드 구조 (InspectionData, WorkItemData, WorkOrderItem) | | Q6. 백엔드에 뭐가 있고 뭐가 없는가? | ✅ | 2.3 API 현황 + 백엔드 라우트/컨트롤러 구조 | | Q7. 작업 완료 확인 방법은? | ✅ | 10.1 테스트 케이스 + 10.2 성공 기준 | | Q8. 막혔을 때 참고 문서는? | ✅ | 9. 참고 문서 | **결과**: 8/8 통과 → ✅ 자기완결성 확보 --- ## 12. 세션 및 메모리 관리 정책 ### 11.1 세션 시작 시 ``` 1. 이 문서의 📍 현재 진행 상태 확인 2. 해당 Phase 상세 절차 읽기 3. 관련 파일 읽기 4. "Phase X.X 시작할까요?" 확인 ``` ### 11.2 작업 중 ``` - 변경 이력 섹션에 실시간 기록 - Phase/항목별 상태 업데이트 (⏳ → 🔄 → ✅) - 컨펌 필요사항 → 컨펌 대기 목록에 추가 ``` ### 11.3 세션 종료 시 ``` - 📍 현재 진행 상태 업데이트 - 변경 이력에 최종 업데이트 기록 ``` --- *이 문서는 /sc:plan 스킬로 생성되었습니다. (2026-02-07)*