Subsystem 01
Transaction gateway
Idempotency key validation and balance checks
Typical stack
Go (Gin) or Rust (Axum) service
Reference architecture
An immutable double-entry ledger where every posting balances, a retried request never posts twice, and any account's history can be replayed for auditors.
Design constraints
Targets for the scenario this reference is sized for. A real engagement starts by replacing them with your own numbers.
Component topology
Subsystems with separate responsibilities, clear contracts between them and storage that scales on its own. The stack named for each is typical, not mandatory.
Stack topology
Double-entry financial ledger with event sourcing and Kafka
Illustrative reference architecture
Transaction gateway
Idempotency key validation and balance checks
Go (Gin) or Rust (Axum) service
Immutable event stream
Ordered, durable transaction log partitioned by account_id
Apache Kafka / Confluent Cloud
Ledger storage engine
Append-only double-entry ledger entries and account balances
PostgreSQL with strict constraint triggers
Read model projector
Live account balance projections for the customer UI
Redis in-memory key-value store
Subsystem 01
Idempotency key validation and balance checks
Typical stack
Go (Gin) or Rust (Axum) service
Subsystem 02
Ordered, durable transaction log partitioned by account_id
Typical stack
Apache Kafka / Confluent Cloud
Subsystem 03
Append-only double-entry ledger entries and account balances
Typical stack
PostgreSQL with strict constraint triggers
Subsystem 04
Live account balance projections for the customer UI
Typical stack
Redis in-memory key-value store
Data lifecycle
The payment client submits a transaction with an Idempotency-Key header to the transaction gateway.
The gateway checks Redis for that key; if it hasn't been processed, it reserves a pending lock.
The transaction is validated against double-entry rules and published to an account-partitioned Kafka topic.
The ledger consumer writes an append-only record to PostgreSQL inside a single ACID transaction.
The balance projector updates the cached Redis balance, and the confirmation goes back to the caller.
Reliability and resilience
Failure mode 01
Mitigation
Use PostgreSQL row-level locks (SELECT … FOR UPDATE) or optimistic version numbers on balance rows.
Failure mode 02
Mitigation
Put a UNIQUE constraint on the idempotency_key column, keep keys for a retention window (for example 24 hours) and purge expired ones with a scheduled job.
Failure mode 03
Mitigation
Keep monotonic sequence IDs per account and raise a reconciliation alert on any gap.
Questions
Event sourcing keeps the full history of every money movement, so any account's state at any point in time can be rebuilt for an audit or a dispute.
The ledger is append-only, so a mistake is corrected by posting a compensating journal entry, never by editing the original record.
Send us your requirements, expected load and budget. We'll reply within one business day with an honest read on the design, and on whether we're the right team to build it.