# [Lv.4] 웹앱 상담이력 카드 → 1·2·3사 최적조합 표시 (analysis_matrix → composite_calculator)

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "src/pages/CompositeDesign.tsx"
    - "src/components/composite/**"
    - "src/**/__tests__/**"
    - "tests/e2e/**"
  forbidden_paths:
    - "server/**"
    - "extension/**"
    - ".github/**"
  commands: ["npx vitest","npx playwright","npx tsc","git"]
  merge_policy: "none"
  ttl_hours: 20
```
> ★ merge_policy=none. base=현 origin/main. 신규 브랜치. **서버 변경 0**(엔드포인트·계산엔진 이미 존재).

## 배경 (회장 핵심 요구 + Codex 조율 확정)
파일럿 왕복(캡처→저장→조회) 성공. 그런데 insuro.biz `ConsultationHistoryView`(상담이력 카드)가 **저장된 담보 원본만 나열** — 회장이 원하는 **1사/2사/3사 최적조합**이 안 뜬다. 데이터·엔진 다 존재:
- 저장 레코드(V) `analysis_matrix` = `{insurers:[{code,name}×10], coverages:[{cd,name,amount,premiums:{보험사코드→보험료}}×32]}` (담보×보험사 격자 완비, 실측 확인).
- `POST /api/insuro/composite-calculate-from-matrix`(server/main.py:7178) → `composite_calculator.calculate_composite_from_matrix`. 입력 `{matrix, selected_coverages}`, 반환 `{single_best:{insurer,insurer_code,total,coverages[]}, dual_best:{insurers[{name,code,total}],total,saving_pct,coverages[]}, triple_best:동형, data_count}`.

## 작업
1. **ConsultationHistoryView(또는 CompositeDesign) 각 레코드에**: 저장된 `analysis_matrix`+`selected_coverages`로 **`POST /api/insuro/composite-calculate-from-matrix`** 호출. body = `{ matrix: record.analysis_matrix, selected_coverages: record.selected_coverages ?? null }`. 인증=기존 `getAuthHeader()`.
2. **1·2·3사 결과 렌더**(회장 요구 산출):
   - **1사**: 가장 싼 단일 보험사 + 총 보험료
   - **2사**: 최적 2사 조합 + 담보별 어느 보험사 배정 + 총액 + **절감률(saving_pct)**
   - **3사**: 최적 3사 조합 + 구성 + 총액 + 절감률
   - 1사 대비 절감액/절감률 강조. (가능하면 20년 환산·표/그래프 — 계산엔진 반환에 있으면 표시, 없으면 총액·절감만.)
3. **per-record 상태**: hydrate(계산 호출)·loading·error(계산 실패 시 안내) 상태 추가. 담보 원본 나열은 접이식(details)로 보조 유지 가능, **주 표시는 1·2·3사 조합**.
4. **flag OFF/빈 결과 graceful** 유지(기존 V 조회 흐름 회귀 0).

## 제약
- **서버 변경 0**. src/ 만. 안전: matrix 는 반드시 **이미 per-FA 스코프된 GET 레코드**에서 가져와 계산 엔드포인트에 전달(임의 matrix 주입 금지).
- 기존 vpath/crm-vpath e2e 회귀 0.

## 검증
- `npx tsc` 클린. 단위/컴포넌트: analysis_matrix mock → 계산 호출 → 1·2·3사 렌더. 계산 실패 → error 상태. 
- e2e(가능): 저장 레코드 있는 상태 mock → 1·2·3사 카드 렌더. 기존 e2e 회귀 0.
- 실 스모크(선택): 회장 파일럿 레코드로 1·2·3사 실제 계산 렌더.

## 완료 (★ 순서 B)
- 변경 = src/ 만 (`git diff --stat`).
- **dev6 금지** — dev1. 커밋 → push → finish-task **foreground 1회** → .done 즉시 종료. **background+wait 금지.** ANU 원격 검증·머지·CF Pages 배포는 ANU가.

## goal_assertions (auto-generated)
- `npx tsc`
