An e-commerce furniture storefront with an embedded AI-powered chat assistant. The chatbot uses a LangGraph agentic workflow backed by Google Gemini to answer customer questions by performing semantic (vector) search across a live MongoDB inventory.
| Layer | Technology |
|---|---|
| Frontend | React 19, Create React App, CSS |
| Backend | Express 5, TypeScript, Node.js |
| AI Agent | LangGraph, LangChain, Google Gemini 2.5 Flash |
| Embeddings | Google gemini-embedding-001 (3072 dimensions) |
| Database | MongoDB Atlas (inventory + vector index + session checkpoints) |
| Schema Validation | Zod |
- AI chat widget — Floating chat interface (bottom-right) powered by a LangGraph agent that reasons over the product catalog to answer customer queries.
- Semantic vector search — Customer messages are embedded and matched against product embeddings via MongoDB Atlas Vector Search; falls back to regex text search when needed.
- Multi-turn conversations — Each chat session is identified by a
threadId; conversation history is persisted in MongoDB via LangGraph's checkpoint saver. - Rate-limit resilience — Exponential backoff retry logic on the agent for Gemini API rate-limit errors.
- Database seeding — A seeding script generates synthetic furniture items with Gemini and stores their embeddings in MongoDB ready for vector search.
- E-commerce storefront UI — Header with search, category navigation, hero section, and multi-column footer.
ecommerce-chat-helper/
├── server/
│ ├── index.ts # Express server + API routes
│ ├── agent.ts # LangGraph agent + item_lookup tool
│ ├── seed-database.ts # Generates & seeds furniture data into MongoDB
│ ├── package.json
│ └── tsconfig.json
├── client/
│ ├── src/
│ │ ├── App.js
│ │ ├── App.css # All component styles
│ │ └── components/
│ │ ├── EcommerceStore.js # Store layout (header, hero, footer)
│ │ └── ChatWidget.js # Chat bubble + message UI
│ └── package.json
└── README.md
- Node.js 18+
- A MongoDB Atlas cluster with:
- A database named
inventory_database - A collection named
items - A Vector Search index named
vector_indexon theembeddingfield (3072 dimensions, cosine similarity)
- A database named
- A Google AI Studio API key with access to Gemini 2.5 Flash and the embedding model
Create a .env file inside the server/ directory:
MONGODB_ATLAS_URI=mongodb+srv://<user>:<password>@<cluster>.mongodb.net/?appName=<AppName>
GOOGLE_API_KEY=your_google_api_key_here
PORT=8000The client runs on port
3000(Create React App default) and proxies chat requests tohttp://localhost:8000.
# Backend
cd server
npm install
# Frontend
cd ../client
npm installRun this once to populate MongoDB with synthetic furniture items and their vector embeddings:
cd server
npx ts-node seed-database.tsThis generates 10 furniture products via Gemini, computes 3072-dimensional embeddings, and inserts them into the inventory_database.items collection.
Make sure your
MONGODB_ATLAS_URIandGOOGLE_API_KEYare set before running the seed script.
In MongoDB Atlas, create a Vector Search index on the items collection with the following definition:
{
"fields": [
{
"numDimensions": 3072,
"path": "embedding",
"similarity": "cosine",
"type": "vector"
}
]
}Name the index vector_index.
cd server
npm run devThe Express server starts on http://localhost:8000.
cd client
npm startThe React app opens at http://localhost:3000.
Health check.
Response: 200 OK — plain text confirmation.
Start a new conversation.
Request body:
{ "message": "Do you have any oak dining tables?" }Response:
{
"threadId": "abc-123-def",
"response": "Yes! We carry several oak dining tables..."
}Continue an existing conversation.
URL param: threadId — returned from the initial POST /chat call.
Request body:
{ "message": "What are the prices?" }Response:
{
"response": "The full price is $899, currently on sale for $699..."
}User message
│
▼
LangGraph StateGraph
│
├─► Gemini 2.5 Flash (decide if tool call needed)
│ │
│ ▼ (if item lookup needed)
│ item_lookup tool
│ │
│ ├─► MongoDB Atlas Vector Search (primary)
│ └─► Regex text search (fallback)
│
└─► Gemini synthesizes answer from tool results
│
▼
Response to client
Session state (message history) is checkpointed to MongoDB after every turn so conversations resume correctly across requests.
{
item_id: string,
item_name: string,
item_description: string,
brand: string,
manufacturer_address: {
street: string, city: string, state: string,
postal_code: string, country: string
},
prices: { full_price: number, sale_price: number },
categories: string[],
user_reviews: [{ review_date: string, rating: number, comment: string }],
notes: string,
embedding: number[], // 3072-dim vector
embedding_text: string, // text used to generate the embedding
pageContent: string
}