# task-2843 PR-E2 — 웹앱 CompositeDesign/CrmCustomers V-path 재배선 (조회/뷰)

- **팀**: dev2 (오딘)
- **레벨**: Lv.4 | **merge_policy**: none (PR OPEN 유지, 자동머지 금지)
- **base**: origin/main a1551c8 | **브랜치**: task/task-2843-dev2
- **작업일**: 2026-07-23

---

## S — Situation
확장 프로그램이 캡처→매칭→동의→ingest를 담당(PR-D1/D2 머지 완료). 웹앱 두 페이지(CompositeDesign/CrmCustomers)는 아직 레거시 `ohmy-capture-history`·`ohmy-history` + 클라이언트 매칭(CustomerMatchDialog·link POST)에 배선되어 있었다. PR-E1(서버 V 읽기 엔드포인트, PR #121)이 이미 머지되어 조회 API가 존재.

## C — Complication
웹앱을 **조회/뷰 전용**으로 재배선해야 한다. 단, (1) 서버/확장/api.ts/integrations 변경 0, (2) 레거시 코드 삭제 금지(다른 페이지 참조 가능), (3) V 데이터 Supabase 직접 read 금지(REQUIRES_REVIEW 누출 위험), (4) dual-source 폴백 금지. 레거시 매칭 흐름은 "삭제"가 아니라 "V 뷰에서 unreachable"로 만들어야 한다.

## Q — Question
레거시 코드를 남긴 채로 V 모드에서 매칭/link 흐름을 어떻게 도달 불가로 만들 것인가?

## A — Answer
**신규 state 분리 설계**. V 모드는 기존 `captureHistory` state를 재사용하지 않고 신규 `consultationRecords` state로 분리 → 매칭 다이얼로그 트리거 useEffect(`captureHistory` 의존)와 `CustomerMatchDialog`(`matchDialogTarget` 의존)가 데이터 기근으로 자연히 inert = **코드 삭제 없이 unreachable** 달성.

---

## 수정/생성 파일 (worktree)
- `src/components/composite/ConsultationHistoryView.tsx` (신규 233줄) — `ConsultationRecord` 타입 단일 소스 export + analysis_matrix 우선/per_insurer fallback + selected_coverages/query_condition/created_at 렌더. 모든 하위 필드 방어적 optional.
- `src/components/composite/__tests__/ConsultationHistoryView.test.tsx` (신규 89줄, 6 tests)
- `src/pages/CompositeDesign.tsx` — `consultationRecords`/`consultationLoading`/`consultationError` state + `fetchConsultationHistory`(GET consultation-history/v1, 403→disabled, ok→records, try/catch 크래시 0). 레거시 조회 effect를 V fetch로 교체 → captureHistory 빈 채 유지. 신규 "최근 상담이력" 카드에 ConsultationHistoryView 렌더.
- `src/pages/CrmCustomers.tsx` — `fetchOhmyHistory` 내부를 GET consultation-history/v1?reference_id=<id>로 교체(403→준비중 안내). Dialog를 ConsultationHistoryView로 교체. capture_id 기반 reassign/이동 버튼 V뷰에서 제거(handleReassign/HistoryReassignDialog 코드는 보존, inert wiring 정리).
- `tests/e2e/composite-design-vpath.spec.ts` (신규 413줄, 2 tests)

커밋: `9f6e83f`(재배선+ConsultationHistoryView), `dd26fa9`(unused setter 정리), `e4498f4`(e2e).

## 테스트 결과
- **npx tsc --noEmit**: 에러 0 (클린)
- **npx vitest run (전체)**: 52 파일 / **795 tests PASS**, FAIL 0 (회귀 0). 신규 ConsultationHistoryView 6/6 포함.
- **npx playwright test composite-design-vpath.spec.ts**: **2/2 PASS**
  - 케이스 A(flag ON/200): V 레코드 렌더("최근 상담이력"/"분석 매트릭스"/"보험사 2곳") + 레거시 매칭 다이얼로그 hidden 확인.
  - 케이스 B(flag OFF/403): "상담이력 기능이 준비 중입니다." 렌더, 매트릭스 미노출.
  - **핵심 단언**: `/api/insuro/ohmy-capture/*/link` POST **0회** (양 케이스 route 카운터로 단언).

## L1 스모크테스트 결과
- **서버 재시작**: 성공 (`npm run build` → `vite preview --port 8099`, 빌드 성공/dist 생성, chunk-size 경고만 = 기존)
- **API 응답 확인**: 해당없음(프론트 작업) — 대신 e2e route mock으로 V GET/403 경로 검증
- **스크린샷**: `/home/jay/workspace/memory/reports/task-2843-l1-composite-design.png` — `/composite-design` 접속 시 인증 게이트로 `/login` 리다이렉트(정상 동작), 로그인 화면 정상 렌더, 콘솔 에러 0건. 인증 후 실제 V 렌더는 mock 인증 e2e(항목 3, 2/2 PASS)로 대체 검증.
- 브라우저/서버 정리: preview(8099) kill 완료, 이번 작업 좀비 프로세스 0.

## 스코프 검증
- `git diff --stat origin/main`: 5파일(위 목록)만. `server/`·`extension/`·`.github/`·`src/config/api.ts`·`src/integrations/` **미등장**.
- `grep supabase.from('consultation_history_v1')`: **0건** (V 데이터 Supabase 직접 read 없음, 서버 API 경유만).

## 모델 사용 기록
- 프레이야(프론트) — sonnet: CompositeDesign/CrmCustomers 재배선 + ConsultationHistoryView + 컴포넌트 테스트 + unused setter 정리
- 헤임달(QA) — sonnet: 전체 회귀 + e2e 작성/실행 + L1 스모크
- 팀장(오딘, opus): 설계 판단(state 분리)·분배·검토·통합. 직접 코딩 0. haiku 미사용.

## 발견 이슈 및 해결
1. **TS6133 setReassignTarget 미사용** (reassign 버튼 제거 부작용) → useState 구조분해에서 setter 드롭(`const [reassignTarget] = useState(...)`)으로 inert wiring 유지하며 해소. handleReassign/HistoryReassignDialog 코드 보존. tsc/build/test 재검증 통과.

## 미해결/범위 밖 (참고)
- `query_condition`/`selected_coverages`/`per_insurer`/`analysis_matrix`의 정확한 런타임 응답 하위 스키마는 pilot allowlist·flag 실제 ON 서버 응답으로는 미검증(서버 스키마 파일 기준 유추 + 방어적 optional 처리로 커버). flag ON pilot 단계에서 실응답 대조 권장.
- CompositeDesign "단계 B" 확장 유도 카드는 captureHistory/recentViews 기준 표시 판단 유지(task anchor 범위 밖, 미변경).

## 머지 판단
- **머지 필요**: No (merge_policy=none — PR OPEN 유지, 자동머지 금지)
- **브랜치**: task/task-2843-dev2
- **워크트리 경로**: /home/jay/projects/InsuRo/.worktrees/task-2843-dev2
- **머지 의견**: tsc 클린 + 전체 795 tests + e2e 2/2(레거시 link POST 0회 단언) + 스코프 클린. 코드 품질/충돌 위험 낮음. **다만 서버 flag ON 실응답 대조 및 Codex/ANU 독립검증 후 회장 승인 시 머지** 권장. base a1551c8 명시(scope-guard 공유브랜치 오탐 대비).

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

