← All projects

Munny

Personal finance dashboard with Plaid sync. Answers "can I afford this?"

  • React
  • TypeScript
  • Node.js
  • Express
  • MongoDB

Budgeting tools tell you what you already spent. Munny tells you whether a purchase fits in the rest of the month, accounting for pending transactions, scheduled recurring charges, and savings goals.

Plaid sync

node-cron runs nightly. For each linked account, fetch the latest 30 days of transactions, dedupe by Plaid transaction ID, and reconcile pending-to-settled transitions. Pending charges are stored with a tentative flag so they show on the dashboard but don't double-count once they settle.

Decision endpoint

Takes (amount, category, accountId). Simulates the rest of the month forward:

  1. Apply the candidate purchase
  2. Subtract scheduled recurring charges through end-of-month
  3. Subtract savings-goal contributions still owed
  4. Return the first constraint that breaks — category cap, savings target, projected end balance — or null

Response is { ok, brokenBy, projection }. The UI uses brokenBy to explain why a no is a no, which turns out to matter more than the yes/no itself.

Recurring-charge ownership

A recurring charge has to be assigned to a specific account or the projection lies. The naive "whatever account it last hit" fails when you rotate cards. Munny uses a weighted-recency heuristic on the last few occurrences, plus a manual override. Still gets it wrong sometimes; that's why the override exists.

Stack

Vite + React + React Query + Auth0 on the client. Express + Mongoose on the API. Zod schemas shared between them. API on Fly.io, SPA on Cloudflare Pages, MongoDB Atlas.