MDN 근거 3건 수집 후 결정 7개를 근거 기반으로 확정하고 §구현 가이드 4개 sub-section 을 채웠다. 조사에서 기존 계약 2건의 사실 오류가 나왔다. - EVICTION_SCOPE_DRIFT: 브라우저 eviction 은 origin 전량 삭제이므로 FE-REG-STORAGE.evictionOrder 는 애플리케이션 주도 정리에만 유효 - CACHE_STORAGE_CONSTRAINT_DRIFT: Cache Storage 는 SW 전용이 아니다 (Window.caches 접근 가능). FE-D027 의 제한은 정책이지 플랫폼 제약이 아님 - NO_GROUND_TRUTH: ca-tmpl 은 backend 전용이라 이 branch 에 미적용 - CAPABILITY_NAME_COLLISION: ca-tmpl capabilities.yaml 과 다른 개념 신규 raw: mdn-storage-quotas-eviction-persistence, mdn-file-system-access-opfs, mdn-object-url-cache-storage 6개 신규 branch-note 전부에 governing_docs 추가.
262 lines
16 KiB
Markdown
262 lines
16 KiB
Markdown
---
|
|
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]
|
|
governing_docs: [raw/project-notes/ca-skeleton-frontend-operational-contract.md]
|
|
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
|
|
|
|
<!-- section-id: branch-parent -->
|
|
## 부모 (필수)
|
|
|
|
- [[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]]
|
|
|
|
<!-- section-id: branch-contract-packet -->
|
|
## 브랜치 계약 패킷
|
|
|
|
- **생성 시 프로젝트 개정**: `2`
|
|
- **패킷 스키마**: `contract_packet: 1`
|
|
- **완료 조건**: SW update UX·rollback SW 되돌림·sync idempotency·worker timeout fixture와 `FE-RB-007` drill이 통과한다
|
|
|
|
<!-- section-id: inherited-project-decisions -->
|
|
### 상속한 프로젝트 결정
|
|
|
|
| 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]] |
|
|
|
|
<!-- section-id: branch-local-decisions -->
|
|
### 브랜치 지역 결정
|
|
|
|
| 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` |
|
|
|
|
<!-- section-id: declared-overrides -->
|
|
### 선언한 예외
|
|
|
|
> `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 다.
|
|
|
|
<!-- GENERATED: artifact-imports:start -->
|
|
### 가져온 artifact 계약
|
|
|
|
| Artifact Ref | Owner | Producer | Schema Ref |
|
|
|---|---|---|---|
|
|
<!-- GENERATED: artifact-imports:end -->
|
|
|
|
<!-- GENERATED: project-contract-imports:start -->
|
|
## 가져온 프로젝트 계약
|
|
|
|
| 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 대상 |
|
|
<!-- GENERATED: project-contract-imports:end -->
|
|
|
|
<!-- GENERATED: received-delegations:start -->
|
|
### 수신한 위임
|
|
|
|
| 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 |
|
|
<!-- GENERATED: received-delegations:end -->
|
|
|
|
<!-- GENERATED: flow:start -->
|
|
### 가져온 흐름 단계
|
|
|
|
| Stage Ref | Order | Owner | Input | Action | Output |
|
|
|---|---:|---|---|---|---|
|
|
<!-- GENERATED: flow:end -->
|
|
|
|
<!-- section-id: branch-goal -->
|
|
## 목표
|
|
|
|
`WorkerTaskPort`·`ServiceWorkerHostPort`·`BackgroundSyncPort` 를 정의하고, `FE-D034` 의 SW 역할 분리를 구현 계약으로 내린다. 이 계약이 없으면 Background Sync 가 idempotency key 없는 mutation 을 재생해 중복 생성하고, SW precache 가 이전 release 자산을 붙들어 `FE-OC-016`·`FE-OC-017` 의 release coherence 를 깬다.
|
|
|
|
- 이슈:
|
|
- PR:
|
|
|
|
<!-- section-id: branch-scope -->
|
|
## 범위
|
|
|
|
### 포함 범위
|
|
|
|
- `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` 상속)
|
|
|
|
<!-- section-id: decision-evidence -->
|
|
## 결정-근거 매핑
|
|
|
|
| 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` 순수 모듈 참조로 완화 |
|
|
|
|
<!-- section-id: implementation -->
|
|
## 구현 가이드
|
|
|
|
> 근거 raw 자료(`FE-Q-011`) 수집 전까지 비워 둔다. SW 수명주기(installing→waiting→active)와 Background Sync 의 재시도 정책은 명세를 읽지 않고 쓸 수 없다.
|
|
|
|
<!-- section-id: edge-failure-dependency -->
|
|
## 엣지·실패·의존
|
|
|
|
- **실패·엣지 경로**
|
|
- 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 등록 전제
|
|
|
|
<!-- section-id: claims-to-verify -->
|
|
## 검증해야 할 주장
|
|
|
|
| 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`
|