# 체크리스트: InsuRo 복합설계 AI 계산기

**status**: in-progress
**작성일**: 2026-04-30
**최종 갱신**: 2026-05-02 (Phase 0~4 재구성)

---

## ✅ Phase 1 (직접 크롤링) — 폐기 (task-2333 → task-2336에서 피벗)
- [x] 직접 크롤링 스크립트 — 운영 정지 (코드 보존)
- [x] `ohmy_plans/premiums/coverages` 테이블 — 참고 데이터로 보존
- [x] `/api/insuro/composite-plans` — deprecation 표시

---

## ✅ Phase 2 (Chrome Extension 피벗) — task-2336 완료
- [x] manifest.json + background.js + content.js 기본 구조
- [x] inject.js fetch/XHR 오버라이드 (`/api/ProductPremiums` 캡처)
- [x] background.js → InsuRo POST `/api/insuro/ohmy-capture`
- [x] 마이그레이션 010 (`ohmy_user_views`, `ohmy_recent_views`)
- [x] 사이드로드 zip 빌드 + 설치 가이드 페이지

---

## ✅ Phase A (UX 정합화) — task-2349 머지 완료
- [x] DOM 마커 (`document.documentElement.dataset.insuroHelper`)
- [x] postMessage HELLO 핸드셰이크 폴백
- [x] EXT_ID 의존 완전 제거
- [x] 입력 폼 완전 제거 (성별/나이/보종/플랜/담보)
- [x] 3단계 UI (확장 미설치 / 확장+캡처없음 / 확장+캡처있음)
- [x] JWT 릴레이 postMessage origin 검증
- [x] background.js onMessage SET_INSURO_JWT 핸들러

---

## ✅ Phase B (버전 정책 보충) — task-2351 머지 완료
- [x] `pingExtension()` `status` 필드 추가 ("ok" | "minor_outdated" | "major_outdated")
- [x] `MIN_EXT = { major, minor }` 임계값
- [x] CompositeDesign UI status별 분기 (메이저=잠금, 마이너=토스트)

---

## ✅ Phase 0 — 사전 조사 (task-2354, 회장 승인 대기 — 2026-05-02 완료)

### 0-1. 기존 InsuRo CRM 스키마 조사
- [x] CrmCustomers/CrmCustomerDetail 페이지 코드 확인
- [x] customers 테이블 스키마 추출 (컬럼/제약/RLS) — 보고서 2-1
- [x] 기존 고객 등록 API 엔드포인트 식별 — register-temporary-customer (main.py 6394)
- [x] CRM history/메모/연락처 관련 테이블 매핑 — 9개 테이블

### 0-2. PII 암호화 설계
- [x] Supabase Vault 사용 가능 여부 확인 — 미사용
- [x] pgcrypto 컬럼 암호화 옵션 평가 — 이미 활성(20260424180000)
- [x] 암호화 키 관리 방안 — Python Fernet + .env (운영은 Railway/Render 환경변수)
- [x] 매칭 키 hash 함수 + salt 정책 — `SHA-256(name|dob|gender|salt)`, 고정 salt 트레이드오프 명시
- [x] 표시용 마스킹 정책 — "홍**" / "850101"

### 0-3. 매핑 문서 작성
- [x] ohmymanager 캡처 → 기존 CRM 컬럼 매핑 테이블 — 보고서 5절
- [x] 신규 필드 vs 기존 필드 구분 — 보고서 5절
- [x] 회장 승인 게이트 — **결정 사항 6건 제출, 승인 대기**

### 0-4. 검증 (Phase 0 완료 게이트)
- [x] 마아트 독립 검증 PASS (사실 정합성 PASS, 차단 사항 없음)
- [x] 마아트 권고 4건 보고서 반영 완료 (4-3 git 보안, 4-4 salt 트레이드오프, 6-2 encrypted 컬럼, 7절 JWT 조건부 서술)
- [x] Codex 우려 6건 단계별 대응 매트릭스 작성 (보고서 7절)

---

## ✅ Phase 1 — 캡처 + history 기본 (task-2354, 2026-05-02 코드 + 3종 검증 PASS)

