Files
gongxue-base/docs/refactor/crm-worker.md
2026-06-30 16:42:23 +08:00

110 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CRM Webhook Worker
更新时间2026-06-30
`apps/worker` 是后端异步任务进程,当前 CRM 任务支持客资首绑 webhook 推送和租户后台学生批量跟进推送。API 只负责在客资首绑或学生运营动作时写入 `crm_webhook_queue`worker 负责消费到期任务、签名、发送、失败重试和写入 `crm_webhook_log`
## 运行命令
本地单次消费一批任务:
```bash
npm --workspace @tiku-saas/worker run crm:once
```
或使用根脚本测试:
```bash
npm run test:worker:crm
```
生产常驻:
```bash
npm --workspace @tiku-saas/worker run start
```
建议 API 和 worker 作为两个独立进程部署,共用同一个 `DATABASE_URL`
## 配置
环境变量:
```text
WORKER_CRM_BATCH_SIZE=20
WORKER_CRM_POLL_INTERVAL_MS=10000
WORKER_CRM_MAX_ATTEMPTS=5
WORKER_CRM_BACKOFF_SECONDS=5,30,120,600,1800
WORKER_CRM_REQUEST_TIMEOUT_MS=10000
WORKER_CRM_ALLOW_INSECURE_LOCALHOST=false
```
租户后台配置仍走:
```text
PUT /api/crm/config
GET /api/crm/config
GET /api/crm/queue
POST /api/tenant-admin/students/crm-push
```
密钥必须写入 `app_private.tenant_secrets`,公共表 `crm_config.secret_ref` 只保留引用,例如:
```text
app_private.tenant_secrets:crm:webhook
```
## Provider
worker 根据队列 payload 的 `provider` 或 webhook URL 自动判断:
| provider | URL 特征 | 行为 |
| --- | --- | --- |
| `generic` | 默认 | POST `{ event: "lead.created", data: ... }``{ event: "student.crm_push", data: ... }` |
| `dingtalk` | `dingtalk.com` | markdown 消息;按钉钉自定义机器人安全设置做 timestamp/sign |
| `feishu` | `feishu.cn` / `larksuite.com` | interactive card按飞书自定义机器人签名做 timestamp/sign |
| `wecom` | `qyapi.weixin.qq.com` / `work.weixin.qq.com` | 企业微信群机器人 markdown 消息 |
官方参考:
- 钉钉开放平台:[自定义机器人安全设置](https://open.dingtalk.com/document/robots/customize-robot-security-settings)`timestamp + "\n" + secret` 做 HMAC-SHA256 后 Base64。
- 飞书开放平台:[自定义机器人签名校验](https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot),使用 timestamp 和 secret 生成签名。
- 企业微信开发者文档:[群机器人配置说明](https://developer.work.weixin.qq.com/document/path/91770),群机器人 webhook 使用 `msgtype` 消息体。
## 队列状态
`crm_webhook_queue.status`
```text
pending -> processing -> sent
pending -> processing -> retrying -> processing -> sent
pending -> processing -> retrying -> failed
pending -> discarded
```
说明:
- `pending` / `retrying`:等待 worker 消费。
- `processing`worker 已抢占任务。
- `sent`:目标 webhook 返回 2xx。
- `failed`:超过最大重试次数。
- `discarded`:租户 CRM 未启用或 URL 缺失,任务不会继续重试。
每次尝试都会写入 `crm_webhook_log`,日志只记录 provider、目标 host、请求体和响应摘要不写入 webhook secret。
## 安全边界
- 前端不能直接写 `crm_webhook_queue`
- 前端不能持有 CRM webhook secret。
- 学生批量推送必须走 `POST /api/tenant-admin/students/crm-push`,后端会校验 `crm:write``students:read``students:followups:write`、学生范围、班级范围和租户成员指派人。
- 学生推送 payload 只包含 `avatarPreset` 默认头像口径,不写入、不回显微信/QQ/旧库头像 URL。
- 生产环境 webhook 必须使用 HTTPS。
- `WORKER_CRM_ALLOW_INSECURE_LOCALHOST=true` 只用于本地 fake webhook 测试。
- worker 使用数据库服务端连接读取 `app_private.tenant_secrets`,不要把 secret 复制到公共表。
## 后续增强
- 钉钉/飞书/企微富卡片模板。
- 失败告警和死信运营后台。
- 更细销售转化看板。