All projects

Fortuna

A finance app that asks how you felt when you spent it.

Role
Solo engineer — product, backend, mobile, infra
Timeline
Dec 2025 — Present
Status
In active development
29 tables in the schema
2 platforms shipped from one codebase
8 emotional states tracked per expense

A production personal finance app built on a simple bet: the reason people overspend is emotional, so the ledger should record the feeling alongside the amount.

Why it mattered

Every budgeting app I tried could tell me I spent $16.99 at a restaurant. None could tell me I did it because I was hungry and my friends were going anyway. That second fact is the one that predicts whether it happens again next week.

The problem

Budgeting apps stop at categorisation. They produce a tidy record of what already happened and no insight into why, which is exactly the part a person needs in order to change anything. I wanted a system that captured the trigger, not just the transaction.

What I built

  • Emotional ledger: each expense can carry how you felt, why you bought it, and a named trigger (social pressure, stress, boredom), so patterns surface as behaviour rather than as pie charts.
  • Aura, an AI financial coach on Anthropic Claude, running conversational sessions and generating budgets from observed spending — with tool-forced structured outputs and PII stripped before egress.
  • Receipt OCR that extracts line items, prices and merchant from a photo, then asks the user to confirm before anything is written.
  • Plaid bank linking with live transaction sync, plus an ecosystem model for the people, pets and commitments money actually flows to.
  • React Native across iOS and Android with biometric auth, and a FastAPI and PostgreSQL backend with JWT/MFA, row-level security and device-bound sessions across a 29-table schema.
  • Celery and Redis running timezone-aware financial pipelines and APNS delivery per user.

Inside the app

The product in order: the daily surface, the emotional check-in that makes the ledger different, then the coaching and automation built on top of it. Click any screen to enlarge

Fortuna home screen showing monthly net, income, spend and impulse percentage
HomeNet position, impulse rate and the day's coaching prompt on one surface.
Fortuna emotional check-in screen offering eight states such as calm, drained and stressed
Emotion check-inAsked at capture time, before the numbers — while the honest answer is still available.
Fortuna expense detail showing emotional context, reason for purchase and a social pressure trigger
Expense reflection$16.99 is the small fact. “Social pressure, felt hungry” is the one that predicts a repeat.
Fortuna receipt scanning screen prompting the user to photograph a receipt
Receipt captureOCR pulls items, prices and merchant — the user confirms before anything is written.
Aura AI coach screen presenting a spending snapshot and budget suggestions
Aura: budget intelligenceAura reads the month and proposes the next concrete move, not a chart.
Aura coaching conversation discussing recent account activity with the user
Aura: coaching sessionA conversation with context on your accounts, not a generic chatbot.
Fortuna budget screen with an Aura-generated smart budget based on spending patterns
Generated budgetsBudgets generated from observed behaviour, then handed back for approval.
Fortuna accounts screen showing two Chase accounts connected through Plaid
Bank syncPlaid linking with live transaction sync across connected accounts.
Fortuna ecosystem screen for tracking people, pets, projects and commitments
EcosystemThe people, pets and commitments money actually flows to, modelled explicitly.

Engineering notes

Asking the question at the right moment

An emotion prompt is worthless an hour later — you have already rationalised the purchase. The check-in fires at capture time, in the same flow as logging the expense, which is the only point where the honest answer is still available.

Privacy before the model call

Emotional and financial data is about as sensitive as a dataset gets. A sanitization layer tokenizes identifying fields before anything leaves for the model, so Aura reasons over shapes and amounts rather than identities.

Failure is a product decision

A circuit breaker wraps every model call. When the provider degrades, the app falls back to deterministic summaries instead of hanging on a spinner — a smaller answer beats no answer.

Timezone-aware money

Recurring cashflows evaluate in the user's local timezone, not the server's. Celery schedules per user rather than as one nightly global sweep, which is what makes a 'rent posts tomorrow' notification arrive at the right hour.

Curious about any of this?

I am glad to go deeper on the architecture, the tradeoffs, or the parts that did not work the first time. That conversation is usually more useful than the README.