High-integrity financial transaction engine implementing Double-Entry Ledger patterns, ACID compliance, and Pessimistic Locking to prevent double-spending race conditions.
sequenceDiagram
participant Client
participant API
participant DB as Database (Postgres)
Client->>API: POST /transfer (User A -> User B)
rect rgb(20, 20, 20)
note right of API: Start Database Transaction
API->>DB: BEGIN
note right of API: 1. Prevent Deadlock (Sort IDs)
note right of API: 2. Acquire Locks (SELECT FOR UPDATE)
API->>DB: SELECT * FROM users WHERE id IN (A, B) FOR UPDATE
DB-->>API: Locked User Data
note right of DB: 🔒 Rows A & B are now LOCKED
API->>API: 3. Verify Balance (Invariant Check)
API->>DB: UPDATE users SET balance = balance - amount WHERE id = A
API->>DB: UPDATE users SET balance = balance + amount WHERE id = B
API->>DB: INSERT INTO transactions ...
API->>DB: COMMIT
note right of DB: 🔓 Locks Released
end
DB-->>API: Transaction Committed
API-->>Client: 200 OK (Transfer Complete)
Most “Wallet APIs” fail when subjected to:
This project solves these problems using Database-Level Constraints and Explicit Locking Strategies.
Uses SELECT ... FOR UPDATE (Pessimistic Locking) to lock the payer and payee rows during the transaction.
All transfers run within a single Database Transaction.
Locks are acquired in a deterministic order (by ID), preventing circular waits.
Lock(A) -> Lock(B) is safe.Lock(A) -> Lock(B) AND Lock(B) -> Lock(A) (simultaneously) causes deadlocks. We force ID-based ordering to solve this.docker-compose up -d
Create the .env file with database connection strings.
cp .env.example .env
npm install
npm run db:migrate
This will run concurrency stress tests (Race Condition & Deadlock scenarios).
npm test
Gérson Resplandes Backend Engineer focused on Data Integrity & System Design.