Files
sam-docs/dev/dev_plans/qms-checklist-template-plan.md

24 KiB

QMS 점검표 템플릿 관리 기능 구현 계획

작성일: 2026-03-11 목적: QMS 설정 모달 내 점검표 CRUD + 파일 업로드를 Mock → 실제 API 연동으로 전환 기준 커밋: e9ac2470 (프론트 Mock 구현 완료) 관련 문서: docs/dev/dev_plans/qms-api-integration-plan.md (상위 QMS 계획) 상태: 구현 완료


📍 현재 진행 상태

항목 내용
마지막 완료 작업 Phase 3: 프론트엔드 API 연동 + 버전 UI 제거
다음 작업 검증 (마이그레이션 실행 + 동작 확인)
진행률 12/12 (100%)
마지막 업데이트 2026-03-11

1. 개요

1.1 배경

QMS 페이지(/quality/qms)의 설정 모달에 점검표 관리 탭이 커밋 e9ac2470으로 추가되었다. 현재 USE_MOCK = true 상태로 프론트 UI만 동작하며, 백엔드 API 연동이 필요하다.

추가로 프론트엔드 개선이 필요:

  1. 점검표 항목 섹션 기본 전체 펼침: expandAllCategories 설정값과 Day1ChecklistPanel 연동
  2. 점검표 항목별 파일 업로드: Day1DocumentSection의 파일 업로드 실제 서버 전송

1.2 버전 관리 정책

┌─────────────────────────────────────────────────────────────────┐
│  ⚠️ 버전 관리 제외                                               │
├─────────────────────────────────────────────────────────────────┤
│  - 이번 구현에서 버전 관리는 하지 않음                             │
│  - 버전은 항상 V1 고정                                           │
│  - 저장 시 토스트: "저장 완료" (버전 번호 없음)                     │
│  - VersionSelectBox, 버전 복원 기능 제거                          │
│  - checklist_template_versions 테이블 생성하지 않음                │
└─────────────────────────────────────────────────────────────────┘

1.3 현재 구현 상태 (커밋 e9ac2470 기준)

파일 역할 상태
ChecklistTemplateEditor.tsx (605줄) 카테고리/항목 CRUD, 순서변경, 인라인 편집, 버전 셀렉트박스 UI 완성 (Mock) → ⚠️ 버전 UI 제거 필요
useChecklistTemplate.ts (218줄) 상태관리, CRUD 로직, 저장/초기화/복원 Mock 로직 완성 → ⚠️ 버전/복원 로직 제거 필요
AuditSettingsPanel.tsx (314줄) 화면설정 + 점검표관리 2탭 구조 탭 구조 완성
Day1DocumentSection.tsx (+155줄) 파일 업로드 드래그&드롭 + 검증 UI 완성 (Mock)
types.ts (+19줄) ChecklistTemplateVersion, ChecklistTemplate 타입 ⚠️ 버전 타입 제거 필요
page.tsx (+24줄) useChecklistTemplate 훅 연결 ⚠️ 버전 관련 props 제거 필요

1.4 미구현 항목 (이번 계획 범위)

# 항목 설명
1 백엔드 테이블 checklist_templates + qms_documents 2개 (categories JSON 포함)
2 백엔드 API GET + PUT + 파일 업로드 엔드포인트
3 Server Actions quality/qms/actions.ts 신규 생성
4 useChecklistTemplate → API 전환 USE_MOCK = false, 실제 API 호출
5 파일 업로드 서버 전송 Day1DocumentSection.onFileUpload 실제 구현
6 점검표 편집 → 심사화면 반영 editCategories 저장 후 categories 갱신 연결
7 expandAllCategories 설정 연동 설정값 변경 시 Day1ChecklistPanel 반영
8 프론트 버전 UI 제거 VersionSelectBox 제거, 버전 관련 props/타입 정리

1.5 기준 원칙

