# 작업 보고: task-2997 — InsuRo UI 정보구조·용어 정정

- 팀: dev5-team (마르둑)
- 레벨: Lv.1 (UI 메타데이터·문구)
- 저장소: `/home/jay/workspace/projects/insuro` (외부 repo)
- 워크트리: `/home/jay/workspace/projects/insuro/.worktrees/task-2997-dev5`
- 브랜치: `task/task-2997-dev5` · base sha `7534d4feea476c9ac60f2bece33316d4d57653b7` · HEAD `fb310e5`

---

## S — 상황

회장님이 InsuRo UI 를 직접 점검해 정보구조·용어 문제 4건을 발견했다. 2026-08-22 하루에 이미
프로덕션 DDL 2회·프론트 배포 3회·PR 4건 머지가 있었고 GitHub 승인 강제(Ruleset)가 꺼져 있어,
ANU·Codex 합의로 **메뉴 분류·용어·문구만** 고치는 소범위 태스크로 좁혀 승인됐다.
화면 신설·입력방식 변경은 명시적으로 제외됐다.

## C — 복잡성

선행 태스크 task-2994(전수진단)가 **네비게이션 정의가 2벌**임을 밝혀 놓았다. 이번 지시가 고치라고
지정한 `src/config/routes.ts` 의 `section` 필드는 `AppSidebar.tsx` 가 렌더러인데, 그 컴포넌트는
src 전체에서 import 0건이다. 즉 `section` 은 **화면에 반영되지 않는 죽은 메타데이터**다.
실제 라이브 메뉴는 `src/components/navigation/navigationConfig.ts` 이고, 이 파일은
`allowed_resources.paths` 밖이라 수정할 수 없다.

따라서 지시된 조치(`section` 변경)는 그대로 수행 가능하지만, **③의 의도(약관 업로드를 관리자에게만
노출)는 이 태스크 범위 안에서 달성되지 않는다.** 명세의 "명세와 실측이 다르면 임의 판단하지 말고
ANU 에 보고하라" 조항에 따라, 범위를 넓히지 않고 지시대로 수행한 뒤 실측 근거와 함께 보고한다.

## Q — 질문

지시된 4건을 범위 안에서 어디까지 실제로 달성했고, 무엇이 달성되지 않았으며 그 근거는 무엇인가?

## A — 답변

4건 모두 지시된 조치를 반영했다. 다만 ①③ 은 **화면에 아무 영향이 없음**을 실브라우저로 확증했고,
② 는 화면 일부에 용어가 혼재한 채 남았다(범위 밖 파일). ANU 판단 필요 항목 3건을 아래에 박제한다.

---

## 1. 변경 전 원문 기록 (검증 1번 — 대조 근거)

base sha `7534d4f` 시점 `src/config/routes.ts` 원문:

```
  {
    path: "/tools/policy-terms-upload",
    title: "약관 업로드",
    icon: FileCheck2,
    section: "분석&도구",
    component: PolicyTermsUpload,
  },
  {
    path: "/new-design-comparison",
    title: "신규설계 비교",
    icon: GitCompare,
    section: "분석&도구",
    component: NewDesignComparison,
  },
```

`src/pages/PolicyTermsUpload.tsx:219` 원문:
```
약관 PDF를 업로드하면 담보 조항을 정독하여 판별축(axes)을 확보합니다. 이후 보장분석
화면에서 증권과 함께 첨부하면 기존 담보 자동 매칭에 활용됩니다.
```

## 2. 지시 4건 반영 결과

### ① 신규설계 비교 section → 고객관리 — 반영됨
`section: "분석&도구"` → `section: "고객관리"` (`routes.ts:334`). 판정 기준(특정 고객 전제 → 고객관리) 적용.

### ② 견적 → 설계 용어 통일 — 7곳 전량 반영됨
`src/pages/NewDesignComparison.tsx` 의 "견적" 7곳(85·89·166·170·196·229·238행)을 "설계" 로 변경.
변경 후 이 파일의 `견적` 잔존 **0건**(grep 실측).

판정 근거(팀 최초 판정이 뒤집힌 항목):
- API 정식 필드명이 `new_design`, Pydantic 클래스가 `NewDesignIn`/`NewDesignCoverageIn`
  (`server/new_design_comparison/models.py:172,190`), 화면 h1 이 "신규설계 비교", 라우트가
  `/new-design-comparison` — **4곳이 일치**한다. 계약서의 `// 신규 견적` 은 필드에 달린 **주석**이지
  명명 권위가 아니다.
