Files
clean-architecture-frontend…/docs/architecture/decisions/VD-16-browser-transfer-composition-and-image-delivery.md

26 KiB

VD-16: Browser transfer composition과 Image delivery

  • 상태: Accepted — design complete, implementation pending
  • 결정일: 2026-07-28
  • 이 ADR이 선택한 common delta의 current status: DESIGNED_NOT_IMPLEMENTED
  • common delta의 목표 reference status: AVAILABLE_NOT_COMPOSED
  • 관련 결정: VD-10, VD-11, VD-12, VD-13, VD-14, VD-15
  • current status ledger: docs/architecture/browser-data-capability-completion-ledger.md
  • 재검토: 첫 product upload/download/Image CDN capability를 조합하기 전

배경

현재 저장소에는 File runtime, presigned capability provider/vault/executor, multipart/resumable upload, one-shot streaming download와 Image CDN verification runtime의 개별 factory가 있다. 이 구현들은 production bootstrap에서 제거돼 있고 각각의 local close() 또는 dispose()만 제공한다.

제품에서 이들을 직접 조합하면 다음 문제가 생긴다.

  • account/session이 바뀌어도 이전 capability, checkpoint, refresh 또는 async completion이 살아남을 수 있다.
  • 서로 다른 config가 같은 byte/resource/preset을 다르게 해석할 수 있다.
  • 일부 provider만 생성된 partial runtime이 요청을 받기 시작할 수 있다.
  • upload, download와 image에 retry, kill switch, deadline과 observation owner가 중복될 수 있다.
  • Image engine은 이미 decode된 server descriptor를 받으므로 BFF transport, expiry refresh와 presentation handoff의 책임이 비어 있다.
  • 실제 provider가 frontend mock과 같은 계약을 지키는지 재사용 가능한 conformance harness가 없다.

이 결정은 도메인별 upload 화면이나 cloud vendor를 공통 플랫폼에 넣지 않는다. 선택된 capability를 안전하게 조립·폐기하는 composition protocol과 Image descriptor acquisition 경계를 정한다.

현재 상태

항목 상태 설명
개별 presigned/upload/image runtime AVAILABLE_NOT_COMPOSED factory와 deterministic test가 있으나 제품 graph에는 없음
one-shot streaming download AVAILABLE_NOT_COMPOSED Range resume가 아닌 전체 객체 스트림
top-level transfer runtime DESIGNED_NOT_IMPLEMENTED export index만 있고 atomic factory/readiness/lifecycle 없음
Image descriptor HTTP provider DESIGNED_NOT_IMPLEMENTED caller가 BackendIssuedImageAsset을 직접 전달
safe image DOM projection DESIGNED_NOT_IMPLEMENTED presentation descriptor는 있으나 renderer boundary 없음
app-managed background download NOT_SELECTED VD-14의 별도 optional capability
cross-browser background-download guarantee PLATFORM_LIMITED browser-managed handoff가 기본 fallback
app-managed background upload NOT_SELECTED durable source staging/worker auth protocol이 별도로 필요
cross-browser background-upload guarantee PLATFORM_LIMITED worker lifetime/local source permission을 공통 보장할 수 없음

이 ADR을 추가해도 위 상태는 자동으로 바뀌지 않는다. port, runtime, test와 removal evidence가 구현된 뒤에만 reference 상태를 올린다.

결정

1. 하나의 account-scoped composition owner

선택된 file/transfer/image capability는 BrowserTransferRuntimeComposition 역할의 단일 owner가 다음 순서로 생성한다.

parse immutable config
  -> validate implementation ceilings
  -> obtain immutable session/account scope
  -> create policy registries
  -> create provider transports
  -> create capability vaults
  -> create checkpoint/lock/channel owners
  -> create file/upload/download/image runtimes
  -> run required compatibility probes
  -> publish READY facade atomically

factory가 중간에 실패하면 생성된 owner를 역순으로 닫고 facade를 반환하지 않는다. partial runtime, degraded provider 또는 mutable config를 application에 노출하지 않는다.

composition은 다음 두 종류를 반환하는 union이어야 한다.

READY {
  generation,
  capabilities,
  application facades,
  readiness,
  close()
}

UNAVAILABLE {
  safe reason,
  retryability,
  fallback capability,
  disposePartial()
}

UNAVAILABLE에 provider URL, raw browser exception, account/tenant ID 또는 credential을 넣지 않는다.