┌─────────────────────────────────────────────────────────────────┐
│  🎯 핵심 원칙                                                    │
├─────────────────────────────────────────────────────────────────┤
│  - Service-First: 비즈니스 로직은 Service에 구현                  │
│  - Multi-tenancy: BelongsToTenant 필수                           │
│  - options JSON: 점검표 카테고리 데이터는 JSON 컬럼에 저장          │
│  - 파일 업로드: 기존 files 테이블 + tenant disk 활용               │
│  - Mock→API: USE_MOCK 플래그 OFF로 점진적 전환                    │
│  - 단순 저장: 버전 관리 없이 현재 상태만 덮어쓰기                   │
└─────────────────────────────────────────────────────────────────┘

1.6 변경 승인 정책

분류 예시 승인
즉시 가능 프론트 props 추가, 타입 확장, actions.ts 생성, 버전 UI 제거 불필요
⚠️ 컨펌 필요 마이그레이션 생성, 새 서비스/컨트롤러, API 엔드포인트 필수
🔴 금지 기존 테이블 구조 변경, 기존 API 동작 변경 별도 협의

1.7 준수 규칙

  • docs/dev/standards/api-rules.md — API 개발 규칙
  • docs/dev/standards/quality-checklist.md — 품질 체크리스트
  • docs/dev/guides/file-storage-guide.md — 파일 업로드 가이드
  • docs/dev/standards/options-column-policy.md — JSON options 정책

2. 대상 범위

2.1 Phase 1: 백엔드 — 테이블 설계 + 마이그레이션 (api/)

# 작업 항목 상태 비고
1.1 checklist_templates 테이블 마이그레이션 categories JSON 포함 + 초기 데이터 시딩
1.2 Model 생성 (ChecklistTemplate) BelongsToTenant

2.2 Phase 2: 백엔드 — Service + Controller + API (api/)

# 작업 항목 상태 비고
2.1 ChecklistTemplateService 생성 조회 + 저장 + 항목삭제 시 파일 처리
2.2 ChecklistTemplateController 생성
2.3 SaveChecklistTemplateRequest FormRequest 생성 중첩 JSON 검증 규칙 포함
2.4 파일 업로드 API (기존 files 시스템 polymorphic 활용) document_type + field_key + 서버 측 검증
2.5 라우트 등록
2.6 Swagger 문서

2.3 Phase 3: 프론트엔드 — API 연동 + 버전 UI 제거 (react/)

# 작업 항목 상태 비고
3.1 버전 관련 UI/타입/로직 제거 VersionSelectBox, 버전 props 등
3.2 quality/qms/actions.ts Server Actions 생성
3.3 useChecklistTemplate.ts API 전환 USE_MOCK = false, isLoading/error 상태 추가
3.4 파일 업로드 실제 연동 Day1DocumentSection
3.5 expandAllCategories 설정 ↔ Day1ChecklistPanel 연동 props 전달

3. 작업 절차

3.1 단계별 절차

Phase 1: 백엔드 테이블 (api/)
├── 1.1 checklist_templates 마이그레이션 (categories JSON 포함)
├── 1.2 qms_documents 마이그레이션 (파일-항목 연결)
├── 1.3 ChecklistTemplate 모델 생성
└── 1.4 QmsDocument 모델 생성

