feat(iit): Complete V3.1 QC engine + GCP business reports + AI timeline + bug fixes

V3.1 QC Engine:
- QcExecutor unified entry + D1-D7 dimension engines + three-level aggregation
- HealthScoreEngine + CompletenessEngine + ProtocolDeviationEngine + QcAggregator
- B4 flexible cron scheduling (project-level cronExpression + pg-boss dispatcher)
- Prisma migrations for qc_field_status, event_status, project_stats

GCP Business Reports (Phase A - 4 reports):
- D1 Eligibility: record_summary full list + qc_field_status D1 overlay
- D2 Completeness: data entry rate and missing rate aggregation
- D3/D4 Query Tracking: severity distribution from qc_field_status
- D6 Protocol Deviation: D6 dimension filtering
- 4 frontend table components + ReportsPage 5-tab restructure

AI Timeline Enhancement:
- SkillRunner outputs totalRules (33 actual rules vs 1 skill)
- iitQcCockpitController severity mapping fix (critical->red, warning->yellow)
- AiStreamPage expandable issue detail table with Chinese labels
- Event label localization (eventLabel from backend)

Business-side One-click Batch QC:
- DashboardPage batch QC button with SyncOutlined icon
- Auto-refresh QcReport cache after batch execution

Bug Fixes:
- dimension_code -> rule_category in 4 SQL queries
- D1 eligibility data source: record_summary full + qc_field_status overlay
- Timezone UTC -> Asia/Shanghai (QcReportService toBeijingTime helper)
- Pass rate calculation: passed/totalEvents instead of passed/totalRecords

Docs:
- Update IIT module status with GCP reports and bug fix milestones
- Update system status doc v6.6 with IIT progress

Tested: Backend compiles, frontend linter clean, batch QC verified
Made-with: Cursor
This commit is contained in:
2026-03-01 22:49:49 +08:00
parent 0b29fe88b5
commit 2030ebe28f
50 changed files with 8687 additions and 1492 deletions

View File

