# MNG 문서관리 시스템 상세 기술 명세

> **작성일**: 2026-03-06
> **상태**: 운영 중
> **프로젝트**: SAM MNG (관리자 웹)
> **관련**: [README.md](README.md) (API 명세)

---

## 1. 개요

### 1.1 목적

블라인드/스크린 제조 현장의 **검사 성적서, 작업일지, 수입검사 기록** 등 품질/생산 문서를 전자화하여 관리하는 시스템. 문서 양식(Template)을 정의하면 EAV 패턴으로 데이터를 동적 저장하며, 다단계 결재 워크플로우를 지원한다.

### 1.2 핵심 특징

| 특징 | 설명 |
|------|------|
| **EAV 패턴** | 양식별로 다른 필드를 하나의 `document_data` 테이블에 저장 |
| **2가지 양식 빌더** | 레거시 빌더 (DB 정규화) + 블록 빌더 (A4 JSON 스키마) |
| **결재 워크플로우** | 작성 → 검토 → 승인 (다단계 순차 결재) |
| **자동 데이터 매핑** | 작업지시서/수주 데이터에서 기본필드 자동 채움 |
| **다형성 연결** | work_order, sales_order 등 다양한 모델과 연결 |
| **자재 LOT 추적** | 검사 문서에서 투입 자재의 LOT 이력 조회 |

### 1.3 문서 구조

| 문서 | 설명 |
|------|------|
| [README.md](README.md) | API 엔드포인트, 모델 요약, FormRequest |
| **이 문서** | MNG 화면별 상세, 동작원리, 데이터 흐름 |

---

## 2. 메뉴/탭 구조

```
생산 관리
└── 문서관리
    ├── 문서 목록            /documents                   ← 문서 검색/필터/관리
    ├── 새 문서 작성         /documents/create             ← 템플릿 선택 → 폼 입력
    ├── 문서 상세            /documents/{id}               ← 읽기 전용 + 결재 현황
    ├── 문서 수정            /documents/{id}/edit          ← DRAFT/REJECTED만
    ├── 인쇄                /documents/{id}/print          ← 성적서 인쇄용
    │
    └── 문서양식 관리
        ├── 양식 목록        /document-templates           ← 양식 검색/관리
        ├── 새 양식 (레거시)  /document-templates/create    ← 레거시 빌더
        ├── 양식 수정         /document-templates/{id}/edit ← 자동 빌더 판별
        ├── 양식 디자이너     /document-templates/block-create   ← 블록 빌더
        └── 블록 수정         /document-templates/{id}/block-edit ← 블록 빌더 수정
```

---

## 3. 파일 구조

```
mng/
├── app/Http/Controllers/
│   ├── DocumentController.php                   ← 문서 CRUD 화면
│   └── DocumentTemplateController.php           ← 양식 관리 화면
├── app/Models/Documents/
│   ├── Document.php                             ← 문서 모델
│   ├── DocumentApproval.php                     ← 결재 단계
│   ├── DocumentData.php                         ← EAV 데이터
│   ├── DocumentTemplate.php                     ← 양식 마스터
│   └── ... (기타 템플릿 관련 모델)
└── resources/views/
    ├── documents/
    │   ├── index.blade.php                      ← 문서 목록
    │   ├── edit.blade.php                       ← 문서 작성/수정
    │   ├── show.blade.php                       ← 문서 상세
    │   └── print.blade.php                      ← 인쇄 전용
    └── document-templates/
        ├── index.blade.php                      ← 양식 목록
        ├── edit.blade.php                       ← 레거시 빌더
        ├── block-editor.blade.php               ← 블록 빌더
        └── partials/
            ├── block-palette.blade.php          ← 블록 타입 목록
            ├── block-canvas.blade.php           ← 편집 캔버스
            └── block-properties.blade.php       ← 속성 패널
```

---

## 4. 데이터베이스 아키텍처

### 4.1 테이블 관계도

