Fair-Share
Group expense tracker with JWT auth, server-side balance settlement and a category breakdown, split across a React client and an Express/MongoDB API.

Problem
Splitting shared expenses across a group — rent, trips, shared subscriptions — usually ends up in a spreadsheet nobody trusts. I wanted a tool that tracked who owes what automatically, without manual balance math.
Approach
Two repositories: a React client and a Node/Express REST API backed by MongoDB. Users sign up, create groups, log expenses against them choosing who paid and who the cost splits between, and every balance is derived from that ledger rather than entered by hand. Supabase Storage holds the images so the API never handles file uploads.
Architecture
- Client: React 19 + Vite, React Router 7 with every route past the
landing page behind
React.lazy. All requests go through a single configured axios instance that attaches the bearer token and, on a401, clears it and redirects to login — components pass paths, never URLs - Server: Express 5 and Mongoose over MongoDB Atlas, structured around resource routes (auth, users, groups, expenses) with bcrypt password hashing and centralized error handling
- Balance maths: one module,
expenseCalculations.js, exposing per-user totals and per-member group balances — the single source of truth for every figure the UI renders - Storage: Supabase Storage for profile, group and receipt photos
Key decisions
- Balance calculations live in one module rather than being recomputed ad hoc per component, so the number a user sees on the overview, on a group card and in the group header is always the same number
- Authorization tightens per action rather than sitting at the router: some
routes are self-only, some member-only, some author-only, and each returns
a real
401/403/404instead of always responding200 - Password hashes are excluded from every API response by default and only re-selected internally to verify a login
- Group admin rights are transferable, because a group outlives whoever happened to create it
Results
A deployed expense manager with JWT-authenticated accounts and protected
routes, groups with transferable admin, per-expense payer and split
selection, paid/borrowed/net balances for both the individual and the
group, a two-tone balance bar repeated across the overview and every group
card, a donut chart of spending by category, image uploads, a navigation
rail that collapses to a drawer on mobile, and labelled controls with
visible focus rings and prefers-reduced-motion support.
What I’d do differently
Neither repository has a test framework, which is the first thing I’d add
now that the balance maths is centralized enough to be worth testing. I’d
also normalize the API payloads: expenseAuthor and expenseUsers come
back as ID strings from list endpoints but as populated objects from detail
endpoints, and every consumer has to handle whichever shape it is handed.