Making invisible automation watchable: a review-request flow in a phone mockup
Automation demos fail because nothing visible happens. This one puts an interactive phone mockup next to the trigger form — and runs on a stateless Worker that keeps request state inside the request id.
Project: Review Flowopen →The Review Flow demo exists because automation is invisible. "We'll automatically text your customers for a Google review" is a strong pitch with nothing to look at. So the demo makes the flow observable: you trigger a review request as the business, then watch it arrive as the customer.
The page is two columns. Left: a business portal form — customer name, phone, a delay picker. Right: an interactive phone mockup. Submit the form and after the chosen delay the SMS banner drops onto the mockup's lock screen; tap it and you get a Google-style review screen where you pick stars and post. One visitor plays both sides of the loop in about thirty seconds.
Stack: React 19, TypeScript, Vite, Tailwind CSS v4. The repo includes an Express backend with optional Twilio integration (real SMS, locked to one allowlisted number). The deployed demo runs on Cloudflare Workers in simulated mode.
Porting the backend to a Worker without storage
The Express server keeps pending requests in an in-memory map and flips their status on a setTimeout. Workers don't give you that — isolates come and go, and the instance that answers a status poll may not be the one that took the submission. Instead of reaching for KV or a Durable Object, the Worker encodes the whole request into the id it hands back:
The id is base64 of the submitted payload plus its timestamp, so "did the SMS send yet" is a pure function of the id and the clock. No store, no bindings, and any isolate can answer any poll. It only works because the simulated flow is deterministic — the real Twilio path needs actual state — but for the demo it means the backend is ~90 lines and free to run.
The front end polls once a second and doesn't care which backend answers:
What I'd improve
- Polling every second is fine for a demo; the real version should push status over SSE instead.
- The Express and Worker backends duplicate the API shape by hand — a shared types module would keep them honest.
- The review screen could deep-link to a real Google review URL when configured for an actual business.
One of eight small-business demos on this site. Projects · Get a quote