### 1-1. Extension 변경
- [x] content.js: ohmymanager 도메인 감지
- [x] content.js: 매트릭스 DOM 스크래핑 함수
  - [x] 1차 입력 추출 (이름/생년월일/성별/생손보유형/상품유형/만기)
  - [x] 만기 드롭다운 분리 파싱 ("20년/100세" → payment_term + maturity_age)
  - [x] 플랜 추출
  - [x] 보험사 컬럼 + 보험사별 합계
  - [x] 담보 행 + 가입금액 + 보험사별 단가
- [x] content.js: 매트릭스 hash 함수 (capture_hash) — 재귀 stableStringify (Codex critical 해소)
- [ ] content.js: API 응답 가로채기 백업 (DOM 셀렉터 깨짐 대비) — Phase 4로 분리
- [x] content.js: 플로팅 버튼 (Z-①)
  - [x] 우측 하단 fixed position
  - [x] 인디고 톤, "📊 InsuRo로 분석" 텍스트
  - [x] InsuRo JWT 미로그인 시 미표시 (회장 결정 #10)
  - [x] 클릭 → 매트릭스 스크래핑 → background.js OHMY_MATRIX_CAPTURED
- [x] manifest.json: 0.3.0 (host_permissions 변경 없음)
- [ ] manifest.json: 시크릿 모드 가이드 추가 — Phase 4로 분리

### 1-2. 백엔드
- [x] 마이그레이션: `server/migrations/011_ohmy_capture_history.sql` (테이블 + 4 인덱스 + 3 RLS)
- [x] PII 암호화 컬럼 (encrypted_name, encrypted_dob)
- [x] customer_key_hash 인덱스
- [x] capture_hash 유니크 인덱스 (user_id, capture_hash) — 중복 방지
- [x] customers 최소 인프라 (Phase 0.5): `supabase/migrations/20260502010000_customers_pii_columns.sql`
  - [x] encrypted_name/encrypted_dob/customer_key_hash nullable 컬럼 추가
  - [x] (agent_id, customer_key_hash) PARTIAL UNIQUE INDEX
- [x] `server/pii_crypto.py` 신규 모듈 — Fernet + key_hash + mask (5함수)
- [x] POST `/api/insuro/ohmy-capture` 엔드포인트 (main.py:7191)
  - [x] InsuRo JWT 검증
  - [x] 인카 organization 검증 (`_verify_incar_member`)
  - [x] PII 암호화 + key_hash 계산
  - [x] **server-side capture_hash 재계산** (Codex high 해소)
  - [x] capture_hash 중복 체크 → 23505 → 200 duplicate=true
  - [x] history INSERT
  - [x] (Phase 3 연동 전까지) customer_id NULL
- [x] GET `/api/insuro/ohmy-capture-history` 엔드포인트 (main.py:7245)
  - [x] 본인 history만 (user_id 필터)
  - [x] 페이지네이션 (limit/offset)
  - [x] PII 마스킹 후 반환 ("홍**" / "850101")
- [x] 옛 `composite-design/ingest` deprecation (X-Deprecated 헤더 + 주석)

### 1-3. 프론트 — history 표시
- [x] CompositeDesign 단계 C UI 재구성
  - [x] history 목록 카드 (마스킹 이름/생년월일 + 만기 + 캡처 시각)
  - [x] 항목 클릭 → 1사/2사/3사 분석 결과 표시
  - [x] 캡처 매트릭스 → 클라이언트 그리디 (`calculateCompositeFromMatrix`)
- [x] history API 호출 hook (`fetchCaptureHistory`) — extInstalled true 시 자동 호출
- [x] 0건 가이드 (Z-① 플로팅 버튼 안내 카드)
- [x] 옛 recentViews 흐름 보존 (recentViews.length > 0 시 표시)

### 1-4. 검증 (Phase 1)
- [x] py_compile / node --check / npx tsc --noEmit / npm run build 모두 PASS
- [x] 마아트 독립 검증 PASS(조건부) — 차단 사항 없음
- [x] Codex 사전 검증 pass=true (재검증) — critical 0/high 0/medium 1(이후 해소)/low 2
- [x] Gemini 리뷰 — Phase 1 승인 가능
- [ ] L1 실 환경 스모크 (서버 기동 + 엔드포인트 호출) — 회장 승인 후 staging에서 진행
- [ ] ohmymanager 실 DOM 셀렉터 보정 — 후속 PR (마아트 점검 영역)

---

## ✅ Phase 2 — 비교 UI (task-2356, 2026-05-02 코드 + 검증 PASS)

### 2-1. 클러스터링
- [x] customer_key_hash 기반 동일 고객 history 그룹화 (CompositeDesign.tsx `buildGroups`)
- [x] history 목록 UI: 고객별 카드 (`HistoryGroupCard.tsx`) + 만기/조건별 sub-history
- [x] 서버 GET history 응답에 `source` 필드 노출 (server/main.py L7412/L7467)

### 2-2. 만기별 비교
- [x] 같은 고객 + 다른 payment_term history 2건+ 자동 감지 (`new Set(payment_term).size >= 2`)
- [x] 비교 카드 UI: 20년/100세 vs 30년/100세 N열 그리드 (`MaturityCompare.tsx`)
- [x] 총 납입액 시뮬레이션 (월 보험료 × 12 × `parsePaymentTermYears`)
- [x] 추천 만기 산정 (가장 작은 total_lifetime + 차액 표시 + Award 배지)
- [ ] 보험사별 곡선 비교 (옵션, 향후 강화) — 본 Phase에서는 1사 기준 비교만 활성

### 2-3. ohmymanager "만기별 비교" 탭 캡처
- [x] content.js: ohmymanager 그 탭 감지 (`detectCaptureSource()` — pathname/hash/search 통합)
- [x] 별도 source="tab_compare"로 history 저장 (Phase 1 POST에서 이미 명세, GET 노출 추가)
- [x] InsuRo에서 별도 "탭 비교" 카테고리로 표시 (amber 톤, `tabCompareGroups`)

### 2-4. 검증 (Phase 2)
- [x] vitest 단위 테스트 4건 PASS (HistoryGroupCard 그룹화/비교 버튼 활성)
- [x] tsc --noEmit 0 / npm run build PASS / py_compile PASS / node --check PASS
- [x] L1 스모크: vite dev `:8080` 기동 성공, Playwright navigate 성공, 콘솔 error는 dev `.env.local` 미설정 1건(코드 무관)
- [x] 회귀 점검: fetchCaptureHistory / composite-calculate-from-matrix / recentViews / autoSelectedRef / capture_id 모두 생존

---

## ✅ Phase 3 — CRM 자동 연동 (task-2359, 2026-05-02 코드 + 검증 PASS)

### 3-1. 매칭 로직
- [x] customer_key_hash로 기존 CRM 고객 조회 (server/main.py:7378~7392)
- [x] 일치 시: confirm 다이얼로그 "이 고객 홍**(850101) 맞나요?" / "신규 등록" (CustomerMatchDialog.tsx + CompositeDesign 자동 검출)
- [x] 미일치 시: 신규 고객 자동 등록 (`upsert_customer_for_capture` UPSERT 패턴, customer_match.py)
- [x] 컴포지트 유니크 제약 활용: idx_customers_agent_key_hash_unique (Phase 0.5에서 이미 적용)

### 3-2. CRM 통합
- [x] customers 테이블 INSERT (auto-link) — dual-write (평문 name/birth_date + encrypted_name/dob/customer_key_hash)
- [x] ohmy_capture_history.customer_id 채움 (auto-link 후 즉시 UPDATE)
- [x] CrmCustomers.tsx에 "ohmy history" 버튼 추가 — 다이얼로그로 history 표시
- [x] history 항목 "분석 페이지로 이동" → /composite-design?capture_id=N

### 3-3. 사후 수정 (동명이인 안전장치)
- [x] HistoryReassignDialog.tsx — 잘못 매칭된 history를 다른 고객으로 이동
- [x] POST /api/insuro/ohmy-capture-history/{id}/reassign 엔드포인트

### 3-4. 검증 (Phase 3)
- [x] 신규 엔드포인트 4개 추가 + 기존 ohmy-capture 응답 확장 (match_candidate / auto_linked_customer)
- [x] 신규 컴포넌트 2개 + 페이지 통합 2개 (CompositeDesign + CrmCustomers)
- [x] vitest 16건 PASS (HistoryGroupCard 5 + CustomerMatchDialog 5 + HistoryReassignDialog 6)
- [x] tsc --noEmit 0 / npm run build PASS / py_compile PASS
- [x] Codex 사전 검증 PASS (low risk 1건 — 빈 task plan.md, 실제 영향 없음)
- [x] 마아트 독립 검증 PASS(조건부) — duplicate 분기 auto-link 누락 권고 1건 즉시 수정 완료
- [ ] L1 실 환경 스모크 (서버 기동 + 엔드포인트 호출 + 4가지 시나리오) — 회장 검증 단계에서 staging 진행
- [ ] 회장 검증: CRM 자동 등록 시범 + 동명이인 confirm 다이얼로그 UX

---

## ✅ Phase 4 — 운영 안정화 + 4가지 시나리오 E2E 자동화 (task-2365, 머지 완료 — `5dd0193` PR #82, 2026-05-02)

### 4-0. 4가지 시나리오 PASS 매트릭스 (옵션 C — 전체 모킹, Vite dev + Playwright `page.route()`)

- [x] 시나리오 1: 첫 캡처 (신규 고객) — ohmy fixture / composite-design / no-dialog (s1-1~s1-3)
- [x] 시나리오 2: 두 번째 캡처 (동일 고객 다른 만기) — match-dialog / after-confirm (s2-1~s2-3)
- [x] 시나리오 3: 동명이인 — dialog / after-new (s3-1~s3-2)
- [x] 시나리오 4: CRM 흐름 8단계 + 최종 (s4-1~s4-8 + s4-final)
- [x] 산출물 13 파일 (`tests/e2e/composite-design-phase3.spec.ts` 742줄 외)
- [x] 4 PASS / 4 (21.6s, 외부 의존성 0, 운영 영향 0)
- [x] 스크린샷 17장 + Playwright HTML 리포트

### 4-1. DOM 셀렉터 견고성 (후속 — task-2365 범위 밖)
- [ ] API 응답 가로채기 백업 활성화
- [ ] DOM 셀렉터 변경 감지 모니터링 (선택)

### 4-2. 모바일 대응 (후속 — task-2365 범위 밖)
- [ ] ohmymanager 모바일 화면 캡처 검증
- [ ] 플로팅 버튼 모바일 위치/크기 조정
- [ ] 터치 동작 + 작은 화면 대응

### 4-3. 시크릿 모드 가이드 (후속 — task-2365 범위 밖)
- [ ] 가이드 페이지에 시크릿 모드 권한 안내
- [ ] 새 브라우저 사이드로드 재설치 안내

### 4-4. history 관리 (후속 — task-2365 범위 밖)
- [ ] 사용자 수동 삭제 UI
- [ ] (선택) GoogleDrive 백업 옵션

---

## 🔧 Phase 5+ — 후속 (별도 task)

> ⚠️ task-2373 (Phase 5)이 진행될 경우 위 4-1~4-4 일부 항목과 중복 가능성 — task-2373 결과 반영 시 재정리 필요.

- [ ] 금소법 동의 화면 + 법무 검토
- [ ] PDF 출력 (A4 1장, 고객 대면용)
- [ ] 대안 조합 표시
- [ ] 인기 조합 캐시
- [ ] 보험료 변동 history (월 갱신)

---

## 검증 시나리오 종합 (회장 승인 기준)

1. ✅ **첫 캡처 (신규 고객)**: ohmymanager → 플로팅 버튼 → history1 + CRM 신규 등록
2. ✅ **두 번째 캡처 (동일 고객 다른 만기)**: 30년/100세 토글 후 클릭 → history2 + CRM 매칭 confirm
3. ✅ **만기별 비교**: 자동 비교 카드 → 20년 vs 30년 총액 차이
4. ✅ **ohmymanager "만기별 비교" 탭**: 별도 source="tab_compare"
5. ✅ **동명이인**: confirm에서 "신규 등록" → 별도 고객 카드
6. ✅ **중복 클릭**: 같은 매트릭스 hash → 저장 안 함
7. ✅ **InsuRo 미로그인**: 플로팅 버튼 미표시
8. ✅ **F12 Console 에러 0건 + npm run build PASS**

---

## 위임 게이트

### Phase 0 → Phase 1 진행 전
- 기존 CRM 스키마 조사 보고 → 회장 승인
- PII 암호화 설계 보고 → 회장 승인
- 매핑 문서 → 회장 승인

### Phase 3 → Phase 4 진행 전
- CRM 자동 등록 시범 테스트 → 회장 검증
- 동명이인 confirm 다이얼로그 UX → 회장 검증
