DBRaven
Full ReviewModerate Readinessdraft

Architecture Review: Financial Ledger Platform

A strict consistency financial architecture for double-entry accounting, payment processing, and audit trail management where every debit must have a corresponding credit, every state transition must be ordered and durable, and the complete history must be reconstructable without gaps. Event sourcing provides an append-only audit log; the outbox pattern guarantees at-least-once downstream event delivery without distributed two-phase commit (idempotent consumers deduplicate on event ID for effectively-once processing); PostgreSQL provides ACID guarantees for ledger entry atomicity.

Evidence Confidence

Moderate

strong

Executive Summary

Financial Ledger Platform: moderate operational readiness (81% evidence confidence). 6 architectural strengths identified, 4 operational risks to manage. Primary concern: Lock Contention. Requires Advanced operational maturity.

Readiness Rationale

Overall moderate readiness across 8 dimensions. Limited: team maturity. Strong: migration, observability, failure recovery.

Key Concerns

  • !Lock Contention
  • !Split-Brain

Key Strengths

  • +The outbox pattern eliminates split-brain between a database write and a message broker publish by writing both the domain record…
  • +Financial transaction workloads benefit from event sourcing because the event log provides an immutable audit trail, enables…
  • +Write-heavy transactional workloads that emit downstream events (order placed, payment captured) benefit from the outbox pattern…
  • +PostgreSQL serves as a capable event store for moderate event volumes, leveraging JSONB payloads, UNIQUE constraints for…

8

Assessments

4

Tradeoffs

6

Sections

11

Recommendations

Readiness Assessments

8

Architectural Tradeoffs

4

Recommendations

11
High

Monitor: Lock Contention

risk_monitoring

Concurrent writers to the same rows serialize behind each other's row locks, so latency is set not by the work a transaction does but by how long it waits for the writers ahead of it. On a hot row the queue depth, and therefore the tail latency, grows with concurrency while throughput flattens. Blocked writers hold connections open, so a single contended row can drain the connection pool as a secondary failure.

Affects 1 node. (Write-Heavy Transactional)

High

Monitor: Split-Brain

risk_monitoring

A failover mechanism promotes a new leader without confirming the old one has stopped, so two nodes simultaneously believe they hold the primary role and both accept writes. The two histories diverge, and when the partition that triggered the failover heals, one set of committed transactions must be discarded.

Affects 1 node. (Two-Phase Commit (2PC)). 1 mitigation identified

High

Implement: Monitor generic risk probe signals

observability

Seed 'Lock Contention Risk Probe' identifies 2 metrics relevant to lock_contention.

Metrics to instrument: error_rate, p95_latency_ms

Moderate

Mutable account balance table with no event history → Event sourced ledger with append-only events and projected balance view

migration_planning

Trigger: Audit requirement to reconstruct account state at any historical point in time; compliance requirement for complete transaction history; inability to explain why a balance is what it is from current state alone. Migrate from 'Mutable account balance table with no event history' to 'Event sourced ledger with append-only events and projected balance view'. Bootstrap historical state as a single "initial_balance" event per account. Run the event-sourced model in parallel with the mutable model for 30 days before decommissioning the mutable path.

Historical event reconstruction is only possible from the migration cutover date: pre-migration history must be bootstrapped as initial balance events; Projected balance views must be kept consistent with the event log; any discrepancy indicates a bug that must be caught in testing

Moderate

Synchronous Kafka publish in transaction (dual-write pattern) → Outbox pattern with CDC relay to Kafka

migration_planning

Trigger: Kafka publish failures causing financial transaction rollbacks; or Kafka publish succeeding but transaction rolling back, causing phantom events downstream. Migrate from 'Synchronous Kafka publish in transaction (dual-write pattern)' to 'Outbox pattern with CDC relay to Kafka'. The outbox pattern is non-negotiable for financial systems. The synchronous dual-write is an anti-pattern that creates phantom events on rollback.

Outbox relay introduces a delivery lag (typically < 5s); downstream consumers must handle this eventual delivery, not assume synchronous availability; Relay stall must trigger an immediate operational alert: unmonitored stall is a consistency incident

Moderate

Prepare runbook for: Burst Traffic Cold Cache Stampede

simulation_preparedness

Simulation demonstrates critical degradation of redis, postgresql

Without a runbook, recovery from this failure mode will be ad-hoc

burst-traffic-cold-cache-stampede
Moderate

Prepare runbook for: Connection Pool Exhaustion with Horizontal User Scale

simulation_preparedness

Simulation demonstrates critical degradation of postgresql

Without a runbook, recovery from this failure mode will be ad-hoc

connection-pool-growth-with-user-scale
Moderate

Plan evolution: OLTP Analytics Queries → OLTP + OLAP Separation

evolution_planning

