Files
clean-architecture-frontend…/docs/architecture/frontend-platform-implementation-roadmap.md
T
2026-08-01 19:39:59 +09:00

68 KiB

프론트엔드 플랫폼 구현 로드맵

정본 안내 (non-authoritative for runtime capability decisions)

Runtime Config/boot, Fetch HTTP client, Router, Query/Mutation, realtime 공통 경계, Web Worker, Service Worker, offline command와 Background Sync의 구현 결정은 프론트엔드 런타임 Capability 저장소 정합형 구현 결정 폐쇄 상세 설계가 정본이다. 본 문서의 해당 서술이 정본과 충돌하면 정본을 따른다.

1. 목적과 준비 완료의 의미

이 문서는 developcb195f8을 계획 기준선으로 삼아, 현재 저장소에 선언된 프론트엔드 계약을 실제 런타임과 자동 검증까지 연결하는 구현 순서를 정의한다. 기준 커밋은 출발점일 뿐이며 각 구현 브랜치는 직전 브랜치가 병합된 최신 develop에서 시작한다.

구현 단계는 다음처럼 구분한다.

단계 목적 exit 상태
P0 새 기능이 사용할 input/output, HTTP/query, route/recovery 수직 경로 완성 LOCAL_CORE_READY
P1 form/page/design/i18n, diagnostics, test, 공급망까지 템플릿 품질 완성 LOCAL_TEMPLATE_READY
P2 실제 요구가 생겼을 때 선택할 adapter recipe 제공 선택 항목만 RECIPE_READY

P0와 P1은 사용자가 요청한 높은 수준의 저장소 내부 준비도를 판단하기 전에 모두 끝내야 한다. 이를 정밀한 백분율 점수로 표현하지 않고 다음 세 조건으로 판정한다.

  1. 계약과 레지스트리의 모든 필드에 실제 consumer가 있다.
  2. 정상 경로와 실패 경로가 자동 테스트로 증명된다.
  3. 각 변경이 독립적으로 되돌릴 수 있고 feature branch와 evidence가 보존된다.

P2는 제품 번들에 모든 기술을 미리 넣는 단계가 아니다. 선택 조건, port/facade, fake adapter, 실패 정책과 제거 절차를 준비하는 단계다.

2. 명시적인 범위 밖

다음 항목은 저장소가 seam, fail-closed 기본값, 검증 명령과 증거 형식을 제공할 수는 있지만 실제 완료는 외부 프로젝트 또는 운영 환경의 책임이다.

  • 실제 hosting/CDN의 atomic deploy, cache purge, 응답 헤더와 rollback 실행
  • 실제 OAuth/OIDC/기업 IdP tenant, client, redirect URI와 token lifecycle
  • production telemetry, RUM, analytics, error-reporting vendor와 consent 정책
  • 실제 사용자에게서 수집한 28일 field Web Vitals와 최소 표본 결정
  • 저장소 호스팅 서비스의 required check, branch protection과 evidence retention
  • 운영용 CSP allowlist, signing key, provenance attestation과 비밀 관리
  • 실제 브랜드, 업무 문구, 번역 승인, 지원 locale와 법적 고지
  • 도메인 API, 권한 모델, 제품별 form schema와 업무 규칙
  • 운영 release 승인

이 항목이 준비되지 않아도 demo, fake, no-op, unavailable adapter를 사용해 P0/P1의 저장소 내부 구현과 테스트를 끝낼 수 있어야 한다. 반대로 외부 증거가 없는데 PRODUCTION_READY, WCAG_READY, FIELD_SLO_READY를 주장해서는 안 된다. 상위 promotion gate는 임의의 값을 만들어 PASS하지 않고 FAIL_UNVERIFIED를 유지한다.

3. 공통 구현 원칙

  • .ts.tsx를 만들기 전에 lint, architecture, registry, typecheck와 test 검색 범위가 해당 확장자를 검사한다.
  • React는 application input port를 호출하고, application은 output port만 안다. 구체 adapter 조립은 bootstrap만 담당한다.
  • route, API, error, query, storage, telemetry와 release registry는 문서용 목록이 아니라 실행과 검증의 단일 소스다.
  • path, search, body, response와 external event는 경계에서 parse하며 parse된 결과를 다음 계층으로 전달한다.
  • retry, cache, redirect, reload, submission과 redaction에는 각각 한 명확한 정책 소유자만 둔다.
  • 정상 테스트와 함께 invalid import, schema, URL, mutation, chunk, secret 같은 negative fixture가 실제 gate에 의해 거절돼야 한다.
  • vendor SDK type과 import는 local facade/adapter 밖으로 노출하지 않는다.
  • 선택 gate가 닫히지 않은 라이브러리는 lockfile에 추가하지 않는다.
  • 대규모 rename과 여러 capability를 한 merge에 섞지 않는다.

4. Gitflow 브랜치 보존 규칙

현재 저장소는 maindevelop을 사용하고 feature prefix가 비어 있다. 아래 표의 feature-... 이름을 그대로 git flow feature start에 전달한다.

최신 develop 확인
  -> git flow feature start <정확한 feature-... 이름>
  -> 작은 검증 가능한 commit
  -> git flow feature publish <정확한 feature-... 이름>
  -> 자동 gate와 review
  -> develop에 --no-ff merge
  -> develop과 feature branch를 모두 push
  -> local/origin feature branch 보존

git flow feature finish는 feature branch를 삭제할 수 있으므로 사용하지 않는다. 병합 후에도 로컬 브랜치와 origin/feature-...를 제거하지 않는다. merge commit SHA, feature tip, 실행한 gate와 artifact 위치를 PR 또는 merge evidence에 기록한다.

후속 브랜치는 미병합 feature branch에서 시작하지 않는다. 선행 브랜치를 먼저 develop에 병합하고 최신 develop에서 새 브랜치를 시작한다. 병합 순서를 바꾸려면 dependency와 acceptance를 다시 검토해야 한다.

rollback은 reset이나 branch 삭제로 수행하지 않는다.

  1. 관련 promotion을 중단한다.
  2. 보존된 feature branch와 merge commit으로 정확한 변경 범위를 찾는다.
  3. develop에서 별도 hotfix/... 또는 revert branch를 만든다.
  4. git revert -m 1 <merge-commit>으로 merge를 되돌린다.
  5. rollback gate 후 revert branch와 원래 feature branch를 모두 보존한다.
  6. 수정은 최신 develop에서 새 feature branch로 다시 진행한다.

5. 12개 브랜치와 병합 순서

flowchart TD
  B01["01 P0 TypeScript tooling"]
  B02["02 P0 input/output boundary"]
  B03["03 P0 HTTP and query"]
  B04["04 P0 routing and recovery"]
  B05["05 P0 reference feature"]
  B06["06 P1 forms and pages"]
  B07["07 P1 design system"]
  B08["08 P1 i18n"]
  B09["09 P1 diagnostics"]
  B10["10 P1 tests and registry evidence"]
  B11["11 P1 supply chain"]
  B12["12 P2 optional recipes"]

  B01 --> B02 --> B03 --> B04 --> B05
  B05 --> B06 --> B07 --> B08 --> B09 --> B10 --> B11
  B11 -. "요구가 확인된 recipe만" .-> B12
순서 보존할 Gitflow feature branch 단계 직접 선행조건 rollback point
01 feature-frontend-typescript-tooling-foundation P0 기준선, VD-01 RP-01
02 feature-frontend-application-boundary-runtime P0 01 RP-02
03 feature-frontend-http-query-contract-execution P0 02 RP-03
04 feature-frontend-routing-release-recovery-runtime P0 03, VD-03 RP-04
05 feature-frontend-reference-feature-vertical-slice P0 04 RP-05
06 feature-frontend-form-page-platform P1 05, VD-04 RP-06
07 feature-frontend-design-system-platform P1 06, VD-05 RP-07
08 feature-frontend-i18n-message-formatting-contract P1 07, VD-06 RP-08
09 feature-frontend-diagnostics-telemetry-runtime P1 08, VD-07 RP-09
10 feature-frontend-test-registry-evidence-hardening P1 09, VD-08 RP-10
11 feature-frontend-supply-chain-verification P1 10, VD-09 RP-11
12 feature-frontend-optional-adapter-recipes P2 11, VD-10 RP-12

6. 브랜치별 구현과 acceptance

01. feature-frontend-typescript-tooling-foundation

목표

점진적 TypeScript 전환 전에 JS, JSX, TS, TSX와 테스트가 모두 같은 정적 분석과 CI gate를 통과하게 한다. 애플리케이션 전체를 일괄 변환하지 않는다.

