Post-mortem

Guide2Profit — Startup Financial Modelling

A financial-modelling SaaS that replaced a founder’s spreadsheet: costs, payroll and funding plans in; five-year forecasts, P&L, break-even and funding requirements out. We built it properly and it went nowhere — because founders do not want to model their own finances. This is what we built, and the conversation that ended it.

Role
Developer — architecture and build
Origin
My friend’s idea; the two of us built it
Period
Aug — Sep 2024
Status
Shelved — no market fit

React/Node.js/Express/Supabase/PostgreSQL/JWT/Google Gemini/Vercel

11

Financial modules

4 input, 7 output

7

Calculation engines

six pure, one reaches for its model

14

Client screens

forms, dashboards, glossary

166

Files

97 client, 68 server

01 Context

Someone else’s spreadsheet.

The idea was not mine. A friend of mine had the domain knowledge and a financial model that worked — in a spreadsheet. We built it together: his concept, my code. My job was to turn that model into a system other founders could use without inheriting his formulas, his tab structure or his assumptions about which cell you were allowed to touch.

Spreadsheets are excellent at financial modelling and terrible at being software. The maths is entangled with the layout, every copy immediately diverges from the original, and one overwritten cell silently corrupts every figure downstream with no warning and no history.

So the brief was narrow and clear: keep the model, lose the spreadsheet. A founder should enter what they know — what it costs to start, who they will hire, what they expect to sell — and get back the statements an investor asks for.

02 Architecture

Inputs one side, outputs the other.

Startup finance has an awkward property: the outputs depend on each other. Break-even needs the P&L. The P&L needs the sales forecast and payroll. Funding requirement needs almost everything. Model that carelessly and you get a web of modules reading each other’s database tables, where changing one number means guessing what else moved.

The server is split down that seam instead. Everything a founder enters lives under one namespace; everything the system derives lives under another. Four input modules feed seven output modules, and the direction is strictly one-way.

  • Startup costOne-time spend before revenue begins
  • Employee payrollHeadcount, salaries and the cost of each hire
  • Operations & financeThe recurring cost base and revenue assumptions
  • Funding planEquity and loans, and when that cash actually lands

From those four, the system derives 7: sales forecast, forecast p&l, break-even analysis, cogs calculator, salaries, funding requirement, startup cost summary. Every input module is the same three files — controller, model, routes; every output module adds a fourth. A new financial output is a known shape rather than a design discussion.

03 Calculation

The maths never touches the database.

Each of the seven output modules carries a fourth file the input modules do not: a calculation engine. It holds the arithmetic, and it is the only file that does. Controllers handle the request, models handle persistence, and the engine is handed plain data and returns plain data.

The break-even engine is the clearest example. It takes the sales forecast and the P&L as arguments — not as queries — and returns an object. It reads nothing, writes nothing, and has no idea a database exists.

That constraint buys two things. The arithmetic is testable without a database, and the dependency between outputs is visible in a function signature instead of buried in a query. If break-even needs the P&L, you can see it in the parameter list.

Six of the seven engines hold that line. The funding engine does not — it imports its own model and fetches rather than being handed what it needs. It is the one place the rule is broken, and it is also the module I find hardest to reason about, which is about as clean a demonstration of the rule’s value as I could ask for.

It also forces the edge cases into the open. Division by a gross margin of zero is the obvious way a financial model explodes, and the engines guard it explicitly rather than letting an Infinity propagate into a founder’s forecast.

11

Financial modules

4 input, 7 output

7

Calculation engines

six pure, one reaches for its model

14

Client screens

forms, dashboards, glossary

166

Files

97 client, 68 server

04 The assistant

An LLM that may not add up.

The product has an assistant built on Google Gemini. Founders using a financial planner do not usually know what “capital work in progress” means, and answering that in a glossary nobody opens is worse than answering it in place.

The interesting decision is what the assistant is not allowed to do. Its system prompt forbids arithmetic outright — it explains what a figure means, what belongs in it and how to gather it, then hands the user back to the form. It never produces a number.

This was deliberate. A language model that confidently miscalculates a break-even point is worse than no assistant at all, because the output looks exactly as authoritative as the correct one. The deterministic engines own every figure in the product; the model owns the explanation and nothing else.

It is personalised rather than generic: the service reads the user’s stored startup stage, industry, business model and company description, and folds them into the prompt, so the guidance refers to the business actually being planned.

It is also capped — twenty messages per user per day, enforced server-side and answered with a 429. An LLM endpoint with no ceiling is someone else’s bill.

05 Why it stopped

Nobody needed it.

We demoed it to a founder at Kissflow. His answer took about a minute, and it was right.

A startup founder does not want to model their own finances. The work is tedious, the stakes are high enough that you want a professional, and the professionals already exist — you hire an auditor or an accountant and hand them the problem. Asking a founder to sit down and enter five years of payroll assumptions is asking them to do a job they were always going to delegate.

We had built for a user who does not exist: someone financially literate enough to fill the inputs in correctly, but not yet organised enough to have hired the person who normally does. That gap is much thinner than it looks from inside the build.

So we stopped. The product works — 14 screens, eleven modules, a Supabase-backed API — and none of that was the problem. It solved a headache founders resolve by paying someone else to have it.

There is no live link on this page for the same reason there is no traffic. The Vercel frontend still serves, but the backend sits on a Supabase free tier that sleeps after inactivity, and it has been inactive for a long time. Calling it “live” would be a nicer sentence and a false one.

06 Retrospective

What the failure taught me.

I would have had that conversation in week one. The objection that ended the project cost one demo and could have been sought out before a line was written. We spent five weeks building an answer and no time at all checking whether anyone had the question. That is the whole lesson, and it is not a technical one.

I would write the engines in TypeScript. The calculation files are the one place in the codebase where a wrong type is genuinely expensive, and they are plain JavaScript. Every engine takes loosely-shaped objects from upstream modules and trusts the fields are there.

I would test the engines from day one. They were built to be testable — pure, no I/O, arguments in and an object out — and then not tested. That is the cheapest test suite in the project going unwritten.

I would fix the funding engine. Six engines are pure functions and one is not, which means the rule is a convention rather than a constraint. Nothing stops the next engine from reaching for the database too.

I would version the model. A founder’s plan is a document that changes over months, but the schema stores the current state rather than a history. Being able to ask “what did this forecast look like before we changed the hiring plan” is most of the value of doing it in software at all.

Happy to talk about the ones that did not work.

The source is public, so everything above is checkable. I think a project that failed for a clear reason is worth more in conversation than one that quietly succeeded.