A group expense-splitting backend that solves the part most tutorials skip: minimizing settlement transactions with a real graph algorithm, and modeling money the way production fintech code actually has to.
Split Smart lets a group of people track shared expenses and settle up with the minimum number of payments — not naive pairwise "everyone pays everyone" splitting, but an actual debt-simplification algorithm that collapses a group's tangled IOUs into the smallest possible set of transactions.
It's built as a portfolio-grade backend: the kind of service that's expected to run correctly under real usage, not just pass a demo.
Most expense-splitter builds stop at CRUD: create an expense, divide it evenly, done. Two decisions here are deliberately not that:
- Debt simplification, not naive splitting. If A owes B, B owes C, and C owes A, a naive splitter creates three payments. This project scopes debts into connected components and resolves them with a greedy deque-based matching algorithm, so a tangled group settles in the minimum number of real transactions.
- Money as
Decimal, notfloat. Floating-point rounding errors in financial calculations are a well-known, entirely avoidable bug class. Every monetary value in this schema isDecimalfrom the ground up.
- Group and multi-user expense tracking with role-based membership
- Debt-simplification engine (connected-component scoping + greedy deque matching) that minimizes settlement transactions
- Financially correct money handling via
Decimalthroughout — no float-rounding bugs - Standardized, spec-compliant error responses (RFC 7807 problem details) instead of ad hoc error shapes
- Domain-driven folder structure, not a flat everything-in-one-place layout
| Layer | Technology |
|---|---|
| API framework | FastAPI |
| Database | PostgreSQL |
| Caching | Redis |
| Background jobs | Celery |
| Testing | pytest |
| CI | GitHub Actions |
The codebase follows a domain-driven structure rather than the typical flat models/, routes/, schemas/ split — code is grouped by business domain (users, groups, expenses, payments) so each domain owns its models, schemas, and logic together.
Directory structure:
└── aminishereai-split-smart/
├── README.md
├── features.md
├── LICENSE
├── pyproject.toml
├── requirements.txt
├── schemas.md
├── uv.lock
├── .python-version
└── app/
├── main.py
├── core/
│ ├── __init__.py
│ ├── configs.py
│ ├── database.py
│ ├── lifespan.py
│ ├── logging.py
│ └── redis.py
├── src/
│ ├── __init__.py
│ ├── auth/
│ │ ├── __init__.py
│ │ ├── dependencies.py
│ │ ├── exceptions.py
│ │ ├── models.py
│ │ ├── router.py
│ │ └── services.py
│ ├── expenses/
│ │ ├── __init__.py
│ │ ├── dependencies.py
│ │ ├── exceptions.py
│ │ ├── models.py
│ │ ├── router.py
│ │ └── services.py
│ ├── groups/
│ │ ├── __init__.py
│ │ ├── dependencies.py
│ │ ├── exceptions.py
│ │ ├── models.py
│ │ ├── router.py
│ │ └── services.py
│ └── payments/
│ ├── __init__.py
│ ├── dependencies.py
│ ├── exceptions.py
│ ├── models.py
│ ├── router.py
│ └── services.py
└── utils/
└── exceptions/
├── __init__.py
├── base.py
├── problems.py
└── register.py
Six core tables:
| Table | Purpose |
|---|---|
Users |
Account records |
Groups |
A collection of users sharing expenses |
User_Group |
Membership join table, carries per-user role within a group |
Expenses |
A recorded expense, amount stored as Decimal |
Expense_Splits |
How a given expense is divided across group members |
Payments |
Settlement transactions between users |
All errors are returned as RFC 7807 application/problem+json responses — a consistent, standardized shape (type, title, status, detail) instead of one-off error formats per endpoint.
(Representative — match to your actual route definitions.)
| Method | Endpoint | Description |
|---|---|---|
POST |
/groups |
Create a group |
POST |
/groups/{id}/members |
Add a member |
POST |
/expenses |
Record an expense and its splits |
GET |
/groups/{id}/balances |
Current balances per member |
POST |
/groups/{id}/settle |
Run debt simplification, return the minimal settlement plan |
git clone https://github.com/aminishereai/split-smart.git
cd split-smart
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
# Create a .env file with:
# DATABASE_URL=postgresql://user:password@localhost:5432/splitsmart
# REDIS_URL=redis://localhost:6379/0
uvicorn app.main:app --reloadThis is an active build, not a finished product — shown here honestly rather than dressed up:
Done:
- Full schema and domain-driven architecture
- Debt-simplification algorithm
- RFC 7807 error handling
- Self-review pass that caught and fixed real bugs (bad queries, unawaited coroutines, misused HTTP exceptions, incorrect status codes)
In progress:
- Async conversion
- Redis caching layer
- pytest test suite
- Celery background jobs
- Docker / production deployment setup
MIT