# task-2225 완료 보고서

## SCQA

**S**: InsuRo의 이미지 생성 기능이 Supabase Edge Function(`generate-image`)에서 Gemini API를 직접 호출하는 구조였으며, `GOOGLE_AI_API_KEY` 미설정으로 동작하지 않는 상태였다.

**C**: 이미지 생성이 완전 중단된 상태로, 사용자는 콘텐츠에 맞는 AI 이미지를 생성할 수 없었다. 또한 플랜별 차등 이미지 품질(무료→카드뉴스, 프로→포토리얼)이 구현되지 않아 사업 차별화 포인트가 부재했다.

**Q**: Edge Function 의존을 제거하고 서버 사이드로 전환하여, 플랜별 3단계 이미지 생성(Satori/Gemini/Hybrid)을 구현할 수 있는가?

**A**: 서버 엔드포인트 `/api/insuro/generate-image` 추가 + Satori 기반 렌더러 구현 완료. 프론트엔드도 fetch API로 전환 완료. npm build 성공(12.05초), 서버 재시작 후 엔드포인트 정상 응답 확인(401 인증 게이트 동작). pytest 9건 전체 통과. Gemini/Hybrid는 서비스 계정 활성화 전이므로 Satori 폴백으로 구현.

---

## 수정 파일 목록

| 파일 | 변경 내용 | grep 검증 | 상태 |
|------|-----------|-----------|------|
| server/image_generator.py (신규) | Satori/Gemini/Hybrid 이미지 생성 모듈 | grep "PLAN_IMAGE_TIER" OK | verified |
| server/scripts/satori-render.js (신규) | Node.js Satori+resvg-js 렌더러 | grep "satori-render" OK | verified |
| server/main.py:4075 | POST /api/insuro/generate-image 엔드포인트 추가 | grep "generate-image" OK | verified |
| server/main.py:53 | import image_generator 추가 | grep "import image_generator" OK | verified |
| src/components/ImageGeneratorPanel.tsx:131 | Edge Function → fetch API 전환 | grep "INSURO_API_BASE" OK | verified |
| src/config/planSkillMap.ts:75 | PLAN_IMAGE_TIER, IMAGE_TIER_LABELS, getImageTier 추가 | grep "PLAN_IMAGE_TIER" OK | verified |
| server/tests/test_image_generator.py (신규) | image_generator 단위 테스트 9건 | pytest 9 passed OK | verified |

## 발견 이슈 및 해결

### 자체 해결 (5건)

1. **image_generator.py 미사용 import** — `base64`, `_TEMPLATES_DIR` 제거
   - 상세: Pyright 경고로 발견, 미사용 코드 삭제 (187a1f4)
2. **satori-render.js 미사용 import** — `path` require 제거
   - 상세: TypeScript 경고로 발견, 미사용 코드 삭제 (187a1f4)
3. **satori/resvg-js 미설치** — npm install로 서버 디렉토리에 설치
   - 상세: 워크트리에서 패키지가 없어 사전에 설치 처리
4. **[Gemini HIGH] 폰트 경로 하드코딩** — 환경변수 `CJK_FONT_PATH`, `CJK_FONT_BOLD_PATH` 폴백 추가
   - 상세: 배포 환경 이식성 개선 (54182b0)
5. **[Gemini MEDIUM] _generate_gemini 시그니처 불일치** — `slide_index`, `total_slides` 인자 추가
   - 상세: Satori 폴백 시 항상 0/1로 고정되던 버그 수정 (54182b0)

### 범위 외 미해결 (2건)

1. **main.py:1070, 1103 Pyright 타입 에러** — 범위 외 사유: 기존 코드의 Supabase data 타입 불일치, 본 작업과 무관
2. **Gemini/Hybrid 실 연동** — 범위 외 사유: 서비스 계정 활성화 후 별도 작업 필요 (현재 Satori 폴백)

## L1 스모크테스트 결과

- 서버 재시작: **성공** (포트 8099에서 worktree 코드 기동)
- API 응답 확인: `curl http://localhost:8099/api/status` → `{"status":"ok"}`
- 인증 게이트 확인: `POST /api/insuro/generate-image` (인증 없이) → `401 {"detail":"Missing or invalid authorization"}` — 정상
- 스크린샷: `memory/screenshots/task-2225-login.png` (로그인 페이지 — 인증 필요 기능이므로 로그인 이후 화면 접근 불가)

## 빌드 결과

- `npm run build` → **성공** (12.05초, dist/ 생성)
- Python import: `import image_generator` → **성공**
- pytest: `server/tests/test_image_generator.py` → **9 passed** (0.08초)

## 테스트 결과

- 전체 테스트: 2521 passed, 2 warnings (113.61초)
- image_generator 테스트: 9 passed (0.08초)
  - TestPlanImageTier: 6건 PASS (플랜별 티어 매핑 검증)
  - TestGenerateImageRouting: 3건 PASS (폴백, 스크립트 경로, 폰트 경로 검증)

## 머지 판단

- **머지 필요**: 완료 (PR #48 머지됨)
- **브랜치**: task/task-2225-dev2
- **PR**: https://github.com/JonghyukJeon/InsuRo/pull/48
- **Gemini PR 리뷰**: High 1건 수용, Medium 2건 수용, Medium 1건 기각 (기각 사유 PR 코멘트 기록)
- **머지 결과**: 2026-04-27 머지 완료, main 빌드 성공

## Gemini PR 리뷰 대응

### 수용 (3건)
1. [HIGH] 폰트 경로 하드코딩 → 환경변수 폴백 추가
2. [MEDIUM] _generate_gemini 시그니처 → slide_index/total_slides 인자 추가
3. [MEDIUM] token_usage_log 에러 무시 → logger.error 추가

### 기각 (1건)
- [DISMISS] 한글 플랜명 키 → 서버 전체가 한글 플랜명 기준. Enum 전환은 전체 리팩터링 필요, 범위 외.

## 모델 사용 기록

- 팀원: 토르 / 작업 내용: 백엔드 이미지 생성 모듈 + 엔드포인트 / 사용 모델: sonnet / 정당성: -
- 팀원: 프레이야 / 작업 내용: 프론트엔드 API 전환 + planSkillMap 추가 / 사용 모델: sonnet / 정당성: -
- 팀원: 헤임달 / 작업 내용: image_generator 단위 테스트 9건 / 사용 모델: sonnet / 정당성: -

## Codex 사전 검증

- 결과: **PASS** (risks=7, 차단 이슈 없음)
- 주요 high 리스크 대응:
  - 플랜명 불일치 → 서버 한글 플랜명 기준 통일 (PLAN_IMAGE_TIER에 한글 키 사용)
  - 사용량 검증 → require_feature("ai_image_generate") 서버 측 게이트 사용
  - Satori subprocess → 타임아웃 30초, stderr 로깅, FileNotFoundError 처리 포함

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


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


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


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


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