```
document_templates (양식 마스터)
├── 1:N → document_template_approval_lines (결재선 정의)
├── 1:N → document_template_basic_fields (기본필드 정의)
├── 1:N → document_template_sections (섹션 정의)
│         └── 1:N → document_template_section_items (검사항목)
├── 1:N → document_template_columns (테이블 컬럼 정의)
├── 1:N → document_template_section_fields (섹션 필드)
├── 1:N → document_template_links (외부 연결 정의)
│         └── 1:N → document_template_link_values (템플릿 레벨 연결값)
│
└── 1:N → documents (문서 인스턴스)
          ├── 1:N → document_approvals (결재 진행)
          ├── 1:N → document_data (EAV 필드값)
          ├── 1:N → document_attachments (첨부파일)
          └── 1:N → document_links (문서 레벨 연결)
```

### 4.2 documents (문서)

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `id` | BIGINT PK | |
| `tenant_id` | BIGINT FK | 테넌트 격리 |
| `template_id` | BIGINT FK | 사용 양식 |
| `document_no` | VARCHAR UNIQUE | 문서번호 (자동 채번) |
| `title` | VARCHAR | 문서 제목 |
| `status` | VARCHAR(20) | 상태 (5가지) |
| `linkable_type` | VARCHAR NULL | 다형성 모델 타입 |
| `linkable_id` | BIGINT NULL | 다형성 모델 ID |
| `submitted_at` | TIMESTAMP NULL | 결재 요청 일시 |
| `completed_at` | TIMESTAMP NULL | 결재 완료 일시 |
| `created_by` | BIGINT FK | 작성자 |
| `deleted_at` | TIMESTAMP NULL | 소프트 삭제 |

**인덱스**: `(tenant_id, status)`, `document_no`, `(linkable_type, linkable_id)`

### 4.3 document_data (EAV 필드값)

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `id` | BIGINT PK | |
| `document_id` | BIGINT FK | 소속 문서 |
| `section_id` | BIGINT FK NULL | 소속 섹션 (NULL=기본필드) |
| `column_id` | BIGINT FK NULL | 소속 컬럼 (테이블 데이터용) |
| `row_index` | INT | 테이블 행 번호 (기본: 0) |
| `field_key` | VARCHAR | 필드 식별자 (`bf_1`, `cf_2`, `col_3`) |
| `field_value` | TEXT NULL | 실제 값 |

**인덱스**: `(document_id, section_id)`, `(document_id, field_key)`

### 4.4 document_approvals (결재)

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `id` | BIGINT PK | |
| `document_id` | BIGINT FK | 소속 문서 |
| `user_id` | BIGINT FK | 결재자 |
| `step` | INT | 결재 순서 (1, 2, 3...) |
| `role` | VARCHAR | 역할 (작성, 검토, 승인) |
| `status` | VARCHAR(20) | PENDING / APPROVED / REJECTED |
| `comment` | TEXT NULL | 결재 의견 |
| `acted_at` | TIMESTAMP NULL | 처리 일시 |

**인덱스**: `(document_id, step)`, `(user_id, status)`

### 4.5 document_attachments (첨부파일)

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `document_id` | BIGINT FK | 소속 문서 |
| `file_id` | BIGINT FK | File 모델 연결 |
| `attachment_type` | VARCHAR | `general`, `signature`, `image`, `reference` |
| `description` | VARCHAR NULL | 설명 |
| `created_by` | BIGINT FK | 업로드자 |

---

## 5. 양식(Template) 시스템

### 5.1 두 가지 빌더 방식

| 방식 | 필드명 | 저장 구조 | UI | 상태 |
|------|--------|----------|-----|------|
| **레거시 빌더** | `builder_type = null` | 정규화 테이블들 | `edit.blade.php` | 기존 양식용 |
| **블록 빌더** | `builder_type = 'block'` | `schema` JSON | `block-editor.blade.php` | 신규 양식용 |

**자동 판별 로직:**

```php
// DocumentTemplateController::edit()
if ($template->isBlockBuilder()) {
    return $this->blockEdit($id);    // block-editor.blade.php
} else {
    return view('document-templates.edit');  // 레거시
}
```

