The problem
Leads came in as emails and went out as forwards. A rep's notes were in their phone, a rep's call count was a guess, and a lead that got no call for a week was invisible until somebody asked. Sharing one spreadsheet with everyone would have shown every rep every other rep's shops. Keeping a spreadsheet per rep meant the office had no single picture.
What I built
A phone app built with AppSheet over one Google Sheet. A rep signs in with their company Google account and sees only the leads assigned to them. Each lead has three buttons: Call, Email, Text. Each writes a timestamped activity row and then opens the phone's dialer, mail, or messages. A note is three taps. Status moves itself on the first contact. New leads go in on a staging tab in the sheet and a menu click pushes them to the reps with an email each.
What changed
"Who's called this shop" became a number on the card. The office saw calls, emails, and texts per rep on a chart without asking anyone. A new rep was one row in a roster tab and a share; the app didn't need editing. And after a stray column insert broke the app for everyone once, a guard in the sheet started raising the alarm the moment a tab's shape changed.
The rep's phone
The app opens on a deck of the rep's leads, newest on top, each card carrying the shop, its status, and how many times it has been contacted. Tap one and the buttons are the first thing on the screen. The drawing below is reconstructed from the app's configuration: the app lived in the company's Google Workspace, which was closed with the company, so there is no screenshot to show.
Left: the deck a rep opens to. Right: one lead. Every number and chip on the left is computed from rows the buttons on the right wrote.
Rules the sheet enforced
- A roster tab decides who sees what. Reps and admins are rows in a Reps tab: name, email, role, active, assignable. The app looks up the signed-in email there. Admins see every lead; a rep sees rows assigned to them; anyone not on the tab sees nothing. Adding a rep is one row and a share. The app itself never changes.
- Reps never touch the sheet. The app reads and writes the sheet as its owner, so nobody in the field needs, or gets, access to the spreadsheet behind it.
- Every row has a real key. Leads, activity, and notes carry their own IDs instead of relying on a row number, so sorting or deleting in the sheet can't scramble which activity belongs to which shop.
- Assignable is not the same as admin. A flag on the roster keeps the office staff out of the "assign to" dropdown while leaving them full visibility, and the dropdown in the staging tab filters on the same flag.
- The sheet guards its own shape. A script counts the columns on every tab whenever the sheet changes and alerts the moment one is inserted or removed. Somebody did that once, by accident, and every rep's app stopped working until it was found.
How a lead moved
Two versions, one sheet. The first, in February, was a parser that read the vendor's lead emails into a master sheet every fifteen minutes and kept a spreadsheet per rep in sync both ways, with the sheet owning the lead's details and the rep owning status and notes. Then the reps asked for it on their phones, and the second version replaced the per-rep spreadsheets with the app and gave the office a staging tab and a button.
The sheet in the middle is the same one throughout. The first version put the reps in spreadsheets of their own; the second put the sheet on their phones and the office on a button.
What didn't work, and what replaced it
Most of the second version's design came from things that failed on the way. AppSheet's own API would have let the script hand leads to the app directly, but it needs a plan tier the company's Google Workspace policy blocked, so the script writes the sheet and sends its own email instead. AppSheet's push notifications fire only for rows added inside the app, never for rows a script writes, so the email with a link into the app became the notification. Deep links to a single record opened the wrong screen on phones often enough to be dropped for a link to the deck sorted newest first. And an early tool I wrote to add a rep, a browser robot that clicked through the AppSheet editor and rewrote six expressions, was deleted the day the security filters were rewritten to look the rep up in the roster tab, because from then on adding a rep needed no edit at all.
Where it stands
Dax Distro wound down in July 2026 and the app, its sheet, and the Workspace it lived in went with it. The scripts, the setup guide, and the app's full configuration are archived, which is what the drawings on this page are built from. The shops, reps, and numbers in them are invented.
The reps' other tool from the same months: the order portal, where a won lead became an order.
Stack
No-code was the right tool because the users were on phones, the data was already a spreadsheet, and the hard part was never the screens. It was deciding who sees what, and putting that decision in one place the office could edit.
Built in conversation
Same method as everything on this site. The security filters, the grouped actions that log and then dial, the staging-tab script, the schema guard, and the decision to delete the browser robot all came out of dialogue with Claude, with the reps trying each change on their phones between rounds.