---
task_id: task-2447
type: plan
scope: task
created: 2026-05-04
updated: 2026-05-04
status: in-progress
---

# 계획서: task-2447

**task**: task-2447
**목표**: Extension 자동 sync 하이브리드 (옵션 C) — main의 `extension/` 변경 → 자동 zip release → InsuRo 페이지가 항상 최신 버전 표시 + 다운로드 제공
**승인**: 회장 (2026-05-04) "버전이 달라지면 InsuRo 페이지의 확장 다운로드 기능이 함께 업데이트되어야 한다."
**근거**: `/home/jay/workspace/memory/tasks/task-2447.md` (Lv.3 단일 payload, 봇은 본 파일만 실행)

---

## 목표

1. `extension/manifest.json` version 변경 시 CI가 자동으로 sync 강제 (popup.html hardcoded version 제거)
2. main 푸시 시 `extension/` 변경 → GitHub Release `extension-v{version}` 자동 생성 + zip 첨부
3. InsuRo 백엔드가 캐시 + GitHub release URL fallback으로 항상 최신 버전 정보 제공
4. InsuRo `/composite-design/setup` 페이지가 v0.1.0 박제 → 동적 표시 + 신/구 비교 안내
5. 합격 6 케이스(A-F) 모두 PASS, ruleset 머지 (admin bypass 금지)

## 범위

### 포함
- workspace: `scripts/extension_version_bump.py` (CI guard) + `tests/scripts/test_extension_version_bump.py`
- workspace: `.github/workflows/extension-release.yml` (task spec 위치 — 다만 extension/은 InsuRo에 있으므로 실 동작 워크플로는 InsuRo 측에도 미러)
- InsuRo: `extension/manifest.json` v0.4.0 → v0.4.1 bump
- InsuRo: `extension/popup.html` hardcoded "v0.1.0" 제거 → 동적 표시
- InsuRo: `extension/popup.js` chrome.runtime.getManifest() 기반 version 출력
- InsuRo: `server/routes/extension.py` (router) + 5분 TTL 캐시 + GitHub release URL 구성
- InsuRo: `server/main.py` 내 기존 inline endpoint를 새 router로 위임 (URL은 backward compat 유지)
- InsuRo: `server/config/extension_version.json` 0.1.0 → 0.4.1 sync
- InsuRo: `server/tests/test_extension_routes.py` (신규)
- InsuRo: `src/pages/CompositeExtensionGuide.tsx` 설치 v ≠ 최신 v 시 stale 경고
- InsuRo: `.github/workflows/extension-release.yml` (실 트리거 가능 위치)

### 제외 (다음 페이즈 이후)
- GitHub release publish webhook → 백엔드 cache invalidation (5분 TTL로 충분)
- popup window UI 전면 재설계 (line 30 footer만 수정)
- task-2433 mmlfcp 셀렉터 fix (이미 main에 반영됨)
- task-2434/2440/2445 산출물 (forbidden)

## 위임 계획

- 백엔드(엔키): `server/routes/extension.py` + 캐시 + main.py 위임 + extension_version.json sync + 백엔드 테스트
- 프론트(이쉬타르): `CompositeExtensionGuide.tsx` stale 경고 + extension/ 파일 3종 (manifest/popup.html/popup.js) 수정
- 인프라(팀장 직접): `extension_version_bump.py` + 워크플로우 yml + 스크립트 테스트
- 테스터(닌기르수): G3 검증 직전 회귀 + L1 스모크테스트 보조

## 검증 기준

| 케이스 | 기준 | 확인 명령어 |
|---|---|---|
| A | manifest version bump 강제 | `python3 scripts/extension_version_bump.py --check` → 불일치 시 exit 1 |
| B | popup.html hardcoded version 제거 | `grep -E 'v[0-9]+\.[0-9]+\.[0-9]+' extension/popup.html` → 0건 |
| C | extension-release.yml workflow 추가 | `ls .github/workflows/extension-release.yml` (InsuRo) |
| D | `/api/insuro/composite-design/extension-version` 정상 응답 | `curl` → 0.4.1 + GitHub release URL |
| E | InsuRo setup 페이지 동적 표시 | playwright 스크린샷 또는 build PASS |
| F | 본 task PR ruleset 통과 후 머지 | `gh pr view` → merged=true + admin bypass 0건 |

## 3 Step Why 자문

**1st Why** — 왜 이 설계가 필요한가?
회장 Edge에서 v0.4.0 라벨이지만 task-2433 fix가 미반영된 옛 zip이 설치되어 매트릭스 alert 미동작. 페이지 자체도 v0.1.0 박제로 신뢰도 훼손. 버전 라벨과 실제 내용 불일치 사고가 task-2423/2429/2433 모두 반복됨.

**2nd Why** — 왜 manifest 동적 + GitHub release 자동 빌드가 최선인가?
한 곳(`extension/manifest.json`) 수정만으로 ① popup.html 표시 ② InsuRo 페이지 표시 ③ 다운로드 zip 모두 동기화. 사람이 깜빡할 여지를 제거. CI가 강제하므로 회귀 0%.

**3rd Why** — 왜 캐시 5분 TTL + GitHub URL 직링크가 다른 대안보다 나은가?
- 대안 ①: 백엔드가 zip을 직접 stream → 트래픽 비용 + 백엔드 부하. 기각.
- 대안 ②: 프론트가 GitHub API 직접 호출 → CORS + rate limit + 인증 노출. 기각.
- 채택: 백엔드 캐시 + GitHub release 302 redirect → 트래픽 GitHub가 부담, 백엔드는 metadata만, 5분 TTL로 변경 즉시 반영.