Evolution from Unified OLTP + Analytics on PostgreSQL → Separated OLTP (PostgreSQL) + OLAP (ClickHouse/Snowflake)

Migration complexity: medium. Rollback: always.

oltp-analytics-to-separated
Moderate

Plan evolution: PostgreSQL → Partitioned PostgreSQL

evolution_planning

Evolution from Single-Node PostgreSQL → Partitioned PostgreSQL

Migration complexity: high. Rollback: rarely.

postgresql-to-partitioned
Low

Monitor threshold: Tier 1: Hot Account Lock Contention

scaling_monitoring

Signal: pg_locks shows contended rows on accounts table; write p99 > 50ms; deadlock errors in application logs; pg_stat_activity showing many transactions waiting for RowExclusiveLock on the same account rows

Bottleneck: Concurrent debit/credit transactions competing for the same account row versions. Evolution: Implement optimistic locking with version column and retry; or queue concurrent updates for the same account entity through an account-scoped serialization queue at the application layer; or partition the accounts table by account range

Low

Monitor threshold: Tier 2: Synchronous Replication Write Latency

scaling_monitoring

Signal: Write p99 > 100ms with synchronous_commit = remote_apply; replica WAL apply lag visible in pg_stat_replication; network jitter between primary and replica causing write latency spikes correlating with replication ACK delays

Bottleneck: Synchronous replication write-ahead wait amplifying network latency for every committed transaction. Evolution: Co-locate primary and replica in the same availability zone for lowest replication RTT; tune wal_sender_timeout and recovery_min_apply_delay; evaluate whether synchronous_commit = on (durable to primary WAL only) is acceptable for your regulatory risk model

Scaling Pressure Signals

8

pg_locks shows contended rows on accounts table; write p99 > 50ms; deadlock errors in application logs; pg_stat_activity showing many transactions waiting for RowExclusiveLock on the same account rows

Threshold

Tier 1: Hot Account Lock Contention

Likely Bottleneck

Concurrent debit/credit transactions competing for the same account row versions

Recommended Evolution

Implement optimistic locking with version column and retry; or queue concurrent updates for the same account entity through an account-scoped serialization queue at the application layer; or partition the accounts table by account range

Write p99 > 100ms with synchronous_commit = remote_apply; replica WAL apply lag visible in pg_stat_replication; network jitter between primary and replica causing write latency spikes correlating with replication ACK delays

Threshold

Tier 2: Synchronous Replication Write Latency

Likely Bottleneck

Synchronous replication write-ahead wait amplifying network latency for every committed transaction

Recommended Evolution

Co-locate primary and replica in the same availability zone for lowest replication RTT; tune wal_sender_timeout and recovery_min_apply_delay; evaluate whether synchronous_commit = on (durable to primary WAL only) is acceptable for your regulatory risk model

Evidence:kafka-consumer-lag-cascadepartition-hotspot-amplification

PostgreSQL WAL volume > 500MB/minute sustained; event sourcing table growing faster than VACUUM can reclaim; wal_buffers flushing > 2x per second; I/O utilization on WAL volume > 80%

Threshold

Tier 3: Event Log Volume and WAL Saturation

Likely Bottleneck

Event sourcing append rate combined with balance projection writes saturating WAL throughput

Recommended Evolution

Move WAL to a dedicated NVMe volume; tune checkpoint_completion_target to 0.9; partition the events table by time range (monthly partitions) to bound per-partition VACUUM scope; evaluate whether the balance projection can be computed lazily (on read) rather than maintained eagerly (on write)

PostgreSQL primary sustaining > 3000 TPS on financial transactions; write p99 > 200ms despite I/O and pool optimization; audit event table exceeding 1 billion rows

Threshold

Tier 4: Single-Primary Throughput Ceiling

Likely Bottleneck

Single PostgreSQL primary write throughput ceiling for ACID transactional workloads

Recommended Evolution

Evaluate domain partitioning by currency, region, or account range across multiple PostgreSQL primaries with saga-based cross-shard coordination; or evaluate CockroachDB for distributed ACID writes with global consistency guarantees

pg_locks shows contended rows on accounts table; write p99 > 50ms; deadlock errors in application logs; pg_stat_activity showing many transactions waiting for RowExclusiveLock on the same account rows

Threshold

Escalation trigger: Concurrent debit/credit transactions competing for the same account row versions

Likely Bottleneck

Tier 1: Hot Account Lock Contention

Recommended Evolution

Monitor: error_rate, p95_latency_ms

Write p99 > 100ms with synchronous_commit = remote_apply; replica WAL apply lag visible in pg_stat_replication; network jitter between primary and replica causing write latency spikes correlating with replication ACK delays

Threshold

Escalation trigger: Synchronous replication write-ahead wait amplifying network latency for every committed transaction

Likely Bottleneck

Tier 2: Synchronous Replication Write Latency

Recommended Evolution