- 결과표는 회사별로 `한도`(가입금액=설계 파라미터)와 `보험료` 를 **쌍으로** 렌더링한다
  (`src/components/policy/NewDesignComparisonTable.tsx:344-364`). 가격 전용 화면이 아니다.

**"실제로 견적을 뜻하는 곳"(명세가 남겨두라고 한 항목) — 발견하여 그대로 둠**:
서버가 생성하는 disclaimer 3곳 `server/new_design_comparison/engine.py:137,198,254`
(`"신규 견적 보험료가 없어..."`, `"견적 기준금액 대비 선형 환산..."`). 항상 "보험료"/"기준금액" 과
짝을 이루는 진짜 가격 맥락이며, UX 규칙상 verbatim 렌더링 대상이고 `server/**` 는 수정 금지 범위다.

### ③ 약관 업로드 section → 관리자 — 반영됨 (단, 화면 효과 없음)
`section: "분석&도구"` → `section: "관리자"` (`routes.ts:306`).
`adminOnly: true` 는 **추가하지 않았다** — 라우터 접근 차단은 기능 변경이며 "분류와 문구만" 이라는
명세 범위를 벗어난다. 회귀 방지 테스트로 `adminOnly` 가 undefined 임을 단언해 고정했다.

### ④ 약관 업로드 설명 문구 정정 — 반영됨
변경 후:
```
이 화면은 보험 상품(보험사·상품명) 단위로 약관 지식을 시스템에 등록하는 곳으로, 특정
고객의 분석과는 별개의 작업입니다. 업로드한 약관 PDF는 담보 조항을 정독해 판별축(axes)으로
저장되며, 이미 등록된 것과 동일한 파일은 재정독 없이 재사용됩니다. 이후 보장분석 화면에서
동일한 약관 PDF를 첨부하면 여기서 등록된 지식을 찾아 기존 담보 자동 매칭에 활용합니다.
```
문구에 담은 사실은 전부 서버 코드로 확인했다(추측 없음):
- 상품(보험사·상품명) 단위 등록 — `server/routes/policy_terms_v1.py:90-219`
- 동일 파일 재정독 없이 재사용 — sha256 캐시 `policy_terms_v1.py:136-156`
- 보장분석 첨부 시 등록 지식 조회 — `server/policy_analysis_table.py:264-274` `find_product_by_sha256`
- `analyze-policy` 는 고객명·개별 증권 단위의 별개 동작 — `server/main.py:7026-7179`

## 3. 실브라우저 검증 (검증 3·4번) — 지시된 조치가 화면에 미반영임을 확증

인증을 실제로 통과한 상태에서 검증했다(로그인월 아님을 스크린샷 육안 확인).
인증 방식: 기존 E2E 패턴 재사용(`tests/e2e/crm-customers-vpath.spec.ts:26-235` Supabase 세션 주입 +
`user_roles.role` 모킹으로 `useIsAdmin` 제어).

탭별 메뉴 DOM 전량 추출 결과(스크롤 누락 방지를 위해 DOM 전수 추출 + 스크린샷 병행):
- 고객관리: 대시보드, 고객 목록, 파이프라인, 고객 증권분석, 메신저, 디지털 명함
- 분석 & 도구: 소식지분석, 보험료/환급률 분석, 인슈위키, 메디스캔, PDF 편집기, 이미지 편집기,
  **약관 업로드**, 보험사 전산정보, 각종 계산기, 외부 참고 사이트, 정보성 키워드 분석,
  복합설계 계산기, Helper 확장 설치
- AI 마케팅 / 안내 & 설정: 해당 항목 없음
- 관리자(12개): 공지사항·금소법·조직·구독 플랜·AI 엔진·이미지 피드백·개발 로드맵·CRM·소식지·
  보험료 데이터·이용 가이드·인포키워드 관리 — **약관 업로드 없음**

판정:
- `약관 업로드` 는 **관리자·비관리자 양쪽 모두 "분석 & 도구" 탭에 노출**된다. 관리자 메뉴에는 없다.
  → **검증 4번(관리자에게만 보이는지)은 달성되지 않았다.**
- `신규설계 비교` 는 4개 탭 어디에도, 관리자 메뉴에도 **없다**(navigationConfig 미등록).
  URL 직접 접근은 정상 렌더된다.
- `routes.ts` 의 `section` 변경은 화면에 **어떤 영향도 주지 않았다** — 전제(죽은 컴포넌트) 실측 확인.