2. Runtime config는 closed schema다

config는 composition root만 읽고 깊은 snapshot/freeze한다. 최소한 다음 registry-owned reference를 갖는다.

  • config schema version과 runtime compatibility version
  • opaque session/account scope와 generation
  • application origin과 fixed BFF endpoint IDs
  • exact PRESIGNED_TRANSFER_V1, PRESIGNED_MULTIPART_V1, RANGE_RESUMABLE_DOWNLOAD_V1, IMAGE_CDN_DESCRIPTOR_V1 중 선택한 protocol registry와 fixed endpoint map
  • upload purpose/profile, part/concurrency/retry/deadline hard ceiling
  • download profile, size/integrity/strategy와 Range capability selection
  • checkpoint namespace, retention, inventory와 maintenance budget
  • lock/cancel transport selection과 unsupported outcome
  • Image issuer/origin/preset/key/probe/decode policy
  • descriptor refresh lead time, request/decode deadline와 concurrency
  • capability별 traffic admission과 kill switch
  • observation sink와 redaction policy
  • active-operation drain deadline

caller는 raw endpoint, URL, header, object key, transform, retry count, byte ceiling, cache policy 또는 account partition을 request마다 override할 수 없다.

config는 구현 절대 상한을 높일 수 없다. 구현 상한보다 큰 값, 중복 registry ID, same-origin private Image CDN, 모순되는 fallback 또는 provider 누락은 startup에서 fail-closed한다.

3. Lifecycle state machine

top-level runtime은 다음 상태만 가진다.

CREATING
  -> PROBING
  -> READY
  -> DRAINING
  -> CLOSED

CREATING | PROBING
  -> FAILED
  -> CLOSED
  • READY만 새 operation을 받는다.
  • DRAINING은 새 operation을 거절하고 진행 중 operation에 bounded deadline을 제공한다.
  • deadline 뒤 남은 operation은 runtime lifetime signal로 abort한다.
  • close()는 terminal/idempotent이며 DRAINING/CLOSED에서 반복 호출해도 새 side effect를 만들지 않는다.
  • 닫힌 runtime은 reopen하지 않는다. 새 config/scope에는 새 generation을 만든다.
  • operation은 시작할 때 runtime generation과 account scope snapshot을 얻고 모든 async boundary와 terminal commit 전에 다시 확인한다.
  • 늦게 끝난 fetch, hash, IndexedDB transaction, image verification 또는 decode가 old generation이면 결과를 폐기하고 native resource를 닫는다.

4. Logout과 account/tenant switch

session owner notification이 authority다. BroadcastChannel, storage event, capability expiry 또는 page unload를 logout authority로 사용하지 않는다.

session owner announces local revoke
  -> traffic admission CLOSED
  -> runtime generation FENCED
  -> reject new operations
  -> signal active reads/fetch/backoff/probes
  -> bounded drain
  -> close capability and image vaults
  -> close cancel channels and release locks/connections
  -> apply checkpoint retention/purge policy with exact old scope
  -> dispose observations
  -> CLOSED
  -> construct new scope/runtime independently
  • old-scope purge와 new-scope open을 같은 transaction이나 facade에 섞지 않는다.
  • checkpoint가 crash 때문에 남아도 exact scope/policy binding이 다르면 새 runtime이 읽지 못해야 한다.
  • presigned URL, signed headers와 Image private URL은 어떤 teardown record에도 저장하지 않는다.
  • old account의 descriptor refresh, part completion과 download destination commit은 generation fence 뒤 성공으로 보고하지 않는다.
  • logout이 backend capability의 즉시 revoke를 보장하지 않는다. 강한 회수가 필요하면 BFF가 revoke authority 또는 proxy/relay를 제공해야 한다.

5. Capability별 facade

application에는 top-level runtime 자체나 native adapter를 반환하지 않는다. composition은 설치된 feature에 필요한 좁은 facade만 주입한다.

FeatureUploadFacade
  -> select local file profile
  -> create/resume/pause/abort approved purpose

FeatureDownloadFacade
  -> request approved resource
  -> receive policy-selected handoff/save outcome

FeatureImageFacade
  -> request opaque asset/preset
  -> receive safe presentation descriptor

feature는 File, Blob, Response, ReadableStream, FileSystemHandle, presigned URL, Image signature DTO, checkpoint store 또는 QueryClient를 받지 않는다. progress UI를 위한 observation도 bounded aggregate snapshot이며 transfer authority가 아니다.

