← Vinay
Personal Project · Ongoing

A finance tracker that runs itself, every night, without me touching it.

Expenso ingests my bank alert emails, classifies every transaction, flags anomalies, and answers plain-English questions about my spending — automated end to end with a nightly job. Eliminated about 3 hours a week of manual finance tracking.

FastAPI PostgreSQL LangChain Claude Haiku HTMX

Inside the dashboard

Screenshots from the live app — annual and monthly overviews, the daily spend trend, and the transactions feed with low-confidence flagging.

Expenso year overview: total spend, income, savings, a spending-intensity heatmap, and a monthly bar chart.
Year overview
Expenso monthly dashboard with anomaly callout cards.
Monthly overview
Daily spending trend chart in Expenso.
Daily spend trend
Expenso transactions page with search, filtering, and low-confidence flagging.
Transactions

The pipeline

Expenso connects to Gmail via OAuth2, pulls bank alert emails incrementally, and regex-parses each one into a structured transaction — amount, date, direction, merchant, UPI reference. Only confirmed successful transactions are kept; failed or attempted ones are discarded. The whole thing is built to be re-run safely: every insert is idempotent, so a missed night just catches up automatically the next run, with zero duplicate or lost data across 6+ months of daily runs.

Nightly pipeline architecture

Classification that gets better on its own

Every transaction moves through three tiers before it's filed:

1 · Rule-based

Substring match against 74+ known merchant patterns. Instant, full confidence.

2 · LLM fallback

Unmatched merchants go to Claude Haiku, which returns a confidence score. Anything ≥0.9 is auto-promoted into a new rule for next time.

3 · Manual override

Anything still wrong gets corrected inline — and that correction is learned as a rule too, so the system never makes the same mistake twice.

>90%
categorization accuracy
10
spend categories
~3 hrs
manual tracking eliminated / week
Three-tier classification engine

Ask it anything about your spending

A natural-language query interface translates plain-English questions into SQL via Claude Haiku, runs them against PostgreSQL, and returns a formatted answer — including multi-step analytical queries using CTEs. Every generated query is validated before it runs: SELECT/WITH only, no DDL, capped at 50 rows, 8-second timeout.

Ask Expenso natural-language query interface answering a spending question.
Ask Expenso
Natural-language query flow

Design principles

Immutability — raw emails are never modified; every transaction is re-derivable from source. Idempotency — every insert uses ON CONFLICT logic, so re-running any phase is always safe. Self-healing — incremental ingestion means the pipeline recovers from a missed night without intervention. A macOS launchd job runs the full cycle every night at 00:01, with a staleness check that notifies me if ingestion stalls for 3+ days.