Production Deployment Guide

This guide covers best practices for deploying TrustWeave in production environments.

Overview

Production deployments require careful consideration of:

  • Security: Key management, access control, encryption
  • Performance: Caching, connection pooling, resource management
  • Reliability: Error handling, monitoring, health checks
  • Scalability: Horizontal scaling, stateless design
  • Observability: Logging, metrics, tracing

Configuration Best Practices

1. Use Production-Grade KMS

Never use inMemory KMS in production. Use a production-grade key management service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
val trustWeave = TrustWeave.build {
    keys {
        // ✅ Production: Use AWS KMS, Azure Key Vault, or HashiCorp Vault
        provider(AWS) {
            region("us-east-1")
            keyAlias("trustweave-signing-key")
        }
        // Or
        provider("azureKeyVault") {
            vaultUrl("https://myvault.vault.azure.net")
            keyName("signing-key")
        }
        algorithm(ED25519)
    }
    // ... rest of configuration
}

Key Considerations:

  • Use hardware security modules (HSM) for high-security applications
  • Implement key rotation policies
  • Use separate keys for different environments (dev, staging, prod)
  • Enable key versioning and audit logging

2. Configure Persistent Storage

Use persistent storage for wallets and trust registries:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
val trustWeave = TrustWeave.build {
    keys { ... }
    did { ... }
    trust {
        // ✅ Production: Use database-backed trust registry
        provider("database") {
            connectionString("jdbc:postgresql://db.example.org.trustweave")
            schema("trust_registry")
        }
    }
}

// Wallets should use persistent storage
val wallet = trustWeave.wallet {
    holder(holderDid)
    // Use database or S3 storage
    storageProvider("database")
    storagePath("wallets/${holderDid}")
}

Storage Options:

  • Database: PostgreSQL, MySQL for structured data
  • Object Storage: S3, Azure Blob for large credentials
  • File System: Only for single-instance deployments

3. Configure Blockchain Anchors

Use production blockchain networks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
val trustWeave = TrustWeave.build {
    // ... other configuration
    anchor {
        // ✅ Production: Use mainnet or production testnets
        chain("algorand:mainnet") {
            provider(ALGORAND) {
                apiKey(env("ALGORAND_API_KEY"))
                network("mainnet")
            }
        }
        // Or
        chain("polygon:mainnet") {
            provider(POLYGON) {
                rpcUrl("https://polygon-rpc.com")
                privateKey(env("POLYGON_PRIVATE_KEY"))
            }
        }
    }
}

Considerations:

  • Use mainnet for production data
  • Implement transaction retry logic
  • Monitor gas fees and transaction costs
  • Set appropriate timeouts

4. Enable Trust Registry

Always enable trust registry in production:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
val trustWeave = TrustWeave.build {
    // ... other configuration
    trust {
        provider("database") {
            connectionString(env("TRUST_DB_URL"))
            // Enable trust checking
            enableTrustChecking(true)
        }
    }
}

// Verify credentials with trust checking (registry from the same TrustWeave.build { trust { ... } })
val trustRegistry = requireNotNull(trustWeave.configuration.trustRegistry)
val verification = trustWeave.verify {
    credential(credential)
    requireTrust(trustRegistry)
}

Error Handling

Production Error Handling Pattern

Always handle errors explicitly in production:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import org.trustweave.core.exception.TrustWeaveException
import org.trustweave.credential.model.CredentialType
import org.trustweave.credential.model.vc.VerifiableCredential
import org.trustweave.credential.results.IssuanceResult
import org.trustweave.did.exception.DidException
import org.trustweave.did.identifiers.Did
import org.trustweave.trust.TrustWeave
import org.slf4j.LoggerFactory

private val logger = LoggerFactory.getLogger(MyService::class.java)

suspend fun issuePersonCredential(
    trustWeave: TrustWeave,
    issuerDid: Did,
    holderDid: String,
    claims: Map<String, Any>
): Result<VerifiableCredential> {
    return when (
        val issued = trustWeave.issue {
            credential {
                type(CredentialType.VerifiableCredential, CredentialType.Person)
                issuer(issuerDid)
                subject {
                    id(holderDid)
                    claims.forEach { (key, value) -> key to value }
                }
            }
            signedBy(issuerDid, "key-1")
        }
    ) {
        is IssuanceResult.Success -> Result.success(issued.credential)
        is IssuanceResult.Failure -> {
            logger.error("Issuance failed: ${issued.allErrors.joinToString()}")
            Result.failure(
                TrustWeaveException.InvalidState(
                    message = issued.allErrors.joinToString("; "),
                    context = emptyMap(),
                    cause = null
                )
            )
        }
    }
}

