# task-1129.1 완료 보고서: 대시보드 파일 뷰어 기능 추가

## SCQA

**S**: 대시보드에서 작업 산출물(보고서, 지시서 등)을 확인하려면 텔레그램 파일 전송을 통해야 하며, 대시보드 내에서 직접 파일을 열어볼 수 없다.

**C**: 작업 보고서 확인마다 텔레그램 전송-다운로드 단계가 필요하여 작업 흐름이 끊기고, 산출물 리뷰 효율이 떨어진다.

**Q**: 대시보드에서 직접 파일을 클릭하여 내용을 볼 수 있는 파일 뷰어를 안전하게 구현할 수 있는가?

**A**: GET /api/file API + FileViewerModal UI를 추가하여, 대시보드 내에서 허가된 workspace 파일을 직접 열람 가능하게 구현. 6중 보안 검증(path traversal, 화이트리스트, 확장자, 민감 파일, resolve 검증, 존재 확인) 적용. pytest 7건 통과, 보안 테스트 18건 전체 통과, pyright 에러 0건.

---

## 수정 파일 목록

| 파일 | 변경 내용 |
|------|-----------|
| `dashboard/server.py` | GET `/api/file?path=` 엔드포인트 추가 (라인 2857-2908) |
| `dashboard/components/utils.js` | FileViewerModal 컴포넌트 추가 (라인 667-731), TaskDetailModal에 파일 경로 클릭 핸들러 + "보고서 원문 보기" 버튼 추가 |
| `dashboard/components/App.js` | fileViewerPath 상태 추가, window._showFileViewer 등록, FileViewerModal 렌더링 |
| `teams/dev1/tests/test_file_api.py` | 파일 API 보안/기능 테스트 18건 |

---

## 구현 상세

### 1. 파일 뷰어 API (server.py)
- **엔드포인트**: `GET /api/file?path=<relative_path>`
- **보안 검증 6단계**:
  1. path 파라미터 존재 확인 (400)
  2. `..` path traversal 차단 (403)
  3. 화이트리스트 경로: `memory/reports/`, `memory/tasks/`, `memory/specs/`, `memory/meetings/` (403)
  4. 허용 확장자: `.md`, `.txt`, `.json`, `.yaml`, `.yml`, `.py` (403)
  5. 민감 파일(`.env`, `.credentials`, `.keys`, dot파일) 차단 (403)
  6. `resolve()` 후 workspace 하위 경로 확인 (403)
- **응답**: `{"path", "content", "filename", "extension"}`

### 2. FileViewerModal (utils.js)
- z-index `z-[60]` (기존 모달 z-50 위에 표시)
- 마크다운 파일은 `marked.parse` + `DOMPurify.sanitize`로 렌더링
- 텍스트/코드 파일은 `<pre>` 태그로 원문 표시
- 파일명, 확장자 배지, 경로 표시, 닫기 버튼

### 3. 파일 링크 연동
- TaskDetailModal 보고서 내 `memory/(reports|tasks|specs|meetings)/` 경로 텍스트 클릭 시 FileViewerModal 오픈
- "보고서 원문 보기" 바로가기 버튼 추가
- `window._showFileViewer(path)` 글로벌 함수로 어디서든 호출 가능

---

## 테스트 결과

### pytest (기존 서버 테스트)
- **7건 통과**, 0.22초, 실패 0건

### 파일 API 보안 테스트 (test_file_api.py)
- **18건 전체 통과**
- 기능 테스트: 3건 (정상 파일 접근 검증)
- Path Traversal: 3건 (`..`, URL 인코딩 우회 차단)
- 화이트리스트: 5건 (비허가 경로 차단)
- 확장자 필터: 3건 (`.exe`, `.sh` 등 차단)
- 민감 파일: 2건 (`.env`, dot파일 차단)
- 에러 케이스: 2건 (빈 경로, 미존재 파일)

### QC 자동 검증
- pyright: 에러 0건
- style: black 포맷팅 적용 완료
- data_integrity: PASS

---

## 발견 이슈 및 해결

### 자체 해결 (3건)
1. **black 포맷팅 미적용** -- server.py에 black 재포맷팅 적용
   - 상세: `black dashboard/server.py` 실행
2. **FileViewerModal z-index 충돌 가능성** -- z-[60]으로 기존 모달(z-50)보다 높게 설정하여 해결
   - 상세: FileViewerModal이 TaskDetailModal 위에 표시되어야 하므로 z-index 계층 분리
3. **보고서 내 파일 경로 정규식 범위** -- `memory/(reports|tasks|specs|meetings)/` 4개 하위 디렉토리만 매칭하도록 정규식 제한
   - 상세: 허가된 디렉토리만 클릭 가능하게 하여 API 화이트리스트와 일치시킴

### 범위 외 미해결 (0건)
없음

---

## QC 자동 검증 결과

```json
{
  "test_runner": "PASS (7 passed in 0.22s)",
  "pyright_check": "PASS (0 errors)",
  "style_check": "PASS (black 적용 후)",
  "data_integrity": "PASS"
}
```