라우트 직접 접근(비관리자): `/tools/policy-terms-upload` 200 정상 렌더(AdminRouteGuard 미적용 —
`adminOnly` 플래그 없음), `/new-design-comparison` 200 정상 렌더. **task-2996 가드와 충돌 없음.**

스크린샷(전부 `/home/jay/workspace/memory/screenshots/task-2997/`):
`01-dashboard-nonadmin.png`, `tab-1-고객관리.png`, `tab-2-분석도구.png`, `tab-3-AI마케팅.png`,
`tab-4-안내설정.png`, `admin-notices-adminmenu.png`, `admin-analytics-tools-tab.png`,
`direct-policy-terms-upload-nonadmin.png`, `direct-new-design-comparison-nonadmin.png`

검증 과정 특기사항: `tab-2-분석도구.png` 와 `admin-analytics-tools-tab.png` 가 md5 동일
(`ccc7c6d39e461ac87ece6f2c3981e7f2`). 관리자 캡처 진위를 의심해 교차확인한 결과,
`admin-notices-adminmenu.png` 에 관리자 사이드바 12개가 실제 렌더되어 관리자 상태가 재현됐음을
확인했다. 두 상태가 픽셀 동일한 것은 **관리자/비관리자 서브메뉴가 실제로 같기 때문**이며 정상 결과다.

## 4. 수정 파일별 검증 상태

| 파일 | 변경 | 검증 방법 | status |
|---|---|---|---|
| /home/jay/projects/InsuRo/.worktrees/task-2997-dev5/src/config/routes.ts | section 2건 | git diff 실측 + vitest 4단언 + 실브라우저 | verified |
| /home/jay/projects/InsuRo/.worktrees/task-2997-dev5/src/pages/NewDesignComparison.tsx | 견적→설계 7곳 | grep 견적 0건 + E2E 2/2 + 빌드 | verified |
| /home/jay/projects/InsuRo/.worktrees/task-2997-dev5/src/pages/PolicyTermsUpload.tsx | 설명 문구 1건 | git diff 실측 + 서버코드 사실대조 + 빌드 | verified |
| /home/jay/projects/InsuRo/.worktrees/task-2997-dev5/tests/routes.section.test.ts | 신규 4단언 | vitest 수집·통과 실측 | verified |

## 5. 빌드 · 회귀 (검증 5번) — 팀장 직접 재실행

기준선은 **명세 수치가 아니라 base sha `7534d4f` 에서 재측정**했다.

| 항목 | base(7534d4f) | HEAD(fb310e5) | 판정 |
|---|---|---|---|
| vitest Test Files | 90 passed | 91 passed | 신규 1파일만 증가 |
| vitest Tests | 1295 passed | 1299 passed | 신규 4단언만 증가, 실패 0 |
| vitest EXIT | 0 | 0 | 유지 |
| npm run build EXIT | - | 0 | PASS |

★ `vitest.config.ts:12` 가 `tests/e2e/**` 를 제외하므로 **vitest 전량 통과는 회귀 없음을 뜻하지 않는다.**
별도로 Playwright E2E 를 실행했다: 대상 spec 2/2 통과, `tests/e2e/` 전체 **10/10 passed (33.2s)**.
변경된 7개 문자열은 E2E 단언 문자열과 겹치지 않는다(spec 이 검사하는 탭 라벨
`"신규 단독 (기존 대조 미연결)"` 은 diff 에 미포함된 별개 문자열).

## 6. trip-wire 5종 실측

| trip-wire | 실측치 | 근거 |
|---|---|---|
| Critical7 | 0 | red-team-auto-review.py 3파일 전부 vulnerability_count 0 / passed true |
| PII net-new | 0 | 변경 내용이 한국어 UI 문자열 및 section 값뿐 |
| 회귀 실패 | 0 | vitest 1299 passed + Playwright e2e 10/10 passed |
| forbidden_paths 침범 | 0 | 변경 4파일 전부 allowed glob 매칭, 금지목록 매칭 0건 |
| nonce | task-2997 | 일치 |

## 7. ★ ANU 판단 필요 3건 (자가해소하지 않음)

### (1) ③의 의도가 이 태스크 범위 안에서 달성 불가 — 후속 태스크 필요
`routes.ts` 의 `section` 은 죽은 메타데이터라 `약관 업로드` 는 여전히 비관리자에게 "분석 & 도구"
탭에서 보인다(실브라우저 확증). 관리자 전용 노출을 실제로 구현하려면
`src/components/navigation/navigationConfig.ts:57` 에서 항목을 제거하고 `adminMenuItems`(130-143행)로
옮겨야 하는데, 이 파일은 `allowed_resources.paths` 밖이다.
`adminOnly: true` 추가도 접근 차단이라는 기능 변경이라 하지 않았다. **ANU 지시 없이 넓히지 않음.**