Upload lifecycle integration

6. Pause와 abort는 다르다

top-level upload facade가 향후 제공할 상태는 다음과 같다.

ACTIVE
  -> PAUSE_REQUESTED
  -> PAUSED
  -> RESUMING
  -> ACTIVE

ACTIVE | PAUSED
  -> ABORT_REQUESTED
  -> ABORT_PENDING
  -> ABORTED

ACTIVE
  -> COMPLETING
  -> QUARANTINED
  • pause는 새 part와 retry를 중지하고 현재 bounded native operation을 abort한 뒤 non-authorizing checkpoint를 유지한다.
  • cross-context pause wire literal은 RESUMABLE_UPLOAD_PAUSE_V1이며 uploadKey, exact scope/generation과 bounded message metadata만 운반한다.
  • durable PAUSED를 추가하는 checkpoint는 schemaVersion: 2다. v1 ACTIVE | ABORT_PENDING reader/writer와 섞지 않고 old-writer drain, historical migration과 N-1 fail-closed를 증명한다.
  • abort는 server session authority와 reconcile한 뒤 terminal checkpoint를 제거한다.
  • pause signal은 authority가 아니라 best-effort same-scope hint다. 수신자는 exact upload key/scope/generation을 검증한다.
  • checkpoint inventory는 presigned URL이나 raw file path 없이 opaque upload key, safe state, age/byte/part bucket과 expiry만 반환한다.
  • inventory/list와 retention sweep은 count, cursor, deadline을 갖는다.
  • abandoned/expired checkpoint는 server status 또는 expiry policy와 CAS를 확인한 뒤 bounded batch로 제거한다.
  • file 재선택 뒤 source fingerprint/size/media/part layout이 exact하게 맞지 않으면 resume하지 않는다.

app-managed background upload는 이 state machine을 재사용할 수 있지만 page runtime의 pause/resume를 background 보장으로 표현하지 않는다.

Download integration

7. Strategy selector

download strategy는 application caller가 지정하지 않고 immutable profile, resource delivery class, expected bytes, browser capability와 user activation을 입력으로 하는 headless selector가 결정한다.

조건 결과
save picker 지원, user activation 있음, large stream WHOLE_OBJECT_PICKER_STREAM
server-managed resource, picker 없음 또는 handoff가 제품 정책 BROWSER_MANAGED_HANDOFF
generated artifact가 approved Blob cap 이하 BOUNDED_OBJECT_URL
large generated artifact, picker 없음 SERVER_GENERATION_REQUIRED 또는 UNSUPPORTED
Range profile + seekable destination + provider contract RANGE_RESUMABLE_FOREGROUND
background download가 선택되고 지원되는 browser + owned staging APP_MANAGED_BACKGROUND_DOWNLOAD

selector는 capability probe와 actual invocation failure를 구분한다. WHOLE_OBJECT_PICKER_STREAM인데 picker가 없으면 request validation 오류가 아니라 UNSUPPORTED 또는 승인 fallback이어야 한다. Safari/WebView/private mode의 fallback도 동일 표에서 결정하며 user agent 문자열만으로 기능을 가정하지 않는다.

selector의 위 값은 application-level DownloadExecutionPlan이다. 현재 file-delivery primitive와의 mapping은 다음처럼 닫는다.

execution plan 현재 adapter mapping
WHOLE_OBJECT_PICKER_STREAM DownloadStrategy=PROMPT_AND_STREAM
BROWSER_MANAGED_HANDOFF source kind BROWSER_MANAGED_RESOURCE + DownloadStrategy=BROWSER_MANAGED
BOUNDED_OBJECT_URL DownloadStrategy=BOUNDED_OBJECT_URL
RANGE_RESUMABLE_FOREGROUND VD-14의 별도 future port; 현재 adapter에 mapping 금지
APP_MANAGED_BACKGROUND_DOWNLOAD 별도 optional worker/staging port
SERVER_GENERATION_REQUIRED / UNSUPPORTED browser delivery를 시작하지 않는 closed outcome

Range resume의 checkpoint, validator와 seek/truncate 결정은 VD-14를 따른다. app-managed background download는 기본 selector 결과가 아니다.

Image descriptor acquisition과 delivery

8. Wire protocol

private Image descriptor BFF 계약은 다음 literal을 사용한다.

IMAGE_CDN_DESCRIPTOR_V1

