---
task_id: task-2342
type: plan
scope: task
created: 2026-05-02
updated: 2026-05-02
status: completed
---

# 계획서: task-2342

**task**: task-2342
**목표**: PWA Service Worker가 `/downloads/*` 경로를 SPA navigation으로 잘못 분류하여 SPA Router 404 페이지를 표시하던 문제 해소
**승인**: 아누(개발실장) 자동 승인 (Lv.2)
**근거**: 사용자 보고 (2026-05-01) — `https://insuro.biz/downloads/insuro-helper-0.1.0.zip` 직접 접근 시 404 페이지 노출

---

## 목표

`/downloads/*` 경로를 PWA SW의 navigation fallback에서 명시적으로 제외하여 정적 자원으로 처리되게 한다. 사용자가 zip URL 직접 접근 시 zip 다운로드가 정상 트리거되어야 한다.

## 범위

### 포함
- `vite.config.ts`의 `workbox.navigateFallbackDenylist`에 `/^\/downloads\//` 추가
- 추가 안전장치로 정적 다운로드 확장자 정규식(`/\.(?:zip|pdf|exe|dmg|tar|gz)$/`)도 함께 등록
- `public/_headers`에 `/downloads/*.zip` Content-Disposition: attachment 블록 추가
- 빌드 → dist/sw.js 검증 → PR → Gemini 리뷰 → 머지 → 프로덕션 검증

### 제외 (다음 페이즈 이후)
- `skipWaiting`/`clientsClaim` 명시적 적용 (vite-plugin-pwa `registerType: "autoUpdate"`가 사실상 동등 동작 수행 — 추가 명시는 별도 task로 분리 가능)
- 기존 사용자 SW 강제 갱신용 SW 버전 prefix 변경 (필요 시 운영 안내로 hard reload 권고로 대체)

## 위임 계획

- 설계/검증: **마르둑(팀장)** — 단일 파일 수정, 위험 낮음
- vite.config.ts + _headers 수정 + 빌드: **이쉬타르(프론트)** — Edit + npm run build + grep 검증
- L1 스모크테스트(로컬 dist 서빙 + Playwright fetch): **닌기르수(테스터)** — zip magic number 확인

## 검증 기준

- 빌드: `npm run build` 성공 + dist/sw.js에 `/downloads/` denylist 패턴 4개 포함
- 로컬 검증: Playwright `fetch('/downloads/insuro-helper-0.1.0.zip')` → firstBytes `50 4b 03 04` (ZIP magic)
- 프로덕션 검증: `curl -s https://insuro.biz/sw.js | grep -oE 'denylist:\[[^]]*\]'` → 4개 regex 포함
- 프로덕션 zip 검증: `curl https://insuro.biz/downloads/insuro-helper-0.1.0.zip` → 11453 bytes ZIP archive
