How a menu change gets made
The sync only pushes what’s in the master menu. So the first job is making it easy to change the master menu, wherever the owner happens to be. There are three ways a change gets in: somebody edits the Drive sheet, somebody taps a dish sold-out on a phone page, or somebody forwards a supplier price list to a dedicated address. The first one is obvious. The other two exist because in real life nobody opens a spreadsheet on a busy lunch service to mark the special 86’d.
Key takeaways
- Three intake lanes feed one master menu: the Drive sheet, a phone quick-edit lane, and a supplier-price lane.
- Forwarded price lists are read by Textract; Bedrock Haiku 4.5 matches each line to an item and proposes a price.
- Every proposed price change goes to the owner’s Slack for one-tap approval before it lands in the menu.
- The quick-edit lane is a tiny phone page for the two changes that happen mid-service: sold-out and small tweaks.
- The Drive sheet stays the canonical store. The other lanes are conveniences that write into it.
Three lanes into one master menu
Lane 1: the Drive sheet itself
The simplest lane. Open the master menu sheet in Drive, edit a row, save. The columns are short: name, description, category, price, a sold-out flag, a seasonal flag, and a small list of which channels the item publishes to. A change-triggered Lambda — menu-sync — exports the sheet as plain JSON via the Drive API and writes it to s3://ms-menu-source/menu.json whenever the sheet changes. The planner reads from S3, not Drive directly. That keeps Drive API calls predictable and gives you S3 versioning for free, so a bad bulk-edit can be rolled back in one click.
This lane covers the cases where you’re sitting down with the menu in front of you — adding a new seasonal dish, rewriting a description, reorganizing categories. Most planned menu work goes in this way.
Lane 2: the quick-edit page (the lane staff actually use mid-service)
Two changes happen in the middle of a busy service: a dish sells out, or a price needs a quick nudge. Nobody is opening a spreadsheet for those. So the quick-edit lane is a tiny phone web page — a list of every item with a sold-out toggle and a price field. Tap the short rib sold-out and the page posts to a small quick-edit Function URL Lambda, which writes the change straight to the Drive sheet via the Sheets API and triggers the planner.
These changes don’t need approval. Marking a dish sold-out is reversible (toggle it back when the kitchen restocks), and a small price nudge inside the auto-sync limit is exactly the kind of routine change the rules already allow to flow. The page is locked behind a simple staff PIN stored in Parameter Store, so only the floor team can reach it. The point of this lane is speed: the change a server makes in two taps should be live everywhere before the next table orders.
Lane 3: supplier prices
Costs change when suppliers change them, and they almost always arrive as a PDF or spreadsheet attached to an email. Forcing the owner to retype a price list into the menu sheet is a chore that gets skipped — and skipping it means selling food at last quarter’s cost.
Lane 3 picks up forwarded price lists. Set up a dedicated address — something like prices@your-restaurant.com — via Amazon SES. Forward a supplier list to it and the system takes over. SES writes the raw MIME to s3://ms-raw-mime/. The S3 PUT triggers a parser Lambda that runs Amazon Textract on the attachment to read the lines, then calls Bedrock Haiku 4.5 to match each supplier line to a menu item and propose an updated cost. The prompt is short: “Match each line to a menu item by name. Return JSON only. Don’t invent a match you’re unsure of — mark it for review instead.” The proposals go to the owner’s Slack with approve, edit, and discard buttons. On approve, the new prices are written to the sheet.
Every proposed price goes to a human first for a simple reason: a price the model misread is worse than a price that never updated at all. The misread one quietly charges the wrong amount everywhere until somebody notices on the month-end numbers.
Why the menu stays the source of truth
Three lanes in, but only one place the planner actually reads. That’s a deliberate constraint. If two lanes both wrote directly to the channels, every “why does the website say this?” question would mean checking three places. Funneling everything through the Drive sheet means there is exactly one row per item, and any staff member can read or edit it without learning a new tool. The convenience lanes are first-class for getting changes in, but they always pass through the sheet on the way.
Next post: how the planner reads the master menu, compares it against what each channel currently shows, and picks one of four moves per channel.
All posts