Public
Multi-tenant e-commerce with AI chatbot, storefront & dashboard
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

Multi-Tenant Commerce Engine

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.

What It Does

  • 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.

Architecture

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

Storage Abstraction

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:

PlatformDatabaseAdapter
Val TownlibSQL (Turso)std/sqlite/main.ts wrapper
Termux / LocalSQLite via node:sqliteDatabaseSync wrapper

Both adapters implement the same IDatabase interface, so the chatbot, order logic, and all CRUD operations are 100% shared between platforms.

Quick Start

Option 1: Val Town (Cloud)

  1. Fork this val or create a new one
  2. The HTTP endpoint is live immediately
  3. Visit https://your-val.val.run/dashboard to register your store
  4. Add products via the dashboard
  5. Share your store URL: https://your-val.val.run/store/{merchantId}

Option 2: Termux (Local on Android)

# 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

Option 3: Any Machine with Deno

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).

API Reference

Public Endpoints (No Authentication)

MethodPathDescription
GET/ or /api/healthHealth check + endpoint listing
POST/api/merchant/registerRegister a new merchant
POST/api/chatSend a message to the AI chatbot
GET/api/store/{merchantId}Public store info (products + merchant)
GET/store/{merchantId}Storefront HTML page (token-free)
GET/dashboardMerchant dashboard HTML page
GET/api/widget.js?merchant={id}Embeddable chat widget JS

Authenticated Endpoints (Requires X-Merchant-Key header)

MethodPathDescription
GET/api/merchantGet merchant profile
GET/api/statsDashboard stats (products, orders, revenue)
GET/api/productsList all products
POST/api/productsAdd a product
PUT/api/products/{id}Update a product
DELETE/api/products/{id}Delete a product
GET/api/ordersList all orders
PATCH/api/orders/{id}Update order status

Register a Merchant

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." }

Chat with the AI

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"}'

Add a Product

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"}'

Embedding the Chat Widget

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.

Chatbot Conversation Flow

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"

Order Lifecycle

  1. Customer chats with the AI assistant
  2. AI extracts name, phone, address, and quantity
  3. Order is booked atomically (insert + stock decrement in one transaction)
  4. Webhook fires to the merchant's webhook_url with full order details
  5. Merchant ships the order manually and updates status via dashboard

Order statuses: bookeddispatcheddelivered (or cancelled)

Security

  • Every database query includes merchant_id in 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 require X-Merchant-Key
  • Webhook notifications include an X-Merchant-Id header for verification

Running on Termux — Detailed Guide

Prerequisites

  1. Install Termux from F-Droid (not Play Store)
  2. Update packages: pkg update && pkg upgrade
  3. Install Deno: pkg install deno
  4. Install git (optional): pkg install git

Step-by-Step

# 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

Termux Permissions

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.

Keeping the Server Running

# 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

Environment Variables

VariableDefaultDescription
PORT3000HTTP server port (Termux/local only)
DB_PATHcommerce.dbSQLite database file path (Termux/local only)

Tech Stack

  • 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

License

MIT — free to use, modify, and distribute.