All Projects
Featured
May 1, 2026

Budget Tracker

A multi-tenant budget tracking web app built with Next.js 15, Prisma, and PostgreSQL. Each user gets a private workspace to plan monthly budgets, log income and expenses, and allocate savings toward personal goals — replacing what used to live in a messy spreadsheet.

Budget Tracker

Overview

Budget Tracker is a personal finance web application I built to replace a Google Sheets template I'd been using for years. The spreadsheet had grown unwieldy — manually entering expenses cell-by-cell, flipping between monthly tabs, and no way to share or collaborate without exposing everyone's data to everyone. So I rebuilt it from the ground up as a proper multi-tenant web app where anyone can sign up and get their own private workspace.

The app handles monthly budgets per category, income from multiple sources, itemized expenses, savings goals with progress tracking, and a dashboard that visualizes the whole financial year at a glance.

Key Features

  • **Multi-tenant authentication** — JWT in httpOnly cookies, bcrypt-hashed passwords, every database query scoped by `userId` so users can never see each other's data
  • **Monthly budgets per category** with live progress bars, overage warnings, and a "spent vs budgeted" comparison
  • **Transaction ledger** — log every expense and income with dates, categories, descriptions, and notes; full search; inline edit/delete
  • **Savings goals** with target amounts, progress percentages, and per-month contribution tracking
  • **Custom categories** — add, rename, recolor, and pick from 24 icons; data is yours, not hardcoded
  • **Year-at-a-glance dashboard** — total income, spending, savings rate, donut chart of spending distribution, monthly income-vs-expense bar chart, cumulative savings curve, and clickable category breakdown that opens a modal of all transactions
  • **Mobile-friendly responsive design** with a collapsible sidebar
  • **Light/dark mode ready** with theme tokens defined throughout

Architecture

The app is a single Next.js 15 application using the App Router. Every page lives under one of two route groups: `(auth)` for login/register, and `(dashboard)` for the authenticated app. API routes are colocated under `/api`, with each REST endpoint as its own `route.ts` file — similar to how Laravel's `routes/api.php` maps to controllers.

Multi-tenancy is implemented via row-level isolation: every business table carries a `userId` foreign key, the JWT in the session cookie contains the user's ID, and a `withAuth()` wrapper around every API route forces queries to be scoped by that ID. Ownership is re-checked on every PATCH/DELETE before any mutation, so even a forged request can't touch another user's data.

The database is PostgreSQL hosted on Neon. Prisma ORM handles the schema, migrations, and queries through Neon's Postgres driver adapter — chosen over the default driver because it's purpose-built for serverless environments like Vercel and avoids cold-start connection issues.

Tech Stack

  • **Framework:** Next.js 15 (App Router) with React 19
  • **Language:** TypeScript
  • **Database:** PostgreSQL on Neon (serverless-friendly free tier)
  • **ORM:** Prisma 7 with the `@prisma/adapter-pg` driver adapter
  • **Auth:** Custom JWT (jose library) in httpOnly cookies + bcryptjs for password hashing
  • **Styling:** Tailwind CSS with CSS-variable theme tokens
  • **Charts:** Recharts (donut, bar, area)
  • **Icons:** lucide-react
  • **Validation:** Zod schemas on every API route
  • **Hosting:** Vercel with auto-deploy from GitHub
  • **Analytics:** Google Analytics 4
  • **DNS:** Cloudflare

What Made This Interesting

The biggest design decision was multi-tenancy. The simplest approach — one DB per user — would've worked but was overkill for a small app. The most complex approach — schema-per-tenant — would've been a nightmare on a serverless setup. I went with row-level isolation because it's well-trodden, it's what most production SaaS apps use, and it's easy to reason about: every query has `where: { userId }` and that's the whole security model.

The other interesting bit was the migration from MySQL to PostgreSQL late in the build. The original plan was Aiven's free MySQL, but the auto-sleep behavior on the free tier kept timing out Vercel's serverless functions on cold starts. Switching to Neon PostgreSQL took about 20 minutes — change the Prisma provider, swap the driver adapter, push the schema, re-seed. The application code itself didn't change at all because Prisma abstracts the database differences cleanly. It's a good demonstration of why ORMs are worth the extra layer.

Live Demo

Try the app with these credentials — pre-loaded with two years of sample data:

  • **URL:** [budget.humaam.dev](https://budget.humaam.dev)
  • **Email:** `demo@example.com`
  • **Password:** `Welcome@123`

Or sign up with your own email — every account gets its own private workspace with 13 default categories and 6 starter savings goals.

Tech Stack

Next.js
React
TypeScript
Prisma
PostgreSQL
Neon
Tailwind CSS
Recharts
Vercel

Gallery

Budget Tracker screenshot 2
Budget Tracker screenshot 3
Budget Tracker screenshot 4

Like what you see?

Let's discuss how I can help build something similar for you.

Get in Touch