From a crumpled receipt to a reconciled ledger.
Trackster is an expense tracker for freelancers and small businesses. Photograph a receipt on Android, let Claude read it, confirm the fields it wasn't sure about, and watch it land in QuickBooks. Trips, split bills, recurring expenses and eight currencies, all reconciled in one home currency.
The receipt is the truth. It just lives in a shoebox.
Freelancers mix business and personal spending across cash, cards and wallets, in more than one currency, and then try to reconstruct it for tax season. Typing receipts in by hand is the step everyone skips, so the books are always wrong by exactly the amount nobody entered.
Vision models can read a receipt now. The hard part is everything around that call: trusting the fields it's unsure about, working with no signal, syncing to the accountant's system, and keeping totals stable when the exchange rate moves.
Solo — web, mobile,
backend, billing
Two apps, one API, one data model, and the monetization stack on top — Stripe on web, Play Billing on Android, ads for the free tier. Currently on a testing VPS, not yet in the Play Store.
Next.js 16 · React 19 · Tailwind 4 · Recharts · Zod
Flutter · Riverpod 3 · go_router · dio · secure storage
PostgreSQL · Prisma 6 · 25 models · 22 migrations
Claude Haiku 4.5 vision · QuickBooks OAuth2 · FCM push
Stripe · Google Play Billing · AdMob / AdSense free tier
A camera, a queue,
and a ledger
Photograph a receipt; merchant, date, total, tax, line items and a category come back with a confidence per field.
Low-confidence fields land in a queue instead of silently in the books; duplicates warn but never block.
Each expense is pushed as a Purchase with the receipt attached, through a database-backed retry outbox.
Shared trips with invite links, per-member shares and a debt simplifier that settles n people in n−1 payments.
Daily to yearly templates that materialize into real expenses — with no cron job anywhere.
A scope on every expense, a VAT report, and CSV, Excel and PDF exports for the accountant.
Trust the model, verify the field
The extraction call is the easy part. The product is what happens when the model is 72% sure about the category: that field goes to a review queue, the other four are accepted, and the user fixes one thing instead of retyping five.
- Claude Haiku 4.5 by default, at roughly $0.004 per receipt; the model is a config value.
- Every field carries a confidence score; anything under threshold routes to review.
- A mock driver returns realistic data when no key is set, so the whole app runs offline in dev.
- Free tier meters scans per month; Pro and Business lift the cap.
Totals that don't
move while you look
Eight currencies, one home currency, and a rule: convert exactly once. Every chart, budget bar and export reads the same denormalized column, so the dashboard and the CSV can never disagree with each other.
The same discipline runs through trips: shares and settlements are integer cents, and the simplifier guarantees the fewest transfers with no rounding residue.
Fewer moving parts,
more guarantees
Due templates are materialized when the app calls /api/me — on every open. Missed periods are backfilled inside one transaction alongside the next-run advance, capped at twelve per template per call, and the function never throws.
Why — A cron on a personal VPS is one more thing to break silently. The user opening the app is the most reliable clock there is.
The mobile app queues expenses in secure storage and drains them on reconnect, resume or pull-to-refresh. The server enforces a unique constraint on user plus client request id — a follow-up migration scoped it per user after a cross-user collision.
Why — A retry that creates a second expense is worse than a failed sync. The database, not the client, has to guarantee once.
Every expense and income row carries a denormalized home-currency amount. No aggregate ever calls the FX service; they all sum one column.
Why — Live conversion means a dashboard whose totals drift while you watch. One conversion per row means the numbers are stable and auditable.
A dependency-free greedy min-cash-flow pass over integer cents turns a trip's tangle of shares into the fewest transfers, and a pure split module handles equal, percentage and exact splits.
Why — Nobody wants to pay six friends back; they want to pay one. Integer cents mean the last transfer never comes out at 0.01.
Extraction, storage and FX are interfaces with swappable drivers: Claude or mock, local or S3 or Cloudinary, live or cached. No vendor SDK is called from a route handler.
Why — Model prices change, storage moves, and a demo has to run without a single secret in the environment.