Interface
Angular front end
14 screens, signals, no UI library
Technical overviewBackend engineering and financial systems
The finance module of an ERP, where the bookkeeping rules hold when requests are retried, raced, or malformed.
Source code
The repository is private. The architecture, engineering decisions, and verified evidence are documented below.
01
A double-entry general ledger in C# on .NET 10, with receivables, period close, bank reconciliation, and financial reports on top of it, an Angular front end, and SQL Server underneath. Every entry balances, the journal is append-only, and balances are derived from it. Each guarantee that depends on concurrency has a test that was run with the protecting code removed and seen to fail.
02
Interface
14 screens, signals, no UI library
Entry point
One button per role
Routing
Rate limits keyed on the visitor’s address
Web server
Serves the build, proxies /api, strict CSP
Service
Minimal endpoints, problem details with stable codes
Business logic
Every bookkeeping rule, no dependencies
Background job
Claims statements from a queue table with a lease
Database
decimal(19,4), check constraints, filtered unique indexes
Scheduled job
Drops, migrates and reseeds the demo books
03
Idempotency keys race on a unique constraint, posts and a period close meet on a shared lock taken with HOLDLOCK, and invoices carry a rowversion token against double issue and overpayment. Posts never conflict with each other, only with a close, so the lock costs nothing in the common case.
Whoever drafted an invoice cannot issue it, even holding both roles. A route policy says what a role may do; only the domain knows who drafted, so the rule lives there and answers 403 segregation_of_duties.
The number is taken inside the issuing transaction, so a failed issue gives its number back and the sequence has no gaps. A database sequence would not block, and it would leave gaps an auditor asks about. Issues serialise on that row.
Nothing stores a balance. The entry date is copied onto each line under a foreign key on the pair, so the copy cannot drift, and a balance becomes one index range seek starting from the totals frozen at the last close.
04
$ dotnet test
Ledger.Domain.Tests 113 passed
Ledger.Api.Tests 109 passed · SQL Server 2022 in a container
$ POST /journal-entries (same Idempotency-Key, twice)
201 Created · then 200 with Idempotent-Replay: true
✓ one entry posted, trial balance in balance05