Event-driven digital wallet & immutable ledger backend — built as a hands-on system design project to learn the patterns used in real fintech infrastructure (Razorpay, Juspay, Stripe): atomic transactions, idempotency, event-driven architecture, and reconciliation.
Most toy wallet projects do this:
User clicks "Send Money" → UPDATE balance → Done
LedgerX does this instead:
Transfer Request
↓
Authentication
↓
Idempotency Check
↓
Row-Level Lock + DB Transaction
↓
Immutable Ledger Entries (never updated/deleted)
↓
Commit
↓
Publish Event (RabbitMQ)
↓
Webhook Dispatch (BullMQ, retries + backoff)
↓
Reconciliation Worker (catches its own inconsistencies)
Core principle: there is no Balance table. A wallet's balance is never stored — it's always SUM(credits) − SUM(debits), computed from an append-only ledger and cached with explicit invalidation. This is how real accounting/ledger systems work, and it eliminates an entire category of bugs where a cached balance and the actual transaction history silently drift apart.
Client
│
REST API (Express)
│
Auth Middleware (JWT)
│
┌────────────┼────────────┐
│ │ │
Wallet Service Transaction Ledger Service
│ Service │
│ │ │
└────────────┼────────────┘
│
Idempotency Layer (Redis)
│
PostgreSQL (Prisma 7)
- Ledger (append-only)
- Transaction
- Wallet
│
Event Publisher (RabbitMQ, durable)
│
┌────────────────┼────────────────┐
│ │ │
Webhook Consumer BullMQ Workers Reconciliation
(retries + backoff) (background) Worker (cron)
| Layer | Choice | Why |
|---|---|---|
| Language | TypeScript | Strict typing across financial logic |
| Framework | Express.js | Full architectural control |
| Database | PostgreSQL | ACID transactions + row-level locking |
| ORM | Prisma 7 | Driver adapters + raw SQL where needed |
| Auth | JWT + bcrypt | Secure authentication |
| Validation | Zod | Runtime validation |
| Cache / Locks | Redis | Idempotency + balance caching |
| Background Jobs | BullMQ | Retryable async processing |
| Messaging | RabbitMQ | Durable event publishing |
| Logging | Pino | Structured JSON logging |
| Testing | Jest + Supertest | Automated integration tests |
| Containers | Docker Compose | Local infrastructure |
- User signup/login
- JWT authentication
- Secure password hashing with bcrypt
- Wallet creation
- Atomic deposits
- Atomic transfers
- Append-only ledger
- Balance computed from ledger entries
SELECT ... FOR UPDATE- Prevents race conditions
- Concurrent transfer protection
- Redis-backed idempotency keys
- Duplicate request prevention
- Safe retries
- RabbitMQ event publishing
- BullMQ webhook workers
- Exponential retry
- Background consistency checks
- Admin reconciliation endpoint
- ACID rollback guarantees
- Compensating transactions
- Immutable history
- Cache-aside pattern
- Explicit invalidation
- Safe balance computation
- Money stored as integer values (paise/cents)
- No floating point arithmetic
- Environment-driven configuration
- Zod validation for all configuration
- Balance never stored directly
- Generic authentication error messages for security
src/
modules/
auth/
wallet/
transaction/
ledger/
webhook/
reconciliation/
admin/
common/
config/
prisma/
schema.prisma
cp .env.example .env
docker compose up -d
npm install
npx prisma migrate dev
npm run dev
npm test| Variable | Purpose |
|---|---|
| DATABASE_URL | PostgreSQL connection |
| REDIS_URL | Redis connection |
| RABBITMQ_URL | RabbitMQ connection |
| JWT_SECRET | JWT signing secret |
| JWT_EXPIRES_IN | Token expiry |
| BCRYPT_SALT_ROUNDS | Password hashing |
| IDEMPOTENCY_LOCK_TTL_SECONDS | Lock lifetime |
| IDEMPOTENCY_RESPONSE_TTL_SECONDS | Cached response lifetime |
| WEBHOOK_MAX_RETRIES | Retry count |
| WEBHOOK_BACKOFF_DELAY_MS | Retry delay |
| RECONCILIATION_GRACE_PERIOD_MS | Reconciliation timing |
| RECONCILIATION_INTERVAL_MS | Worker schedule |
| BALANCE_CACHE_TTL_SECONDS | Cache TTL |
| RABBITMQ_EXCHANGE | Exchange name |
npm testTests include:
- Authentication
- Wallet ownership
- Atomic deposits
- Atomic transfers
- Concurrent transfer race conditions
- Idempotency
- Rollback
- Transaction reversal
- Webhook retries
- Reconciliation
- Interactive Swagger/OpenAPI documentation
- Production deployment
- Docker image
- Frontend dashboard
Built to deeply understand ACID transactions, immutable ledger design, concurrency control, idempotency, event-driven architecture, webhook delivery, reconciliation, and distributed systems concepts commonly used in modern payment infrastructure.