An AI-powered customer support chatbot for e-commerce stores, built with Next.js and Express.
- 💬 Real-time chat interface with AI-powered responses
- 🛒 Specialized for e-commerce customer support (shipping, returns, store policies)
- 💾 Persistent chat sessions across page reloads
- 🎨 Modern, responsive UI with Tailwind CSS
- 🔄 Conversation history stored in SQLite database
- Next.js 16 - React framework
- React 19 - UI library
- Tailwind CSS 4 - Styling
- TypeScript - Type safety
- Express 5 - Node.js web framework
- Better-SQLite3 - SQLite database
- Google Generative AI (Gemini) - AI responses
- TypeScript - Type safety
- Node.js v20.6+ (required for
--env-fileflag) - npm or yarn
- Google Gemini API Key - Get one from Google AI Studio
live-chat-agent/
├── app/ # Next.js frontend
│ ├── page.tsx # Main chat interface
│ ├── layout.tsx # Root layout
│ └── globals.css # Global styles
├── backend/ # Express backend
│ └── src/
│ ├── index.ts # Server entry point
│ ├── routes/
│ │ └── chat.ts # Chat API routes
│ ├── services/
│ │ ├── chat_service.ts # Chat logic
│ │ └── llm_service.ts # AI integration
│ └── db/
│ ├── db.ts # Database connection
│ ├── messages.ts # Message queries
│ └── schema.sql # Database schema
├── public/ # Static assets
└── README.md
git clone <repository-url>
cd live-chat-agent# Navigate to backend directory
cd backend
# Install dependencies
npm install
# Create environment file
cp .env.example .env
# Or create manually:
echo "GEMINI_API_KEY=your_api_key_here" > .env
echo "DATABASE_URL=file:./src/db/app.db" >> .env
# Start the backend server
npm run devThe backend will run on http://localhost:4000
# Navigate back to root directory (from backend)
cd ..
# Install dependencies
npm install
# Start the frontend development server
npm run devThe frontend will run on http://localhost:3000
Visit http://localhost:3000 in your browser to start chatting with Noah!
| Variable | Description | Required |
|---|---|---|
GEMINI_API_KEY |
Your Google Gemini API key | Yes |
PORT |
Server port (default: 4000) | No |
| Method | Endpoint | Description |
|---|---|---|
POST |
/chat/message |
Send a message and get AI response |
GET |
/chat/history/:sessionId |
Get conversation history |
Request Body:
{
"message": "What is your return policy?",
"sessionId": "optional-session-id"
}Response:
{
"reply": "Items can be returned within 30 days for a full refund...",
"sessionId": "uuid-session-id"
}You'll need two terminal windows:
Terminal 1 - Backend:
cd backend
npm run devTerminal 2 - Frontend:
npm run devTo clear all chat history:
rm backend/src/db/app.dbThe database will be recreated automatically when the backend restarts.
This project uses SQLite with Better-SQLite3 for simplicity and zero-configuration setup.
The database schema is automatically applied when the backend starts. No manual migration steps required!
The schema file is located at backend/src/db/schema.sql:
CREATE TABLE IF NOT EXISTS conversations (
id TEXT PRIMARY KEY,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
conversation_id TEXT NOT NULL,
sender TEXT NOT NULL,
text TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (conversation_id) REFERENCES conversations(id)
);No seed data is required. The database starts empty and conversations are created dynamically when users start chatting.
The backend follows a layered architecture pattern for clean separation of concerns:
backend/src/
├── index.ts # Entry point - Express app setup, middleware, server
├── routes/
│ └── chat.ts # API Layer - Route handlers, request validation
├── services/
│ ├── chat_service.ts # Business Logic Layer - Orchestrates chat flow
│ └── llm_service.ts # Integration Layer - LLM provider abstraction
└── db/
├── db.ts # Data Layer - Database connection & initialization
├── messages.ts # Data Layer - Message repository (CRUD operations)
└── schema.sql # Database schema definition
| Layer | Files | Responsibility |
|---|---|---|
| Routes | chat.ts |
HTTP handling, request validation, response formatting |
| Services | chat_service.ts |
Business logic, orchestration between DB and LLM |
| Integration | llm_service.ts |
External API calls, prompt engineering, error handling |
| Data | db.ts, messages.ts |
Database operations, data persistence |
-
SQLite over PostgreSQL/MySQL: Chose SQLite for zero-config setup and portability. The database file is created automatically - no Docker or external services needed.
-
Session-based conversations: Each conversation has a unique UUID stored in localStorage. This enables:
- Chat persistence across page reloads
- Conversation history for LLM context
- Easy "New Chat" functionality
-
Synchronous Better-SQLite3: Used synchronous API for simplicity. SQLite operations are fast enough that async overhead isn't justified for this use case.
-
ES Modules: The backend uses ES modules (
"type": "module") for modern JavaScript compatibility and better tree-shaking.
This project uses Google Gemini 2.0 Flash via the @google/generative-ai SDK.
Why Gemini?
- Generous free tier (ideal for development)
- Fast response times
- Good instruction-following capabilities
- Simple SDK integration
The LLM is prompted with a system prompt that defines its role and constraints:
const SYSTEM_PROMPT = `
You are a helpful and polite customer support agent for a small e-commerce store.
Answer clearly, concisely, and professionally.
Store Policies:
- Shipping: We ship worldwide. Delivery takes 5–7 business days.
- Returns: Items can be returned within 30 days for a full refund.
- Support Hours: Monday to Friday, 9 AM to 6 PM IST.
IMPORTANT: You must ONLY answer questions related to our store, products, orders,
shipping, returns, and store policies.
If a user asks anything unrelated to the e-commerce store, politely redirect them.
`;The LLM receives the last 10 messages from the conversation history, enabling:
- Context-aware responses
- Follow-up question handling
- Consistent conversation flow
To switch to OpenAI or Anthropic, modify backend/src/services/llm_service.ts:
OpenAI Example:
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
export async function generateReply(history, userMessage) {
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: [
{ role: "system", content: SYSTEM_PROMPT },
...history.map(msg => ({
role: msg.sender === "user" ? "user" : "assistant",
content: msg.text
})),
{ role: "user", content: userMessage }
]
});
return response.choices[0].message.content;
}-
No authentication: Any user can create conversations. Sessions are client-side only.
-
No rate limiting: The API doesn't limit requests, making it vulnerable to abuse.
-
Single LLM provider: Hardcoded to Gemini - no fallback if the service is down.
-
No streaming: Responses are returned all at once, not streamed token-by-token.
-
Basic error handling: LLM errors return a generic message without retry logic.
-
🔐 Authentication & User Management
- Add user accounts with JWT authentication
- Associate conversations with users
- Admin dashboard for viewing all conversations
-
⚡ Response Streaming
- Stream LLM responses using Server-Sent Events (SSE)
- Show text appearing in real-time for better UX
-
🔄 LLM Fallback & Retry
- Add multiple LLM providers (OpenAI as backup)
- Implement exponential backoff retry logic
- Circuit breaker pattern for resilience
-
📊 Analytics & Monitoring
- Track common questions and topics
- Measure response quality and user satisfaction
- Dashboard for conversation analytics
-
🎨 Enhanced UI
- Markdown rendering in chat messages
- File/image upload support
- Typing indicators with actual LLM status
- Dark/light theme toggle
-
🧪 Testing
- Unit tests for services
- Integration tests for API endpoints
- E2E tests with Playwright
-
🚀 Production Ready
- Docker containerization
- CI/CD pipeline
- Rate limiting and API key management
- PostgreSQL for production database
npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run lint- Run ESLint
npm run dev- Start development server with hot reloadnpm run build- Compile TypeScriptnpm run start- Start production server
ISC
