# 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";
<Router base="/chat"><AppRoutes /></Router>
```

**`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

<Directory "/redant/web/homelegance-chatbot/dist/public">
    Options -Indexes +FollowSymlinks
    AllowOverride None
    Require all granted
</Directory>

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:<pw>@<pg_host>: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:<pw>@<erp-host>:5432/<db>
ERP_API_KEY=<与 chatbot 相同的 key>
PORT=8080
```

**DBA 需执行**
```sql
CREATE USER chatbot_readonly WITH PASSWORD '<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: <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=<jwt>` 传入
  - `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 |