Error Recovery Strategies

Implement retry logic for transient errors:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import kotlinx.coroutines.delay
import kotlin.random.Random
import org.trustweave.core.exception.TrustWeaveException
import org.trustweave.did.exception.DidException

suspend fun <T> retryOperation(
    maxRetries: Int = 3,
    initialDelay: Long = 1000,
    operation: suspend () -> T
): T {
    var lastError: Exception? = null
    var delay = initialDelay.toDouble()

    repeat(maxRetries) { attempt ->
        try {
            return operation()
        } catch (error: Exception) {
            lastError = error

            // Don't retry on validation / client input errors
            if (error is TrustWeaveException.ValidationFailed ||
                error is DidException.InvalidDidFormat) {
                throw error
            }

            if (attempt < maxRetries - 1) {
                val jitter = Random.nextLong(0, (delay * 0.1).toLong())
                delay((delay + jitter).toLong())
                delay *= 2.0
            }
        }
    }

    throw lastError ?: Exception("Operation failed after $maxRetries retries")
}

Performance Optimization

1. Connection Pooling

Use connection pooling for database operations:

1
2
3
4
5
6
7
8
9
// Configure connection pool
val dataSource = HikariDataSource().apply {
    jdbcUrl = "jdbc:postgresql://db.example.org.trustweave"
    maximumPoolSize = 20
    minimumIdle = 5
    connectionTimeout = 30000
    idleTimeout = 600000
    maxLifetime = 1800000
}

2. Caching

Implement caching for frequently accessed data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.Caffeine
import java.util.concurrent.TimeUnit

class CachedDidResolver(
    private val delegate: DidResolver,
    private val cache: Cache<String, DidResolutionResult>
) : DidResolver by delegate {

    override suspend fun resolve(did: String): DidResolutionResult {
        return cache.get(did) {
            delegate.resolve(did)
        } ?: delegate.resolve(did)
    }
}

// Configure cache
val didCache = Caffeine.newBuilder()
    .maximumSize(10_000)
    .expireAfterWrite(1, TimeUnit.HOURS)
    .build<String, DidResolutionResult>()

3. Async Operations

Use coroutines for concurrent operations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import org.trustweave.core.exception.TrustWeaveException
import org.trustweave.credential.model.CredentialType
import org.trustweave.credential.model.vc.VerifiableCredential
import org.trustweave.credential.results.IssuanceResult
import org.trustweave.did.identifiers.Did
import org.trustweave.trust.TrustWeave

// Issue multiple credentials concurrently
// CredentialRequest.issuerDid is a String from your API layer; signedBy requires Did as the first argument.
suspend fun issueMultipleCredentials(
    trustWeave: TrustWeave,
    requests: List<CredentialRequest>
): List<VerifiableCredential> {
    return requests.map { request ->
        async {
            when (
                val r = trustWeave.issue {
                    credential {
                        type(CredentialType.VerifiableCredential, CredentialType.fromString(request.type))
                        issuer(request.issuerDid)
                        subject {
                            id(request.holderDid)
                            request.claims.forEach { (key, value) ->
                                key to value
                            }
                        }
                    }
                    signedBy(Did(request.issuerDid), request.keyId)
                }
            ) {
                is IssuanceResult.Success -> r.credential
                is IssuanceResult.Failure -> throw TrustWeaveException.InvalidState(
                    message = r.allErrors.joinToString("; "),
                    context = emptyMap(),
                    cause = null
                )
            }
        }
    }.awaitAll()
}

Security Best Practices

1. Environment Variables

Never hardcode secrets. Use environment variables or secret management:

1
2
3
4
5
6
7
import org.trustweave.testkit.services.*
// ✅ Good: Use environment variables
val apiKey = System.getenv("ALGORAND_API_KEY")
    ?: throw IllegalStateException("ALGORAND_API_KEY not set")

// ✅ Better: Use secret management service
val apiKey = secretManager.getSecret("algorand-api-key")

2. Input Validation

Always validate inputs before operations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fun validateDid(did: String): ValidationResult {
    if (!did.startsWith("did:")) {
        return ValidationResult.Invalid("DID must start with 'did:'")
    }
    val parts = did.split(":")
    if (parts.size < 3) {
        return ValidationResult.Invalid("Invalid DID format")
    }
    return ValidationResult.Valid
}

// Use before operations
val validation = validateDid(userInputDid)
if (!validation.isValid()) {
    return Result.failure(DidException.InvalidDidFormat(
        did = userInputDid,
        reason = validation.errorMessage()
    ))
}

3. Rate Limiting

