Build Mortgage Coach
KINDAback to the verdict
A loan comparison builder whose entire value is that the numbers are correct and their assumptions are visible: amortisation computed exactly, every scenario stating its inputs, and an output that cannot be mistaken for the regulated disclosure it is not.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the calculation engine and the document renderer.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - installfree
Why Three hundred and sixty periods of floating point produces a closing balance that is not zero, and a borrower checking your numbers will find it.
Get it Any well-tested arbitrary precision decimal library for your runtime.
Verify
A thirty year schedule closes at exactly zero - have readyfree
Why Your own calculation cannot verify itself, and the whole value of this tool is that the numbers hold up.
Get it Take a published schedule from a regulator or a bank for a stated principal, rate and term, and use it as a test fixture.
Verify
Your schedule matches the published one to the cent - decidefree to decide; compliance advice if this is commercial
Why Using a regulated term for a figure computed differently is the most serious thing this build can get wrong, and the decision belongs before the first calculation.
Get it Decide whether you will implement the regulation's own calculation exactly. If not, choose different names for your figures and write down what each includes. open ↗
Verify
A written note names every displayed figure and states exactly what it includes - have readyfree
Why Phase 5 requires the output to be visually distinct from them, which you cannot check without having them side by side.
Get it Download the official sample forms from the regulator.
Verify
Your output and the official form are distinguishable at a glance
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- scenarios(id, comparison_id, label, principal_minor, rate_bps, term_months, product_kind, points_bps, fees_json, escrow_json) - assumptions(scenario_id, key, value, source) · tax rate, insurance, appreciation, inflation, anything that moves a number - schedules(scenario_id, period, payment_minor, interest_minor, principal_minor, balance_minor) · generated, retained, checkable - rate_quotes(id, scenario_id, rate_bps, quoted_on, source, expires_on) · a rate has a date or it is not a rate - comparisons(id, borrower_ref, created_by, created_at, published_at, disclaimer_version) - outputs(id, comparison_id, path, rendered_at, inputs_hash) · so a document can be reproduced exactly from its inputs - Every displayed figure is derived from a retained schedule, so there is no summary number that cannot be traced to a row.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DATABASE_URLsecret | required | postgres://localhost:5432/comparisons | Borrower scenarios and figures. Financial data about identified people. |
ROUNDING_POLICY | required | half_up_cent | Stated on every output, because a borrower comparing against a bank needs to know. |
RATE_EXPIRY_DAYS | required | 7 | How long a quoted rate is presented as current. Short, because rates move. |
APR_TERM_ALLOWED | required | false | Whether the regulated term may be used. False unless the regulation's own calculation is implemented exactly. |
DISCLAIMER_VERSION | required | 2026-09 | Recorded per comparison, so you know what a past document said. |
COMMON_HORIZON_MONTHS | required | 120 | The default comparison horizon. Same across scenarios or the comparison is meaningless. |
The build, in order
Amortisation that survives being checked
Your schedule matches an independent calculation to the cent.
Three hundred and sixty periods of floating point is a visible error.
Files
src/money.tsAn independent source, in the test suite. Your own maths is not a check.
Files
tests/amortisation.test.tsAnd assert the closing balance is exactly zero.
Files
src/amortise.ts
done when · tick each as it passeswatch out- Floating point arithmetic over three hundred and sixty periods accumulates error that shows up as a final balance that is not zero, and a borrower who checks your figures against a bank's will find the discrepancy and stop trusting the whole document. Use exact decimal types, state the rounding policy, and assert the final balance is exactly zero.
Products that are not simple loans
Adjustable rates, interest-only periods and buydowns compute correctly.
Both. Applying only one produces a worst case that is wrong.
Files
src/arm.tssrc/arm.test.tsNot as an option. Suppressing it is the misleading default.
Files
src/scenarios.tsThe end of an interest-only or buydown period is what surprises people.
Files
src/steps.ts
done when · tick each as it passeswatch out- Showing an adjustable rate loan at its initial rate for the whole term makes it look permanently cheaper than a fixed one, which is the single most misleading thing this category of tool can do. Compute and display the fully indexed and cap-limited worst case beside the initial period, always, not as an option.
Comparing scenarios on the same assumptions
Two loans are compared fairly or the comparison is refused.
Different horizons produce any answer you like.
Files
src/compare.tsAt the top, not in a footnote. This is where comparisons mislead.
Files
src/compare.tsPoints against rate is the actual question. Answer it with a number.
Files
src/breakeven.tssrc/breakeven.test.ts
done when · tick each as it passeswatch out- Comparing two loans over different horizons, or with different assumed tax and insurance figures, produces whichever answer the person building it wanted, and it looks entirely legitimate. Require assumptions to match, and where they genuinely differ, show the difference at the top rather than in a footnote.
Rates have dates
No figure is presented as current when it is not.
A rate without a date is not information.
Files
src/rates.tsIn the document, not only in the editor.
Files
src/rates.tsPossible, deliberate and recorded.
Files
src/publish.ts
done when · tick each as it passeswatch out- A saved comparison reopened three weeks later shows rates that are no longer available as though they were, and it is the most likely way this tool misleads someone without anyone intending to. Attach a date to every rate, expire it, and make a stale comparison visibly stale rather than quietly wrong.
A document that is honest about what it isproduct builder
Nobody could mistake the output for a regulated disclosure.
Not in a footer. A borrower has to be able to tell.
Files
src/render.tsOn the document. Hidden assumptions make it a sales tool.
Files
src/render.tsSame inputs, identical document, verified by checksum.
Files
src/render.tstests/reproducible.test.ts
done when · tick each as it passeswatch out- Borrowing the layout or the language of the official disclosure makes the document feel authoritative in exactly the way it should not, and a borrower will reasonably treat it as the real thing. Make it look like what it is, state the distinction on the first page, and include the schedules so the figures can actually be verified.
That is the whole plan for Mortgage Coach. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Producing any regulated disclosure.
- Live lender rate feeds.
- Underwriting and eligibility assessment.
- Advice or recommendation.
- Integrations with loan origination systems, pricing engines and CRMs, so every scenario is typed in by hand
- Compliance-vetted presentation output and audit trail, which is the entire reason a regulated lender licenses this instead of using a spreadsheet
- Borrower engagement tracking: who opened the presentation, how long they looked, which option they clicked
- Polished branded video and mobile presentation formats that agents and borrowers are used to receiving
- Someone else maintaining the edge cases: ARMs, buydowns, MI structures, state-specific cost lines
- Scenario sensitivity, showing what a rate move does to the comparison
- A borrower-facing view that lets them change assumptions themselves
- Refinance break-even against an existing loan, which is the other common question
Need the files? The project pack on the verdict page hands your agent the whole brief · more finance & accounting.