### 5.2 양식 마스터 (document_templates)

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `name` | VARCHAR | 양식명 (예: "제품검사 성적서") |
| `category` | VARCHAR | 분류 (common_codes 기반) |
| `title` | VARCHAR NULL | 문서 제목 템플릿 |
| `company_name` | VARCHAR NULL | 회사명 |
| `company_address` | VARCHAR NULL | 회사 주소 |
| `company_contact` | VARCHAR NULL | 연락처 |
| `footer_remark_label` | VARCHAR NULL | 비고란 라벨 |
| `footer_judgement_label` | VARCHAR NULL | 판정란 라벨 |
| `footer_judgement_options` | JSON NULL | 판정 선택지 (적합/부적합) |
| `builder_type` | VARCHAR NULL | `block` 또는 NULL |
| `schema` | JSON NULL | 블록 빌더 JSON 스키마 |
| `page_config` | JSON NULL | 페이지 설정 (A4, 여백 등) |
| `is_active` | BOOLEAN | 활성 여부 |

### 5.3 레거시 빌더 구성 요소

#### 결재선 (document_template_approval_lines)

```
step 1: 작성 (작성자 본인)
step 2: 검토 (팀장)
step 3: 승인 (부장)
```

| 컬럼 | 설명 |
|------|------|
| `name` | 라벨 (작성, 검토, 승인) |
| `dept` | 부서 |
| `role` | 역할 |
| `sort_order` | 순서 |

#### 기본필드 (document_template_basic_fields)

문서 상단의 고정 필드 영역.

| 컬럼 | 설명 |
|------|------|
| `label` | 필드 라벨 (품명, LOT NO, 납기일 등) |
| `field_key` | 식별자 (EAV 저장 시 사용) |
| `field_type` | 입력 타입 (text, date, number, item_search) |
| `default_value` | 기본값 |
| `sort_order` | 순서 |

**EAV 저장 시 field_key 패턴:**

```
bf_1 → 기본필드 ID 1 (예: 품명)
bf_2 → 기본필드 ID 2 (예: LOT NO)
bf_3 → 기본필드 ID 3 (예: 납기일)
```

#### 섹션 (document_template_sections)

검사 기준서의 섹션 단위.

| 컬럼 | 설명 |
|------|------|
| `title` | 섹션 제목 (예: "겉모양 검사", "치수 검사") |
| `image_path` | 도해 이미지 경로 (검사 부위 도면) |
| `sort_order` | 순서 |

#### 검사항목 (document_template_section_items)

각 섹션 내의 개별 검사항목.

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `category` | VARCHAR | 구분 (겉모양, 치수, 재질) |
| `item` | VARCHAR | 검사항목명 |
| `standard` | VARCHAR | 검사기준 (100mm ±5mm) |
| `tolerance` | JSON NULL | 허용오차 (min/max) |
| `standard_criteria` | VARCHAR NULL | 판정기준 |
| `method` | VARCHAR | 검사방법 (육안, 측정) |
| `measurement_type` | VARCHAR NULL | 측정 유형 |
| `frequency_n` | INT NULL | 검사건수 N |
| `frequency_c` | INT NULL | 합격건수 C |
| `frequency` | VARCHAR NULL | 검사빈도 텍스트 |
| `field_values` | JSON NULL | 확장 필드 (마이그레이션 없이 추가) |

#### 테이블 컬럼 (document_template_columns)

검사 데이터 테이블의 컬럼 정의.

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `label` | VARCHAR | 컬럼 라벨 |
| `width` | INT NULL | 너비 (px) |
| `column_type` | VARCHAR | `text`, `check`, `complex`, `measurement`, `select` |
| `group_name` | VARCHAR NULL | 상단 병합 헤더명 |
| `sub_labels` | JSON NULL | complex 타입 하위 라벨 |
| `sort_order` | INT | 순서 |

**컬럼 타입 상세:**

| 타입 | 설명 | 예시 |
|------|------|------|
| `text` | 단순 텍스트 입력 | 비고, 메모 |
| `check` | 체크박스 (합격/부적합) | 외관 검사 합격 여부 |
| `complex` | 여러 서브필드 조합 | 측정값 + 단위 + 판정 |
| `measurement` | 수치 입력 | 길이: 100.5mm |
| `select` | 드롭다운 선택 | 판정: 합격/불합격/보류 |

#### 외부 연결 (document_template_links)

템플릿에서 외부 테이블 데이터를 참조하기 위한 정의.

