Case study / Workflow automation
Catering Concierge
A catering operations app for independent restaurants. Its working pilot links Zapier to the app: Zapier pairs each inquiry with an AI-written review, an authenticated endpoint stores it once for the configured restaurant, and signed-in owners read their inquiries in one place.
Built for independent restaurants that receive catering requests through several channels and need one place to see what has come in.
- My role
- I defined the problem and application workflow, guided AI-assisted implementation, reviewed the results, and refined the interface and human-verification process.
- Built with
- Next.js, React, and TypeScript with Prisma on Neon PostgreSQL, Google sign-in through Better Auth, and Zapier, deployed on Railway.
- Status
- Deployed demonstration on Railway with fictional data. Inquiry import and review work as a limited pilot; menus, quotes, email, and events are planned.
01 / Problem
Many channels, one kitchen.
Catering requests reach an independent restaurant by different routes: email, website forms, and conversations someone types up later. Each arrives in its own format, with the date, headcount, and dietary needs buried in free text, and each has to be found, read, and checked for gaps before anyone can reply.
Catering Concierge is planned as a full catering workflow, from first contact to a confirmed event. The first working piece is intake: pulling inquiries out of the tools where they land and into one place, attached to the right restaurant, without duplicates, and designed so each owner sees only their own restaurant’s inquiries.
02 / How it works
Prepare in Zapier, review in the app.
-
Prepare in Zapier
A published Zap watches a Zapier table of fictional pilot inquiries. For each new record, an AI by Zapier step writes a review, and a code step packages the record ID, the original message, and the review as JSON. The AI runs inside Zapier; the application itself calls no AI service.
-
Deliver to the app
Zapier posts the JSON to the app’s import endpoint with a bearer token. Before touching the database, the server checks its configuration, the token, the content type, the size, and the exact fields. It then stores the inquiry for the restaurant set in server configuration, labelled as demonstration data.
-
Review in one place
A signed-in owner opens Inquiries and sees their restaurant’s latest inquiries, newest first. Each shows the original request and Zapier’s AI review under separate labels. The screen is read-only for now: nothing is approved, edited, or sent from it.
03 / Implementation decisions
Narrow by design, strict at the edges.
The server decides where data goes
The destination restaurant and source table come from server configuration, never from the request. The endpoint accepts exactly three fields: the record ID, the inquiry message, and the AI review. Anything else, including an attempt to name a restaurant or mark a record as real, is rejected.
Checks run before the database
Requests are checked in a fixed order: configuration, bearer token, content type, body size (a 128 KiB limit enforced while the body is read), and then the payload. A request that fails any of them never reaches the database. The token check hashes both values and compares them in constant time.
One record, one inquiry
A repeat delivery of the same Zapier record returns the existing inquiry instead of creating another or overwriting it. A unique database index on the restaurant, table, and record ID backs this up: if two deliveries arrive together, the database rejects the second and the endpoint returns the first. Automated tests cover simultaneous deliveries using a simulated database.
Restaurant scope comes from the session
The Inquiries screen takes its restaurant only from the signed-in user’s membership, never from a URL or form, and every query filters by it. Signed-out visitors are sent to sign-in and users without a restaurant to setup. If loading fails, the page shows an unavailable notice instead of data.
Imported text stays untrusted
Line endings are normalized and unsupported control characters are refused, but the message and the AI review are otherwise stored as received and displayed as plain text. Responses never echo submitted content, and logs record error types without request bodies or tokens.
Labelled, not dressed up
Every imported record is stored and shown as demonstration data. The dashboard pipeline is a separate fictional preview, and modules that aren’t built are marked Planned in the navigation instead of being filled with convincing screens.
04 / The interface
What’s public, what’s behind sign-in.
The dashboard and planned module pages are open to anyone. Sign-in uses Google, and the sign-in page says plainly what signing in does today: confirm identity, set up one restaurant, and read that restaurant’s imported inquiries.
The Inquiries screen requires a restaurant account, so it isn’t pictured here. The dashboard images show the app’s built-in fictional sample data.
05 / Scope
What it does, and doesn’t.
What is implemented
- Google sign-in with seven-day sessions, and setup of one restaurant per account with an owner membership
- An authenticated Zapier import endpoint with payload validation, a size limit, and duplicate handling
- A restaurant-scoped, read-only Inquiries screen showing each original request with its Zapier AI review
- A dashboard and pipeline preview built on clearly labelled fictional sample data
- A health endpoint and a Railway deployment
- Automated tests for the sign-in wiring, restaurant setup, the import endpoint, and inquiry reads, using a simulated database where needed
What it does not do
- It is a demonstration on fictional data, running against a development database, not a production restaurant service.
- The import is a single-restaurant pilot: one configured restaurant, one Zapier table, and one shared token.
- The app makes no AI calls of its own. The review text comes from Zapier and is shown as received; the app doesn’t check whether it is correct.
- Inquiries can be read, but not edited, approved, quoted, or answered, and nothing is extracted from them into structured fields.
- The Email, Menu, Quotes, Events, and Settings pages describe planned scope only. Business analytics is also planned.
- Entering an inquiry by hand is in development and isn’t part of the deployed version.
- Restaurant scoping and simultaneous duplicate deliveries are covered by automated tests against a simulated database. Separation between two real restaurant accounts hasn’t been tested live.
06 / Contribution
What I contributed.
I defined the problem and application workflow, guided AI-assisted implementation, reviewed the results, and refined the interface and human-verification process.
Built with
- Next.js and React App Router pages with server-side data loading, written in TypeScript.
- Tailwind CSS Interface styling and theme tokens.
- Prisma and Neon PostgreSQL The data model, migrations, and the unique index behind duplicate handling.
- Better Auth Google sign-in and database-backed sessions.
- Zapier Tables, AI by Zapier, Code by Zapier, and an authenticated API request that delivers each inquiry.
- Node.js test runner Automated tests for the import endpoint, sign-in wiring, and restaurant scope.
- Railway Hosting for the demonstration deployment.
Next / Have a similar problem?
Let’s talk it through.
Tell me what you need to organize or the workflow you want to simplify, and we’ll work out together whether a tool like this would help.
Start a conversation