# task-1170.1 완료 보고서: 파일 뷰어 경로 처리 전수 점검

**S**: 대시보드 파일 뷰어에서 5가지 형태의 경로(절대경로 with/without `/`, 상대경로, short path, 파일명만)가 들어오며, 경로 정규화 로직이 server.py와 utils.js에 중복 존재했다.

**C**: `ALLOWED_PREFIXES`가 `memory/` 하위 4개 디렉토리만 커버하여 `checkpoints/`, `events/`, `daily/` 등 접근 불가. short path 자동보정도 4개뿐. 프론트엔드에서 `/home/jay/workspace/` prefix 스트리핑이 서버와 중복.

**Q**: 모든 경로 형태를 서버 단일 지점에서 정규화하고, 누락된 디렉토리 접근을 허용할 수 있는가?

**A**: `normalize_file_path()` 헬퍼 함수를 추출하여 서버를 경로 정규화의 단일 진실 원천으로 확립. `ALLOWED_PREFIXES`를 `memory/` 통합 + `projects/`, `services/`, `pipelines/` 추가로 12개로 확장. short path 보정을 12개 디렉토리로 확장. 프론트엔드 중복 로직 제거. 13개 경로 테스트 케이스 전체 통과.

---

## 수정 파일

### `/home/jay/workspace/dashboard/server.py`
- **라인 2803~2819**: `normalize_file_path()` 모듈 레벨 헬퍼 함수 신규 추가
  - `./` prefix 제거
  - 절대경로 → 상대경로 변환 (`/home/jay/workspace/`, `home/jay/workspace/`)
  - short path 자동 보정 (12개 memory 하위 디렉토리)
- **라인 3112**: 인라인 정규화 코드 10줄 → `normalize_file_path()` 호출 1줄로 대체
- **라인 3118**: `ALLOWED_PREFIXES` 확장
  - 변경 전: `memory/reports/`, `memory/tasks/`, `memory/specs/`, `memory/meetings/` + 8개 = 12개
  - 변경 후: `memory/` 통합 + `projects/`, `services/`, `pipelines/` 추가 = 12개

### `/home/jay/workspace/dashboard/components/utils.js`
- **라인 693~695**: 중복 prefix 스트리핑 제거 (2줄 삭제)
  - `const prefix = '/home/jay/workspace/';` 삭제
  - `if (fullPath.startsWith(prefix)) fullPath = fullPath.slice(prefix.length);` 삭제
  - `let fullPath` → `const fullPath` 변경

---

## 발견 이슈 및 해결

### 자체 해결 (4건)
1. **ALLOWED_PREFIXES 누락** — `memory/` 통합 + 3개 디렉토리 추가로 해결
2. **short path 보정 누락** — 12개 memory 하위 디렉토리로 확장
3. **경로 정규화 중복** — 서버 단일 함수로 통합, 프론트엔드 중복 제거
4. **`./` prefix 미처리** — `normalize_file_path()`에 `./` 제거 로직 추가

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

---

## 테스트 결과

### normalize_file_path 단위 테스트: 13/13 통과
- 절대경로 with `/`: `/home/jay/workspace/memory/reports/task-100.md` → `memory/reports/task-100.md` ✅
- 절대경로 without `/`: `home/jay/workspace/memory/reports/task-100.md` → `memory/reports/task-100.md` ✅
- 상대경로: `memory/specs/some-spec.md` → 변환 없음 ✅
- short path (tasks/): `tasks/task-100.md` → `memory/tasks/task-100.md` ✅
- short path (events/, 신규): `events/task-100.done` → `memory/events/task-100.done` ✅
- short path (checkpoints/, 신규): `checkpoints/task-100.md` → `memory/checkpoints/task-100.md` ✅
- short path (daily/, 신규): `daily/2026-03-28.md` → `memory/daily/2026-03-28.md` ✅
- `./` prefix: `./memory/reports/task-100.md` → `memory/reports/task-100.md` ✅
- output 경로: `output/meta-ads/slide1.png` → 변환 없음 ✅
- projects 경로 (신규): `projects/insuwiki/src/app.py` → 변환 없음 ✅
- teams 경로: `teams/dev1/worker.py` → 변환 없음 ✅
- 절대 output 경로: `/home/jay/workspace/output/file.png` → `output/file.png` ✅
- short path (reports/): `reports/task-100.md` → `memory/reports/task-100.md` ✅

### ALLOWED_PREFIXES 검증: 7/7 통과
- `memory/checkpoints/`, `memory/events/` 등 이전 불가 경로 모두 허용 확인
- `projects/` 신규 추가 확인

### 보안 검증: 통과
- path traversal (`..`) 차단 유지
- 확장자 필터, 민감 파일 차단 변경 없음

### Python 구문 검증: `ast.parse()` Syntax OK

---

## QC 검증

```
overall: WARN (style_check만 WARN, 나머지 PASS)
- file_check: PASS (server.py 196KB, utils.js 53KB)
- data_integrity: PASS
- test_runner: PASS (pytest 7 passed in 0.26s)
- pyright_check: PASS (0 errors, 0 warnings)
- style_check: WARN (black 포맷팅 미적용 — 기능 무관)
- critical_gap: PASS
- spec_compliance: PASS
- duplicate_check: PASS
```
