refactor: 프론트 템플릿 리펙토링
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
# Frontend Application Foundation
|
||||
|
||||
This repository is not treated as a minimal React project template and it is not
|
||||
an independent general-purpose SDK. Its architectural role is:
|
||||
|
||||
> Frontend Application Foundation = Starter / Composition Skeleton + Reusable Capability Platform
|
||||
|
||||
The starter side owns bootstrap, routing, providers, project conventions and a
|
||||
removable reference feature. The capability side owns reusable technical
|
||||
problems such as HTTP execution, Server State, authentication boundaries,
|
||||
IndexedDB/OPFS, Cache Storage, realtime, browser RPC, transfer and diagnostics.
|
||||
|
||||
The cost of a sophisticated capability is acceptable only when product features
|
||||
do not have to understand that internal sophistication.
|
||||
|
||||
## Hybrid architecture
|
||||
|
||||
Platform code is horizontal:
|
||||
|
||||
- `application`: generic application inputs/policies/ports
|
||||
- `contracts`: genuinely cross-capability shared vocabulary and registries
|
||||
- `adapters`: reusable capability runtimes
|
||||
- `presentation`: generic UI/routing/query integration
|
||||
- `bootstrap`: concrete composition
|
||||
|
||||
Product business code is vertical:
|
||||
|
||||
- `features/<feature>/domain`
|
||||
- `features/<feature>/application`
|
||||
- `features/<feature>/contracts`
|
||||
- `features/<feature>/adapters`
|
||||
- `features/<feature>/presentation`
|
||||
|
||||
The dependency model is:
|
||||
|
||||
Domain / Use case
|
||||
|
|
||||
| owns
|
||||
v
|
||||
Business port
|
||||
^
|
||||
| implements / binds
|
||||
|
|
||||
Feature-owned adapter binding
|
||||
|
|
||||
| generic type + mapper/codec + policy
|
||||
v
|
||||
Reusable capability runtime
|
||||
|
|
||||
v
|
||||
Browser / network / native API
|
||||
|
||||
A use case never imports a platform adapter. Generic binding happens in the
|
||||
feature adapter/composition seam.
|
||||
|
||||
## Capability-specific typed bindings
|
||||
|
||||
Do not introduce one universal `Repository<TKey, TValue>` abstraction for HTTP,
|
||||
storage, realtime and transfer. Their lifecycle and failure semantics differ.
|
||||
|
||||
A reusable capability boundary is composed from:
|
||||
|
||||
- generic input/output types,
|
||||
- feature-owned mapper or codec,
|
||||
- feature-selected policy,
|
||||
- one capability-specific runtime.
|
||||
|
||||
The HTTP reference path is the first concrete example.
|
||||
`src/adapters/http/feature-http-binding.ts` owns transport/outcome
|
||||
normalization. The reference feature contributes only:
|
||||
|
||||
- operation ID,
|
||||
- route ID,
|
||||
- exact request input type,
|
||||
- exact success value type,
|
||||
- wire-to-domain mapper.
|
||||
|
||||
The feature gateway therefore does not reimplement timeout, cancellation,
|
||||
transport failure, authentication failure or contract-violation projection.
|
||||
|
||||
Storage, realtime and transfer may gain their own typed binders only after
|
||||
actual feature repetition demonstrates the need. They must not be forced
|
||||
through the HTTP abstraction.
|
||||
|
||||
## Custom adapter escape hatch
|
||||
|
||||
A product feature uses a reusable capability when the capability preserves the
|
||||
business requirement.
|
||||
|
||||
If a platform contract would require changing or weakening the business model,
|
||||
the feature implements a custom outbound adapter behind the same application
|
||||
port. The architecture boundary remains stable; platform reuse is optional.
|
||||
|
||||
## Feature installation
|
||||
|
||||
A feature owns its contract, runtime and adapter contributions.
|
||||
|
||||
Central installed catalogs are aggregation points only:
|
||||
|
||||
- `installed-product-manifest.ts`: which product features are compiled/selected
|
||||
- `installed-feature-contracts.ts`: contract aggregation
|
||||
- `installed-feature-runtimes.tsx`: runtime contribution aggregation
|
||||
- `installed-feature-adapters.ts`: application-input contribution aggregation
|
||||
|
||||
Feature-specific composition belongs under the feature itself. Central
|
||||
catalogs must not grow feature-specific branching logic.
|
||||
|
||||
## Presentation consumer surface
|
||||
|
||||
`ApplicationProvider` remains the composition root for presentation, but new
|
||||
consumers should not navigate a root `ApplicationApi` service locator.
|
||||
|
||||
Use the narrow hooks in
|
||||
`src/presentation/providers/application-provider.tsx`:
|
||||
|
||||
- `useApplicationSession`
|
||||
- `useApplicationPreferences`
|
||||
- `useApplicationDiagnostics`
|
||||
- `useApplicationRuntime`
|
||||
- `useApplicationRecovery`
|
||||
- `useApplicationFeature`
|
||||
|
||||
`useApplication` exists only as a deprecated compatibility escape hatch.
|
||||
|
||||
## Canonical imports
|
||||
|
||||
New feature code should use capability public entry points rather than deep
|
||||
runtime modules. For HTTP the canonical path is
|
||||
`src/adapters/http/index.ts`.
|
||||
|
||||
Compatibility re-exports may exist during a migration window, but they must be
|
||||
marked as compatibility/deprecated paths and should not expand into an
|
||||
unbounded public barrel.
|
||||
|
||||
## Policy ownership
|
||||
|
||||
Duplication is judged by ownership, not by syntax percentage.
|
||||
|
||||
Small local validators can remain duplicated when locality improves auditing.
|
||||
Business or concurrency policy must have one owner. For example the reference
|
||||
create mutation keeps definition ID, idempotency requirement, duplicate policy
|
||||
and invalidation policy in one feature-owned definition and binds only
|
||||
`scope` and `execute` per usage site.
|
||||
|
||||
## Runtime decomposition rule
|
||||
|
||||
Large runtime files are not split by line count.
|
||||
|
||||
Extract a boundary when it has its own state machine, lifecycle owner, failure
|
||||
model or compensation/recovery responsibility. Candidate seams include:
|
||||
|
||||
- connection/open/upgrade lifecycle,
|
||||
- transaction ownership,
|
||||
- migration state machine,
|
||||
- reconnect/backoff and heartbeat,
|
||||
- subscription ownership,
|
||||
- retry/deadline/cancellation ownership,
|
||||
- settlement/reconciliation/cleanup.
|
||||
|
||||
A cohesive 2,000-line state machine can remain together. A 300-line file with
|
||||
multiple lifecycle owners is a better extraction candidate.
|
||||
|
||||
### Current runtime boundary audit
|
||||
|
||||
The current large-runtime inventory was reviewed using that rule.
|
||||
|
||||
- IndexedDB remains large, but connection, transaction, migration, maintenance
|
||||
and failure translation already have separate owners/modules.
|
||||
- resumable upload already separates runtime policy, checkpoint persistence,
|
||||
HTTP control-plane transport, part execution, cancellation and mutation
|
||||
locking.
|
||||
- realtime already separates reconnect policy/coordinator, event codec/consumer
|
||||
and stream coordination.
|
||||
- OPFS is separated into browser runtime, journal, byte-store, policy and worker
|
||||
protocol/runtime responsibilities.
|
||||
- HTTP V3 still owned retry eligibility/backoff inside the execution state
|
||||
machine, so that responsibility moved to
|
||||
`src/adapters/http/http-retry-lifecycle.ts`.
|
||||
|
||||
No other runtime is split merely because of its line count.
|
||||
|
||||
## Consumer quality metrics
|
||||
|
||||
Before adding another abstraction, implement or model multiple real feature
|
||||
uses and measure:
|
||||
|
||||
- feature-owned adapter LOC,
|
||||
- repeated platform glue,
|
||||
- number of platform-internal types exposed to the feature,
|
||||
- central catalog edits,
|
||||
- files changed for one normal query/command,
|
||||
- whether native browser/network APIs leak into the feature.
|
||||
|
||||
The target feature-development path is:
|
||||
|
||||
1. domain type and invariant,
|
||||
2. use case,
|
||||
3. port,
|
||||
4. transport/storage schema plus mapper/codec,
|
||||
5. capability binding,
|
||||
6. presentation controller/page.
|
||||
|
||||
A product feature should not need to know the retry scheduler, abort ownership,
|
||||
effect-certainty machinery, transaction leases, reconnect coordinator, OPFS
|
||||
journal or provider lifecycle.
|
||||
|
||||
The executable REST and IndexedDB consumer baselines are recorded in
|
||||
[`capability-consumer-experience.md`](./capability-consumer-experience.md).
|
||||
Contract placement and the global-vs-owner-local audit are recorded in
|
||||
[`contract-ownership.md`](./contract-ownership.md).
|
||||
|
||||
## Verification paths
|
||||
|
||||
Product-development verification, capability verification and release assurance
|
||||
are intentionally separate. See
|
||||
[`docs/testing/taxonomy.md`](../testing/taxonomy.md).
|
||||
|
||||
Host-level CI-runner tests belong to `tests/system`, not `tests/unit`.
|
||||
Reusable capability consumer contracts belong to `tests/contract`.
|
||||
Reference in New Issue
Block a user