Files
natsClient_JS/docs/2-solution_design.md
2026-09-18 22:03:10 +07:00

83 lines
4.5 KiB
Markdown

# Solution Design: natsClient_JS
## 1. Problem Decomposition
| Problem | Description | User Impact |
|---------|-------------|-------------|
| P-001 | Consumers must manage a NATS connection lifecycle | Boilerplate, connection churn, dropped sockets |
| P-002 | Consumers must decode/encode payloads | Manual `StringCodec`/`JSON` in every call site |
| P-003 | Consumers need synchronous request/reply | Duplicated await-loop logic |
| P-004 | Consumers need a server-side reply handler | No way to serve requests from the client |
| P-005 | Consumers need msghandler envelope handling | Manual packing/unwrapping |
| P-006 | Consumers need to know connection state | No way to drive a status indicator |
| P-007 | Consumers need clean teardown | Leaked subscriptions and sockets |
## 2. Solution Approach
A single shared NATS connection exposed as ES module exports, with one helper function per
operation (subscribe, publish, request, reply, msghandler, close). Connection state flows into a
reactive Svelte store so consumers can bind it directly. Envelope packing delegates to
`msghandler-csr.js`, keeping this library focused on transport and lifecycle.
## 3. Decision Rationale
| Decision ID | Decision | Rationale | Alternatives Rejected |
|-------------|----------|-----------|----------------------|
| SD-001 | Shared module-level connection (`nc`) | One socket serves every operation for the whole app | Per-call `connect` — connection churn |
| SD-002 | URL resolution precedence chain | Predictable, layered configuration (opts → env → config → default) | A single required URL arg — no env/config fallback |
| SD-003 | `StringCodec` + `JSON.stringify`/`JSON.parse` | Uniform text encoding for both directions | Per-consumer encoding logic |
| SD-004 | Monitor `nc.status()` and `nc.closed()` | Reactive `connecting`/`connected`/`disconnected`/`error` states | Polling the connection |
| SD-005 | Subscription registry (`Map`) | Centralized unsubscribe in `closeNats` | Scattered subscriptions with no cleanup |
| SD-006 | Delegate msghandler to `msghandler-csr.js` | Separation of envelope codec from transport | Reimplementing envelope logic here |
| SD-007 | Svelte store for `connectionStatus` | Framework-agnostic consumers get reactivity for free | Plain variable consumers must wire their own subscription |
## 4. High-Level Component Diagram
### C4 Level 2 - Container
```mermaid
%% C4 Level 2 - Container
flowchart LR
app[Consuming App<br/>Svelte app] -->|imports| natsClient[(natsClient.js)]
natsClient -->|nats.ws WSS| nats[(NATS broker)]
natsClient -->|smartpack/smartunpack| msg[(msghandler-csr.js)]
natsClient -->|writable| store[(connectionStatus store)]
```
**Component Descriptions**:
- **natsClient.js**: Shared connection + operation helpers (subscribe/publish/request/reply) +
status store + msghandler delegation.
- Links to requirements: FR-001..FR-008, NFR-101, NFR-201
- **msghandler-csr.js**: Envelope pack/unpack.
- Links to requirements: FR-006
- **connectionStatus store**: Reactive `{state, message}` for the app.
- Links to requirements: FR-007
## 5. Alternatives Considered
| Alternative | Pros | Cons | Decision |
|-------------|------|------|----------|
| Per-call connection | Isolated lifecycle | Connection churn, re-auth overhead | Rejected — SD-001 |
| Manual decode at call site | No dependency | Duplicated error handling | Rejected — SD-003 |
| Callbacks instead of async iterators | Familiar | Verbose, harder to cancel | Rejected — uses `for await` |
## 6. Risk Assessment
| Risk | Impact | Probability | Mitigation |
|------|--------|-------------|------------|
| Broker unreachable at startup | Connection fails | Medium | `getNats` throws; consumer retries |
| Decode error on a message | Lost message / crash | Low | `catch` around decode/parse/handler |
| Reconnect never settles | Stuck `disconnected` | Low | `nc.status()` + `nc.closed()` monitoring |
## 7. Requirements Traceability
| Solution Component | Requirement ID | Decision ID | Description |
|-------------------|----------------|-------------|-------------|
| Shared connection | FR-001, FR-003 | SD-001 | One socket for pub/sub and publish |
| URL resolution | FR-001 | SD-002 | opts → env → config → default |
| Message decode | FR-002 | SD-003 | StringCodec + JSON/text fallback |
| Status tracking | FR-007 | SD-004 | status() + closed() monitor |
| Subscription cleanup | FR-008 | SD-005 | Map registry |
| msghandler | FR-006 | SD-006 | Delegation to msghandler-csr.js |
| Reactive status | NFR-201 | SD-007 | Svelte store |