feat: harden test and registry evidence
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
# VD-08: 개발용 Storybook과 로컬 시각 회귀 증적
|
||||
|
||||
- 상태: Accepted
|
||||
- 결정일: 2026-07-26
|
||||
- 적용 브랜치: `feature-frontend-test-registry-evidence-hardening`
|
||||
- 재검토: 제품이 cloud visual review, 다중 OS baseline 또는 별도 디자인 시스템
|
||||
배포를 요구할 때
|
||||
|
||||
## 배경
|
||||
|
||||
`/examples/ui`와 `/examples/states`는 실제 application composition 안에서 공통
|
||||
UI와 상태 표면을 보여 주지만, primitive를 격리해 interaction과 접근성을 검증하는
|
||||
workshop은 아니었다. 실패 시 screenshot도 디버깅 증거일 뿐 의도된 UI 기준선과
|
||||
현재 렌더의 차이를 차단하지 못했다.
|
||||
|
||||
외부 visual review 서비스, 별도 Storybook 배포와 브랜드별 baseline은 아직
|
||||
선정되지 않았다. 이 결정을 기다리며 UI 회귀 검증을 비워 두거나 production
|
||||
application bundle에 workshop runtime을 포함하는 것 모두 적절하지 않다.
|
||||
|
||||
## 결정
|
||||
|
||||
1. Storybook은 development dependency와 별도 static artifact로만 사용한다.
|
||||
production entry와 application `dist`에는 Storybook runtime, story 또는
|
||||
테스트 selector를 포함하지 않는다.
|
||||
2. story는 public design-system entry를 소비하고 실제 locale, theme, session,
|
||||
router와 query provider 계약으로 렌더한다. production component를 복제한
|
||||
story 전용 구현을 만들지 않는다.
|
||||
3. interaction과 story-level axe는 Playwright가 정적 Storybook을 대상으로
|
||||
실행한다. unexpected console, page error와 request failure는 테스트 실패다.
|
||||
4. 시각 회귀는 production `build` 후 `preview`를 대상으로 pinned Chromium,
|
||||
locale, color scheme과 viewport에서 `toHaveScreenshot()`으로 실행한다.
|
||||
5. 최초 기준선은 wide shell, compact pseudo-locale drawer, dark design-system
|
||||
gallery, loading/empty/error/access 상태 표면을 포함한다.
|
||||
6. animation과 caret만 결정적으로 비활성화한다. `html`, `body`, `main` 또는
|
||||
application 전체를 mask해 false PASS를 만드는 설정은 gate가 거절한다.
|
||||
7. snapshot 갱신은 `test:visual:update`라는 명시적 명령으로 분리하고 PNG diff를
|
||||
review한다. 일반 `test:visual`은 승인 기준선을 변경하지 않는다.
|
||||
8. local visual threshold는 작은 rasterization 차이만 허용하며 실제 layout,
|
||||
copy, theme 또는 상태 변화가 숨겨지도록 확대하지 않는다.
|
||||
9. `/examples/*`는 production composition smoke로 유지하고 Storybook story의
|
||||
대체물로 취급하지 않는다. 반대로 Storybook만 통과해 application shell
|
||||
integration을 완료 처리하지 않는다.
|
||||
10. cloud service가 선정되지 않아도 repository-local workshop, interaction,
|
||||
a11y와 visual baseline gate는 완전하게 실행 가능해야 한다.
|
||||
|
||||
## 실행과 증적
|
||||
|
||||
- workshop config: `.storybook/main.ts`, `.storybook/preview.tsx`
|
||||
- story: `src/presentation/design-system/design-system.stories.tsx`
|
||||
- interaction/a11y: `tests/storybook/workshop.spec.ts`
|
||||
- visual: `tests/visual/platform.visual.spec.ts`
|
||||
- baseline: `tests/visual/__snapshots__/`
|
||||
- production E2E: `playwright.config.js`
|
||||
- local dev E2E: `playwright.dev.config.js`
|
||||
- evidence policy: `scripts/check-test-evidence.mjs`
|
||||
|
||||
CI는 JUnit, HTML report, failure trace/screenshot, visual baseline 존재 여부와
|
||||
금지된 full-screen mask/무소유 skip fixture를 함께 검사한다.
|
||||
|
||||
## 한계와 재검토 조건
|
||||
|
||||
로컬 기준선은 실제 iOS/Android 기기, 여러 운영체제의 font rasterization,
|
||||
디자인 승인 workflow와 다중 브랜드를 증명하지 않는다. 이를 요구하면 동일
|
||||
public component와 story를 입력으로 사용하는 외부 review adapter를 추가하되,
|
||||
provider 결과가 없을 때 임의 PASS로 대체하지 않는다.
|
||||
|
||||
## Rollback
|
||||
|
||||
Storybook dependency/config, workshop test와 visual config/baseline은 production
|
||||
runtime 변경 없이 독립적으로 제거할 수 있다. rollback 후에도 `/examples/*`,
|
||||
component behavior, automated accessibility와 built-dist E2E는 유지한다.
|
||||
@@ -12,7 +12,7 @@
|
||||
- 기본 번들에 포함할 역량과 필요할 때 설치할 확장 역량을 구분한다.
|
||||
- 특정 벤더를 채택하더라도 제품 코드가 벤더 API에 직접 결합되지 않는지 확인한다.
|
||||
|
||||
최초 검토 기준은 `develop`의 `cb195f8`이며, RP-01~RP-08 구현 결과를 이 문서에
|
||||
최초 검토 기준은 `develop`의 `cb195f8`이며, RP-01~RP-10 구현 결과를 이 문서에
|
||||
누적 반영했다. 이후 구현으로 경로나 세부 내용이 달라질 수 있으므로, 각 항목은
|
||||
문서의 경로뿐 아니라 해당 테스트와 아키텍처 게이트로 계속 검증해야 한다.
|
||||
|
||||
@@ -39,15 +39,16 @@ recovery 계약, 제거 가능한 reference 수직 슬라이스, form/page, desi
|
||||
i18n 실행 경계와 diagnostics/telemetry production wiring은 구현됐다. 현재 선행 해결
|
||||
대상은 다음과 같다.
|
||||
|
||||
1. registry evidence와 실제 compatibility diff
|
||||
2. 공급망과 optional adapter recipe 심화 게이트
|
||||
1. 공급망의 transitive inventory/license/vulnerability/SBOM/provenance 검증
|
||||
2. optional adapter의 opt-in 경계와 제거 가능한 recipe
|
||||
|
||||
따라서 현재 상태를 “프론트 공통부가 모두 구현됐다”고 표현하면 범위가 과장된다.
|
||||
더 정확한 표현은 다음과 같다.
|
||||
|
||||
> 운영·안전 계약과 범용 앱 셸은 갖춰졌지만, 기능 개발자가 사용하는 application
|
||||
> API, 서버 상태, 폼, 라우팅, 페이지 패턴의 표준 수직 경로는 아직 보강이
|
||||
> 필요하다.
|
||||
> application API, 서버 상태, 폼, 라우팅, 페이지, 디자인 시스템과 테스트 증적의
|
||||
> 표준 수직 경로는 갖춰졌다. 현재 남은 저장소 내부 범위는 공급망 검증과
|
||||
> opt-in adapter recipe이며 실제 hosting·IdP·운영 provider는 프로젝트 통합
|
||||
> 범위다.
|
||||
|
||||
## 3. 판정 기준
|
||||
|
||||
@@ -77,17 +78,17 @@ i18n 실행 경계와 diagnostics/telemetry production wiring은 구현됐다.
|
||||
| 앱 셸·반응형 | 준비됨 | native modal Drawer, compact/desktop layout, Escape/link dismiss/focus restore, pseudo reflow와 RTL direction | compact browser matrix 유지 |
|
||||
| 페이지 템플릿 | 준비됨 | Standard/Collection/Detail/Form/Status와 public design-system entry | feature별 slot 조합 유지 |
|
||||
| 디자인 토큰 | 준비됨 | primitive/semantic/component CSS, 48-token 자동 계약, dark/forced-colors/reduced-motion | 제품 brand token은 외부 프로젝트에서 확장 |
|
||||
| 공통 UI | 준비됨 | action/form/feedback/overlay/navigation primitive와 pattern, compatibility export | Storybook/visual은 RP-10 |
|
||||
| 공통 UI | 준비됨 | action/form/feedback/overlay/navigation primitive와 pattern, compatibility export | public story와 visual state matrix 유지 |
|
||||
| 아이콘 | 준비됨 | Lucide static vendor facade와 semantic icon/IconButton 접근성 계약 | 의미 icon 추가 시 bundle/접근성 기준 적용 |
|
||||
| 폼 | 준비됨 | Zod 기반 local facade, error summary/focus, 422 allowlist, dirty/pending/conflict 정책 | 복합 form 요구가 생기면 VD-04 조건으로 vendor adapter 평가 |
|
||||
| 국제화 | 준비됨 | 137-key typed catalog, locale provider, Intl formatter, safe fallback/alias, pseudo·RTL gate | 실제 locale·번역 승인은 프로젝트에서 연결 |
|
||||
| logging/diagnostics | 준비됨 | 별도 `DiagnosticsPort`, 8-event registry, allowlist, bounded/no-op adapter와 production producer | 실제 프로젝트의 remote sink는 port 뒤에서 선택 |
|
||||
| telemetry | 준비됨/프로젝트 선택 | 5-event registry, bounded queue, redaction/value policy, boot·HTTP·render·release·drop producer | analytics/RUM/error vendor와 consent는 프로젝트에서 선택 |
|
||||
| 비동기 상태 불변식 | 준비됨 | 배타적 typed overlay, stale latch, 실제 retry/conflict action | reference 화면에서 전체 상태 전시 |
|
||||
| 단위·통합·E2E | 준비됨 | Vitest, RTL, MSW, Playwright 3엔진 | TS 테스트 검사, 실제 bootstrap 통합, 위험 시나리오 보강 |
|
||||
| UI 회귀 검증 | 미제공 | axe/reflow는 있으나 visual baseline 없음 | Storybook 또는 동급 workshop과 시각 회귀 |
|
||||
| 샘플 제거 | 준비됨 | feature/catalog/test 제거 후 type/architecture/registry/test/home/build 8단계 검증 | 새 contribution도 같은 제거 gate에 포함 |
|
||||
| registry·compatibility 집행 | 부분 준비 | registry와 gate는 있으나 실제 before/after 및 orphan 검사가 제한적 | type/reference/orphan/diff/migration을 자동 검증 |
|
||||
| 단위·통합·E2E | 준비됨 | source/test strict typecheck, shared MSW 19개 scenario, 실제 bootstrap, built-dist 3엔진·compact E2E | 제품별 critical flow를 같은 catalog/gate에 추가 |
|
||||
| UI 회귀 검증 | 준비됨 | dev-only Storybook interaction/axe와 pinned Chromium visual baseline 4종 | cloud review와 다중 OS/device는 프로젝트 선택 |
|
||||
| 샘플 제거 | 준비됨 | feature/catalog/test 제거 후 type/architecture/registry/test/home/build 9단계 검증 | 새 contribution도 같은 제거 gate에 포함 |
|
||||
| registry·compatibility 집행 | 준비됨 | 10개 registry type/reference/consumer/orphan, 승인 digest와 actual semantic diff, breaking evidence | public 계약 변경 시 baseline review 유지 |
|
||||
| 공급망 검사 | 부분 준비 | lockfile·문서·gate는 있으나 실제 transitive 취약점/license/SBOM 깊이가 부족 | pinned scanner와 policy exception/증적 연결 |
|
||||
| realtime·offline·file 등 | 프로젝트 선택 | 현재 없음 | port/adapter recipe와 선택 기준 제공 |
|
||||
|
||||
|
||||
@@ -808,6 +808,35 @@ RP-10은 직전 승인 registry snapshot과 test evidence다. flaky visual/brows
|
||||
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.js`로 분리했다.
|
||||
- Storybook public primitive story, interaction과 axe test, wide/compact/
|
||||
pseudo/dark/state surface의 pinned Chromium visual baseline 4종을 CI evidence로
|
||||
연결했다.
|
||||
- V8 coverage와 9개 high-risk module을 대상으로 40개 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`
|
||||
|
||||
**목표**
|
||||
|
||||
@@ -43,7 +43,12 @@
|
||||
- `test:unit`
|
||||
- `test:component`
|
||||
- `test:integration`
|
||||
- `test:coverage`
|
||||
- `test:e2e`
|
||||
- `test:e2e:dev`
|
||||
- `build:storybook`
|
||||
- `test:storybook`
|
||||
- `test:visual`
|
||||
- `test:a11y`
|
||||
- `review:a11y-manual`
|
||||
- `test:sample-removal`
|
||||
@@ -67,7 +72,7 @@ field/documentation 단계를 구성한다.
|
||||
- 320px reflow와 mobile navigation을 E2E로 확인한다.
|
||||
- release build의 bundle과 lab performance budget이 별도 gate다.
|
||||
|
||||
### 2.3 확인된 공백
|
||||
### 2.3 RP-10에서 닫힌 공백과 남은 외부 범위
|
||||
|
||||
#### 테스트 TypeScript typecheck 기반
|
||||
|
||||
@@ -76,20 +81,12 @@ field/documentation 단계를 구성한다.
|
||||
검사하되 실패를 의도한 `tests/fixtures`는 별도 negative command가 소유한다.
|
||||
Vitest의 변환 성공을 TypeScript typecheck의 대체물로 취급하지 않는다.
|
||||
|
||||
#### 실제 bootstrap integration test가 없다
|
||||
#### 실제 bootstrap integration
|
||||
|
||||
`tests/component/bootstrap-shell.test.jsx`는 production bootstrap을 import하지
|
||||
않고 테스트 내부의 `<TestShell>`만 렌더링한다. E2E는 실제 entry를 통과하지만,
|
||||
다음 실패를 작은 통합 테스트에서 식별하기 어렵다.
|
||||
|
||||
- runtime config fetch 실패
|
||||
- config/manifest mismatch
|
||||
- adapter composition 실패
|
||||
- provider 순서 또는 누락
|
||||
- external auth owner 유무
|
||||
- product tree를 마운트하기 전 fail-closed
|
||||
- boot error shell의 safe metadata
|
||||
- StrictMode와 unmount cleanup
|
||||
runtime config와 release manifest를 검증한 composition root에서 실제 provider
|
||||
순서와 application input을 연결하는 component/integration test를 제공한다.
|
||||
production Playwright profile은 source fixture가 아니라 `build` + `preview`의
|
||||
실제 entry와 hashed route chunk를 사용한다.
|
||||
|
||||
#### TanStack Query의 React integration test 기반
|
||||
|
||||
@@ -100,53 +97,44 @@ optimistic commit/rollback, conflict 해제와 namespace invalidation이 실제
|
||||
QueryClient 위에서 실행된다. HTTP 자동 retry가 소유자이므로 이 adapter의
|
||||
query/mutation vendor retry는 꺼져 있다.
|
||||
|
||||
#### Form 테스트가 단일 TextField 흐름에 머문다
|
||||
#### Form과 route 위험
|
||||
|
||||
현재 component/E2E는 label, description, error association과 빈 값 submit을
|
||||
검사한다. error summary, 첫 오류 focus, async validation race, 422 field error,
|
||||
double submit, dirty navigation, mutation conflict는 없다.
|
||||
form component/reference feature test가 error summary, 첫 오류 focus, Zod
|
||||
transform, 422 allowlist, double submit, dirty navigation, optimistic rollback과
|
||||
conflict를 검증한다. route registry/runtime 양방향 참조, codec, lazy module,
|
||||
location reset, scroll restoration, blocker와 bounded chunk recovery도
|
||||
unit/component/built artifact 검증에 연결됐다.
|
||||
|
||||
#### Route registry와 실행 tree가 별도로 테스트된다
|
||||
#### Storybook과 시각 회귀
|
||||
|
||||
registry snapshot과 일부 navigation/access policy test는 있으나 다음 계약을
|
||||
강제하지 않는다.
|
||||
public design-system primitive를 실제 platform provider로 렌더하는 dev-only
|
||||
Storybook, interaction/axe test와 production build를 대상으로 한
|
||||
`toHaveScreenshot()` baseline 4종을 제공한다. cloud review, 다중 OS font
|
||||
rasterization과 실제 device farm은 프로젝트가 요구할 때 연결한다.
|
||||
|
||||
- 모든 route ID에 lazy runtime module이 존재하는가
|
||||
- params/search가 실제 codec으로 검증되는가
|
||||
- deep link와 basename refresh가 동작하는가
|
||||
- chunk load failure가 1회 reload/support surface로 연결되는가
|
||||
- route error boundary가 location 변경 시 reset되는가
|
||||
- scroll restoration과 form navigation blocker가 동작하는가
|
||||
#### Shared MSW와 결정성
|
||||
|
||||
#### Storybook과 시각 회귀가 없다
|
||||
operation별 success/empty/slow/network/timeout/content/envelope/schema/auth/
|
||||
403/404/409/422/429/retry/terminal을 포함한 19개 scenario catalog와 strict
|
||||
unhandled-request server를 공유한다. clock/random/scheduler/storage helper와
|
||||
browser console/page/network failure 정책으로 비결정적 우회를 차단한다.
|
||||
|
||||
`/examples/ui`는 통합 gallery지만 component별 모든 state를 격리하지 않는다.
|
||||
Storybook story, interaction story, story-level axe, `toHaveScreenshot()` baseline이
|
||||
없다. `screenshot: "only-on-failure"`는 디버깅 증거이며 시각 회귀 테스트가 아니다.
|
||||
#### Built-dist와 compact E2E
|
||||
|
||||
#### MSW scenario가 공유되지 않는다
|
||||
기본 `test:e2e`는 CI에서 기존 server를 재사용하지 않고 `build` + `preview`를
|
||||
Chromium, Firefox, WebKit과 compact project로 실행한다. 빠른 Vite 개발 profile은
|
||||
`test:e2e:dev`로 분리한다.
|
||||
|
||||
integration file마다 `setupServer`, handler, response body를 다시 정의한다.
|
||||
Node integration, Storybook browser, feature component test, E2E mock service가 같은
|
||||
시나리오 이름과 contract fixture를 공유하지 않는다.
|
||||
#### 위험 기반 coverage
|
||||
|
||||
#### E2E가 개발 서버를 대상으로 한다
|
||||
V8 text/JSON/LCOV를 생성하고 전체 기준과 retry/storage/telemetry/compatibility/
|
||||
performance/promotion/chunk/diagnostics/registry compatibility 9개 high-risk
|
||||
module에 40개 scoped threshold를 적용한다. critical module 누락 또는 threshold
|
||||
미달 fixture는 merge gate를 실패시킨다.
|
||||
|
||||
현재 Playwright web server는 `pnpm dev`다. route behavior 확인에는 유효하지만
|
||||
다음 release 위험은 production build/preview에서만 확인할 수 있다.
|
||||
|
||||
- hashed lazy chunk
|
||||
- source 변환과 tree shaking
|
||||
- base path
|
||||
- deep-link fallback
|
||||
- build-time environment
|
||||
- release manifest와 runtime config 조합
|
||||
- minified code의 chunk failure
|
||||
|
||||
#### Coverage가 실행·차단되지 않는다
|
||||
|
||||
`vitest.config.js`에는 reporter만 선언되어 있고 coverage provider, script,
|
||||
threshold, diff policy가 없다.
|
||||
남은 범위는 실제 device/browser farm, cloud visual approval, 외부 인증·telemetry
|
||||
provider와 production field data다. 이 증거가 없을 때 저장소 내부 test를
|
||||
`PRODUCTION_READY`의 대체물로 사용하지 않는다.
|
||||
|
||||
## 3. 위험 기반 테스트 계층
|
||||
|
||||
@@ -1228,8 +1216,9 @@ corepack pnpm build
|
||||
corepack pnpm check:bundle
|
||||
```
|
||||
|
||||
TypeScript test, Storybook, coverage, visual, built-dist 명령이 도입되면 위 목록과
|
||||
CI registry에 추가한다.
|
||||
TypeScript test, Storybook, coverage, visual과 built-dist 명령은
|
||||
`config/ci/gates.json`의 blocking step과 JUnit/HTML/trace/fixture evidence에
|
||||
연결되어 있다.
|
||||
|
||||
## 18. Feature Definition of Done
|
||||
|
||||
|
||||
Reference in New Issue
Block a user