# Homelegance Chatbot — 开发与部署日志
> 记录从初始部署到 ERP 集成、知识库等完整开发过程
---
## 目录
1. [项目概述](#1-项目概述)
2. [部署架构](#2-部署架构)
3. [Phase 1 — 基础部署(MySQL → PostgreSQL)](#3-phase-1--基础部署)
4. [Phase 2 — 修复部署问题](#4-phase-2--修复部署问题)
5. [Phase 3 — ERP 集成(FastAPI Bridge)](#5-phase-3--erp-集成)
6. [Phase A — 知识库(Knowledge-First)](#6-phase-a--知识库)
7. [Phase B — 产品体验(快速回复按钮)](#7-phase-b--产品体验)
8. [Phase C — Workflow 流程引擎](#8-phase-c--workflow-流程引擎)
9. [服务器操作速查](#9-服务器操作速查)
10. [待完成事项](#10-待完成事项)
---
## 1. 项目概述
**产品名称**:Homelegance AI Chatbot(Ellie)
**部署地址**:`www.homelegance.com/chat/`
**服务器**:AlmaLinux 8.10,Apache httpd,同一台 Web 服务器
**技术栈**:
| 层 | 技术 |
|---|---|
| 前端 | React 19 + Vite + TypeScript + Tailwind CSS + shadcn/ui |
| 后端 | Node.js + Express + tRPC |
| ORM | Drizzle ORM(drizzle-orm/pg-core) |
| 数据库 | PostgreSQL(独立 DB 服务器,`chatbot` Schema) |
| AI | Anthropic Claude API(`claude-sonnet-4-6`) |
| 进程管理 | PM2 |
| ERP 桥接 | Python 3.12 + FastAPI(内网 127.0.0.1:8080) |
---
## 2. 部署架构
```
Internet
│
▼
Apache :443 (www.homelegance.com)
├─ /chat/api → ProxyPass → Node.js :3000
├─ /chat/ → Alias → /redant/web/homelegance-chatbot/dist/public/
└─ / → AJP → Tomcat(原有 Dealer Portal)
Node.js :3000 (PM2)
├─ PostgreSQL :5432 (chatbot schema — 自身数据库)
└─ FastAPI :8080 (内网 ERP 桥接)
└─ ERP PostgreSQL(只读)
```
### 关键路径
- 代码目录:`/redant/web/homelegance-chatbot/`
- ERP Bridge:`/redant/web/homelegance-chatbot/erp-bridge/`
- PM2 配置:`ecosystem.config.cjs`
- 环境变量:`.env.production`
- Apache 配置:加入 www.homelegance.com 的 VirtualHost
---
## 3. Phase 1 — 基础部署
### 主要变更
**`vite.config.ts`** — 移除 Manus 插件,加入 `base: "/chat/"`
```ts
base: "/chat/",
// 删除: vitePluginManusRuntime, jsxLocPlugin, vitePluginManusDebugCollector
```
**`client/src/App.tsx`** — 加入 wouter Router base
```tsx
import { Router } from "wouter";
```
**`client/src/main.tsx`** — API 路径使用 BASE_URL
```ts
url: `${import.meta.env.BASE_URL}api/trpc`
```
**`drizzle.config.ts`** — dialect 改为 postgresql
**`server/db.ts`** — MySQL → PostgreSQL 适配:
- `onDuplicateKeyUpdate` → `onConflictDoUpdate`
- `insertId` → `.returning({ id: table.id })`
- `affectedRows` → `return 0`
**`package.json`**
```json
"db:push": "drizzle-kit push"
```
### Apache 配置片段(加入现有 VirtualHost *:443)
```apache
ProxyPreserveHost On
ProxyPass /chat/api http://127.0.0.1:3000/api
ProxyPassReverse /chat/api http://127.0.0.1:3000/api
ProxyPass /chat/ !
Alias /chat /redant/web/homelegance-chatbot/dist/public
Options -Indexes +FollowSymlinks
AllowOverride None
Require all granted
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/chat/
RewriteCond %{REQUEST_URI} !/chat/api
RewriteCond %{REQUEST_URI} !\.(js|css|png|jpg|jpeg|gif|ico|svg|woff2|woff|ttf|eot|map|json|webp|txt)$
RewriteRule ^ /redant/web/homelegance-chatbot/dist/public/index.html [L]
```
---
## 4. Phase 2 — 修复部署问题
### 问题与解决
| 问题 | 根因 | 解决方案 |
|------|------|---------|
| 页面空白 | `vitePluginManusRuntime` 注入阻塞代码 | 删除所有 Manus 插件 |
| umami 400 错误 | `%VITE_ANALYTICS_ENDPOINT%` 未替换 | 从 `index.html` 删除该脚本 |
| API 404 | tRPC URL `/api/trpc` 绝对路径,走到 Tomcat | 改用 `import.meta.env.BASE_URL` |
| SPA fallback 返回 HTML 给 JS 文件 | `%{REQUEST_FILENAME} !-f` 检查 DocumentRoot 而非 Alias 路径 | 改用扩展名排除法 |
| `startSession` 500 错误 | MySQL `insertId` 在 PostgreSQL 不存在 | 改用 Drizzle `.returning()` |
| PM2 不加载 `ANTHROPIC_API_KEY` | `env_file` 在该版本 PM2 不可靠 | 改用 Node.js `fs` 直接解析 `.env.production` |
### ecosystem.config.cjs 修复
```js
const env = loadEnv(path.resolve(__dirname, ".env.production"));
module.exports = { apps: [{ name: "homelegance-chat", env, ... }] };
```
### .env.production 必填项
```env
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://chatbot_user:@:5432/homelegance_chat
JWT_SECRET=<64字符随机>
ANTHROPIC_API_KEY=sk-ant-api03-...
ERP_API_URL=http://127.0.0.1:8080
ERP_API_KEY=<随机>
```
---
## 5. Phase 3 — ERP 集成
### 架构
```
Node.js sendMessage
→ 意图检测(规则正则)
→ FastAPI Bridge(127.0.0.1:8080)
→ erp_api.* 存储函数(PostgreSQL 只读账号)
→ 结果注入 System Prompt [ERP CONTEXT]
→ Claude 生成回复
```
### 新建文件
#### `erp-bridge/main.py` — FastAPI 桥接服务
| 端点 | 调用的 ERP 函数 |
|------|--------------|
| `GET /health` | — |
| `POST /catalog` | `erp_api.catalog_lists(conditions jsonb, limit int)` |
| `POST /contacts` | `erp_api.contact_lists(conditions jsonb, limit int)` |
| `POST /orders` | `erp_api.sales_orders_lists(conditions jsonb, limit int)` |
| `GET /orders/{so_id}` | `erp_api.sales_order_get(so_id text)` |
| `POST /stock` | `erp_api.stock_lists(conditions jsonb, limit int)` |
**返回列通过 Python `set[str]` 常量控制**,无需改查询逻辑。
#### `server/erpClient.ts` — HTTP 客户端(8 秒超时)
#### `server/erpTools.ts` — 业务查询函数,返回 LLM 友好字符串
**6 个业务函数**:
- `lookupOrder(soId)` — 单个订单详情
- `lookupOrdersByCustomer(cid, n)` — 客户最近 N 个订单
- `lookupOrdersByPO(poId)` — PO 号查询
- `lookupCatalog(params)` — 产品目录搜索
- `lookupStock(params)` — 库存查询
- `lookupContact(params)` — 客户资料查询
### sendMessage 意图检测顺序
```
1. SO-XXXXX 正则 → lookupOrder()
2. "my orders/recent orders" → lookupOrdersByCustomer()
3. PO-XXXXX 正则 → lookupOrdersByPO()
4. "in stock/inventory" + 型号正则 → lookupStock()
5. 家具关键词 → lookupCatalog()
6. "customer/dealer/company" + 名称 → lookupContact()
```
### ERP Bridge 部署
```bash
cd /redant/web/homelegance-chatbot/erp-bridge
pip3.12 install -r requirements.txt
cp .env.example .env && vi .env
cp erp-bridge.service /etc/systemd/system/
systemctl daemon-reload && systemctl enable --now erp-bridge
curl http://127.0.0.1:8080/health
```
**erp-bridge/.env**
```env
ERP_DATABASE_URL=postgresql://chatbot_readonly:@:5432/
ERP_API_KEY=<与 chatbot 相同的 key>
PORT=8080
```
**DBA 需执行**
```sql
CREATE USER chatbot_readonly WITH PASSWORD '';
GRANT SELECT ON TABLE catalog, customers, stock_po,
sales_orders, sales_order_items, sales_order_note,
order_status, warehouse TO chatbot_readonly;
```
---
## 6. Phase A — 知识库(Knowledge-First)
### 设计原则
> **Knowledge Base First** — Ellie 必须先搜索 Q&A 知识库,命中则直接返回,不调用 LLM;未命中才进入 ERP 检测 → LLM 流程。
### 新增 DB 表(drizzle/schema.ts)
| 表名 | 用途 |
|------|------|
| `chatbot.knowledge_entries` | Q&A 知识条目(管理员维护) |
| `chatbot.knowledge_suggestions` | 自动捕获的未解答问题 |
| `chatbot.knowledge_products` | 从 Excel/CSV 导入的产品目录 |
### sendMessage 完整处理链
```
用户消息
↓
① 知识库搜索(keyword 匹配)
命中 → 直接返回(source: "knowledge"),useCount++
↓ 未命中
② Workflow Flow 引擎(意图检测)
命中 → 执行 Flow 节点,返回(source: "flow")
↓ 未命中
③ ERP 意图检测(6种正则)
命中 → 调用 FastAPI Bridge,结果注入 System Prompt
↓
④ Claude LLM 生成回复
↓
⑤ 自动记录 Suggestion(供管理员审核,持续扩充知识库)
```
### Knowledge 路由(新增 tRPC 端点)
```
knowledge.listEntries / getEntry / createEntry / updateEntry / deleteEntry
knowledge.importEntries — CSV 批量导入
knowledge.listSuggestions / promoteSuggestion / dismissSuggestion
knowledge.listProducts / importProducts
```
---
## 7. Phase B — 产品体验
### 快速回复按钮
`startSession` 返回欢迎消息时携带 `metadata.quickReplies`:
```json
{
"content": "Welcome to Homelegance! I'm **Ellie**...",
"metadata": {
"quickReplies": ["🔥 Hot Deals", "📦 Order Status", "🛋️ Product Catalog"]
}
}
```
前端 `ChatbotWidget.tsx` 读取并渲染为可点击按钮,点击后作为用户消息发送。
### Knowledge Management 页面(3 Tab)
`client/src/pages/DataSources.tsx` 重写为:
**Tab 1: Data Source** — Q&A 条目
- 统计:Total / Active / Total Uses
- 表格:Question | Answer | Category | Source | Uses | Status | Actions
- 手动添加 / CSV 导入(自动识别 header)
**Tab 2: Product** — 产品目录
- 支持 CSV 导入(model, description, categories, collection, price, availability, features, dimensions, imageUrl)
- Replace All 选项
**Tab 3: Suggestions** — 自动捕获的未解答问题
- 统计:Pending / Promoted / Dismissed
- 按状态过滤
- Promote(填写答案后升级为知识条目)/ Dismiss
---
## 8. Phase C — Workflow 流程引擎
### 新文件:`server/flowEngine.ts`
**5 个 Support Flow 意图模式**:
| Flow ID | 触发关键词/正则 |
|---------|--------------|
| `check-order-status` | "order status", "check.*order", "where.*my order" |
| `track-shipment` | "tracking", "track.*shipment", "where.*package" |
| `submit-return` | "return", "RMA", "refund" |
| `cancel-order` | "cancel.*order" |
| `faq-deflection` | "payment", "warranty", "shipping.*time", "minimum.*order" |
**执行逻辑**:
1. 优先读取 DB 中保存的 Flow 节点(`workflow_nodes`)
2. 若无 DB 节点,使用内置静态回复
3. 支持 `shouldEscalate` 标志(Escalation 节点触发时自动转人工)
### 与 sendMessage 的集成顺序
```
KB 搜索 → Flow 引擎 → ERP 意图 → LLM → 记录 Suggestion
```
---
## 9. 服务器操作速查
### 日常部署流程
```bash
# 本地
git add . && git commit -m "..." && git push origin master
# 服务器
cd /redant/web/homelegance-chatbot
git pull origin master
pnpm build
pm2 restart homelegance-chat
```
### DB Schema 更新(新增表后)
```bash
cd /redant/web/homelegance-chatbot
export $(grep -v '^#' .env.production | xargs)
pnpm db:push
```
### PM2 完整重启(env 变更后)
```bash
pm2 delete homelegance-chat
pm2 start ecosystem.config.cjs
pm2 save
pm2 env 0 | grep ANTHROPIC # 验证
```
### 查看日志
```bash
pm2 logs homelegance-chat --lines 50
grep -i "LLM\|error\|Chat\|KB\|Flow\|ERP" /var/log/pm2/homelegance-chat-out-0.log | tail -30
```
### ERP Bridge
```bash
systemctl status erp-bridge
journalctl -u erp-bridge -f
curl -H "X-API-Key: " http://127.0.0.1:8080/health
```
---
## 10. 待完成事项
### 优先级高
- [ ] **ERP Bridge 部署**:在服务器上配置 `.env`,安装 systemd 服务,测试 5 个端点
- [ ] **DB Schema 推送**:`pnpm db:push` 创建 3 个新知识库表
- [ ] **导入 Q&A 知识库**:通过 Knowledge → Data Source → Import CSV 导入初始问答对
### 优先级中
- [ ] **SSO 集成**(Phase 4):Dealer Portal 带 JWT token 跳转 → Ellie 自动识别 dealer 身份
- Portal 生成短效 JWT(5分钟),`?sso_token=` 传入
- `chat.startSession` 验证 token,提取 `customer_id`、`company_name`、`sales_rep`
- Dashboard 自动显示 Customer ID / Sales Rep 列
- [ ] **产品目录导入**:将 Homelegance Excel 产品表转为 CSV,通过 Knowledge → Product 导入
- [ ] **Leads Flows / Sales Flows**:文档标注为 Pending,下一开发阶段实现
### 优先级低
- [ ] **语义搜索升级**:当前知识库用关键词匹配,未来可接入 Embeddings(OpenAI/Anthropic)实现真正语义匹配
- [ ] **多城市部署**:6 个城市共用同一个 Anthropic API Key,各自独立 PM2 + PostgreSQL
---
## Git 提交历史(本项目)
| Commit | 说明 |
|--------|------|
| `c64aee5` | Remove Manus dependencies from frontend build |
| `e2b6e8b` | Fix API paths for /chat/ base URL deployment |
| `bc0d946` | Fix Apache SPA fallback for Alias + RewriteRule conflict |
| `96a20c0` | Fix SPA fallback: use extension exclusion instead of %1 capture |
| `a896b48` | Fix all MySQL-specific APIs for PostgreSQL compatibility |
| `d41f355` | Add ERP integration: FastAPI bridge + intent-aware context injection |
| `4bfd994` | Allow erp-bridge .env.example to be tracked by git |
| `25bc2c6` | Fix PM2 env loading: parse .env.production via fs instead of env_file |
| _(latest)_ | Phase A/B/C: Knowledge Base, Quick Replies, Flow Engine |