# 문서 스냅샷 아키텍처 계획 > **작성일**: 2026-03-06 > **목적**: 문서 보기/인쇄 시 HTML 스냅샷 기반 출력으로 전환 (B안 + 구조화 데이터 병행) > **상태**: 🔄 진행중 > **영향 범위**: API(저장), React(캡처/전송), MNG(출력) --- ## 현재 진행 상태 | 항목 | 내용 | |------|------| | **마지막 완료 작업** | Phase 0+1 (API) + Phase 3 (MNG 출력 로직) | | **다음 작업** | Phase 2: React HTML 캡처 및 전송 | | **진행률** | 7/10 (70%) | | **마지막 업데이트** | 2026-03-06 | --- ## 1. 개요 ### 1.1 배경 현재 MNG 문서 보기(`show.blade.php`)는 문서 양식별로 전용 blade partial을 만들어 렌더링한다: - `bending-inspection-data.blade.php` (절곡 중간검사) - `bending-worklog.blade.php` (절곡 작업일지) 이 방식의 문제: 1. **확장 불가**: 회사마다 다양한 양식이 존재 → 양식마다 blade 파일 생성 불가 2. **스냅샷 미보장**: 하드코딩된 제품 목록/도면치수가 정책 변경 시 과거 문서를 깨뜨림 3. **이중 렌더링**: React와 MNG에서 동일 문서를 각각 렌더링 → 불일치 발생 ### 1.2 목표 아키텍처 ``` [React] 문서 저장 시 ├── 구조화 데이터 저장 (기존 유지) │ ├── document_data (EAV 플랫) │ └── work_order_items.options.inspection_data (JSON 스냅샷) └── rendered_html 저장 (신규) └── React가 렌더링한 HTML을 캡처 → documents.rendered_html에 저장 [MNG] 문서 보기 시 ├── rendered_html 있으면 → 그대로 출력 (렌더링 로직 0) └── rendered_html 없으면 → 기존 동적 렌더링 fallback ``` ### 1.3 핵심 원칙 ``` 1. 하나의 view 파일로 모든 문서를 보기 (문서 양식별 blade 파일 금지) 2. rendered_html이 있으면 무조건 그것을 사용 (완전한 스냅샷) 3. 구조화 데이터는 편집/검색/통계용으로 병행 유지 4. React에서만 문서 렌더링 책임 → MNG는 출력만 담당 ``` ### 1.4 변경 승인 정책 | 분류 | 예시 | 승인 | |------|------|------| | 즉시 가능 | blade 템플릿 수정, 기존 partial 정리 | 불필요 | | 컨펌 필요 | API 저장 로직 변경, React 저장 흐름 변경 | **필수** | | 금지 | documents 테이블 구조 변경 (이미 rendered_html 존재) | 불필요 | --- ## 2. 현황 분석 ### 2.1 DB 현황 `documents` 테이블에 이미 `rendered_html` (LONGTEXT, nullable) 컬럼이 존재: - 마이그레이션: `api/database/migrations/2026_02_28_100001_add_block_data_to_documents.php` - 현재 값: 모든 문서에서 NULL (사용 안 됨) - **DB 변경 불필요** ### 2.2 React 현황 문서 저장 흐름 (`InspectionReportModal.tsx`): ``` handleSave() ├── contentRef.current.getInspectionData() → 구조화 데이터 추출 ├── 템플릿 모드: saveInspectionDocument(workOrderId, { data: records }) └── 레거시 모드: saveInspectionData(workOrderId, processType, data) ``` 현재 `rendered_html`을 전송하지 않음. 추가 필요: - 문서 DOM에서 HTML 캡처 → API 전송 시 포함 ### 2.3 API 현황 `DocumentService` / `DocumentController`: - `rendered_html` 필드를 받아서 저장하는 로직 없음 - Document 모델의 `$fillable`에 `rendered_html` 포함 여부 확인 필요 ### 2.4 MNG 현황 `show.blade.php`: - 문서 양식별 조건 분기 + 전용 partial include - `rendered_html` 출력 로직 없음 - 전용 partial 파일: - `partials/bending-inspection-data.blade.php` - `partials/bending-worklog.blade.php` --- ## 3. 작업 범위 ### Phase 0: 사전 정리 | # | 작업 항목 | 상태 | 비고 | |---|----------|:----:|------| | 0.1 | API Document 모델 $fillable 확인 및 rendered_html 추가 | ✅ | | | 0.2 | 기존 절곡 전용 partial 파일 정리 방침 결정 | ✅ | rendered_html 전환 후 삭제 | ### Phase 1: API - rendered_html 저장 지원 | # | 작업 항목 | 상태 | 비고 | |---|----------|:----:|------| | 1.1 | Document 모델 $fillable에 rendered_html 추가 | ✅ | | | 1.2 | DocumentService store/update에서 rendered_html 저장 | ✅ | | | 1.3 | StoreRequest/UpdateRequest에 rendered_html 검증 추가 | ✅ | nullable, string | | 1.4 | WorkOrderService inspection/worklog에 rendered_html 전달 | ✅ | create + update 모두 | ### Phase 2: React - HTML 캡처 및 전송 | # | 작업 항목 | 상태 | 비고 | |---|----------|:----:|------| | 2.1 | 문서 DOM에서 인라인 스타일 포함 HTML 캡처 유틸 | ⏳ | CSS 인라인화 필요 | | 2.2 | InspectionReportModal 저장 시 rendered_html 포함 전송 | ⏳ | | | 2.3 | 작업일지 저장 시 rendered_html 포함 전송 | ⏳ | WorkLogModal 등 | ### Phase 3: MNG - 스냅샷 출력 | # | 작업 항목 | 상태 | 비고 | |---|----------|:----:|------| | 3.1 | show.blade.php에 rendered_html 우선 출력 로직 추가 | ✅ | | | 3.2 | 기존 전용 partial 파일 fallback으로 유지 (과도기) | ✅ | | | 3.3 | print.blade.php에도 rendered_html 출력 적용 | ⏳ | | ### Phase 4: 검증 및 정리 | # | 작업 항목 | 상태 | 비고 | |---|----------|:----:|------| | 4.1 | 브라우저 검증 (MNG 보기/인쇄) | ⏳ | | | 4.2 | 기존 전용 partial 파일 삭제 | ⏳ | rendered_html 전환 완료 후 | --- ## 4. 상세 작업 내용 ### 4.1 HTML 캡처 방식 (Phase 2.1) React에서 문서 컨텐츠 영역의 DOM을 캡처할 때 고려사항: **방법 A: innerHTML 직접 추출 + CSS 인라인화** ```typescript // 문서 컨텐츠 영역에 ref 부여 const contentRef = useRef(null); // 저장 시 HTML 추출 const captureHtml = () => { const el = contentRef.current; if (!el) return ''; // Tailwind 클래스 → 인라인 스타일 변환 (또는 스타일시트 포함) // 방법 1: 계산된 스타일을 인라인으로 // 방법 2: 필요한 Tailwind CSS를 ``` **권장: 방법 B** — MNG에서 Tailwind가 로드되어 있으므로, Tailwind 클래스를 그대로 사용하되 MNG에 없는 커스텀 스타일만 `