157 lines
8.6 KiB
Markdown
157 lines
8.6 KiB
Markdown
# Optional frontend adapter recipes
|
|
|
|
이 문서는 도메인과 무관한 선택형 frontend capability를 실제 프로젝트에
|
|
도입하는 실행 가이드다. 기본 스켈레톤에는 vendor runtime을 설치하지 않는다.
|
|
`RECIPE_AVAILABLE`은 계약·fake·failure policy가 준비됐다는 뜻이며 실제 provider,
|
|
runtime behavior 또는 production readiness를 뜻하지 않는다.
|
|
|
|
## 1. 현재 상태와 파일 지도
|
|
|
|
| 항목 | 경로 | production 포함 |
|
|
| --- | --- | --- |
|
|
| 선택/금지/예산 SSOT | `config/recipes/frontend-capability-recipes.json` | 정책만 |
|
|
| catalog JSON schema | `schemas/config/frontend-capability-recipes.schema.json` | 아니오 |
|
|
| TypeScript port | `recipes/frontend-capabilities/contracts.ts` | 아니오 |
|
|
| fake/unavailable | `recipes/frontend-capabilities/fake-adapters.ts` | 아니오 |
|
|
| contract test | `tests/recipes/optional-capability-contracts.test.ts` | 아니오 |
|
|
| 정적/번들 gate | `scripts/check-optional-recipes.mjs` | build 도구 |
|
|
| negative fixture | `scripts/check-optional-recipe-fixtures.mjs` | 아니오 |
|
|
| 완전 제거 gate | `scripts/test-optional-recipe-removal.mjs` | 아니오 |
|
|
|
|
현재 `productionRuntimeDependencies`는 빈 배열이며 12개 recipe 모두 선택되지
|
|
않았다. TypeScript example은 product source가 import할 library가 아니라 선택
|
|
시 복사하고 좁힐 출발점이다.
|
|
|
|
## 2. 어느 경계에 두는가
|
|
|
|
| capability 성격 | port 소유자 | adapter 방향 | concrete 위치 예 |
|
|
| --- | --- | --- | --- |
|
|
| application이 외부 결과를 요청 | application | outbound | `src/adapters/<capability>` |
|
|
| URL/browser event가 의도를 전달 | application input | inbound | `src/presentation/adapters` |
|
|
| React rendering behavior만 교체 | presentation | local facade | `src/presentation/<capability>` |
|
|
| feature 전용 protocol | feature application | in/out 분리 | `src/features/<name>/adapters` |
|
|
|
|
WebSocket 연결 생성, reconnect와 credential attachment는 outbound다. 수신 JSON
|
|
검증과 application input 호출은 inbound다. Service Worker update event,
|
|
BroadcastChannel event도 같은 원칙을 적용한다. generated DTO와 vendor SDK
|
|
type은 facade 밖으로 노출하지 않는다.
|
|
|
|
## 3. 12개 recipe 선택표
|
|
|
|
| recipe | 설치하는 경우 | 설치하면 안 되는 경우 | 핵심 fallback |
|
|
| --- | --- | --- | --- |
|
|
| realtime | ordered push/resume protocol이 확정됨 | polling이 충분하거나 ordering owner 없음 | bounded polling/stale UI |
|
|
| offline/IndexedDB | durable offline data/queue가 제품 요구 | credential 저장, DB 직접 연결, HTTP cache로 충분 | online-only + offline state |
|
|
| Service Worker/PWA | install/offline shell과 cache owner 승인 | update/rollback UX 없음 | hosting cache 기반 network app |
|
|
| file transfer | progress/cancel/size/type 정책 필요 | long-lived credential URL | bounded normal request |
|
|
| generated API | versioned source와 drift CI가 있음 | DTO가 domain/UI로 노출됨 | typed request builder + schema |
|
|
| feature flag | rollout/kill switch owner와 default 있음 | authorization에 사용 | typed local default |
|
|
| Web Worker | profiler가 main-thread 병목을 증명 | 단순 network I/O | chunked/deferred execution |
|
|
| multi-tab | 비민감 event 동기화가 필요 | server가 conflict authority | focus 시 authoritative refresh |
|
|
| browser permission | user gesture 기반 기능 필요 | boot 요청, denied UX 없음 | manual input/instruction |
|
|
| client workflow | cross-page client-only state가 실재 | query/server state 복제 | URL/local/context/query |
|
|
| large data UI | 실측 scale이 budget 초과 | pagination으로 충분, a11y 미정 | accessible pagination |
|
|
| analytics/error sink | provider·consent·retention 승인 | arbitrary payload/redaction 우회 | bounded local diagnostics |
|
|
|
|
정확한 failure matrix, security/privacy, gzip budget과 제거 순서는 JSON catalog가
|
|
SSOT다. 문서와 catalog가 다르면 gate가 검사하는 catalog를 우선 고치고 이 표도
|
|
같이 갱신한다.
|
|
|
|
## 4. 공통 구현 순서
|
|
|
|
1. 문제를 vendor 이름이 아닌 capability와 측정값으로 기록한다.
|
|
2. catalog의 trigger와 forbidden 조건을 모두 검토한다.
|
|
3. project owner, security/privacy reviewer, gzip budget과 재검토 날짜를 VD-10
|
|
amendment에 기록한다.
|
|
4. existing URL/local/context/query/application port로 해결되지 않는지 확인한다.
|
|
5. 필요한 contract만 `recipes`에서 해당 application/presentation 경계로 복사해
|
|
실제 payload와 failure union으로 좁힌다.
|
|
6. concrete SDK는 `src/adapters/...` 또는 local presentation facade adapter에서만
|
|
import한다.
|
|
7. composition root가 concrete adapter를 주입한다. page/use case가 constructor를
|
|
직접 호출하지 않는다.
|
|
8. fake, unavailable, timeout/cancel, cleanup, malformed input, redaction과
|
|
integration test를 작성한다.
|
|
9. runtime config schema, dependency inventory/approval, SBOM, bundle budget,
|
|
browser support와 runbook을 갱신한다.
|
|
10. 실제 provider integration과 negative behavior가 통과한 뒤에만 catalog 상태를
|
|
별도 project catalog에서 `INSTALLED`로 바꾼다.
|
|
|
|
## 5. capability별 필수 검증
|
|
|
|
### Realtime
|
|
|
|
- runtime schema로 envelope/version/event ID/sequence/timestamp를 검증한다.
|
|
- reconnect는 exponential backoff 상한, visibility/offline 상태, auth refresh와
|
|
resume token expiry를 정의한다.
|
|
- duplicate/out-of-order는 domain use case에 전달하기 전에 정책화한다.
|
|
- route unmount/logout에서 unsubscribe하고 heartbeat timer를 종료한다.
|
|
|
|
### Offline/Service Worker
|
|
|
|
- store/cache 이름과 schema는 release와 독립적인 migration version을 가진다.
|
|
- quota, corrupt row, partial migration, downgrade/rollback을 fixture로 만든다.
|
|
- authenticated response와 credential은 기본 cache 대상이 아니다.
|
|
- stale worker loop를 막고 unregister 후 owned cache 삭제가 가능한지 검증한다.
|
|
|
|
### File/generated API
|
|
|
|
- upload는 client MIME을 신뢰하지 않고 size/type/server rejection을 모두 다룬다.
|
|
- progress는 unknown total을 허용하며 navigation/unmount에서 AbortSignal로
|
|
취소한다.
|
|
- generated code는 facade 뒤 DTO이며 runtime response schema와 contract drift
|
|
gate를 유지한다.
|
|
|
|
### Flag/worker/multi-tab/browser
|
|
|
|
- flag unknown/unavailable/stale에서 명시적 typed fallback을 사용하고 access
|
|
control로 사용하지 않는다.
|
|
- worker는 task ID/generation/cancel을 사용해 stale result를 폐기하고 crash를
|
|
normalized failure로 바꾼다.
|
|
- multi-tab은 source/event/version으로 self-echo와 duplicate를 막고 payload를
|
|
비민감 invalidation hint로 제한한다.
|
|
- browser permission은 user gesture에서만 요청하고 denied/dismissed/unsupported를
|
|
서로 다른 UX 결과로 처리한다.
|
|
|
|
### Client workflow/large data/analytics
|
|
|
|
- workflow store는 server entity/collection을 복제하지 않고 query key나 ID 참조만
|
|
보관한다. logout/reset/version mismatch 정책을 테스트한다.
|
|
- virtualization은 profiler와 production-like row count로 정당화하며 keyboard,
|
|
focus restoration, screen reader와 stale row identity를 검증한다.
|
|
- analytics는 essential diagnostics와 consent-required event를 분리하고 closed
|
|
event/attribute registry, pre-queue redaction, sampling, bounded queue와
|
|
retention을 적용한다.
|
|
|
|
## 6. 검증 명령
|
|
|
|
```bash
|
|
corepack pnpm check:types:recipes
|
|
corepack pnpm test:recipes
|
|
corepack pnpm build
|
|
corepack pnpm check:optional-recipes
|
|
corepack pnpm check:optional-recipe-fixtures
|
|
corepack pnpm test:optional-recipe-removal
|
|
```
|
|
|
|
negative gate는 cleanup 누락, unselected dependency, local adapter 밖 vendor
|
|
import, credential localStorage/URL/telemetry 경로, workflow store의 server-state
|
|
복제와 production source의 recipe import를 거절한다. removal gate는 recipe와
|
|
recipe test를 삭제한 임시 사본에서 base typecheck, architecture, test와 build를
|
|
실행한다.
|
|
|
|
## 7. 제거 체크리스트
|
|
|
|
1. 신규 호출과 background 작업을 중지한다.
|
|
2. subscription, worker, channel, media track, observer를 cleanup한다.
|
|
3. persisted store/cache/event queue의 migrate 또는 purge 정책을 실행한다.
|
|
4. composition registration과 runtime config를 제거한다.
|
|
5. concrete adapter, facade/port와 vendor dependency를 제거한다.
|
|
6. dependency baseline, SBOM과 bundle baseline을 갱신한다.
|
|
7. typecheck/test/build, production bundle absence와 도메인 기능 fallback을
|
|
검증한다.
|
|
|
|
provider 장애 시 fake로 바꾸어 production을 PASS 처리하지 않는다. 문서화된
|
|
unavailable fallback만 사용하고 provider가 필수인 promotion은
|
|
`FAIL_UNVERIFIED` 또는 blocked 상태로 유지한다.
|