Skip to main content

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:

  1. Event Store: Persisting the stream of immutable events that represent the complete audit trail of all financial state changes
  2. 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: IEventStore interface 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 kurrentdbclient library (dedicated event sourcing features)

Ledger Storage Strategy

  • Interface: ILedgerStorageService interface defines the contract for financial transaction operations
  • Default Implementation: PostgresLedgerAdapter using standard SQL transactions
  • High-Performance Option: TigerBeetleLedgerAdapter for 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)