Update four existing specs (overview, server, napi-and-pubsub, call-protocol) to reflect Phase 0 decisions: three-layer model, IdentityProvider, ForwardingPolicy, OperationEnv, static/dynamic config split. Review all 9 Phase 0a ADRs (026-034) for consistency. Fix 4 critical issues from architecture review: missing OQ-SVC-05 in open-questions.md, deprecated hub terminology, undefined AuthService and noq terms. Replace inline OQ text with cross-references per format rules. Add ConfigServiceImpl definition to configuration.md. Port absolute workspace paths to project-relative links by copying referenced docs (feasibility, certbot, fail2ban, event_source_types) into docs/research/.
7.7 KiB
ADR-027: Crate Decomposition
Status
Accepted
Context
alknet-core currently contains everything: transport, SSH, auth, config, the call protocol handler, and the server accept loop. As the project grows to include SQLite-backed identity, HD key derivation, and metagraph storage, core would need to depend on rusqlite, bip39, petgraph, and other heavy dependencies — unacceptable for a library crate that CLI users embed.
Different deployment topologies need different subsets:
- A minimal CLI tunnel only needs core, transport, and auth types
- A head node needs SQLite-backed identity and the secret service
- A flowgraph visualization tool only needs petgraph operations
Circular dependencies must be avoided. alknet-storage implements
alknet-core's IdentityProvider trait, so alknet-core cannot depend on
alknet-storage. alknet-storage references alknet-secret's EncryptedData wire
format, but not as a crate dependency.
Decision
Decompose the project into six crates with a strict acyclic dependency graph.
Crate Structure
-
alknet-core — Transport, SSH, call protocol, config, auth types, identity,
OperationSpec,Interfacetrait. The foundational crate that everything else depends on (by type, not by crate dep in some cases).- Depends on: russh, tokio, irpc (feature-gated), serde, arc-swap
- Does NOT depend on: alknet-secret, alknet-storage, alknet-flowgraph
-
alknet-secret — BIP39 mnemonic generation, SLIP-0010 Ed25519 HD key derivation, AES-256-GCM encryption,
SecretProtocolirpc service.- Depends on: bip39, ed25519-bip32 (or rust-bip32-ed25519), aes-gcm, sha2, irpc
- Does NOT depend on: alknet-core, alknet-storage
-
alknet-storage — SQLite-backed metagraph, identity tables, ACL graph, honker integration,
StorageProtocolirpc service.- Depends on: rusqlite (via honker), honker, petgraph, jsonschema, irpc
- Does NOT depend on alknet-core (but implements alknet-core's
IdentityProvidertrait via the trait, not a crate dep) - Does NOT depend on alknet-secret (but references
EncryptedDatatype format for wire compatibility)
-
alknet-flowgraph —
FlowGraph<N,E>over petgraph, operation graph, call graph, type compatibility checking.- Depends on: petgraph, serde, jsonschema, thiserror
- Does NOT depend on: alknet-core, alknet-storage, alknet-secret
-
alknet-napi — Node.js native addon. Exposes alknet-core to Node.js.
- Depends on: alknet-core
- Does NOT depend on: alknet-secret, alknet-storage, alknet-flowgraph
-
alknet (CLI binary) — Assembles everything.
- Depends on: alknet-core, alknet-secret (feature), alknet-storage (feature), alknet-flowgraph (feature), toml
Dependency Graph
alknet-secret alknet-storage alknet-flowgraph
(standalone) (standalone) (standalone)
│ │ │
│ (feature flags │ (trait impl │ (type compat
│ in CLI binary) │ via CLI wire) │ via JSON)
▼ ▼ ▼
┌─────────────────────┐
│ alknet-core │
│ (transport, SSH, │
│ call protocol, │
│ Identity, Config) │
└─────────┬───────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
alknet-napi alknet (CLI binary — assembles everything)
All four library crates (core, secret, storage, flowgraph) are independent of
each other. Dependencies flow upward only. The CLI binary sits at the top
and wires concrete implementations together. alknet-storage implements
alknet-core's IdentityProvider trait without a crate dependency — the CLI
binary provides the bridge.
Narrow Interface Points
Three types serve as the narrow interface points between crates:
-
Identity— Defined inalknet_core::auth. Used by auth handler, forwarding policy, and call protocol. alknet-storage implementsIdentityProviderto produce instances. -
IdentityProvider— Trait defined inalknet_core::auth. Implemented byConfigIdentityProvider(in core) andStorageIdentityProvider(in alknet-storage). The CLI/NAPI layer wires the concrete implementation. -
OperationSpec— Defined inalknet_core::call. Used by the operation registry and by alknet-flowgraph for type compatibility checking. The bridge is serialization — flowgraph serializes to JSON, storage persists it.
irpc Feature Flag
irpc is a feature flag in alknet-core. When disabled, auth and config go through
IdentityProvider and ConfigReloadHandle directly — no irpc overhead. Nodes
that only do SSH tunneling don't need the service layer.
In alknet-secret and alknet-storage, irpc is an independent dependency, not feature-gated. These crates always define irpc service protocols because they are used in production deployments where the service layer is active.
alknet-storage's Relationship to alknet-core
alknet-storage does NOT depend on alknet-core as a crate. Instead:
- alknet-storage defines its own
IdentityProviderimpl that matches alknet-core's trait signature. The trait is re-exported or defined locally with#[cfg(feature = "alknet-core")]interop. - In practice, the CLI binary crate depends on both and wires them together.
alknet-storage provides
StorageIdentityProvider; alknet-core takesimpl IdentityProvider.
alknet-storage's Relationship to alknet-secret
alknet-storage does NOT depend on alknet-secret as a crate. Instead:
- alknet-storage and alknet-secret share the
EncryptedDatawire format (key version, salt, IV, ciphertext). This is a type-level compatibility, not a crate dependency. - alknet-secret encrypts; alknet-storage stores the encrypted blob in a
SecretNodein the metagraph. The bridge is serialization.
Consequences
- Positive: Core is lean. No database, no crypto, no petgraph. CLI users get a small binary.
- Positive: Services are pluggable. alknet-secret and alknet-storage can be swapped for alternative implementations.
- Positive: No circular dependencies. The dependency graph is a DAG.
- Positive: Deployment topology determines which crates to include. A CLI tunnel uses only alknet-core. A head node uses everything.
- Positive: irpc is feature-gated in core. Minimal deployments don't pay for service layer overhead.
- Negative:
IdentityProvidertrait interop between alknet-core and alknet-storage requires careful versioning. If the trait signature changes, both crates must update. - Negative:
EncryptedDatawire format compatibility between alknet-secret and alknet-storage is implicit (not enforced by the type system). A shared types crate could be extracted if needed, but adds another crate dependency.
References
- research/integration-plan.md — Phase 2, dependency graph
- research/core.md — alknet-core contents
- research/services.md — Service protocols
- research/storage.md — alknet-storage contents
- research/flow.md — alknet-flowgraph contents
- ADR-028 — Auth as irpc service (service protocol enabled by decomposition)
- ADR-029 — Identity as core type (narrow interface point)