0048: Swappable Storage Adapters for Book-Keeper
Date: 2025-11-22
Status: Accepted
Service: book-keeper
Context
The Book-Keeper service has two critical storage needs:
- Event Store: Persisting the stream of immutable events that represent the complete audit trail of all financial state changes
- Ledger Storage: High-speed transaction processing for the double-entry bookkeeping system
Different deployment scenarios have vastly different requirements:
- Development/Small-scale: Simple setup, low operational overhead, acceptable performance (hundreds of TPS)
- Production/High-scale: Extreme throughput (tens of thousands of TPS), financial-grade safety guarantees, specialized features
Committing to a single storage technology upfront would either over-complicate initial deployments or create a costly migration path for scaling.
Decision
We will implement a swappable, adapter-based architecture for all write-side storage, allowing the specific technology to be chosen via configuration without code changes.
Event Store Strategy
- Interface:
IEventStoreinterface defines the contract for saving and retrieving event streams - Default Implementation: PostgreSQL table as event store (strong transactional guarantees, simple stack)
- High-Throughput Option: KurrentDB adapter using
kurrentdbclientlibrary (dedicated event sourcing features)
Ledger Storage Strategy
- Interface:
ILedgerStorageServiceinterface defines the contract for financial transaction operations - Default Implementation:
PostgresLedgerAdapterusing standard SQL transactions - High-Performance Option:
TigerBeetleLedgerAdapterfor extreme throughput and financial-grade safety
Configuration examples:
# Simple deployment
EVENT_STORE_ADAPTER: postgres
LEDGER_ADAPTER: postgres
# High-performance deployment
EVENT_STORE_ADAPTER: kurrentdb
LEDGER_ADAPTER: tigerbeetle
Consequences
Positive
- Deployment Flexibility: Start simple (PostgreSQL-only), scale up when needed without code changes
- Technology Independence: Core business logic is decoupled from infrastructure choices
- Performance Optimization: Can choose best-in-class storage for each component independently
- Future-Proofing: Easy to add new adapters (e.g., EventStoreDB, custom solutions) without disrupting existing code
Negative
- Complexity: Need to maintain multiple adapter implementations and ensure feature parity
- Testing Burden: Must test against all supported adapters to ensure compatibility
- Abstraction Overhead: Interface must be general enough to accommodate different technologies, potentially limiting access to vendor-specific features
Neutral
- Configuration Management: Requires proper environment-specific configuration management
- Adapter Maturity: Not all adapters may have the same level of production readiness (PostgreSQL is most battle-tested)
Related ADRs
- ADR-0002: Swappable Infrastructure via Adapters - Platform-wide pattern