Payment Ledger
A personal ASP.NET Core API for double-entry balances: JWT auth, Postgres, idempotent transfers, HMAC-signed webhooks, and an outbox worker that posts deposits after accept.
- Role
- Personal project
- Year
- 2026
- Links
- GitHub
- Stack
- C#
- ASP.NET Core
- EF Core
- PostgreSQL
- JWT
- Serilog
- OpenTelemetry
- Docker
Context
I wanted a clean place to practice money-correctness patterns outside client work: journal entries that must balance, idempotent transfer keys, optimistic concurrency on account balances, and reliable webhook intake without doing the side effect in the request path.
What I built
Clean architecture across Domain, Application, Infrastructure, and Api projects on ASP.NET Core 10 and EF Core with Postgres. Transfers run in one transaction with Postgres xmin optimistic concurrency; inbound webhooks verify HMAC, return 202, and an outbox worker claims rows with FOR UPDATE SKIP LOCKED, backs off, then dead-letters. Serilog logging plus optional OpenTelemetry metrics.
Details
- Double-entry journal: money stored as integer minor units; every entry's lines must sum to zero
- Idempotent transfers via Idempotency-Key: same key and body replays the response; same key and different body returns 422
- HMAC-signed webhook intake with an outbox worker for deposits into a seeded system clearing account
- Health checks, Serilog, and OpenTelemetry meters for transfers, webhooks, and outbox lag
- Integration tests with Testcontainers when Docker is available
Status
Open source at github.com/mgiwa78/payment-ledger.