| 컬럼 | 설명 |
|------|------|
| `link_key` | 연결 식별자 |
| `label` | 화면 라벨 |
| `link_type` | `single` (1개 선택) / `multiple` (다중 선택) |
| `source_table` | 소스 테이블 (`items`, `processes`, `users`) |
| `search_params` | API 검색 추가 조건 (JSON) |
| `display_fields` | 표시 필드 (title, subtitle) |
| `is_required` | 필수 여부 |

### 5.4 블록 빌더 구조

**페이지 설정 (page_config):**

```json
{
    "size": "A4",
    "orientation": "portrait",
    "margin": {
        "top": 20,
        "right": 15,
        "bottom": 20,
        "left": 15
    }
}
```

**스키마 (schema):**

블록 배열로 레이아웃 정의. 드래그앤드롭으로 편집.

```json
{
    "blocks": [
        { "type": "text", "x": 0, "y": 0, "width": 100, "content": "검사 성적서" },
        { "type": "table", "x": 0, "y": 50, "columns": [...], "rows": [...] },
        { "type": "image", "x": 200, "y": 100, "src": "..." }
    ]
}
```

**블록 빌더 UI (3패널):**

```
┌──────────┬────────────────────┬──────────┐
│ 블록     │                    │ 속성     │
│ 팔레트   │     A4 캔버스       │ 패널     │
│          │                    │          │
│ [텍스트]  │  ┌──────────────┐  │ 너비: _  │
│ [이미지]  │  │ 드래그앤드롭   │  │ 높이: _  │
│ [표]     │  │ 블록 배치      │  │ 색상: _  │
│ [선]     │  │              │  │ 폰트: _  │
│ [도형]   │  └──────────────┘  │          │
└──────────┴────────────────────┴──────────┘
```

---

## 6. EAV 데이터 저장 패턴

### 6.1 핵심 개념

하나의 `document_data` 테이블에 **모든 양식의 모든 필드값**을 저장. 양식이 다르면 field_key가 다르고, 같은 양식이라도 섹션/행이 다르면 section_id/row_index로 구분.

### 6.2 저장 구조

```
document_data 레코드 예시:

기본필드 (상단 고정 영역):
┌─────────────┬────────────┬───────────┬───────────┬───────────┬─────────────┐
│ document_id │ section_id │ column_id │ row_index │ field_key │ field_value │
├─────────────┼────────────┼───────────┼───────────┼───────────┼─────────────┤
│ 42          │ NULL       │ NULL      │ 0         │ bf_1      │ 블라인드A   │ ← 품명
│ 42          │ NULL       │ NULL      │ 0         │ bf_2      │ LOT-2026-001│ ← LOT NO
│ 42          │ NULL       │ NULL      │ 0         │ bf_3      │ 2026-03-15  │ ← 납기일
├─────────────┼────────────┼───────────┼───────────┼───────────┼─────────────┤

테이블 데이터 (섹션별 검사 결과):
│ 42          │ 10         │ 20        │ 0         │ col_20    │ 합격        │ ← 섹션10, 컬럼20, 1행
│ 42          │ 10         │ 20        │ 1         │ col_20    │ 부적합      │ ← 섹션10, 컬럼20, 2행
│ 42          │ 10         │ 21        │ 0         │ col_21    │ 100.5       │ ← 섹션10, 컬럼21, 1행
└─────────────┴────────────┴───────────┴───────────┴───────────┴─────────────┘
```

### 6.3 field_key 네이밍 규칙

| 접두사 | 의미 | 예시 |
|--------|------|------|
| `bf_` | 기본필드 (BasicField) | `bf_1`, `bf_2` |
| `cf_` | 섹션필드 (SectionField) | `cf_5`, `cf_6` |
| `col_` | 컬럼 데이터 | `col_20`, `col_21` |

### 6.4 데이터 조회 패턴

```php
// 기본필드 값 조회
$data = DocumentData::where('document_id', $id)
    ->whereNull('section_id')
    ->get()
    ->keyBy('field_key');

$productName = $data['bf_1']->field_value;

// 섹션별 테이블 데이터 조회
$rows = DocumentData::where('document_id', $id)
    ->where('section_id', $sectionId)
    ->get()
    ->groupBy('row_index');
```

