forked from wangziqi/gongxue-base
feat: add crm webhook worker
This commit is contained in:
@@ -35,4 +35,4 @@
|
||||
2. 新建 `apps/taro`,按 `docs/refactor/taro-frontend-integration.md` 优先接租户解析、首页、题库练习、背单词、知识手册、个人中心。
|
||||
3. 导出 PocketBase 真实数据到 `pb_export/*.json`,执行 `npm run pb:import:json` 和 `npm run pb:import:validate`。
|
||||
4. 为对象存储、分数线、视频、Excel/CSV 补齐 provider/导入能力,并复用 `content_import_jobs` 管线。
|
||||
5. 接真实短信、微信/QQ 登录、微信支付/支付宝和 CRM worker,进入商用验收。
|
||||
5. 接真实短信、微信/QQ 登录、微信支付/支付宝,继续增强 CRM worker 和其它异步任务,进入商用验收。
|
||||
|
||||
@@ -92,7 +92,7 @@ npm run pb:import:validate
|
||||
|
||||
## 下一阶段拆分
|
||||
|
||||
- `apps/api/src/features` 继续按业务域扩展:真实支付 provider、真实 OAuth provider、平台审计和 worker。
|
||||
- `apps/api/src/features` 继续按业务域扩展:退款对账、真实 OAuth provider、平台审计和更多后台任务。
|
||||
- `src/services/supabaseApi.ts` 逐页替换旧 PB 只读接口,优先学生端和小程序共用页面。
|
||||
- 新增 `apps/worker` 承接 CRM webhook、支付补偿、日报统计、导入后异步检查。
|
||||
- 扩展 `apps/worker`:CRM webhook 已落地,后续继续承接支付补偿、日报统计、导入后异步检查和公共题库同步。
|
||||
- 新增 `apps/taro` 后,Auth/JWT 优先复用 Supabase client;复杂业务命令复用 `apps/api`/RPC/Edge Functions,不单独维护另一套后端逻辑。
|
||||
|
||||
@@ -140,7 +140,8 @@
|
||||
| 手工补绑 | 可联调 | 需要 `referral:write` |
|
||||
| 销售统计/客户列表/团队 | 可联调 | `/api/referral/sales-*`、`team` |
|
||||
| CRM 配置/队列 | 可联调 | `/api/crm/config`、`/api/crm/queue` |
|
||||
| 真实 CRM webhook worker | 待补齐 | 钉钉/飞书/企微发送、签名、重试、死信 |
|
||||
| CRM webhook worker | 可联调 | `apps/worker` 已支持 generic webhook、钉钉、飞书、企微群机器人消息体/签名、到期任务消费、失败退避重试、最终失败、discarded 和 `crm_webhook_log` |
|
||||
| CRM 增强 | 待补齐 | 轮询/定向分配策略、富卡片模板、失败告警、死信运营后台和批量 CRM 推送 |
|
||||
| 分佣结算基础闭环 | 可联调 | `/api/commission/settings`、`member-rate`、`summary`、`orders`、`settlements`、`settlements/generate`、`settlements/status`;支持订单/激活码归因、批次/成员/默认比例优先级、北京时间账期、结算单生成、审核、打款状态、已打款锁定、销售/代理本人范围和租户隔离 |
|
||||
| 分佣打款增强 | 待补齐 | 银行/微信/支付宝真实打款、结算导出、发票/凭证、财务复核和分佣看板 |
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
|
||||
- 租户自定义角色模板基础 API 已完成;继续补权限配置 UI、班级/教师/学生范围权限和平台级审计报表。
|
||||
- 三套默认主题、租户主题预览、Logo/图标/分享图配置。
|
||||
- CRM worker:钉钉、飞书、企微机器人,轮询/定向分配,失败重试。
|
||||
- CRM worker:钉钉、飞书、企微机器人发送、签名、失败重试已落地;继续补轮询/定向分配、富卡片、失败告警和死信运营台。
|
||||
- 销售/代理分佣结算、销售团队看板、客资跟进效果。
|
||||
- AI 择校推荐:地区考试数据、学生输入 schema、AI JSON 输出、PDF 报告生成。
|
||||
- 性能压测、慢 SQL 审查、备份恢复演练、灰度发布和回滚预案。
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
- 已新增 `npm run db:smoke-seed`,用于 `supabase:reset` 后恢复最小烟测数据。
|
||||
- 已新增 `npm run smoke:core-api`,用于验证个人中心、分数线、题目视频、背单词进度/收藏等学生端核心 API。
|
||||
- 已新增 `npm run test:api`,自动 seed、构建、启动临时 API,并断言核心学生端接口、内容导航/组卷、租户隔离、资源权限和题目导入。
|
||||
- 已新增 `apps/worker` 和 `npm run test:worker:crm`,用于消费 CRM webhook 队列,验证本地 fake webhook、队列状态、日志和密钥不泄露。
|
||||
|
||||
## 已验证接口
|
||||
|
||||
@@ -233,7 +234,7 @@ GET /api/tenant-admin/audit-logs
|
||||
- 班级学生 API 会按 `tenant_memberships.role_template_id -> tenant_role_templates.data_scope`、成员显式权限和 `tenant_class_members` 共同确定可见范围;非全局权限教师只能查看自己负责班级的学生。
|
||||
- 学生批量导入、批量分班、学生状态、备注和跟进任务都使用独立权限点;教师默认可为范围内学生写备注和跟进任务,但不能批量导入、禁用学生或放大可见班级。
|
||||
- 销售/代理客资采用首绑保护:普通扫码/分享事件不会覆盖已有归属,只有具备 `referral:write` 的租户成员可手动强制补绑。
|
||||
- CRM 当前完成配置、密钥入私密表、客资入队和队列查询;真实 webhook 发送、重试、签名在后续 `apps/worker` 中实现。
|
||||
- CRM 当前完成配置、密钥入私密表、客资入队、队列查询和 `apps/worker` 消费;worker 支持 generic webhook、钉钉、飞书、企业微信机器人消息体/签名、失败重试和日志。
|
||||
- 内容资源当前完成台账、租户后台维护、学生端 SVIP 下载权限,以及 `local_dev`、阿里云 OSS、腾讯 COS、Supabase Storage 的上传/下载签名 provider。真实对象存在性校验、PDF 预览渲染、防盗链、水印和大文件上传后 worker 校验仍需继续补。
|
||||
- 题库内容导航当前以 `content_entries/content_nodes` 为主模型,可表达“入口 -> 多级分类 -> 院校/专业/学科/销售意向标记”;题目集合和练习方式由 `question_collections/practice_blueprints` 管理,练习 session 会保存当次题目 ID 快照。
|
||||
- 练习访问控制由 `content_entries/content_nodes/question_collections/practice_blueprints` 的 `accessRules` 合并决定;普通用户消耗 `practice_daily_usage`,事件写入 `practice_access_events`,SVIP/staff 不消耗免费额度。
|
||||
@@ -245,12 +246,13 @@ GET /api/tenant-admin/audit-logs
|
||||
2. 接入真实短信 provider:阿里云/腾讯云,密钥放 `app_private.tenant_secrets` 或生产 Vault。
|
||||
3. 接入真实 OAuth provider:微信网页、微信小程序、QQ,并处理旧 PocketBase 身份映射。
|
||||
4. 补退款、支付补偿任务、对账、异常订单处理和优惠券核销报表。
|
||||
5. 增加 `apps/worker`:支付补偿、CRM webhook、日报统计、导入后检查。
|
||||
5. 扩展 `apps/worker`:支付补偿、日报统计、导入后检查、CRM 死信告警和公共题库同步。
|
||||
6. 开始 Taro scaffold,把 `supabaseApi` 抽到跨端包或适配层。
|
||||
|
||||
## 测试命令
|
||||
|
||||
```text
|
||||
npm run test:api
|
||||
npm run test:worker:crm
|
||||
npm run check:refactor
|
||||
```
|
||||
|
||||
@@ -41,4 +41,4 @@
|
||||
3. 学习统计增强:排行榜防刷/预聚合、断点续练、专项练习策略和更细题型分析。
|
||||
4. 视频会员控制:视频资源签名 URL、防盗链、水印、播放次数和会员权益。
|
||||
5. 数据看板 API:把旧 dashboard/revenue 统计迁到新 API。
|
||||
6. 真实 provider:短信、微信/QQ 登录、微信支付/支付宝、CRM worker。
|
||||
6. 真实 provider:短信、微信/QQ 登录、微信支付/支付宝;CRM worker 基础已落地,继续补分配策略和告警。
|
||||
|
||||
107
docs/refactor/crm-worker.md
Normal file
107
docs/refactor/crm-worker.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# CRM Webhook Worker
|
||||
|
||||
更新时间:2026-06-29
|
||||
|
||||
`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
|
||||
```
|
||||
|
||||
密钥必须写入 `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: ... }` |
|
||||
| `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。
|
||||
- 生产环境 webhook 必须使用 HTTPS。
|
||||
- `WORKER_CRM_ALLOW_INSECURE_LOCALHOST=true` 只用于本地 fake webhook 测试。
|
||||
- worker 使用数据库服务端连接读取 `app_private.tenant_secrets`,不要把 secret 复制到公共表。
|
||||
|
||||
## 后续增强
|
||||
|
||||
- 轮询/定向分配销售。
|
||||
- 钉钉/飞书/企微富卡片模板。
|
||||
- 失败告警和死信运营后台。
|
||||
- 批量 CRM 推送、跟进效果统计。
|
||||
@@ -35,7 +35,7 @@
|
||||
| 资料下载/PDF | 已扩展 `content_assets`,新增资源台账和导入任务表 | 旧 `app_assets/images` 兼容导入 | 租户后台资源管理、上传/下载签名占位、学生端资料列表/下载权限已实现 | 核心 API 集成测试含 SVIP 资料下载 | 资料资源基础闭环可跑,真实 OSS/COS 签名、PDF 预览渲染、资料下载前端待补 |
|
||||
| 个人中心 | 已建 `student_profiles`、会员权益、订单、练习记录 | 已支持部分用户资料导入 | 个人资料、目标院校/专业、会员状态、最近练习、统计聚合 API 已实现 | 核心 API 烟测 | 学生端基础个人中心已实现,签到/任务/更细统计待补 |
|
||||
| 活动/优惠 | 已建优惠券、激活码、激活码批次、banner、FAQ、公告等基础表 | 部分支持 | banner/FAQ/公告只读与租户后台维护、激活码预检查/兑换、激活码批次、批量生成激活码、优惠券维护、前台领取/下单抵扣已实现 | 核心 API 集成测试 | 基础运营后台可用,复杂活动规则、营销自动化、核销报表待补 |
|
||||
| 销售/代理客资追踪 | 已建推荐码、首绑客资、团队关系、小程序码缓存、CRM 队列 | 旧 `referral_tracks` 已有映射基础 | 邀请码、扫码/分享事件、首绑保护、销售统计、客资明细、手动补绑、团队关系、CRM 配置/队列已实现 | 核心 API 集成测试 | 增长链路基础可用,真实微信小程序码、分佣结算单、CRM worker 推送待补 |
|
||||
| 销售/代理客资追踪 | 已建推荐码、首绑客资、团队关系、小程序码缓存、CRM 队列 | 旧 `referral_tracks` 已有映射基础 | 邀请码、扫码/分享事件、首绑保护、销售统计、客资明细、手动补绑、团队关系、CRM 配置/队列、CRM worker 推送已实现 | 核心 API 集成测试、CRM worker 集成测试 | 增长链路基础可用,真实微信小程序码、CRM 分配策略、富卡片和销售转化看板待补 |
|
||||
| 租户后台 | 已建品牌、域名、设置、支付账户、登录 provider、私密密钥表、成员、审计日志、资源台账、导入台账、内容导航台账 | 不适用 | 概览、品牌、设置、域名、支付账户、登录配置、密钥掩码、活动内容、兑换码/优惠券、成员管理、权限矩阵、审计查询、内容入口/分类树/题目集合/练习蓝图维护、资源管理、题目 JSON 导入已实现 | 核心 API 集成测试含角色/权限/租户隔离/密钥不泄露/导航/组卷/资源与导入断言 | 租户配置与运营闭环可用,前端权限 UI、Excel 导入、真实对象存储签名待补 |
|
||||
| 平台后台 | 已建 SaaS 套餐、订阅、账单、服务费、用量 | 不适用 | 租户管理、账单、收款确认、用量记录、平台管理员 Supabase JWT 鉴权已实现 | API 集成测试 | 平台收费链路骨架可用,平台审计报表/自动计费待补 |
|
||||
| 登录认证 | 已建短信验证码、会话、OAuth provider 配置表,并支持 `auth_user_id` 映射 | 旧用户映射已预留 | 短信 mock 登录、迁移期 session、Supabase JWT 验签映射、微信小程序登录主链路已实现 | API 集成测试 | H5 Supabase Auth 可联调;真实短信/微信网页/QQ 登录生产联调待补 |
|
||||
|
||||
@@ -133,9 +133,8 @@
|
||||
- 主题预览和发布。
|
||||
|
||||
3. CRM worker
|
||||
- 钉钉、飞书、企业微信机器人 adapter。
|
||||
- 轮询/定向分配。
|
||||
- 推送失败重试和签名。
|
||||
- 已完成 `apps/worker` CRM 队列消费、generic webhook、钉钉、飞书、企业微信机器人 adapter、签名、失败重试和日志。
|
||||
- 继续补轮询/定向分配、富卡片模板、失败告警、死信运营后台和批量 CRM 推送。
|
||||
|
||||
4. 运维
|
||||
- 后台操作审计报表。
|
||||
|
||||
@@ -38,6 +38,15 @@ F:\project
|
||||
Dockerfile
|
||||
package.json
|
||||
tsconfig.json
|
||||
worker/ 后台异步任务进程
|
||||
src/
|
||||
jobs/
|
||||
crm.ts CRM webhook 队列消费、签名、重试、日志
|
||||
config.ts worker 环境变量
|
||||
db.ts worker 数据库连接
|
||||
index.ts worker CLI/常驻循环入口
|
||||
package.json
|
||||
tsconfig.json
|
||||
|
||||
packages/
|
||||
config/ 共享配置和 env 工具
|
||||
@@ -117,6 +126,7 @@ git status --short --branch
|
||||
正常情况下,后续提交应只包含这些路径:
|
||||
|
||||
- `apps/api/**`
|
||||
- `apps/worker/**`
|
||||
- `packages/**`
|
||||
- `supabase/**`
|
||||
- `scripts/import-pocketbase/**`
|
||||
|
||||
Reference in New Issue
Block a user