Legacy Roofing: the CRM, and the bottleneck it revealed
The outcome. Legacy Roofing and Exteriors is a two-person company. Kris owns it and runs production almost single-handed, with his partner Evan alongside. They were paying about $835 a month for two CRM tools that didn't talk to each other, and still didn't have what they wanted. I built one custom system that replaces both and runs for about $40 a month: a full estimate-to-payment lifecycle with customer-facing portals, digital signatures, change orders, invoicing, and payment tracking, plus a 1,550-item materials database I OCR'd out of supplier price lists feeding an estimate engine that handles waste and margin math on its own. Roughly 7.5 hours of AI-assisted work for the initial production build, 900+ automated tests, deployed live on Azure with their real data in it. Then I hit the harder problem, and it changed the entire engagement.
How I thought about it
What was actually going on. They were running AccuLynx and DripJobs at the same time. AccuLynx had the feature depth, DripJobs had the interface Evan actually liked. Neither tool gave them both, so they paid for two and lived with data sitting in silos between them. The monthly cost was out of proportion to the value they were using.
What I decided, and what I ruled out. The cheap move was to consolidate onto one of the two and drop the other. I ruled that out because it forced a bad trade every time: keep AccuLynx and lose the interface they preferred, keep DripJobs and lose the depth. A custom build let them keep both, unified, at a fraction of the cost. For hosting I chose Azure with managed PostgreSQL over cheaper unmanaged options, because this is a client's live business data and automated backups and failover matter more than saving a few dollars a month. One more call I'd defend: any automation I add stays back-office. A robotic voice talking to customers Kris knows personally in a small town would cost him more than a missed call ever would, so the AI works behind the scenes, not in front of his people.
The decision that mattered most came after the build. Kris went quiet. Instead of pushing the migration harder, I sat with why he wasn't responding and concluded the ask itself was wrong for the moment. Moving a business onto new software and then learning it is a heavy lift for a two-person shop in peak season that's still forming its own processes. He confirmed it on the next call. He told me he almost didn't pick up because his phone doesn't stop ringing. So I stopped selling the switch and reframed the work around giving him time back, starting with a hands-free voice intake he can call while driving to answer a structured set of diagnostic questions. That lets me find the real constraint without asking him to sit still for it.
Where this could break
The honest limits. He hasn't adopted the system into daily operations yet, so there's no day-to-day production usage to point to. That's a capacity problem, not a code problem: the automated morning briefing ran against his live pipeline and did exactly what it should, and I switched it off because a daily briefing only earns its place once he's actually operating in the system, and he isn't there yet. The diagnostic loop stays open until he calls the intake line. It's a single-client build, so it hasn't been proven to generalize. Hover measurement integration is deferred, not delivered.
What changed
One system instead of two, at roughly five percent of the monthly cost, deployed and waiting with his real data in it. And the engagement itself changed shape, from "replace your software" to "find where your time is going and take some of it back," which is the thing he actually needs.
What I'd do next
If I ran this again, I'd audit the operation before building anything. He already had a working setup, and the highest-value move was finding the real constraint first, not shipping software into a business that had no room to receive it.