Lead-to-cash system for a field business · Live in production
Bay Area Wi-Fi Networks
The quoting and CRM platform my network-installation company runs on — a customer can go from a form to an approved, paid quote without anyone picking up the phone.
Role: Product design, flow design, money model, and direction of the agents that wrote it.
Timeline: Live in production — running the business since early 2026
- Collected in 90 days
- $250k+
- Database tables
- 27
- API endpoints
- 422
- Commits
- 1,901
- Test files
- 30
Payments collected through the system in its first 90 days of operation, per the company's own records. Bay Area Wi-Fi Networks is my company, so this is a figure I can stand behind directly rather than a client's claim.
Table definitions in shared/schema.ts. Counted in the repository on 8 August 2026.
Registered route handlers across the server modules. Counted in the repository on 8 August 2026.
git rev-list --count HEAD. Counted in the repository on 8 August 2026.
node:test files under server/. Counted in the repository on 8 August 2026.
What was actually broken
In field services, the business goes to whoever quotes first. A lead comes in from Yelp, Google or Thumbtack, and that customer is getting three other quotes the same afternoon. If yours takes two days because someone has to spec the equipment, price the labour and write it up by hand, the job is gone before you send it.
That was the real constraint — not marketing, not capacity. The gap between "someone is interested" and "here is a price you can accept" was measured in days, and every hour in that gap lost jobs.
Everything in this system exists to close that gap.
The flow I designed
The website answers a question before it asks for anything. The front door is a Network Performance Score — a short assessment of how someone's current setup is actually performing — and a cost estimator that gives a real range. You find out something useful about your own house before anyone asks who you are. Same principle as the scorecard on the CLEAR site, and it works for the same reason.
Quotes are assembled, not written. The quote builder holds the live UniFi catalogue, a compatibility rules engine that knows which equipment actually works together, and the labour maths. What used to be an evening of specification becomes minutes, which is the entire competitive advantage.
The customer approves and pays in one place, with no account. A signed link opens a page where they can review the work, pick optional add-ons, choose financing, and pay. No password, no portal, no phone tag.
Technicians see the job, not the money. The technician portal is reached by token and deliberately shows scope without pricing. A tech standing in someone's hallway needs to know what to install; showing them the margin helps nobody and creates an awkward conversation waiting to happen.
A lead stays "new" until someone actually does something about it. Not until someone opens it — until someone acts. Systems that mark work as seen when it is merely glanced at are lying to you about your own follow-up, and follow-up is the whole business.
Interface notes
The promise is time
Two minutes, not “contact us for a quote”. In field services the job goes to whoever answers first, so the homepage leads with how fast you get an answer rather than how good the company is.
Two doors, deliberately
“Get My Score” for someone happy to self-serve, “Book Free Consult” for someone who wants a person. Forcing everybody down one path loses whichever half you didn't choose for.
It names the fear, right under the button
“No spam. Just your results and next steps.” The reason people hesitate over a form like this is what happens to their phone number afterwards — so it is answered at the moment of hesitation, not in a privacy policy.
You can see the whole shape of it
“Step 1 of 7” and a progress bar, before you answer anything. A form that hides its own length is the fastest way to lose somebody halfway through it.
Big targets, plain words
Residential or Commercial as two large tiles rather than a dropdown. This gets filled in one-handed, on a phone, by somebody mildly annoyed that their Wi-Fi doesn't work.
Still nobody has asked who you are
The estimate comes first; contact details come after there is a number worth having. Same trade as the scorecard on the CLEAR site, and it works for the same reason.
The hard part
Making sure the number the customer agreed to is the number that stands.
Quoting sounds simple until the realities arrive. One job often needs several versions — a good, better and best — that live together but must not be confusable. When the customer approves one, the others have to stop being live offers. And the moment they approve, the price they saw has to be frozen, because an admin tidying up the quote next week must never retroactively change what somebody already agreed to buy.
So approved quotes keep a snapshot of exactly the revision that was approved, and later edits cannot reach back through it. "Locked" is derived from whether a sibling was approved, rather than stored as a flag — a stored flag is one more thing that can drift out of agreement with reality, and this is the one place where drift means charging someone the wrong amount.
Financing made it harder again. Installments mean charging a card repeatedly over time, across a manual path and a webhook path that can both fire, so the guards against double-charging have to sit at several layers at once rather than in one hopeful place.
The general lesson, again: the feature is easy, the guarantee is hard. And where money is concerned, the guarantee is the entire product.
Stack
| Frontend | React 18 + Vite, Wouter, TanStack Query |
|---|---|
| UI | shadcn/ui on Radix, Tailwind, framer-motion, Recharts, TipTap |
| Backend | Express + TypeScript |
| Database | PostgreSQL + Drizzle ORM |
| Payments | Stripe Checkout, webhooks, and financing instalments — Idempotency guards at several layers, because a double-charge is unrecoverable trust. |
| Telephony | Twilio voice and SMS, with a shared team inbox |
| IMAP/SMTP with a Gmail API fallback, threaded per lead | |
| AI | OpenAI for estimator analysis and voicemail extraction |
| Catalogue | Puppeteer + Cheerio, scraping the live UniFi store — Equipment pricing that goes stale produces quotes that lose money. |
| Lead sources | Yelp, Google and Thumbtack, ingested automatically |
| Testing | Node's built-in test runner, booting the real Express app |
Outcome
More than $250,000 collected through the system in its first 90 days.
It runs the business end to end: lead capture from three marketplaces, the assessment funnel, quoting, approvals, payments, financing, the shared inbox for email and SMS, technician dispatch, and the financial reporting.
An unexpected second effect: because the site is structured, plainly written and genuinely answers the questions people ask, AI assistants started recommending the company to people looking for network installers. That was not the goal — it turns out that building a site to be understood is the same work as building one to be cited.