Client software · 2026
Loan officer CRM
One book per officer, and it fails closed.
- Role
- Sole designer and engineer
- Status
- In production — private
- Built with
- Next.js · Postgres · TOTP MFA · Docker · Signed releases
The brief
Loan officers at a mortgage lender were buying consumer reverse-mortgage leads from several sources and working them out of whatever each officer preferred — a spreadsheet, a notebook, the source’s own portal. Nobody could see a book but its owner, and nobody could tell which source was worth paying for.
What it does
Every officer has their own book. Leads arrive from several sources, get reconciled, and move through reverse-mortgage stages that match how the product is actually sold rather than a generic sales funnel. Managers see their people. Owners see everything. Call outcomes, callbacks and corrections are recorded against the lead, so a book has a history instead of a current state.
The parts that were hard
This is regulated consumer finance, and most of the engineering is in what the software refuses to do.
It fails closed on identity. The application will not start against a database whose name it does not expect. Missing configuration, borrowed credentials from a neighbouring system, example secrets left in a file, or an insecure public origin all stop it dead rather than letting it run in a state nobody intended. A CRM that quietly connects to the wrong database is worse than one that will not boot.
It is deliberately alone. Its own repository, database, cookies, ports and deployment, sharing nothing with the recruiting platform. Two systems holding different regulated data should not be one blast radius.
Nothing leaves it. No call, SMS, email, recording or automated lead purchase is sent by this application. Inherited helpers that could have done any of that are not wired to routes, and turning any of them on is a separate, reviewed decision rather than a flag.
Imports are reviewed, not trusted. A CSV of purchased leads is checked before it lands, because the cost of a bad import in a regulated book is not a cleanup task.
What is shown here
Every screenshot on this page is a local build running seeded demonstration data in a database kept separate from anything real. The officers, borrowers, numbers and notes are invented. No borrower record is shown, and the client is not named.