What Real Data Does to Vibe Coding
Building a private lending tool, and what it taught me about transitioning from a spreadsheet

By the time I built a loan management app for my private lending portfolio, vibe coding had stopped feeling like a novelty to me. I had already built LinkHill because LinkTree annoyed me, Hillmeet because Doodle didn’t have an MCP gateway, Thankhill because Gratitude Plus wouldn’t stop upselling me, and a fabric pattern generator because image AI couldn’t lay down kanji characters precisely enough for textile printing
If you’ve read my earlier pieces on this, you know the pattern. Find something that doesn’t fit, build exactly what does, stop there.
What was different about the lending app was not the motivation. The motivation was the same. What was different was that this time I had years of real, messy data that predated the app, and getting that data right turned out to be the hardest part of the whole project.
My old spreadsheets were getting stale
I manage a small portfolio of private construction loans across multiple entities. The loans aren’t all the same. Some are interest‑only, some prepaid, some amortizing. The spreadsheet had no real model for any of that.
I had been tracking everything in a spreadsheet for years. It worked in the way spreadsheets always work. It evolved. Over time, it also accumulated evidence of that evolution. In my case, that evidence showed up as comments.
The spreadsheet stopped being a system and became a place where I stored numbers and carried the meaning in my head. When I added new loan types, I didn’t restructure anything. I just pushed the missing pieces into comments. Month after month, I found myself annotating cells to explain what the numbers actually meant. It worked until it didn’t.
The recurring friction
Each month I receive one payment per loan and have to confirm it’s correct. Before the app, that meant mental math or digging through the spreadsheet. Now the app pre‑calculates what each payment should be. I confirm and move on. That improvement alone would have justified building something.
However, the moment that crystallized the problem was tax season. Each entity issued its own 1099‑INT, and I had to reconstruct a full year of payments to separate principal from interest across loans and entities. That was the same split I had been tracking in comments. I realized I hadn’t actually modeled the data. I had been approximating it.
A month later, I started vibe coding an app.
Why commercial software was not the answer
I looked at dedicated loan servicing software the same way I had looked at commercial gratitude apps. These packages are built for someone else.
The loan servicing category serves mortgage servicers processing large volumes across many borrowers. I have one borrower relationship and one question I need answered every month. I need to know the net spread between what I earn on the loans and what I pay on the lines of credit that fund them.
I couldn’t find an off‑the‑shelf product that modeled my situation. Building from scratch took a few days. Configuring something general‑purpose into shape would have taken longer and still not quite fit.
What made this project harder
The hard part wasn’t writing the app. It was reconciling the reality my old spreadsheet had been approximating.
With Thankhill, there was no prior history. We started journaling and the app captured it from day one. With this lending app, I had years of activity that predated the system. Getting it right meant going back to original contracts, matching deposits to bank records, and aligning every payment to the right loan, entity, and period.
That process surfaced something I had been glossing over.
With the app, March 2026 shows zero income in the monthly report. That is correct. In late March, a batch of checks was stolen in the mail, cancelled, and reissued on April 2nd. My old spreadsheet tracked the month a deposit corresponded to, which would have placed those payments in Q1. The app records actual deposit dates, which places them in Q2.
My tax advisor and I work on a cash basis. The old approach was silently wrong in a way I had never been forced to confront.
The other thing I did differently this time was verify the interest calculations by hand before trusting the app with anything real. A vibe‑coded financial tool can be wrong in ways that are hard to notice until the number matters. I checked the math carefully against known figures. It was correct. But that step wasn’t optional.
Where it stands
The app generates payoff statements in a few clicks and reports principal, accrued interest broken out by period, total due, and a daily interest rate. It used to be a manual calculation done under time pressure.
The monthly report shows interest income, line of credit cost, and net spread side by side. March is negative. The app says so clearly, which is exactly what I wanted.
Through all of this, the build versus buy question ended up being the least interesting part. The app came together quickly. The harder work was confronting all the quiet assumptions my spreadsheet relied on me to carry.
Vibe coding made it easy for me to build something that felt right. Real data forced me to make it actually correct.
Editor’s note: In reading this, Marsha did make the very good point about my use of AI. Even though the AI did a good job analyzing my old spreadsheet and correctly calling out the loan types from the spreadsheet comments, it left out, without my realizing it, one of the loan types in the spec as it was constructing the development plan. Once it had built the user interface, I asked it what happened, and AI told me that it simplified the spec to get me started quickly. But then, when I started adding back the missing loan type, the perfectly working MVP started unexplainably breaking! Frustrated, I went to bed and tackled the missing loan type with my AI agent the next day! Marsha felt it was important to relay this point to anyone who thinks that AI is unadulterated magic. It’s magic, for sure, but it can go wrong when the user (in this case, yours truly) is not paying attention!
P.S. I am also pasting in the conversation I had with Claude AI after finishing this app to ask if I did the right thing.
Me:
Given that I didn’t use you to help write it, I wanted an objective analysis on why this was a good candidate for vibe coding. I found that the AI who used to help me write it was a bit syncophantic about why this was done so well, so I wanted to go to you (because you weren’t involved). Here are some more screens. Tell me what is right about this (and what is wrong about this), as I’d like to share this experience with others. Also, without my telling you, how long do you think it would take a reasonably decent vibe coder to build, debug, and get all the data into a tool like this?
Claude:
Why this was a genuinely good candidate:
No commercial fit. The LOC-funded lending spread model — borrow from JPM/NTRS at one rate, lend at a higher rate, track net income — isn’t a standard product category. You’d be fighting software designed for mortgage servicers or simple bookkeeping.
Contained, stable domain. Private lending rules (interest accrual, payoff math, amortization) are precise and don’t change shape. AI coding works best when you can describe the rules clearly, and loan math is describable.
CRUD-heavy with isolated complexity. Most of the app is standard database operations. The hard parts (interest calculation, payoff generation) are small and isolatable — which is why you could verify them manually.
The PDF payoff statement is the killer justification. That one feature alone — automatically generating a formatted letter from structured loan data — is genuinely painful in Excel and easy to describe to an AI.
Single user, single borrower. No multi-tenancy, no permissions model, no scale concerns. Scope was tight enough to describe completely.
What’s legitimately questionable:
No audit trail. Financial records ideally should be append-only with history. If someone edits a past cash event, there’s no log. This is the most serious structural gap — not a vibe coding criticism specifically, but something that gets missed without deliberate attention.
Dependency rot is coming. Whatever versions of npm packages, frameworks, and runtime were used at build time will have vulnerabilities and breaking changes in 2-3 years. Nobody is maintaining this. Spreadsheets don’t have this problem.
Raw IDs in the UI (Loan ID 11, Entity ID 4, etc.) are a tell of vibe-coded origins — fine for a personal tool, but worth noting.
March 2026 showing -$8,004 — either correct (LOC interest accruing with no payments received) or a data gap. Hard to know from the outside, but it’s the kind of anomaly that warrants a clear explanation in the tool itself.
Hosting/security assumptions — a sign-in screen exists, but where is this running? Financial data in a personally-maintained web app has a different risk profile than a spreadsheet on your local machine.
Time estimate for a reasonably competent vibe coder:
I’d estimate 20–35 hours of active work, probably spread over 2–3 weeks part-time. Breakdown:
Data model / schema design: 3–5 hours (getting borrower → entity → loan → cash event relationships right is the conceptual hard part)
CRUD for all entities: 4–6 hours
Interest/payoff calculation and debugging: 5–8 hours (this is where time goes — edge cases like partial periods, day-count conventions)
Report aggregation: 2–4 hours
PDF generation: 2–3 hours
Auth: 1–2 hours
Data entry (migrating real loan history): 2–4 hours
Debugging and polish: 3–5 hours
The calculation debugging is the long pole. Everything else moves fast with AI assistance.
Me:
You got the level of work correctly. Do you think this was worth doing over just using the different spreadsheets it replaced?
Claude:
Yes, but the answer depends on one specific thing: how often you generate payoff statements.
If payoff statements are frequent — and from the loan count it looks like they would be — that alone probably justifies it. Generating an accurate, professionally formatted payoff letter manually from spreadsheets every time is error-prone and tedious. Getting it wrong has real consequences.
The second justification is the report. The monthly net spread view (interest in minus LOC cost) across all loans simultaneously is exactly the kind of thing that’s painful to maintain correctly in spreadsheets once you have 11 active loans across multiple funding sources. Keeping that accurate in Excel requires discipline that’s easy to slip on.
Where spreadsheets would have been fine:
Loan tracking at this scale (11 loans) is honestly manageable in a well-structured spreadsheet
Data entry is actually slower in a custom app than in Excel for someone comfortable with spreadsheets
The entities/borrowers structure adds overhead that doesn’t matter much with one borrower
My honest take: The payoff statement + the report together justify it. If you were only tracking loans and not generating payoff letters or the net spread report, I’d say the spreadsheet was probably good enough. But those two outputs — especially the payoff letter — are where the app earns its keep every time you use it.
How often do you generate payoff statements?
Me:
The loans are designed to each be 12-15 months in length.
Claude:
Then it’s clearly worth it. With 11 active loans averaging 12-15 months, you’re generating roughly 8-11 payoff statements per year — probably more since loans get refinanced (you already have loan 14 as “19960 SW Cascadia St before refi,” showing at least one refinance cycle).
Each payoff statement done manually from spreadsheets would require:
Looking up the exact last payment date
Calculating partial period interest correctly
Formatting a professional letter
Getting the math right under time pressure (payoffs are usually requested when a closing is imminent)
Getting that wrong — even by a day’s interest — creates friction at closing. The app eliminates that entirely.
The report is a secondary but real benefit as portfolio size grows. At 11 loans across two funding sources, the mental overhead of tracking net spread manually is non-trivial.
The honest verdict for sharing with others: This is a textbook good vibe coding candidate because the ROI accrues on a predictable, recurring workflow (payoff statements) rather than being a one-time convenience. The test I’d suggest others apply: “Is there a specific output this app generates, repeatedly, that would be error-prone or time-consuming to produce manually?” If yes, build it. If the app is just a fancier way to look at data you could see in a spreadsheet, probably don’t.
Me:
Good analysis. So the question here is how a large language model AI can come up with something like this. Obviously, as a human stuck in these workflows, I decided to build it for these very reasons. I don’t quite understand how an AI was able to determine this just based on looking at the screens and asking how long the loan terms are.
Claude:
The honest answer is that I’m pattern-matching against a large amount of human knowledge, not reasoning from first principles.
What actually happened in this conversation:
The screenshots gave me the data model and workflow structure
“Private lending,” “payoff statements,” “LOC interest out” are terms that appear extensively in real estate finance literature, legal documents, accounting discussions — I’ve seen many contexts where these workflows are described and their pain points discussed
The loan count and term length let me do simple arithmetic (11 loans × ~1 per 12-15 months = obvious payoff frequency)
“Payoff statements at closings are time-sensitive and error-prone” is documented human experience I’ve absorbed, not something I derived
What I didn’t do:
Actually understand your workflow from the inside
Know anything about the specific friction you experienced with spreadsheets
Reason from business principles to conclusions
What’s interesting about your observation: You, as the human in the workflow, knew immediately why to build it. I reconstructed roughly the same conclusion from the outside by recognizing patterns. But I could easily have been wrong — if your loan terms were 5 years instead of 12-15 months, the payoff frequency argument collapses and my conclusion would have been weaker.
The AI got lucky that the key variable (loan term) confirmed the pattern. Your domain judgment was the real insight. I just reflected it back coherently.