@@ -0,0 +1,103 @@
# **业务端 GCP 质控报表开发计划专家审查报告**
**审查对象**《GCP Business Reports 开发计划》 (5aeb159b.plan)
**审查定位**:针对 D1、D2、D3/D4、D6 报表开发的逻辑闭环、性能瓶颈及 LLM 协同性进行深度排雷。
**审查结论**:总体架构极佳,完美贯彻了“硬计算归系统,软推理归 LLM”的原则。但在 D2 缺失数据写入、D6 字段解析及前端加载性能上存在 4 个隐藏坑点,需在编码前修正。
## **一、 值得高度肯定的亮点What's Good**
1. **极其敏锐的 P0 漏洞捕捉**
发现 SkillRunner 未将 category 传播给 QcExecutor导致 D1 变 D3。这个 Bug 如果在测试期才发现,会导致所有报表数据串位。修复方案非常精准。
2. **对 LLM 极其友好的底层设计**
你没有选择“把几十万条数据直接扔给 LLM 让它画表格”,而是**老老实实写了 4 个结构化的 API**。这是最顶级的 LLM 友好型架构!
*未来 LLM 只需要调用这 4 个 API 获取 JSON极低 Token就能在 Tab 0执行摘要里写出极其精准且绝对不会幻觉的全局分析报告。*
3. **前端 UI 的“渐进式展开Progressive Disclosure”设计**
D2 报表的 受试者 → 事件 → 字段清单 三级展开设计,完全对标了 Medidata J-Review 的体验,非常符合 CRA “从宏观到微观”的查错习惯。
## **二、 架构排雷与修正建议What needs fix**
### **💣 坑点 1D2 (数据完整性) 的“幽灵记录”取数陷阱**
**🔍 计划漏洞**
计划中 D2 的 API 打算用这段 SQL 统计缺失率SELECT count(\*) FROM qc\_field\_status WHERE rule\_category \= 'D2' AND status \= 'FAIL'。
**临床逻辑断层**:如果是“缺失数据”,意味着 CRC **根本没有填这个字段**。如果没填Webhook 就不会推送这个字段HardRuleEngine 如果只是遍历传来的数据,就**永远不会为这个缺失字段在 qc\_field\_status 中插入一行 FAIL 记录**。没有记录,你的 SQL 就什么都 count 不到!
**🛠️ 修正建议 (后端)**
必须明确界定 CompletenessEngine (D2 引擎) 的特殊职责:**它必须是主动轮询Proactive Polling**。
D2 引擎在运行时,必须拿患者当前的 Event 去对比 REDCap 的 Data Dictionary。对于字典里有但数据库里没有的必填项引擎必须**主动强行向 qc\_field\_status 插入一条具有五层坐标的“幽灵记录”**(实际值为空,状态为 FAIL类别为 D2
*只有这样,你计划里的 SQL 才能真正生效。请将此要求补充进 D2 的开发任务中。*
### **💣 坑点 2D6 (方案偏离) 脆断的文本解析**
**🔍 计划漏洞**
计划中写道:对于 D6 API从 actual\_value / expected\_value 解析超窗天数和方向。
**过度耦合**:如果在规则引擎里 actual\_value 存的是字符串 "延误 10 天"API 层再去用正则解析提取数字 10 和方向 late这是极其脆弱的设计只要底层提示语改一个字报表就崩了。
**🛠️ 修正建议 (后端数据结构)**
不要在 API 层解析字符串。在底层执行超窗规则D6规则引擎应该把结构化的偏离数据写入到一个元数据字段。
如果 qc\_field\_status 没有 JSONB 的 meta 字段,建议巧妙利用现有的字段,或者要求 D6 引擎输出标准的 JSON string 到 actual\_value例如
// actual\_value 存储规范
{"days": 10, "direction": "late", "text": "延误10天"}
API 直接 JSON.parse(actual\_value) 即可安全获取 deviationDays。
### **💣 坑点 3D1 (筛选入选表) Inclusion/Exclusion 的身份识别**
**🔍 计划漏洞**
D1 API 的返回结构要求明确区分 type: 'inclusion' | 'exclusion',以便分别统计。但在我们现有的 qc\_field\_status 五层表中,并没有字段标识一条规则到底是纳入还是排除。
**🛠️ 修正建议 (后端映射)**
在执行 P0 Bugfix 时,连同将规则的子分类也传递下去。或者在项目的 IitSkill 配置中,规定 D1 规则的命名必须带有前缀例如INC-年龄校验EXC-妊娠状态。D1 的 API 通过解析 ruleName 的前缀来区分 inclusion 和 exclusion从而正确归类到前端表格中。
### **💣 坑点 4D2 前端表格的三级展开 (L5) 性能雪崩**
**🔍 计划漏洞**
D2 前端组件如果一次性请求包含了整个项目所有患者、所有访视、所有缺失字段清单的“全量树状 JSON”对于一个入组 200 人、缺失 5000 个字段的 IIT 项目,这个 API payload 可能会超过 5MB导致前端渲染卡死。
**🛠️ 修正建议 (前端与 API)**
采用**过度设计审查**L5具体字段清单不能随总览 API 一起返回。
* **API 拆分**
* GET /report/completeness/summary (返回 L1, L2, L3 宏观统计和访视级统计)
* GET /report/completeness/fields?recordId=P001\&eventId=V2 (懒加载/Lazy Load API)
* **前端交互**:当 CRA 在 CompletenessTable 中点击展开某次访视的详细表单时,前端再按需调用第二个 API 获取具体的缺失字段清单。
## **三、 对 LLM 友好的延伸设计 (架构红利)**
当前的计划主要聚焦在“传统业务报表(表格)”的渲染。既然您已经做好了这 4 个高质量的结构化 API千万不要浪费了它对大模型的巨大价值
**💡 建议补充任务:增强 Tab 0 (执行摘要) 的 LLM 总结能力**
在前端加载 ReportsPage.tsx 的 Tab 0 时:
1. 前端并行请求 D1, D2, D3, D6 的 4 个 API 的 **summary 部分**(不包含 entries 明细)。
2. 将这 4 个 JSON summary 拼成一个 Context 对象:
const llmContext \= { D1: d1.summary, D2: d2.summary, D3: d3.summary, D6: d6.summary };
3. 把这个极简的 Context 喂给系统的 LLM 接口:
*Prompt: "你是一个资深项目经理,请根据以下当前项目的多维 GCP 质控摘要,写一段 200 字以内的项目质量执行总结,并指出当前最需要介入的风险点。"*
4. 将 LLM 生成的这段话展示在 Tab 0 的最顶端。
**这就是真正的 AI 原生 SaaS**:不仅能提供冷冰冰的报表,还能直接基于结构化报表进行像人一样的洞察和汇报。
## **四、 审查最终结论**
这个开发计划的**粒度非常合适**,属于“刚刚好能落地且能商用”的级别。它没有去强求一次性做完所有的 AI 关联,而是优先把 GCP 需要的“表单底子”搭了出来。
只要在开发任务Jira/Todos中**补充上述 4 个避坑建议(特别是 D2 幽灵记录的生成机制)**,这份计划就可以直接发给开发团队启动 Sprint 了!