diff --git a/raw/project-notes/ca-skeleton-frontend-operational-contract.md b/raw/project-notes/ca-skeleton-frontend-operational-contract.md index f956c44..898ca7c 100644 --- a/raw/project-notes/ca-skeleton-frontend-operational-contract.md +++ b/raw/project-notes/ca-skeleton-frontend-operational-contract.md @@ -399,14 +399,27 @@ Out of scope: | `FE-D015` | retry는 initial call 이후 최대 2회, exponential backoff + full jitter, cap 2s | `conditional-default` | `feature-api-client-response-envelope-contract` | `FE-OC-009`, `FE-OC-021` | retry storm 억제를 위한 project default | backend SLO·rate limit contract 확정 | — | | `FE-D016` | mutation 자동 retry는 stable idempotency key와 backend replay contract가 있을 때만 허용 | `accepted-documented-only` | `feature-api-client-response-envelope-contract` | `FE-OC-009`, `FE-OC-023` | duplicate write 방지 invariant | mutation이 naturally idempotent임이 schema로 증명 | — | | `FE-D017` | auth lifecycle은 외부 owner, skeleton은 `AuthSessionPort`만 소비 | `accepted-documented-only` | `feature-frontend-auth-session-integration-contract` | `FE-OC-010` | [[raw/project-notes/keycloak-patterns-overview]] | skeleton이 독립 auth product로 scope 변경 | — | -| `FE-D018` | route/API-operation/env/storage/error/query/telemetry/release token은 8개 registry로 관리 | `accepted-documented-only` | `feature-frontend-contract-registry-governance` | `FE-OC-013`, `FE-OC-022` | rename·compatibility 영향 추적 | code generation SSOT 채택 | — | -| `FE-D019` | service worker와 offline asset cache는 default off | `conditional-default` | `feature-frontend-release-cache-rollback-contract` | `FE-OC-016`, `FE-OC-017`, `FE-OC-023` | stale asset·config mismatch surface 축소 | offline product requirement와 update UX가 설계됨 | — | +| `FE-D018` | route/API-operation/env/storage/error/query/telemetry/release/capability token은 9개 registry로 관리 | `accepted-documented-only` | `feature-frontend-contract-registry-governance` | `FE-OC-013`, `FE-OC-022` | rename·compatibility 영향 추적 | code generation SSOT 채택 | — | +| `FE-D019` | service worker와 offline asset cache는 default off | `superseded` | `feature-frontend-release-cache-rollback-contract` | `FE-OC-016`, `FE-OC-017`, `FE-OC-023` | stale asset·config mismatch surface 축소 | `FE-D034`가 2026-07-28에 대체 — SW 역할을 precaching과 push/sync 호스트로 분리 | — | | `FE-D020` | hashed asset은 immutable, HTML·runtime config·release manifest는 revalidate/no-store 정책 분리 | `accepted-documented-only` | `feature-frontend-release-cache-rollback-contract` | `FE-OC-016`, `FE-OC-017` | release coherence invariant | hosting cache primitive 제약 | — | | `FE-D021` | telemetry는 best-effort queue + redaction, sink failure는 UI를 실패시키지 않음 | `accepted-documented-only` | `feature-frontend-observability-logging-trace-contract` | `FE-OC-014` | operational isolation | regulated audit event처럼 delivery guarantee가 필요한 별도 channel 도입 | — | | `FE-D022` | test stack default는 Vitest + RTL + MSW + Playwright + axe | `conditional-default` | `feature-frontend-test-taxonomy-contract` | `FE-OC-020` | Vite/browser/component/e2e responsibility 분리 | organization test platform이 대체 | — | | `FE-D023` | static release는 immutable release directory + atomic active pointer로 배포 | `conditional-default` | `feature-frontend-release-cache-rollback-contract` | `FE-OC-016`, `FE-OC-017`, `FE-OC-025` | rollback 가능 artifact requirement | provider가 다른 atomic primitive만 제공 | — | | `FE-D024` | dependency lock, secret scan, vulnerability scan, license inventory, dependency review를 merge/release gate로 분리 (lock 은 `FE-GATE-001`, 나머지 4개는 `FE-GATE-013`) | `accepted-documented-only` | `feature-frontend-build-bundle-supply-chain-contract` | `FE-OC-018`, `FE-OC-019`, `FE-OC-020` | supply-chain scope 최소값 | organization security policy가 더 강한 gate 지정 | — | | `FE-D025` | sample slice는 제거 가능한 contract fixture이며 product import를 금지 | `accepted-documented-only` | `feature-sample-feature-slice-contract-fixture` | `FE-OC-024` | backend skeleton의 sample-fixture 운영 원칙을 frontend에 적용 | fixture 없이 동일 gate coverage를 증명 | — | +| `FE-D026` | 신규 runtime capability 6종은 `FE-REG-CAPABILITY` flag로 default OFF이며 활성화는 owner·gate·runbook을 동반한다 | `conditional-default` | `feature-frontend-env-runtime-config-contract` | `FE-OC-004`, `FE-OC-022`, `FE-OC-027`, `FE-OC-028`, `FE-OC-029`, `FE-OC-030`, `FE-OC-031`, `FE-OC-032` | project-local default, 외부 source claim 아님 | 특정 capability가 제품 필수가 되어 상시 활성이 요구됨 | — | +| `FE-D027` | 로컬 바이너리 backend는 IndexedDB를 default로 하고 OPFS는 대용량 순차 write에 opt-in, Cache Storage는 service worker 호스팅 response cache 전용이다 | `conditional-default` | `feature-frontend-binary-file-io-store-contract` | `FE-OC-013`, `FE-OC-027` | project-local default, 외부 source claim 아님 | OPFS 브라우저 지원 또는 quota 정책이 바뀜 | — | +| `FE-D028` | 탭 간 무효화는 BroadcastChannel 우선에 `storage` event fallback을 쓰고 leader election 없이 무효화 key만 전파한다 | `conditional-default` | `feature-frontend-cache-tier-cross-tab-invalidation-contract` | `FE-OC-012`, `FE-OC-028` | project-local default, 외부 source claim 아님; 값 전파는 PII·stale 표면을 넓힘 | 다중 탭 실시간 협업이 제품 요구가 됨 | — | +| `FE-D029` | presigned URL 획득은 shared client를 경유하고 실제 byte 전송은 session credential을 첨부하지 않는 transfer adapter가 수행한다 | `accepted-documented-only` | `feature-frontend-large-object-transfer-contract` | `FE-OC-006`, `FE-OC-019`, `FE-OC-029` | credential 유출 방지 invariant, project decision | 스토리지가 same-origin proxy만 제공 | — | +| `FE-D030` | 재개 가능 전송은 part size·병렬도·part 재시도 상한을 registry로 고정하고 part 상태를 `BlobStorePort`에 보존한다 | `conditional-default` | `feature-frontend-large-object-transfer-contract` | `FE-OC-029` | project-local default, 외부 source claim 아님 | 스토리지 제공자가 다른 multipart 제약을 요구 | — | +| `FE-D031` | transport default는 REST이고 GraphQL·gRPC-Web·Connect-Web은 `FE-REG-API`의 protocol 필드로 opt-in하며 미지원 환경은 REST gateway로 fallback한다 | `conditional-default` | `feature-frontend-multi-protocol-api-transport-contract` | `FE-OC-006`, `FE-OC-007`, `FE-OC-030` | project-local default, 외부 source claim 아님 | backend가 단일 비-REST protocol만 제공 | — | +| `FE-D032` | 실시간 transport는 SSE를 우선하고 양방향이 필요하면 WebSocket, 둘 다 불가할 때만 최소 간격·backoff·visibility gating을 갖춘 bounded polling을 쓴다 | `conditional-default` | `feature-frontend-realtime-subscription-lifecycle-contract` | `FE-OC-031` | project-local default, 외부 source claim 아님; polling은 마지막 수단 | backend가 SSE를 제공하지 않거나 양방향이 기본 요구가 됨 | — | +| `FE-D033` | 실시간 연결은 full jitter backoff와 30초 cap을 쓰고 재시도 상한 후 terminal 상태로 전이하며 resume은 `Last-Event-ID` 또는 cursor로 수행하고 unmount 시 구독을 해제한다 | `conditional-default` | `feature-frontend-realtime-subscription-lifecycle-contract` | `FE-OC-011`, `FE-OC-031` | 재연결 폭주·구독 누수 억제, project decision | backend가 서버 주도 재연결 정책을 계약으로 제공 | — | +| `FE-D034` | service worker는 역할을 분리해 release asset precaching은 default off로 유지하고 push·background sync·Cache Storage 호스트 역할만 capability opt-in으로 허용하며 update UX 계약을 요구한다 | `conditional-default` | `feature-frontend-background-execution-worker-contract` | `FE-OC-016`, `FE-OC-017`, `FE-OC-023`, `FE-OC-032` | precaching은 release coherence 훼손 원인이나 push·sync는 SW 없이는 불가; project decision | offline-first가 제품 요구가 되고 update UX가 설계됨 | `FE-D019` | +| `FE-D035` | background sync 재생은 `idempotency: keyed` operation만 허용한다 | `accepted-documented-only` | `feature-frontend-background-execution-worker-contract` | `FE-OC-009`, `FE-OC-032` | `FE-D016`의 중복 write 방지 invariant를 지연 재생에 확장 | mutation이 naturally idempotent임이 schema로 증명됨 | — | +| `FE-D036` | Web Worker 작업은 structured-clone 또는 Transferable로만 통신하고 timeout과 terminate를 계약하며 worker 안에서 application port를 재구현하지 않는다 | `accepted-documented-only` | `feature-frontend-background-execution-worker-contract` | `FE-OC-002`, `FE-OC-032` | worker 안 로직 중복이 layer 경계를 우회하는 것을 차단, project decision | SharedArrayBuffer 기반 병렬 처리가 요구됨 | — | + +`FE-D026`~`FE-D036`의 `Evidence / rationale`에 적힌 `project-local default, 외부 source claim 아님`은 `FE-D001`이 쓰는 표기와 같다. 대응 raw 근거 문서가 아직 없다는 사실을 감추지 않고 명시하는 장치이며, 수집 계획은 `FE-Q-011`이 소유한다. ### 3.3 Decision change protocol @@ -443,19 +456,33 @@ Out of scope: | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-RETRY-001` | 1 | `retry` | retry는 initial call 이후 최대 2회, exponential backoff와 full jitter, 2초 cap을 사용한다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D015` | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-IDEMPOTENCY-001` | 1 | `idempotency` | mutation auto-retry는 stable idempotency key와 backend replay contract가 있을 때만 허용한다 | `accepted-documented-only` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D016` | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-AUTH-BOUNDARY-001` | 1 | `auth-boundary` | auth lifecycle은 외부 owner가 소유하고 skeleton은 AuthSessionPort만 소비한다 | `accepted-documented-only` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D017`; [[raw/project-notes/keycloak-patterns-overview]] | -| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REGISTRY-001` | 1 | `registry` | route, API operation, env, storage, error, query, telemetry, release token을 8개 registry로 관리한다 | `accepted-documented-only` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D018` | -| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-OFFLINE-CACHE-001` | 1 | `offline-cache` | service worker와 offline asset cache는 default off다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D019` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REGISTRY-001` | 1 | `registry` | route, API operation, env, storage, error, query, telemetry, release token, capability를 9개 registry로 관리한다 | `accepted-documented-only` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D018` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-OFFLINE-CACHE-001` | 2 | `offline-cache` | service worker의 release asset precaching은 default off이고 push·background sync·Cache Storage 호스트 역할만 capability opt-in으로 허용한다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D034` (`FE-D019` supersede) | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CACHE-POLICY-001` | 1 | `cache-policy` | hashed asset은 immutable, HTML·runtime config·release manifest는 revalidate/no-store로 분리한다 | `accepted-documented-only` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D020` | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-TELEMETRY-001` | 1 | `telemetry` | telemetry는 best-effort queue와 redaction을 사용하며 sink failure가 UI를 실패시키지 않는다 | `accepted-documented-only` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D021` | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-TEST-STACK-001` | 1 | `test-stack` | test stack default는 Vitest, RTL, MSW, Playwright, axe다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D022` | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-DEPLOYMENT-001` | 1 | `deployment` | static release는 immutable release directory와 atomic active pointer로 배포한다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D023` | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-SUPPLY-CHAIN-001` | 1 | `supply-chain` | dependency lock, secret scan, vulnerability scan, license inventory, dependency review를 merge/release gate로 분리한다 | `accepted-documented-only` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D024` | | `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-SAMPLE-FIXTURE-001` | 1 | `sample-fixture` | sample slice는 제거 가능한 contract fixture이며 product import를 금지한다 | `accepted-documented-only` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D025` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CAPABILITY-001` | 1 | `capability` | 신규 runtime capability 6종은 FE-REG-CAPABILITY flag로 default OFF이며 활성화는 owner·gate·runbook을 동반한다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D026` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-BINARY-STORE-001` | 1 | `binary-store` | 로컬 바이너리 backend는 IndexedDB를 default로 하고 OPFS는 대용량 순차 write에 opt-in, Cache Storage는 service worker 호스팅 response cache 전용이다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D027` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-CROSS-TAB-001` | 1 | `cross-tab` | 탭 간 무효화는 BroadcastChannel 우선에 storage event fallback을 쓰고 leader election 없이 무효화 key만 전파한다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D028` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-TRANSFER-CREDENTIAL-001` | 1 | `transfer-credential` | presigned URL 획득은 shared client를 경유하고 실제 byte 전송은 session credential을 첨부하지 않는 transfer adapter가 수행한다 | `accepted-documented-only` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D029` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-RESUMABLE-TRANSFER-001` | 1 | `resumable-transfer` | 재개 가능 전송은 part size·병렬도·part 재시도 상한을 registry로 고정하고 part 상태를 BlobStorePort에 보존한다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D030` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-PROTOCOL-001` | 1 | `protocol` | transport default는 REST이고 GraphQL·gRPC-Web·Connect-Web은 FE-REG-API의 protocol 필드로 opt-in하며 미지원 환경은 REST gateway로 fallback한다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D031` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REALTIME-TRANSPORT-001` | 1 | `realtime-transport` | 실시간 transport는 SSE를 우선하고 양방향이 필요하면 WebSocket, 둘 다 불가할 때만 최소 간격·backoff·visibility gating을 갖춘 bounded polling을 쓴다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D032` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REALTIME-LIFECYCLE-001` | 1 | `realtime-lifecycle` | 실시간 연결은 full jitter backoff와 30초 cap을 쓰고 재시도 상한 후 terminal 상태로 전이하며 resume은 Last-Event-ID 또는 cursor로 수행하고 unmount 시 구독을 해제한다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D033` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-SERVICE-WORKER-ROLE-001` | 1 | `service-worker-role` | service worker는 역할을 분리해 release asset precaching은 default off로 유지하고 push·background sync·Cache Storage 호스트 역할만 capability opt-in으로 허용하며 update UX 계약을 요구한다 | `conditional-default` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D034` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-BACKGROUND-SYNC-001` | 1 | `background-sync` | background sync 재생은 idempotency keyed operation만 허용한다 | `accepted-documented-only` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D035` | +| `DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-WORKER-TASK-001` | 1 | `worker-task` | Web Worker 작업은 structured-clone 또는 Transferable로만 통신하고 timeout과 terminate를 계약하며 worker 안에서 application port를 재구현하지 않는다 | `accepted-documented-only` | [[raw/project-notes/ca-skeleton-frontend-operational-contract]] | §3.2 `FE-D036` | > **개정 기록 (§3.3 protocol)** > > - 2026-07-21 · `DEC-...-SUPPLY-CHAIN-001` · `compatibility_impact: additive` · revision 유지(1). Decision Summary 에 `dependency review` 를 추가했다. 이는 새 결정이 아니라 **불완전한 요약의 정정**이다 — `FE-OC-018` 과 §13.1 이 처음부터 dependency review 를 요구했고 §3.2 `FE-D024` 도 이를 포함하는데 이 registry 행만 4개 control 로 적혀 있었다. 기존 4개 control 의 동작은 바뀌지 않고, gate 정의(§15.1 `FE-GATE-013`)도 이미 dependency-review fixture 를 포함한 채 revision 1 이므로 같은 판정을 적용한다. -> - Summary 셀은 소비 branch 의 상속 표와 **문자열이 정확히 일치해야 한다**(`wiki_consistency_check.py` 의 `CONFLICTS_WITH_PROJECT_DECISION`). 분류·근거 같은 메타는 이 기록에 적고 Summary 에 섞지 않는다. +> - 2026-07-28 · `DEC-...-OFFLINE-CACHE-001` · `compatibility_impact: behavior-change` · revision 1→2. `FE-D034` 가 `FE-D019` 를 supersede 하면서 service worker 를 "전면 off" 에서 "precaching off + 역할별 capability opt-in" 으로 바꿨다. WebPush·Background Sync·Cache Storage 가 service worker 없이는 동작하지 않기 때문이다. behavior-change 이므로 §3.3 4단계에 따라 `FE-GATE-032`(SW update UX + rollback 시 SW 되돌림)와 `FE-RB-007` 이 migration·rollback evidence 를 담당한다. 이 결정을 pin 한 [[raw/branch-notes/feature-frontend-release-cache-rollback-contract]] 는 `@2` 로 갱신했다. +> - 2026-07-28 · `DEC-...-REGISTRY-001` · `compatibility_impact: additive` · revision 유지(1). 9번째 registry `FE-REG-CAPABILITY` 를 추가했다. 기존 8개 registry 의 owner·schema·동작은 바뀌지 않으므로 `DEC-...-SUPPLY-CHAIN-001` 선례와 같은 판정을 적용한다. 다만 Summary 문자열이 바뀌므로 이를 복사해 둔 소비 branch 4곳([[raw/branch-notes/feature-frontend-storage-registry-contract]]·[[raw/branch-notes/feature-frontend-observability-logging-trace-contract]]·[[raw/branch-notes/feature-frontend-contract-registry-governance]]·[[raw/branch-notes/feature-frontend-contract-compatibility-governance]])의 상속 표를 함께 갱신했다. +> - 2026-07-28 · `DEC-...-CAPABILITY-001` 외 10건 신규 등록. 근거 raw 문서가 아직 없으므로 §3.2 대응 행의 `Evidence / rationale` 에 `project-local default, 외부 source claim 아님` 을 명시했고, 수집 계획은 `FE-Q-011` 이 소유한다. +> - Summary 셀은 소비 branch 의 상속 표와 **문자열이 정확히 일치해야 한다**(`wiki_consistency_check.py` 의 `CONFLICTS_WITH_PROJECT_DECISION`). 분류·근거 같은 메타는 이 기록에 적고 Summary 에 섞지 않는다. 조사 앞에 공백을 넣지 않는다 — `…release token을 8개 registry로` 형태가 기준이다. ---