---

## 7. 결재 워크플로우

### 7.1 상태 전이

```
DRAFT (작성중)
    │
    ├── submit() → PENDING (결재중)
    │                 │
    │                 ├── approve() [step 1] → 다음 step 대기
    │                 ├── approve() [step 2] → 다음 step 대기
    │                 ├── approve() [마지막] → APPROVED (승인)
    │                 │
    │                 └── reject() → REJECTED (반려)
    │                                   │
    │                                   └── edit → submit() → PENDING (재요청)
    │
    └── cancel() → CANCELLED (취소)
```

### 7.2 상태값 및 라벨

| 코드 | 라벨 | 색상 | 편집 가능 |
|------|------|------|----------|
| `DRAFT` | 작성중 | gray | 예 |
| `PENDING` | 결재중 | yellow | 아니오 |
| `APPROVED` | 승인 | green | 아니오 |
| `REJECTED` | 반려 | red | 예 (수정 후 재요청) |
| `CANCELLED` | 취소 | gray | 아니오 |

### 7.3 결재 단계 (Approval)

```
DocumentTemplateApprovalLine (양식 정의)
    ↓ (문서 생성 시 복사)
DocumentApproval (문서별 결재 레코드)

step 1: 작성 → PENDING → 결재자 승인 → APPROVED
step 2: 검토 → PENDING → 결재자 승인 → APPROVED
step 3: 승인 → PENDING → 결재자 승인 → APPROVED → 문서 전체 APPROVED
```

### 7.4 결재 판단 메서드

```php
// Document 모델
canEdit()     // DRAFT 또는 REJECTED
canSubmit()   // DRAFT 또는 REJECTED
canApprove()  // PENDING (현재 결재자만)
canCancel()   // DRAFT 또는 PENDING (작성자만)
```

---

## 8. 자동 데이터 매핑

### 8.1 개요

문서 작성/수정 시, 연결된 작업지시서(work_order)/수주(order) 데이터에서 기본필드를 **자동으로 채움**. 사용자 입력 부담을 줄이고 데이터 정확성을 보장.

### 8.2 검사 성적서 매핑 (field_key 기반)

| field_key | 라벨 | 소스 |
|-----------|------|------|
| `product_name` | 품명 | `workOrderItem.item_name` |
| `specification` | 규격 | `workOrderItem.specification` |
| `lot_no` | LOT NO | `order.order_no` |
| `lot_size` | LOT 크기 | `"N 개소"` (개소 수 기반) |
| `client` | 발주처 | `order.client_name` |
| `site_name` | 현장명 | `workOrder.project_name` |
| `inspection_date` | 검사일 | `workOrderItem.options.inspection_data.inspected_at` |
| `inspector` | 검사자 | 검사자 이름 |

### 8.3 작업일지 매핑 (label 기반)

| label 포함 문자열 | 소스 |
|------------------|------|
| `발주처` | `order.client_name` |
| `현장명` | `workOrder.project_name` |
| `작업일자` | `now()` |
| `LOT NO`, `LOT` | `order.order_no` |
| `납기일`, `납기` | `order.delivery_date` |
| `작업지시번호` | `workOrder.work_order_no` |
| `수주일` | `order.received_at` 또는 `order.created_at` |

### 8.4 자동 매핑 흐름

```
문서 작성/수정 페이지 로드
    ↓
DocumentController::edit()
    ↓
resolveAndBackfillBasicFields($template, $document)
    ↓
linkable_type 확인 (work_order? order?)
    ↓
field_key 또는 label 매칭
    ↓
DB에 값이 없으면 → 소스 데이터에서 resolve
    ↓
뷰에 자동 채움된 값 전달
```

---

## 9. 자재 LOT 추적

### 9.1 개요

검사 성적서에서 해당 작업지시의 **투입 자재 LOT 이력**을 조회. `stock_transactions` 테이블의 OUT(투입)/IN(취소) 트랜잭션을 상쇄하여 순수 투입량을 계산.

### 9.2 추적 구조

