↓Skip to main content

GP Expenses — Personal Finance Tracker

·2 mins

Status: actively in progress — the core ledger and recurring payments flow are working end to end; UI polish and additional reporting are ongoing.

The problem #

Spreadsheets are fine for tracking expenses until you need recurring payments, partial confirmations, or an accurate running balance that accounts for money that will leave your account but hasn’t yet. GP Expenses is a personal finance tracker built to solve that properly: a single source of truth for what you have, what’s pending, and what’s projected.

Architecture #

A monorepo with two independent packages:

  • Backend (gpexpenses/) — Spring Boot 3.4, Java 21, Spring Data JDBC (no JPA/Hibernate), JWT authentication. REST API only, no server-rendered UI.
  • Frontend (frontend-web/) — SvelteKit 2, Svelte 5 (runes), Tailwind CSS 4, DaisyUI. A fully client-side SPA (SSR disabled) that proxies to the backend API.
  • Database — H2 file-based for local development, PostgreSQL in production.

Key design decisions #

  • Unified transactions ledger. Expenses and income share a single table, distinguished by a type field, instead of separate models. This simplifies the statement/balance logic considerably and avoids duplicating queries across two parallel domains.
  • Three-state transaction lifecycle. Every transaction is PENDING, CONFIRMED, or CANCELLED. Manual entries start CONFIRMED; payments generated from a recurring template start PENDING so an outdated template amount never silently affects the balance. Cancelling is a soft delete — the row stays for auditing and is excluded from all balance calculations.
  • Two balances, not one. The account statement reports a confirmedBalance (what you actually have) and a projectedBalance (including pending payments and unpaid recurring templates), so the app can answer both “what do I have” and “what will I have” without extra client-side logic.
  • Spring Data JDBC over JPA. Deliberately avoided Hibernate’s implicit behavior (lazy loading, dirty checking) in favor of explicit, predictable queries — a better fit for a domain this size.

Stack #

Java 21 · Spring Boot 3.4 · Spring Data JDBC · JWT · SvelteKit 2 · Svelte 5 · Tailwind CSS 4 · DaisyUI · PostgreSQL (prod) / H2 (dev)