---
task_id: task-2911
scope: task
level: 1
team: dev2-team
title: 소식지 관리 카드에 손보/생보 구분 배지 추가
status: done (순서 B — push+.done 완료, 머지·재배포는 ANU)
branch: task/task-2911-dev2
head_sha: a392540
merge_policy: none
date: 2026-08-06
---

# task-2911 — 소식지 관리 카드 손보/생보 구분 배지 (SCQA)

## Situation (상황)
InsuRo "소식지 관리" 탭 카드(회사명·제목·분석완료 배지·👁️·🗑️)에서 회사가 **손해보험사(손보)**인지 **생명보험사(생보)**인지 한눈에 구분되지 않음. 회장 요청으로 각 카드에 손보/생보 표식 필요.

## Complication (문제)
- 회사명 문자열만으로 유형을 판별해야 함(새 API 호출 금지, 순수 프론트 분류).
- 동일 브랜드가 손보·생보 양쪽 존재(예: 라이나손해보험 vs 라이나생명) → 이름 전체 기준 정확 분류 필요.
- 색상이 기존 "분석 완료" 초록 배지와 겹치면 시각 혼동.
- 용어는 회장 지시로 "손보"/"생보"(+미분류)만 허용.

## Question (핵심 질문)
회사명만으로 손보/생보를 정확히 분류하고, 기존 카드 기능 회귀 0으로 배지를 노출할 수 있는가?

## Answer (해결)
`classifyInsurer` 순수 함수(큐레이션 정확매칭 + 키워드 휴리스틱 fallback)와 배지 색상 단일 소스 헬퍼를 신설하고, 카드/검토큐 두 곳에서 재사용.

### 변경 파일 (4개, additive)
1. `src/lib/insurerType.ts` (신규, 79 lines) — `classifyInsurer(name): "손보"|"생보"|"미분류"` + `insurerBadgeMeta(type)` 색상/라벨 단일 소스.
2. `src/lib/__tests__/insurerType.test.ts` (신규, 47 lines) — vitest 6 케이스.
3. `src/pages/AdminNewsletters.tsx` (수정, +6) — 카드 회사명 옆 배지.
4. `src/components/newsletter/ReviewQueue.tsx` (수정, +6) — 검토 대기 큐 항목에 동일 배지 재사용.

### 분류 로직
- **큐레이션 맵**: 손보 17개 + 생보 20개 Set, 공백 제거 정규화 후 정확 매칭(override 최우선).
- **휴리스틱 fallback**(순서): ① `생명`·`라이프`·`생보` → 생보 → ② `손해보험`·`화재`·`해상`·`손보` → 손보 → ③ 미분류.
- 빈 문자열/공백만 → 미분류.
- **배지 색상**: 손보=`bg-blue-100 text-blue-700`(파랑) / 생보=`bg-violet-100 text-violet-700`(보라, 초록과 비충돌) / 미분류=`bg-gray-100 text-gray-600`(회색).

## 검증
### 자동 (팀장 직접 재실행)
- **vitest**: `6 passed / 0 failed` (`insurerType.test.ts`).
- **tsc**(`tsconfig.app.json`): 신규 4파일 에러 0 (나머지 에러는 전부 pre-existing 무관 파일).
- **npm run build**: PASS (`✓ built in 12.66s`, dist/sw.js 생성).

### L1 스모크테스트 결과 (필수 기록)
- **서버 재시작**: 해당없음 (프론트 정적 빌드 산출물, 관리자 페이지는 auth+Supabase 실데이터 필요 → 실카드 라이브 렌더 대신 실함수 출력 기반 렌더 채택).
- **API 응답 확인**: 해당없음 (새 API 호출 없음).
- **실함수 출력 검증** (`npx tsx`로 실제 `classifyInsurer` 호출):
  - 회장 스크린샷 6사(DB손해보험·KB손해보험·NH농협손해보험·라이나손해보험·롯데손해보험·메리츠화재) → **전부 손보** ✓
  - 삼성화재·현대해상·한화손해보험 → 손보 ✓
  - 삼성생명·한화생명·교보생명·신한라이프·KB라이프·NH농협생명·라이나생명·동양생명·미래에셋생명 → 생보 ✓
  - 라이나손해보험(손보) ↔ 라이나생명(생보) 이름 구분 ✓
  - 우체국보험·알수없는회사·빈문자열 → 미분류 ✓
- **스크린샷**: `memory/reports/task-2911-badges.png` (전송) — 실함수 출력 21건을 실제 카드 레이아웃(회사명+배지+분석완료 배지+아이콘)으로 브라우저 렌더 후 Playwright 캡처. 손보=파랑·생보=보라·미분류=회색이 정확히 구분되며 "분석 완료" 초록과 비충돌, 정렬 유지 육안 확인.
  - ※ 하네스는 lucide 아이콘을 이모지로 대체(CDN 폰트 이모지 미지원으로 아이콘만 네모 표시) — 배지 자체는 정상. 실앱은 lucide 아이콘 사용.

## 제약 준수
- src/ 4파일만 수정. server·extension·.github 불변. 새 API 0. 기존 카드 기능(업로드·👁️·🗑️·인라인 편집·분석완료 배지) 구조 무변경 → 회귀 0.

## 모델 사용 기록
- 프레이야(프론트엔드 구현): **sonnet** (general-purpose Task tool).
- 팀장(오딘, opus): 설계/검토/독립검증/L1 스모크. 직접 코딩 없음.

## 완료 처리 (순서 B, merge_policy: none)
- 커밋 a392540 → push 완료 → 원격 head==로컬 HEAD(a392540) 확인.
- **머지·재배포·독립검증(실렌더)은 ANU 소유** (본 task는 PR/keep, 팀장 머지 금지).
- ANU 독립검증 권장: clean worktree에서 vitest+build, 실제 관리자 페이지 렌더(auth+실데이터)로 카드 배지 육안.

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

