Skip to content

qzMalekuz/playTo-pay

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Playto Payout Engine

Payout engine for Playto Pay — merchants accumulate balance from customer payments and withdraw to their Indian bank accounts.

Stack: Django + DRF · PostgreSQL · Celery + Redis · React + Tailwind


Quick Start (Docker)

Requires Docker and Docker Compose.

docker-compose up --build

This starts Postgres, Redis, Django (port 8000), Celery worker, Celery beat, and React (port 3000).

On first run, backend automatically runs migrations and seeds 3 merchants with credit history.


Local Setup (without Docker)

Prerequisites

  • Python 3.9+
  • PostgreSQL running locally
  • Redis running locally
  • Node.js 18+

Backend

cd backend
python -m venv venv
source venv/bin/activate          # Windows: venv\Scripts\activate
pip install -r requirements.txt

Create a .env file in backend/:

SECRET_KEY=your-secret-key
DATABASE_URL=postgres://postgres:postgres@localhost:5432/playto
REDIS_URL=redis://localhost:6379/0
DEBUG=True
ALLOWED_HOSTS=localhost,127.0.0.1
python manage.py migrate
python seed.py                     # seeds 3 merchants + credit history
python manage.py runserver

In a second terminal (Celery worker):

cd backend && source venv/bin/activate
celery -A config worker --loglevel=info

In a third terminal (Celery beat — for retry logic):

cd backend && source venv/bin/activate
celery -A config beat --loglevel=info --scheduler django_celery_beat.schedulers:DatabaseScheduler

Frontend

cd frontend
npm install
npm run dev

Open http://localhost:5173


Running Tests

cd backend && source venv/bin/activate
python manage.py test payouts

Tests:

  • ConcurrencyTest — two simultaneous 6000 paise requests on a 10000 paise balance. Asserts exactly one succeeds, one is rejected, final balance is 4000.
  • IdempotencyTest — same request sent twice with same Idempotency-Key. Asserts one payout row, both responses identical.
  • StateMachineTest — asserts failed → completed, completed → pending, pending → completed all raise InvalidTransition.

API Reference

All payout endpoints require:

  • X-Merchant-Id: <id> header — identifies the merchant (no auth for demo)
Method Path Description
GET /api/v1/merchants/ List all merchants
GET /api/v1/merchants/<id>/balance/ Available + held balance
GET /api/v1/merchants/<id>/ledger/ Last 50 ledger entries
POST /api/v1/payouts/ Create payout
GET /api/v1/payouts/ List payouts
GET /api/v1/payouts/<id>/ Single payout detail

POST /api/v1/payouts/ — required headers:

Idempotency-Key: <uuid>
X-Merchant-Id: <merchant_id>
Content-Type: application/json

Body:

{ "amount_paise": 50000, "bank_account_id": 1 }

Key Design Decisions

No balance column. Balance is always computed as SUM(credits) - SUM(debits) from LedgerEntry rows. A stored balance can drift; a derived balance cannot.

select_for_update() for concurrency. Locks the merchant row before the balance check so two concurrent requests serialize at the DB. The check and debit are in the same transaction.atomic() — no TOCTOU race possible.

IntegrityError catch for idempotency. A unique constraint on (merchant, key) handles the in-flight race without a pre-check + lock pattern. The DB does the work.

State machine in the model. transition_to() enforces legal transitions for every caller. Failed and completed are terminal — no outgoing transitions.

Atomic fund return. Status change and compensating credit are in the same transaction.atomic(). A payout cannot be marked failed without returning funds, and funds cannot be returned without the status change.


Seed Data

Initial balances after seeding (will change as payouts are made):

Merchant Starting Balance
Rahul Sharma — DesignCo ₹9,000
Priya Patel — DevStudio ₹23,000
Amit Verma — ContentLab ₹2,550

About

A platform where merchants see their balance, request payouts, and track payout status while handeling the concurrency, idempotency, and data integrity.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors