# InsuRo PWA — Service Worker가 /downloads/* 경로 404 fallback 처리 수정

## 작업 레벨: Lv.2 (긴급)

## 프로젝트
- InsuRo 프론트: `/home/jay/projects/InsuRo`

## 배경

2026-05-01 사용자가 `https://insuro.biz/downloads/insuro-helper-0.1.0.zip` 접근 시 **"404 Oops! Page not found"** SPA fallback 페이지 표시.

**검증:**
- curl로 직접 호출: `HTTP/2 200 ✅` (정상)
- dist/downloads/ 산출물 존재 확인 (insuro-helper-0.1.0.zip 11453 bytes + extension-guide/step{1..5}.png)
- production 도메인 자체 정상 (다른 정적 파일도 200)

**원인 (가설)**: PWA Service Worker가 `/downloads/*` 경로를 SPA navigation request로 잘못 분류 → navigateFallback (`/index.html`)으로 처리 → SPA Router가 라우트 못 찾음 → 404 페이지 렌더링.

**메모리 피드백 적중**: "PWA 배포 후 구버전 로드 시 SW 캐시 우선 의심 (2026-04-29)"

## 목표

`/downloads/*` 경로를 PWA SW의 navigation fallback에서 **명시적으로 제외**하여 정적 자원으로 처리되게 함.

## 진단 항목

1. **vite-plugin-pwa 또는 Workbox 설정** 위치 파악
   - `vite.config.ts` 또는 `vite.config.js`
   - `workbox` / `VitePWA` 옵션
2. **navigateFallback 설정 확인**
   - 현재 설정이 모든 경로를 SPA로 라우팅하나?
   - `navigateFallbackDenylist` 또는 `navigateFallbackAllowlist` 설정 유무
3. **현재 dist/sw.js 분석**
   - precache 168 entries 중 `/downloads/`가 포함됐나?
   - runtimeCaching 정책 확인

## 수정안

### 옵션 A: navigateFallbackDenylist 추가 (권장)
```ts
// vite.config.ts
VitePWA({
  workbox: {
    navigateFallback: '/index.html',
    navigateFallbackDenylist: [
      /^\/downloads\//,        // ← 추가
      /^\/api\//,              // 이미 있을 수도
      /\.(zip|png|jpg|webp|svg|pdf)$/,  // 정적 자원 확장자
    ],
    // ...
  }
})
```

### 옵션 B: globPatterns에서 downloads 폴더 명시 추가
```ts
workbox: {
  globPatterns: ['**/*.{js,css,html,ico,png,svg,webp,woff2}'],
  // /downloads/*.zip은 globPatterns에 미포함 → precache 안 됨 + fallback도 안 걸리도록 denylist
}
```

### 옵션 C: _redirects 또는 _headers (Cloudflare Pages)
- public/_redirects에 명시적 리다이렉트 규칙 추가:
  ```
  /downloads/* /downloads/:splat 200
  ```
- 또는 Cloudflare Pages 자체에서 정적 자원 우선 처리

## 검증 (필수 — 위임 후 사용자 환경에서 작동 확인)

1. `npm run build` → dist/sw.js 생성
2. dist/sw.js를 grep으로 navigateFallbackDenylist 확인
3. 머지 후 systemctl 재시작 (백엔드 무관, frontend 자동 배포)
4. **Playwright로 production 사이트 SW 시뮬레이션:**
   - https://insuro.biz 접속하여 SW 등록
   - https://insuro.biz/downloads/insuro-helper-0.1.0.zip 직접 navigate
   - 응답 확인 — zip 다운로드 트리거 (아니면 SW가 여전히 가로챔)
5. 사용자에게 수정 완료 보고 + "Ctrl+Shift+R로 hard reload" 안내

## affected_files

**수정:**
- `/home/jay/projects/InsuRo/vite.config.ts` (또는 .js) — VitePWA workbox 옵션
- 또는 `/home/jay/projects/InsuRo/public/_redirects` (Cloudflare Pages용, 신규 가능)

**조건부 신규:**
- `/home/jay/projects/InsuRo/public/_headers` (Content-Disposition: attachment 헤더로 zip 강제 다운로드 만들기, 선택)

## 검증 시나리오

1. `npm run build` 성공
2. dist/sw.js에 `navigateFallbackDenylist` 확인 + `/downloads/` 포함
3. PR 머지 → Cloudflare Pages 자동 배포
4. 시크릿 모드(SW 무시)에서 https://insuro.biz/downloads/insuro-helper-0.1.0.zip → 즉시 다운로드
5. 일반 모드에서 hard reload(Ctrl+Shift+R) 후 동일 URL → 다운로드 정상 (구SW가 새 SW로 갱신됨)
6. /composite-design/setup 페이지에서 "확장 다운로드" 버튼 클릭 → 다운로드 정상

## 운영 메모

- PWA SW는 한 번 등록되면 사용자 브라우저에 영속 → 새 SW 배포 후에도 옛 SW가 활성 상태일 수 있음
- 해결: SW의 `skipWaiting: true` + `clientsClaim: true` 옵션으로 새 SW 즉시 활성화
- 또는 SW 버전 prefix 변경으로 강제 갱신
- 사용자 안내: hard reload (Ctrl+Shift+R) 또는 시크릿 모드 사용 권고

## 보고

- `memory/reports/insuro-pwa-sw-downloads-fix.md`
- 변경 전후 비교 (curl 200 vs SW 404 → 둘 다 200)
- Playwright 시뮬레이션 스크린샷
- 사용자가 hard reload 후 다운로드 작동하는지 검증 결과

## goal_assertions (auto-generated)
- `npm run build`
- `npm run build`