request는 composition-owned fixed HTTPS endpoint를 호출하며 최소한 다음 application-safe 입력만 허용한다.

  • protocol
  • opaque asset reference
  • named preset reference 또는 preset family
  • intended presentation class
  • current runtime generation에 묶인 CSRF/session transport

caller는 CDN URL, source URL, origin, object key, width, height, DPR, quality, fit, format, cache header, signing key ID나 expiry를 제출하지 않는다.

response decoder는 content type, status, header/body byte cap, total deadline와 closed JSON shape를 검증한다. response에는 최소한 다음이 binding된다.

  • exact protocol과 issuer
  • opaque asset ID와 immutable revision
  • origin/preset binding IDs
  • static raster media와 intrinsic dimensions
  • allowed preset binding ID set
  • issued/expiry time
  • signature algorithm, key ID, canonical binding digest와 signature

unknown field 정책은 protocol version에서 고정한다. credential, backend stack, raw provider key 또는 arbitrary transform은 descriptor에 포함하지 않는다.

HTTP 200만 descriptor success다. 401/403/404의 외부 mapping은 existence hiding 정책에 따라 closed failure로 정규화하며 raw backend message를 버린다. redirect, opaque response, wrong content type, oversize, timeout와 malformed descriptor는 capability를 생성하지 않는다.

9. Provider와 verifier 경계

  • BFF는 authorization, asset existence, quarantine/promotion state와 descriptor 발급 authority를 소유한다.
  • verifier registry는 composition이 승인한 bounded old/new public key set만 가진다.
  • client signature 검증은 BFF authorization의 대체가 아니라 response tamper와 registry mismatch를 fail-closed하는 보조 경계다.
  • CDN은 asset revision과 preset binding ID로 exact transform candidate를 재계산한다. signed query나 client 계산 width가 authority가 아니다.
  • private asset의 emergency revocation은 backend/CDN/BFF가 소유한다. client는 runtime close와 short expiry로 exposure를 줄인다.

10. Refresh state machine

descriptor provider는 asset/preset/scope/generation별 bounded single-flight만 허용한다.

ABSENT
  -> FETCHING
  -> VERIFIED
  -> FRESH
  -> REFRESH_DUE
  -> REFRESHING
  -> FRESH

FETCHING | REFRESHING
  -> TERMINAL_POLICY_FAILURE
  -> PLACEHOLDER

FETCHING | REFRESHING
  -> RETRYABLE_FAILURE
  -> EXISTING_FRESH_UNTIL_EXPIRY | PLACEHOLDER

any state + scope/runtime revoke
  -> REVOKED
  • refresh lead time은 config가 정하되 expiry hard ceiling을 넘지 않는다.
  • private descriptor를 generic Query cache, Web Storage 또는 IndexedDB에 persistence하지 않는다.
  • concurrent callers는 같은 verified result를 받을 수 있지만 URL/string을 application state에 장기 복사하지 않는다.
  • 기존 descriptor가 아직 fresh하고 refresh가 일시 실패하면 expiry까지만 사용할 수 있다. expiry 뒤 stale-while-error를 금지한다.
  • lazy load로 실제 fetch가 expiry 뒤 시작될 가능성이 있으면 eager/priority로 바꾸거나 load 직전에 새 descriptor를 발급한다.
  • logout, key registry replacement와 runtime generation 변경은 in-flight transport, verification과 probe를 abort하고 늦은 결과를 폐기한다.

11. Safe presentation projection

공통 presentation primitive는 검증된 ImagePresentationDescriptor를 다음 정적 속성으로만 투영한다.

  • fallback src
  • ordered <source type srcset>
  • registry-owned sizes
  • intrinsic widthheight
  • loading, decoding, fetchpriority
  • referrerpolicy
  • crossorigin="anonymous"

primitive는 URL을 parse·조립·append하거나 transform query를 생성하지 않는다. descriptor가 가진 string을 React property로 전달하기 전에 closed allowed protocol/origin과 runtime generation을 다시 확인한다. raw HTML 주입과 CSS URL 조립을 금지한다.

다음은 제품 presentation owner가 결정한다.

  • 의미 있는 alt
  • placeholder와 오류 copy
  • skeleton/aspect-ratio UX
  • above-the-fold preload/priority
  • route/SSR preload hint
  • click/open/download behavior

descriptor refresh 실패를 native broken-image UI에만 맡기지 않고 제품이 승인한 placeholder outcome으로 매핑한다.

