Clean Architecture in TrustWeave
TrustWeave applies Uncle Bob’s Clean Architecture principles to ensure maintainability, testability, and independence from frameworks.
Dependency Rule
Source code dependencies point only inward. Inner layers know nothing of outer layers.
1
2
3
4
5
6
7
8
9
┌─────────────────────────────────────────────────────────────┐
│ Frameworks & Drivers (Ktor, Testcontainers, DB drivers) │ ← Outermost
├─────────────────────────────────────────────────────────────┤
│ Interface Adapters (DSL builders, presenters, gateways) │
├─────────────────────────────────────────────────────────────┤
│ Use Cases (CredentialIssuanceService, DidManagementService)│
├─────────────────────────────────────────────────────────────┤
│ Entities (Did, VerifiableCredential, TrustPath) │ ← Innermost
└─────────────────────────────────────────────────────────────┘
Layer Mapping
| Clean Architecture | TrustWeave | Location |
|---|---|---|
| Entities | Did, VerifiableCredential, CredentialType, ProofType, AnchorRef |
did-core, credential-api, anchor-core |
| Use Cases | CredentialIssuanceService, CredentialVerificationService, DidManagementService, WalletManagementService, TrustManagementService |
trust/services/ |
| Interface Adapters | DSL builders (IssuanceBuilder, DidBuilder), TrustWeave facade |
trust/dsl/ |
| Frameworks | Ktor, Spring Boot, Testcontainers | Plugins, examples |
Dependency Inversion Principle
High-level modules depend on abstractions (ports), not concrete implementations:
- TrustWeave receives
CredentialService,DidResolver,KeyManagementServicevia config - CredentialIssuanceService depends on
CredentialService(interface), notDefaultCredentialService - SmartContractService can be injected—
TrustWeaveusesconfig.smartContractService ?: DefaultSmartContractService(...)
Ports (Interfaces)
| Port | Implemented By | Module |
|---|---|---|
CredentialService |
DefaultCredentialService |
credential-api |
DidMethod |
KeyDidMethod, WebDidMethod, etc. | did-plugins |
KeyManagementService |
InMemoryKms, AwsKms, etc. | kms-plugins |
BlockchainAnchorClient |
AlgorandAnchorClient, etc. | anchors-plugins |
WalletFactory |
InMemoryWalletFactory, etc. | wallet-plugins |
SmartContractService |
DefaultSmartContractService |
contract |
Single Responsibility Principle
Each service has one reason to change:
CredentialIssuanceService— issuance orchestration onlyCredentialVerificationService— verification onlyDidManagementService— DID creation and resolutionTrustWeaveFactory— wiring and SPI resolution
Kotlin Idioms
- Sealed classes for result types (
IssuanceResult,DidCreationResult,VerificationResult) - Extension functions for domain mappings (
ProofType.toProofSuiteId()) - Coroutines for async operations (
suspend fun) - Data classes for value objects (
Did,CredentialConfig) - DSL builders for fluent configuration (
TrustWeave.build { ... }) - Scope functions (
let,apply,also) for concise flows
Composition Root
TrustWeave.build { } and TrustWeaveFactory form the composition root—all dependencies are wired there. Application code receives a fully configured TrustWeave instance.
Testing
- Use
testkitfor in-memory implementations of ports - Inject mocks via
TrustWeave.build { credentialService(myMock) } - Use
@Disabledfor placeholder tests with clear reasons