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>
8.2 KiB
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"
}
]
}
实施流程:
- Sync: RedcapAdapter 拉取 Metadata。
- Generate: 代码遍历 Metadata,生成一个 draft_rules 数组。
- Merge: 将 draft_rules 与数据库里已有的 manual_rules 合并。
- 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 请求
校验签名
写入 pg-boss 队列
立即返回 200 OK (耗时 < 10ms)。
- 异步层 (Worker):后台 Worker 从队列获取 record_id
拉取数据
执行 Engine A/B
写入日志。
- 同步层 (Node.js):接收 HTTP 请求
- 价值:确保 EDC 前端操作零卡顿,彻底解耦录入与质控。
5.2 批量全量回溯 (Batch Processing)
- 场景:规则变更后(如入排标准修改),需要重新检查历史数据;或每日定时巡检。
- 机制:
- 调度器:创建 BatchQcJob。
- 分片执行:将 1000 条记录拆分为 20 个子任务(每批 50 条),并行推入队列。
- 流控:Worker 控制并发数,避免瞬间打爆 REDCap API。
5.3 "黄色"报警汇总 (Delayed Notifications)
- 场景:发现非紧急的逻辑矛盾或缺失值(黄色/绿色级别)。
- 机制:
- 写入:质控 Worker 发现问题
写入 iit_qc_logs
标记为 pending_digest。
- 发送:每日下午 17:00 定时任务触发
聚合当日所有黄色问题
生成一份简报发送给 PI。
- 写入:质控 Worker 发现问题
- 价值:防消息轰炸,提升用户体验。
5.4 规则自动同步 (Metadata Sync)
- 场景:项目初始化或 REDCap 字段变更。
- 机制:
- 触发:用户点击"同步字段"按钮。
- 执行:前端收到"任务已提交"
后台 Worker 调用 exportMetadata (耗时较长)
解析并更新 iit_field_mapping
更新任务状态。
- 价值:防止长连接超时。
6. 总结
这 4 个建议是完全成熟的生产级方案。
- 它们解决了 "规则从哪来" (1)。
- 解决了 "数据怎么存" (2)。
- 解决了 "怎么发通知" (3)。
- 解决了 "异常怎么办" (4)。
配合之前的 V2.9 极简架构(Engine + Tools + Skill),以及本补充文档中的 异步处理规范,这套系统已经具备了极高的商业交付价值。建议直接纳入 PRD 开发。