WI-...-028~033 에 대응하는 FE-OC-027~032 owner 노트. - 각 노트의 제외 범위에 'use case·domain model·business rule' 을 명시해 이 skeleton 이 port 와 adapter 계약까지임을 못박았다 - 근거 절에 '근거 등급 경계' 문단을 넣어 project-local default 와 외부 근거를 구분했다 (수집은 FE-Q-011~014 가 소유) - 구현 가이드 절은 비워 두고 사유를 남겼다 — 근거 raw 없이 채우면 모든 cell 이 UNSUPPORTED_IMPL_DECISION 이 된다 - multi-protocol 노트는 '신규 port 0개' 를 제외 범위에 명시했다. port 가 늘어나면 그 자체가 회귀 신호다
17 KiB
title, source_type, status, id, kind, project, work_item, inherits, refines, overrides, depends_on, imports, delegates, accepts_delegations, contract_packet, branch, parent_branch, related_projects, tags, created, target_merge, status_label
| title | source_type | status | id | kind | project | work_item | inherits | refines | overrides | depends_on | imports | delegates | accepts_delegations | contract_packet | branch | parent_branch | related_projects | tags | created | target_merge | status_label | |||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| branch / feature-frontend-realtime-subscription-lifecycle-contract | branch-note | raw | BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-032 | project-work-item | ca-skeleton-frontend-operational-contract | WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-032 |
|
|
|
|
1 | feature-frontend-realtime-subscription-lifecycle-contract |
|
|
2026-07-28 | in-progress |
branch: feature-frontend-realtime-subscription-lifecycle-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-background-execution-worker-contract
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
2 - 패킷 스키마:
contract_packet: 1 - 완료 조건: backoff·resume·구독 해제·이벤트 검증 fixture와
FE-RB-006drill이 통과한다
상속한 프로젝트 결정
| 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_REALTIME 을 이 branch 가 소유하고 default OFF 로 유지한다 |
raw/project-notes/ca-skeleton-frontend-operational-contract |
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REALTIME-TRANSPORT-001@1 |
실시간 transport는 SSE를 우선하고 양방향이 필요하면 WebSocket, 둘 다 불가할 때만 최소 간격·backoff·visibility gating을 갖춘 bounded polling을 쓴다 | RealtimeSubscriptionPort adapter 선택 순서에 적용한다 |
raw/project-notes/ca-skeleton-frontend-operational-contract |
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REALTIME-LIFECYCLE-001@1 |
실시간 연결은 full jitter backoff와 30초 cap을 쓰고 재시도 상한 후 terminal 상태로 전이하며 resume은 Last-Event-ID 또는 cursor로 수행하고 unmount 시 구독을 해제한다 | 연결 수명주기 상태 기계와 해제 계약에 적용한다 | raw/project-notes/ca-skeleton-frontend-operational-contract |
브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | 구독 해제는 RealtimeSubscriptionPort 가 반환하는 handle 로만 수행하고, adapter 내부에 열린 연결 목록을 유지해 파괴 시 전부 닫는다 |
refines DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-REALTIME-LIFECYCLE-001@1 |
근거 raw 미수집 (FE-Q-011) |
proposed |
| D2 | backoff jitter 의 random source 는 주입 가능해야 한다 (결정론 테스트 요건) | local |
DELEG-FE-005 선례 — feature-api-client-response-envelope-contract 가 같은 문제를 이미 위임함 |
proposed |
| D3 | 구독별로 독립적인 full jitter 를 쓰고, 추가로 전역 동시 재연결 상한을 둔다 | local |
근거 raw 미수집 (FE-Q-011) |
proposed |
선언한 예외
해당 없음.
가져온 artifact 계약
| Artifact Ref | Owner | Producer | Schema Ref |
|---|
가져온 프로젝트 계약
| Ref | Owner | 요약 | Branch 적용 |
|---|---|---|---|
FE-GATE-031@1 |
raw/project-notes/ca-skeleton-frontend-operational-contract | backoff·resume·구독 해제·이벤트 검증 fixture 가 실패하면 merge·release 를 MUST 차단 | 이 branch 가 owner 로서 fixture 와 report 를 산출 |
FE-OC-007@1 |
raw/branch-notes/feature-runtime-schema-validation-contract | JSON envelope와 payload는 boundary에서 runtime schema를 MUST 통과 | 인바운드 프레임도 같은 규칙 적용 |
FE-OC-008@1 |
raw/branch-notes/feature-frontend-error-classification-boundary-contract | 모든 failure는 stable frontend error kind로 MUST 정규화하고 raw body·stack을 UI에 노출하면 안 됨 | 실시간 실패 4종의 정규화 대상 |
FE-OC-011@1 |
raw/branch-notes/feature-async-ui-state-contract | async surface는 initial-loading, success, empty, terminal-error를 MUST 표현 | §9.5 실시간 state 를 이 4-state 에 매핑 |
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-006 의 기술 escalation 대상 |
수신한 위임
없음. 이 branch 는 DELEG-FE-007 의 delegator 다.
가져온 흐름 단계
FLOW-FE-EVENT-001·002는 이 branch 가 소유하므로 import 하지 않는다.
| Stage Ref | Order | Owner | Input | Action | Output |
|---|---|---|---|---|---|
FLOW-FE-EVENT-003@1 |
3 | feature-runtime-schema-validation-contract |
unvalidated event JSON | event envelope 공유 스키마 검증 | discriminated event envelope |
FLOW-FE-EVENT-004@1 |
4 | feature-runtime-schema-validation-contract |
discriminated event envelope | eventSchema per-event 검증 |
검증된 event payload |
FLOW-FE-EVENT-005@1 |
5 | feature-frontend-error-classification-boundary-contract |
검증된 event payload 또는 실패 신호 | 정규화된 이벤트 또는 failure 반환 | application event 또는 normalized failure |
목표
RealtimeSubscriptionPort 와 PushSubscriptionPort 를 정의하고, 연결·재연결·재개·이벤트 검증·해제를 계약한다. 이 계약이 없으면 끊김에 상한 없는 즉시 재연결을 걸어 backend 를 증폭 공격하고, 라우트 이탈 후에도 WebSocket 이 열린 채 남아 연결 수가 단조 증가하며, 미검증 프레임이 상태에 병합되어 TypeError 가 렌더 트리 깊은 곳에서 늦게 터진다.
- 이슈:
- PR:
범위
포함 범위
RealtimeSubscriptionPort— SSE·WebSocket·bounded polling adapterPushSubscriptionPort— 권한 요청, VAPID 공개키 기반 구독 등록- 연결 수명주기 상태 기계와 §9.5 surface state
- full jitter backoff, 30초 cap(
REALTIME_RECONNECT_CAP_MS), 재시도 상한 후 terminal 전이 - resume —
Last-Event-ID/ cursor, gap 감지 FLOW-FE-EVENT-001·002소유 (프레임 수신, transport decode)- 구독 해제 계약과 누수 검출(
SUBSCRIPTION_LEAKEDfixture) - bounded polling 의 최소 간격·backoff·visibility gating
FE-RB-006의 기술 escalationCAP_FE_REALTIMEcapability 행 소유
제외 범위
- use case, domain model, business rule — port 와 adapter 계약까지만 정의한다
- 이벤트의 도메인 의미와 상태 병합 정책
- service worker 등록·수명주기 —
DELEG-FE-007로 raw/branch-notes/feature-frontend-background-execution-worker-contract 에 위임 (WebPush 는 SW 위에서 동작) - push 발송 서버와 VAPID 개인키 관리 —
FE-Q-014 - 인바운드 프레임의 스키마 검증 구현 —
FLOW-FE-EVENT-003·004는 raw/branch-notes/feature-runtime-schema-validation-contract 소유 - unary protocol adapter — raw/branch-notes/feature-frontend-multi-protocol-api-transport-contract 소유
근거 (필수, 최소 1개+)
| Source | 정당화하는 결정 |
|---|---|
[[docs/superpowers/specs/2026-07-28-ca-skeleton-frontend-runtime-adapter-features-design]] §5.1·§7.5·§9.2 |
port 분해, 이벤트 흐름 5단계, 실시간 surface state |
| raw/project-notes/ca-skeleton-frontend-operational-contract §7.5·§9.1 | 기존 retry backoff·jitter 정책과 async state 모델 |
근거 등급 경계: FE-D032(transport 선택 순서)와 FE-D033(연결 수명주기)의 rationale 은 각각 project-local default, 외부 source claim 아님 과 재연결 폭주·구독 누수 억제, project decision 이다. SSE(WHATWG HTML EventSource)·WebSocket·Web Push 명세를 다룬 raw 자료는 이 repo 에 없다(FE-Q-011). 30초 cap 은 측정값이 아니라 초기 default 다.
TODO
RealtimeSubscriptionPort인터페이스와 해제 handle 확정 — 등급:plannedPushSubscriptionPort인터페이스 확정 — 등급:planned- transport 선택 순서(SSE → WebSocket → polling) 구현 — 등급:
planned - full jitter backoff + cap + terminal 전이 (주입 가능 random source) — 등급:
planned - resume cursor 와 gap 감지 — 등급:
planned FLOW-FE-EVENT-001·002프레임 수신·디코드 — 등급:planned- 구독 해제 계약과 누수 fixture — 등급:
planned - bounded polling 의 visibility gating — 등급:
planned - §9.5 surface state 컴포넌트 매핑 — 등급:
planned FE-RB-006drill assertion — 등급:plannedFE-GATE-031realtime lifecycle report 산출 — 등급:planned
진행 중 메모
reconnecting 과 disconnected 의 구분이 이 branch 의 핵심 UX 계약이다. 전자를 terminal-error 로 표시하면 사용자가 불필요하게 새로고침하고, 후자를 refreshing 으로 표시하면 영원히 오지 않는 데이터를 기다린다. 구현 시 두 상태가 같은 컴포넌트 분기로 합쳐지지 않는지 리뷰에서 확인한다.
D2(주입 가능 random source)는 DELEG-FE-005 가 이미 같은 문제를 다뤘다 — feature-api-client-response-envelope-contract 가 feature-frontend-clean-architecture-layering-contract 에 주입 형태를 위임했다. 이 branch 는 그 결과를 재사용하고 새 위임을 만들지 않는다.
결정 사항
- 2026-07-28: 재시도 상한 후 terminal 전이 / 이유: 무한 재시도는 backend 증폭이고 사용자에게도 상태를 숨김 / 검토한 대안: 무한 재시도 + 긴 cap / 근거:
FE-D033 - 2026-07-28: 구독별 독립 jitter + 전역 동시 재연결 상한 / 이유: 구독이 여럿이면 같은 시점에 만료해 thundering herd 가 됨 / 검토한 대안: 전역 단일 backoff / 근거:
FE-RISK-016
결정-근거 매핑
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | handle 기반 해제 + adapter 내부 연결 목록 | 항상 | 없음 — FE-Q-011 |
project-local default |
adapter 파괴 시점이 명확하지 않은 사용 패턴이 있을 수 있음 |
| D2 | 주입 가능 random source | 항상. 결정론 테스트 요건 | DELEG-FE-005 선례 |
project precedent |
주입 형태가 layering branch 결정에 종속 |
| D3 | 구독별 독립 jitter + 전역 상한 | 구독이 2개 이상일 때. 단일 구독이면 전역 상한은 무의미 | 없음 — FE-Q-011 |
project-local default |
전역 상한이 정상 재연결을 지연시킬 수 있음 |
구현 가이드
근거 raw 자료(
FE-Q-011) 수집 전까지 비워 둔다. SSE 의 재연결·Last-Event-ID동작과 WebSocket close code 해석은 명세를 읽지 않고 쓸 수 없다.
엣지·실패·의존
- 실패·엣지 경로
- 최초 연결 실패 →
REALTIME_CONNECT_FAILED, backoff 재시도,connecting유지 - 재시도 상한 소진 →
REALTIME_DISCONNECTEDterminal. 자동 재시도 없음, 사용자 주도 retry - resume cursor 로 메울 수 없는 공백 →
REALTIME_RESUME_GAP, 권위 데이터 refetch 권고 - 프레임 스키마 위반 →
EVENT_SCHEMA_MISMATCH, 해당 프레임만 드롭하고 연결은 유지 - transport decode 실패 → 프레임을 버리되 연결을 즉시 끊지 않음(
FLOW-FE-EVENT-002불변식) - unmount → 구독 해제. 해제 누락은
SUBSCRIPTION_LEAKEDfixture 가 잡는 결함이지 런타임 kind 가 아님 - 알림 권한 거부 →
PUSH_PERMISSION_DENIED, 재요청 반복 금지 - SSE·WebSocket 모두 미지원 → bounded polling 으로 강등(
degraded-alternative)
- 최초 연결 실패 →
- 다른 계약 의존
- raw/branch-notes/feature-runtime-schema-validation-contract 의
FLOW-FE-EVENT-003·004에 의존 - raw/branch-notes/feature-frontend-error-classification-boundary-contract 의
FLOW-FE-EVENT-005총함수에 의존 - raw/branch-notes/feature-async-ui-state-contract 의 4-state 모델에 의존 — §9.5 가 그 위에 매핑됨
- raw/branch-notes/feature-frontend-background-execution-worker-contract 의 SW 등록에 의존 (
DELEG-FE-007, WebPush 전용) - raw/branch-notes/feature-frontend-clean-architecture-layering-contract 의 주입 형태 결정에 의존 (
DELEG-FE-005결과 재사용)
- raw/branch-notes/feature-runtime-schema-validation-contract 의
검증해야 할 주장
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| unmount 후 열린 구독이 0이다 | 해제 누락이 조용히 누적됨 | fixture — 컴포넌트 mount/unmount 반복 후 adapter 내부 연결 목록 길이 0 (FE-NFR-017) |
planned |
| 재연결 간격이 30초 cap 을 넘지 않는다 | jitter 계산이 cap 을 초과하기 쉬움 | 결정론 fake clock test — 모든 시도 간격 ≤ cap (FE-NFR-016) |
planned |
| 상한 소진 후 자동 재시도가 멈춘다 | 무한 루프가 조용히 남음 | fixture — 상한 도달 후 추가 연결 시도 0 | planned |
| 미검증 프레임이 application 에 도달하지 않는다 | 검증을 우회하는 빠른 경로가 생기기 쉬움 | negative fixture — 스키마 위반 프레임 주입 후 application 콜백 미호출 | planned |
| 스키마 위반 프레임 하나가 연결을 끊지 않는다 | 방어적으로 끊는 구현이 흔함 | fixture — 위반 프레임 후 정상 프레임 수신 확인 | planned |
| resume gap 이 실제로 감지된다 | 서버가 gap 을 알려주지 않으면 감지 방법이 제한적 | integration test — 이벤트 ID 불연속 주입 후 REALTIME_RESUME_GAP |
needs-confirmation |
| 다중 구독 재연결이 동시에 몰리지 않는다 | 독립 jitter 만으로 충분한지 불확실 | 부하 fixture — N개 구독 동시 끊김 후 재연결 시각 분포 (FE-RISK-016) |
needs-confirmation |
| bounded polling 이 백그라운드 탭에서 멈춘다 | visibility gating 누락이 흔함 | fixture — document.hidden 상태에서 요청 0 |
planned |
관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
미생성.
마주친 문제
없음.
묶음 (이 branch에서 파생된 자료)
Sub-branches (세부 작업)
아직 없음.
오류 기록 (이 branch 작업 중 발생)
아직 없음.
면접 준비 (이 작업에서 나올 수 있는 면접 질문)
아직 없음.
강의 (이 작업을 위해 학습한 강의)
아직 없음.
job-posting tie-ins (이 작업에서 파생된 글감)
아직 없음.
관련 일일 노트
- 아직 없음
완료 후 정리
- PR 링크:
- 리뷰 메모:
- 머지 결과 / 배포 환경:
- wiki 추출 대상 (verified만,
wiki/projects/로만 추출):actually-implemented항목: 없음locally-verified항목: 없음prod-verified항목: 없음
- 추출하지 않을 항목: 현재 전 항목
planned