Monitor: error_rate, p95_latency_ms

PostgreSQL WAL volume > 500MB/minute sustained; event sourcing table growing faster than VACUUM can reclaim; wal_buffers flushing > 2x per second; I/O utilization on WAL volume > 80%

Threshold

Escalation trigger: Event sourcing append rate combined with balance projection writes saturating WAL throughput

Likely Bottleneck

Tier 3: Event Log Volume and WAL Saturation

Recommended Evolution

Monitor: error_rate, p95_latency_ms

PostgreSQL primary sustaining > 3000 TPS on financial transactions; write p99 > 200ms despite I/O and pool optimization; audit event table exceeding 1 billion rows

Threshold

Escalation trigger: Single PostgreSQL primary write throughput ceiling for ACID transactional workloads

Likely Bottleneck

Tier 4: Single-Primary Throughput Ceiling

Recommended Evolution

Monitor: error_rate, p95_latency_ms

Migration Readiness

12

Migration Stages

3
Stage

Mutable account balance table with no event history → Event sourced ledger with append-only events and projected balance view

info

Migration trigger: Audit requirement to reconstruct account state at any historical point in time; compliance requirement for complete transaction history; inability to explain why a balance is what it is from current state alone

Stage

Synchronous Kafka publish in transaction (dual-write pattern) → Outbox pattern with CDC relay to Kafka

info

Migration trigger: Kafka publish failures causing financial transaction rollbacks; or Kafka publish succeeding but transaction rolling back, causing phantom events downstream

Stage

Single PostgreSQL primary serving all reads and writes → CQRS with separate read model and write model

info

Migration trigger: Financial dashboard query p99 > 500ms causing dashboard-driven I/O competing with write transactions; reporting queries running against the primary during month-end close causing write latency spikes

!

Risks

9
Risk

Historical event reconstruction is only possible from the mi

warning

Historical event reconstruction is only possible from the migration cutover date: pre-migration history must be bootstrapped as initial balance events

Risk

Projected balance views must be kept consistent with the eve

warning

Projected balance views must be kept consistent with the event log; any discrepancy indicates a bug that must be caught in testing

Risk

Outbox relay introduces a delivery lag (typically < 5s); dow

warning

Outbox relay introduces a delivery lag (typically < 5s); downstream consumers must handle this eventual delivery, not assume synchronous availability

Risk

Relay stall must trigger an immediate operational alert: unm

warning

Relay stall must trigger an immediate operational alert: unmonitored stall is a consistency incident

Risk

Read model is eventually consistent: dashboards may show sli

warning

Read model is eventually consistent: dashboards may show slightly stale balances during high write periods

Risk

Read model must be reconciled with write model periodically

warning

Read model must be reconciled with write model periodically to detect projection drift

Risk

Cross-service workflows that previously used database transa

critical

Cross-service workflows that previously used database transactions now require Saga orchestration. Mitigation: Design idempotent event handlers; implement compensating transactions for every multi-step workflow; test failure injection in staging

modular-monolith-to-event-driven

Risk

Consumer lag silently accumulates: a lagging consumer is not

critical

Consumer lag silently accumulates: a lagging consumer is not a failed consumer. Mitigation: Alert on consumer lag rate-of-change, not absolute depth; implement dead letter queues with alerting

modular-monolith-to-event-driven

Risk

Missing partition for current time window causes all INSERTs

critical

Missing partition for current time window causes all INSERTs to fail with 'no partition of relation found'. Mitigation: Create partitions 7-30 days in advance; alert when next partition does not exist before its time window opens

postgresql-to-partitioned

Review Sections

6

Referenced Intelligence

kafkapostgresqlburst-traffic-cold-cache-stampedeconnection-pool-growth-with-user-scalecqrs-projection-lag-expansioncross-region-stale-read-windowdistributed-cache-invalidation-failureevent-replay-storm-recoverykafka-consumer-lag-cascademulti-tenant-noisy-neighborpartition-hotspot-amplificationpostgresql-replication-lag-surgequery-cost-without-indexesread-amplification-n-plus-one-queriesredis-cache-collapse-stampederetry-storm-amplificationsplit-brain-during-network-partitionstorage-bloat-without-archivingstorage-cost-compounding-without-retentionwrite-heavy-bulk-import-saturationmodular-monolith-to-event-drivenoltp-analytics-to-separatedpostgresql-to-partitionedrabbitmq-to-kafkasingle-region-to-multi-regionarchitecture-evolutionauditabilitybtree-indexingcache-invalidationcap-theoremconsistency-modelscqrs-operationalevent-sourcingeventual-consistencykafka-consumer-lagmulti-tenancynormalizationoltp-vs-olappartition-hotspotsquery-planningqueue-backlogreplication-lagvector-databaseswrite-amplification
Architecture Review: Financial Ledger Platform: DBRaven