Provider contract harness

12. 재사용 가능한 suite

frontend는 transport 구현과 분리된 provider contract harness를 제공한다. 같은 case set을 deterministic fake, local emulator와 실제 BFF/object storage/CDN에 실행한다.

Presigned/download case:

  • exact protocol/status/content type/body cap
  • method/origin/path/query/header binding
  • redirect와 credential omission
  • expiry/revocation/replay
  • truncation/overrun/content encoding
  • CORS exposed receipt/checksum

Multipart case:

  • create/status/part/complete/abort idempotency
  • part layout/checksum/receipt reconciliation
  • 404/410/expiry와 orphan cleanup
  • quarantine/promotion
  • retry-after와 ambiguous completion

Image case:

  • protocol/issuer/key/preset exact match
  • old/new signing key overlap과 removal
  • immutable revision/cache key
  • private no-store/CORS/CSP
  • pixel/decode/encoded byte ceiling
  • malformed/animated/active content
  • expiry refresh, revocation과 placeholder

actual provider test는 bearer URL, signature, account/asset/session ID를 artifact에 기록하지 않는다. fixture는 synthetic opaque values와 disposable storage를 쓴다.

Failure, readiness와 fallback

13. Readiness report

readiness는 application-safe capability별 결과다.

상태 의미
READY 필수 provider/config/browser probe가 모두 유효
DEGRADED 승인된 좁은 fallback만 가능
UNAVAILABLE 기능을 노출하지 않음
DRAINING 기존 작업만 정리 중
CLOSED terminal

DEGRADED는 byte/pixel/security ceiling을 낮출 수는 있지만 높이지 않는다. 예를 들어 enhanced picker off → native input, multipart concurrency off → sequential, private Image CDN off → approved placeholder는 가능하다. integrity off, arbitrary URL 허용, private response cache 또는 unbounded Blob은 fallback이 아니다.

14. Kill switch

최소한 다음 switch를 독립적으로 둔다.

  • new presigned issuance
  • direct object-storage data plane
  • new upload session
  • upload resume
  • upload complete
  • Range resume
  • picker streaming save
  • private image descriptor issuance
  • advanced image format
  • responsive candidates

switch 변경은 active operation의 의미를 소급 변경하지 않는다. 신규 진입을 닫은 뒤 reconcile/drain한다. remote runtime config를 사용한다면 config의 authenticity, release compatibility와 last-known-safe 정책을 별도 hosting 계약으로 검증한다.

관측성과 개인정보

허용:

  • operation kind와 safe outcome
  • runtime/readiness state
  • byte/part/candidate/retry/age/deadline bucket
  • policy rejection, abort, reconcile와 drain bucket
  • aggregate active count, checkpoint count와 orphan age

금지:

  • URL, query, signed/request/response header
  • capability, bearer token, signature와 key material
  • resource/session/asset/upload/account/tenant ID
  • file name, local path, object key와 storage physical key
  • digest, ETag, receipt와 checkpoint payload
  • raw backend/browser exception message와 stack

runtime generation과 registry ID도 외부 telemetry에 그대로 보내지 않고 bounded compatibility bucket으로 변환한다.

Rollout과 rollback

15. Rollout

  1. ledger와 관련 ADR을 accepted로 고정한다.
  2. closed config/port와 provider contract harness를 먼저 구현한다.
  3. fake와 negative fixture에서 partial composition/late result를 거절한다.
  4. top-level runtime을 AVAILABLE_NOT_COMPOSED로 유지하고 removal gate를 만든다.
  5. product owner, exact scope와 provider config를 선택하고 bootstrap에 kill switch DISABLED 상태로 조합한다. 이 시점 primary status는 COMPOSED다.
  6. 실제 BFF/storage/CDN conformance와 readiness probe를 통과한다.
  7. Chromium/Firefox/WebKit과 실제 device에서 account switch, expiry와 crash를 검증한다.
  8. runbook/rollback drill 뒤 internal cohort의 read-only/image public 또는 upload shadow flow부터 연다.
  9. private/image upload/download capability를 독립 canary와 kill switch로 확대한다.