Implement rate limiting to prevent abuse:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import io.github.bucket4j.Bucket
import io.github.bucket4j.Bucket4j

class RateLimitedTrustWeave(
    private val delegate: TrustWeave,
    private val bucket: Bucket
) {
    suspend fun issue(block: IssuanceBuilder.() -> Unit): IssuanceResult {
        if (!bucket.tryConsume(1)) {
            return IssuanceResult.Failure.InvalidRequest(
                field = "rateLimit",
                reason = "Rate limit exceeded"
            )
        }
        return delegate.issue(block)
    }
}

// Configure rate limiter
val bucket = Bucket4j.builder()
    .addLimit(Bandwidth.simple(100, Duration.ofMinutes(1)))
    .build()

Monitoring and Observability

1. Logging

Use structured logging:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import org.slf4j.LoggerFactory
import org.slf4j.MDC
import org.trustweave.credential.results.IssuanceResult
import org.trustweave.core.exception.TrustWeaveException

private val logger = LoggerFactory.getLogger(MyService::class.java)

suspend fun issueCredentialSample(...) {
    MDC.put("operation", "issue_credential")
    MDC.put("issuerDid", issuerDid.toString())

    logger.info("Issuing credential", mapOf(
        "issuerDid" to issuerDid.toString(),
        "holderDid" to holderDid
    ))

    when (val issued = trustWeave.issue { /* ... */ }) {
        is IssuanceResult.Success -> {
            logger.info("Credential issued successfully", mapOf(
                "credentialId" to issued.credential.id
            ))
            MDC.clear()
            return issued.credential
        }
        is IssuanceResult.Failure -> {
            val error = TrustWeaveException.InvalidState(
                message = issued.allErrors.joinToString("; "),
                context = emptyMap(),
                cause = null
            )
            logger.error("Failed to issue credential", mapOf(
                "errors" to issued.allErrors
            ), error)
            MDC.clear()
            throw error
        }
    }
}

2. Metrics

Collect metrics for key operations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Timer
import org.trustweave.credential.results.IssuanceResult
import org.trustweave.trust.TrustWeave
import org.trustweave.trust.dsl.credential.IssuanceBuilder

class MetricsTrustWeave(
    private val delegate: TrustWeave,
    private val registry: MeterRegistry
) {
    suspend fun issue(block: IssuanceBuilder.() -> Unit): IssuanceResult {
        val sample = Timer.start(registry)
        val result = delegate.issue(block)
        sample.stop(registry.timer("trustweave.issue.duration"))
        when (result) {
            is IssuanceResult.Success ->
                registry.counter("trustweave.issue.success").increment()
            is IssuanceResult.Failure ->
                registry.counter("trustweave.issue.error", "code", "issuance_failure").increment()
        }
        return result
    }
}

3. Health Checks

Implement health checks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import org.springframework.boot.actuate.health.Health
import org.springframework.boot.actuate.health.HealthIndicator
import org.trustweave.testkit.services.*

class TrustWeaveHealthIndicator(
    private val trustWeave: TrustWeave
) : HealthIndicator {

    override fun health(): Health {
        return try {
            runBlocking {
                // Test DID creation
                val testDid = trustWeave.createDid {
                    method(KEY)
                    algorithm(ED25519)
                }

                Health.up()
                    .withDetail("status", "operational")
                    .withDetail("testDid", testDid)
                    .build()
            }
        } catch (error: Exception) {
            Health.down()
                .withDetail("status", "unavailable")
                .withDetail("error", error.message)
                .withException(error)
                .build()
        }
    }
}

Deployment Checklist

Before deploying to production:

  • Use production-grade KMS (AWS KMS, Azure Key Vault, etc.)
  • Configure persistent storage for wallets and trust registry
  • Use production blockchain networks (mainnet)
  • Enable trust registry and trust checking
  • Implement comprehensive error handling
  • Add retry logic for transient errors
  • Configure connection pooling
  • Implement caching for frequently accessed data
  • Use environment variables for secrets
  • Implement input validation
  • Add rate limiting
  • Configure structured logging
  • Set up metrics collection
  • Implement health checks
  • Configure monitoring and alerting
  • Set up backup and disaster recovery
  • Document runbooks and procedures
  • Perform load testing
  • Review security configuration
  • Test error scenarios
  • API Patterns](api-patterns.md) - Correct API usage patterns
  • Error Handling](../advanced/error-handling.md) - Detailed error handling guide
  • Performance](../advanced/performance.md) - Performance optimization guide
  • Security](../security/README.md) - Security best practices
  • Troubleshooting](troubleshooting.md) - Common issues and solutions

This site uses Just the Docs, a documentation theme for Jekyll.