Group expense splitter. Day 1 covers: project setup, database schema, and JWT authentication.
- Project structure (
client/+server/) - PostgreSQL schema:
users,groups,group_members,expenses,expense_splits - Auth API: signup, login, get current user (
/api/auth/me) - Passwords hashed with bcrypt, sessions handled via JWT
Create a free Postgres database (recommended: Neon or Supabase). Then run the schema against it:
psql "<your-database-url>" -f server/schema.sql(Or paste the contents of server/schema.sql into your provider's SQL editor.)
cd server
npm install
cp .env.example .env
# edit .env: paste your DATABASE_URL and set a random JWT_SECRET
npm run devServer runs at http://localhost:5000. Visit it in a browser — you should see:
{"status": "SplitEasy API is running"}Using curl, Postman, or Thunder Client:
Sign up
curl -X POST http://localhost:5000/api/auth/signup \
-H "Content-Type: application/json" \
-d '{"name":"Jane Doe","email":"jane@example.com","password":"password123"}'Log in
curl -X POST http://localhost:5000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"jane@example.com","password":"password123"}'Both return a token — copy it and use it to test the protected route:
Get current user
curl http://localhost:5000/api/auth/me \
-H "Authorization: Bearer <paste-token-here>"New endpoints (all require the Authorization: Bearer <token> header from login):
Create a group
POST /api/groups
Body: { "name": "Goa Trip" }
List my groups
GET /api/groups
Get one group + members
GET /api/groups/:groupId
Add a member (they must already have a SplitEasy account)
POST /api/groups/:groupId/members
Body: { "email": "friend@example.com" }
Add an expense (equal split)
POST /api/groups/:groupId/expenses
Body: {
"description": "Dinner",
"amount": 1200,
"paidBy": 1
}
Add an expense (custom split)
POST /api/groups/:groupId/expenses
Body: {
"description": "Cab",
"amount": 500,
"paidBy": 1,
"splitType": "custom",
"splits": [
{ "userId": 1, "amount": 300 },
{ "userId": 2, "amount": 200 }
]
}
List expenses in a group
GET /api/groups/:groupId/expenses
Get balances (who owes / is owed how much)
GET /api/groups/:groupId/balances
Returns each member's paid, owed, and net balance. Positive balance = they're owed money. Negative = they owe money.
Remember to save the token you got from login and include it in every request:
$token = "paste_your_token_here"
$headers = @{ Authorization = "Bearer $token" }
# Create a group
Invoke-RestMethod -Uri "http://localhost:5000/api/groups" -Method POST -Headers $headers -ContentType "application/json" -Body '{"name":"Goa Trip"}'Added GET /api/groups/:groupId/settle-up — simplifies everyone's debts into the
minimum number of payments needed, using a greedy largest-creditor/largest-debtor
matching algorithm (see server/utils/settleUp.js).
React + Tailwind client in client/, purple theme. Pages: login, signup, dashboard
(group list), and group detail (members, add expense, balances, settle-up view).
cd client
npm install
npm run devOpens at http://localhost:5173. Make sure the backend (server/) is running at
the same time on http://localhost:5000 — the frontend talks to it directly.
- Colors: plum
#2D1B4E, amethyst#7C4DFF, violet#5B21B6, lavender#F3EEFF, ink#1E1B2E, owed#22C55E, owe#F97066 - Fonts: Sora (headings), Inter (body/data)
- Signature element: settle-up transactions render as connected avatar pills with an arrow, not a plain table
Deploy backend (Render) + frontend (Vercel), final polish, README.