# task-1224.1 완료 보고서: 대시보드 보고서 뷰어 — 이미지 파일 인라인 미리보기

**S**: 대시보드 기록 탭(ArchiveView)에서 보고서를 열면, 이미지 파일 경로(.png/.jpg 등)가 클릭 가능한 텍스트 링크로만 표시된다.

**C**: 이미지 내용을 확인하려면 매번 링크를 클릭해 FileViewerModal을 열어야 하므로, 보고서 리뷰 시 이미지 맥락 파악이 비효율적이다.

**Q**: 이미지 경로를 클릭 없이 바로 인라인 미리보기로 표시할 수 있는가?

**A**: `linkifyFilePaths()`에 이미지 경로 감지 + 미리보기 컨테이너 삽입 로직을 추가하고, `initInlineImagePreviews()` 함수를 구현하여 IntersectionObserver 기반 lazy load로 인라인 이미지를 렌더링하도록 개선. ArchiveView에서 보고서 렌더링 후 자동 초기화. 로딩 중 스피너 표시, 실패 시 기존 링크만 유지(graceful degradation).

## 수정 파일

- `/home/jay/workspace/dashboard/components/utils.js`
  - `linkifyFilePaths()` (558-572행): 이미지 확장자(png/jpg/jpeg/gif/webp) 감지 시 `<a>` 링크 뒤에 `.inline-image-preview` div 삽입 (Pass 1, Pass 2)
  - `initInlineImagePreviews()` (582-646행): 신규 함수 — IntersectionObserver로 뷰포트 진입 시 `/api/file?path=...` fetch, base64 `<img>` 생성, DOM API 사용(XSS 방지)
- `/home/jay/workspace/dashboard/components/ArchiveView.js`
  - 11행: `contentRef` useRef 추가
  - 13-18행: useEffect로 `initInlineImagePreviews(contentRef.current)` 호출
  - 77행: md-render div에 `ref={contentRef}` 연결
- `/home/jay/workspace/dashboard/index.html`
  - 49행: `@keyframes spin` CSS 추가

## 발견 이슈 및 자체 해결 (3건)

### 자체 해결 (3건)
1. **XSS 취약점 — innerHTML에 사용자 경로 삽입** — DOM API(createElement/addEventListener)로 전환하여 해결
   - 상세: utils.js:611-617 — `img.src`, `img.addEventListener('click', ...)` 사용으로 경로 특수문자에 의한 HTML injection 방지
2. **TaskDetailModal에 빈 공간 생김** — 미리보기 div 초기 스타일 제거(margin/min-height 없음)하여 `initInlineImagePreviews` 미호출 시 레이아웃 영향 0
   - 상세: `linkifyFilePaths()`는 TaskDetailModal(utils.js:740)에서도 사용되나, initInlineImagePreviews는 ArchiveView에서만 호출. 초기 빈 div에 스타일 없으므로 영향 없음
3. **filename-only 이미지 경로 검색 실패 가능성** — `/api/file-search` fallback 체인 구현 (검색 → 직접 fetch → 실패 시 숨김)
   - 상세: utils.js:601-605 — file-search API 실패 시 직접 경로로 재시도, 최종 실패 시 display:none

## 구현 상세

- **이미지 감지 확장자**: `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`
- **이미지 크기 제한**: `max-width:100%; max-height:300px`
- **Lazy loading**: IntersectionObserver (rootMargin: 200px), 미지원 브라우저는 첫 5개만 즉시 로드
- **로딩 상태**: 스피너 + "이미지 로딩 중..." 텍스트
- **이미지 클릭**: FileViewerModal 열기 (기존 전체화면 뷰 유지)
- **적용 범위**: ArchiveView(기록 탭)의 보고서 마크다운만 — FileViewerModal, TaskDetailModal은 미적용(작업 지시 준수)

## 테스트

- 프론트엔드 JS 컴포넌트 변경으로 Python 서버 테스트에 영향 없음
- 기존 프론트엔드 테스트 파일 없음 (JS 테스트 프레임워크 미설정)
- 수동 테스트 필요 항목:
  1. 기록 탭 → 보고서 열기 → 이미지 경로에 인라인 미리보기 표시 확인
  2. 스크롤 시 lazy load 동작 확인
  3. 존재하지 않는 이미지 경로 → 링크만 표시 확인
  4. 이미지 클릭 → FileViewerModal 열림 확인
  5. TaskDetailModal에서 빈 공간 없는지 확인

## QC 자동 검증

- **Overall**: WARN (4 PASS, 7 SKIP, 1 WARN)
- file_check: PASS — utils.js(56,947B), ArchiveView.js(6,045B), index.html(5,315B), 보고서(3,874B)
- data_integrity: WARN — task timer running 상태 (finish-task.sh에서 end 처리 예정)
- test_runner: SKIP — 관련 테스트 파일 0개 (프론트엔드 JS 전용 변경)
- critical_gap: PASS
- spec_compliance: PASS
- duplicate_check: PASS (최대 유사도 8.1%)
