A production-ready, multi-tenant e-commerce platform with a zero-cost AI chatbot that handles product inquiries and automates order booking. Runs on Val Town (cloud) or Termux (local) with the same codebase.
- Multi-tenant isolation — Each merchant gets their own store, products, and orders. Every SQL query is scoped by
merchant_id, making cross-tenant reads structurally impossible. - AI Chatbot — A zero-cost NLP engine (no external API calls) that handles customer conversations: greetings, product inquiries, price/availability checks, and full order booking with automatic extraction of customer name, phone, address, and quantity.
- Automatic order booking — When a customer completes a chat conversation, the system atomically creates an order, decrements stock, and dispatches a webhook notification to the merchant.
- Token-free buyer experience — Buyers just visit a store URL. No login, no API key, no registration. They browse products and chat with the AI assistant.
- Embeddable chat widget — Drop one
<script>tag on any website to add a floating AI shopping assistant. - Merchant dashboard — A full management UI for registration, product management, order tracking, and analytics.
multi-tenant-commerce-engine/
├── main.ts # Val Town HTTP entrypoint + router
├── lib/
│ ├── types.ts # TypeScript interfaces + IDatabase abstraction
│ ├── storage.ts # Pluggable DB singleton (Val Town or local)
│ ├── utils.ts # JSON responses, CORS, ID generation, auth
│ ├── db.ts # Schema initialization (4 tables + indexes)
│ ├── merchants.ts # Merchant CRUD + public store info + stats
│ ├── products.ts # Product CRUD (list, add, update, delete)
│ ├── orders.ts # Order management + atomic booking
│ ├── chatbot.ts # NLP engine + conversation state machine
│ └── dispatch.ts # Supplier webhook notifications
├── public/
│ ├── store.html # Token-free buyer storefront + chat
│ ├── dashboard.html # Merchant management dashboard
│ └── widget.js # Embeddable chat widget for any site
├── termux/
│ └── server.ts # Standalone server (node:sqlite) for Termux
└── README.md
All business logic in lib/ imports db() from lib/storage.ts — never a platform-specific database module. The entrypoint (main.ts for Val Town, termux/server.ts for local) calls setDatabase() once at startup to inject the appropriate adapter:
| Platform | Database | Adapter |
|---|---|---|
| Val Town | libSQL (Turso) | std/sqlite/main.ts wrapper |
| Termux / Local | SQLite via node:sqlite | DatabaseSync wrapper |
Both adapters implement the same IDatabase interface, so the chatbot, order logic, and all CRUD operations are 100% shared between platforms.
- Fork this val or create a new one
- The HTTP endpoint is live immediately
- Visit
https://your-val.val.run/dashboardto register your store - Add products via the dashboard
- Share your store URL:
https://your-val.val.run/store/{merchantId}
# 1. Install Deno pkg install deno # 2. Clone or download the code git clone https://www.val.town/x/tokigo7440/multi-tenant-commerce-engine cd multi-tenant-commerce-engine # 3. Run the server deno run --allow-net --allow-read --allow-write --unstable-node-apis termux/server.ts # 4. Open the dashboard # http://localhost:3000/dashboard
deno run --allow-net --allow-read --allow-write --unstable-node-apis termux/server.ts
The local server creates a commerce.db SQLite file in the working directory. Set DB_PATH to customize the location, and PORT to change the port (default 3000).
| Method | Path | Description |
|---|---|---|
GET | / or /api/health | Health check + endpoint listing |
POST | /api/merchant/register | Register a new merchant |
POST | /api/chat | Send a message to the AI chatbot |
GET | /api/store/{merchantId} | Public store info (products + merchant) |
GET | /store/{merchantId} | Storefront HTML page (token-free) |
GET | /dashboard | Merchant dashboard HTML page |
GET | /api/widget.js?merchant={id} | Embeddable chat widget JS |
| Method | Path | Description |
|---|---|---|
GET | /api/merchant | Get merchant profile |
GET | /api/stats | Dashboard stats (products, orders, revenue) |
GET | /api/products | List all products |
POST | /api/products | Add a product |
PUT | /api/products/{id} | Update a product |
DELETE | /api/products/{id} | Delete a product |
GET | /api/orders | List all orders |
PATCH | /api/orders/{id} | Update order status |
curl -X POST https://your-server/api/merchant/register \ -H "Content-Type: application/json" \ -d '{"name":"My Store","phone":"+1234567890","country":"USA","webhook_url":"https://your-webhook.com/orders"}'
Response:
{ "merchant_id": "mrc_abc123...", "api_key": "sk_def456...", "message": "Merchant registered successfully." }
curl -X POST https://your-server/api/chat \ -H "Content-Type: application/json" \ -d '{"merchant_id":"mrc_abc123...","message":"I want to buy wireless earbuds"}'
curl -X POST https://your-server/api/products \ -H "Content-Type: application/json" \ -H "X-Merchant-Key: sk_def456..." \ -d '{"name":"Wireless Earbuds","price":29.99,"stock":50,"category":"electronics"}'
Add this single line to any HTML page:
<script src="https://your-server/api/widget.js?merchant=MERCHANT_ID"></script>
This creates a floating 💬 button that opens a chat window connected to your AI shopping assistant. Customers can browse products, ask about prices, and place orders — all without leaving your site.
BROWSING
├── "hi" → Greeting + product catalog
├── "what products do you have?" → Product list
├── "how much is X?" → Price info
├── "is X available?" → Stock info
└── "I want to buy X" → ──→ AWAITING_NAME
│
AWAITING_PHONE
│
AWAITING_ADDRESS
│
AWAITING_QUANTITY
│
ORDER BOOKED ✅
+ Webhook dispatched
The chatbot automatically extracts customer information from messages:
- Names: "My name is John", "I'm Sarah"
- Phones: "+1234567890", "(555) 123-4567"
- Addresses: "123 Main St, New York"
- Quantities: "2", "two", "3 units", "a dozen"
- Customer chats with the AI assistant
- AI extracts name, phone, address, and quantity
- Order is booked atomically (insert + stock decrement in one transaction)
- Webhook fires to the merchant's
webhook_urlwith full order details - Merchant ships the order manually and updates status via dashboard
Order statuses: booked → dispatched → delivered (or cancelled)
- Every database query includes
merchant_idin the WHERE clause — cross-tenant data access is structurally prevented - API keys are 48-character hex strings generated with
crypto.getRandomValues - Buyer-facing endpoints (
/api/chat,/api/store/:id) require no authentication — only the merchant management endpoints requireX-Merchant-Key - Webhook notifications include an
X-Merchant-Idheader for verification
- Install Termux from F-Droid (not Play Store)
- Update packages:
pkg update && pkg upgrade - Install Deno:
pkg install deno - Install git (optional):
pkg install git
# Create a working directory mkdir ~/commerce && cd ~/commerce # Download the files (or clone if using git) # You need: main.ts, lib/, public/, termux/ # Run the server deno run --allow-net --allow-read --allow-write --unstable-node-apis termux/server.ts # The server starts on port 3000 # Open http://localhost:3000/dashboard in your phone browser
The --allow-net flag is needed for the HTTP server, --allow-read for serving HTML files, --allow-write for the SQLite database file, and --unstable-node-apis for node:sqlite.
# Install tmux to keep the server running in the background pkg install tmux # Start a new session tmux new -s commerce # Run the server deno run --allow-net --allow-read --allow-write --unstable-node-apis termux/server.ts # Detach: Ctrl+B then D # Reattach: tmux attach -t commerce
| Variable | Default | Description |
|---|---|---|
PORT | 3000 | HTTP server port (Termux/local only) |
DB_PATH | commerce.db | SQLite database file path (Termux/local only) |
- Runtime: Deno (Val Town & Termux)
- Database: libSQL/SQLite (Val Town) or node:sqlite (Termux)
- Frontend: Vanilla HTML/CSS/JS (no build step, no framework dependencies)
- AI: Zero-cost pattern-matching NLP (no external API calls, no tokens needed)
- Webhook: Standard HTTP POST with JSON payload
MIT — free to use, modify, and distribute.