The client ran on spreadsheets. We kept it that way, and made it an operating system
- Client:
- A national beverage brand
- Industry:
- Field operations
- Status:
- In production
- Stack:
- Flutter · TypeScript · Node.js · Google Cloud Run · Google Sheets · Google Drive · Claude
Field marketing for a national brand ran on Google Sheets and AppSheet, and the operations team knew every tab of it. The conventional consulting move is a migration: replace the spreadsheets, retrain the team, and hope adoption survives. We judged that wrong for this client. The spreadsheets were not the problem; the lack of engineering around them was.
So we engineered around them. A Flutter app gives ambassadors their schedule, event reporting, expenses, and earnings. A React console gives the operations team a drag-and-drop scheduling board. Between them sits a Cloud Run API that treats Sheets as a real database, with per-tab locking, idempotency-aware retries, and audit logging, so two systems never fight over a row and a flaky network never double-writes an expense. The platform runs the operation daily: the Android app is live on Google Play, iOS is in App Review, and a public application page feeds new ambassadors into the same admin approval flow.
The system
Three decisions that mattered
Do not migrate a working operations team
The operations staff could read, fix, and trust their spreadsheets. Forcing a database migration would have traded that fluency for a system only we understood. Instead the API enforces the discipline Sheets lacks: a mutex per tab for atomic read-modify-write, retries that know which operations are safe to repeat, and an audit log of every mutation. Zero migrations were forced on the team.
Scheduling is deterministic; the AI narrates
Shift assignment is a pure scoring function over six documented signals: availability, performance, distance, reliability, fairness, and familiarity. Claude writes the prose explanation of a draft and the weekly summary, under a hard timeout with a deterministic fallback. If the model is down, scheduling does not even slow down.
Three auth paths, hardened server-side
Field staff sign in however their phone lets them: Google, Apple with server-side token verification, or email one-time codes with hashed single-use tokens, lockouts, and cooldowns. Convenience for the field, without trusting the client device.
The AI layer, honestly
Claude does two things and only two things: it explains a schedule draft that the deterministic engine produced, and it summarizes the week for the operations lead. Fifteen-second hard timeout, graceful fallback, no decision authority. We think this pattern, AI explains but never decides, is the right default for operational software, and this system is where we proved it.
What broke, and what we changed
Google Sheets rate limits are real and arrive at the worst moments. The first retry layer made things worse by repeating non-idempotent appends; the current one distinguishes safe retries from unsafe ones and backs off with jitter. The lesson is baked into the platform: treating a spreadsheet like a database is fine exactly as long as you engineer it like one.
Results, and how they were measured
3
surfaces on one API
Ambassador mobile app, admin scheduling console, and the Cloud Run service.
6
signals in the scheduling engine
Documented weights, deterministic output, reproducible decisions.
0
migrations forced on the ops team
The team kept the spreadsheets they trust; the system made them safe.