← Back to Projects

Finance Tracker

AI-powered personal accounting

Development

What Finance Tracker Does

Finance Tracker is a personal expense categorization tool with AI-powered auto-tagging. You import bank/credit card transactions (CSV), the AI categorizes them (groceries, rent, subscriptions, etc.), and you get charts showing where your money actually goes.

The core purpose: Stop wondering where $3,000 disappeared last month. Let AI read transaction descriptions and tell you "you spent $847 on food delivery this month."

The Architecture

Three-Pillar Breakdown

🗄️ DATABASE: PostgreSQL
│
├─ users                 User accounts (via Keycloak SSO)
├─ transactions          Imported bank transactions
├─ categories            Expense categories (custom + defaults)
├─ categorization_rules  "If description contains 'UBER' → Transportation"
└─ ai_suggestions        OpenAI's category guesses (stored for review)

🖥️ INTERFACE: Next.js (Frontend)
│
├─ /dashboard            Spending overview (charts, totals by category)
├─ /import               CSV upload interface
├─ /transactions         List view with manual category overrides
├─ /categories           Manage custom categories
└─ /settings             OpenAI API key input, budget goals

⚡ API LOGIC: Python (FastAPI) Backend
│
├─ /api/import           Parse CSV, extract transactions
├─ /api/categorize       Send to OpenAI, get category predictions
├─ /api/transactions     CRUD for transaction management
└─ /api/reports          Generate spending reports

Why Split Frontend/Backend?

Finance Tracker started as a weekend experiment. The architecture reflects that:

If we were starting today, we'd probably use Next.js for the whole thing (like Rental Platform). But it works, so we haven't refactored.

The AI Categorization Flow

1. User uploads CSV (e.g., from Chase credit card)
   └─ Example row:
       Date: 2025-01-15
       Description: "UBER *TRIP 2X3Y4"
       Amount: -$18.42

2. Backend parses CSV → extract transactions

3. For each transaction, check rules first:
   └─ IF description matches rule → apply category
   └─ ELSE → send to OpenAI API

4. OpenAI API call:
   Prompt: "Categorize this transaction:
            Description: UBER *TRIP 2X3Y4
            Amount: $18.42
            
            Choose from: Food, Transportation, Entertainment,
            Housing, Utilities, Healthcare, Other"
   
   Response: "Transportation"

5. Store AI suggestion in database (not auto-applied)

6. User reviews suggestions in UI:
   └─ Accept (save category)
   └─ Override (choose different category)
   └─ Create rule ("Always categorize UBER as Transportation")

7. Once approved, charts update with new data

Why Not Auto-Apply AI Categories?

AI gets it wrong sometimes. Examples we've seen:

So the flow is: AI suggests, human decides, create rules to avoid re-categorizing next month.

The Rule System

Once you categorize "STARBUCKS" as "Food", Finance Tracker offers to create a rule:

RULE CREATION PROMPT:
"Create a rule so future Starbucks transactions are auto-categorized?"

IF YES:
  └─ Save rule:
      IF description CONTAINS "STARBUCKS"
      THEN category = "Food"

NEXT MONTH:
  └─ New transaction: "STARBUCKS #1234 SAN FRANCISCO"
  └─ Rule matches → auto-categorize as "Food"
  └─ No AI call needed (faster + saves OpenAI API costs)

Over time, you build a personal rule set. After 3-4 months, AI is only needed for truly novel transactions.

The Tech Stack

Layer Technology Why This Choice
Frontend Next.js + TypeScript Charts (Recharts), forms, SSR for dashboard.
Backend Python + FastAPI Pandas for CSV parsing, OpenAI Python SDK, easy data analysis.
Database PostgreSQL Store transactions, categories, rules. Date-range queries.
AI OpenAI API (GPT-4) Transaction description → category prediction.
Auth Keycloak (SSO) Same login as other BENED apps.
Deployment Docker (2 containers) Next.js frontend + Python backend, nginx reverse proxy.

CSV Import Pattern

Different banks have different CSV formats. Finance Tracker uses column mapping:

CHASE CREDIT CARD CSV:
  Columns: Transaction Date, Post Date, Description, Category, Type, Amount

BANK OF AMERICA CSV:
  Columns: Date, Description, Amount, Running Bal.

IMPORT INTERFACE:
  User uploads CSV
  └─ Backend detects headers
  └─ Shows mapping UI:
      "Which column is the transaction date?"
      → User selects "Transaction Date"
      
      "Which column is the description?"
      → User selects "Description"
      
      "Which column is the amount?"
      → User selects "Amount"
      
  └─ Save mapping preferences per bank
  └─ Next import auto-detects bank and uses saved mapping

Spending Reports

The dashboard shows:

Backend generates these via SQL queries:

SPENDING BY CATEGORY (THIS MONTH):
  SELECT category, SUM(amount) as total
  FROM transactions
  WHERE user_id = ? 
    AND date >= '2025-01-01'
    AND date < '2025-02-01'
  GROUP BY category
  ORDER BY total DESC;

SPENDING TREND (LAST 6 MONTHS):
  SELECT 
    DATE_TRUNC('month', date) as month,
    SUM(amount) as total
  FROM transactions
  WHERE user_id = ?
    AND date >= NOW() - INTERVAL '6 months'
  GROUP BY month
  ORDER BY month;

Staging vs Production

Staging Production
URL stagingfinance.bened.works finance.bened.works
Code /opt/bened-finance-tracker /srv/bened-finance-tracker
Database finance_staging finance_production
OpenAI Shared API key (test mode) User's own API key (bring-your-own)
Purpose Feature dev, test imports Real users, real transactions

Privacy Considerations

Bank transactions are SENSITIVE data. Design choices to protect privacy:

What's Missing (Known Gaps)

The Deployment Story

PRODUCTION DEPLOY:
1. Build frontend:
   cd frontend && npm run build
   → Generates static files in .next/

2. Build Docker images:
   docker build -t finance-frontend:latest ./frontend
   docker build -t finance-backend:latest ./backend

3. Stop old containers:
   docker stop finance-frontend finance-backend
   docker rm finance-frontend finance-backend

4. Start new containers:
   docker run -d --name finance-frontend \\
     --network bened-platform_bened-network \\
     finance-frontend:latest
   
   docker run -d --name finance-backend \\
     --network bened-platform_bened-network \\
     --env-file .env \\
     finance-backend:latest

5. Nginx at finance.bened.works proxies:
   └─ / → frontend container
   └─ /api → backend container

How This Connects to Other Apps

Finance Tracker is mostly standalone, but:

Finance Tracker → Operations Portal (Planned)
  └─ Export categorized expenses
  └─ Used for LLC/nonprofit expense reporting

Keycloak → Finance Tracker
  └─ SSO login (same user identity across BENED apps)

The Honest Assessment

Finance Tracker is a personal tool that became a product. It started as "I need to see where my money goes", became useful for the team, and now we're wondering if others would pay for it.

What works well:

What needs work:

It's in the "useful internally, not quite ready for public launch" phase.