--- title: branch / feature-frontend-background-execution-worker-contract source_type: branch-note status: raw id: BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-033 kind: project-work-item project: ca-skeleton-frontend-operational-contract work_item: WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-033 inherits: [DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-SERVICE-WORKER-ROLE-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-BACKGROUND-SYNC-001@1, DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-WORKER-TASK-001@1] refines: [] overrides: [] depends_on: [WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-005, WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-024] imports: [FE-GATE-032@1, FE-OC-009@1, FE-OC-016@1, FE-OC-017@1, FE-OC-025@1] delegates: [DELEG-FE-011@1] accepts_delegations: [DELEG-FE-007@1] contract_packet: 1 branch: feature-frontend-background-execution-worker-contract parent_branch: related_projects: [ca-skeleton-frontend, ca-skeleton] tags: [branch, ca-skeleton-frontend, worker, service-worker, background-sync] created: 2026-07-28 target_merge: status_label: in-progress --- # branch: feature-frontend-background-execution-worker-contract ## 부모 (필수) - [[raw/project-notes/ca-skeleton-frontend-operational-contract]] 형제 branch (같은 부모, 이번 확장에서 함께 생성): - [[raw/branch-notes/feature-frontend-binary-file-io-store-contract]] - [[raw/branch-notes/feature-frontend-cache-tier-cross-tab-invalidation-contract]] - [[raw/branch-notes/feature-frontend-large-object-transfer-contract]] - [[raw/branch-notes/feature-frontend-multi-protocol-api-transport-contract]] - [[raw/branch-notes/feature-frontend-realtime-subscription-lifecycle-contract]] ## 브랜치 계약 패킷 - **생성 시 프로젝트 개정**: `2` - **패킷 스키마**: `contract_packet: 1` - **완료 조건**: SW update UX·rollback SW 되돌림·sync idempotency·worker timeout fixture와 `FE-RB-007` drill이 통과한다 ### 상속한 프로젝트 결정 | Decision Ref | Project Summary | Branch Application | Source | |---|---|---|---| | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001@1` | 신규 runtime capability 6종은 FE-REG-CAPABILITY flag로 default OFF이며 활성화는 owner·gate·runbook을 동반한다 | `CAP_FE_BACKGROUND_EXEC` 를 이 branch 가 소유하고 default OFF 로 유지한다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-SERVICE-WORKER-ROLE-001@1` | service worker는 역할을 분리해 release asset precaching은 default off로 유지하고 push·background sync·Cache Storage 호스트 역할만 capability opt-in으로 허용하며 update UX 계약을 요구한다 | `ServiceWorkerHostPort` 의 등록 범위와 §9.7 update surface state 에 적용한다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-BACKGROUND-SYNC-001@1` | background sync 재생은 idempotency keyed operation만 허용한다 | `BackgroundSyncPort` 의 큐 등록 조건에 적용한다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-WORKER-TASK-001@1` | Web Worker 작업은 structured-clone 또는 Transferable로만 통신하고 timeout과 terminate를 계약하며 worker 안에서 application port를 재구현하지 않는다 | `WorkerTaskPort` 의 통신·수명 계약에 적용한다 | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | ### 브랜치 지역 결정 | Decision ID | Decision | Relation | Supporting Claims | Status | |---|---|---|---|---| | D1 | `skipWaiting` 을 자동 호출하지 않는다. 새 SW 활성화는 사용자 주도 action 으로만 수행한다 | `refines DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-SERVICE-WORKER-ROLE-001@1` | 근거 raw 미수집 (`FE-Q-011`) | `proposed` | | D2 | `serviceWorkerVersion` 을 release token 으로 산출해 rollback 시 SW 되돌림 여부를 판정 가능하게 한다 | `local` | 근거 raw 미수집 (`FE-Q-011`) | `proposed` | | D3 | worker 엔트리(`src/workers/*.worker.js`)와 `public/sw.js` 는 `presentation`·`application`·`domain` 을 import 하지 않는다 | `refines DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-WORKER-TASK-001@1` | 근거 raw 미수집 (`FE-Q-011`) | `proposed` | ### 선언한 예외 > `FE-D019`("service worker와 offline asset cache는 default off") 는 `FE-D034` 로 **superseded** 되었다. 이 branch 는 그 후속 결정의 owner 이며, 아래는 예외 선언이 아니라 대체 사실의 기록이다. | Override ID | Overrides | Reason | Approval | Status | |---|---|---|---|---| | — | — | 예외 없음. `DEC-...-OFFLINE-CACHE-001@2` 를 그대로 소비한다 | — | — | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-OFFLINE-CACHE-001@2` 의 소비자는 [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] 이며, 이 branch 는 그 결정을 `SERVICE-WORKER-ROLE-001@1` 로 상속받아 SW 쪽 절반을 구현한다. precaching 절반은 여전히 release branch 소유이자 default off 다. ### 가져온 artifact 계약 | Artifact Ref | Owner | Producer | Schema Ref | |---|---|---|---| ## 가져온 프로젝트 계약 | Ref | Owner | 요약 | Branch 적용 | |---|---|---|---| | `FE-GATE-032@1` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | SW update UX·sync idempotency·worker timeout fixture 가 실패하면 merge·release 를 MUST 차단 | 이 branch 가 owner 로서 fixture 와 report 를 산출 | | `FE-OC-009@1` | [[raw/branch-notes/feature-api-client-response-envelope-contract]] | retry는 safe/idempotent request에 한정하고 cap·jitter·`Retry-After`를 MUST 적용 | 지연 재생도 같은 idempotency 조건을 따름 | | `FE-OC-016@1` | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] | HTML, asset, runtime config, release manifest cache policy를 MUST 구분 | SW 가 이 정책을 훼손하지 않음 | | `FE-OC-017@1` | [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] | rollback은 immutable prior release로 수행하고 build/config/API compatibility를 MUST 검증 | `serviceWorkerVersion` 을 compatibility 판정에 추가 (`DELEG-FE-011`) | | `FE-OC-025@1` | [[raw/branch-notes/feature-frontend-operational-runbook-contract]] | boot, chunk mismatch, API degradation, telemetry failure, rollback, realtime 연결, background 실행 runbook을 MUST 유지 | `FE-RB-007` 의 기술 escalation 대상 | ### 수신한 위임 | Delegation Ref | From | Concern | Status | |---|---|---|---| | `DELEG-FE-007@1` | [[raw/branch-notes/feature-frontend-realtime-subscription-lifecycle-contract]] | `fe.deleg.sw-host-for-push` | accepted | ### 가져온 흐름 단계 | Stage Ref | Order | Owner | Input | Action | Output | |---|---:|---|---|---|---| ## 목표 `WorkerTaskPort`·`ServiceWorkerHostPort`·`BackgroundSyncPort` 를 정의하고, `FE-D034` 의 SW 역할 분리를 구현 계약으로 내린다. 이 계약이 없으면 Background Sync 가 idempotency key 없는 mutation 을 재생해 중복 생성하고, SW precache 가 이전 release 자산을 붙들어 `FE-OC-016`·`FE-OC-017` 의 release coherence 를 깬다. - 이슈: - PR: ## 범위 ### 포함 범위 - `WorkerTaskPort` — worker 생성·통신(structured-clone/Transferable)·timeout·terminate - `ServiceWorkerHostPort` — SW 등록·갱신 상태 스트림, §9.7 update surface state - `BackgroundSyncPort` — keyed mutation 만 큐 등록 - `serviceWorkerVersion` release token 산출과 rollback 판정 입력 제공 - worker/SW 엔트리 파일의 import 경계 강제 - `FE-RB-007` 의 기술 escalation - `CAP_FE_BACKGROUND_EXEC` capability 행 소유 - `DELEG-FE-007` 수신 — WebPush 용 SW 호스팅 ### 제외 범위 - **use case, domain model, business rule** — port 와 adapter 계약까지만 정의한다 - **release asset precaching** — `FE-D034` 에 의해 default off 로 유지되며 [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] 소유 - rollback **판정** 자체 — `DELEG-FE-011` 로 위임. 이 branch 는 `serviceWorkerVersion` 입력만 제공 - push 발송 서버·VAPID 개인키 — `FE-Q-014` - push 구독의 UX·권한 요청 흐름 — [[raw/branch-notes/feature-frontend-realtime-subscription-lifecycle-contract]] 의 `PushSubscriptionPort` 소유 - worker 안에서 수행할 도메인 계산 규칙 ## 근거 (필수, 최소 1개+) | Source | 정당화하는 결정 | |---|---| | `[[docs/superpowers/specs/2026-07-28-ca-skeleton-frontend-runtime-adapter-features-design]]` §5.1·§5.4·§9.4 | port 분해, worker/SW 엔트리 import 경계, SW update surface state | | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] §7.7·§12.5 | idempotency 계약과 rollback invariant | **근거 등급 경계**: `FE-D034`(SW 역할 분리)의 rationale 은 `precaching은 release coherence 훼손 원인이나 push·sync는 SW 없이는 불가; project decision` 이고, `FE-D035`·`FE-D036` 은 각각 `FE-D016` 상속과 project decision 이다. Service Worker·Background Sync·Web Push 명세를 다룬 raw 자료는 이 repo 에 없다(`FE-Q-011`). `skipWaiting` 금지는 명세가 아니라 `FE-OC-016` coherence 에서 도출한 project 판단이다. ## TODO - [ ] `WorkerTaskPort` 인터페이스와 timeout·terminate 계약 확정 — 등급: `planned` - [ ] `ServiceWorkerHostPort` 인터페이스와 등록 scope 확정 — 등급: `planned` - [ ] `BackgroundSyncPort` 의 keyed-only 등록 조건 — 등급: `planned` - [ ] §9.7 update surface state 와 사용자 주도 적용 action — 등급: `planned` - [ ] `serviceWorkerVersion` 토큰 산출과 release manifest 연결 — 등급: `planned` - [ ] worker/SW 엔트리 import 경계 lint fixture — 등급: `planned` - [ ] rollback 시 SW 되돌림 fixture — 등급: `planned` - [ ] `FE-RB-007` drill assertion — 등급: `planned` - [ ] `FE-GATE-032` background execution report 산출 — 등급: `planned` ## 진행 중 메모 `FE-D019` 를 되살리려는 압력이 나중에 생길 수 있다 — "이왕 SW 있으니 자산도 캐시하자". 그 순간 `FE-OC-016`·`FE-OC-017` 이 다시 위태로워진다. precaching 을 켜려면 `FE-D034` 를 다시 supersede 하는 절차(§3.3)를 밟아야 하며, 그때 update UX 와 rollback drill 이 함께 설계되어야 한다는 조건이 `FE-D034` 의 revisit trigger 에 이미 적혀 있다. ## 결정 사항 - 2026-07-28: 자동 `skipWaiting` 금지 / 이유: 열린 탭이 release 를 갈아타면 HTML·asset·config 가 섞임 / 검토한 대안: 유휴 시 자동 적용 / 근거: `FE-OC-016` coherence 에서 도출, 근거 raw 미수집 - 2026-07-28: background sync 는 keyed only / 이유: 지연 재생은 중복 write 위험이 온라인 재시도보다 큼 / 검토한 대안: 모든 mutation 재생 + 서버 dedup 신뢰 / 근거: `FE-D035` (`FE-D016` 상속) ## 결정-근거 매핑 | Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk | |---|---|---|---|---|---| | D1 | 자동 `skipWaiting` 금지 | 항상. 모든 탭이 단명하는 제품이면 재검토 | `FE-OC-016` coherence 도출 | `project decision` | 사용자가 적용 action 을 누르지 않으면 구버전이 오래 남음 | | D2 | `serviceWorkerVersion` release token | SW 를 쓸 때. 안 쓰면 토큰은 비어 있음 | 없음 — `FE-Q-011` | `project-local default` | release manifest 스키마가 커짐 | | D3 | worker/SW 엔트리의 import 경계 | 항상 | 없음 — `FE-Q-011` | `project-local default` | 공유 로직을 복제하게 될 수 있음 — `domain` 순수 모듈 참조로 완화 | ## 구현 가이드 > 근거 raw 자료(`FE-Q-011`) 수집 전까지 비워 둔다. SW 수명주기(installing→waiting→active)와 Background Sync 의 재시도 정책은 명세를 읽지 않고 쓸 수 없다. ## 엣지·실패·의존 - **실패·엣지 경로** - SW 등록·갱신 실패 → `SW_REGISTRATION_FAILED`, SW 없이 계속. **제품 흐름을 차단하지 않음** - 새 SW 설치 완료 → `sw-update-pending`. 실패가 아니라 상태이며 error kind 가 아님 - Background Sync API 미지원 → `BACKGROUND_SYNC_UNSUPPORTED`, 온라인 복귀 시 전면 재시도로 대체 - keyed 아닌 mutation 의 재생 시도 → `BACKGROUND_SYNC_REPLAY_REJECTED`, 큐에서 제거하고 재생하지 않음 - Worker 생성 불가 → `WORKER_UNAVAILABLE`, 메인 스레드 대체 경로 또는 기능 저하 - worker task timeout → `WORKER_TASK_TIMEOUT`, terminate 후 결과를 기다리지 않음 - rollback 후 SW 버전 불일치 → `FE-RB-007` 절차. `serviceWorkerVersion` 을 함께 되돌림 - **다른 계약 의존** - [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] 의 rollback 판정에 의존 (`DELEG-FE-011` 로 위임) - [[raw/branch-notes/feature-api-client-response-envelope-contract]] 의 idempotency 계약에 의존 — keyed 판정 기준 - [[raw/branch-notes/feature-frontend-realtime-subscription-lifecycle-contract]] 가 이 branch 의 SW 호스팅에 의존 (`DELEG-FE-007`) - [[raw/branch-notes/feature-frontend-binary-file-io-store-contract]] 의 Cache Storage backend 는 이 branch 의 SW 등록 전제 ## 검증해야 할 주장 | Claim | Why uncertain | How to verify | Status | |---|---|---|---| | `skipWaiting` 이 자동 호출되지 않는다 | 라이브러리 기본값이 자동인 경우가 많음 | grep + fixture — SW 스크립트에 무조건 `skipWaiting` 호출 0건 | `planned` | | keyed 아닌 mutation 이 replay 되지 않는다 | 큐 등록 시점에 idempotency 를 안 보고 넣기 쉬움 | negative fixture — `idempotency: none` operation 등록 시도가 거부되는지 | `planned` | | rollback 후 SW 버전이 target release 와 일치한다 | SW 는 별도 수명주기를 가져 뒤처지기 쉬움 | drill — rollback 후 `serviceWorkerVersion` 대조 (`FE-RB-007`) | `planned` | | worker task 가 timeout 후 terminate 된다 | terminate 없이 결과만 무시하면 스레드가 남음 | fixture — timeout 후 worker 인스턴스 수 확인 (`FE-NFR-019`) | `planned` | | SW 등록 실패가 제품 흐름을 막지 않는다 | boot 경로에 넣으면 막힘 | fixture — 등록 실패 강제 후 route mount 성공 확인 | `planned` | | worker/SW 엔트리가 상위 layer 를 import 하지 않는다 | 번들러가 조용히 끌어옴 | dependency-cruiser fixture — 금지 import 검출 | `planned` | | SW 활성화가 열린 탭의 release 를 바꾸지 않는다 | `clients.claim()` 이 같은 문제를 일으킴 | integration test — 활성화 후 기존 탭의 asset 버전 유지 확인 | `needs-confirmation` | ## 관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때) 미생성. ## 마주친 문제 없음. ## 묶음 (이 branch에서 파생된 자료) ### Sub-branches (세부 작업) 아직 없음. ### 오류 기록 (이 branch 작업 중 발생) 아직 없음. ### 면접 준비 (이 작업에서 나올 수 있는 면접 질문) 아직 없음. ### 강의 (이 작업을 위해 학습한 강의) 아직 없음. ### job-posting tie-ins (이 작업에서 파생된 글감) 아직 없음. ## 관련 일일 노트 - 아직 없음 ## 완료 후 정리 - PR 링크: - 리뷰 메모: - 머지 결과 / 배포 환경: - **wiki 추출 대상** (verified만, `wiki/projects/`로만 추출): - `actually-implemented` 항목: 없음 - `locally-verified` 항목: 없음 - `prod-verified` 항목: 없음 - **추출하지 않을 항목**: 현재 전 항목 `planned`