WatchLedger
Problem
Event-sourced portfolio tracker built on CQRS. Every trade and price update is appended as an immutable event; read models (holdings, performance) are projections rebuilt from the event log rather than mutated in place, giving full historical auditability.
Constraints
- -Historical price data grows unbounded β queries against it must stay fast without manual archiving
- -Read models must be derivable purely by replaying the event log, never mutated directly
- -Financial calculations (IRR, CAGR, appreciation rate) must be correct against arbitrary buy/sell event sequences
Architecture
Commands are validated and appended to an append-only event log via Watermill message routing over NATS. Projections subscribe to the event stream and rebuild CQRS read models (current holdings, historical performance) on every new event. PostgreSQL stores both the event log and the projected read models, with table partitioning on historical price data to keep time-range queries fast as the log grows. gRPC exposes the command and query APIs.
Tech Choices & Why
Event sourcing + CQRS
An immutable event log gives full audit history for every trade and price change, and lets read models be rebuilt or corrected by replaying events.
Watermill
Go message-routing library providing command/event bus plumbing between the write side (commands) and the read side (projections) without a heavier framework.
PostgreSQL table partitioning
Historical price data is append-heavy and time-ordered β partitioning keeps range queries fast as the dataset grows.
Key Metrics
Architecture
CQRS + Event Sourcing
Stack
Go + NATS + Postgres
Data
Partitioned Time Series
Challenges & Solutions
Problem
Read models need to reflect every historical trade and price update without direct mutation, while staying fast to query.
Solution
CQRS projections are rebuilt from the append-only event log via Watermill-routed events; PostgreSQL table partitioning on historical price data keeps read-side queries fast.
Problem
Financial calculations like IRR and CAGR need to be correct for arbitrary sequences of buy/sell events, not just simple buy-and-hold.
Solution
IRR, CAGR, and appreciation-rate figures are derived directly from the replayed event stream rather than from a mutable running balance, so out-of-order corrections replay correctly.
Trade-offs
- ~Event sourcing adds complexity versus a simple CRUD ledger β justified here by the audit-trail and replay requirements.
- ~Rebuilding projections from the full event log is more expensive than a mutable table, offset by only replaying on schema changes or corrections.
Impact
Demonstrates a CQRS + event-sourcing architecture in Go: an append-only event log, replayable projections, and partitioned time-series storage for financial calculations (IRR, CAGR, appreciation rate) with full historical auditability.
What I'd Improve
- +Add snapshotting to avoid full event-log replay for accounts with long histories
- +Add multi-currency cost-basis tracking
This project was reviewed by Luka (Principal Research Consultant) and Nala (UI/UX Compliance Auditor). They had no comments, which we interpret as approval.