ワンクリックで
verify-inquiry-ui
문의 상세 페이지 UI 컴포넌트 검증 (shadcn/ui + Tailwind 기준). 문의 탭(Info/Analysis/Answer/History) 및 업로드 컴포넌트 수정 후 사용.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
문의 상세 페이지 UI 컴포넌트 검증 (shadcn/ui + Tailwind 기준). 문의 탭(Info/Analysis/Answer/History) 및 업로드 컴포넌트 수정 후 사용.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
세션 변경사항을 분석하여 검증 스킬 누락을 탐지합니다. 기존 스킬을 동적으로 탐색하고, 새 스킬을 생성하거나 기존 스킬을 업데이트한 뒤 CLAUDE.md를 관리합니다.
REST API 응답 DTO 일관성 및 에러 코드 표준 검증. API 엔드포인트 추가/수정, DTO 변경, 에러 처리 수정 후 사용. API 계약 변경이 프론트엔드에 영향을 줄 수 있을 때 사용.
Flyway DB 마이그레이션 일관성 검증. 마이그레이션 추가/수정 후 사용.
프론트엔드 UI 컴포넌트 품질 검증 (shadcn/ui + Tailwind 기준). UI 컴포넌트 수정 후 사용.
KB 비동기 인덱싱 파이프라인 검증. 인덱싱 관련 코드 수정 후 사용.
RAG 파이프라인 (답변 작성 + 분석 + 다운로드) 검증. 답변 작성/분석/다운로드 관련 코드 수정 후 사용.
| name | verify-inquiry-ui |
| description | 문의 상세 페이지 UI 컴포넌트 검증 (shadcn/ui + Tailwind 기준). 문의 탭(Info/Analysis/Answer/History) 및 업로드 컴포넌트 수정 후 사용. |
frontend/src/components/inquiry/ 하위 컴포넌트 수정 후frontend/src/components/upload/ 하위 컴포넌트 수정 후frontend/src/lib/api/client.ts의 타입/함수 변경 후| File | Purpose |
|---|---|
frontend/src/components/inquiry/InquiryAnswerTab.tsx | 답변 탭 (Tailwind grid split pane + Citation 파싱 + PdfViewer + translatedQuery 표시) |
frontend/src/components/inquiry/InquiryCreateForm.tsx | 문의 생성 폼 (react-hook-form + zod + shadcn Button) |
frontend/src/components/inquiry/InquiryInfoTab.tsx | 정보 탭 (문서 목록 + 인덱싱 상태 + Skeleton) |
frontend/src/components/inquiry/InquiryHistoryTab.tsx | 이력 탭 (버전 히스토리 + Tailwind grid split pane + PdfViewer) |
frontend/src/app/inquiries/[id]/page.tsx | 문의 상세 페이지 서버 래퍼 (generateStaticParams + Suspense) |
frontend/src/app/inquiries/[id]/InquiryDetailClient.tsx | 문의 상세 클라이언트 (useParams + useSearchParams + 탭 라우팅) |
frontend/src/components/upload/SmartUploadModal.tsx | 스마트 업로드 모달 (KB 문서 일괄 업로드) |
frontend/src/components/upload/FileDropZone.tsx | 파일 드래그앤드롭 영역 (cn + Tailwind) |
frontend/src/components/upload/FileQueueItem.tsx | 파일 큐 아이템 (cn + status 기반 스타일 + 제품군 드롭다운) |
frontend/src/lib/api/client.ts | API 클라이언트 (타입 정의 + 헬퍼 함수) |
frontend/src/lib/i18n/labels.ts | 한국어 라벨 매핑 함수 (labelReviewDecision, labelApprovalDecision 포함) |
frontend/src/components/inquiry/WorkflowResultCard.tsx | 워크플로우 결과 공유 컴포넌트 (showActions prop, 리뷰 이슈/게이트 결과 표시) |
frontend/src/components/inquiry/PipelineProgress.tsx | 파이프라인 진행 UI (Kawaii 고양이 + 6단계 진행 표시 + SSE 실시간 업데이트) |
frontend/src/hooks/useInquiryEvents.ts | SSE 이벤트 구독 훅 (pipeline-step named event + 재연결 + 탭 복원) |
파일: InquiryAnswerTab.tsx, InquiryHistoryTab.tsx
검사: parseCitation 함수가 6개 키 (chunk, score, documentId, fileName, pageStart, pageEnd)를 파싱하는지 확인.
grep -n "chunk=\|score=\|documentId=\|fileName=\|pageStart=\|pageEnd=" frontend/src/components/inquiry/InquiryAnswerTab.tsx frontend/src/components/inquiry/InquiryHistoryTab.tsx
PASS: 양쪽 모두 6개 키 정규식 매칭 존재 FAIL: 키 누락 또는 fileName regex 오류
파일: InquiryAnswerTab.tsx, InquiryHistoryTab.tsx
검사: split pane이 Tailwind grid (grid grid-cols-1 gap-6 lg:grid-cols-[1fr_400px])로 구현되었는지 확인.
grep -n "grid.*cols\|lg:grid-cols\|lg:sticky\|lg:self-start" frontend/src/components/inquiry/InquiryAnswerTab.tsx frontend/src/components/inquiry/InquiryHistoryTab.tsx
PASS: Tailwind grid + lg: 반응형 + sticky 오른쪽 패널 존재
FAIL: 레거시 .split-pane CSS 클래스 사용 또는 split pane 누락
파일: InquiryAnswerTab.tsx, InquiryHistoryTab.tsx
검사: PdfViewer를 next/dynamic으로 ssr: false 설정하여 임포트하는지 확인.
grep -rn "dynamic\|ssr.*false\|PdfViewer" frontend/src/components/inquiry/InquiryAnswerTab.tsx frontend/src/components/inquiry/InquiryHistoryTab.tsx
PASS: 양쪽 모두 dynamic(() => import(...), { ssr: false }) 패턴 존재
FAIL: 직접 import 사용
파일: InquiryAnswerTab.tsx, InquiryHistoryTab.tsx
검사: 답변 초안 본문에 Tailwind whitespace-pre-wrap 클래스가 적용되는지 확인.
grep -rn "whitespace-pre-wrap\|pre-wrap" frontend/src/components/inquiry/InquiryAnswerTab.tsx frontend/src/components/inquiry/InquiryHistoryTab.tsx
PASS: 답변 본문 표시 영역에 whitespace-pre-wrap 클래스 적용
FAIL: whitespace-pre-wrap 없음
파일: InquiryAnswerTab.tsx
검사: KNOWLEDGE_BASE="지식 기반" (info), INQUIRY/else="문의 첨부" (neutral) 매핑이 AnswerTab에서 올바르게 적용되는지 확인. (InquiryAnalysisTab.tsx는 삭제됨 — 분석 결과가 AnswerTab에 통합)
grep -rn "지식 기반\|문의 첨부\|KNOWLEDGE_BASE\|sourceType" frontend/src/components/inquiry/InquiryAnswerTab.tsx
PASS: KNOWLEDGE_BASE="지식 기반" (info), INQUIRY="문의 첨부" (neutral) 매핑 존재 FAIL: 뱃지 variant 또는 라벨 불일치
파일: frontend/src/components/inquiry/*.tsx
검사: 영문 enum 값을 직접 표시하지 않고 labels.ts의 함수를 통해 변환하는지 확인.
grep -rn "labelVerdict\|labelAnswerStatus\|labelDocStatus\|labelChannel\|labelTone" frontend/src/components/inquiry/
PASS: 4개 이상의 라벨 함수 사용 FAIL: 영문 enum 값 직접 표시
파일: frontend/src/components/inquiry/*.tsx
검사: 모든 inquiry 컴포넌트에서 레거시 .btn 클래스 대신 shadcn Button 컴포넌트를 사용하는지 확인.
grep -rn "from.*button\|className=\"btn" frontend/src/components/inquiry/*.tsx
PASS: shadcn Button import 존재, .btn 클래스 없음
FAIL: 레거시 .btn 클래스 사용
파일: InquiryCreateForm.tsx
검사: react-hook-form의 useForm + zodResolver를 사용하고, zod 스키마가 정의되어 있는지 확인.
grep -rn "useForm\|zodResolver\|z\.object\|z\.string\|z\.enum" frontend/src/components/inquiry/InquiryCreateForm.tsx
PASS: useForm + zodResolver + z.object 스키마 존재 FAIL: 수동 상태 관리 또는 유효성 검사 누락
파일: InquiryCreateForm.tsx, FileDropZone.tsx
검사: 파일 업로드에 허용 파일 형식이 지정되어 있는지 확인.
grep -n "accept\|\.pdf\|\.doc" frontend/src/components/inquiry/InquiryCreateForm.tsx frontend/src/components/upload/FileDropZone.tsx
PASS: accept 속성에 PDF/DOC/DOCX 지정 FAIL: accept 속성 없음
파일: frontend/src/lib/api/client.ts
검사: getDocumentDownloadUrl과 getDocumentPagesUrl 헬퍼 함수가 존재하는지 확인.
grep -n "getDocumentDownloadUrl\|getDocumentPagesUrl" frontend/src/lib/api/client.ts
PASS: 두 함수 모두 존재 FAIL: 함수 누락
파일: InquiryAnswerTab.tsx, InquiryHistoryTab.tsx
검사: PdfViewer에 pagesDownloadUrl prop이 전달되어 근거 페이지 분할 다운로드가 가능한지 확인.
grep -n "pagesDownloadUrl" frontend/src/components/inquiry/InquiryAnswerTab.tsx frontend/src/components/inquiry/InquiryHistoryTab.tsx
PASS: 양쪽 모두 pagesDownloadUrl={...getDocumentPagesUrl(...) + "&download=true"} 패턴 존재
FAIL: pagesDownloadUrl prop 누락 (전체 다운로드만 가능)
파일: InquiryAnswerTab.tsx, InquiryHistoryTab.tsx
검사: 답변 본문 내 (파일명, p.XX-YY) 패턴이 클릭 가능한 요소로 변환되는지, citationRegex가 한국어 문자를 제외([^,가-힣\n]+)하여 한국어 괄호 표현식을 잘못 캡처하지 않는지 확인.
문제 배경: [^,]+\.pdf 패턴은 한국어 문자를 포함하므로, 답변 본문에 유효기간(외부 포장...)까지...(파일명.pdf, p.X) 패턴이 있을 때 첫 번째 (부터 .pdf까지 모두 파일명으로 잡아 매칭 실패 → 일반 텍스트 표시.
grep -n "citationRegex\|가-힣" frontend/src/components/inquiry/InquiryAnswerTab.tsx frontend/src/components/inquiry/InquiryHistoryTab.tsx
PASS: 두 파일 모두 [^,가-힣\n]+\.pdf 패턴 사용 + 클릭 시 setSelectedEvidence 호출
FAIL: [^,]+\.pdf 패턴 사용 (한국어 미제외) → 한국어 괄호가 있는 문장에서 자료 링크가 일반 텍스트로 표시됨
파일: PdfViewer.tsx, PdfExpandModal.tsx
검사: 다운로드가 <a download> 대신 fetch → blob → createObjectURL 패턴을 사용하는지 확인. (크로스오리진에서 <a download>는 브라우저가 무시)
grep -rn "triggerBlobDownload\|createObjectURL\|fetch.*blob" frontend/src/components/ui/PdfViewer.tsx frontend/src/components/ui/PdfExpandModal.tsx
PASS: triggerBlobDownload 함수 존재 + 모든 다운로드 버튼이 이 함수 사용
FAIL: <a href download> 패턴으로 직접 다운로드 시도
파일: InquiryAnswerTab.tsx
검사: AI 자동 워크플로우(autoWorkflow), 리뷰 상세(reviewDetail), 승인 게이트 결과(gateResults) UI가 존재하고 올바르게 표시되는지 확인.
grep -n "autoWorkflow\|reviewDetail\|gateResults\|labelReviewDecision\|labelApprovalDecision" frontend/src/components/inquiry/InquiryAnswerTab.tsx
PASS: autoWorkflow 체크박스, reviewDetail 패널, gateResults 4개 게이트 표시 존재 FAIL: AI 워크플로우 UI 없음 또는 라벨 함수 미사용
파일: InquiryAnswerTab.tsx
검사: 답변 본문 수정 기능이 textarea + 저장/취소 버튼으로 구현되고, SENT 상태에서 수정 버튼이 숨겨지는지 확인.
grep -n "isEditing\|editedDraft\|handleSaveDraft\|textarea\|수정\|저장\|취소" frontend/src/components/inquiry/InquiryAnswerTab.tsx
PASS: isEditing 토글, textarea, 저장/취소 버튼, SENT 상태 시 수정 버튼 숨김 FAIL: 수정 기능 없음 또는 SENT 상태에서 수정 가능
파일: InquiryAnswerTab.tsx
검사: 전송 요청 ID가 Date.now() 등을 활용하여 매번 고유한 값을 생성하는지 확인. 정적 문자열 사용 시 재전송 방지가 동작하지 않음.
grep -n "sendRequestId\|Date.now\|requestId" frontend/src/components/inquiry/InquiryAnswerTab.tsx
PASS: Date.now() 또는 UUID 등 동적 값으로 requestId 생성
FAIL: 정적 문자열 (예: -send-v1) 사용
파일: InquiryAnswerTab.tsx, frontend/src/lib/api/client.ts
검사: InquiryDetail에 preferredTone 필드가 있고, AnswerTab에서 초기 tone 값으로 사용되는지 확인.
grep -n "preferredTone\|initialTone\|selectedTone" frontend/src/components/inquiry/InquiryAnswerTab.tsx frontend/src/lib/api/client.ts
PASS: client.ts에 preferredTone 타입 정의 + AnswerTab에서 초기값으로 사용 FAIL: preferredTone 필드 미정의 또는 초기값 미적용
파일: InquiryAnswerTab.tsx
검사: 하이브리드 검색 시 한국어 질문이 영어로 번역된 경우, 번역 결과(translatedQuery)가 UI에 표시되는지 확인. 원본 질문과 동일하면 표시하지 않아야 함.
grep -n "translatedQuery" frontend/src/components/inquiry/InquiryAnswerTab.tsx
PASS: translatedQuery 필드를 조건부로 표시 (원본과 다를 때만)하고 italic 스타일 적용
FAIL: translatedQuery 표시 로직 없음 또는 무조건 표시
| # | 검사 항목 | 결과 | 상세 |
|---|---|---|---|
| 1 | Citation 파싱 정규식 | PASS/FAIL | 누락 키, regex 방식 |
| 2 | Tailwind Grid Split Pane | PASS/FAIL | grid 패턴, lg: 반응형 |
| 3 | PdfViewer SSR 제한 | PASS/FAIL | import 방식 |
| 4 | whitespace-pre-wrap | PASS/FAIL | 미적용 컴포넌트 |
| 5 | sourceType 뱃지 매핑 | PASS/FAIL | 불일치 위치 |
| 6 | 한국어 라벨 함수 | PASS/FAIL | 직접 표시 위치 |
| 7 | shadcn Button 사용 | PASS/FAIL | 레거시 .btn 사용처 |
| 8 | react-hook-form + zod | PASS/FAIL | 누락 패턴 |
| 9 | 파일 업로드 accept | PASS/FAIL | accept 속성 |
| 10 | 다운로드 URL 헬퍼 | PASS/FAIL | 함수 유무 |
| 10a | pagesDownloadUrl prop | PASS/FAIL | AnswerTab/HistoryTab |
| 10b | 인라인 인용 클릭 | PASS/FAIL | citation 파싱 + 클릭 |
| 10c | triggerBlobDownload | PASS/FAIL | 크로스오리진 다운로드 |
| 11 | AI 워크플로우 UI | PASS/FAIL | autoWorkflow/reviewDetail/gateResults |
| 12 | 답변 본문 수정 UI | PASS/FAIL | textarea + 저장/취소 + SENT 숨김 |
| 13 | sendRequestId 고유성 | PASS/FAIL | Date.now() 사용 |
| 14 | preferredTone 초기값 | PASS/FAIL | 타입 정의 + 자동 적용 |
| 15 | translatedQuery 표시 | PASS/FAIL | 조건부 표시 + italic 스타일 |
| 16 | WorkflowResultCard 공유 | PASS/FAIL | AnswerTab + HistoryTab 사용 |
| 17 | CITATION/HALLUCINATION 카테고리 | PASS/FAIL | labels + WorkflowResultCard |
| 18 | workflowRunCount 표시 | PASS/FAIL | HistoryTab 재실행 횟수 |
| 19 | history-detail API 사용 | PASS/FAIL | HistoryTab listAnswerDraftHistoryDetail |
| 20 | 제품군 태그 선택 UI | PASS/FAIL | 드롭다운 + 태그 + 최대 3개 |
| 21 | productFamily 뱃지 + fallback | PASS/FAIL | 뱃지 + retrievalQuality 경고 |
| 22 | 제품군/검색품질 라벨 | PASS/FAIL | 라벨 맵 + 함수 |
| 23 | API client 타입 확장 | PASS/FAIL | ProductFamilyInfo + getProductFamilies |
| 24 | FileQueueItem 드롭다운 | PASS/FAIL | 자유 텍스트 vs 드롭다운 |
파일: InquiryAnswerTab.tsx, InquiryHistoryTab.tsx, WorkflowResultCard.tsx
검사: 워크플로우 결과 표시가 공유 컴포넌트 WorkflowResultCard를 통해 렌더링되고, AnswerTab은 showActions=true, HistoryTab은 showActions=false로 사용하는지 확인.
grep -rn "WorkflowResultCard\|showActions" frontend/src/components/inquiry/InquiryAnswerTab.tsx frontend/src/components/inquiry/InquiryHistoryTab.tsx frontend/src/components/inquiry/WorkflowResultCard.tsx
PASS: 양쪽 모두 WorkflowResultCard import + 사용, AnswerTab에 showActions, HistoryTab에 readOnly(showActions=false) 모드
FAIL: 인라인 워크플로우 결과 렌더링 존재 또는 WorkflowResultCard 미사용
파일: WorkflowResultCard.tsx, frontend/src/lib/i18n/labels.ts
검사: WorkflowResultCard에서 CITATION/HALLUCINATION 카테고리가 올바르게 표시되고, labels.ts에 한국어 매핑이 있는지 확인.
grep -n "CITATION\|HALLUCINATION\|인용 검증\|환각 탐지" frontend/src/components/inquiry/WorkflowResultCard.tsx frontend/src/lib/i18n/labels.ts
PASS: labels.ts에 CITATION: "인용 검증", HALLUCINATION: "환각 탐지" 매핑 + WorkflowResultCard에서 labelIssueCategory 사용
FAIL: 카테고리 라벨 누락 또는 영문 직접 표시
파일: InquiryHistoryTab.tsx
검사: 이력탭에서 워크플로우 재실행 횟수(workflowRunCount)가 표시되고, 5회 제한 조건이 UI에 반영되는지 확인.
grep -n "workflowRunCount\|실행됨\|재실행" frontend/src/components/inquiry/InquiryHistoryTab.tsx
PASS: workflowRunCount 표시 (예: {n}/5 실행됨) + workflowRunCount < 5 && status !== "SENT" 조건으로 재실행 버튼 표시
FAIL: 실행 횟수 미표시 또는 무제한 재실행 허용
파일: InquiryHistoryTab.tsx, frontend/src/lib/api/client.ts
검사: 이력탭이 listAnswerDraftHistoryDetail API를 사용하여 AI 리뷰 이력을 포함한 상세 데이터를 조회하는지 확인.
grep -n "listAnswerDraftHistoryDetail\|AnswerHistoryDetailResult\|aiReviewHistory" frontend/src/components/inquiry/InquiryHistoryTab.tsx frontend/src/lib/api/client.ts
PASS: client.ts에 listAnswerDraftHistoryDetail 함수 + AnswerHistoryDetailResult 타입 정의, HistoryTab에서 사용
FAIL: 기존 listAnswerDraftHistory 사용 (AI 리뷰 이력 미포함)
파일: InquiryCreateForm.tsx
검사: 제품군 드롭다운 + "추가" 버튼 + 태그 뱃지(X 제거 버튼) + 최대 3개 제한이 구현되어 있는지 확인. getProductFamilies() API를 호출하여 옵션을 로드하는지 확인.
grep -n "productFamilies\|getProductFamilies\|MAX_PRODUCT\|제품군\|추가\|제거" frontend/src/components/inquiry/InquiryCreateForm.tsx
PASS: 드롭다운 + 추가 버튼 + 태그 뱃지 + X 제거 + 최대 3개 제한 + getProductFamilies API 호출 FAIL: 제품군 선택 UI 없음 또는 자유 텍스트 입력
파일: InquiryAnswerTab.tsx
검사: 증거 상세에 productFamily 뱃지가 표시되고, retrievalQuality가 EXACT가 아닐 때 경고 배너가 표시되는지 확인. extractedProductFamilies 태그 표시도 확인.
grep -n "productFamily\|retrievalQuality\|CATEGORY_EXPANDED\|UNFILTERED\|extractedProductFamilies\|labelProductFamily\|labelRetrievalQuality" frontend/src/components/inquiry/InquiryAnswerTab.tsx
PASS: productFamily 뱃지 + retrievalQuality 조건부 경고 배너 + extractedProductFamilies 태그 + labelProductFamily/labelRetrievalQuality 함수 사용 FAIL: productFamily 표시 없음 또는 retrievalQuality 경고 없음
파일: frontend/src/lib/i18n/labels.ts
검사: PRODUCT_FAMILY_LABELS (10개 제품군) 맵과 labelProductFamily() 함수, RETRIEVAL_QUALITY_LABELS 맵과 labelRetrievalQuality() 함수가 존재하는지 확인.
grep -n "PRODUCT_FAMILY_LABELS\|labelProductFamily\|RETRIEVAL_QUALITY_LABELS\|labelRetrievalQuality" frontend/src/lib/i18n/labels.ts
PASS: PRODUCT_FAMILY_LABELS (10항목) + labelProductFamily + RETRIEVAL_QUALITY_LABELS (3항목) + labelRetrievalQuality 함수 모두 존재 FAIL: 라벨 맵 또는 함수 누락
파일: frontend/src/lib/api/client.ts
검사: ProductFamilyInfo 인터페이스, getProductFamilies() API, AnalyzeEvidenceItem.productFamily, AnswerDraftResult.retrievalQuality/extractedProductFamilies, CreateInquiryPayload.productFamilies 타입이 정의되어 있는지 확인.
grep -n "ProductFamilyInfo\|getProductFamilies\|retrievalQuality\|extractedProductFamilies\|productFamilies" frontend/src/lib/api/client.ts
PASS: ProductFamilyInfo + getProductFamilies() + retrievalQuality + extractedProductFamilies + productFamilies 모두 존재 FAIL: 타입 또는 API 함수 누락
파일: frontend/src/components/upload/FileQueueItem.tsx
검사: KB 문서 업로드 시 제품군 선택이 자유 텍스트가 아닌 드롭다운으로 구현되어 있는지 확인.
grep -n "productFamily\|getProductFamilies\|select\|option" frontend/src/components/upload/FileQueueItem.tsx
PASS: <select> 또는 드롭다운 + getProductFamilies 옵션 로드
FAIL: <input type="text"> 자유 텍스트 입력
다음은 위반이 아닙니다: