feat(aia): Complete AIA V2.0 with universal streaming capabilities

Major Changes:
- Add StreamingService with OpenAI Compatible format
- Upgrade Chat component V2 with Ant Design X integration
- Implement AIA module with 12 intelligent agents
- Update API routes to unified /api/v1 prefix
- Update system documentation

Backend (~1300 lines):
- common/streaming: OpenAI Compatible adapter
- modules/aia: 12 agents, conversation service, streaming integration
- Update route versions (RVW, PKB to v1)

Frontend (~3500 lines):
- modules/aia: AgentHub + ChatWorkspace (100% prototype restoration)
- shared/Chat: AIStreamChat, ThinkingBlock, useAIStream Hook
- Update API endpoints to v1

Documentation:
- AIA module status guide
- Universal capabilities catalog
- System overview updates
- All module documentation sync

Tested: Stream response verified, authentication working
Status: AIA V2.0 core completed (85%)
This commit is contained in:
2026-01-14 19:15:01 +08:00
parent 3d35e9c58b
commit 1b53ab9d52
386 changed files with 52096 additions and 65238 deletions

View File

@@ -1,69 +1,69 @@
# REDCap蟇ケ謗・謚€譛ッ譁ケ譯井ク主ョ樊命謖<E591BD>
**版本:** V1.0
**创建日期:** 2026-01-02
**适用阶段:** IIT Manager Agent MVP - Day 2
**文档性质:** 核心技术基石
**重要程度:** ⭐⭐⭐⭐⭐
**迚域悽<EFBFBD>?* V1.0
**蛻帛サコ譌・譛滂シ?* 2026-01-02
**騾ら畑髦カ谿オ<EFBFBD>?* IIT Manager Agent MVP - Day 2
**<EFBFBD>。」諤ァ雍ィ<EFBFBD>?* 譬ク蠢<EFBDB8>橿譛ッ蝓コ遏?
**驥崎ヲ∫ィ句コヲ<EFBFBD>?* 箝絶ュ絶ュ絶ュ絶ュ?
---
## <20>搭 譁<>。」逶ョ譬<EFBDAE>
本文档是IIT Manager Agent与REDCap集成的**权威技术指南**,明确:
1. REDCap对接方式的技术选型
2. Data Entry Trigger (DET) 的验证与配置
3. REST API的使用方法
4. ✅ 实时质控的完整架构
5. Day 2的开发实施步骤
譛ャ譁<EFBFBD>。」譏ッIIT Manager Agent荳山EDCap<EFBFBD><EFBFBD>逧?*譚<>ィ∵橿譛ッ謖<EFBDAF><E8AC96>?*<2A><EFBFBD>遑ョ<E98191><EFBDAE>
1. 笨?REDCap蟇ケ謗・譁ケ蠑冗噪謚€譛ッ騾牙梛
2. 笨?Data Entry Trigger (DET) <EFBFBD>ェ瑚ッ∽ク朱<EFBFBD>鄂ョ
3. 笨?REST API<EFBFBD>スソ逕ィ譁ケ豕?
4. 笨?螳樊慮雍ィ謗ァ逧<EFBDA7>ョ梧紛譫カ譫?
5. 笨?Day 2<EFBFBD>€蜿大ョ樊命豁・鬪?
---
## 🎯 核心结论Executive Summary
## <EFBFBD>識 譬ク蠢<EFBDB8>サ楢ョコ<EFBDAE><EFBDBA>xecutive Summary<EFBFBD>?
### ✅ **技术选型DET实时触发 + REST API数据读写**
### 笨?**謚€譛ッ騾牙梛<E78999>咼ET<45>亥ョ樊慮隗ヲ蜿托シ<E68998> + REST API<50>域焚謐ョ隸サ蜀呻シ<E591BB>**
**荳埼㊦逕ィ<E98095><EFBDA8>** External Module (EM)
**原因:** EM需要PHP开发、侵入REDCap源码、维护成本高、不适合外部系统集成
**蜴溷屏<EFBFBD>?* EM髴€隕 ̄HP蠑€蜿代€∽セオ蜈・REDCap貅千<E8B285>€∫サエ謚、謌先悽鬮倥€∽ク埼€ょ粋螟夜Κ邉サ扈滄寔謌<E5AF94>
**采用方案:**
**<EFBFBD>畑譁ケ譯茨シ?*
| 组件 | 技术 | 用途 | 实时性 |
| <EFBFBD>サカ | 謚€譛?| 逕ィ騾?| 螳樊慮諤?|
|------|-----|------|--------|
| **Data Entry Trigger** | REDCap原生功能 | 数据保存时实时通知 | 0秒延迟 |
| **Data Entry Trigger** | REDCap蜴溽函蜉溯<EFBFBD> | 謨ー謐ョ菫晏ュ俶慮螳樊慮騾夂衍 | 0遘貞サカ霑?|
| **REST API (Export)** | HTTP + JSON | 諡牙叙謨ー謐ョ縲∝<E7B8B2>謨ー謐ョ | 謖蛾怙隹<E68099>畑 |
| **REST API (Import)** | HTTP + JSON | 回写质控意见Phase 2 | 按需调用 |
| **REST API (Import)** | HTTP + JSON | 蝗槫<EFBFBD>雍ィ謗ァ諢剰ァ<EFBFBD><EFBFBD>hase 2<>?| 謖蛾怙隹<E68099> |
| **霓ョ隸「譛コ蛻カ** | pg-boss螳壽慮莉サ蜉。 | 陦・蜈<EFBDA5>ET驕玲シ乗焚謐ョ | 30蛻<30>帖 |
---
## 🔍 技术调研结果
## <EFBFBD>剥 謚€譛ッ隹<EFBDAF><E99AB9>皮サ捺<EFBDBB>?
### 调研1REDCap提供的对接方式
### <EFBFBD><EFBFBD><EFBFBD>1<EFBFBD>啌EDCap謠蝉セ帷噪蟇ケ謗・譁ケ蠑?
**调研来源:**
**<EFBFBD><EFBFBD>疲擂貅撰シ?*
- REDCap 15.8.0貅千<EFBFBD><EFBFBD>
- External Module Framework螳俶婿譁<E5A9BF>。」
- REDCap二次开发深度指南
- REDCap莠梧ャ。蠑€蜿第キア蠎ヲ謖<EFBFBD><EFBFBD>?
**蜿醍鴫逧<E9B4AB>ッケ謗・譁ケ蠑擾シ<E693BE>**
| 譁ケ蠑<EFBDB9> | 謚€譛ッ譬<EFBDAF> | 騾ら畑蝨コ譎ッ | 謌台サャ譏ッ蜷ヲ騾ら畑 |
|------|--------|---------|-------------|
| **External Module** | PHP + Hook | REDCap内部功能扩展、UI定制 | ❌ 不适用 |
| **REST API** | HTTP + JSON | 外部系统集成、数据同步 | ✅ **适用** |
| **Data Entry Trigger** | Webhook | 实时通知外部系统 | ✅ **适用** |
| **External Module** | PHP + Hook | REDCap<EFBFBD>Κ蜉溯<EFBFBD>謇ゥ螻輔€ゞI螳壼宛 | 笶?荳埼€ら畑 |
| **REST API** | HTTP + JSON | 螟夜Κ邉サ扈滄寔謌舌€∵焚謐ョ蜷梧ュ?| 笨?**騾ら畑** |
| **Data Entry Trigger** | Webhook | 螳樊慮騾夂衍螟夜Κ邉サ扈<EFBFBD> | 笨?**騾ら畑** |
### 隹<><E99AB9><EFBFBD>2<EFBFBD>咼ata Entry Trigger (DET) 鬪瑚ッ<E7919A>
**源码位置:**
**貅千<EFBFBD>∽ス咲スョ<EFBFBD>?*
```
/var/www/html/redcap/redcap_v15.8.0/Classes/DataEntry.php
/var/www/html/redcap/redcap_v15.8.0/ProjectSetup/index.php
/var/www/html/redcap/redcap_v15.8.0/ControlCenter/modules_settings.php
```
**关键代码:**
**蜈ウ髞ョ莉」遐<EFBFBD>シ?*
```php
// DataEntry.php 譬ク蠢<EFBDB8>ョ樒鴫
global $data_entry_trigger_url, $data_entry_trigger_enabled;
@@ -74,88 +74,88 @@ if (!$data_entry_trigger_enabled || $data_entry_trigger_url == '') {
$full_url = $pre_url . $data_entry_trigger_url;
```
**验证结论:**DETREDCap原生功能,真实存在且广泛使用
**鬪瑚ッ∫サ楢ョコ<EFBFBD>?* 笨?DET譏ッREDCap蜴溽函蜉溯<EFBFBD><EFBFBD>檎悄螳槫ュ伜惠荳泌ケソ豕帑スソ逕ィ
---
## 🏗️ 完整架构设计
## <EFBFBD><EFBFBD>?螳梧紛譫カ譫<EFBDB6>ョセ隶。
### 架构图
### 譫カ譫<EFBFBD><EFBFBD>?
```
┌─────────────────────────────────────────────────────┐
1. CRC REDCap 中保存记录
- 录入患者数据
- 点击"Save"按钮
└──────────────────┬──────────────────────────────────┘
↓ 立即触发REDCap DET0秒延迟
┌─────────────────────────────────────────────────────┐
2. REDCap Data Entry Trigger (DET)
POST https://iit.xunzhengyixue.com/
api/v1/iit/webhooks/redcap
Payload:
- project_id: 16
- record: 101
- instrument: demographics
- redcap_event_name: baseline_arm_1
└──────────────────┬──────────────────────────────────┘
↓ 1秒内
┌─────────────────────────────────────────────────────┐
3. Node.js Webhook接收器
- 验证请求来源(可选)
- 立即返回200 OK<100ms不阻塞REDCap
- 异步调用质控流程setImmediate
└──────────────────┬──────────────────────────────────┘
↓ 异步处理
┌─────────────────────────────────────────────────────┐
4. REDCap REST API - exportRecords
- 使用API Token认证
- 拉取指定record_id的完整数据
- 包含所有字段值、元数据
└──────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
5. 推送到质控队列
- jobQueue.send('iit:quality-check', record)
- 异步处理,不影响实时响应
└──────────────────┬──────────────────────────────────┘
↓ 由QualityCheckAgent处理Day 6
┌─────────────────────────────────────────────────────┐
6. AI质控分析
- 规则引擎验证
- AI推理检测异常
- 生成质控报告
└──────────────────┬──────────────────────────────────┘
3-5秒内
┌─────────────────────────────────────────────────────┐
7. 多渠道反馈
A. 企业微信推送给CRC实时通知
B. REDCap API importQueries(写回质疑)
C. IIT Manager前端显示(待办事项)
└─────────────────────────────────────────────────────┘
笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
笏? 1. CRC 蝨?REDCap 荳ュ菫晏ュ倩ョー蠖? 笏?
笏? - 蠖募<EFBFBD>謔」閠<EFBFBD>焚謐? 笏?
笏? - 轤ケ蜃サ"Save"謖蛾聴 笏?
笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
竊?遶句叉隗ヲ蜿托シ<E68998>EDCap DET<45>?遘貞サカ霑滂シ<E6BB82>
笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
笏? 2. REDCap Data Entry Trigger (DET) 笏?
笏? POST 竊?https://iit.xunzhengyixue.com/ 笏?
笏? api/v1/iit/webhooks/redcap 笏?
笏? Payload: 笏?
笏? - project_id: 16 笏?
笏? - record: 101 笏?
笏? - instrument: demographics 笏?
笏? - redcap_event_name: baseline_arm_1 笏?
笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
竊?1遘貞<E98198>
笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
笏? 3. Node.js Webhook謗・謾カ蝎? 笏?
笏? - 鬪瑚ッ∬ッキ豎よ擂貅撰シ亥庄騾会シ<EFBFBD> 笏?
笏? - 遶句叉霑泌屓200 OK<EFBFBD>?100ms<EFBFBD>御ク埼仆蝪朿EDCap<EFBFBD>? 笏?
笏? - 蠑よュ・隹<EFBFBD>畑雍ィ謗ァ豬∫ィ具シ<EFBFBD>etImmediate<EFBFBD>? 笏?
笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
竊?蠑よュ・螟<EFBDA5>
笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
笏? 4. REDCap REST API - exportRecords 笏?
笏? - 菴ソ逕ィAPI Token隶、隸<EFBFBD> 笏?
笏? - 諡牙叙謖<EFBFBD>ョ嗷ecord_id<EFBFBD>ョ梧紛謨ー謐? 笏?
笏? - <EFBFBD>性謇€譛牙ュ玲ョオ蛟シ縲∝<EFBFBD>謨ー謐ョ 笏?
笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
竊?
笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
笏? 5. 謗ィ騾∝芦雍ィ謗ァ髦溷<EFBFBD> 笏?
笏? - jobQueue.send('iit:quality-check', record) 笏?
笏? - 蠑よュ・螟<EFBFBD><EFBFBD>御ク榊スア蜩榊ョ樊慮蜩榊コ<EFBFBD> 笏?
笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
竊?逕アQualityCheckAgent<EFBFBD><EFBFBD><EFBFBD>ay 6<EFBFBD>?
笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
笏? 6. AI雍ィ謗ァ蛻<EFBFBD> 笏?
笏? - <EFBFBD><EFBFBD>蠑墓梼鬪瑚ッ<EFBFBD> 笏?
笏? - AI謗ィ逅<EFBFBD>€豬句シょク? 笏?
笏? - 逕滓<EFBFBD>雍ィ謗ァ謚・蜻<EFBFBD> 笏?
笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏ャ笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
竊?3-5遘貞<EFBFBD>
笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
笏? 7. 螟壽ク<EFBFBD>驕灘渚鬥? 笏?
笏? A. 莨∽ク壼セョ菫。謗ィ騾∫サ僂RC<EFBFBD>亥ョ樊慮騾夂衍<EFBFBD>? 笏?
笏? B. REDCap API importQueries<EFBFBD><EFBFBD>蝗櫁エィ逍托シ<EFBFBD> 笏?
笏? C. IIT Manager蜑咲ォッ譏セ遉コ<EFBFBD>亥セ<EFBFBD>萱莠矩。ケ<EFBFBD><EFBFBD> 笏?
笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
┌─────────────────────────────────────────────────────┐
│ 补充定时轮询机制每30分钟
- 防止DET遗漏数据
- 使用dateRangeBegin增量拉取
- 推送到相同的质控队列
└─────────────────────────────────────────────────────┘
笏娯楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
笏? 陦・蜈<EFBDA5>シ壼ョ壽慮霓ョ隸「譛コ蛻カ<E89BBB>域ッ?0蛻<30><EFBFBD>? 笏?
笏? - 髦イ豁「DET驕玲シ乗焚謐ョ 笏?
笏? - 菴ソ逕ィdateRangeBegin蠅樣㍼諡牙叙 笏?
笏? - 謗ィ騾∝芦逶ク蜷檎噪雍ィ謗ァ髦溷<EFBFBD>? 笏?
笏披楳笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏€笏?
```
### 实时性对比
### 螳樊慮諤ァ蟇ケ豈?
| 譁ケ譯<EFBDB9> | 蟒カ霑滓慮髣エ | 謌台サャ逧<EFBDAC>€画叫 |
|------|---------|-----------|
| **纯轮询每5分钟** | 最高5分钟 | ❌ 不满足实时性要求 |
| **纯轮询每1分钟** | 最高1分钟 | ⚠️ 资源浪费、延迟仍高 |
| **DET + API** | 0秒触发 + 3-5秒处理 | ✅ **最优方案** |
| **DET + 轮询补充** | 实时 + 可靠 | ✅ **最终架构** |
| **郤ッ霓ョ隸「<EFBFBD>域ッ?蛻<><EFBFBD>?* | 譛€鬮?蛻<>帖 | 笶?荳肴サ。雜ウ螳樊慮諤ァ隕∵ア?|
| **郤ッ霓ョ隸「<EFBFBD>域ッ?蛻<><EFBFBD>?* | 譛€鬮?蛻<>帖 | 笞<><E7AC9E><EFBFBD><>コ先オェ雍ケ縲∝サカ霑滉サ埼ォ?|
| **DET + API** | 0遘定ァヲ蜿?+ 3-5遘貞、<E8B29E><EFBDA4>?| 笨?**譛€莨俶婿譯?* |
| **DET + 霓ョ隸「陦・蜈<EFBFBD>** | 螳樊慮 + 蜿ッ髱<EFBDAF> | 笨?**譛€扈域楔譫?* |
**结论:** CRC点击"保存" → 5秒内收到企业微信通知 ✅
**扈楢ョコ<EFBFBD>?* CRC轤ケ蜃サ"菫晏ュ<E6998F>" 竊?5遘貞<E98198>謾カ蛻ー莨∽ク壼セョ菫。騾夂衍 笨?
---
## 📦 技术实现详解
## <EFBFBD>逃 謚€譛ッ螳樒鴫隸ヲ隗?
### 1. Data Entry Trigger (DET) 驟咲スョ
@@ -163,9 +163,9 @@ $full_url = $pre_url . $data_entry_trigger_url;
```
1. 逋サ蠖紐EDCap<61>喇ttp://localhost:8080/
2. 使用管理员账户Admin / Admin123!
3. 进入Control Center "Additional Customizations"
4. 找到:"Data Entry Trigger" 选项
2. 菴ソ逕ィ邂。逅<EFBFBD>遭雍ヲ謌キ<EFBFBD><EFBFBD>dmin / Admin123!<EFBFBD>?
3. 霑帛<EFBFBD><EFBFBD>ontrol Center 竊?"Additional Customizations"
4. 謇セ蛻ー<EFBFBD>?Data Entry Trigger" 騾蛾。ケ
5. 隶セ鄂ョ荳コ<E88DB3><EFBDBA>"Enabled"
6. 菫晏ュ倬<EFBDAD>鄂ョ
```
@@ -176,10 +176,10 @@ $full_url = $pre_url . $data_entry_trigger_url;
```
1. 霑帛<E99C91>豬玖ッ暮。ケ逶ョ<E980B6>嗾est0102 (PID 16)
2. 左侧菜单 → Project Setup
3. 找到:"Additional Customizations"
4. 展开:"Data Entry Trigger URL"
5. 填入Webhook URL
2. 蟾ヲ萓ァ闖懷黒 竊?Project Setup
3. 謇セ蛻ー<EFBFBD>?Additional Customizations"
4. 螻募シ€<EFBFBD>?Data Entry Trigger URL"
5. 蝪ォ蜈・Webhook URL<EFBFBD>?
- 蠑€蜿醍識蠅<E8AD98>シ喇ttp://localhost:3001/api/v1/iit/webhooks/redcap
- 豬玖ッ慕識蠅<E8AD98>シ喇ttps://backend-dev.xunzhengyixue.com/api/v1/iit/webhooks/redcap
- 逕滉コァ邇ッ蠅<EFBDAF>シ喇ttps://iit.xunzhengyixue.com/api/v1/iit/webhooks/redcap
@@ -190,22 +190,22 @@ $full_url = $pre_url . $data_entry_trigger_url;
#### 豁・鬪、3<EFBDA4>夐ェ瑚ッET驟咲スョ
**使用RequestBin/ngrok验证:**
**菴ソ逕ィRequestBin/ngrok鬪瑚ッ<EFBFBD>シ?*
```bash
# 使用ngrok创建临时公网URL开发测试用
# 菴ソ逕ィngrok蛻帛サコ荳エ譌カ蜈ャ鄂繕RL<EFBFBD>亥シ€蜿第オ玖ッ慕畑<EFBFBD>?
ngrok http 3001
# 蟆<>grok URL驟咲スョ蛻ーREDCap DET
# 萓句ヲゑシ喇ttps://1234-abc-def.ngrok.io/api/v1/iit/webhooks/redcap
# REDCap中保存一条记录
# 蝨ィREDCap荳ュ菫晏ュ倅ク€譚。隶ー蠖?
# 譽€譟・ngrok謗ァ蛻カ蜿ー譏ッ蜷ヲ謾カ蛻ーPOST隸キ豎<EFBDB7>
```
#### DET逧ПOST Payload譬シ蠑<EFBDBC>
**REDCap发送的请求:**
**REDCap蜿鷹€∫噪隸キ豎ゑシ?*
```http
POST /api/v1/iit/webhooks/redcap HTTP/1.1
@@ -221,7 +221,7 @@ project_id=16
&redcap_url=http://localhost:8080/
```
**字段说明:**
**蟄玲ョオ隸エ譏趣シ?*
| 蟄玲ョオ | 邀サ蝙<EFBDBB> | 隸エ譏<EFBDB4> | 遉コ萓<EFBDBA> |
|------|-----|------|------|
@@ -229,7 +229,7 @@ project_id=16
| `record` | string | 隶ー蠖肘D | "101" |
| `instrument` | string | 陦ィ蜊募錐遘ー | "demographics" |
| `redcap_event_name` | string | 莠倶サカ蜷咲ァー<EFBDA7>育コオ蜷醍<E89CB7>皮ゥカ<EFBDA9><EFBDB6> | "baseline_arm_1" |
| `[instrument]_complete` | string | 表单完成状态(0/1/2 | "2" |
| `[instrument]_complete` | string | 陦ィ蜊募ョ梧<EFBFBD>迥カ諤<EFBFBD><EFBFBD>0/1/2<EFBFBD>?| "2" |
| `redcap_url` | string | REDCap螳樔セ偽RL | "http://localhost:8080/" |
---
@@ -244,23 +244,23 @@ http://localhost:8080/api/
#### API隶、隸<EFBDA4>シ啜oken
**生成步骤:**
**逕滓<EFBFBD>豁・鬪、<EFBFBD>?*
```
1. 逋サ蠖紐EDCap
2. 霑帛<E99C91>鬘ケ逶ョ<E980B6>嗾est0102 (PID 16)
3. 左侧菜单 → "API"
3. 蟾ヲ萓ァ闖懷黒 竊?"API"
4. 轤ケ蜃サ "Generate API Token"
5. 复制Token32位字符串
5. 螟榊宛Token<EFBFBD>?2菴榊ュ礼ャヲ荳イ<E88DB3>?
6. 菫晏ュ伜芦邇ッ蠅<EFBDAF>序驥擾シ<E693BE>
REDCAP_API_TOKEN_TEST=YOUR_TOKEN_HERE
```
**Token存储:**
- ✅ 环境变量(推荐)
- ✅ 数据库加密字段IitProject.redcapApiToken
- ❌ 不要提交到Git
**Token蟄伜お<EFBFBD>?*
- 笨?邇ッ蠅<EFBDAF>序驥擾シ域耳闕撰シ<E692B0>
- 笨?謨ー謐ョ蠎灘刈蟇<E58888>ュ玲ョオ<EFBDAE><EFBDB5>itProject.redcapApiToken<EFBFBD>?
- 笶?荳崎ヲ∵署莠、蛻ーGit
#### API方法1导出记录 (exportRecords)
#### API譁ケ豕<EFBFBD>1<EFBFBD>壼ッシ蜃コ隶ー蠖?(exportRecords)
**逕ィ騾費シ<E8B2BB>** 諡牙叙謨ー謐ョ<E8AC90>域髪謖∝「樣㍼蜷梧ュ・<EFBDAD><EFBDA5>
@@ -277,28 +277,28 @@ curl -X POST http://localhost:8080/api/ \
-F "dateRangeBegin=2026-01-01 00:00:00"
```
**参数说明:**
**蜿よ焚隸エ譏趣シ?*
| 蜿よ焚 | 蠢<>。ォ | 隸エ譏<EFBDB4> | 遉コ萓<EFBDBA> |
|------|-----|------|------|
| `token` | | API Token | "ABC123..." |
| `content` | ✅ | 固定值 | "record" |
| `format` | ✅ | 返回格式 | "json" |
| `type` | ✅ | 数据结构 | "flat" |
| `records` | ❌ | 指定记录ID | ["101", "102"] |
| `fields` | ❌ | 指定字段 | ["age", "gender"] |
| `dateRangeBegin` | ❌ | 时间过滤(增量同步关键) | "2026-01-01 00:00:00" |
| `dateRangeEnd` | ❌ | 结束时间 | "2026-01-31 23:59:59" |
| `token` | 笨?| API Token | "ABC123..." |
| `content` | 笨?| 蝗コ螳壼€?| "record" |
| `format` | 笨?| 霑泌屓譬シ蠑<EFBDBC> | "json" |
| `type` | 笨?| 謨ー謐ョ扈捺桷 | "flat" |
| `records` | 笶?| 謖<>ョ夊ョー蠖肘D | ["101", "102"] |
| `fields` | 笶?| 謖<>ョ壼ュ玲ョオ | ["age", "gender"] |
| `dateRangeBegin` | 笶?| 譌カ髣エ霑<EFBDB4>サ、<EFBDBB>亥「樣㍼蜷梧ュ・蜈ウ髞ョ<E9AB9E><EFBDAE> | "2026-01-01 00:00:00" |
| `dateRangeEnd` | 笶?| 扈捺據譌カ髣エ | "2026-01-31 23:59:59" |
**响应示例:**
**蜩榊コ皮、コ萓具シ?*
```json
[
{
"record_id": "101",
"redcap_event_name": "baseline_arm_1",
"first_name": "张",
"last_name": "三",
"first_name": "蠑?,
"last_name": "?,
"age": "30",
"gender": "1",
"demographics_complete": "2"
@@ -308,9 +308,9 @@ curl -X POST http://localhost:8080/api/ \
#### API譁ケ豕<EFBDB9>2<EFBFBD>壼ッシ蜃コ蜈<EFBDBA>焚謐ョ (exportMetadata)
**用途:** 获取字段定义、表单结构
**逕ィ騾費シ<EFBFBD>** 闔キ蜿門ュ玲ョオ螳壻ケ峨€∬。ィ蜊慕サ捺<EFBDBB>?
**请求示例:**
**隸キ豎ら、コ萓具シ?*
```bash
curl -X POST http://localhost:8080/api/ \
@@ -319,7 +319,7 @@ curl -X POST http://localhost:8080/api/ \
-F "format=json"
```
**响应示例:**
**蜩榊コ皮、コ萓具シ?*
```json
[
@@ -346,11 +346,11 @@ curl -X POST http://localhost:8080/api/ \
]
```
#### API方法3导入记录 (importRecords) - Phase 2
#### API譁ケ豕<EFBFBD>3<EFBFBD>壼ッシ蜈・隶ー蠖?(importRecords) - Phase 2
**用途:** 回写数据如质控意见、AI建议
**逕ィ騾費シ<EFBFBD>** 蝗槫<E89D97>謨ー謐ョ<E8AC90>亥ヲりエィ謗ァ諢剰ァ√€、I蟒コ隶ョ<E99AB6>?
**请求示例:**
**隸キ豎ら、コ萓具シ?*
```bash
curl -X POST http://localhost:8080/api/ \
@@ -368,7 +368,7 @@ curl -X POST http://localhost:8080/api/ \
#### 3.1 RedcapAdapter<65><72>PI騾る<E9A8BE>蝎ィ<E89D8E><EFBDA8>
**文件:** `backend/src/modules/iit-manager/adapters/RedcapAdapter.ts`
**<EFBFBD>サカ<EFBFBD>?* `backend/src/modules/iit-manager/adapters/RedcapAdapter.ts`
```typescript
import axios from 'axios';
@@ -452,7 +452,7 @@ export class RedcapAdapter {
}
/**
* 导出元数据(字段定义)
* 蟇シ蜃コ蜈<EFBFBD>焚謐ョ<EFBFBD>亥ュ玲ョオ螳壻ケ会シ?
*/
async exportMetadata(): Promise<any[]> {
const formData = new FormData();
@@ -523,7 +523,7 @@ export class RedcapAdapter {
#### 3.2 WebhookController<65><72>ebhook謗・謾カ蝎ィ<E89D8E><EFBDA8>
**文件:** `backend/src/modules/iit-manager/controllers/webhookController.ts`
**<EFBFBD>サカ<EFBFBD>?* `backend/src/modules/iit-manager/controllers/webhookController.ts`
```typescript
import { FastifyRequest, FastifyReply } from 'fastify';
@@ -536,7 +536,7 @@ export class WebhookController {
/**
* 謗・謾カREDCap Data Entry Trigger Webhook
*
* 性能要求:响应时间 < 100ms不阻塞REDCap
* 諤ァ閭ス隕∵アゑシ壼桃蠎疲慮髣?< 100ms<6D>井ク埼仆蝪朿EDCap<EFBFBD>?
*/
async handleRedcapWebhook(
request: FastifyRequest,
@@ -569,7 +569,7 @@ export class WebhookController {
event: redcap_event_name
});
// 立即返回200不阻塞REDCap
// 遶句叉霑泌屓200<EFBFBD>井ク埼仆蝪朿EDCap<EFBFBD>?
const responseTime = Date.now() - startTime;
reply.code(200).send({
status: 'received',
@@ -577,7 +577,7 @@ export class WebhookController {
response_time_ms: responseTime
});
// 异步处理不阻塞HTTP响应
// 蠑よュ・螟<EFBFBD><EFBFBD>井ク埼仆蝪曰TTP蜩榊コ費シ?
setImmediate(async () => {
try {
await this.processWebhook({
@@ -589,7 +589,7 @@ export class WebhookController {
});
} catch (error) {
logger.error('Webhook processing failed:', error);
// 不抛出错误,因为已经返回200
// 荳肴鴨蜃コ髞呵ッッ<EFBFBD>悟屏荳コ蟾イ扈剰ソ泌屓200莠?
}
});
}
@@ -616,7 +616,7 @@ export class WebhookController {
return;
}
// 2. 幂等性检查(防止重复处理)
// 2. 蟷らュ画€ァ譽€譟・<EFBFBD>磯亟豁「驥榊、榊、<EFBFBD><EFBFBD>?
const isDuplicate = await this.checkDuplicate(
project.id,
record,
@@ -635,7 +635,7 @@ export class WebhookController {
);
const records = await adapter.exportRecords({
records: [record] // 只拉取这一条记录
records: [record] // 蜿ェ諡牙叙霑吩ク€譚。隶ー蠖?
});
if (records.length === 0) {
@@ -699,7 +699,7 @@ export class WebhookController {
#### 3.3 SyncManager<65>郁スョ隸「陦・蜈<EFBDA5><EFBFBD>
**文件:** `backend/src/modules/iit-manager/services/SyncManager.ts`
**<EFBFBD>サカ<EFBFBD>?* `backend/src/modules/iit-manager/services/SyncManager.ts`
```typescript
import { prisma } from '@/config/database';
@@ -709,10 +709,10 @@ import { RedcapAdapter } from '../adapters/RedcapAdapter';
export class SyncManager {
/**
* 初始化同步(注册定时任务)
* 蛻晏ァ句喧蜷梧ュ・<EFBFBD>域ウィ蜀悟ョ壽慮莉サ蜉。<EFBFBD>?
*/
async initializeSync(projectId: string, interval: string = '*/30 * * * *'): Promise<void> {
// 注册定时任务每30分钟
// 豕ィ蜀悟ョ壽慮莉サ蜉。<EFBFBD>域ッ<EFBFBD>30蛻<EFBFBD><EFBFBD>?
await jobQueue.schedule(
'iit:redcap:poll',
interval,
@@ -783,7 +783,7 @@ export class SyncManager {
* 蛛懈ュ「蜷梧ュ・<EFBDAD>亥叙豸亥ョ壽慮莉サ蜉。<E89C89><EFBDA1>
*/
async stopSync(projectId: string): Promise<void> {
// pg-boss不支持直接取消schedule需要在Worker中检查项目状态
// pg-boss荳肴髪謖∫峩謗・蜿匁カ<EFBFBD>chedule<EFBFBD>碁怙隕∝惠Worker荳ュ譽€譟・鬘ケ逶ョ迥カ諤?
logger.info(`Sync stopped for project ${projectId}`);
}
}
@@ -791,7 +791,7 @@ export class SyncManager {
#### 3.4 霍ッ逕ア驟咲スョ
**文件:** `backend/src/modules/iit-manager/routes/index.ts`
**<EFBFBD>サカ<EFBFBD>?* `backend/src/modules/iit-manager/routes/index.ts`
```typescript
import { FastifyInstance } from 'fastify';
@@ -802,12 +802,12 @@ export async function iitManagerRoutes(fastify: FastifyInstance) {
const webhookController = new WebhookController();
const syncManager = new SyncManager();
// Webhook端点(接收REDCap DET
// Webhook遶ッ轤ケ<EFBFBD>域磁謾カREDCap DET<EFBFBD>?
fastify.post('/webhooks/redcap', async (request, reply) => {
return webhookController.handleRedcapWebhook(request, reply);
});
// 手动触发同步(测试用)
// 謇句勘隗ヲ蜿大酔豁・<EFBFBD>域オ玖ッ慕畑<EFBFBD>?
fastify.post('/projects/:id/sync', async (request, reply) => {
const { id } = request.params as { id: string };
await syncManager.handlePoll(id);
@@ -818,7 +818,7 @@ export async function iitManagerRoutes(fastify: FastifyInstance) {
#### 3.5 Worker豕ィ蜀<EFBDA8>
**文件:** `backend/src/modules/iit-manager/index.ts`
**<EFBFBD>サカ<EFBFBD>?* `backend/src/modules/iit-manager/index.ts`
```typescript
import { jobQueue } from '@/common/jobs';
@@ -844,19 +844,19 @@ export async function initializeIITManager() {
### 豬玖ッ<E78E96>1<EFBFBD>夐ェ瑚ッET驟咲スョ
**步骤:**
**豁・鬪、<EFBFBD>?*
1. 驟咲スョngrok<6F>啻ngrok http 3001`
2.<>grok URL驟咲スョ蛻ーREDCap DET
3. REDCap中保存一条记录
3. 蝨ィREDCap荳ュ菫晏ュ倅ク€譚。隶ー蠖?
4.€譟・ngrok謗ァ蛻カ蜿ー譏ッ蜷ヲ謾カ蛻ーPOST隸キ豎<EFBDB7>
**预期结果:**
- ngrok收到POST请求
- Payload包含project_id、record等字段
**<EFBFBD>悄扈捺棡<EFBFBD>?*
- 笨?ngrok謾カ蛻ーPOST隸キ豎<EFBFBD>
- 笨?Payload<EFBFBD>project_id縲〉ecord遲牙ュ玲ョ?
### 豬玖ッ<E78E96>2<EFBFBD>夐ェ瑚ッ、PI Token
**测试脚本:** `test-redcap-api.ts`
**豬玖ッ戊<EFBFBD>譛ャ<EFBFBD>?* `test-redcap-api.ts`
```typescript
import { RedcapAdapter } from './adapters/RedcapAdapter';
@@ -871,11 +871,11 @@ async function testRedcapAPI() {
const records = await adapter.exportRecords();
console.log('Records:', records);
// 测试导出元数据
// 豬玖ッ募ッシ蜃コ蜈<EFBFBD>焚謐?
const metadata = await adapter.exportMetadata();
console.log('Metadata fields:', metadata.length);
console.log('REDCap API test passed!');
console.log('笨?REDCap API test passed!');
}
testRedcapAPI();
@@ -883,7 +883,7 @@ testRedcapAPI();
### 豬玖ッ<E78E96>3<EFBFBD>夂ォッ蛻ー遶ッ髮<EFBDAF><E9ABAE>豬玖ッ<E78E96>
**测试脚本:** `test-redcap-integration.ts`
**豬玖ッ戊<EFBFBD>譛ャ<EFBFBD>?* `test-redcap-integration.ts`
```typescript
async function testIntegration() {
@@ -898,11 +898,11 @@ async function testIntegration() {
}
});
// 2. 初始化同步
// 2. 蛻晏ァ句喧蜷梧ュ?
const syncManager = new SyncManager();
await syncManager.initializeSync(project.id);
// 3. 手动触发一次轮询
// 3. 謇句勘隗ヲ蜿台ク€谺。霓ョ隸?
await syncManager.handlePoll(project.id);
// 4. 讓。諡欷ebhook
@@ -918,7 +918,7 @@ async function testIntegration() {
{} as any
);
console.log('Integration test passed!');
console.log('笨?Integration test passed!');
}
```
@@ -926,18 +926,18 @@ async function testIntegration() {
## <20>搭 Day 2螳樊命貂<E591BD>
### 阶段1环境准备30分钟
### 髦カ谿オ1<EFBFBD>夂識蠅<EFBFBD>㊥螟<EFBFBD><EFBFBD>30蛻<EFBFBD><EFBFBD>?
- [ ] 蝨ィREDCap Control Center蜷ッ逕ィDET蜉溯<E89C89>
- [ ] 蝨ィtest0102鬘ケ逶ョ逕滓<E98095>API Token
- [ ] 配置环境变量:
- [ ] 驟咲スョ邇ッ蠅<EFBFBD>序驥擾シ?
```env
REDCAP_BASE_URL=http://localhost:8080
REDCAP_API_TOKEN_TEST=YOUR_TOKEN_HERE
```
- [ ] 菴ソ逕ィcurl豬玖ッ柊PI譏ッ蜷ヲ蜿ッ逕ィ
### 阶段2开发RedcapAdapter1.5小时)
### 髦カ谿オ2<EFBFBD>壼シ€蜿然edcapAdapter<EFBFBD>?.5蟆乗慮<EFBFBD>?
- [ ] 蛻帛サコ譁<EFBDBA>サカ<EFBDBB>啻adapters/RedcapAdapter.ts`
- [ ] 螳樒鴫 `exportRecords()` 譁ケ豕<EFBDB9>
@@ -945,15 +945,15 @@ async function testIntegration() {
- [ ] 螳樒鴫 `formatRedcapDate()` 蟾・蜈キ譁ケ豕<EFBDB9>
- [ ] 郛門<E9839B>蜊募<E89C8A>豬玖ッ包シ啻RedcapAdapter.test.ts`
### 阶段3开发WebhookController2小时
### 髦カ谿オ3<EFBFBD>壼シ€蜿糎ebhookController<EFBFBD>?蟆乗慮<E4B997>?
- [ ] 蛻帛サコ譁<EFBDBA>サカ<EFBDBB>啻controllers/webhookController.ts`
- [ ] 螳樒鴫 `handleRedcapWebhook()` 譁ケ豕<EFBDB9>
- [ ] 螳樒鴫 `processWebhook()` 遘∵怏譁ケ豕<EFBDB9>
- [ ] 实现 `checkDuplicate()` 幂等性检查
- [ ] 螳樒鴫 `checkDuplicate()` 蟷らュ画€ァ譽€譟?
- [ ] 驟咲スョ霍ッ逕ア<E98095>啻POST /api/v1/iit/webhooks/redcap`
### 阶段4开发SyncManager1.5小时)
### 髦カ谿オ4<EFBFBD>壼シ€蜿全yncManager<EFBFBD>?.5蟆乗慮<EFBFBD>?
- [ ] 蛻帛サコ譁<EFBDBA>サカ<EFBDBB>啻services/SyncManager.ts`
- [ ] 螳樒鴫 `initializeSync()` 譁ケ豕<EFBDB9>
@@ -961,19 +961,19 @@ async function testIntegration() {
- [ ] 螳樒鴫 `stopSync()` 譁ケ豕<EFBDB9>
- [ ] 豕ィ蜀係orker<65>啻iit:redcap:poll`
### 阶段5集成测试1小时
### 髦カ谿オ5<EFBFBD>夐寔謌先オ玖ッ包シ<EFBFBD>1蟆乗慮<EFBFBD>?
- [ ] 驟咲スョngrok/RequestBin豬玖ッ疋ET
- [ ] 霑占。<E58DA0> `test-redcap-api.ts`
- [ ] 霑占。<E58DA0> `test-redcap-integration.ts`
- [ ] 验证端到端流程
- [ ] 鬪瑚ッ∫ォッ蛻ー遶ッ豬∫ィ?
- [ ] 隶ー蠖墓オ玖ッ慕サ捺棡
### 阶段6文档更新30分钟
### 髦カ谿オ6<EFBFBD>壽枚譯」譖エ譁ー<EFBFBD><EFBFBD>30蛻<EFBFBD><EFBFBD>?
- [ ] 更新MVP开发任务清单Day 2完成
- [ ] 记录API Token和配置信息
- [ ] 更新架构图
- [ ] 譖エ譁ーMVP蠑€蜿台ササ蜉。貂<EFBDA1><EFBFBD><E9BB92>ay 2螳梧<E89EB3><E6A2A7>?
- [ ] 隶ー蠖柊PI Token蜥碁<EFBFBD>鄂ョ菫。諱?
- [ ] 譖エ譁ー譫カ譫<EFBDB6><E8ADAB>?
- [ ] 謠蝉コ、Git
---
@@ -982,48 +982,48 @@ async function testIntegration() {
### 1. DET驟咲スョ隕∫せ
**常见错误:**
- ❌ 忘记在Control Center启用DET全局开关
- ❌ Webhook URL填写错误(多了斜杠、少了路径)
- ❌ 本地开发环境无法接收外网Webhook
**蟶ク隗<EFBFBD>漠隸ッ<EFBFBD>?*
- 笶?蠢倩ョー蝨ィControl Center蜷ッ逕ィDET蜈ィ螻€€蜈?
- 笶?Webhook URL蝪ォ蜀咎漠隸ッ<EFBFBD>亥、壻コ<EFBFBD>万譚<EFBFBD>縲∝ー台コ<EFBFBD>キッ蠕<EFBFBD><EFBFBD>
- 笶?譛ャ蝨ー蠑€蜿醍識蠅<E8AD98>裏豕墓磁謾カ螟也ス糎ebhook
**解决方案:**
- ✅ 使用ngrok创建临时公网URL测试
- ✅ 开发环境可先用RequestBin验证Payload格式
- ✅ 生产环境确保URL可访问防火墙、HTTPS
**隗」蜀ウ譁ケ譯茨シ?*
- 笨?菴ソ逕ィngrok蛻帛サコ荳エ譌カ蜈ャ鄂繕RL豬玖ッ<E78E96>
- 笨?蠑€蜿醍識蠅<E8AD98>庄蜈育畑RequestBin鬪瑚ッ ̄ayload譬シ蠑<EFBFBD>
- 笨?逕滉コァ邇ッ蠅<EFBDAF>。ョ菫拔RL蜿ッ隶ソ髣ョ<E9ABA3>磯亟轣ォ蠅吶€TTPS<EFBFBD>?
### 2. API Token螳牙<E89EB3>
**安全实践:**
- ✅ 存储在环境变量或数据库加密字段
- ✅ 定期轮换Token
- ✅ 最小权限原则(只开启需要的权限)
- ❌ 不要提交到Git
- ❌ 不要在日志中打印完整Token
**螳牙<EFBFBD>螳櫁キオ<EFBFBD>?*
- 笨?蟄伜お蝨ィ邇ッ蠅<EFBDAF>序驥乗<E9A9A5>謨ー謐ョ蠎灘刈蟇<E58888>ュ玲ョ?
- 笨?螳壽悄霓ョ謐「Token
- 笨?譛€蟆乗揀髯仙次蛻呻シ亥宵蠑€蜷ッ髴€隕∫噪譚<E599AA><EFBFBD>?
- 笶?荳崎ヲ∵署莠、蛻ーGit
- 笶?荳崎ヲ∝惠譌・蠢嶺クュ謇灘魂螳梧紛Token
### 3. 諤ァ閭ス莨伜喧
**Webhook响应时间:**
- ✅ 必须 < 100ms立即返回200
- ✅ 使用 `setImmediate()` 异步处理
- ❌ 不要在Webhook中执行耗时操作
**Webhook蜩榊コ疲慮髣エ<EFBFBD>?*
- 笨?蠢<>。サ < 100ms<6D>育ォ句叉霑泌<E99C91>?00<30>?
- 笨?菴ソ逕ィ `setImmediate()` 蠑よュ・螟<EFBDA5>
- 笶?荳崎ヲ∝惠Webhook荳ュ謇ァ陦瑚€玲慮謫堺ス<E5A0BA>
**API调用频率:**
- ✅ 增量拉取(使用dateRangeBegin
- ✅ 指定字段(减少数据量)
- ✅ 合理设置timeout30秒
**API<EFBFBD>畑鬚醍紫<EFBFBD>?*
- 笨?蠅樣㍼諡牙叙<E78999>井スソ逕ィdateRangeBegin<EFBFBD>?
- 笨?謖<>ョ壼ュ玲ョオ<EFBDAE>亥㍼蟆第焚謐ョ驥擾シ?
- 笨?蜷育炊隶セ鄂ョtimeout<75>?0遘抵シ<E68AB5>
### 4. 髞呵ッッ螟<EFBDAF>
**DET Webhook失败:**
- REDCap会重试3次间隔1分钟
**DET Webhook螟ア雍・<EFBFBD>?*
- REDCap莨夐㍾隸?谺。<E8B0BA>磯龍髫<E9BE8D>1蛻<31><EFBFBD>?
- 螯よ棡莉榊、ア雍・<E99B8D>軍EDCap莨夊ョー蠖募芦譌・蠢<EFBDA5>
- 謌台サャ逧<EFBDAC>スョ隸「譛コ蛻カ蜿ッ莉・陦・蜈<EFBDA5>貍冗噪謨ー謐ョ
**API调用失败:**
- 实现重试机制3次指数退避
**API<EFBFBD>畑螟ア雍・<EFBFBD>?*
- 螳樒鴫驥崎ッ墓惻蛻カ<E89BBB>?谺。<E8B0BA>梧欠謨ー騾€驕ソ<E9A995><EFBDBF>
- 隶ー蠖募、ア雍・譌・蠢<EFBDA5>
- 告警通知管理员
- 蜻願ュヲ騾夂衍邂。逅<EFBDA1><E98085>?
---
@@ -1031,41 +1031,42 @@ async function testIntegration() {
### Day 2螳梧<E89EB3><EFBFBD>
- [ ]REDCap API Token已生成并验证
- [ ]RedcapAdapter可以拉取测试数据
- [ ] ✅ DET已配置并成功接收Webhook
- [ ]Webhook可以触发API拉取
- [ ] ✅ 轮询机制可以定时运行
- [ ] ✅ 数据推送到质控队列
- [ ] ✅ 单元测试全部通过
- [ ] ✅ 端到端集成测试通过
- [ ] 笨?REDCap API Token蟾イ逕滓<EFBFBD>蟷カ鬪瑚ッ<EFBFBD>
- [ ] 笨?RedcapAdapter蜿ッ莉・諡牙叙豬玖ッ墓焚謐ョ
- [ ] 笨?DET蟾イ驟咲スョ蟷カ謌仙粥謗・謾カWebhook
- [ ] 笨?Webhook蜿ッ莉・隗ヲ蜿羨PI諡牙叙
- [ ] 笨?霓ョ隸「譛コ蛻カ蜿ッ莉・螳壽慮霑占。<E58DA0>
- [ ] 笨?謨ー謐ョ謗ィ騾∝芦雍ィ謗ァ髦溷<E9ABA6>
- [ ] 笨?蜊募<E89C8A>豬玖ッ募<EFBDAF>驛ィ騾夊ソ<E5A48A>
- [ ] 笨?遶ッ蛻ー遶ッ髮<EFBDAF><E9ABAE>豬玖ッ暮€夊ソ<E5A48A>
### 諤ァ閭ス謖<EFBDBD><E8AC96><EFBFBD>
- [ ] Webhook蜩榊コ疲慮髣エ < 100ms
- [ ] API调用成功率 > 99%
- [ ] 端到端延迟 < 5秒DET触发 → 企微通知)
- [ ] API<EFBFBD>畑謌仙粥邇?> 99%
- [ ] 遶ッ蛻ー遶ッ蟒カ霑?< 5遘抵シ<E68AB5>ET隗ヲ蜿<EFBDA6> 竊?莨∝セョ騾夂衍<E5A482>?
---
## <20>迫 逶ク蜈ウ譁<EFBDB3>。」
- **MVP开发任务清单:** `MVP开发任务清单.md`
- **完整技术方案:** `IIT Manager Agent 完整技术开发方案 (V1.1).md`
- **REDCap二次开发指南:** `../../Redcap/03-API对接与开发/33-REDCap二次开发深度指南.md`
- **REDCap部署手册:** `../../Redcap/01-部署与配置/10-REDCap_Docker部署操作手册.md`
- **MVP€蜿台ササ蜉。貂<EFBFBD><EFBFBD><EFBFBD>** `MVP€蜿台ササ蜉。貂<EFBFBD><EFBFBD>?md`
- **螳梧紛謚€譛ッ譁ケ譯茨シ<E88CA8>** `IIT Manager Agent 螳梧紛謚€譛ッ蠑€蜿第婿譯?(V1.1).md`
- **REDCap莠梧ャ。蠑€蜿第欠蜊暦シ<EFBFBD>** `../../Redcap/03-API蟇ケ謗・荳主シ€蜿?33-REDCap莠梧ャ。蠑€蜿第キア蠎ヲ謖<EFBDA6><E8AC96>?md`
- **REDCap驛ィ鄂イ謇句<EFBFBD><EFBFBD>?* `../../Redcap/01-驛ィ鄂イ荳朱<EFBFBD>鄂?10-REDCap_Docker驛ィ鄂イ謫堺ス懈焔蜀<EFBFBD>.md`
---
## <20>統 譖エ譁ー譌・蠢<EFBDA5>
| 日期 | 版本 | 更新内容 | 更新人 |
| 譌・譛<EFBFBD> | 迚域悽 | 譖エ譁ー蜀<EFBDB0>ョケ | 譖エ譁ー莠?|
|------|------|---------|--------|
| 2026-01-02 | V1.0 | 蛻晏ァ狗沿譛ャ<E8AD9B>悟ョ梧<EFBDAE>€譛ッ隹<EFBDAF><E99AB9>泌柱譁ケ譯郁ョセ隶。 | AI Assistant |
---
**这是IIT Manager Agent的技术基石文档,请妥善保管!** ⭐⭐⭐⭐⭐
**霑呎弍IIT Manager Agent<EFBFBD>橿譛ッ蝓コ遏ウ譁<EFBFBD>。」<EFBFBD>瑚ッキ螯・蝟<EFBFBD>ソ晉ョ。<EFBFBD><EFBFBD>** 箝絶ュ絶ュ絶ュ絶ュ?