AI Bistro Ordering is a full-stack AI-powered restaurant ordering system that combines a React Native mobile client with a structured TypeScript backend orchestration pipeline. A demo of the system can be viewed here.
Instead of allowing the LLM to directly mutate application state, the backend separates the AI workflow into deterministic orchestration stages including normalization, menu resolution, and cart execution.
The project focuses heavily on:
- Structured AI orchestration
- Deterministic cart execution
- Menu and modifier resolution
- Prompt-context engineering
- Typed backend architecture
- Stable cart state management
- AI-assisted conversational ordering
The backend separates the AI workflow into multiple execution stages:
- Prompt context generation
- Action normalization
- Menu resolution
- Deterministic cart execution
- Cart synchronization
This avoids allowing the LLM to directly control database mutations.
Before normalization, the backend transforms raw database state into structured prompt-friendly context optimized for LLM reasoning.
This includes:
- Cart state serialization
- Modifier serialization
- Menu context formatting
- Execution history formatting
- Conversational context shaping
The goal is to improve reasoning consistency and reduce ambiguity during AI ordering execution.
Cart mutations are executed by backend services instead of AI-generated logic.
The execution layer handles:
- Quantity merging
- Modifier replacement
- Stable cart item identity
- Item removal
- Modifier synchronization
- Stateful cart updates
The backend resolves AI-generated menu references into executable entities using structured resolution logic.
This includes:
- Alias matching
- Modifier validation
- Menu entity resolution
- Structured menu lookup
- Resolution confidence handling
The entire project is written in TypeScript.
The architecture is separated into:
- Repository layer
- Service layer
- Route layer
- Prompt layer
- Mapping layer
- Domain types
- DTO contracts
apps/
├── mobile/ # React Native Expo client
└── server/ # Express + AI orchestration backendCreate:
apps/server/.envRequired variables:
GEMINI_API_KEY=
SUPABASE_URL=
SUPABASE_KEY=
GEMINI_MODEL=Create:
apps/mobile/.envRequired variables:
EXPO_PUBLIC_API_BASE_URL=http://{IP}:{PORT}/apiThis project uses PostgreSQL through Supabase.
- Create a Supabase project
- Open the SQL editor
- Run:
/packages/shared/schema.sqlThis creates all required database tables for:
- Menu entities
- Modifier groups
- Modifier options
- Cart state
- Chat sessions
- Chat messages
- Conversational ordering workflows
- Structured AI execution tracking
cd apps/server
npm installCreate:
apps/server/.envThen populate all required variables.
Execute:
/packages/shared/schema.sqlinside the Supabase SQL Editor.
The backend includes a menu ingestion pipeline.
Run:
cd apps/server
npm run ingestThis executes:
apps/server/src/scripts/ingestion.script.tsThe ingestion pipeline imports menu data into PostgreSQL.
cd apps/server
npm run devThe Express server will start in watch mode.
cd apps/mobile
npm installCreate:
apps/mobile/.envExample:
EXPO_PUBLIC_API_BASE_URL=http://{IP}:{PORT}/apicd apps/mobile
npm run startThen:
- Scan the QR code using Expo Go
Or run:
npm run iosnpm run androidnpm run webLocated in:
apps/server/src/routes/| Route | Responsibility |
|---|---|
cart.routes.ts |
Cart CRUD and cart state synchronization |
chat.routes.ts |
Chat session and conversational messaging |
menu.routes.ts |
Menu and category retrieval |
ordering.routes.ts |
AI ordering orchestration pipeline |
health.routes.ts |
Health check endpoints |
Located in:
apps/server/src/services/| Service | Responsibility |
|---|---|
normalization.service.ts |
Converts natural language into structured ordering actions |
prompt-context.service.ts |
Transforms raw cart/menu JSON into prompt-optimized context |
resolution.service.ts |
Resolves menu entities, modifiers, and aliases |
ordering.service.ts |
Coordinates the end-to-end AI ordering pipeline |
cart.service.ts |
Deterministic cart mutation and synchronization |
menu.service.ts |
Menu aggregation and lookup logic |
chat.service.ts |
Chat session persistence and history management |
gemini.service.ts |
Google Gemini API integration |
Located in:
apps/server/src/prompts/Contains structured prompts for:
- Action normalization
- Menu reasoning
- Conversational ordering
- Resolution flows
Located in:
apps/server/src/db/Responsible for:
- Supabase integration
- Repository abstraction
- PostgreSQL persistence
Located in:
apps/mobile/src/components/| Component | Responsibility |
|---|---|
ai-prompt-bar.component.tsx |
Conversational AI ordering input |
cart-item-row.component.tsx |
Cart item rendering |
cart-sheet.component.tsx |
Cart drawer and checkout state |
category-rail.component.tsx |
Menu category navigation |
menu-item-card.component.tsx |
Menu item presentation |
quantity-stepper.component.tsx |
Quantity adjustment controls |
Located in:
apps/mobile/src/overlays/| Overlay | Responsibility |
|---|---|
floating-cart.overlay.tsx |
Floating cart access UI |
modifier-sheet.overlay.tsx |
Modifier selection workflow |
toast-host.overlay.tsx |
Global toast notifications |
Located in:
apps/mobile/src/services/| Service | Responsibility |
|---|---|
api.service.ts |
Base HTTP client |
menu.service.ts |
Menu API integration |
cart.service.ts |
Cart synchronization |
chat.service.ts |
Conversational messaging |
ordering.service.ts |
AI ordering requests |
The mobile application uses Zustand for:
- Cart state
- Ordering state
- Chat state
- UI synchronization
- User sends a natural language ordering request
- Example:
"Add two cheeseburgers with no onions"
The backend transforms raw JSON state into structured prompt-friendly context.
This includes:
- Cart serialization
- Modifier formatting
- Menu context formatting
- Execution history formatting
- Conversational context shaping
The backend converts natural language into structured actions.
Example:
{
"action": "add_item",
"item": "Cheeseburger",
"quantity": 2,
"modifiers": ["no onions"]
}The backend resolves menu entities and validates modifiers.
The backend executes cart mutations using structured cart services.
The updated cart state is returned to the mobile client.
Backend tests use Vitest.
Run:
cd apps/server
npm run testOr:
npm run test:runSome existing tests are currently outdated.
For new features or architecture changes, it is recommended to write additional tests as needed.
- The backend intentionally separates AI reasoning from application state mutation
- The orchestration pipeline becomes deterministic after normalization and resolution
- Prompt context generation is treated as a first-class backend concern
- Menu resolution and modifier validation are backend-controlled
- The architecture is optimized for maintainability and predictable execution