Skip to content

raajpatre/rough-bills

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

21 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Rough Bills Logo

Rough Bills

Track the hangout, not the math.

React Vite Tailwind CSS Node.js Express PostgreSQL Prisma Vercel

Stars Last Commit Top Language

🌐 Live Demo · Features · Algorithm · Getting Started


πŸ“Έ Gallery

Landing & Login Active Hangouts
Login screen Dashboard
Hangout Detail & Settlements Expense & Payment History
Hangout detail Expense history

πŸ“– Overview

Every student group trip ends the same way β€” nobody knows who owes what, the mental math doesn't add up, and the WhatsApp messages go on for days.

Rough Bills solves this without a spreadsheet.

Create a hangout, share a room code, log who paid for what β€” and Rough Bills calculates the fewest number of payments needed for everyone to settle up. No more overcounting. No more awkward debt arithmetic. When the hangout closes, final dues are locked in and members can mark payments against them.

The design is intentional: warm paper textures, hand-drawn aesthetic, dashed borders. Most expense apps feel like bank software. This one feels like something you'd sketch on a napkin β€” because that's exactly what the problem is.


✨ Features

  • Hangout rooms β€” Create a session with a name, get a short room code, and share it with the group. No email required to join.
  • Real-time expense logging β€” Any member logs an expense (paid by whom, split across whom), and the running balances update immediately.
  • Minimum cash flow settlements β€” When a hangout closes, the app calculates the mathematically optimal settlement plan β€” the fewest number of transfers needed to make everyone whole.
  • Post-hangout payment tracking β€” After closing, members mark individual payments against the final dues. Balances update as payments clear.
  • Hangout history β€” Every closed hangout is archived with its full expense log, settlement plan, and payment trail.
  • Username-only auth β€” No email required. Create an account with just a username and password β€” keeps the UX fast and friction-free.

🧠 The Algorithm

The core settlement logic uses a minimum cash flow approach:

  1. After all expenses are logged, each member's net position is calculated: what they paid out minus what they owe.
  2. Members with a positive net position are creditors; members with a negative net position are debtors.
  3. A greedy algorithm matches the largest debtor with the largest creditor, records the transfer, and repeats until all balances clear.

This minimizes the total number of transactions needed β€” a group of n members always settles in at most n - 1 transfers, regardless of how many individual expenses were logged.

The implementation lives in server/src/lib/calculations/ and is fully unit-tested (11 tests, 0 failures):

βœ” splits a single expense equally across two members
βœ” handles multiple expenses with alternating payers
βœ” greedy matching reduces transfers for multiple creditors and debtors
βœ” omits zero-net users from balances and settlements
βœ” distributes remainder deterministically by member order
βœ” returns no balances and no settlements for empty expense arrays
βœ” rejects expenses whose payer is not a hangout member
βœ” calculateDirectSettlements preserves pairwise dues while netting opposite-direction spend
βœ” full payment clears the outstanding due
βœ” partial payment only reduces the remaining due
βœ” buildArchivedDebtSummary uses only remaining closed-hangout dues

πŸ› οΈ Tech Stack

Layer Choice
Frontend React 19 + Vite + Tailwind CSS
Backend Node.js + Express
Database PostgreSQL (Neon) + Prisma ORM
Auth JWT (username-based, no email required)
Hosting Vercel (frontend) Β· Railway or Render (backend)

πŸš€ Getting Started

Prerequisites

  • Node.js 20+
  • A PostgreSQL database URL (Neon recommended for free tier)

Installation

git clone https://github.com/raajpatre/rough-bills.git
cd rough-bills
npm install

Environment

Create a root .env:

DATABASE_URL="postgresql://..."
JWT_SECRET="your-secret-here"   # generate with: openssl rand -hex 32
CLIENT_ORIGIN="http://localhost:5173"
PORT=4000

Run

npm run prisma:generate
npm run dev:server
npm run dev:client

For first-time database setup:

npm run prisma:migrate --workspace server

🚒 Production Deployment

Frontend (Vercel)

  • Root directory: client
  • Build command: npm run build
  • Output directory: dist
  • Environment variable: VITE_API_BASE_URL=https://your-backend-domain.com/api

Backend (Railway / Render)

  • Root: server
  • Start command: node src/server.js
  • Environment variables: DATABASE_URL, JWT_SECRET, CLIENT_ORIGIN, NODE_ENV=production, PORT

πŸ“„ License

MIT β€” open to use, adapt, and deploy.


If Rough Bills saved you from a group chat argument, consider dropping a ⭐ β€” it helps.

Made with ❀️ by raajpatre

About

Track the hangout, not the math. Mobile-first group expense splitter with room codes, minimum cash flow settlement algorithm, and post-hangout payment tracking.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors