A business card scanner for a construction CRM, and the misread card that shaped everything.
I appreciate a good business card. The best ones (I think) act as an extension of your personality. If I can look at your business card and tell a little bit about who you are and how you work, then it's safe to say it's done its job. Now imagine if your CRM could look at a business card and know everything about that person? Maybe not some of their deeper, darker secrets, but maybe like, enough to add them as a Contact with as little friction as possible? That feels like it should be doable.
So one night, after I had convinced my 3-month old son to fall asleep, I decided to use my 90ish minutes of freedom before I passed out to work with Claudio to formulate a plan (Claudio is what I call my Claude. Because I have a cool personality, not because I'm a psycho. And Welcome Home is a banger). The plan ended up being super simple with Fable 5. Here was the first prompt I used:
Could we build a business card scanner app where users could take a picture of multiple business cards in the Salesforce mobile app and have the details stored as Contacts/Accounts inside of TrebleHook? Please help me refine this to achieve and intuitive and snappy ui and experience.
I work on TrebleHook, a CRM for the construction/architecture/engineering industry built on Salesforce. And to be honest, I don't get out much. I mean that as a pun about how I don't go to many conferences (but it's also true that I would rather stay home most of the time). I do work with salespeople all the time though. And to be fair, that's part of the reason I don't care to go to many conferences. I get my fill throughout the year (jk I love my sales team <3).
No, the part I do like is the part where I get to partner with the sales team and hear from potential customers, and even current ones, about what their pain points are in their day-to-day. My spidey senses tingle whenever I hear about something that sounds fun to build and high value, and I immediately want to try to find a way to build that thing. Sometimes there are elegant solutions to be found and rich user experiences to be built inside the Salesforce platform, and sometimes you ain't got time to build all that. So you reach for a prebuilt AppExchange solution (Salesforce's app store where people can sell prebuilt solutions that can be installed into your Salesforce org). And SOMETIMES there are frustrating moments when an AppExchange solution you rely on to help a customer solve a specific problem gets delisted and you're left to answer to a disappointed user base (I am not salty).
When this specific nightmare happened to me, it was over a business card scanner that one of our customers was using to enter Contacts from the business cards they collected at conferences and meetings. The concept makes a ton of sense for a CRM. That feels like a thing that you should be able to do pretty easily, but unfortunately, it wasn't an easy thing for us to do. So the requirement sat in the backlog for two years.
In that time, I heard the same requirement from a dozen or so other customers and prospects. And I'm not even on every sales call, so I know this pops up in meetings the sales team has. I know that people want this. I was also introduced to AI tools in that time. I used ChatGPT for a year or so. Mostly to summarize meeting notes and draft email responses. And then I met Claudio. I got exposed to some of the possibilities by a colleague at work and I started using Claude to quickly build all kinds of things. So now I had all the requirements I needed from the people who wanted to use it and the means to build something that could be a valuable solution to a legitimate business problem.
I knew that I needed this tool to be an LWC (Lightning Web Component) because I have control issues and that is Salesforce's current way of building custom screens with code. If you want to break free from the constraints of the out-of-the-box Salesforce UI, LWCs are the way to go. Time for a little reality check, though. Before this, I had never built an LWC. I'd built on the two older frameworks it replaced, Visualforce and Aura, so I knew the platform, the data, and roughly how the pieces fit together, but this framework was new to me.
Here is what Claudio came up with:
A fast path and a careful path. The moment you scan a card, quick pattern rules fill in the fields instantly, so the screen never feels like it's waiting. In the background, the raw text goes to the server, which checks the person and company against what's already in the CRM, with an optional AI pass to clean up whatever the quick rules got wrong. By the time you finish reviewing, the answers are usually already back.
One source of truth on duplicates. Matching runs in one place, on the server, honoring the org's own duplicate rules. That way the preview you approve and the save that follows can never disagree about whether someone already exists.
All-or-nothing saves. Companies save first, then people, then the optional link onto a project team, with the card photo attached to each new contact. If any part fails, nothing saves. And everything a batch creates can be undone in one tap.
The practical constraints, named up front. The scanner only works inside the Salesforce mobile app, so desktop needed a fallback (upload a photo instead). And two behaviors were worth testing on a real phone before committing to the design: whether the camera could keep scanning in one continuous session, and whether iPhone and Android read cards equally well. (Foreshadowing.)
A scoped first version. Capture loop, review tray, batch save with duplicate verdicts, and the project-team link, with the AI cleanup pass deferred to the next round. Then it offered to build the skeleton. So I said the word.
There was exactly one tester: me, on real hardware. Real cards, a real phone. That was deliberate. The whole design assumes the machine lies in small ways, and the only way to catch that is to point it at reality, not at the four tidy sample cards I had typed up myself. Nine rebuilds in ten days came out of that testing, and almost every one was set off by something breaking in my own hands: the freeze, the misread email address, a parser that had been quietly reading from the wrong place the whole time.
The whole design ended up resting on one uncomfortable fact: the software that reads a card gets small things wrong, and a small wrong thing in a CRM is worse than a blank space. A blank field, you notice and fix. A plausible-looking mistake, you trust.
Here is the example that taught me. Turning a photo of a card into usable text is a job called OCR, short for optical character recognition; it's the same kind of technology a bank uses to read a check. On a real card, scanned on a real phone in bad light, the OCR misread the email address. Say the correct address was jdoe@acme-env.com. What the software saw was jdoeaacme-env.com: the @ symbol had been read as the letter "a." That one slip can't be undone by simple rules, because once the @ is gone there's no way to know where it used to sit. My first version used a set of pattern-matching rules, and it handled the four cards I'd typed up myself perfectly. On the real card it quietly produced a contact with no email address and a nonsense website, and reported success.
The OCR read the @ sign as the letter a, and no rule on earth can tell you where it went.
That single failure set the shape of everything after it. The rules still run first, because they're instant and make the app feel quick. But the raw text the camera saw stays visible, tucked under a tap, so you can always check the machine's work against the actual card. Every field can be edited before anything is saved. And in the background, an AI model rereads the messy scan and repairs what only judgment can repair. It was the only thing I found that could look at jdoeaacme-env.com and correctly put the @ back, because it reasons the way a person would. Last, anything the tool creates can be undone with a single tap, on the theory that a tool confident enough to create records for you should be just as willing to take them back.
One more design decision came late. I wired the AI cleanup to run two ways. It can call the AI vendor directly on our own account, or route through Salesforce's own governed AI path, the Einstein Trust Layer, where the same request runs inside Salesforce's security boundary and is paid for in platform credits rather than dollars. A single setting picks which provider and which model, so the two can be compared head to head on the same card.
The cost comparison was clarifying. The direct route runs well under a penny per card. The governed route, going by published rates, runs somewhere in the range of ten to twenty times that. That isn't a knock on it. It's the measurable price of a real guarantee, that your data never leaves the platform's walls, and for some companies that guarantee is exactly worth paying for. What I like is that the design turns it into a deliberate choice instead of a default nobody examined.
The first version froze on a real phone after a single card. I'd designed the camera like a conveyor belt, reopening itself for the next scan automatically, over and over. On an iPhone, that second automatic reopen simply hangs and never comes back. My only tester, me, plus a coworker whose phone I wasn't allowed to touch, had to force the app closed to recover. The fix was the embarrassing kind: take one picture per tap, and always reset the camera cleanly when a scan finishes, even when it fails.
Then I found the app had been reading the scanned words from the wrong place in the camera's results the whole time, so it had only ever been working from a thin slice of what was actually captured. Pointing it at the right place gave the rules real text to work with for the first time.
Then the vocabulary was too narrow. I'd taught the tool construction job titles, superintendent, estimator, preconstruction, so when a card read Managing Editor it didn't recognize it as a person's title at all. Teaching software which words to ignore is humbling work.
I want to be straight about this, because it's the part I'm proudest of and the part the story above quietly hides. I had never built a Lightning Web Component before this project. Read back over what broke and how it got fixed and it sounds like the work of someone who knew exactly what he was doing. I didn't. I'd built on the older Salesforce frameworks, Visualforce and Aura, so I understood the platform and the shape of the problem, but the framework itself was new to me the entire way through.
What made it work was a genuine partnership with an AI coding agent. I directed it, tested every version on real hardware, and pushed back with screenshots when something looked wrong; it wrote and deployed the code, explored the system, and reviewed its own work. The freeze was caught by my hands, not its tests. It wrote in a framework I couldn't yet write in myself, and I could tell whether the result was right because I understood what it was supposed to do.
I don't think of this as "vibe coding," where you describe a feeling and ship whatever comes back. I had a clear picture of how the thing needed to be built from the very start: heuristics first so it feels fast, the raw scan always visible so you can check it, every field editable, an AI pass for the mistakes rules can't fix, and undo on everything. Those calls were mine, and they're also what made the whole process safe. When the machine is allowed to be wrong, and you can always see the mistake and take it back, you can move fast without betting the data on it. The agent closed a skill gap I genuinely had. It did not replace the judgment about what to build.
That's the part I'd underline for anyone uneasy about working this way. I'm not a front-end specialist, and I didn't turn into one overnight. I brought a decade of knowing how these systems should behave, paired it with a tool that could write in a framework I was still learning, and shipped something I'm confident beats the default. The gap it closed was mine. The method was steady enough that I turned around and did it again, on a harder problem, in the map with its own build story.
Worth it, and not a close call. It started from a real gap and a set of requirements the people who wanted it had already handed me, and it ends with a tool that does the thing it was asked to do. The feedback that shaped it along the way was the specific, unsparing kind you only get from someone who genuinely wants the thing to work, even when that someone is you.
And I'm confident about the comparison that matters here: as a way to get a business card into a CRM, this is better than anything Salesforce gives you out of the box. The standard experience is a blank form and your own typing. This reads the card, checks it against your data, fixes its own mistakes, and lets you undo the whole thing if it got something wrong. That comparison I'll stand behind today.
Mostly it proved out a way of working: start from a real need, design so the machine can be wrong without doing damage, and test it against the messy real thing until it holds. That is the part I carry into whatever I build next.