Phase 2: 백엔드 API (api/)
├── 2.1 ChecklistTemplateService (getOrCreate + 저장 + 항목삭제 시 파일 처리)
├── 2.2 ChecklistTemplateController + SaveChecklistTemplateRequest
├── 2.3 QmsDocumentService + QmsDocumentController (서버 측 파일 검증)
├── 2.4 라우트 등록 (/api/v1/quality/checklist-templates/*, /api/v1/quality/qms-documents/*)
└── 2.5 Swagger 문서

Phase 3: 프론트엔드 (react/)
├── 3.1 버전 관련 UI/타입/로직 제거
├── 3.2 actions.ts 생성 (Server Actions)
├── 3.3 useChecklistTemplate → API 전환 (isLoading/error 상태 추가)
├── 3.4 파일 업로드 연동
└── 3.5 expandAllCategories 설정 연동

4. 상세 설계

4.1 테이블 설계

checklist_templates (점검표 템플릿)

CREATE TABLE checklist_templates (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    tenant_id BIGINT NOT NULL,

    name VARCHAR(255) NOT NULL DEFAULT '품질인정심사 점검표',
    type VARCHAR(50) NOT NULL DEFAULT 'day1_audit',  -- 심사 유형 구분
    categories JSON NOT NULL,   -- [{ id, title, subItems: [{ id, name }] }]

    options JSON NULL,       -- 확장 속성

    created_by BIGINT NULL,
    updated_by BIGINT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL,

    FOREIGN KEY (tenant_id) REFERENCES tenants(id),
    FOREIGN KEY (created_by) REFERENCES users(id),
    FOREIGN KEY (updated_by) REFERENCES users(id),
    INDEX idx_tenant_type (tenant_id, type),
    UNIQUE KEY unique_tenant_type (tenant_id, type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

⚠️ UNIQUE KEY에 deleted_at 미포함: MySQL에서 NULL은 UNIQUE 제약에서 제외되므로, deleted_at 포함 시 active 레코드 중복 방지 불가. soft delete는 글로벌 스코프로 처리.

파일-항목 연결 (files 테이블 polymorphic 활용)

기존 files 테이블의 컬럼을 활용하여 점검항목별 파일을 연결:
- document_type = 'checklist_template'
- document_id   = checklist_templates.id
- field_key     = sub_item_id (e.g. "sub-1-1")

별도 qms_documents 테이블 불필요 — files 테이블의 document_type + document_id + field_key 조합으로 연결. 항목 삭제 시: Service에서 삭제된 sub_item_id의 파일을 soft delete. 문서 교체 시: 기존 파일 즉시 삭제 (hard delete).

설계 결정 사항:

  • checklist_templates 1개 테이블만 신규 생성
  • categoriesJSON 컬럼에 저장 — 카테고리/하위항목을 별도 테이블로 분리하지 않음
    • 이유: 점검표는 항상 전체 로드, 개별 카테고리 쿼리 불필요
  • 파일 연결: files 테이블 polymorphic (document_type + document_id + field_key)
  • type 컬럼으로 향후 다른 심사 유형(day2 등) 확장 가능
  • 저장 = categories JSON 덮어쓰기 (PUT)
  • updated_by로 마지막 수정자 추적
  • 항목 삭제 시: files soft delete → 휴지통에서 최종 삭제
  • 문서 교체 시: 기존 파일 즉시 삭제 (hard delete)

4.2 API 엔드포인트

점검표 CRUD:

Method Path 설명
GET /api/v1/quality/checklist-templates?type=day1_audit 템플릿 조회
PUT /api/v1/quality/checklist-templates/{id} 템플릿 저장 (덮어쓰기)

파일 업로드 (기존 파일 시스템 활용):

Method Path 설명
POST /api/v1/quality/qms-documents 점검항목별 문서 업로드
GET /api/v1/quality/qms-documents?sub_item_id={id} 항목별 문서 조회
DELETE /api/v1/quality/qms-documents/{id} 문서 삭제

4.3 API 요청/응답 구조

GET 템플릿 조회

// Response
{
  "success": true,
  "data": {
    "id": 1,
    "name": "품질인정심사 점검표",
    "type": "day1_audit",
    "categories": [
      {
        "id": "cat-1",
        "title": "1. 품질경영 일반",
        "subItems": [
          { "id": "sub-1-1", "name": "품질방침 및 품질목표 수립" },
          { "id": "sub-1-2", "name": "조직도 및 업무분장" }
        ]
      }
    ],
    "updated_at": "2026-03-10T15:30:00",
    "updated_by_name": "홍길동"
  }
}

PUT 템플릿 저장

// Request
{
  "categories": [
    {
      "id": "cat-1",
      "title": "1. 품질경영 일반",
      "subItems": [
        { "id": "sub-1-1", "name": "품질방침 및 품질목표 수립" },
        { "id": "sub-1-2", "name": "조직도 및 업무분장" }
      ]
    }
  ]
}

// Response
{
  "success": true,
  "message": "저장 완료"
}

4.4 FormRequest 검증 규칙

SaveChecklistTemplateRequest

public function rules(): array
{
    return [
        'categories' => 'required|array|min:1',
        'categories.*.id' => 'required|string|max:50',
        'categories.*.title' => 'required|string|max:255',
        'categories.*.subItems' => 'required|array',
        'categories.*.subItems.*.id' => 'required|string|max:50',
        'categories.*.subItems.*.name' => 'required|string|max:255',
    ];
}

XSS 방지: title, name 필드에 HTML 태그 삽입 방지 (strip_tags 또는 커스텀 Rule)

UploadQmsDocumentRequest

public function rules(): array
{
    return [
        'template_id' => 'required|integer|exists:checklist_templates,id',
        'sub_item_id' => 'required|string|max:50',
        'file' => 'required|file|max:20480|mimes:pdf,xlsx,xls,docx,doc,hwp',
    ];
}

서버 측 파일 타입 + 크기 검증 필수 (프론트 검증만으로 불충분)

4.5 항목 삭제 시 파일 처리 정책

┌─────────────────────────────────────────────────────────────────┐
│  📄 항목 삭제 시 파일 처리                                        │
├─────────────────────────────────────────────────────────────────┤
│  1. 점검표 저장(PUT) 시 Service에서 이전 categories와 비교       │
│  2. 삭제된 sub_item_id 목록 추출                                 │
│  3. 해당 sub_item_id의 qms_documents를 soft delete              │
│  4. 실제 파일은 삭제하지 않음 (복구 가능성 유지)                    │
│  5. 향후 정리: 배치 작업으로 soft deleted 파일 물리 삭제 가능       │
└─────────────────────────────────────────────────────────────────┘

4.6 프론트엔드 변경 사항

버전 관련 제거 대상

제거 대상:
1. ChecklistTemplateEditor.tsx
   - VersionSelectBox 컴포넌트 전체 제거
   - versions, currentVersion, onRestoreVersion props 제거

2. useChecklistTemplate.ts
   - versions, currentVersion 상태 제거
   - restoreVersion() 함수 제거
   - MOCK_VERSIONS 데이터 제거
   - 저장 토스트: toast.success('저장 완료')

3. AuditSettingsPanel.tsx
   - ChecklistManagementProps에서 versions, currentVersion, onRestoreVersion 제거

4. types.ts
   - ChecklistTemplateVersion 인터페이스 제거
   - ChecklistTemplate에서 currentVersion, versions 제거

5. page.tsx
   - checklistManagement 객체에서 versions, currentVersion, onRestoreVersion 제거

actions.ts (신규)

// Server Actions 목록
export async function getChecklistTemplate(type?: string)
export async function saveChecklistTemplate(templateId: number, data: { categories })
export async function uploadQmsDocument(subItemId: string, file: File)
export async function getQmsDocuments(subItemId: string)
export async function deleteQmsDocument(documentId: number)

useChecklistTemplate.ts 변경 요약

변경 포인트:
1. USE_MOCK = false
2. 초기 로드: useEffect → getChecklistTemplate('day1_audit')
3. saveTemplate() → saveChecklistTemplate() API 호출
4. 토스트: toast.success('저장 완료')
5. 버전 관련 상태/로직 전부 제거
6. 저장 성공 후 categories 상태 갱신 → Day1ChecklistPanel 반영
7. isLoading, error 상태 추가 (API 전환 필수)
8. 에러 시 toast.error('저장 실패') + 에러 메시지 표시
9. 로딩 중 저장 버튼 비활성화

Day1ChecklistPanel.tsx 변경 요약

변경 포인트:
1. expandAllCategories prop 추가 (AuditDisplaySettings에서 전달)
2. useEffect로 expandAllCategories 변경 감지 → expandedCategories 업데이트

Day1DocumentSection.tsx 변경 요약

변경 포인트:
1. onFileUpload prop → 실제 uploadQmsDocument() 호출
2. 업로드 완료 후 문서 목록 갱신

4.7 초기 데이터 전략 (마이그레이션 시딩)

┌─────────────────────────────────────────────────────────────────┐
│  🌱 마이그레이션 시딩                                             │
├─────────────────────────────────────────────────────────────────┤
│  - 마이그레이션 실행 시 기존 테넌트에 기본 템플릿 자동 생성        │
│  - 기본 categories: mockData.ts의 MOCK_DAY1_CATEGORIES 기반     │
│  - 새 테넌트 가입 시: TenantCreated 이벤트 또는 수동 생성         │
└─────────────────────────────────────────────────────────────────┘

5. 컨펌 대기 목록

# 항목 변경 내용 영향 범위 상태
1 테이블 설계 checklist_templates + qms_documents 2개 신규 api/ DB ⚠️ 컨펌 필요
2 API 엔드포인트 2개 (GET/PUT) + 파일 3개 (POST/GET/DELETE) api/ 라우트 ⚠️ 컨펌 필요
3 파일 연결 qms_documents 전용 중간 테이블로 파일-항목 연결 관리 api/ ⚠️ 컨펌 필요
4 초기 데이터 getOrCreate 패턴 (마이그레이션 시딩 없음) api/ Service ⚠️ 컨펌 필요
5 항목 삭제 시 삭제된 sub_item_id의 qms_documents soft delete api/ Service ⚠️ 컨펌 필요

6. 변경 이력

날짜 항목 변경 내용 파일 승인
2026-03-11 - 문서 초안 작성 - -
2026-03-11 설계 버전 관리 제거 (V1 고정, 단순 덮어쓰기) 전체 사용자 요청
2026-03-11 설계 페르소나 분석 반영: UNIQUE KEY 수정, qms_documents 테이블 추가, FormRequest 검증 규칙, getOrCreate 패턴, 항목 삭제 시 파일 처리, 로딩/에러 상태 전체 분석 결과

7. 참고 문서

  • 상위 QMS 계획: docs/dev/dev_plans/qms-api-integration-plan.md
  • 품질관리 기능: docs/features/quality-management/README.md
  • 파일 업로드 가이드: docs/dev/guides/file-storage-guide.md
  • API 규칙: docs/dev/standards/api-rules.md
  • options 정책: docs/dev/standards/options-column-policy.md
  • 품질 체크리스트: docs/dev/standards/quality-checklist.md

7.1 관련 파일 경로

프론트엔드 (react/):

src/app/[locale]/(protected)/quality/qms/
├── page.tsx                           # 메인 페이지
├── types.ts                           # 타입 정의
├── mockData.ts                        # Mock 데이터 (전환 후 삭제 대상)
├── actions.ts                         # ❌ 신규 생성 필요
├── components/
│   ├── AuditSettingsPanel.tsx         # 설정 패널 (탭 2개)
│   ├── ChecklistTemplateEditor.tsx   # 점검표 편집기 (버전 UI 제거 필요)
│   ├── Day1ChecklistPanel.tsx        # 점검표 항목 표시
│   └── Day1DocumentSection.tsx       # 문서 섹션 + 파일 업로드
└── hooks/
    ├── useDay1Audit.ts               # 1일차 심사 로직
    └── useChecklistTemplate.ts       # 점검표 템플릿 관리 (Mock→API 전환)

백엔드 (api/) — 신규 생성 대상:

app/
├── Http/Controllers/Api/V1/
│   └── ChecklistTemplateController.php    # 신규
├── Http/Requests/Quality/
│   └── SaveChecklistTemplateRequest.php   # 신규 (중첩 JSON 검증)
├── Services/
│   └── ChecklistTemplateService.php       # 신규 (조회 + 저장 + 파일 처리)
├── Models/Qualitys/
│   └── ChecklistTemplate.php              # 신규 (기존 Quality 모델과 같은 위치)
database/migrations/
└── XXXX_create_checklist_templates_table.php  # 신규 (시딩 포함)

8. 세션 및 메모리 관리 정책

8.1 세션 시작 시

1. 이 계획 문서 읽기
2. qms-api-integration-plan.md 참조 (아키텍처 결정사항)
3. 현재 진행 상태 확인 → 다음 작업 파악

8.2 작업 중 관리

- Phase/항목별 상태 업데이트 (⏳ → 🔄 → ✅)
- 변경 이력 섹션에 실시간 기록
- 컨펌 필요사항 → 컨펌 대기 목록에 추가

9. 검증 결과

작업 완료 후 이 섹션에 검증 결과 추가

9.1 테스트 케이스

시나리오 예상 결과 실제 결과 상태
점검표 템플릿 조회 categories JSON 반환
카테고리 추가 → 저장 "저장 완료" 토스트, DB 반영
하위 항목 편집 → 저장 기존 ID 유지, 이름만 변경
파일 업로드 (PDF 5MB) 성공, files 테이블에 기록
파일 업로드 (EXE) 거부, 오류 메시지 표시
expandAllCategories ON 모든 카테고리 펼침
expandAllCategories OFF 모든 카테고리 접힘
점검표 저장 후 심사화면 즉시 반영 (새로고침 불필요)
초기화(Reset) 마지막 저장 상태로 복원
빈 카테고리 저장 시도 FormRequest 검증 실패, 오류 메시지
카테고리 이름에 HTML 태그 태그 제거 또는 거부
항목 삭제 후 저장 삭제된 항목의 qms_documents soft delete
새 테넌트 최초 조회 getOrCreate로 기본 템플릿 자동 생성
서버 측 파일 검증 (EXE 확장자) 서버에서 거부 (mimes 검증)
API 에러 시 프론트 처리 에러 토스트 + 로딩 해제

9.2 성공 기준

기준 달성 비고
USE_MOCK = false로 전환 완료
점검표 CRUD 전체 동작
저장 시 "저장 완료" 토스트 버전 번호 없음
파일 업로드/조회/삭제 동작
expandAllCategories 설정 연동
점검표 편집 → 심사화면 즉시 반영
버전 UI 완전 제거 VersionSelectBox 등

10. 자기완결성 점검 결과

10.1 체크리스트 검증

# 검증 항목 상태 비고
1 작업 목적이 명확한가? Mock → API 전환 + 버전 제거
2 성공 기준이 정의되어 있는가? 9.2 참조
3 작업 범위가 구체적인가? Phase 1~3, 10개 세부 항목
4 의존성이 명시되어 있는가? Phase 순서, 테이블→모델→서비스→컨트롤러
5 참고 파일 경로가 정확한가? 7.1 관련 파일 경로
6 단계별 절차가 실행 가능한가? SQL, API 스펙, 제거 대상 명시
7 검증 방법이 명시되어 있는가? 9.1 테스트 케이스
8 모호한 표현이 없는가? 구체적 파일명, 컬럼명, 엔드포인트 명시

10.2 새 세션 시뮬레이션 테스트

질문 답변 가능 참조 섹션
Q1. 이 작업의 목적은 무엇인가? 1.1 배경
Q2. 어디서부터 시작해야 하는가? 2.1 Phase 1
Q3. 어떤 파일을 수정해야 하는가? 7.1 관련 파일 경로
Q4. 작업 완료 확인 방법은? 9.1 테스트 케이스
Q5. 막혔을 때 참고 문서는? 7. 참고 문서

이 문서는 /plan 스킬로 생성되었습니다.