Second half · how it is built, why, what we would improve, how you take it away
A proof of concept: Google Workspace, and a person in the loop.
This is not a finished ops platform. It is a half-day FDE of one workflow — shared inbox and purchase orders → a pack Tom can check — so we can see, in six weeks, which bits still need a person. If ordinary trade contacts do not, those drafts can go out later. High-level relationships stay human. Orbit has no API. Nothing is sent today.
What is in the room today
Website, and a zip you can send
The finished product for this demo is the zip: inbox, sample, Why this, How it’s built. Unzip, double-click start-ui.bat, open http://127.0.0.1:8788. The live site is meridian.bydutton.com — same UI.
Rules map SKUs. AI reads the email.
Codes, “the usual”, fridge vs freezer, 3-phase — inspectable in engine.js. The Worker asks OpenAI what they actually want and how urgent it is. The model does not invent codes, does not send, and is not called again when you take the tour or change pages.
No Orbit connector
Copy the pack. Tom still types. Building a fake import would be theatre. The boundary is in the product, not a footnote.
Drafts and the spreadsheet
House templates. Gmail opens with From, To, subject and body filled — assumed Gmail because they already live in Workspace. Copy a TSV row now. Sync to Google Sheets waits until real Google login can grant the sheet.
Why this stack
Meridian already lives in Gmail, Drive, and a spreadsheet. A new password would be another thing to forget. Secrets never go in the zip. Clash Display and OpenKit paper/ink so the thing in the room does not look like a default dashboard — we would restyle it to their brand once we have sat with them.
How an incoming email is read
Choose a message (or drop one). Two things run:
- Rules in the browser — codes, quantities, customer, flags, house-template draft. This works in the zip UI with no Worker.
- AI on the Worker —
POST /api/understandwith the text only. OpenAI returns intent, priority, missing facts, and a checkable draft. The key is a Worker secret. The browser never sees it.
If the model says the wording is more urgent than the rules, priority is raised and flagged. SKU lines from the model are thrown away. Hillside stays with Sandra. You still open Gmail yourself. Each message is read once; a spinner sits on the AI card until that read finishes.
OpenAI on this demo only
OCR and email context use OpenAI (gpt-4o for photos, gpt-4o-mini for meaning) because a spare personal API key with leftover credits was available for this test scenario. It is a server secret — never in public/, never in the zip, never in git. Production would use a key Meridian owns. If that secret is missing, price-list rules still run. Photos of printed POs are read today; handwriting still needs a person — see improvements.
Chrome notifications — already in the app, testable in the trial
Signed-in Chrome (and Edge) can pop a desktop notification when new mail lands in the shared ops inbox. That is extra to the on-page list. Nothing is sent. Orbit is not written to.
How it was added
public/js/notify.js— Ask Chrome for permission, poll/api/inboxevery 12 seconds, show a system notification.public/sw.js— Click the notification, the tab focuses and that message opens.src/inbox.ts— Shared feed of dropped or live items. Packed samples do not re-notify on every load.- Inbox: Notify me then Test ping so you can check it in the room without waiting for mail.
In a six-week trial we would measure whether ops actually notice weekend and after-hours mail faster with the permission on versus off — time-to-open, not vanity click counts. The website must stay open in a browser for this path. A proper mobile app is how you drop that constraint.
Security — what is locked down now
Already in place
- Only @meridiancatering.co.uk. A personal Gmail is 403.
- Session cookie is HttpOnly, SameSite=Lax, Secure on HTTPS, HMAC-signed. The browser cannot mint a session.
- The OpenAI key is a server secret. OCR and understand never run in the zip itself.
- AI, OCR, inbox writes and Sheets sync require a signed-in session. Rate-limited. Origin checked. Bodies capped.
- Security headers on HTML and
/api/*: CSP, frame deny, nosniff, no-referrer, HSTS on HTTPS,no-storeon APIs. - No mail send. No Orbit write. No Google Sheets write until Google login can grant it. No secrets in the zip.
Production Sign in is Google only — no product copy, no named list. Workspace already knows the person and their job title. Google holds the credentials. We hold neither a password database nor Orbit keys.
Google login — sign-in now, Sheets on the same account later
Meridian already uses Google for the shared inbox and Drive. Sign-in is Google, restricted to @meridiancatering.co.uk. One identity should later append the open-item row to the Database sheet. Not a second password.
How it feels
- This room (kept on purpose): a five-name list so you can be Sandra, Tom, Priya, Meena or Derek in one click and see each job. Easiest way to demo.
- Production: the page is Sign in only — Continue with Google, no Why this / Sample / How it’s built, no named-account briefing. Google returns the Workspace user. Name and job role (Ops Manager, Customer Operations, Accounts, Managing Director) come from the directory automatically. They land in the inbox as themselves.
- Try the easy picker on /login — there are no other links until you choose an account.
- Sheets write needs the extra
spreadsheetsscope on that same login.POST /api/sheets/syncis 501 until then. Copy TSV still works. - Sign-in protects who can open the pack. It does not widen what the pack is allowed to do.
Better risk than a homemade login: Google holds the credentials, we hold neither a password database nor Orbit keys.
Domain
The live hostname is meridian.bydutton.com. Health: /api/health reports that Orbit is not connected, that mail is not sent, and understand / OCR / Sheets / notification status.
What we would improve next — in order
1. Real Google login on the domain
Keep this room’s named list for demos. Production is Sign in only — no product information, no picking a person. Google Workspace already knows who they are and their job title; we map that to the role in the header. Real MFA, audit of who opened the tool. Same login later opens Drive read-only and appends to Google Sheets. This is the first production step, not a redesign.
2. Confirm the mail client without asking
We assumed Gmail because the pack lives in Workspace. We would not annoy Sandra with a survey. One real message from them is enough: Received chain, Authentication-Results, DKIM, and reverse DNS of the sending IPs show Google’s mailers — or Outlook, or something else — so compose and sync match how they actually work.
3. UI that looks like Meridian
OpenKit tokens got it in the room. After a sitting with the client: their colour, their logo, the density Tom wants on a forty-order afternoon. Not a redesign of the workflow.
4. Notifications in the six-week trial
Chrome desktop alerts are already in the product. During the trial, run Notify me on some desks and not others. See if first-open of weekend and after-hours mail actually moves. Test ping is there so permission can be checked on day one.
5. Six-week board
First-response hours, fridge/freezer mistakes, how often Tom accepts the pack, invoice rows reaching Meena the same day. If those do not move, we turn it off.
6. After the trial: 24-hour chase
Only if the board moved. If nobody has answered in 24 hours, prepare (and later, for routine accounts only, send) a chase. Never auto-send on Hillside, complaints, or other high-level relationships. A person still owns those.
7. Proof of concept → less human on the ordinary mail
The point of six weeks is to see where a person is still required. If drafts for ordinary, non-high-level trade contacts are accepted as-is, those can go out without a click. At-risk accounts, quotes, and “the usual” stay with Sandra and Tom.
8. Mobile for weekends and urgent orders
The site already has a web manifest so Chrome can install it. A proper mobile app is later: urgent weekend orders, push that does not need a desktop tab left open, the same “check then send” rule, and a camera path for photographed POs.
9. Handwriting OCR — like accounting scan tools
Today a photo of a printed PO is read; handwriting still needs a person on every line. For the web app and especially the mobile app, add handwriting OCR the way accounting tools scan receipts. That is not a research project: plug in an existing OCR programme, or embed a scan-to-text workflow (phone camera → text, then into this pack). Every OCR line stays needs-review. Tom still keys Orbit.
10. Usage and click metrics for production — and for directors
Once this is in daily use we would add product analytics, not vanity dashboards. Usage: who signed in, how often a pack is copied, how often Gmail is opened, tour completion, time from message to pack. Clicks and hesitation: which flags are expanded, skip vs accept, where people stall on the inbox, sample vs live. That is how we improve the tool for full production, and how directors and managers decide whether the six-week board actually moved — first-response hours, keying errors, pack accept rate — without guessing from anecdotes.
Still not on the list — even after a good trial
- Auto-send on Hillside or any at-risk account.
- Writing into Orbit. There is no API.
- Auto “the usual”. Camden still needs a person.
- A quote engine pretending to be a site visit.
Where it breaks today
- No live courier or Orbit status — chases get a draft, not an ETA.
- A photo of a printed PO is read with OCR; handwriting still needs a person on every line until we plug in accounting-style scan-to-text.
- Google Sheets append waits on real Google login.
- We assumed Gmail compose. One real email from them would confirm the client from headers, without a briefing.
- Description matches (quiet fridge → RL-45) are flagged needs-review because they are matches, not codes on the page.
- AI can mis-read a messy email. That is why it only raises priority and offers a draft — it never keys Orbit.
- Desktop notifications need the tab (or the installed web app) available. Weekends properly need mobile later.
How you take this away
The finished product is the zip. Attach meridian-orbit-assistant-ui.zip. Unzip, double-click start-ui.bat, open http://127.0.0.1:8788, pick Sandra. Nothing is sent. Orbit is not written to. No secrets inside. Step-by-step: docs/PUBLISH.md.
What is in the zip
public/ (inbox, sample, Why this, How it’s built), README, and start-ui.bat. Rules map SKUs with no network. Photo OCR and AI context need the live site; the pack still builds from the price list.