A modern bill-splitting and expense tracking application for groups. Track shared expenses, split bills fairly, and settle up with friends.
- Event-Based Organization: Create events for trips, dinners, or any shared expense occasion
- Bill Splitting: Add bills and split them evenly among participants
- Smart Balance Calculation: Automatically calculates who owes whom and minimizes the number of transactions needed
- Payment Tracking: Record payments and mark bills as settled
- Venmo Integration: Quick pay via Venmo on mobile devices
- Google OAuth: Secure authentication with Google Sign-In
- Real-time Updates: Immediate balance updates as bills and payments are added
- Search & Filter: Easily find bills by payer, amount, or participant
- Mobile Responsive: Full functionality on both desktop and mobile devices
- React 19
- TypeScript
- Vite
- React Router
- Axios
- Node.js
- Express
- TypeScript
- Supabase (PostgreSQL)
- Passport.js (Google OAuth)
- Jest (Testing)
- Heroku (Deployment)
- GitHub (Version Control)
ledgersplit/
├── client/ # React frontend application
│ ├── src/
│ │ ├── components/ # Reusable UI components
│ │ ├── context/ # React context providers
│ │ ├── pages/ # Page components
│ │ ├── services/ # API service layer
│ │ ├── styles/ # Style constants and themes
│ │ └── types/ # TypeScript type definitions
│ └── public/ # Static assets
├── server/ # Node.js backend application
│ ├── src/
│ │ ├── middleware/ # Express middleware
│ │ ├── routes/ # API route handlers
│ │ ├── services/ # Business logic layer
│ │ ├── scripts/ # Utility scripts
│ │ └── index.ts # Server entry point
│ └── dist/ # Compiled TypeScript output
├── database-schema.sql # PostgreSQL database schema
└── package.json # Root package configuration
- Node.js 18+ and npm
- PostgreSQL database (via Supabase or local)
- Google OAuth credentials (for authentication)
- Clone the repository:
git clone https://github.com/siltwood/LedgerSplit.git
cd LedgerSplit- Install dependencies:
npm install
cd client && npm install
cd ../server && npm install- Set up environment variables:
Create .env files in both client/ and server/ directories.
Server .env:
# Database
SUPABASE_URL=your_supabase_url
SUPABASE_ANON_KEY=your_supabase_anon_key
# Google OAuth
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
GOOGLE_CALLBACK_URL=http://localhost:3000/api/auth/google/callback
# Session
SESSION_SECRET=your_session_secret
# Email (for password reset)
EMAIL_USER=your_email@gmail.com
EMAIL_PASSWORD=your_app_password
# Environment
NODE_ENV=development
CLIENT_URL=http://localhost:5173Client .env:
VITE_API_URL=http://localhost:3000
VITE_SUPABASE_URL=your_supabase_url
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key- Set up the database:
Run the schema SQL file against your Supabase database:
psql -h your-supabase-host -U postgres -d postgres -f database-schema.sqlOr use the Supabase SQL Editor to execute the contents of database-schema.sql.
- (Optional) Seed test data:
cd server
npm run seedRun the development servers:
Terminal 1 - Backend:
cd server
npm run devTerminal 2 - Frontend:
cd client
npm run devThe frontend will be available at http://localhost:5173 and the backend API at http://localhost:3000.
Build both client and server:
npm run buildStart the production server:
npm startRun the test suite:
cd server
npm testRun tests in watch mode:
npm run test:watchGenerate coverage report:
npm run test:coveragePOST /api/auth/signup- Create new accountPOST /api/auth/login- Login with email/passwordGET /api/auth/google- Initiate Google OAuth flowGET /api/auth/google/callback- Google OAuth callbackPOST /api/auth/logout- Logout current userGET /api/auth/me- Get current user infoPOST /api/auth/forgot-password- Request password resetPOST /api/auth/reset-password- Reset password with token
GET /api/events- List all user eventsPOST /api/events- Create new eventGET /api/events/:id- Get event detailsPUT /api/events/:id- Update eventDELETE /api/events/:id- Delete eventPOST /api/events/join/:token- Join event via share linkPOST /api/events/:id/leave- Leave eventDELETE /api/events/:id/participants/:userId- Remove participant
GET /api/splits- List splits (query by event_id)POST /api/splits- Create new splitGET /api/splits/:id- Get split detailsPUT /api/splits/:id- Update splitDELETE /api/splits/:id- Delete split
GET /api/payments- List payments (query by event_id)POST /api/payments- Record paymentDELETE /api/payments/:id- Delete payment
POST /api/settled/:eventId/toggle- Toggle user's settled confirmation
The application uses the following main tables:
- users - User accounts and profiles
- events - Group events (trips, dinners, etc.)
- event_participants - Event membership
- splits - Bills/expenses
- split_participants - Who participated in each split
- payments - Payment records between users
- event_settled_confirmations - User confirmations that event is settled
See database-schema.sql for the complete schema definition.
The application is configured for deployment on Heroku with the included Procfile.
Deploy to Heroku:
git push heroku mainEnsure all environment variables are set in Heroku:
heroku config:set SUPABASE_URL=your_url
heroku config:set SUPABASE_ANON_KEY=your_key
# ... set all other environment variables- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is private and proprietary.
For issues or questions, please open an issue on GitHub.