### (2) 같은 화면에 용어 혼재 잔존
`src/components/policy/NewDesignComparisonTable.tsx` **264행·303행**에 "신규 견적" 이 남아 있다
(`"...신규 견적 단독 목록이므로 고객 설명자료로..."`, `"...표시할 신규 견적 담보도 없습니다."`).
이 파일은 허용 경로 밖이라 손대지 않았다. 결과적으로 화면에 "신규 설계"(수정분)와
"신규 견적"(잔존분)이 함께 보인다. 후속 묶음에서 처리 필요.

### (3) 명세 `allowed_resources` glob 결함 — 처리 방식 보고
명세 산문은 "관련 테스트" 수정을 허용하지만, YAML glob 에는 `src/pages/__tests__/**` 만 있고
`src/config/__tests__/**` 가 없다. `routes.ts` 테스트를 co-located 위치에 두면 scope-guard 가
정당한 테스트를 차단한다. **테스트를 삭제하거나 범위를 자가 확장하지 않고**, 명세가 명시적으로
허용하고 이 저장소가 이미 사용 중인 `tests/**` 로 배치했다(`tests/routes.section.test.ts`,
커밋 `fb310e5`). vitest 가 실제로 수집·실행함을 확인했다(`✓ tests/routes.section.test.ts (4 tests)`).

## 8. 화면 구조 무변경 확인 (완료 조건)
JSON 입력 방식·컴포넌트 구조·라우트 배열 순서·import·타입 정의 모두 무변경.
diff 는 문자열 리터럴과 `section` 값 및 신규 테스트 파일뿐이다(총 4파일, +49/-11).
금지된 `src/App.tsx`·`ContextSubMenu.tsx`·`PolicyAnalysis.tsx`·`server/**`·`supabase/**` 무침범.

## L1 스모크테스트
- 서버 재시작: **성공** — vite dev 서버 기동(`npx vite --port 8080`), `curl` HTTP **200** 응답 확인.
  검증 종료 후 재확인 시 `000`(무응답)으로 정상 종료 확인. Playwright `webServer` 설정으로도 자동 기동/종료.
- API 응답 확인: **해당없음** — 이번 변경은 프론트 UI 문자열·메타데이터 전용이며 서버 코드 무변경.
  대신 라우트 직접 접근 2건이 실브라우저에서 HTTP 200 정상 렌더됨을 확인
  (`/tools/policy-terms-upload`, `/new-design-comparison`).
- 스크린샷: **9장** — `/home/jay/workspace/memory/screenshots/task-2997/` (3절 목록 참조).
  전부 로그인월이 아닌 실제 대시보드/폼 화면임을 팀장이 육안 확인.

## 모델 사용 기록
- 이쉬타르(프론트엔드) — sonnet: routes.ts section 정정, 용어·문구 반영, 테스트 경로 이동
- 나부(UX/UI) — sonnet: 용어 감사 및 재판정, 문구 설계 (분석·설계 작업이므로 haiku 미사용)
- 닌기르수(테스트/QA) — sonnet: 실브라우저 네비 검증, E2E 회귀 대조
- 마르둑(팀장) — opus: 설계·위임·교차검증. 직접 코딩 0줄. haiku 사용 0건.

## 특기사항 — 팀원 판정을 팀장이 뒤집은 건
나부가 1차로 "견적 7곳 전부 유지(변경 불필요)" 로 판정했다. 회장님이 직접 지적한 항목을
"변경 없음" 으로 닫는 판정이라 근거를 팀장이 직접 열어 검증했고, 근거 자체는 실재하나 결론에
반대 증거(필드명 `new_design` vs 주석 `// 신규 견적`, 결과표의 `한도` 컬럼 누락)가 있어 재판정을
요청했다. 나부가 자기 판정을 뒤집고 "전량 변경" 으로 정정했으며, 팀장이 새 근거를 다시 실측 확인했다.

## 비고
- PR 생성까지가 범위. **머지하지 않았다.** 머지 판단은 ANU.
- 팀원 보고는 전부 팀장이 git diff·grep·vitest·build 재실행 및 스크린샷 육안 확인으로 교차검증했다.

## 세션 통계
- 총 도구 호출: 0회

