Navina Lang
← All projects

Expense Tracker

Household multi-currency expense tracking with AI-assisted categorization

MVP
Express 5PostgreSQLPrismaReactTypeScriptViteGemini

Overview

The Expense Tracker is a household finance application designed for families managing shared spending across multiple people and currencies, with AI-assisted expense categorization.

I built it as a self-directed project to learn modern full-stack application development outside the Web3 ecosystem. The goal wasn't simply to build another expense tracker — it was to understand how production SaaS applications are structured, from authentication and authorization to testing, deployment and AI integration.

Although intentionally small in scope, I approached it with the same engineering principles I applied in financial infrastructure: clear data models, strong testing, thoughtful architecture and a focus on long-term maintainability.

Problem

Most expense tracking applications assume a single user or require every family member to maintain their own account.

Real households are rarely that simple.

Different people pay for different expenses, children shouldn't require login credentials, spending happens in multiple currencies and manually categorizing every purchase quickly becomes repetitive enough that many people stop using the application altogether.

I wanted to design an application that reflected how households actually manage money rather than forcing users into an overly simplified model.

Solution

The application models households as organizations with different roles.

Adults can log in using either email/password or Google authentication, while children and dependents can participate without requiring their own accounts.

Expenses entered in foreign currencies are automatically converted using live exchange rates, while Gemini suggests the most appropriate spending category without automatically modifying user data.

The dashboard provides spending summaries, category breakdowns and filtering by household member, giving users a shared view of household finances while keeping control over financial decisions.

Architecture

The architecture was intentionally kept simple while following production practices.

Backend

Express 5 with PostgreSQL and Prisma ORM provides a lightweight REST API with session-based authentication.

Authentication

Accounts support both traditional email/password authentication and Google OAuth while maintaining a single identity regardless of login method.

Passwords are hashed using Argon2 before storage.

AI Integration

Gemini assists with expense categorization.

Rather than automatically modifying financial records, the AI provides suggestions that users may accept or reject.

Frontend

The frontend is built with React, TypeScript and Vite.

I intentionally avoided component libraries to strengthen my understanding of frontend fundamentals before relying on abstraction layers.

Deployment

The frontend is compiled into static assets and served directly by the Express backend.

Using a single-origin deployment removes the need for CORS configuration while simplifying deployment for an application of this size.

The application is deployed on Render with Neon PostgreSQL.

Data Lifecycle

Accounts are soft deleted and anonymized while preserving historical expenses.

This ensures household financial history remains complete even when members leave the household.

Engineering Decisions

The architectural decision I'd highlight most is modelling households rather than individual users.

Many expense trackers begin with a simple users table and later attempt to add shared ownership.

Instead, households became the primary entity from the beginning, with different member roles representing how families actually manage finances.

The second decision was choosing simplicity over flexibility for deployment.

Serving the frontend directly through Express removes an entire class of deployment complexity around CORS and cross-origin authentication.

For an application of this scale, reducing operational complexity was a better trade-off than independently deploying frontend and backend services.

Finally, AI remains advisory rather than autonomous.

Financial records should always remain under user control, so category suggestions require explicit confirmation before being applied.

Technology Stack

  • Express 5
  • PostgreSQL
  • Prisma ORM
  • React
  • TypeScript
  • Vite
  • React Router
  • Argon2
  • Google OAuth
  • Gemini API
  • Vitest
  • Supertest
  • Render
  • Neon PostgreSQL

Trade-offs

Every architectural decision prioritized simplicity and maintainability over unnecessary complexity.

Hand-Written CSS vs. Component Libraries — Building the interface without a component library slowed development but strengthened my understanding of frontend fundamentals rather than relying on pre-built abstractions.

AI Assistance vs. Automation — Expense categorization remains a suggestion rather than an automatic action. This creates a slightly less automated experience while ensuring users remain in control of their financial records.

Single-Origin Deployment — Deploying frontend and backend together reduces deployment flexibility but greatly simplifies authentication, routing and operational complexity for an application of this size.

Lessons Learned

This project taught me far more than frontend development.

It gave me practical experience designing authentication flows, role-based data models, deployment pipelines and production testing for a traditional SaaS application.

One of the biggest surprises was how valuable integration testing became.

Running Vitest and Supertest against a real PostgreSQL database uncovered edge cases around currency conversion and account deletion that would likely have been missed using mocked databases alone.

It reinforced a lesson I'd already learned from previous projects: when practical, testing against real infrastructure provides far greater confidence than testing isolated components in artificial environments.

What I'd Do Differently Today

If I rebuilt the application today, I'd make several architectural improvements.

  • Introduce event-driven notifications for recurring expenses and household activity.
  • Separate currency conversion into its own service to make exchange-rate providers easier to replace.
  • Improve the invitation flow so household onboarding becomes completely self-service.
  • Introduce domain services around budgeting and reporting rather than keeping all financial logic close to the API layer.

The overall architecture remains intentionally simple, but working through the project gave me a much better understanding of what differentiates a small prototype from a maintainable SaaS application.

Future Improvements

Future iterations would focus on expanding the product rather than increasing technical complexity.

Potential additions include:

  • Budget planning and spending alerts
  • Recurring expense detection
  • Household invitations and onboarding
  • Shared financial goals
  • Receipt scanning with AI-assisted extraction
  • Additional financial reporting and analytics