Summary: - Add 4 new database tables: iit_field_metadata, iit_qc_logs, iit_record_summary, iit_qc_project_stats - Implement pg-boss debounce mechanism in WebhookController - Refactor QC Worker for dual output: QC logs + record summary - Enhance HardRuleEngine to support form-based rule filtering - Create QcService for QC data queries - Optimize ChatService with new intents: query_enrollment, query_qc_status - Add admin batch operations: one-click full QC + one-click full summary - Create IIT Admin management module: project config, QC rules, user mapping Status: Code complete, pending end-to-end testing Co-authored-by: Cursor <cursoragent@cursor.com>
200 lines
8.2 KiB
Markdown
200 lines
8.2 KiB
Markdown
# **IIT Manager Agent V2.9 补充:业务规则与数据治理细则**
|
||
|
||
**文档性质:** 业务逻辑落地方案
|
||
|
||
**评审结论:** 4 点建议逻辑清晰,完全可行。本方案在原有基础上进行了 Postgres 原生特性的优化。
|
||
|
||
## **1\. 质控规则来源:自动化与人工的完美结合**
|
||
|
||
**评价**:非常合理。这是降低实施成本的关键。如果全部靠人工配,运营会累死;如果全部靠自动,医学逻辑会缺失。
|
||
|
||
**落地优化建议**:
|
||
|
||
我们在 iit\_skills 表的 JSON 配置中,引入 **source** 字段来标记规则来源,方便管理。
|
||
|
||
// qc\_skill.json (最终生成的配置文件)
|
||
{
|
||
"hard\_rules": \[
|
||
// \=== 自动生成区 (Auto-Generated) \===
|
||
{
|
||
"field": "age",
|
||
"logic": { "\>=": \[{ "var": "age" }, 18\] },
|
||
"message": "年龄必须 \>= 18",
|
||
"source": "meta\_validation\_min", // 标记来源
|
||
"level": "warning"
|
||
},
|
||
{
|
||
"field": "informed\_consent\_date",
|
||
"logic": { "\!=": \[{ "var": "informed\_consent\_date" }, ""\] },
|
||
"message": "知情同意日期必填",
|
||
"source": "meta\_required",
|
||
"level": "error"
|
||
},
|
||
|
||
// \=== 人工配置区 (Manual) \===
|
||
{
|
||
"field": "visit\_date",
|
||
"logic": { "\<=": \[{ "var": "visit\_date" }, { "var": "today" }\] },
|
||
"message": "访视日期不能是未来",
|
||
"source": "manual\_config",
|
||
"level": "error"
|
||
}
|
||
\]
|
||
}
|
||
|
||
**实施流程**:
|
||
|
||
1. **Sync**: RedcapAdapter 拉取 Metadata。
|
||
2. **Generate**: 代码遍历 Metadata,生成一个 draft\_rules 数组。
|
||
3. **Merge**: 将 draft\_rules 与数据库里已有的 manual\_rules 合并。
|
||
4. **Confirm**: 在管理端展示,人工确认后保存。
|
||
|
||
## **2\. 质控数据存储:利用 JSONB 简化分层**
|
||
|
||
**评价**:分层思路是对的,但**建议简化物理表结构**。
|
||
|
||
如果每个字段的错误都存一行记录(iit\_qc\_results),当项目有 1000 个病人 x 400 个变量时,这张表会瞬间爆炸(千万级行数),查询变慢。
|
||
|
||
**Postgres 优化方案**:
|
||
|
||
利用 Postgres 强大的 **JSONB** 能力,将(1)和(2)合并,保留(3)。
|
||
|
||
### **优化后的 Schema:**
|
||
|
||
**(1) \+ (2) 合并为:iit\_qc\_logs (记录级 \+ 字段级详情)**
|
||
|
||
model IitQcLog {
|
||
id String @id @default(uuid())
|
||
projectId String
|
||
recordId String
|
||
eventId String
|
||
|
||
// 核心结果
|
||
status String // 'PASS' | 'FAIL' | 'WARNING'
|
||
|
||
// 字段级详情,直接存 JSONB
|
||
// 格式: \[{ field: "age", error: "范围越界", level: "RED" }, { ... }\]
|
||
// 优势: Postgres 支持对 JSONB 内部字段建立索引,查询速度一样快,但表行数少 100 倍
|
||
issues Json
|
||
|
||
ruleVersion String // 对应问题4的解决方案
|
||
createdAt DateTime @default(now())
|
||
|
||
@@index(\[projectId, recordId\])
|
||
@@map("iit\_qc\_logs")
|
||
}
|
||
|
||
**(3) 保留:iit\_qc\_project\_stats (每日汇总)**
|
||
|
||
* 用于 Dashboard 快速展示,避免每次都 COUNT(\*) 几百万行日志。
|
||
|
||
## **3\. 主动干预分级:防打扰机制**
|
||
|
||
**评价**:非常棒的\*\*“抗疲劳设计”\*\*。如果不分级,PI 一天收 50 条推送,第二天就会把机器人拉黑。
|
||
|
||
**落地实现**:
|
||
|
||
在 WechatService 中实现一个 **Notification Filter**。
|
||
|
||
// NotificationFilter.ts
|
||
|
||
async function handleAlert(projectId, logs) {
|
||
// 1\. 红色:立即发送
|
||
const redIssues \= logs.filter(i \=\> i.level \=== 'RED');
|
||
if (redIssues.length \> 0\) {
|
||
await sendWechat("🚨 紧急报警: 发现 SAE 或严重违规...");
|
||
await sendSms("..."); // 可选
|
||
}
|
||
|
||
// 2\. 黄色:存入每日摘要队列 (Redis/DB),不立即发
|
||
const yellowIssues \= logs.filter(i \=\> i.level \=== 'YELLOW');
|
||
if (yellowIssues.length \> 0\) {
|
||
await addToDailyDigest(projectId, yellowIssues);
|
||
}
|
||
|
||
// 3\. 绿色:只记录日志,完全不发
|
||
}
|
||
|
||
## **4\. 潜在问题与解决方案:技术细节补全**
|
||
|
||
你提出的解决方案都很到位,我从技术落地角度做一点补充。
|
||
|
||
### **(1) 规则版本管理**
|
||
|
||
* **你的方案**:增加 rule\_version。✅
|
||
* **补充**:iit\_skills 表本身应该有一个 version 字段(自增 Int)。每次生成 IitQcLog 时,把这个 version 抄进去。这样以后回溯时,就知道当时是按哪套法律判的案。
|
||
|
||
### **(2) 性能问题**
|
||
|
||
* **你的方案**:Webhook 只查单条,全量用异步。✅
|
||
* **补充**:这就是我们 V2.9 架构的天然优势。
|
||
* **实时**:WebhookController \-\> SopEngine (单条)。
|
||
* **全量**:pg-boss 定时任务 \-\> BatchQcJob (批量)。
|
||
|
||
### **(3) 重复质控 (防抖)**
|
||
|
||
* **你的方案**:幂等性检查(5分钟)。✅
|
||
* **技术落地**:利用 pg-boss 的 **Debounce** 功能。
|
||
// WebhookController.ts
|
||
// 如果 5 分钟内来了同一个 record\_id 的 Webhook,只执行最后一次
|
||
await boss.send('qc-job', { recordId }, {
|
||
singletonKey: \`qc-${projectId}-${recordId}\`, // 唯一键
|
||
singletonSeconds: 300 // 300秒防抖窗口
|
||
});
|
||
|
||
这样根本不需要写复杂的 Redis 锁,pg-boss 帮你搞定。
|
||
|
||
### **(4) 字段映射变更**
|
||
|
||
* **你的方案**:重新同步。✅
|
||
* **补充**:增加一个 **"变更检测"**。
|
||
* 每次 Webhook 数据来了,检查一下 payload 里的字段名是否在我们的 iit\_field\_mapping 里。如果不认识,说明 REDCap 改了,Agent 自动触发一次 Metadata Sync 任务。
|
||
|
||
## **5\. 异步架构落地场景 (Asynchronous Implementation)**
|
||
|
||
为了保证高并发下的系统稳定性,本方案在以下 4 个关键环节强制使用异步处理(基于 pg-boss):
|
||
|
||
### **5.1 核心质控执行 (Core Execution)**
|
||
|
||
* **场景**:CRC 在 REDCap 点击保存,触发 DET Webhook。
|
||
* **机制**:
|
||
* **同步层 (Node.js)**:接收 HTTP 请求 ![][image1] 校验签名 ![][image1] 写入 pg-boss 队列 ![][image1] 立即返回 200 OK (耗时 \< 10ms)。
|
||
* **异步层 (Worker)**:后台 Worker 从队列获取 record\_id ![][image1] 拉取数据 ![][image1] 执行 Engine A/B ![][image1] 写入日志。
|
||
* **价值**:确保 EDC 前端操作零卡顿,彻底解耦录入与质控。
|
||
|
||
### **5.2 批量全量回溯 (Batch Processing)**
|
||
|
||
* **场景**:规则变更后(如入排标准修改),需要重新检查历史数据;或每日定时巡检。
|
||
* **机制**:
|
||
* **调度器**:创建 BatchQcJob。
|
||
* **分片执行**:将 1000 条记录拆分为 20 个子任务(每批 50 条),并行推入队列。
|
||
* **流控**:Worker 控制并发数,避免瞬间打爆 REDCap API。
|
||
|
||
### **5.3 "黄色"报警汇总 (Delayed Notifications)**
|
||
|
||
* **场景**:发现非紧急的逻辑矛盾或缺失值(黄色/绿色级别)。
|
||
* **机制**:
|
||
* **写入**:质控 Worker 发现问题 ![][image1] 写入 iit\_qc\_logs ![][image1] 标记为 pending\_digest。
|
||
* **发送**:每日下午 17:00 定时任务触发 ![][image1] 聚合当日所有黄色问题 ![][image1] 生成一份简报发送给 PI。
|
||
* **价值**:防消息轰炸,提升用户体验。
|
||
|
||
### **5.4 规则自动同步 (Metadata Sync)**
|
||
|
||
* **场景**:项目初始化或 REDCap 字段变更。
|
||
* **机制**:
|
||
* **触发**:用户点击"同步字段"按钮。
|
||
* **执行**:前端收到"任务已提交" ![][image1] 后台 Worker 调用 exportMetadata (耗时较长) ![][image1] 解析并更新 iit\_field\_mapping ![][image1] 更新任务状态。
|
||
* **价值**:防止长连接超时。
|
||
|
||
## **6\. 总结**
|
||
|
||
这 4 个建议是**完全成熟的生产级方案**。
|
||
|
||
* 它们解决了 **"规则从哪来"** (1)。
|
||
* 解决了 **"数据怎么存"** (2)。
|
||
* 解决了 **"怎么发通知"** (3)。
|
||
* 解决了 **"异常怎么办"** (4)。
|
||
|
||
配合之前的 **V2.9 极简架构**(Engine \+ Tools \+ Skill),以及本补充文档中的 **异步处理规范**,这套系统已经具备了极高的商业交付价值。建议直接纳入 PRD 开发。
|
||
|
||
[image1]: <data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAXCAYAAADpwXTaAAAAX0lEQVR4XmNgGAWjYCQAeXn50+hiZAOgYU/QxcgGcnJy2kA8HV2cbAB03SwgDkIXB0lIkomnAfF1oBHM1DBsERCfRzGMHCCPy5ukAmgETEAXJwvIUzFpMMpTM9GOcAAAmV0cRTlI2MMAAAAASUVORK5CYII=> |