My Spending
Personal Finance & Freelance Bookkeeping
A full-stack finance application combining household expense tracking with bookkeeping tools for freelancers in Japan.

Overview
My Spending is a personal project I built to solve two problems I encountered in everyday life: managing household expenses with my wife and preparing financial records for my freelance work in Japan. What started as a way to centralize family spending gradually evolved into a full-stack application with transaction management, financial dashboards, and accounting ledgers.
The problem
My wife and I were tracking household expenses separately, making it difficult to maintain a clear picture of our shared spending. At the same time, preparing my freelance tax records involved manually organizing transactions in Excel and creating accounting ledgers. I wanted a single application that could support both workflows without making everyday expense tracking unnecessarily complicated.
The solution
I developed a finance management application supporting personal, shared, and professional accounts. Users can organize transactions into customizable categories, track income and expenses through dashboards, and generate accounting ledgers from professional transactions. The application uses Supabase authentication and PostgreSQL Row Level Security to control access to financial data.
Key features
Multiple Account Types
Manage personal, shared, and professional accounts with support for JPY, EUR, and USD. Account membership is modeled separately from account data to support multiple users.
Transaction Management
Create, edit, delete, and filter income and expense transactions. Each transaction belongs to a category, which also determines whether it is included in professional bookkeeping reports.
Financial Dashboard
Visualize income, expenses, and spending patterns through interactive charts and financial summaries built with Chart.js.
Customizable Categories
Create categories with custom names, icons, and colors, and classify them as personal or professional to organize transactions according to their purpose.
Accounting Ledger Generation
Generate a general ledger and individual category ledgers from professional transactions, using the previous calendar year by default. Reports include running balances, monthly subtotals, and accounting adjustments based on my experience preparing freelance tax records in Japan.
Ledger Editing & PDF Export
Review and modify transactions directly from the ledger interface. Changes update the original transaction records, while a dedicated print layout allows users to save ledgers as PDFs through the browser.
Tech stack
Database
Testing
Services & hosting
Technical implementation
Full-Stack Architecture
Built with Next.js App Router, React, and TypeScript, combining server-side data access, API routes, and interactive client components. Business logic is separated from UI components where practical, particularly for ledger calculations.
Database-Level Authorization
Implemented PostgreSQL Row Level Security to restrict financial data access based on account membership and transaction ownership. Users can access transactions in their accounts but can only modify or delete transactions they created.
Dynamic Ledger Calculations
Ledger calculations are pure TypeScript functions: transactions are ordered deterministically, and running balances, monthly subtotals, and year-end adjustments are derived from the transaction data.
Automated Testing
Added unit tests with Vitest and React Testing Library, including ledger calculations checked against hand-calculated values. Tests run automatically through CI on every push.
Challenges & engineering decisions
Moving from Firestore to PostgreSQL
Problem
As the application evolved, Firestore's querying model became restrictive for the relationships and data access patterns I wanted to support. Migrating also meant replacing the existing authentication integration without disrupting login flows.
Solution
I migrated the data model to PostgreSQL, using a relational account-membership table instead of storing members directly on accounts. I then adapted authentication, session handling, and protected routes to Supabase.
Printing Ledgers Across Multiple Pages
Problem
My initial PDF-printing implementation tried to calculate page breaks in JavaScript. Fixed row counts and estimated row heights both produced inconsistent results because descriptions could wrap differently depending on their length, font, and language.
Solution
After trying both approaches, I removed the custom pagination logic and let the browser handle page breaks. CSS print rules now repeat table headers, prevent individual rows from splitting, and provide a consistent A4 layout. This simplified the implementation, although it reduced control over page-specific elements.
Keeping Ledger Balances Consistent
Problem
Editing or deleting an earlier transaction affects every subsequent running balance. Storing calculated balances separately would introduce additional synchronization work and potential inconsistencies.
Solution
I chose to derive balances and subtotals from the transaction data instead of storing them. This keeps the calculations in one place, makes them easy to test, and ensures the ledger reflects any change when reloaded.
Results & lessons learned
Results
My Spending has grown from a household expense tracker into a working full-stack application that also supports my freelance bookkeeping workflow. It generates professional ledgers, supports browser-based PDF exports, and includes automated tests running in CI. Shared-account management and Excel exports remain areas for future development.
Lessons learned
- The right data model depends on the relationships and queries an application actually needs. Moving to PostgreSQL gave me more flexibility as the project grew.
- The simpler solution is sometimes the more reliable one. Replacing custom JavaScript pagination with browser-native printing reduced complexity and made ledger exports more consistent.
- Authorization belongs at the data layer, not just in the interface.
- Building software around a real personal need reveals requirements and edge cases that are easy to overlook at the start of a project.


