# task-1248.1: 대시보드 캠페인 탭에 노하우 파일 뷰어 추가

**작성일**: 2026-03-29
**팀**: dev1-team (헤르메스)
**상태**: 완료

---

## SCQA

**S**: 대시보드 캠페인 탭이 운영되고 있으며, 광고 이미지 제작 과정에서 축적된 노하우/실패사례 파일 3개(`knowhow-design.md`, `knowhow-marketing.md`, `design-qc-knowhow.md`)가 존재한다.

**C**: 이 노하우 파일들을 열람하려면 서버에 직접 접속하여 파일을 찾아 읽어야 하므로, 대시보드에서 즉시 참조할 수 없었다.

**Q**: 대시보드 캠페인 탭 내에서 3개 노하우 파일을 탭 전환 방식으로 바로 열람할 수 있도록 구현할 수 있는가?

**A**: `GET /api/knowhow` API 엔드포인트를 추가하여 3개 md 파일을 JSON으로 반환하고, CampaignView.js에 "노하우 라이브러리" 섹션을 추가하여 탭 전환 UI로 내용을 표시하도록 구현 완료. pytest 7건 전체 통과, pyright 에러 0건.

---

## 수정 파일 목록

- `/home/jay/workspace/dashboard/server.py` — `GET /api/knowhow` 엔드포인트 추가 (3435~3447줄)
- `/home/jay/workspace/dashboard/components/CampaignView.js` — 노하우 라이브러리 섹션 추가 (state 2개, useEffect 1개, UI 섹션 1개)

## 변경 내용 상세

### 백엔드 (server.py)
- `do_GET` 메서드 내 `/api/campaign` 직전에 `/api/knowhow` 분기 추가
- 내부 `_read_md(path)` 함수로 3개 md 파일을 UTF-8 읽기
- 파일 없을 경우 빈 문자열 반환 (예외 안전)
- 응답: `{ "knowhow_design": "...", "knowhow_marketing": "...", "design_qc_knowhow": "..." }`

### 프론트엔드 (CampaignView.js)
- state 추가: `knowhow`(API 데이터), `knowhowTab`(활성 탭, 기본값 'design')
- `useEffect`로 마운트 시 `/api/knowhow` fetch
- 섹션 6 "노하우 라이브러리": Phase 로드맵 아래, `</main>` 직전 배치
- 3개 탭 버튼 (디자인 노하우 / 마케팅 노하우 / 디자인 QC), 가로 flex 배치
- 활성 탭: `bg-slate-700 text-white`, 비활성: `bg-slate-100 text-slate-600`
- 내용 영역: `max-h-[450px] overflow-y-auto`, `<pre>` 마크다운 표시
- API 실패 시 섹션 전체 숨김

---

## 발견 이슈 및 해결

### 자체 해결 (1건)
1. **dead code 제거** — `knowhow === undefined` 조건의 로딩 블록이 초기 state `null`과 불일치하여 실행 불가한 dead code → 해당 블록(6줄) 삭제

### 범위 외 미해결 (2건)
1. **server.py black 포맷팅** — 범위 외 사유: 기존 파일 전체에 걸친 포맷팅 이슈, 본 작업 변경분과 무관
2. **server.py 기존 pyright 경고 9건** — 범위 외 사유: 본 작업 이전부터 존재하는 미사용 변수 경고

---

## 검증 결과

- API 테스트: `curl /api/knowhow` → 3개 키 정상 반환 (design: 6170자, marketing: 1323자, qc: 2568자)
- pytest: 7 passed in 0.34s (관련 테스트 전체 통과)
- pyright: 0 errors, 0 warnings

## QC 자동 검증

```json
{
  "overall": "WARN",
  "summary": "6 PASS, 4 SKIP, 2 WARN",
  "test_runner": "PASS (7 passed in 0.34s)",
  "pyright_check": "PASS (0 errors)",
  "file_check": "PASS",
  "style_check": "WARN (기존 파일 black 포맷팅)",
  "data_integrity": "WARN (task timer running - 완료 시 해소)"
}
```