선행조건과 decision

  • 기준선의 pnpm ci:gate 결과를 보존한다.
  • TypeScript compiler와 기존 dependency 버전은 별도 dependency review 없이는 변경하지 않는다.
  • 공식 JavaScript migration 방식처럼 점진적으로 전환한다. TypeScript JavaScript migration

구체 변경 범위

  • root, application/source, tests용 TypeScript project/reference를 분리한다.
  • src, tests, scripts의 허용 확장자와 build output 제외 범위를 명시한다.
  • ESLint, dependency-cruiser, registry scanner와 architecture script의 검색 범위를 TS/TSX source와 fixture로 통일한다.
  • Vite, Vitest와 Playwright config가 TS source/test 오류를 우회하지 않게 한다.
  • 기존 fixture까지 TS/TSX로 전환하고 strict 정책을 적용한다.
  • port, registry와 forbidden import용 .ts/.tsx fixture를 추가한다.

자동 테스트와 negative test

  • TS/TSX source/test를 함께 typecheck하는 smoke
  • TSX presentation의 concrete HTTP adapter import를 architecture gate가 거절
  • 잘못된 port 구현과 discriminated union 사용이 typecheck 실패
  • TS registry row의 누락 필드, 중복 ID와 unknown reference가 gate 실패
  • 변환된 TS invalid-call fixture도 계속 실패
  • pnpm lint, pnpm check:types, pnpm check:architecture, pnpm check:registries, pnpm test:all, pnpm build

Acceptance

  • 허용된 모든 source/test 확장자가 typecheck, lint, architecture, registry gate 중 필요한 검색 범위에 포함된다.
  • 모든 TS/TSX negative fixture가 CI에 의해 차단된다.
  • 광범위한 unchecked cast나 임시 any로 통과시키지 않는다.
  • production source 대량 변환 없이 독립적으로 revert할 수 있다.

Rollback

RP-01에서 merge를 revert하면 기존 JS 기준선으로 돌아간다. 후속 TS 작업은 RP-01이 복구될 때까지 병합하지 않는다.

02. feature-frontend-application-boundary-runtime

목표

UI가 호출할 input port와 application이 외부에 요구할 output port를 분리하고, composition root가 생성한 Application을 실제 React tree에 주입한다.

선행조건과 decision

  • 01의 TS-aware architecture gate가 병합돼 있어야 한다.
  • 범용 client store는 추가하지 않는다. local interaction은 React state, 공유 navigation state는 URL, server state는 query adapter가 소유한다.
  • 실제 IdP 없이 demo/external/unavailable session adapter를 유지한다.

구체 변경 범위

  • application input API를 query/command use case 중심으로 정의한다.
  • gateway, session, cache, storage, clock, diagnostics와 release capability를 output port로 분류한다.
  • createApplication이 raw adapter를 다시 노출하지 않고 input API만 반환한다.
  • ApplicationProvideruseApplication 역할의 inbound React adapter를 둔다.
  • bootstrap이 concrete output adapter를 선택하고 application을 router/page에 전달한다.
  • presentation의 fetch, browser storage, concrete QueryClient와 outbound adapter 직접 접근을 금지한다.
  • inbound/outbound ownership을 architecture gate와 type fixture에 반영한다.

자동 테스트와 negative test

  • fake output ports를 이용한 application use-case 단위 테스트
  • runtime config → composition root → provider → smoke page 통합 테스트
  • presentation의 adapters/outbound, fetch, concrete QueryClient import 거절
  • application의 React, router, browser storage, vendor SDK import 거절
  • 잘못된 output port 구현과 누락 input이 typecheck 실패
  • bootstrap 이외 계층의 concrete adapter 조립 거절

Acceptance

  • visible page가 raw outbound dependency 대신 application input API를 사용한다.
  • 조립됐지만 사용되지 않는 application, HTTP와 release-info 객체가 없다.
  • fake adapter만으로 application과 presentation의 정상·실패 경로를 테스트한다.
  • vendor type이 application public API에 나타나지 않는다.

Rollback

RP-02는 기존 provider wiring을 한 merge로 되돌릴 수 있어야 한다. 임시 compatibility wrapper는 05 reference feature 완료 전에 제거한다.

03. feature-frontend-http-query-contract-execution

목표

API operation registry의 path/search/body/schema/timeout/retry가 실제 요청에 반영되게 하고, TanStack Query를 application input과 React 사이의 제한된 inbound adapter로 연결한다.

선행조건과 decision

  • 02의 application error와 gateway 경계가 고정돼 있어야 한다.
  • shared HTTP가 network retry를 소유하고 query adapter의 중복 retry는 끈다. 다른 결정을 원하면 이 브랜치 전에 ADR을 남긴다.
  • TanStack Query를 server-state adapter로 유지하되 Zustand/Redux Toolkit에 server state를 복사하지 않는다.

구체 변경 범위

  • request input을 operation/route ID, path params, search params, body, signal과 idempotency key로 분리한다.
  • operation registry에서 method, path, request/response schema, timeout과 retry eligibility를 찾는다.
  • deterministic path/search builder를 만들고 parse/transform된 query/body를 실제 URL/payload에 사용한다.
  • runtime config의 timeout과 max attempts를 client factory에 주입한다.
  • abort, timeout, retry delay와 listener cleanup을 injectable clock/scheduler 경계로 통제한다.
  • TanStack import를 허용할 local query adapter 경계를 하나만 둔다.
  • useApplicationQuery, useApplicationMutation 역할의 controller API를 정의하고 query key, cancellation, invalidation과 optimistic rollback을 연결한다.
  • base state를 loading/success/empty/terminal로, overlay를 refreshing/stale-degraded/pending/conflict로 닫는다.
  • refreshing/stale 및 pending/conflict의 배타성과 stale-failure latch를 명시적으로 구현한다.
  • stale retry, duplicate-submit 방지와 conflict action을 실제 callback에 연결한다.

