Inspiration
Most financial education fails teenagers for one simple reason: it tells them about consequences instead of making them feel them. You can read that carrying a credit card balance at 18% APR is bad. You cannot feel that until you watch your $1,200 balance become a 7-year, $2,100 problem — while your emergency fund is empty and a medical bill just arrived.
We wanted to build the feedback loop that real life doesn't give you until it's too late. The moment that inspired the core mechanic was a simple question: what if you could replay the decision that started the spiral, and watch everything change from that point forward?
That question became FinSim.
What it does
FinSim is a personal finance life simulator. You start at 22 years old with $800 in savings and a job offer. Over 10 rounds — each representing roughly one year of life — you face real financial decisions:
- Round 1: Two job offers. More money now, or benefits and a 401(k) match?
- Round 3: A credit card arrives. Use it freely, or only for emergencies?
- Round 4: A $2,400 medical bill. Your answer depends entirely on Round 1.
- Round 8: Job loss. Three months of no income. How long does your savings last?
Every choice updates 8 live metrics — income, expenses, savings, total debt, credit score, retirement balance, debt-to-income ratio, and a stress index. Decisions compound forward: the rent you chose in Round 2 determines whether the car breakdown in Round 5 is an inconvenience or a debt spiral.
The Socratic AI advisor can be invoked up to 4 times per game. It never tells you what to choose. It asks you a question using your actual numbers — "You're earning $2,250/month after expenses. How much of your $35 minimum payment do you think actually reduces the $1,200 you owe?" — and forces you to reason through the consequence yourself.
The replay system lets you branch from any past decision point after your run ends. The original session is preserved as the source of truth. The replay creates a versioned branch, and the debrief shows a three-line divergence chart — your original path, your replay path, and the optimal path — splitting at the exact round where you chose differently. The dollar impact of that single decision is calculated and displayed.
$$\Delta_{\text{net worth}} = \sum_{r=k}^{10} \left( \text{metrics}_r^{\text{replay}} - \text{metrics}_r^{\text{original}} \right)$$
Where $k$ is the round of divergence. This makes the compounding effect of one decision visible as a number, not a concept.
The public share page generates a unique URL for every completed session — full round timeline, compounding chart, mistake pattern cards, and a one-click X post. Replay scores are excluded from the leaderboard to preserve integrity.
How we built it
FinSim is a pnpm monorepo with a Next.js frontend and an Express API backend.
Frontend — @finsim/web
- Next.js 16 (App Router) with plain JavaScript and Tailwind CSS v4
- Recharts for the net worth progression and divergence charts
- Framer Motion for the crisis pulse animation on rounds 4 and 8
GameContextholds client view state; all simulation logic lives on the server — the frontend only renders what the API returns- Public share pages rendered server-side for each unique session slug
Backend — @finsim/api
- Express 4 with JWT auth stored in httpOnly cookies
- MongoDB + Mongoose for users, sessions, setup profiles, and the full round audit trail
- Simulation engine (
services/simulation/) — pure JavaScript, fully server-authoritative. Five scenarios:baseline,recession,startup-founder,immigrant-household,single-parent. Each session gets a deterministic seed derived from its MongoDB_id, so the same choices always produce the same event sequence:
const simSeed = hashStringToSeed(session._id.toString());
- Mistake pattern detector — pure JS pass over
rounds[]before any AI call, tagging named patterns:CARRIED_CC_BALANCE,NO_EMERGENCY_FUND,SKIPPED_401K_MATCH,HIGH_RENT_RATIO,UNDER_NEGOTIATED_SALARY - Groq SDK (Llama 3.3 70B) for the Socratic advisor and post-game debrief
- RAG pipeline — knowledge base chunked across credit, debt, taxes,
investing, insurance, and behavioral finance; embedded with
@xenova/transformersand stored in Supabase pgvector; retrieved at inference time to ground the advisor in accurate financial concepts - Deterministic debrief fallback — if the Groq call fails, a pure JS pipeline builds the full debrief from round history and mistake patterns with zero AI dependency. The demo never breaks.
- Versioned replay sessions — replay branches reference the original
session's
_idand storereplayFromRoundso the divergence point is always known
Infrastructure
Everything runs on free tiers: Vercel (frontend), a VPS via GitHub Actions (backend), MongoDB Atlas, Supabase, and Groq. Total infrastructure cost: $0.
Challenges we ran into
1. Keeping the Socratic constraint Getting an LLM to ask instead of answer is genuinely hard. Capable models default to being helpful — they want to give you the right choice. We went through many prompt iterations before landing on a structure that enforced the constraint reliably: inject the player's exact numbers, specify the question must use those numbers, and explicitly forbid any form of recommendation language. We also added a server-side check that flags responses containing "you should", "I recommend", or "the best choice" and retries with a stricter prompt.
2. The divergence chart Showing three lines — original, replay, optimal — splitting at a single round marker sounds simple. Making it readable, emotionally clear, and correctly synchronized with the round audit trail took significant iteration. The key insight was anchoring everything left of the divergence point to identical values (since the choices were identical) and only computing deltas from round $k$ forward.
3. Server-authoritative migration Midway through building we realized client-side simulation made leaderboard integrity impossible — anyone could manipulate their metrics. Migrating to a fully server-authoritative model mid-project meant rewriting how the frontend consumed game state and ensuring every round transition was atomic on the backend. It was the right call and it made everything else cleaner, but it cost us half a day.
4. Leaderboard fairness
A $40,000 net worth in the recession scenario is a better result than
$90,000 in baseline. Flat ranking by net worth would punish players who chose
harder scenarios. We added scenario-filtered tabs and a decision quality score
(correct key decisions out of 5) as a secondary ranking signal so the
leaderboard rewards good thinking, not just easy paths.
Accomplishments that we're proud of
- The replay divergence chart — three lines splitting at a dotted round marker, showing the compounding ripple of a single decision across 7 remaining years. It makes an abstract concept visceral.
- A simulation engine with 5 meaningfully different scenarios, including
immigrant-householdandsingle-parent— because financial literacy is not a problem that affects everyone equally, and the simulator shouldn't pretend it does. - A deterministic fallback pipeline that makes the full debrief available even when every external service is down. We didn't want a hackathon project that only works under ideal conditions.
- The Socratic advisor prompt — it took the most iteration of anything we built and it's the feature that makes the biggest difference to how the game feels.
- Shipping a monorepo with a proper server-authoritative backend, RAG pipeline, versioned session branching, and a public share system in 4 days.
What we learned
- Compounding is hard to visualize and easy to feel. Every design decision we made that helped players feel the cascade was more effective than one that tried to explain it. The crisis pulse animation on round 4 taught more than any tooltip.
- Constraints produce better AI behavior than instructions. Telling the LLM "be Socratic" produced mediocre results. Structuring the prompt so the only grammatically valid response was a question produced consistently good ones.
- Integrity by architecture beats integrity by policy. Excluding replay
scores from the leaderboard by filtering
isReplay: trueat the query level is more reliable than any UI-level rule. Build the constraint into the data model. - Determinism is underrated in game design. Seeding each session from its
own
_idmeans every run is reproducible, debuggable, and fair — and it cost almost nothing to implement.
What's next for FinSim
- Classroom mode — a teacher dashboard that assigns specific scenarios to students, tracks class-wide decision patterns, and surfaces the most common mistakes for group discussion
- More scenarios —
gig-economy-worker,early-inheritance,student-loan-heavy— expanding the range of starting conditions to reflect more of the real population - Multiplayer cohort runs — a group of friends all play the same scenario simultaneously; after round 10 the debrief compares everyone's paths on the same chart
- Real financial data integration — actual interest rate curves, real median rent by city, live market return data — making the simulation calibrated to where the player actually lives
- Mobile app — the 15-minute format is perfect for a native mobile experience; the backend is already API-first and ready for it
Built With
- express.js
- javascript
- mongodb
- nextjs
- pgvector
- rag
- suapbase

Log in or sign up for Devpost to join the conversation.