How smyanverma/tradeledger works
Purpose and Runtime Entry Points
TradeLedger is a Django REST API for wallet funding and user-to-user money transfer. Its core guarantee is an immutable double-entry ledger, backed by derived wallet balances, idempotent requests, and database-level concurrency control.
HTTP starts through tradeledger/manage.py, Django routing in tradeledger/config/urls.py, and ASGI/WSGI deployment entry points in tradeledger/config/asgi.py and tradeledger/config/wsgi.py. Celery workers load the app from tradeledger/config/celery.py.
API Composition and Authentication
The project is organized as three Django apps: accounts, wallets, and ledger. Global URL routing delegates public API surfaces to app-specific routes:
• tradeledger/config/urls.py
• tradeledger/apps/accounts/urls.py
• tradeledger/apps/wallets/urls.py
• tradeledger/apps/ledger/urls.py
Accounts owns the custom user model and registration/login/profile APIs. JWT access and refresh tokens form the authentication boundary for wallet and ledger operations:
• tradeledger/apps/accounts/models.py
• tradeledger/apps/accounts/views.py
• tradeledger/apps/accounts/serializers.py
Registration creates a user and an initially empty wallet, linking identity provisioning to the wallet domain.
Wallet Domain and Funding Boundary
Wallets represent each user’s available balance. The balance is a cached/derived operational value rather than the authoritative financial record. Wallet APIs expose the caller’s wallet and a top-up endpoint; top-up is explicitly a demo/payment-gateway simulation boundary, not an external payment integration:
• tradeledger/apps/wallets/models.py
• tradeledger/apps/wallets/views.py
• tradeledger/apps/wallets/serializers.py
The wallet layer supplies the mutable balances that the transfer service updates atomically, while ledger entries provide auditability and source-of-truth history.
Ledger and Transfer Orchestration
The ledger app contains transactions, immutable debit/credit ledger entries, transfer APIs, statements, and the central money-movement service:
• tradeledger/apps/ledger/models.py
• tradeledger/apps/ledger/services.py
• tradeledger/apps/ledger/views.py
A transfer request identifies a receiving user, amount, narration, and client idempotency key. The service is the critical control boundary: it validates the operation, creates/reuses the transaction according to its database-enforced unique idempotency constraint, and records exactly two ledger entries—a sender DEBIT and receiver CREDIT—which net to zero.
Transaction Safety and Consistency
Transfer execution relies on PostgreSQL transactions and row locks. Sender and receiver wallets are selected with SELECT … FOR UPDATE in a stable order before balance reads or writes. This serializes competing debits, prevents overdrafts under races, and avoids lock-order deadlocks.
The database, migrations, and model constraints—not request-level caching or preflight checks—are the consistency authority:
• tradeledger/apps/ledger/migrations/0001_initial.py
• tradeledger/apps/wallets/migrations/0001_initial.py
• tradeledger/apps/accounts/migrations/0001_initial.py
Transaction-history and statement endpoints read the transaction and raw ledger-entry views separately, preserving the distinction between transfer-level records and accounting rows.
Asynchronous Notifications
After a completed transaction, notification work is dispatched outside the synchronous API response path through Celery:
• tradeledger/apps/ledger/tasks.py
• tradeledger/config/celery.py
• tradeledger/apps/ledger/services.py
This separates irreversible financial persistence from potentially slow notification delivery. Redis is the Celery broker/result backend and is also configured for Django caching.
Infrastructure and External Dependencies
Django 5 and Django REST Framework provide the API runtime; PostgreSQL provides locking, transactions, and durable constraints; Redis supports Celery and caching; SimpleJWT provides auth; drf-spectacular publishes OpenAPI/Swagger documentation. Docker Compose runs the web process, PostgreSQL, Redis, and Celery worker:
• tradeledger/docker-compose.yml
• tradeledger/Dockerfile
• tradeledger/config/settings.py
Main entry points: services.py Transfer service · docker-compose.yml Docker Compose · urls.py Global URL routing · views.py Transfer & statement API
Components 17
API & Identity
- Django entry points · CLI, ASGI, and WSGI start the API runtime.
tradeledger/manage.py - Global URL routing
tradeledger/config/urls.py - Accounts API · Registration, login, and profile endpoints.
tradeledger/apps/accounts/views.py - Custom user
tradeledger/apps/accounts/models.py - JWT authentication · Access and refresh tokens protect financial operations.
tradeledger/apps/accounts/serializers.py
Wallet & Ledger
- Wallet API · Exposes wallet balance and simulated top-up.
tradeledger/apps/wallets/views.py - Wallet balances · Mutable operational balances, not the accounting source of truth.
tradeledger/apps/wallets/models.py - Transfer & statement API · Transfer, transaction-history, and raw ledger-entry views.
tradeledger/apps/ledger/views.py - Transfer service · Atomically orchestrates idempotency, locking, balances, and double-entry posting.
tradeledger/apps/ledger/services.py - Transactions & entries · One transaction records paired DEBIT and CREDIT entries that net to zero.
tradeledger/apps/ledger/models.py - Schema constraints · Database-enforced idempotency and financial schema invariants.
tradeledger/apps/ledger/migrations/0001_initial.py
Async Delivery
- Celery runtime
tradeledger/config/celery.py - Transaction notifications · Runs after completed financial persistence.
tradeledger/apps/ledger/tasks.py
Runtime Infrastructure
- PostgreSQL · Durable authority for transactions, row locks, and constraints.
- Redis
- Application settings · Configures database, Redis cache, and runtime integrations.
tradeledger/config/settings.py - Docker Compose · Runs web, PostgreSQL, Redis, and Celery worker processes.
tradeledger/docker-compose.yml
Connections 26
- Django entry points → Global URL routing: serves
- Global URL routing → Accounts API: routes to
- Global URL routing → Wallet API: routes to
- Global URL routing → Transfer & statement API: routes to
- Accounts API → Custom user: creates and reads
- Accounts API → Wallet balances: provisions empty wallet
- JWT authentication → Wallet API: authorizes
- JWT authentication → Transfer & statement API: authorizes
- Wallet API → Wallet balances: reads and tops up
- Transfer & statement API → Transfer service: submits transfers
- Transfer & statement API → Transactions & entries: reads statements
- Transfer service → Wallet balances: locks and updates · Locks both wallets in stable order before balance changes.
- Transfer service → Transactions & entries: creates paired entries
- Transfer service → Schema constraints: relies on idempotency
- Wallet balances → PostgreSQL: persists in
- Transactions & entries → PostgreSQL: persists in
- Schema constraints → PostgreSQL: enforced by
- Transfer service → Transaction notifications: dispatches after completion
- Celery runtime → Transaction notifications: loads
- Transaction notifications → Redis: uses broker/backend
- Application settings → PostgreSQL: configures
- Application settings → Redis: configures cache
- Docker Compose → Django entry points: runs web
- Docker Compose → PostgreSQL: runs
- Docker Compose → Redis: runs
- Docker Compose → Celery runtime: runs worker