```
work_orders (작업지시)
    │
    ├── stock_transactions (재고 트랜잭션)
    │   ├── OUT (투입): qty < 0
    │   └── IN (취소/반납): qty > 0
    │   → 순수 투입량 = ABS(SUM(qty)) where qty < 0
    │
    └── work_order_material_inputs (개소별 투입자재)
        └── stock_lots (LOT 정보) JOIN
```

### 9.3 표시 내용

| 항목 | 설명 |
|------|------|
| 자재명 | 투입된 원자재/부자재 이름 |
| LOT 번호 | 자재의 LOT 식별 번호 |
| 투입 수량 | OUT 트랜잭션 합계 (절대값) |
| 투입일 | 트랜잭션 일시 |

---

## 10. 화면별 상세

### 10.1 문서 목록 (/documents)

**필터 항목:**

| 필터 | 타입 | 설명 |
|------|------|------|
| 검색 | text | 문서번호 또는 제목 |
| 상태 | dropdown | DRAFT, PENDING, APPROVED, REJECTED, CANCELLED, 휴지통(admin) |
| 양식분류 | dropdown | category |
| 템플릿 | dropdown | template_id |
| 날짜 범위 | date | created_at (from ~ to) |

**목록 테이블 컬럼:**

```
문서번호 | 제목 | 양식 | 상태 | 작성자 | 작성일 | 결재현황
```

### 10.2 문서 작성/수정 (/documents/create, /documents/{id}/edit)

**폼 구성:**

```
┌──────────────────────────────────────────────┐
│ 템플릿 선택 (읽기전용)                          │
│ 제목 (필수)                                   │
├──────────────────────────────────────────────┤
│ 기본 필드 (template.basicFields)              │
│ ┌─────────────────┬─────────────────┐        │
│ │ 품명: [자동채움]  │ LOT NO: [자동]   │        │
│ │ 납기일: [날짜]    │ 발주처: [자동]   │        │
│ └─────────────────┴─────────────────┘        │
├──────────────────────────────────────────────┤
│ 섹션 1: 겉모양 검사                             │
│ ┌──────────────────────────────────────┐     │
│ │ 도해 이미지 (있으면)                    │     │
│ ├──────┬──────┬──────┬──────┬──────┤     │
│ │ 구분 │ 항목 │ 기준 │ 결과1│ 결과2│     │
│ ├──────┼──────┼──────┼──────┼──────┤     │
│ │ 치수 │ 길이 │±5mm  │ [  ] │ [  ] │     │
│ │ 외관 │ 흠집 │ 없음 │ [✓] │ [✓] │     │
│ ├──────┴──────┴──────┴──────┴──────┤     │
│ │ [+ 행 추가]              [행 삭제] │     │
│ └──────────────────────────────────────┘     │
├──────────────────────────────────────────────┤
│ 외부 연결 (template.links)                     │
│ 품목 선택: [검색 드롭다운]                       │
├──────────────────────────────────────────────┤
│ 첨부파일                                      │
│ [일반 문서] [서명 이미지] [검사 사진] [참고 자료]  │
├──────────────────────────────────────────────┤
│ [임시저장] [결재 요청]                          │
└──────────────────────────────────────────────┘
```

### 10.3 문서 상세 (/documents/{id})

**읽기 전용 표시:**

```
┌──────────────────────────────────────────────┐
│ 문서번호: DOC-260306-001    상태: [🟢 승인]    │
│ 제목: 블라인드A 검사 성적서                      │
├──────────────────────────────────────────────┤
│ 기본 필드 (읽기 전용)                           │
├──────────────────────────────────────────────┤
│ 검사 데이터 테이블 (읽기 전용)                    │
├──────────────────────────────────────────────┤
│ 결재 현황                                     │
│ ┌────────┬────────┬────────┐                │
│ │ 작성   │ 검토   │ 승인   │                │
│ │ 홍길동  │ 김과장  │ 박부장  │                │
│ │ ✓승인  │ ✓승인  │ ●대기  │                │
│ └────────┴────────┴────────┘                │
├──────────────────────────────────────────────┤
│ 자재 투입 LOT (작업지시 연결 시)                 │
│ ┌────────┬──────────┬──────┬──────┐         │
│ │ 자재명 │ LOT 번호  │ 수량 │ 투입일│         │
│ └────────┴──────────┴──────┴──────┘         │
├──────────────────────────────────────────────┤
│ 첨부파일 목록                                  │
├──────────────────────────────────────────────┤
│ [수정] [인쇄] [결재 승인] [결재 반려]             │
└──────────────────────────────────────────────┘
```

