Case study — AI product, end to end

ThoughtExpense.

"Say it. We track it." An AI expense tracker where logging is one typed sentence — and everything downstream learns from it. Product, design, Android app, web app, and backend: one person, end to end.

ThoughtExpense — AI expense tracking on Android and web
3
Clients shipped solo — Android, web app, API
45+
REST endpoints behind one response envelope
26k
Lines of TypeScript across the monorepo
175
Item category catalog guarding the LLM

The problem

Every expense tracker asks for a category, a date, and an amount — and most people quit within two weeks. When capture dies, the budgets, insights, and advice built on top of it die with it.

The fix

Make capture cost nothing, then earn the rest: Gemini-parsed natural-language logging that learns each user's habits, statistical spending intelligence the LLM only narrates, an AI advisor with honest savings plans, and a metered free tier that converts through RevenueCat — shipped as an Android app, a web app, and a production API.

React Native
Expo
Next.js 16
TypeScript
Express
PostgreSQL
Prisma
Redis
BullMQ
Gemini AI
Pinecone
RevenueCat
Resend
DO Spaces
Tailwind v4
Quick Log screen parsing natural language into categorized expenses

/01 Quick Log — the whole product in one input

Type it like you say it

Expense trackers die from the logging tax: pick a category, pick a date, type an amount, quit within two weeks. ThoughtExpense collapses all of it into one sentence — "coffee 120, uber 250 and groceries 900" becomes three categorized, dated expenses. Gemini handles messy separators, currencies, and natural dates like "yesterday" or "last monday", and always with the user's own history in the prompt.

Latency is designed, not suffered. A debounced on-device parser shows "3 items detected" with category guesses before any network call — composing works offline. The single opaque LLM call becomes staged feedback (identifying amounts → categorizing → saving), and N parsed items save as one batched write, because per-item POSTs were tripping rate limits.

Home dashboard with learned mapping, catalog guardrail, and RAG annotations

/02 The learning loop

A parser that gets better the more you use it

Two loops compound. When a user corrects a category, the server tokenizes the description and stores a keyword mapping; when a parse succeeds, the worker reinforces it. Both feed back into the prompt as learned history — "netflix → Streaming Services (used 10x)" — so categorization stays consistent per user instead of drifting per request.

And because a probabilistic model needs deterministic guardrails, a hand-authored 175-item category catalog overrides the LLM on a keyword hit with confidence pinned to 0.99, and anything parsed below the 0.7 threshold comes back in a needsReview array for the user to confirm. Every expense is also embedded into Pinecone — isolated per user — powering semantic search ("coffee last month over 500") and similar-expense lookups.

Spending Analysis screen with the statistical rules that drive it

/03 Spending intelligence

Statistics decide. The LLM narrates.

The insights that must be correct are never left to the model. Anomalies fire only at ≥50% above the median of prior months and ≥5% of the month's total; large transactions need mean-plus-two-sigma over at least five samples; waste detection finds price creep, overlapping subscriptions, and small leaks with documented, conservative thresholds — all pure, currency-normalized functions.

The LLM then writes the story under strict rules: quote real numbers, never invent them, never lecture. The same discipline runs the AI advisor — client-side intent routing sends savings questions to a structured plan endpoint that may not cut essentials and must honestly say when a target is unreachable — and the Monday weekly briefing, fanned out per user through a BullMQ scheduler and delivered by email.

Monthly Budget screen with natural-language category budget generation

/04 Budgets in plain language

"Food 500, Rent 2000" is a budget

Budgeting gets the same interface as logging: type category limits in one line, Gemini returns a structured breakdown seeded with the user's own categories, and an editable review table makes it real. One number leads the screen — Safe to Spend — traffic-lit teal, amber, red, with warning banners at 90% and 100% and a year of month history behind it.

Savings goals close the loop: contribute or withdraw, auto-complete on reaching the target, auto-reopen if it drops below. Every amount everywhere is multi-currency — stored in its original currency and converted at read time through a cached FX layer that falls back to the original amount rather than ever showing a wrong conversion.

Expenses and Profile screens with the premium gating model

/05 The business model, engineered

A free tier that sells Premium politely

Free and Premium split across six surfaces — receipt scanning, CSV/PDF export, full history, advisor quota, daily insights, ads — and every upsell appears exactly where the wall is hit, never as an interrupt. The advisor's five free questions a month are metered in Redis and fail open: if Redis is down, the user wins, not the meter.

Billing is RevenueCat over Google Play with the full webhook edge-case matrix — cancellations keep access until period end, billing issues get a grace state, refunds cut immediately, and unmappable events return 200 so retries stop. The paywall builds plans from live store offerings, computes the save-percent badge from real prices, and degrades to static pricing on builds without billing keys.

ThoughtExpense marketing site in a browser frame

/06 One system, three clients

Android, web app, and marketing site from one design language

The Expo app was built in a four-day sprint on the proven API — fifteen screens, RevenueCat billing, a hand-rolled SVG donut chart, a sixty-line keyboard-avoidance primitive that replaced a whole native dependency, and a Play Store listing kit generated from version-controlled HTML. The Next.js client is a marketing site and a phone-shaped web app in one codebase, split by route groups.

The web side treats SEO like a product surface: JSON-LD generated from the same array that renders the FAQ, seven dynamic OG-image routes, sitemap priorities, robots rules keeping the dashboard unindexed. Privacy and terms name every subprocessor and pledge no AI training on user data — and the backend's account-deletion endpoint actually reaches into Pinecone, Spaces, and Redis to keep that promise.

Three explored art directions: Refined Teal, Ink & Mint, Paper Ledger

/07 Design process, receipts kept

Three directions, one winner, written rationale

The design canvas explores three named art directions on one consistent demo dataset: Refined Teal (calm cards, Instrument Sans, the brand evolved), Ink & Mint (dark-first, oversized numerals), and Paper Ledger (warm paper, serif masthead, mono amounts). A won — and the canvas annotations record why, with B and C kept for reference.

The chosen tokens run everywhere: the app's theme system with separately tuned dark-mode category tints, the web client's three-layer token architecture, the transactional emails, the store assets, and the app icon set. One brand from splash screen to inbox.

From a sentence to structured data

The parse pipeline

You type

"coffee 120, uber 250 and groceries 900" — commas, newlines, sentences, any of it.

Instant preview

An on-device parser shows items and category guesses in milliseconds, offline.

Gemini + your history

The model parses amounts, dates, and specific categories, guided by learned mappings and a 175-item catalog.

Saved — and learned

One batched write, embeddings to Pinecone, new mappings stored. Next time it knows.

✓ 3-model fallback chainAsync BullMQ variants for mobileReceipt OCR reuses the same pipeline

Building an AI productthat has to be right?

ThoughtExpense is what I mean by AI engineering: learning loops, deterministic guardrails, honest fallbacks — and a business model wired in from day one. If you're building something where the AI has to earn trust, let's talk.