16. Rollback

  1. 신규 issuance/session/descriptor를 중지한다.
  2. runtime을 DRAINING으로 바꾸고 bounded operation을 마무리한다.
  3. ambiguous upload는 server reconcile하고 Range partial은 checkpoint 정책대로 보존 또는 삭제한다.
  4. private capability를 backend에서 revoke하고 client runtime을 close한다.
  5. old compatible composition을 새 generation으로 다시 생성하거나 기능을 unavailable로 유지한다.
  6. optional source, config와 facade를 제거하고 production module inventory와 removal gate를 재검증한다.

schema version을 내리거나 checkpoint를 무조건 삭제해 rollback하지 않는다.

검증과 완료 기준

17. Deterministic

  • partial factory failure의 reverse-order cleanup
  • close idempotency와 closed-runtime rejection
  • account switch 중 late fetch/hash/transaction/decode drop
  • config duplicate/ceiling/missing provider fail-closed
  • selector의 picker/size/resource matrix
  • upload pause/abort/reconcile race와 bounded inventory
  • descriptor refresh single-flight, expiry와 generation fence
  • picture projection의 arbitrary URL/query 생성 0건
  • diagnostics forbidden-value negative fixtures

18. Native browser

  • Chromium/Firefox/WebKit의 native input/save picker fallback
  • multi-tab upload pause/cancel과 unsupported Web Locks path
  • page reload/account switch 중 active transfer drain
  • public/private Image fetch, actual CORS/no-store와 bitmap decode
  • offline/timeout/abort/late completion cleanup
  • Safari/WebView/private mode의 approved selector result

19. Provider와 operations

  • fake/emulator/실제 BFF·object storage·CDN 동일 contract suite
  • signing key rotation과 emergency revoke drill
  • checkpoint retention/orphan cleanup drill
  • capability별 kill switch와 N-1 rollback
  • runtime removal 후 source-module inventory 0건

다음 조건 전에는 목표 상태를 AVAILABLE_NOT_COMPOSED로 올리지 않는다.

  • top-level closed config와 atomic factory가 구현됐다.
  • generation-bound lifecycle과 account teardown이 구현됐다.
  • RESUMABLE_UPLOAD_PAUSE_V1, checkpoint schema v2 old-writer migration과 bounded upload inventory/retention owner가 구현됐다.
  • PRESIGNED_TRANSFER_V1과 선택 protocol의 strict codec, unknown-version rejection 및 reusable provider contract harness가 구현됐다.
  • strategy selector가 browser fallback을 fail-closed한다.
  • Image descriptor provider/refresh와 safe projection이 구현됐다.
  • deterministic fault, boundary, removal test가 통과한다.

다음 조건 전에는 제품 상태를 COMPOSED로 올리지 않는다.

  • product owner와 opaque account scope가 정해졌다.
  • strict config를 사용하는 top-level runtime이 production bootstrap에서 생성되고 실제 feature facade consumer까지 연결됐다.
  • traffic 기본값이 DISABLED이며 local teardown/close 경로가 연결됐다.

다음 조건 전에는 product-local production traffic을 승인하지 않는다.

  • actual BFF/storage/CDN contract harness가 통과한다.
  • browser/device evidence와 runbook drill이 보존됐다.
  • kill switch와 rollback owner가 운영 승인됐다.

관련 문서

선택하지 않은 대안

  • feature가 개별 transfer adapter factory를 직접 조합
  • singleton runtime을 여러 account/tenant가 공유
  • raw presigned/Image URL을 Query cache나 persistence에 저장
  • Image descriptor endpoint/transform을 request마다 caller가 지정
  • page abort를 upload pause 또는 server abort 완료로 간주
  • browser-managed handoff를 저장 완료로 간주
  • user-agent 문자열만으로 Safari fallback 결정
  • Service Worker를 설치하면 background upload/download가 보장된다고 가정
  • capability 일부만 준비된 partial runtime을 degraded success로 반환

결과

장점:

  • account 전환과 teardown의 한 owner가 생긴다.
  • 개별 runtime의 안전한 메커니즘을 제품별 facade로 좁혀 조합할 수 있다.
  • provider mock과 실제 인프라 사이의 계약 차이를 같은 suite로 찾을 수 있다.
  • Image URL과 transform이 application/presentation에서 재조립되지 않는다.
  • capability별 rollout, kill switch와 제거가 독립적이다.

비용:

  • config, lifecycle, provider harness와 browser evidence가 늘어난다.
  • 제품이 선택하지 않은 capability는 여전히 조합할 수 없으며 이것이 의도된 결과다.
  • actual provider와 운영 증거 없이는 reference runtime 구현만으로 production 완료를 주장할 수 없다.