자동 테스트와 negative test

  • path escaping, optional/array search, stable ordering 및 query key/request URL 일치
  • query/body transform 결과 전송, invalid input에서 fetch 0회
  • runtime timeout과 max attempts 0/1/N의 실제 호출 횟수
  • validation 실패, abort, success, exhausted retry의 timer/listener cleanup
  • caller abort와 timeout의 서로 다른 typed failure
  • unsafe mutation, non-retryable status와 schema failure retry 0회
  • 네 base state, 네 overlay와 허용 transition
  • refreshing 실패의 stale latch 및 성공/재시도 후 해제
  • pending/conflict 동시 상태 fixture 거절
  • duplicate submit 1회, optimistic success/rejection rollback/conflict resolution
  • unmount/navigation abort가 terminal error로 오인되지 않음
  • local adapter 밖의 @tanstack/** import 거절

Acceptance

  • cache key에 포함된 request 입력이 실제 URL/body에서도 동일하게 사용된다.
  • runtime timeout/retry 설정이 실제 동작을 바꾼다.
  • 모든 종료 경로의 cleanup과 한계 횟수를 fake clock으로 결정적으로 증명한다.
  • QueryClientProvider가 단순 마운트 객체가 아니며 reference controller가 사용할 표준 API를 제공한다.
  • AsyncSurface의 모든 action이 실제 command와 검증된 state transition을 가진다.

구현 증거 (2026-07-28)

  • installed QUERY_REGISTRY가 namespace와 별도의 versioned invalidation topic, crossContext: "invalidate-only"persistence: "disabled"를 소유한다.
  • tanstack-cache-coordinator.ts가 mutation lease, local active-query invalidation, remote hint coalescing, sequence-gap 전체 reconciliation과 idempotent dispose를 구현한다.
  • production bootstrap/provider tree가 coordinator를 실제 조립한다. native BroadcastChannel을 우선하고 실패하면 exact localStorage pulse로 fallback하며 둘 다 없으면 local-only로 degrade한다.
  • wire contract는 2,048 bytes, exact field set, release cache epoch, topic allowlist, TTL, self/duplicate/stale sequence를 검증하고 query key/data를 허용하지 않는다.
  • storage-keys.ts와 browser storage adapter가 key별 closed value codec, schema/TTL, 기본 16,384-byte cap과 memory fallback envelope를 적용한다.
  • cross-tab-invalidation.test.ts, tanstack-cache-coordinator.test.ts, storage-registry.test.ts, runtime adapter/component test가 deterministic 동작과 production wiring을 검증한다.
  • 상세 상태와 남은 session/account epoch, native multi-tab evidence 및 optional IndexedDB query persistence는 Client cache and browser storage platform에 기록한다.

Rollback

RP-03은 application port를 유지하면서 이전 HTTP compatibility adapter 또는 imperative controller로 되돌릴 수 있어야 한다. request builder와 query adapter commit을 구분해 부분 revert가 가능하게 한다.

04. feature-frontend-routing-release-recovery-runtime

목표

route registry를 executable router의 단일 계약으로 만들고 params/search/access/ surface/chunk metadata를 route flow에 연결한다. lazy chunk 실패도 release manifest와 bounded recovery에 실제 연결한다.

선행조건과 decision

  • 03의 controller가 parsed route input을 받을 수 있어야 한다.
  • VD-03 기본값은 React Router Data Mode다. route object, blocker, scroll restoration과 route error 경계를 사용하되 server state는 application input과 TanStack Query가 계속 소유한다. React Router modes, Data Mode custom setup
  • 고정된 7.18.1 API로 전환하고 router version upgrade는 별도 dependency 브랜치로 분리한다.
  • 실제 hosting cache/purge는 범위 밖이며 test manifest server/browser adapter를 사용한다.

구체 변경 범위

  • 직렬화 가능한 route contract와 component/codec runtime map을 분리한다.
  • route ID의 contract/runtime 양방향 완전성을 TypeScript와 registry gate로 검사한다.
  • registry에서 route objects, navigation, access hint, title, loading/error surface와 chunk ID를 조립한다.
  • params/search를 application 호출 전에 Zod codec으로 parse하고 URL builder도 같은 codec을 사용한다.
  • unknown/authentication-required/forbidden/not-found/error surface의 소유자를 하나씩 정한다.
  • route change의 boundary reset, document title, main focus와 scroll 정책을 적용한다.
  • redirect-loop guard와 최대 hop을 실제 자동 redirect flow에 연결한다.
  • build의 Vite asset manifest와 route chunk ID를 release manifest의 검증 가능한 map으로 연결하고 runtime-config.schema.json을 artifact로 생성한다.
  • config/release/build/asset mismatch 오류 kind를 정확히 나눈다.
  • lazy rejection → no-store manifest refetch → active build/release pair 비교 → guarded reload 1회 → 반복 실패 support/rollback surface를 연결한다.
  • 일반 render error는 chunk reload 경로에 들어가지 않고 local reset을 유지한다.
  • FeatureBoundary, ReleaseInfoPort와 chunk recovery controller를 production call graph에 연결한다.

자동 테스트와 negative test

  • registry row 추가 시 route tree/navigation 동시 추가
  • runtime 누락/orphan, duplicate path/ID, unknown schema/surface/chunk 거절
  • invalid params/search, unknown route와 access rejection에서 application/API 0회
  • URL parse/build round-trip과 canonical search
  • redirect cycle이 최대 hop에서 종료
  • route 전환 후 error reset, main heading focus와 중복 surface 없음
  • stale chunk + manifest mismatch에서 no-store refetch 후 reload 정확히 1회
  • 같은 build/release pair의 두 번째 실패에서 reload 0회와 support surface
  • manifest malformed/offline/storage unavailable의 fail-closed 동작
  • 일반 component throw가 chunk failure로 오분류되지 않음
  • build/config/release/asset mismatch의 정확한 error kind
  • built dist의 route chunk map, runtime schema와 release artifact set 검증

Acceptance

  • 수동 route 열거와 registry가 서로 어긋날 수 없다.
  • route metadata 중 consumer 없는 token이 0개다.
  • invalid/unknown/access-rejected URL에서 product API 0회를 증명한다.
  • chunk recovery 결정이 production call graph에 있으며 무한 reload가 불가능하다.
  • 실제 CDN 없이 저장소 내부 recovery matrix가 결정적으로 통과한다.

Rollback

RP-04는 이전 수동 router와 generic route failure surface로 한 merge를 되돌릴 수 있어야 한다. URL shape는 바꾸지 않으며 불가피한 변경은 compatibility redirect와 migration이 있어야 한다. 실제 CDN purge는 rollback 범위에 포함하지 않는다.

05. feature-frontend-reference-feature-vertical-slice

목표

route에서 실제 HTTP/query/application/presentation까지 연결되며 전체를 제거해도 generic platform이 정상 부팅되는 하나의 reference feature를 만든다.

선행조건과 decision

  • 01~04가 모두 병합돼 있어야 한다.
  • 실제 backend와 IdP 대신 MSW/fake gateway와 demo auth를 사용한다.
  • reference 업무 용어를 제품 도메인 계약으로 승격하지 않는다.

구체 변경 범위

  • 흩어진 sample route, operation, schema, mapper, domain, query key, controller, page와 tests를 canonical src/features/reference-feature 한 ownership 경계로 이동한다.
  • feature 내부에 domain, application input/output, outbound gateway, DTO/schema, mapper, query/mutation controller와 presentation page를 둔다.
  • list filter가 URL codec, query key와 실제 HTTP request에 동일하게 반영된다.
  • safe mutation으로 pending, duplicate prevention, optimistic state, conflict와 rollback을 보여 준다.
  • registry/application에는 removable contribution contract를 사용하고 generic source에는 fixture-specific ID를 하드코딩하지 않는다.
  • production bootstrap과 같은 composition 경로에 fake adapter를 주입한다.
  • src/features/reference-feature 전체를 제거한 ephemeral copy에서 typecheck/test/build/home smoke를 실행하도록 sample-removal gate를 다시 작성한다.

자동 테스트와 negative test

  • bootstrap → router → controller → input use case → gateway → HTTP/MSW → response schema → mapper → cache → page의 수직 통합
  • loading/success/empty/terminal/refreshing/stale/pending/conflict/recovery UI
  • invalid search에서 gateway/fetch 0회
  • invalid DTO가 domain/view model로 전파되지 않음
  • backend forbidden을 client access hint와 무관하게 최종 반영
  • duplicate/unsafe mutation 전송 횟수
  • src/features/reference-feature 삭제 후 typecheck, architecture, registry, unit/integration, home smoke와 build
  • 삭제 후 sample route 부재와 src/tests의 fixture-specific ID 잔여 0개
  • generic home/examples route가 sample 없이 계속 작동

Acceptance

  • static page와 분리된 fixture가 아니라 실제 수직 경로 하나가 존재한다.
  • reference feature를 삭제할 때 central registry를 수작업으로 수정하는 숨은 단계가 없거나 제거 명령이 이를 결정적으로 수행한다.
  • feature 존재/제거 두 모드에서 P0 gate가 모두 통과한다.
  • 01~04를 함께 revert해야만 sample을 제거할 수 있는 숨은 결합이 없다.

Rollback

RP-05는 P0 최종 지점이다. reference feature merge만 revert해도 generic platform은 정상이어야 한다.

7. P0 exit gate

  • JS/TS source와 tests가 동일한 정적 gate에 포함된다.
  • UI는 application input API만 호출하고 concrete outbound adapter를 모른다.
  • HTTP path/search/body/auth/timeout/retry/cancel/decode가 실행 계약과 일치한다.
  • query/mutation controller와 모든 async state transition이 작동한다.
  • route registry/runtime map과 route chunk map이 양방향 완전성을 가진다.
  • lazy chunk failure가 bounded release recovery에 연결된다.
  • reference feature가 실제 수직 경로를 실행하고 전체 삭제 gate를 통과한다.
  • pnpm ci:gate와 P0에서 추가한 모든 negative fixture가 통과한다.

위 조건이 모두 충족돼야 LOCAL_CORE_READY다. RP-05 증거를 보존한 뒤 P1을 시작한다.

8. P1 브랜치

06. feature-frontend-form-page-platform

목표

Zod schema와 application command를 연결하는 form controller 및 standard/collection/detail/form/status page template를 제공한다.

선행조건과 decision

  • 05의 mutation과 async state가 실제 reference flow에서 작동해야 한다.
  • VD-04에서 React Hook Form + Zod resolver 사용 여부를 정한다. 복합 form 요구가 확정되면 local facade 뒤에 추가하고, 거절되면 native form + local controller가 같은 public API와 tests를 충족한다. React Hook Form resolvers, Zod
  • vendor 결정 전에 dependency/lockfile을 변경하지 않는다.

구체 변경 범위

  • presentation form schema와 domain invariant를 분리한다.
  • field registration, parse/error map, dirty/touched/reset/pending/result를 local form API로 감싼다.
  • 422 field/form/unknown-server-field/global error mapping을 정의한다.
  • 첫 오류 focus, error summary, field ID와 live-region을 연결한다.
  • duplicate submit, cancel/leave와 unsaved-change 정책을 적용한다.
  • StandardPage, CollectionPage, DetailPage, FormPage, StatusPage의 slot 계약을 정의한다.
  • heading, breadcrumb, actions, filters, content, aside와 feedback의 소유 위치를 표준화한다.
  • reference list/detail/create-edit/status page를 controller와 template로 전환한다.
  • template가 application use case나 query vendor를 직접 선택하지 않게 한다.

자동 테스트와 negative test

  • client validation 실패에서 command 0회와 첫 invalid field focus
  • transformed/defaulted data가 command에 전달됨
  • field/form/unknown server error와 conflict 후 입력 보존
  • pending 중 연속 submit에도 command 1회
  • reset 후 dirty 해제와 navigation confirmation/focus restore
  • secret-like input이 URL/storage/log/telemetry에 나타나면 실패
  • 각 template의 최소/전체 slot 및 async/error variation
  • 320px, zoom, 긴 heading/action과 wide layout
  • heading/landmark/accessibility-name/axe
  • template가 application/HTTP/query vendor를 import하면 gate 실패
  • action callback 없이 활성 버튼을 렌더링하면 실패

Acceptance

  • form engine을 바꿔도 page와 application API가 변하지 않는다.
  • multi-field form의 validation/pending/dirty/422/conflict가 실행된다.
  • 새 feature가 layout CSS를 복사하지 않고 다섯 page 유형을 조립한다.
  • template는 layout/state slot만 소유하고 데이터 정책은 소유하지 않는다.

Rollback

RP-06은 기존 reference controls/layout으로 돌아가도 controller/application 경계가 유지돼야 한다. vendor adapter, form contract와 template commit을 구분해 부분 revert가 가능하게 한다.

구현 증거 (2026-07-26)

  • VD-04에서 dependency 추가 없는 native controller + Zod local facade를 채택했고 vendor 도입 조건을 문서화했다.
  • src/presentation/forms가 field registration, parse/error map, dirty/touched/reset/pending/result, 422 allowlist, first-error focus, duplicate submit과 dirty navigation을 제공한다.
  • src/presentation/templates가 다섯 page 유형의 slot/landmark/responsive 계약을 제공하며 architecture negative fixture가 application/vendor import를 거절한다.
  • reference list/detail/create/status route가 네 구체 template를 사용하고 production composition test가 list → form → command → HTTP → invalidation → list 경로를 실행한다.
  • component/integration/E2E test가 validation, transform, 422, conflict, secret 비노출, navigation focus와 320px reflow를 검증한다.

07. feature-frontend-design-system-platform

목표

기존 theme와 primitive를 token → primitive → pattern → template 계층으로 확장하고, 모바일 drawer와 복합 interaction을 접근 가능한 local API로 제공한다.

선행조건과 decision

  • 06의 page/form에서 반복되는 실제 token/primitive 요구를 수집한다.
  • VD-05에서 icon source와 headless interaction 방식을 결정한다.
  • Lucide를 선택하면 static named import만 local icon facade에서 허용한다. Lucide React, Lucide accessibility
  • headless vendor가 미결정이면 native dialog/disclosure/control 범위만 완료하며, 미지원 widget을 임의 구현해 완료로 표시하지 않는다.

구체 변경 범위

  • primitive/semantic/component token을 분리한다.
  • color, typography, spacing, size, radius, elevation, z-layer, motion, breakpoint와 opacity 계약을 정의한다.
  • light/dark/system, forced-colors와 reduced-motion을 닫는다.
  • design-system public entry와 deep-import 금지 규칙을 만든다.
  • 기존 Button/TextField/Card/Alert/Badge/Dialog를 호환 가능한 public API로 이동한다.
  • LinkButton/IconButton/Field/TextArea/Select/Checkbox/RadioGroup/Switch/ Spinner/Skeleton/VisuallyHidden을 기본 제공한다.
  • Drawer/Popover/Tooltip/Menu/Tabs/Breadcrumbs/Pagination/Toast/ProgressBar 및 필요한 focus/portal utility를 추가한다.
  • 모바일 navigation을 Drawer로 전환해 focus 이동, modal/background 정책, Escape/scrim/link dismiss와 trigger focus restore를 구현한다.
  • 앱 셸의 문자 glyph/raw control을 local icon/primitive로 교체한다.
  • /examples/ui/examples/states에서 interactive state를 실제 동작으로 노출한다.

자동 테스트와 negative test

  • 필수 semantic token의 light/dark/forced-colors 정의
  • undefined CSS variable/raw palette 사용 거절
  • interactive icon의 accessible name 누락 거절, decorative icon tree 제외
  • product code의 direct icon/headless vendor 또는 deep import 거절
  • disabled/pending/focus/invalid와 reduced-motion/theme persistence
  • keyboard-only open/move/select/dismiss/focus restore
  • Drawer open 시 background interaction 차단과 compact reflow
  • Menu/Tabs arrow key, typeahead와 activation 정책
  • Tooltip만으로 필수 정보를 제공하는 fixture 거절
  • Toast queue 상한/duplicate collapse/timeout pause
  • Chromium/Firefox/WebKit component/E2E/axe

Acceptance

  • shell, templates와 reference feature가 public design-system API를 사용한다.
  • product code의 raw palette, vendor icon/headless import가 0개다.
  • mobile navigation이 검증된 focus/dismiss contract를 따른다.
  • gallery action이 handler 없는 장식이 아니라 실행 가능한 상태를 시연한다.
  • token 누락과 접근 불가능한 interaction을 자동 gate가 차단한다.

Rollback

RP-07은 compatibility export로 기존 primitive import를 복구할 수 있어야 한다. token rename은 alias/migration 기간을 두고, vendor adapter와 local API commit을 분리한다.

구현 증거 (2026-07-26)

  • VD-05에서 lucide-react@1.25.0 static semantic facade와 native-first interaction을 채택하고 headless vendor 재평가 조건을 닫았다.
  • src/presentation/design-system이 48개 필수 token, public TypeScript barrel, action/form/feedback/overlay/navigation primitive와 공통 pattern을 제공한다.
  • 기존 components/ui 경로는 compatibility export로 유지하고 앱 셸, gallery와 reference feature는 public entry를 소비한다.
  • 모바일 navigation은 native modal Drawer로 전환되어 배경 비활성화, Escape, route dismiss와 trigger focus restore를 제공한다.
  • source/negative fixture gate가 undefined token, raw palette, direct vendor, deep import, tooltip-only 정보와 accessible name 누락을 거절한다.
  • component/browser test가 Menu typeahead, Tabs activation, Toast queue, form controls, compact reflow와 open-dialog axe를 실행한다. 로컬 WebKit은 host libevent-2.1.so.7 부재로 환경 검증 상태를 유지한다.

08. feature-frontend-i18n-message-formatting-contract

목표

사용자 문구, 날짜, 숫자, 상대 시간과 direction을 typed message/formatter 경계로 옮겨 특정 언어 literal과 locale 가정을 공통 UI에서 제거한다.

선행조건과 decision

  • 07까지의 common user-facing string 목록이 확보돼 있어야 한다.
  • VD-06 기본값은 browser Intl + typed local catalog다. extraction/plural 등 요구가 이를 넘을 때만 vendor를 선택한다.
  • 실제 번역 승인과 지원 locale은 외부 프로젝트 범위다.

구체 변경 범위

  • typed message key와 interpolation parameter 계약을 정의한다.
  • locale provider, fallback locale, direction과 date/number/relative-time formatter를 제공한다.
  • shell, route, async/form error와 design-system 기본 copy를 catalog로 이동한다.
  • backend raw message를 번역 key로 신뢰하지 않고 error registry로 매핑한다.
  • pseudo-locale와 RTL smoke locale을 테스트 전용으로 제공한다.
  • unknown key/locale, formatter failure와 missing interpolation의 fallback을 정의한다.

자동 테스트와 negative test

  • 모든 등록 locale의 key parity와 interpolation 정합성
  • unknown locale/key에서 raw key/stack을 노출하지 않는 fallback
  • pseudo-locale 확장에 대한 layout/reflow
  • RTL shell/drawer/breadcrumb와 directional icon
  • 날짜/숫자/timezone의 결정적 test
  • untrusted HTML interpolation 및 backend message 직접 렌더링 거절
  • common UI의 금지된 hardcoded user-facing literal 검출

Acceptance

  • shell/state/form/error copy가 typed catalog를 통과한다.
  • pseudo-locale와 RTL E2E가 통과한다.
  • 실제 제품 번역 없이도 locale 교체 지점과 실패 정책이 검증된다.
  • key rename에는 compatibility alias 또는 migration이 있다.

Rollback

RP-08은 기존 기본 언어 catalog를 fallback으로 유지한다. 번역 catalog를 파괴적으로 덮어쓰지 않는다.

구현 증거 (2026-07-26)

  • VD-06에서 dependency를 추가하지 않는 browser Intl + typed local catalog를 채택하고 vendor 재평가 조건, fallback과 key migration 정책을 문서화했다.
  • src/presentation/i18n이 137개 common key, key별 interpolation, ko-KR fallback, compatibility alias, date/number/relative/list/plural/select formatter와 LocaleProvider를 제공한다.
  • shell, route lifecycle/access/recovery, async/form error, page template와 design-system default copy가 catalog consumer로 연결됐다.
  • feature route copy는 feature-owned catalog contribution으로 분리되어 reference feature 제거 시 source와 built artifact에 전용 message key가 남지 않는다.
  • reference application mapper는 locale-formatted date 대신 timestamp를 반환하고 presentation formatter가 UTC 또는 명시 timezone을 적용한다.
  • check:i18n과 type negative fixture가 catalog/placeholder 불일치, hardcoded common literal, backend raw message render, unsafe HTML, unknown key와 interpolation mismatch를 거절한다.
  • unit/component/browser test가 safe fallback, pseudo 320px reflow, document lang/dir, RTL Drawer/Tabs/directional icon과 deterministic formatter를 검증한다.

09. feature-frontend-diagnostics-telemetry-runtime

목표

structured diagnostics와 telemetry를 구분하고 boot, HTTP, cache, storage, route, render와 release 사건을 실제 producer에 연결한다.

선행조건과 decision

  • route/HTTP/query/form/release failure kind가 안정돼 있어야 한다.
  • VD-07에서 외부 exporter를 선택하지 않아도 된다. no-op 또는 기존 best-effort HTTP sink를 기본으로 하고 실제 vendor SDK는 외부 adapter다.

구체 변경 범위

  • diagnostics/logger output port와 telemetry event port의 책임을 분리한다.
  • level, event ID, timestamp, correlation/request/route/release context와 redaction 정책을 정의한다.
  • app.boot.failed, api.request.failed, ui.render.failed, release.mismatch.detected, telemetry.delivery.dropped를 production path에 연결한다.
  • retry attempt마다 terminal failure를 중복 발행하지 않고 bounded summary만 남긴다.
  • route/path/query/body/error에서 고카디널리티와 민감 값을 제거한다.
  • queue 상한, drop reason bucket, sink failure와 nonrecursive fallback을 구현한다.
  • reference feature에서 route → application → HTTP outcome correlation을 증명한다.

자동 테스트와 negative test

  • registry event가 production path에서 필요한 횟수만 발행
  • success/retry recovery/terminal failure event 차이
  • Authorization/cookie/token/raw form/body/PII-like fixture redaction
  • large/circular/unknown error에서도 serializer가 throw하지 않음
  • queue full/sink failure가 app failure나 재귀 폭주를 만들지 않음
  • unknown/high-cardinality event context 거절
  • mount 전 boot failure도 안전한 evidence 생성
  • no-op adapter에서도 동일 application behavior

Acceptance

  • 필수 telemetry event 중 producer 없는 항목이 0개다.
  • sink/vendor가 없어도 기능이 정상이며 failure evidence가 제한된다.
  • credential/raw user input이 queue, console과 artifact에 남지 않는다.
  • exporter wiring만 독립적으로 제거할 수 있다.

Rollback

RP-09는 exporter를 제거하고 즉시 no-op adapter로 전환할 수 있어야 한다. diagnostics port와 redaction test는 유지한다.

구현 증거 (2026-07-26)

  • VD-07에서 level/event 기반 DiagnosticsPort와 semantic TelemetryPort를 분리하고 bounded memory/no-op 또는 설정 기반 best-effort HTTP exporter를 채택했다.
  • diagnostics 8종과 telemetry 5종의 registry, context/attribute allowlist, 고카디널리티 value policy, timestamp와 status/attempt/duration/queue bucket을 구현했다.
  • boot, route, render, HTTP logical outcome, cache, storage, release mismatch와 telemetry drop을 production composition에 연결했다. HTTP는 success/recovery/ terminal/abort 각각 logical execution당 diagnostics 한 번, terminal non-abort failure telemetry 한 번만 발행한다.
  • bounded oldest-drop queue, drop reason 집계, sink/observer failure 격리와 nonrecursive delivery evidence를 구현했다. exporter가 없으면 network와 queue side effect가 없는 true no-op이다.
  • check:diagnostics, source negative fixture와 TypeScript negative fixture가 producer 누락, direct console, unknown event/context, raw URL/query/body/ credential 경계를 거절한다.
  • unit/integration test가 circular/hostile error, pre-mount boot, queue/sink failure, no-op, cache/storage/release producer, success/retry recovery/terminal/ abort 횟수와 reference route/operation/correlation context를 검증한다.

10. feature-frontend-test-registry-evidence-hardening

목표

registry의 구조/참조/consumer/호환성을 실제 diff로 검증하고, P0/P1 위험 경로를 실제 bootstrap과 built artifact에서 증명한다.

선행조건과 decision

  • 09까지의 public contract와 registry field가 안정돼 있어야 한다.
  • VD-08 기본값은 dev-only Storybook workshop과 local Playwright visual baseline이다. cloud review service는 선택이다.
  • /examples/ui, /examples/states는 실제 앱 composition의 통합 smoke로 유지하며 isolated story의 SSOT를 대신하지 않는다. Storybook documentation

구체 변경 범위

  • route/API/schema/error/query/storage/telemetry/config/release registry의 field type/enum/unique/cross-reference/consumer/orphan을 machine-readable하게 검사한다.
  • 직전 승인 snapshot과 현재 snapshot의 actual diff로 additive/behavioral/ breaking/removal을 계산한다.
  • breaking에는 version bump, migration, compatibility window와 rollback evidence를 요구한다.
  • hardcoded current: additive, empty high-risk review와 self-asserted PASS를 제거한다.
  • source와 tests를 모두 포함하는 TypeScript check를 CI 필수 gate로 만든다.
  • MSW handler를 operation/schema 기반 shared scenario catalog로 통합한다.
  • 실제 main composition과 built dist의 integration/release E2E를 추가한다.
  • Playwright compact/mobile project와 risk-based coverage threshold를 추가한다.
  • deterministic clock/random/fetch/storage helper, unexpected console/unhandled rejection 실패 정책을 제공한다.
  • 선택된 workshop interaction 또는 안정 환경의 visual baseline을 추가한다.
  • JUnit/screenshot/trace/evidence naming과 CI gate registry를 맞춘다.

자동 테스트와 negative test

  • duplicate ID/path, invalid enum/type, missing field/reference와 orphan 거절
  • actual removal/type narrowing/path change를 additive로 표시하면 실패
  • breaking diff의 version/migration/rollback 누락 실패
  • ordering-only diff는 semantic change가 아님
  • 승인 baseline digest 변조 실패
  • unexpected network/operation, provider 누락과 unhandled error 실패
  • critical policy coverage threshold 미달 실패
  • built artifact의 source map, config schema 누락과 broken chunk 실패
  • compact viewport와 Chromium/Firefox/WebKit navigation/a11y smoke
  • reference feature 제거 모드의 generic E2E/build
  • screenshot mask가 전체 UI를 가려 false PASS를 만들면 실패

Acceptance

  • route 선언/실행 불일치와 telemetry producer 누락을 registry gate가 잡는다.
  • compatibility impact가 하드코딩 상수가 아니라 actual diff다.
  • 테스트가 source module만이 아니라 real composition과 dist를 증명한다.
  • 모든 P0/P1 high-risk policy에 negative fixture가 하나 이상 있다.
  • CI artifact로 browser/release/fixture 실패를 재현할 수 있다.

Rollback

RP-10은 직전 승인 registry snapshot과 test evidence다. flaky visual/browser infrastructure commit은 product behavior와 분리한다. 장기 skip으로 PASS하지 않고 owner와 만료 시한이 있는 quarantine만 허용한다.

구현 증거 (2026-07-26)

  • VD-08에서 dev-only Storybook static workshop과 production build를 대상으로 한 local Playwright visual baseline을 채택하고 cloud review는 선택 사항으로 분리했다.
  • 10개 registry의 required field, runtime type, enum, unique, cross-reference, consumer와 orphan을 검사하고 승인 snapshot digest와 현재 snapshot의 actual semantic diff를 계산한다. 행·field·type·path뿐 아니라 registry 검증 계약 변경도 breaking evidence 대상이다.
  • ordering-only 변경은 none, row addition은 additive, 일반 값 변경은 behavior-change, 제거/type/path/contract 변경은 breaking으로 계산한다. breaking에는 version, migration, compatibility window, rollback과 owner를 요구하며 digest 변조와 누락 fixture가 실제로 실패한다.
  • API operation별 19개 shared MSW scenario catalog와 strict unhandled-request server를 제공하고 reference vertical integration이 공통 envelope/handler를 사용한다.
  • 기본 Playwright는 build + preview의 실제 dist를 Chromium, Firefox, WebKit에서 검사하고 별도 compact project를 제공한다. 개발 피드백용 Vite profile은 playwright.dev.config.ts로 분리했다.
  • Storybook public primitive story, interaction과 axe test, wide/compact/ pseudo/dark/state surface의 pinned Chromium visual baseline 4종을 CI evidence로 연결했다.
  • V8 coverage와 12개 high-risk module을 대상으로 52개 scoped threshold를 적용하고 threshold 미달 fixture를 차단한다.
  • deterministic clock/random/scheduler/storage, unexpected console/page error/ request failure 정책, 무소유 skip과 full-screen mask 금지 gate를 제공한다.
  • JUnit, HTML report, trace/screenshot, coverage, registry와 fixture artifact를 기존 26개 blocking gate taxonomy에 연결했다.

11. feature-frontend-supply-chain-verification

목표

직접·전이 dependency, vulnerability, license, secret, SBOM/inventory와 provenance를 검증 가능한 release gate로 만든다.

선행조건과 decision

  • 10까지 최종 build/test dependency 구조가 안정돼 있어야 한다.
  • VD-09에서 vulnerability source, license policy, SBOM format과 attestation provider를 선택한다.
  • provider가 미결정이면 임의 PASS를 만들지 않고 promotion을 FAIL_UNVERIFIED로 유지한다. local inventory/fixture 검증은 완료할 수 있다.

구체 변경 범위

  • frozen lockfile에서 direct/transitive dependency inventory를 생성한다.
  • name/version, direct/transitive, resolved integrity와 license를 deterministic하게 기록한다.
  • actual baseline/lockfile diff에서 new/removed/changed dependency와 reviewer-required risk를 계산한다.
  • secret scan 범위를 source/dist/tracked config/generated manifest와 artifact metadata에 맞게 확장한다.
  • 선택된 vulnerability/license adapter가 severity, exception owner/expiry를 machine-readable evidence로 남기게 한다.
  • SBOM 또는 동등 inventory, build digest와 provenance statement를 coherent release artifact set에 연결한다.
  • frozen install과 동일 source/lock/config의 reproducible build를 검증한다.

자동 테스트와 negative test

  • transitive dependency inventory 누락 실패
  • lockfile integrity/digest 변조와 unfrozen install 실패
  • high-risk dependency의 self-approval 실패
  • 금지 license, threshold vulnerability와 만료 exception 실패
  • source/dist/config secret fixture 검출 및 test-secret allowlist 통제
  • SBOM/inventory와 release manifest digest 불일치 실패
  • provenance subject와 artifact digest 불일치 실패
  • dependency ordering만 달라도 deterministic output 유지

Acceptance

  • dependency diff와 high-risk review가 하드코딩 빈 배열이 아니다.
  • transitive inventory, license와 vulnerability 결과가 release evidence에 포함된다.
  • provider/organization decision이 없으면 상위 promotion이 명시적으로 FAIL_UNVERIFIED다.
  • 위험 dependency upgrade만 독립적으로 revert할 수 있다.

Rollback

RP-11은 P1 최종 저장소 기준선이다. scanner outage를 무검증 승인으로 우회하지 않고 promotion을 보류한다.

구현 증거 (2026-07-26)

  • VD-09에서 frozen pnpm graph와 lockfile을 local SSOT로, package manifest license policy와 CycloneDX 1.6을 local evidence로 채택했다. 외부 vulnerability report와 signed attestation이 없으면 promotion은 FAIL_UNVERIFIED다.
  • 현재 직접 35개, 전체 전이 561개 dependency의 name/version, direct/scope/ optional, SHA-512 integrity, license와 dependency edge를 deterministic inventory로 생성한다. lockfile row와 inventory가 양방향 일치하지 않으면 실패한다.
  • 승인 baseline digest와 actual add/remove/change/upgrade diff를 계산하고 새 direct production dependency에는 owner와 다른 reviewer, reason과 rollback을 요구한다.
  • CycloneDX SBOM component/edge와 local in-toto/SLSA 형태 provenance의 source/lock/SBOM/dist digest를 coherence gate로 다시 계산한다.
  • license allow/deny, vulnerability severity와 독립·만료 exception 정책, provider lock digest와 attestation subject를 machine-readable하게 검증한다. provider fixture는 promotion PASS를 증명한 뒤 unconfigured FAIL_UNVERIFIED를 복원한다.
  • secret scan을 source/scripts/tests/config/schema/public/dist/generated release metadata로 확장하고 원문 대신 rule/path/line/fingerprint만 SARIF에 남긴다. test-only allowlist도 owner/reason/expiry를 강제한다.
  • SOURCE_DATE_EPOCH 기반 동일 build 2회 digest, 실제 frozen install mismatch, transitive omission/integrity/baseline/self-review/license/vulnerability/ provider/SBOM/provenance/secret negative fixture를 blocking gate에 연결했다.

9. P1 exit gate

  • 현실적인 form의 validation/dirty/pending/422/conflict가 작동한다.
  • collection/detail/form/status를 포함한 page template가 reference feature에서 사용된다.
  • token → primitive → pattern → template 경계가 자동 보호된다.
  • compact navigation과 interaction의 keyboard/focus 계약이 검증된다.
  • typed message, pseudo-locale와 RTL smoke가 존재한다.
  • 필수 telemetry event가 실제 producer에 연결되고 secret/PII가 redaction된다.
  • registry/compatibility가 actual diff와 cross-reference로 검증된다.
  • bootstrap과 built dist를 포함한 risk-based test/evidence가 남는다.
  • transitive dependency, vulnerability, license와 local SBOM가 선택된 정책에 따라 검증된다. 외부 signing/provenance provider가 미결정이면 해당 promotion만 FAIL_UNVERIFIED다.
  • 현재 merge gate가 요구하는 등록 route의 signed manual accessibility evidence가 갱신된다.
  • P0/P1 feature branch와 merge evidence가 local/origin에 모두 보존된다.

위 조건이 모두 충족되면 LOCAL_TEMPLATE_READY다. 실제 hosting, IdP, production sink와 field data 없이도 저장소 내부 상태는 달성할 수 있지만, 외부 gate 없이는 production promotion을 통과했다고 보지 않는다.

10. P2 브랜치

12. feature-frontend-optional-adapter-recipes

목표

모든 프로젝트에 dependency를 미리 설치하지 않고, 실제 요구가 확인된 capability의 선택 기준, port/facade, fake adapter, failure policy와 test recipe를 제공한다.

선행조건과 decision

  • P0/P1 public boundary가 안정돼 있어야 한다.
  • VD-10에서 실제 소비 요구, owner, 보안 영향, bundle 예산과 제거 조건이 승인된 recipe만 구현한다.
  • 승인되지 않은 recipe의 runtime dependency는 추가하지 않는다.

구체 변경 범위

recipe 기본 경계 반드시 다룰 실패
realtime SSE/WebSocket connection + inbound event, Web Push window/worker, bounded Poll lease disconnect, duplicate/out-of-order/gap, cursor/auth expiry, queue overflow, permission/subscription failure
offline/IndexedDB/OPFS feature repository, resumable migration, journal-backed large-object store blocked/versionchange, quota, corruption, revision/generation conflict, partial object write
Service Worker/Cache Storage public response cache ownership와 update controller stale worker, incomplete candidate, integrity/policy rejection, offline fallback
File/Blob/picker/download opaque file vault, upload session, browser handoff/streamed save dismissal/permission, size/type/signature, abort/session expiry, integrity/partial save
generated API generated client를 gateway 뒤에 감싸는 facade contract drift, unsupported field
feature flag typed key, default와 stale policy provider unavailable, unknown flag
Web Worker request/result/cancel protocol crash, stale result, transfer failure
multi-tab versioned BroadcastChannel event self-echo, duplicate, conflict
browser permission clipboard/notification/media result port denied, dismissed, unsupported
client workflow Zustand/Redux Toolkit/state-machine local facade reset, mismatch, server-state duplication
large data UI virtualizer/data-grid facade focus loss, stale row, scale limit
analytics/error sink consent/redaction/sampling adapter denied consent, queue full, unavailable
  • 각 recipe에 설치/금지 조건, ownership, security/privacy, bundle 영향, fallback과 제거 절차를 기록한다.
  • runnable fixture는 production entry에서 제외한 opt-in example/test entry에 둔다.
  • Zustand와 Redux Toolkit을 동시에 기본 설치하지 않는다.
  • browser가 DB/object store에 직접 접속하는 recipe는 만들지 않고 권한 있는 backend/BFF protocol adapter를 사용한다.

자동 테스트와 negative test

  • 선택 recipe의 fake adapter contract 및 unavailable fallback
  • unsubscribe/cancel/cleanup 누락 fixture 실패
  • local adapter 밖의 vendor SDK direct import 실패
  • credential을 localStorage/telemetry/URL에 저장하는 fixture 실패
  • server state를 client workflow store에 복제하는 fixture 실패
  • recipe 제거 후 base typecheck/test/build 통과
  • opt-in하지 않은 recipe가 production bundle에 없음을 검증

Acceptance

  • 선택 capability는 port/facade, fake adapter, failure matrix, tests와 제거 절차를 가진다.
  • 선택하지 않은 capability는 dependency와 production code를 늘리지 않는다.
  • recipe 하나의 도입/제거가 다른 recipe와 P0/P1 runtime을 변경하지 않는다.

Rollback

RP-12는 recipe별 merge commit이다. optional adapter 문제 시 해당 recipe commit만 revert하고 RP-11을 유지한다. 여러 vendor를 되돌릴 수 없는 한 commit에 묶지 않는다.

구현 증거 (2026-07-26)

  • VD-10에서 실제 project 요구가 선택되지 않았음을 기록하고 12개 capability를 모두 RECIPE_AVAILABLE, production runtime dependency 0개로 유지했다.
  • machine-readable catalog에 recipe별 trigger/forbidden 조건, boundary, port/fake, failure matrix, lifecycle cleanup, project owner 요구, security/privacy, gzip budget, fallback, server-state 정책과 제거 순서를 등록했다.
  • production-excluded recipes/frontend-capabilities에 12개 vendor-neutral TypeScript port와 deterministic fake, fail-closed unavailable adapter를 제공한다. 프로젝트는 선택한 최소 계약만 application/presentation 경계로 복사하고 concrete adapter를 composition에서 연결한다.
  • realtime ordering/unsubscribe, offline migration/close, worker cancel, multi-tab dedupe, permission result, workflow reset, large-data stale generation, analytics consent/redaction/queue와 나머지 facade contract를 runnable test로 검증한다.
  • cleanup 누락, 승인되지 않은 dependency, vendor direct import, credential storage/URL/telemetry 경로, server-state store 복제와 production recipe import negative fixture를 blocking gate에 연결했다.
  • recipe와 recipe test를 통째로 제거한 임시 사본에서 base typecheck, architecture, 전체 test와 production build를 실행하며, opt-in하지 않은 sentinel이 built dist에 없는지 검사한다.
  • 상세 도입/배치/검증/제거 절차는 docs/architecture/optional-adapter-recipes.md에 기록했다.
  • 2026-07-27 후속 설계에서 VD-11을 추가하고 File/Blob/picker/download를 picker/content/upload-session/download-delivery로 분리했다. IndexedDB는 schema/codec, transaction complete, blocked/versionchange, resumable migration 계약으로 보강하고, OPFS는 IndexedDB journal 기반 crash-safe large-object sub-capability, Cache Storage는 public response 전용 release-candidate sub-capability로 명시했다.
  • 같은 후속 구현에서 해당 browser-native sub-capability를 정책 주입형 AVAILABLE_NOT_COMPOSED reference runtime으로 src/adapters에 구현했다. 제품별 schema/codec/query/retention/cache allowlist는 주입하며, 선택 전에는 bootstrap import를 정적 gate로 금지하고 실제 browser conformance suite로 native API 경로를 검증한다.
  • browser-file-storage-contracts.ts와 deterministic fake/test가 CAS/idempotency, quota, picker dismissal, bounded range/stream, partial OPFS write visibility, generation conflict, cache exact query/integrity policy를 실행 가능하게 검증한다. reference runtime source는 존재하지만 production composition의 optional runtime module 수는 계속 0개이며, 실제 선택 branch는 real-browser/fault/runbook evidence 없이 INSTALLED로 승격할 수 없다.
  • 2026-07-28 후속 설계와 구현에서 VD-12를 추가했다. presigned capability는 BFF control plane과 browser/object-storage data plane을 분리하고, multipart upload는 server-authoritative reconcile과 non-secret IndexedDB checkpoint, streaming download는 bounded closed-result source, Image CDN은 opaque asset과 named preset 기반 responsive descriptor로 구현한다. 제품 endpoint/CDN policy가 없으므로 모두 AVAILABLE_NOT_COMPOSED이며 bootstrap에는 연결하지 않는다.
  • generic multi-tab recipe와 별도로, installed TanStack query의 좁은 invalidate-only protocol은 2026-07-28 RP-03 infrastructure로 선택·조립했다. query state/payload를 복제하지 않고 persistence는 계속 disabled다. 기존 IndexedDB reference runtime은 이 선택 때문에 bootstrap에 조립되지 않는다.
  • 같은 날 VD-28과 Realtime events, Web Push, and bounded polling을 추가했다. SSE, WebSocket, Web Push와 Polling을 별도 delivery capability로 분리하고 공통 delivery guarantee 없음, duplicate-tolerant CURSOR 처리, gap/snapshot checkpoint, scope generation, bounded lifecycle과 promotion 계약을 닫았다. 후속 RT-01~04에서 공통 authority, fetch-stream SSE, bounded Polling, closed WebSocket, Web Push window/worker와 단일 writer handoff/reconnect coordinator를 구현해 reusable runtime은 AVAILABLE_NOT_COMPOSED로 올렸다. 제품 endpoint/event registry/provider selection과 production composition은 없으므로 product는 계속 NOT_SELECTED다.
  • 2026-07-28 API-05/API-06 공통 선행 구현으로 Browser RPC V3 operation/provider registry, typed application port, provider-neutral unary/server-stream lifecycle coordinator와 fail-closed unavailable adapter를 추가했다. exact registry join, bounded retry/deadline/abort, stream idle/total/message/terminal, scope generation을 test하므로 이 공통 층만 AVAILABLE_NOT_COMPOSED다. descriptor/codegen, Connect-Web/official grpc-web transport와 실제 proxy/browser conformance는 포함하지 않는다.

12.1 Browser data 후속 work package

RP-12의 reference runtime 존재는 browser data platform 전체의 구현 완료를 뜻하지 않는다. 현재 상태와 상세 exit criteria는 Browser data capability completion ledger를 단일 기준으로 사용한다. 후속 구현은 다음 독립 package로 진행한다.

순서 work package 핵심 exit
BD-01 scope-safe client cache logout/account switch의 cancel/fence/clear/dispose와 late-result 차단
BD-02 Range resumable download precondition-mode별 allowed 200/206/412/416, seek/truncate와 final integrity
BD-03 origin storage lifecycle cross-store pressure/GC, bounded maintenance와 N-1 migration/rollback
BD-04 transfer operational composition atomic config/factory, account teardown, pause/retention과 provider harness
BD-05 Image descriptor delivery fixed BFF provider, refresh fence, safe picture projection과 actual CDN 증거

각 package는 다음 순서를 지킨다.

ledger + ADR accepted
  -> closed port/policy/schema
  -> deterministic contract/fault evidence
  -> reference runtime + boundary/removal gate
  -> AVAILABLE_NOT_COMPOSED
  -> product/provider selection
  -> bootstrap composition + three-engine evidence
  -> COMPOSED

directory/persistent file handle, Query persistence, offline mutation, Service Worker fetch interception, private/range Cache와 app-managed background transfer는 위 package에 암묵적으로 포함하지 않는다. 각각 NOT_SELECTED에서 별도 ADR과 owner 승인을 거쳐야 한다.

12.2 API·Schema·Mapper·Server State 후속 work package

REST reference vertical의 COMPOSED 판정과 multi-protocol production hardening을 구분한다. 현재/목표 상태, protocol 선택 기준과 완료 조건은 API contract, Schema, Mapper와 Server State가 소유한다. Browser Protobuf runtime과 gateway branch의 세부 기준은 Protobuf browser transport와 REST Gateway를 따른다.

순서 work package 핵심 exit
API-01 REST v2 execution auth fail-close/final invariant, collision-free registry, total deadline, bounded status/media decoder
API-02 typed Schema·Mapper codec/mapper type proof, semantic fingerprint/provenance, scalar/null/enum/collection ceiling
API-03 strict Server State bound query definition/key/policy, cursor page, mutation concurrency와 revision/CAS optimistic rollback
API-04 persisted GraphQL allowlisted manifest, data/errors/partial state, cost/auth/CSRF와 actual router conformance
API-05 gRPC-Web descriptor/codegen, frame/trailer/status, unary/server-stream budget와 actual proxy/browser conformance
API-06 Connect-Web exact Connect/gRPC-Web transport row, JSON/binary/GET/EndStream, bounded decode와 actual server/browser conformance
API-07 Protobuf REST Gateway schema/codegen provenance, HttpRule/ProtoJSON/OpenAPI와 selected gateway conformance
API-08 operations/composition contract-set release binding, provider kill switch, coherent rollback과 protocol dependency removal

API-05/API-06가 공유하는 provider-neutral registry와 lifecycle coordinator는 AVAILABLE_NOT_COMPOSED다. 그러나 각 package의 wire adapter exit는 아직 충족되지 않았으므로 API-05/API-06 전체를 완료로 표시하지 않는다.

GraphQL, Connect, gRPC-Web과 REST Gateway는 제품 operation/provider 선택 전 NOT_SELECTED다. 설계 문서가 있다는 이유로 dependency/generated source/proxy config를 기본 bundle에 넣지 않는다. browser client/bidirectional streaming은 구현 backlog가 아니라 PLATFORM_LIMITED이며 별도 transport 요구로 다시 설계한다.

권장 순서는 API-01 → API-02 → API-03이다. API-04~07은 실제 backend contract가 선택된 branch만 구현한다.

12.3 Realtime delivery 후속 work package

copyable recipe의 교육용 RealtimePort와 fake는 production runtime 증거가 아니다. 현재 상태, transport 선택, event authority와 완료 기준은 Realtime events, Web Push, and bounded polling이 소유한다.

순서 work package 핵심 exit
RT-01 common event authority closed registry/envelope, scope generation, sequential apply, dedupe/gap/cursor와 snapshot reset
RT-02 SSE + bounded polling bounded fetch-stream parser, reconnect/heartbeat와 visible-only single-flight Poll lease
RT-03 WebSocket fixed subprotocol, heartbeat/close, bounded inbound/outbound queue와 resume
RT-04 Web Push permission/subscription facade, worker push/click, safe notification와 provider lifecycle
RT-05 product composition/operations backend replay/outbox/auth, hosting/provider/browser evidence, canary/kill switch/drill

RT-01~04의 source, contract/native test, boundary/bundle/removal gate가 통과한 runtime만 AVAILABLE_NOT_COMPOSED로 올린다. 실제 event/notification registry와 provider가 bootstrap/worker에 조립된 선택 capability만 COMPOSED다. exactly-once/global ordering, always-on background connection과 timely cross-browser Web Push guarantee는 구현 backlog가 아니라 PLATFORM_LIMITED다.

11. Vendor decision gate

ID 시점 결정 기본값 또는 미결정 시 처리 차단 범위
VD-01 01 전 TypeScript migration 범위와 compiler 변경 기존 compiler 고정, tooling-first 점진 전환 compiler upgrade와 source 변환
VD-02 02 전 범용 client store 추가하지 않음. local/URL/query/context 사용 실제 cross-feature workflow만
VD-03 04 전 React Router mode Data Mode; server state는 TanStack/application 유지 Framework/SSR 전환만
VD-04 06 전 form engine 복합 form이면 RHF+Zod facade, 아니면 local/native form 구현체
VD-05 07 전 icon/headless UI local facade, native 우선; 미지원 behavior는 미완료 icon/복합 primitive
VD-06 08 전 i18n engine Intl + typed local catalog extraction/plural 고급 기능
VD-07 09 전 diagnostics/telemetry exporter no-op/best-effort HTTP production sink만
VD-08 10 전 Storybook/visual 방식 dev-only Storybook + local Playwright baseline cloud review/별도 배포
VD-09 11 전 vulnerability/license/SBOM/provenance 임의 PASS 금지, FAIL_UNVERIFIED release promotion
VD-10 12 전 optional capability 요구 설치하지 않음 해당 recipe만
VD-23 API-01 전 protocol 선택과 REST execution operation별 protocol 고정, installed REST 유지 REST v2 hardening
VD-24 API-02 전 runtime Schema와 Mapper proof typed codec → pure Result mapper multi-protocol contract/codegen
VD-25 API-03 전 Server State Cache lifecycle TanStack sole owner, bound query/mutation profile query/cache/mutation hardening
VD-26 API-04 전 GraphQL persisted operation only, 기본 미선택 GraphQL operation family
VD-27 API-05 전 gRPC-Web unary/server-stream만, 기본 미선택 gRPC-Web operation family
VD-29 API-06 전 Connect-Web/Connect exact runtime/wire profile, 기본 미선택 Connect operation family
VD-30 API-07 전 Protobuf/REST Gateway current REST는 BFF 유지, direct gateway 기본 미선택 schema/codegen/gateway branch
VD-28 RT-01 전 realtime/Web Push/Polling focus refetch 우선, transport별 opt-in과 bounded fallback realtime delivery capability

각 decision에는 실제 요구, bundle/runtime/a11y/security 영향, local facade 방식, 대안, fallback/migration/removal, owner와 재검토 시점을 기록한다.

결정이 지연될 때 vendor-neutral port와 no-op/fake/unavailable adapter를 먼저 완성한다. 다만 vendor가 있어야 충족되는 behavior를 구현하지 않은 채 완료로 표시해서는 안 된다.

12. Rollback과 promotion

checkpoint 포함 범위 다음 단계 진입 조건 대표 rollback 사유
RP-01 tooling TS/TSX fixture와 gate 통과 TS 파일이 검사에서 누락
RP-02 application boundary composition integration 통과 UI가 raw adapter에 의존
RP-03 HTTP/query request/state negative matrix 통과 query 손실, retry/submit 폭주
RP-04 routing/recovery registry와 reload-loop drill 통과 invalid URL API 호출, reload loop
RP-05 P0 reference feature 존재/제거 gate 통과 hidden sample coupling
RP-06 form/page form/page/a11y gate 통과 입력 손실, template 결합
RP-07 design system token/interaction gate 통과 focus/theme/vendor 회귀
RP-08 i18n catalog/pseudo/RTL gate 통과 missing key, locale 회귀
RP-09 diagnostics producer/redaction gate 통과 PII 노출, event 폭주
RP-10 test/registry actual diff와 evidence gate 통과 false PASS, flaky blocker
RP-11 P1 supply chain LOCAL_TEMPLATE_READY 위험 dependency/검증 공백
RP-12 optional recipe recipe별 opt-in gate vendor 격리 실패
RP-05 + P0 exit
  = LOCAL_CORE_READY

RP-11 + P1 exit
  = LOCAL_TEMPLATE_READY

LOCAL_TEMPLATE_READY
  + 실제 hosting/IdP/보안/접근성/운영 증거
  = PROJECT_INTEGRATION_READY

PROJECT_INTEGRATION_READY
  + production promotion과 eligible field data
  = PRODUCTION/FIELD READY

저장소 내부와 외부 증거를 하나의 백분율로 숨기지 않는다. P0/P1의 모든 acceptance가 자동 검증되고 외부 항목이 명확히 분리된 LOCAL_TEMPLATE_READY를 높은 저장소 내부 준비도의 실질 기준으로 사용한다.

13. 브랜치 공통 인수 체크리스트

각 feature branch는 병합 전에 다음을 evidence에 남긴다.

  • 목표와 변경하지 않는 범위
  • 시작한 develop SHA와 선행 merge SHA
  • 변경한 public contract, registry와 compatibility 영향
  • positive/negative fixture
  • 실행한 typecheck, lint, architecture, unit, integration, E2E와 build 명령
  • artifact와 browser/runtime 환경
  • dependency/lockfile 변경 및 vendor decision ID
  • fake/no-op/unavailable adapter로 검증한 범위
  • external blocker와 FAIL_UNVERIFIED promotion
  • merge commit과 보존된 local/origin feature tip
  • rollback 대상 merge와 복구 확인 gate

acceptance를 만족하지 못한 브랜치는 후속 브랜치의 기반으로 사용하지 않는다. test를 skip하거나 문서상 예외로 바꾸는 것은 완료가 아니다.