### 10.4 인쇄 (/documents/{id}/print)

성적서 형식의 인쇄 전용 화면. `window.print()` 호출. 작업지시 관련 자재(work_order_items) 데이터 포함.

### 10.5 양식 목록 (/document-templates)

**필터:**
- 검색: 양식명, 제목, 분류
- 카테고리: common_codes 기반 + 기존 데이터 폴백
- 활성 상태: 활성 / 비활성 / 휴지통(admin)

**HTMX**: 필터 변경 시 테이블 영역만 부분 로드

---

## 11. 첨부파일 유형

| 유형 | 코드 | 용도 | 예시 |
|------|------|------|------|
| 일반 문서 | `general` | PDF, 엑셀 등 | 규격서, 보고서 |
| 서명 이미지 | `signature` | 검사 완료 서명 | 검사자 서명 사진 |
| 검사 사진 | `image` | 검사 증빙 사진 | 불량 부위 촬영 |
| 참고 자료 | `reference` | 참고용 문서 | KS 규격, 작업 지침 |

---

## 12. API 연동 (MNG → API)

MNG 뷰에서 데이터 저장/삭제는 **API 서버를 호출**하여 처리. GET 요청(뷰 렌더링)은 MNG 컨트롤러가 직접 처리.

| 작업 | MNG (GET 요청) | API (POST/PUT/DELETE) |
|------|---------------|----------------------|
| 목록 조회 | `DocumentController::index()` | `GET /v1/documents` |
| 상세 조회 | `DocumentController::show()` | `GET /v1/documents/{id}` |
| 생성 | 폼 표시만 | `POST /v1/documents` |
| 수정 | 폼 표시만 | `PATCH /v1/documents/{id}` |
| 삭제 | - | `DELETE /v1/documents/{id}` |
| 결재 요청 | - | `POST /v1/documents/{id}/submit` |
| 승인 | - | `POST /v1/documents/{id}/approve` |
| 반려 | - | `POST /v1/documents/{id}/reject` |

---

## 13. 카테고리 해결 로직

양식 카테고리는 **common_codes 테이블**에서 조회하되, 없으면 **기존 데이터에서 추출**하여 폴백.

```php
// DocumentTemplateController::getCategories()
$categories = CommonCode::where('group', 'document_category')
    ->orderBy('sort_order')
    ->get();

if ($categories->isEmpty()) {
    // 폴백: 기존 템플릿의 category 값에서 중복 제거
    $categories = DocumentTemplate::distinct('category')
        ->pluck('category')
        ->filter();
}
```

---

## 14. 검사항목 확장 (field_values JSON)

`document_template_section_items.field_values` JSON 컬럼으로 마이그레이션 없이 새 필드를 추가할 수 있다.

```json
{
    "custom_field_1": "추가 기준값",
    "min_value": 95.0,
    "max_value": 105.0,
    "unit": "mm"
}
```

> options JSON 컬럼 정책(`docs/standards/options-column-policy.md`) 준용

---

## 15. HTMX 전체 페이지 로드 규칙

문서관리 페이지들은 JavaScript를 사용하므로 HTMX 부분 로드 시 스크립트 미실행 문제가 있다. 컨트롤러에서 HX-Request 감지 시 **HX-Redirect로 전체 페이지 리로드 강제**.

```php
if ($request->header('HX-Request')) {
    return response('', 200)->header('HX-Redirect', route('documents.index'));
}
```

---

## 관련 문서

- [README.md](README.md) — API 엔드포인트, 모델 요약, FormRequest
- [DB 스키마 — 문서/전자서명](../../system/database/documents.md) — 테이블 상세
- [게시판 시스템](../boards/README.md) — 유사한 EAV 패턴 참고
- [결재관리 시스템](../approvals/README.md) — 별도 결재 시스템 (문서관리와 독립)

---

**최종 업데이트**: 2026-03-06
