Exityear

An ~8,000-line financial simulator that runs entirely in your browser. Solo-built, launched, monetized, and deliberately sunset.

~8k
lines · pure engine
22
calculation modules
210
regression tests
100%
client-side compute

A solo build, measured by craft rather than traction. See the sunset note on why I moved on.

The problem & the bet

Most people never get to see the two questions that decide financial independence: when can I stop working, and what does a real life change cost me? Moving cities. Taking a sabbatical. Buying versus renting. The tools that answer this well (Boldin, formerly NewRetirement) are powerful, but expensive and dated.

Exityear’s bet: put professional-grade modeling (Monte Carlo, a full US tax engine, multi-scenario “Life Branches,” and geographic-arbitrage cost-of-living) behind a fast, opinionated UI at a fraction of incumbent pricing, and compute all of it on the user’s device so their finances never touch a server.

Architecture at a glance

Three constraints drove every technical decision: correctness (wrong numbers kill a finance product), privacy(people won’t hand their net worth to a startup), and instant feedback (planning is exploratory, so latency kills it).

Browser
  ├─ React UI (Next.js 15, App Router)
  ├─ Web Worker ──► calculation engine   ← ~8k LOC, pure, no I/O
  │                 (income · debt · tax · Monte Carlo · drawdown)
  └─ PocketBase ──► auth + your saved scenarios only
                    (the math never leaves the browser)

Decisions & trade-offs

The interesting part of a build isn’t the feature list. It’s the calls made under real constraints, and what they cost.

01

A pure, testable engine as the defensible core

Decision
Build the retirement math as ~25 dependency-free TypeScript modules with a locked regression suite, rather than lean on a BI/charting library or a backend service.
Trade-off
I had to build (and own the correctness of) a full US tax model, covering federal brackets, FICA, NIIT, and all 50 states, instead of buying one.
Outcome
Any change to tax or drawdown logic had to prove it didn't move known-good outputs, so I could iterate on a 1,300-line projection engine fast without silently shipping wrong retirement numbers.
If I did it again
Same call. The regression suite paid for itself the first time a refactor tried to change a number it shouldn't have.
02

Run the whole simulation client-side in a Web Worker

Decision
Compute every projection in the browser, off the main thread, rather than server-side.
Trade-off
No one's income, assets, or debts ever hit my server (privacy) and recalcs felt instant (no round-trip). The cost: I owned data integrity at the worker boundary and gave up server-side precompute for sharing/SEO.
Outcome
Added a sanitization layer so non-finite math could never reach the charts. Privacy became a real product promise, not marketing.
If I did it again
Keep it. But I'd invest earlier in the serialization contract between worker and UI; that boundary caused the subtlest bugs.
03

Migrate the entire backend from Supabase to PocketBase

Decision
Replatform auth + data off Supabase to a self-hosted stack to cut recurring cost and own the layer. A high-blast-radius change touching every read and write.
Trade-off
Meaningful monthly savings and full control, paid for with a tail of concurrency bugs (PocketBase auto-cancellation) I hadn't priced in.
Outcome
Sequenced it staging-first with idempotent migration scripts and kept the old layer live until the new one verified, then absorbed the stabilization tail.
If I did it again
I underestimated the new platform's concurrency model. I'd spike the riskiest integration (request cancellation) before committing the whole migration.
04

Monte Carlo as the paywall line

Decision
Model uncertainty (success-rate, percentile bands) instead of a single deterministic 'you retire at 52,' and make Monte Carlo the free/paid boundary.
Trade-off
Running 1,000 simulations in the browser meant trading accuracy against latency, so I tuned simulation count and volatility defaults to keep it responsive.
Outcome
The paywall mapped cleanly to value: certainty is the premium feature. Monetization read as product judgment, not a tollgate.
If I did it again
I'd A/B the free-tier limits earlier; I set the free/paid line by intuition, not data.

Engineering for trust

For a financial product, credibility is the whole game. The tax modules cite their sources (IRS / Tax Foundation) in-file, and a Vitest suite pins known-good outputs so the numbers can’t quietly drift:

// projections-regression.test.ts: the numbers are the product
expect(result.retirementBalance).toBeCloseTo(expected, 2)
expect(result.annualRetirementIncome).toBe(knownGood)

That same suite came along verbatim when I forked the engine for the simplified live version and still passed, proving the port didn’t move a single number.

Build once, use twice

The geographic-arbitrage feature ran on a dataset of 100+ cities’ cost-of-living indices. That same dataset generated 130+ programmatic-SEO destination and comparison pages, dynamic Open-Graph social cards, and structured data tuned for LLM-answer visibility. One dataset served both the product and a free organic acquisition channel.

Why I sunset it

Sunsetting Exityear was a deliberate prioritization call, not a flameout. I set out to test whether a solo builder could ship a correct, trustworthy finance product. Technically, the answer was yes.

The harder answer was the market one. Retirement and FIRE planning is a saturated space with entrenched, well-funded incumbents (Boldin and others), and I concluded a solo product had little room to carve out a durable, defensible wedge. Rather than keep pouring time into a crowded market, I made the opportunity-cost call and moved on. I reallocated focus to Kaiwaflow, a Japanese language-learning app, where I saw more room to build something differentiated.

Choosing to stop a project you’ve invested real work in is the same “saying no” muscle a TPM uses to kill a low-ROI workstream and redeploy the effort. Exityear never chased scale, so there was no user base to wind down. Instead, the engine lives on as an open, privacy-first free tool .

An honest note on how it was built

Exityear was built solo with heavy AI assistance. What I owned, and what this page is really about, is the problem framing, the three architectural constraints, the trade-off calls (client-side compute, the backend migration, the paywall line), the sequencing, and the decision to sunset. Those are the parts that don’t come from a code generator.

Try the simplified version

The engine, minus the accounts and the price tag, runs entirely in your browser.

Open Exityear Lite