Files
clean-architecture-frontend…/docs/architecture/capability-consumer-experience.md
T

4.4 KiB

Capability consumer experience baseline

Correctness inside a reusable capability is not sufficient. The platform is also evaluated by how much of that correctness a normal feature developer must understand.

These measurements are baselines, not score targets. A lower line count is not automatically better if it hides business semantics or creates a universal repository abstraction.

Scenario A — reference REST feature

The existing reference feature is the executable REST consumer.

It covers list/detail/create behavior, mapping, typed operation inputs, application ports and an optimistic mutation path.

Current source size:

Feature-owned area LOC
application/reference-feature-api.ts 91
contracts/reference-mapper.ts 109
adapters/reference-http-gateway.ts 65
adapters/create-reference-feature-input.ts 41
Total measured boundary/application source 306

The important boundary metric is not the raw total. It is what those files need to know about the platform.

Current result:

  • HTTP platform imports in the feature adapter layer: 2 files,
  • canonical import path used by both: src/adapters/http/index.ts,
  • direct imports of http-execution-v3.ts, retry scheduler, response reader, auth admission or effect-certainty internals: 0,
  • feature gateway owns transport failure projection: 0,
  • feature gateway chooses operation ID, route ID, exact input/value type and mapper: yes,
  • central installed files own feature-specific adapter/runtime wiring: no; feature-owned contributions are aggregated centrally.

The reusable HTTP capability now owns execution-outcome normalization through createFeatureHttpBinding. A feature may still implement a custom outbound adapter behind its application port when the reusable contract does not match its business requirement.

Scenario B — IndexedDB local draft

An executable consumer probe lives at:

tests/contract/consumer-experience/indexeddb-local-draft.test.ts

with the feature-owned fixture:

tests/contract/consumer-experience/fixtures/local-draft-feature.ts

The fixture models a small local-draft feature with save/find/remove and optimistic revision checking.

Measured result:

Metric Result
feature-owned fixture LOC 97
platform import statements 1
native IndexedDB API references 0
src/adapters/storage/indexeddb/** imports 0
runtime-internal IndexedDB types imported by feature 0

The feature depends only on the public application boundary:

src/application/ports/browser-file-storage/index.ts

and specifically IndexedDbRepositoryPort<LocalDraft, never>.

The contract test rejects feature source that reaches for globalThis.indexedDB, IDBFactory, IDBDatabase, IDBTransaction, IDBObjectStore or the concrete IndexedDB adapter directory.

What this does and does not prove

The probe confirms that feature business code does not need native IndexedDB knowledge once an IndexedDbRepositoryPort has been composed.

It does not prove that composition of createIndexedDbRuntime is cheap. That constructor still owns substantial infrastructure policy:

  • dataset scope and storage policy,
  • physical store governance,
  • retention/idempotency stores,
  • schema migrations,
  • codec and query policy,
  • lifecycle authority,
  • durability, scheduling and observation.

That complexity belongs at the composition/platform boundary, not in the feature. A new create...Repository<T> convenience factory should be added only when a second real product consumer demonstrates which subset is stable enough to become a reusable profile. Creating one now would guess at policy and risk producing a universal storage abstraction.

Consumer-quality review checklist

For each new product feature, record:

  • feature-owned adapter LOC,
  • platform glue LOC,
  • files changed,
  • central catalog edits,
  • direct imports from capability-internal modules,
  • native browser/network API references,
  • duplicated failure/retry/lifecycle policy.

A healthy feature path should look like:

  1. domain type and invariant,
  2. use case,
  3. business port,
  4. feature-owned mapper/codec and policy,
  5. capability-specific binding,
  6. presentation controller/page.

The feature should not need the retry scheduler, abort ownership, effect-certainty machinery, IndexedDB transaction lifecycle, OPFS journal, reconnect coordinator or provider process model.