feat: web, websocket 어댑터 추가 구현
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
# ADR-WS-001: The WebSocket platform ships as packages in one leaf, with machine-checked boundaries
|
||||
|
||||
- Status: accepted
|
||||
- Date: 2026-08-25
|
||||
- Scope: `:adapter:inbound:websocket`
|
||||
|
||||
## Context
|
||||
|
||||
The realtime connection platform design models itself as eighteen Gradle modules under
|
||||
`modules/websocket`, each with a declared purity grade and a declared set of allowed dependencies.
|
||||
This repository's `src/config/architecture/modules.json` is a fail-closed registry that owns the
|
||||
leaf list; adding eighteen leaves is a registry change of a size that needs its own decision, and
|
||||
HARD-STOP #5 forbids doing it implicitly.
|
||||
|
||||
Three earlier platforms in this repository — JPA, GraphQL, and the HTTP platform — met the same
|
||||
situation and resolved it the same way.
|
||||
|
||||
## Decision
|
||||
|
||||
The eighteen design modules ship as packages inside the single registered leaf. `WebSocketStableModule`
|
||||
declares each one's package, purity grade and exact allowed edges, and `WebSocketModuleBoundaryTest`
|
||||
scans the production tree and fails when the declaration and the tree disagree in either direction.
|
||||
|
||||
Three deviations from the design's module map were forced by the check and are recorded in
|
||||
`docs/websocket/repository-adaptation.md`: `WebSocketSubprotocolName` moved to `core` and the codec
|
||||
moved to its own FRAMEWORK_BOUND module, both to avoid cycles the design's placement created here;
|
||||
and the `budget -> core` edge was inverted because `budget` imports nothing from `core`.
|
||||
|
||||
## Consequences
|
||||
|
||||
**The boundary is enforced, not documented.** Six violations were caught during implementation that
|
||||
a document would not have: two would-be cycles, a duplicate module declaration where two ids claimed
|
||||
one package, and three undeclared edges. The duplicate is the instructive one — with two ids on one
|
||||
package, ownership depends on iteration order and one module's rules silently apply to nothing. A
|
||||
guard against it is now part of the boundary test.
|
||||
|
||||
**The detector had a hole.** Its framework-import list named `com.fasterxml` (Jackson 2) and not
|
||||
`tools.jackson` (Jackson 3), which is what Spring 7 actually uses — so a CORE module could have
|
||||
imported a mapper unnoticed. Fixed here and in the HTTP platform, which shared the list.
|
||||
|
||||
**Promotion stays cheap.** Each enum constant is already shaped like a leaf specification, so
|
||||
splitting one out later is a registry edit rather than an archaeology exercise.
|
||||
|
||||
**The design's own rules were kept where they cost something.** `core` names no framework, so the
|
||||
same decisions serve both runtimes and are testable without a server; no Java class name reaches the
|
||||
wire; the payload is an encoded string rather than a map; and handlers are given no way to write,
|
||||
which is what makes ordering and backpressure guarantees rather than conventions.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Register eighteen leaves.** Faithful to the design and a large change to a fail-closed registry
|
||||
for a platform that ships as one artifact either way. Rejected as disproportionate; the boundary
|
||||
test provides the property the modules were for.
|
||||
|
||||
**Ship the modules as packages with no enforcement.** Cheapest, and it makes the boundary a claim.
|
||||
The six violations found during implementation are the argument against it.
|
||||
Reference in New Issue
Block a user