Designing Accounting Transactions as First-Class Domain Events

MehulRastogi1 pts0 comments

Designing Accounting Transactions as First-Class Domain Events | AngelList

Sign inContact sales

Blog<br>Category<br>Engineering<br>Written by

Mehul Rastogi<br>Software Engineer

Copied link

Blog

EngineeringDesigning Accounting Transactions as First-Class Domain Events<br>Jul 8, 2026 — 20 min read

Written by

Mehul Rastogi<br>Software Engineer

Copied link

If you've never had to build a fund accounting system, it sounds like the most boring software on earth. Money comes in from LPs. Money goes out to startups. A spreadsheet, basically, with stricter formatting and a quarterly statement at the end. Slow, conservative, mostly addition.<br>It isn't.<br>A year after the fund wires $500k into a startup, the company raises a Series A and that original investment converts into 120,000 shares of preferred stock. Six months later a stock split quintuples the share count. Then a competitor acquires part of the company in a share swap, leaving the fund holding pieces of two companies. A special dividend gets paid. Some shares get sold in a secondary round. The company IPOs. And finally the fund returns the remaining proceeds to its investors in cash.<br>Seven economic events. One investment. Every one of them has to land in the same books, balance to the penny, and still make sense two years later when an auditor pulls on the thread.<br>The instinct that mostly works<br>The natural way to build a fund accounting system is the way an accountant would build it on paper. Every event becomes a journal entry. You read off the debits and credits, post them to the general ledger, and reconcile at period end. The general ledger (GL) is what auditors actually verify, what GAAP defines down to the account, where the trial balance has to net to zero. Make it the source of truth in your code and you've matched five hundred years of practice.<br>The instinct holds up for a while. The wire-out is two lines, the dividend is two lines, the interest accrual is two lines. You learn the mapping in your head, the system stays legible, and at twenty event types it really does feel like the GL is enough.<br>The catch is that the ledger captures motion, not meaning. It records that cost basis moved from one asset to another, but not that it moved because a SAFE converted into preferred, or because the company was partially acquired in a stock-for-stock deal, or because of a non-taxable reorganization. Those are wildly different events. The ledger flattens them into the same shape. Mix them up, say, handle a stock split as if it were a sale, or a SAFE conversion as if it were a dividend, or an in-kind distribution as if it were cash, and the books fail in different, expensive ways. A 9x phantom gain. Income that was never earned. Cost basis consumed twice. Each is the kind of bug that costs three engineers a weekend to unwind and an accountant a quarter to trust the numbers again. The GL knows what moved. It can't tell you why.<br>The first response is to bolt on discriminators: a memo column, a transaction-type field, a side table tagging each ledger entry with what kind of event produced it. The second response, once those drift out of sync with reality, is defensive reconstruction code that tries to recover the event type from the shape of the entries it left behind. You're now reverse-engineering meaning from movement, two years after the fact, because the meaning was never recorded anywhere.<br>Inverting the dependency<br>The fix is to invert the dependency.<br>Treat each event as an immutable domain object. The event itself is the source of truth, and the ledger is one of several projections derived from it. The event row says: this is a non-taxable partial reorganization of 30% of asset X into asset Y, effective on date D, recorded on date R. A handler attached to that event type writes the ledger entries and an asset metadata snapshot: the asset's unit count and descriptive facts like company name, investment type, and dates.<br>We named that domain object AccountingTransaction (AT for short). An accounting transaction is already a standard accounting concept - a measurable economic event that affects the financial statements - so the name isn't something we invented. The happy accident is that it also lines up with the database sense of transaction, and the parallels run deep. A database transaction commits a unit of work atomically; the database's current state is whatever its full sequence of transactions added up to. An AccountingTransaction lifts that same idea to the accounting layer. The write is atomic : the event, its metadata snapshot, and its ledger entries land inside one database transaction, or none of them do. The event itself is the record of what happened , a dated, dimensioned description of the corporate action, written once and not overwritten with a different story. The ledger and metadata are projections of that record : queryable, derivable, but not authoritative on their own. Corrections arrive the same way any other fact does, as a new event.<br>There are...

event ledger accounting domain events fund

Related Articles