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,31 +1,31 @@
# Dify知识库集成开发记录
# Dify鐭ヨ瘑搴撻泦鎴愬紑鍙戣<EFBFBD>褰?
**开发日期**: 2026-01-04
**开发阶段**: Phase 1.5 - AI对话能力
**任务**: 集成Dify知识库实现研究方案文档查询
**状态**: ✅ 已完成
**寮€鍙戞棩鏈?*: 2026-01-04
**寮€鍙戦樁娈?*: Phase 1.5 - AI瀵硅瘽鑳藉姏
**浠诲姟**: 闆嗘垚Dify鐭ヨ瘑搴撳疄鐜扮爺绌舵柟妗堟枃妗f煡璇?
**鐘舵€?*: 鉁?宸插畬鎴?
---
## 📋 开发目标
## 馃搵 寮€鍙戠洰鏍?
在IIT Manager Agent中集成Dify知识库能力使AI能够查询研究方案、伦理文件、CRF表格等文档并与已有的REDCap实时数据查询能力结合实现**混合检索(Hybrid Retrieval**。
鍦↖IT Manager Agent<EFBFBD>泦鎴怐ify鐭ヨ瘑搴撹兘鍔涳紝浣緼I鑳藉<EFBFBD>鏌ヨ<EFBFBD>鐮旂┒鏂规<EFBFBD>銆佷鸡鐞嗘枃浠躲€丆RF琛ㄦ牸绛夋枃妗紝骞朵笌宸叉湁鐨凴EDCap瀹炴椂鏁版嵁鏌ヨ<EFBFBD>鑳藉姏缁撳悎锛屽疄鐜?*娣峰悎妫€绱<E282AC>Hybrid Retrieval锛?*銆?
## 🎯 技术方案
## 馃幆 鎶€鏈<E282AC>柟妗?
### 鏂规<E98F82>閫夋嫨
| 维度 | 方案A单项目单知识库 | 方案B项目分类多知识库 |
| 缁村害 | 鏂规<E98F82>A锛氬崟椤圭洰鍗曠煡璇嗗簱 | 鏂规<E98F82>B锛氶」鐩<E3808D>垎绫诲<E7BBAB>鐭ヨ瘑搴?|
|------|---------------------|---------------------|
| **知识库数量** | 1个IIT项目 → 1个Dify Dataset | 1个IIT项目 → 多个Dataset方案、伦理、CRF |
| **复杂度** | ✅ 简单 | ❌ 复杂 |
| **MVP适用性** | ✅ 高 | ❌ 低 |
| **选择** | **✅ 采用** | ❌ 暂不采用 |
| **鐭ヨ瘑搴撴暟閲?* | 1涓狪IT椤圭洰 鈫?1涓狣ify Dataset | 1涓狪IT椤圭洰 鈫?澶氫釜Dataset锛堟柟妗堛€佷鸡鐞嗐€丆RF锛?|
| **澶嶆潅搴?* | 鉁?绠€鍗?| 鉂?澶嶆潅 |
| **MVP閫傜敤鎬?* | 鉁?楂?| 鉂?浣?|
| **閫夋嫨** | **鉁?閲囩敤** | 鉂?鏆備笉閲囩敤 |
### 鏂囨。涓婁紶鏂瑰紡
- **閲囩敤鏂规<E98F82>**: 閫氳繃Dify Web鐣岄潰鎵嬪姩涓婁紶
- **原因**: MVP阶段文档更新频率低,手动上传更灵活
- **鍘熷洜**: MVP闃舵<EFBFBD>鏂囨。鏇存柊棰戠巼浣庯紝鎵嬪姩涓婁紶鏇寸伒娲?
- **鏈<>潵浼樺寲**: 鍚庣画鍙<E794BB>紑鍙慉PI鑷<49>姩涓婁紶鑳藉姏
### 椤圭洰鍏宠仈鏂瑰紡
@@ -35,7 +35,7 @@
---
## 🛠️ 技术实现
## 馃洜锔?鎶€鏈<E282AC>疄鐜?
### 1. 鏁版嵁搴揝chema楠岃瘉
@@ -57,14 +57,14 @@ model IitProject {
}
```
### 2. 创建Dify知识库
### 2. 鍒涘缓Dify鐭ヨ瘑搴?
**鎿嶄綔姝ラ<E5A79D>**:
1. 登录Dify控制台
1. 鐧诲綍Dify鎺у埗鍙?
2. 鍒涘缓鐭ヨ瘑搴擄細`Dify_test0102`
3. 上传文档:
3. 涓婁紶鏂囨。锛?
- `鏂扮敓鍎垮強濠村効鑳嗘眮娣ょН鐥囦腑瑗垮尰鍗忓悓闃熷垪鐮旂┒鏂规<E98F82>1210-.docx`
- `重大疑难-病例报告表CRF修改1208.docx`
- `閲嶅ぇ鐤戦毦-鐥呬緥鎶ュ憡琛<E686A1>紙CRF锛変慨鏀?208.docx`
4. 绛夊緟鏂囨。澶勭悊瀹屾垚
**Dataset ID**: `b49595b2-bf71-4e47-9988-4aa2816d3c6f`
@@ -115,14 +115,14 @@ private detectIntent(message: string): {
```typescript
private async queryDifyKnowledge(query: string): Promise<string> {
try {
// 1. 获取项目配置包含difyDatasetId
// 1. 鑾峰彇椤圭洰閰嶇疆锛堝寘鍚玠ifyDatasetId锛?
const project = await prisma.iitProject.findFirst({
where: { status: 'active' },
select: { name: true, difyDatasetId: true }
});
if (!project?.difyDatasetId) {
logger.warn('[ChatService] 项目未配置Dify知识库');
logger.warn('[ChatService] 椤圭洰鏈<EFBFBD>厤缃瓺ify鐭ヨ瘑搴?);
return '';
}
@@ -138,7 +138,7 @@ private async queryDifyKnowledge(query: string): Promise<string> {
}
);
// 3. 格式化检索结果
// 3. 鏍煎紡鍖栨<EFBFBD>绱㈢粨鏋?
if (!retrievalResult.records || retrievalResult.records.length === 0) {
return '';
}
@@ -148,20 +148,20 @@ private async queryDifyKnowledge(query: string): Promise<string> {
const score = (record.score * 100).toFixed(1);
const documentName = record.segment?.document?.name || '<EFBFBD>';
const content = record.segment?.content || '';
formattedKnowledge += `\n[文档${index + 1}] ${documentName} (相关度: ${score}%)\n`;
formattedKnowledge += `\n[鏂囨。${index + 1}] ${documentName} (鐩稿叧搴? ${score}%)\n`;
formattedKnowledge += `${content}\n`;
formattedKnowledge += `---\n`;
});
return formattedKnowledge;
} catch (error: any) {
logger.error('[ChatService] Dify检索失败', { query, error: error.message });
return `【知识库查询失败】: ${error.message}`;
logger.error('[ChatService] Dify妫?, { query, error: error.message });
return `銆愮煡璇嗗簱鏌ヨ<EFBFBD>澶辫触銆? ${error.message}`;
}
}
```
#### (3) 更新主对话流程
#### (3) 鏇存柊涓诲<EFBFBD>璇濇祦绋?
```typescript
async handleMessage(userId: string, userMessage: string): Promise<string> {
@@ -180,16 +180,16 @@ async handleMessage(userId: string, userMessage: string): Promise<string> {
toolResult = await this.countRedcapRecords();
}
// 4. 如果需要查询文档Dify知识库执行检索
// 4. 濡傛灉闇€瑕佹煡璇㈡枃妗紙Dify鐭ヨ瘑搴擄級锛屾墽琛屾<EFBFBD>绱?
let difyKnowledge: string = '';
if (intent === 'query_protocol') {
difyKnowledge = await this.queryDifyKnowledge(userMessage);
}
// 5. 获取上下文最近2轮对话
// 5. 鑾峰彇涓婁笅鏂囷紙鏈€杩?杞<><E69D9E>璇濓級
const context = sessionMemory.getContext(userId);
// 6. 构建LLM消息包含查询结果 + Dify知识库
// 6. 鏋勫缓LLM娑堟伅锛堝寘鍚<EFBFBD>煡璇㈢粨鏋?+ Dify鐭ヨ瘑搴擄級
const messages = this.buildMessagesWithData(
userMessage,
context,
@@ -222,7 +222,7 @@ private buildMessagesWithData(
}
];
// 添加历史上下文最近2轮
// 娣诲姞鍘嗗彶涓婁笅鏂囷紙鏈€杩?杞<>
if (context?.length > 0) {
messages.push(...context);
}
@@ -235,7 +235,7 @@ private buildMessagesWithData(
currentUserMessage += `\n\n## 馃搳 REDCap鏌ヨ<E98F8C>缁撴灉\n${JSON.stringify(toolResult, null, 2)}`;
}
// 注入Dify知识库内容
// 娉ㄥ叆Dify鐭ヨ瘑搴撳唴瀹?
if (difyKnowledge) {
currentUserMessage += `\n\n## 馃摎 鐭ヨ瘑搴撶浉鍏虫枃妗<E69E83>n${difyKnowledge}`;
}
@@ -253,40 +253,40 @@ private buildMessagesWithData(
```typescript
private getSystemPromptWithData(): string {
return `你是IIT Manager Agent,一个专业的研究者临床试验助手。
return `浣犳槸IIT Manager Agent锛屼竴涓<EFBFBD>笓涓氱殑鐮旂┒鑰呬复搴婅瘯楠屽姪鎵嬨€?
【核心能力】
- **实时数据查询**通过REDCap API查询患者CRF数据入组、访视、不良事件等
- **研究方案查询**通过Dify知识库检索研究方案、伦理文件、CRF表格等文档
銆愭牳蹇冭兘鍔涖€?
- **瀹炴椂鏁版嵁鏌ヨ<EFBFBD>**锛氶€氳繃REDCap API鏌ヨ<E98F8C>€匔RF鏁版嵁锛堝叆缁勩€佽<E282AC>瑙嗐€佷笉鑹<E7AC89>簨浠剁瓑锛?
- **鐮旂┒鏂规<EFBFBD>鏌ヨ<EFBFBD>**锛氶€氳繃Dify鐭ヨ瘑搴撴<E690B4>绱㈢爺绌舵柟妗堛€佷鸡鐞嗘枃浠躲€丆RF琛ㄦ牸绛夋枃妗?
【关键原则】
1. **数据真实性第一**所有回答必须基于系统提供的真实数据REDCap或Dify),绝不编造数据
銆愬叧閿<EFBFBD>師鍒欍€?
1. **鏁版嵁鐪熷疄鎬х<EFBFBD>涓€**锛氭墍鏈夊洖绛斿繀椤诲熀浜庣郴缁熸彁渚涚殑鐪熷疄鏁版嵁锛圧EDCap鎴朌ify锛夛紝缁濅笉缂栭€犳暟鎹?
2. **鏄庣‘鏁版嵁鏉ユ簮**锛氬尯鍒哛EDCap瀹炴椂鏁版嵁鍜屾枃妗煡璇嗗簱
3. **涓撲笟涓ヨ皑**锛氫娇鐢ㄤ复搴婄爺绌舵湳璇<E6B9B3>紝淇濇寔瀹㈣<E780B9>鍑嗙
4. **简洁高效**:企业微信场景,控制回复长度
4. **绠€娲侀珮鏁?*锛氫紒涓氬井淇″満鏅<E6BA80>紝鎺у埗鍥炲<E98DA5>闀垮害
【数据获取规则】
- 如果系统提供了"📊 REDCap查询结果",必须基于该数据回答
- 如果系统提供了"📚 知识库相关文档",必须基于该文档回答
- 如果未提供数据,明确告知用户"未查询到相关数据",不得编造
銆愭暟鎹<EFBFBD>幏鍙栬<EFBFBD>鍒欍€?
- 濡傛灉绯荤粺鎻愪緵浜?馃搳 REDCap鏌ヨ<E98F8C>缁撴灉"锛屽繀椤诲熀浜庤<E6B59C>鏁版嵁鍥炵瓟
- 濡傛灉绯荤粺鎻愪緵浜?馃摎 鐭ヨ瘑搴撶浉鍏虫枃妗?锛屽繀椤诲熀浜庤<E6B59C>鏂囨。鍥炵瓟
- 濡傛灉鏈<EFBFBD>彁渚涙暟鎹<EFBFBD>紝鏄庣鍛婄煡鐢ㄦ埛"鏈<>煡璇㈠埌鐩稿叧鏁版嵁"锛屼笉寰楃紪閫?
`;
}
```
---
## 🐛 问题排查与解决
## 馃悰 闂<><E99782>鎺掓煡涓庤В鍐?
### 问题1: AI不查询Dify自己编造答案
### <EFBFBD><EFBFBD>1: AI涓嶆煡璇<EFBFBD>ify锛岃嚜宸辩紪閫犵瓟妗?
**鐜拌薄**:
- 用户在企业微信问:"这个研究的纳入标准是什么?"
- AI回答了貌似合理的内容但Dify控制台显示**没有查询记录**
- AI明显在编造(Hallucination
- 鐢ㄦ埛鍦ㄤ紒涓氬井淇¢棶锛?杩欎釜鐮旂┒鐨勭撼鍏ユ爣鍑嗘槸浠€涔堬紵"
- AI鍥炵瓟浜嗚矊浼煎悎鐞嗙殑鍐呭<EFBFBD>锛屼絾Dify鎺у埗鍙版樉绀?*娌℃湁鏌ヨ<E98F8C>璁板綍**
- AI鏄庢樉鍦ㄧ紪閫狅紙Hallucination锛?
**鎺掓煡杩囩▼**:
#### 第一步:检查意图识别
#### <EFBFBD>竴姝ワ細妫€鏌ユ剰鍥捐瘑鍒?
鎬€鐤戯細`detectIntent`鏂规硶娌℃湁璇嗗埆鍑篳query_protocol`鎰忓浘
@@ -298,11 +298,11 @@ if (/(研究方案|伦理|知情同意|CRF|病例报告表|纳入|排除|标准)
}
```
**发现**: 关键词列表中有"纳入"和"标准",但缺少"**入选**"
**鍙戠幇**: 鍏抽敭璇嶅垪琛ㄤ腑鏈?绾冲叆"鍜?鏍囧噯"锛屼絾缂哄皯"**鍏ラ€?*"锛?
用户问的是"纳入标准",但实际文档中更多使用"入选标准"的表述。
鐢ㄦ埛闂<EFBFBD>殑鏄?绾冲叆鏍囧噯"锛屼絾瀹為檯鏂囨。涓<E38082>洿澶氫娇鐢?鍏ラ€夋爣鍑?鐨勮〃杩般€?
**解决**: 扩充关键词列表
**瑙e喅**: 鎵╁厖鍏抽敭璇嶅垪琛?
```typescript
if (/(鐮旂┒鏂规<E98F82>|浼︾悊|鐭ユ儏鍚屾剰|CRF|鐥呬緥鎶ュ憡琛▅绾冲叆|鍏ラ€墊鎺掗櫎|鏍囧噯|鍏ョ粍鏍囧噯|娌荤枟鏂规<E98F82>|璇曢獙璁捐<E79281>|鐮旂┒鐩<E29492>殑|鐮旂┒娴佺▼|瑙傚療鎸囨爣|璇婃柇鏍囧噯|鐤剧梾鏍囧噯)/.test(message)) {
@@ -316,10 +316,10 @@ if (/(研究方案|伦理|知情同意|CRF|病例报告表|纳入|入选|排除|
**鐩<>殑**: 杩借釜Dify妫€绱㈢粨鏋滄槸鍚︽<E98D9A><EFBFBD>敞鍏ュ埌LLM
**发现**: Dify确实被调用了,但返回的内容是`undefined`
**鍙戠幇**: Dify<EFBFBD>疄琚<EFBFBD>皟鐢ㄤ簡锛屼絾杩斿洖鐨勫唴瀹规槸`undefined`锛?
```
[文档1] undefined (相关度: 76.0%)
[鏂囨。1] undefined (鐩稿叧搴? 76.0%)
undefined
---
```
@@ -334,9 +334,9 @@ undefined
"records": [
{
"segment": {
"content": "纳入与排除标准...",
"content": "绾冲叆涓庢帓闄ゆ爣鍑?..",
"document": {
"name": "重大疑难-病例报告表CRF修改1208.docx"
"name": "閲嶅ぇ鐤戦毦-鐥呬緥鎶ュ憡琛<E686A1>紙CRF锛変慨鏀?208.docx"
}
},
"score": 0.7604317
@@ -348,11 +348,11 @@ undefined
**闂<><E99782>鏍瑰洜**: ChatService涓<65>娇鐢ㄤ簡閿欒<E996BF>鐨勫瓧娈佃矾寰勶紒
```typescript
// ❌ 错误的访问方式
// 鉂?閿欒<E996BF>鐨勮<E990A8><EFBFBD>柟寮?
const documentName = record.document_name; // undefined
const content = record.content; // undefined
// ✅ 正确的访问方式
// 鉁?姝鐨勮<E990A8><EFBFBD>柟寮?
const documentName = record.segment?.document?.name;
const content = record.segment?.content;
```
@@ -364,7 +364,7 @@ retrievalResult.records.forEach((record, index) => {
const score = (record.score * 100).toFixed(1);
const documentName = record.segment?.document?.name || '鏈<>煡鏂囨。';
const content = record.segment?.content || '';
formattedKnowledge += `\n[文档${index + 1}] ${documentName} (相关度: ${score}%)\n`;
formattedKnowledge += `\n[鏂囨。${index + 1}] ${documentName} (鐩稿叧搴? ${score}%)\n`;
formattedKnowledge += `${content}\n`;
formattedKnowledge += `---\n`;
});
@@ -374,12 +374,12 @@ retrievalResult.records.forEach((record, index) => {
| 闂<><E99782> | 鏍瑰洜 | 瑙喅鏂规<E98F82> |
|------|------|---------|
| AI编造答案 | 意图识别关键词不全 | 扩充`detectIntent`关键词列表,添加"入选"等医学术语 |
| AI缂栭€犵瓟妗?| 鎰忓浘璇嗗埆鍏抽敭璇嶄笉鍏?| 鎵╁厖`detectIntent`鍏抽敭璇嶅垪琛<E59EAA>紝娣诲姞"鍏ラ€?绛夊尰瀛︽湳璇?|
| Dify鍐呭<E98D90>涓簎ndefined | 閿欒<E996BF>鐨凙PI鍝嶅簲瀛楁<E7809B><EFBFBD>緞 | 淇<><E6B787>涓篳record.segment.document.name`鍜宍record.segment.content` |
---
## ✅ 测试验证
## 鉁?娴嬭瘯楠岃瘉
### 娴嬭瘯1: 鐮旂┒鏂规<E98F82>鏌ヨ<E98F8C>锛圖ify妫€绱<E282AC>
@@ -389,56 +389,56 @@ retrievalResult.records.forEach((record, index) => {
```
鏍规嵁鐮旂┒鏂规<EFBFBD>鏂囨。锛屾湰鐮旂┒鐨勬帓闄ゆ爣鍑嗗寘鎷<EFBFBD>
1. 年龄小于18岁或大于75岁
1. 骞撮緞灏忎簬18宀佹垨澶т簬75宀?
2. 鍚堝苟鍏朵粬涓ラ噸鍣ㄥ畼鍔熻兘闅滅<E99785>
3. 鏃㈠線鏈夌浉鍏宠嵂鐗╄繃鏁忓彶
4. 濡婂<E6BFA1>鎴栧摵涔虫湡濡囧コ
5. 近3个月内参与过其他临床试验
5. 杩?涓<>湀鍐呭弬涓庤繃鍏朵粬涓村簥璇曢獙
如需查看完整排除标准条款,建议您登录系统查阅详细研究方案文档。
濡傞渶鏌ョ湅瀹屾暣鎺掗櫎鏍囧噯鏉℃<EFBFBD>锛屽缓璁<EFBFBD>偍鐧诲綍绯荤粺鏌ラ槄璇︾粏鐮旂┒鏂规<EFBFBD>鏂囨。銆?
```
**鏃ュ織楠岃瘉**:
```
[ChatService] 鎰忓浘璇嗗埆 { intent: 'query_protocol' }
[ChatService] Dify检索成功 { recordCount: 5 }
[ChatService] Dify妫€绱㈡垚鍔?{ recordCount: 5 }
[ChatService] 澶勭悊娑堟伅 { hasDifyKnowledge: true }
```
**结果**: 成功识别意图调用Dify返回正确答案
鉁?**缁撴灉**: 鎴愬姛璇嗗埆鎰忓浘锛岃皟鐢―ify锛岃繑鍥炴<EFBFBD><EFBFBD>瓟妗?
### 娴嬭瘯2: CRF琛ㄦ牸鏌ヨ<E98F8C>锛圖ify妫€绱<E282AC>
**问题**: "CRF表格中有哪些观察指标?"
**<EFBFBD><EFBFBD>**: "CRF琛ㄦ牸涓<EFBFBD>湁鍝<EFBFBD>簺瑙傚療鎸囨爣锛?
**AI鍥炵瓟**:
```
根据研究方案文档CRF表格中的观察指标包括
鏍规嵁鐮旂┒鏂规<EFBFBD>鏂囨。锛孋RF琛ㄦ牸涓<EFBFBD>殑瑙傚療鎸囨爣鍖呮嫭锛?
1. 基线人口学资料
2. 主要疗效指标(如症状评分)
3. 次要疗效指标(如生活质量评分)
4. 安全性指标(不良事件记录)
5. 实验室检查结果
1. 鍩虹嚎浜哄彛瀛﹁祫鏂?
2. 涓昏<EFBFBD>鐤楁晥鎸囨爣锛堝<EFBFBD>鐥囩姸璇勫垎锛?
3. 娆¤<EFBFBD>鐤楁晥鎸囨爣锛堝<EFBFBD>鐢熸椿璐ㄩ噺璇勫垎锛?
4. 瀹夊叏鎬ф寚鏍囷紙涓嶈壇浜嬩欢璁板綍锛?
5. 瀹為獙瀹ゆ<EFBFBD>鏌ョ粨鏋?
具体指标定义和采集时点请查阅详细CRF表格文档。
鍏蜂綋鎸囨爣瀹氫箟鍜岄噰闆嗘椂鐐硅<EFBFBD>鏌ラ槄璇︾粏CRF琛ㄦ牸鏂囨。銆?
```
**结果**: 成功检索CRF文档
鉁?**缁撴灉**: 鎴愬姛妫€绱<EFBFBD>RF鏂囨。
### 测试3: 患者记录查询(REDCap查询)
### 娴嬭瘯3: 鎮€呰<E282AC>褰曟煡璇<E785A1>REDCap鏌ヨ<EFBFBD>锛?
**问题**: "ID 7的患者情况"
**<EFBFBD><EFBFBD>**: "ID 7鐨勬偅鑰呮儏鍐?
**AI鍥炵瓟**:
```
鏍规嵁REDCap鏁版嵁锛孖D 7鐨勬偅鑰呮儏鍐靛<E98D90>涓嬶細
**基本信息**企业微信7男性8岁身高130cm体重50kgBMI 29.6
**联系方式**邮箱gofeng117@163.com
**研究状态**:治疗室记录为"测试7777"DDCD表单已完成。
**鍩烘湰淇℃伅**锛氫紒涓氬井淇?锛岀敺鎬э紝8宀侊紝韬<E7B49D>珮130cm锛屼綋閲?0kg锛孊MI 29.6銆?
**鑱旂郴鏂瑰紡**锛氶偖绠眊ofeng117@163.com銆?
**鐮旂┒鐘舵€?*锛氭不鐤楀<E990A4>璁板綍涓?娴嬭瘯7777"锛孌DCD琛ㄥ崟宸插畬鎴愩€?
如需查看完整记录或更多访视数据建议您登录REDCap系统。
濡傞渶鏌ョ湅瀹屾暣璁板綍鎴栨洿澶氳<EFBFBD>瑙嗘暟鎹<EFBFBD>紝寤鸿<EFBFBD>鎮ㄧ櫥褰昍EDCap绯荤粺銆?
```
**鏃ュ織楠岃瘉**:
@@ -448,20 +448,20 @@ REDCap API: exportRecords success { recordCount: 1 }
[ChatService] 澶勭悊娑堟伅 { hasToolResult: true, hasDifyKnowledge: false }
```
**结果**: 成功识别为REDCap查询返回实时数据
鉁?**缁撴灉**: 鎴愬姛璇嗗埆涓篟EDCap鏌ヨ<EFBFBD>锛岃繑鍥炲疄鏃舵暟鎹?
### 测试4: 统计查询REDCap查询
### 娴嬭瘯4: 缁熻<E7BC81>鏌ヨ<E98F8C>锛圧EDCap鏌ヨ<E98F8C>锛?
**问题**: "目前入组了多少人?"
**<EFBFBD><EFBFBD>**: "<EFBFBD>墠鍏ョ粍浜嗗<EFBFBD>灏戜汉锛?
**AI鍥炵瓟**:
```
根据REDCap实时数据,**test0102**项目目前共有 **11位** 患者入组。
鏍规嵁REDCap瀹炴椂鏁版嵁锛?*test0102**椤圭洰鐩<EFBFBD>墠鍏辨湁 **11浣?* 鎮h€呭叆缁勩€?
记录ID为1至11。如需查看患者详情建议您登录REDCap系统。
璁板綍ID涓?鑷?1銆傚<E98A86>闇€鏌ョ湅鎮€呰<E282AC>鎯咃紝寤鸿<E5AFA4>鎮ㄧ櫥褰昍EDCap绯荤粺銆?
```
**结果**: 成功统计入组人数
鉁?**缁撴灉**: 鎴愬姛缁熻<EFBFBD>鍏ョ粍浜烘暟
### 娴嬭瘯5: 娣峰悎鏌ヨ<E98F8C>锛圖ify妫€绱<E282AC>
@@ -469,12 +469,12 @@ REDCap API: exportRecords success { recordCount: 1 }
**AI鍥炵瓟**:
```
根据研究方案文档,本研究的**主要研究目的**是评估[具体干预措施]在[目标人群]中的有效性和安全性。
鏍规嵁鐮旂┒鏂规<EFBFBD>鏂囨。锛屾湰鐮旂┒鐨?*涓昏<E6B693>鐮旂┒鐩<E29492>殑**鏄<>瘎浼癧鍏蜂綋骞查<E9AA9E><EFBFBD>柦]鍦╗鐩<E29597>爣浜虹兢]涓<>殑鏈夋晥鎬у拰瀹夊叏鎬с€?
由于当前检索到的文档内容不完整,无法提供更详细的具体描述。建议您查阅完整的研究方案文档以获取准确信息。
鐢变簬褰撳墠妫€绱㈠埌鐨勬枃妗唴瀹逛笉瀹屾暣锛屾棤娉曟彁渚涙洿璇︾粏鐨勫叿浣撴弿杩般€傚缓璁<EFBFBD>偍鏌ラ槄瀹屾暣鐨勭爺绌舵柟妗堟枃妗互鑾峰彇鍑嗙淇℃伅銆?
```
**结果**: 成功检索AI能识别信息不完整的情况
鉁?**缁撴灉**: 鎴愬姛妫€绱<EFBFBD>紝AI鑳借瘑鍒<EFBFBD>俊鎭<EFBFBD>笉瀹屾暣鐨勬儏鍐?
---
@@ -484,62 +484,62 @@ REDCap API: exportRecords success { recordCount: 1 }
```
鐢ㄦ埛鎻愰棶锛堜紒涓氬井淇★級
意图识别detectIntent
┌───────────────┬───────────────┬──────────────┐
query_protocolquery_record count_records
│ (文档查询) │ (记录查询) │ (统计查询) │
└───────┬───────┴───────┬───────┴──────┬───────┘
鈫?
鎰忓浘璇嗗埆锛坉etectIntent锛?
鈫?
鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹<EFBFBD>攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹<EFBFBD>攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
鈹?query_protocol鈹?query_record 鈹?count_records鈹?
鈹? (鏂囨。鏌ヨ<E98F8C>) 鈹? (璁板綍鏌ヨ<E98F8C>) 鈹? (缁熻<E7BC81>鏌ヨ<E98F8C>) 鈹?
鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹<EFBFBD>攢鈹€鈹€鈹€鈹€鈹€鈹€鈹粹攢鈹€鈹€鈹€鈹€鈹€鈹€鈹<EFBFBD>攢鈹€鈹€鈹€鈹€鈹€鈹€鈹粹攢鈹€鈹€鈹€鈹€鈹€鈹<EFBFBD>攢鈹€鈹€鈹€鈹€鈹€鈹€鈹?
鈫? 鈫? 鈫?
Dify API REDCap API REDCap API
(知识库) (患者数据) (患者数据)
(鐭ヨ瘑搴? (鎮h€呮暟鎹? (鎮h€呮暟鎹?
鈫? 鈫? 鈫?
鏂囨。鐗囨<E99097> JSON鏁版嵁 JSON鏁版嵁
└───────────────┴──────────────┘
鈫? 鈫? 鈫?
鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹粹攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
鈫?
鏋勫缓LLM Prompt
(System + Context + Data)
鈫?
DeepSeek-V3
鈫?
AI鍥炵瓟
鈫?
浼佷笟寰<E7AC9F>俊鑷<E4BF8A>姩鍥炲<E98DA5>
```
### 鏍稿績鎶€鏈<E282AC>
| 层级 | 技术 | 用途 |
| 灞傜骇 | 鎶€鏈?| 鐢ㄩ€?|
|------|------|------|
| **AI推理** | DeepSeek-V3 | 自然语言理解与生成 |
| **RAG平台** | Dify | 文档存储、分块、向量化、语义检索 |
| **数据源** | REDCap | 临床试验实时数据 |
| **数据库** | PostgreSQL | 项目配置、用户映射 |
| **ORM** | Prisma | 数据库访问 |
| **会话管理** | SessionMemory | 上下文维护最近3轮 |
| **通信** | 企业微信 | 消息接收与发送 |
| **AI鎺ㄧ悊** | DeepSeek-V3 | <EFBFBD>劧璇<EFBFBD>█鐞嗚В涓庣敓鎴?|
| **RAG骞冲彴** | Dify | 鏂囨。瀛樺偍銆佸垎鍧椼€佸悜閲忓寲銆佽<EFBFBD>涔夋<EFBFBD>绱?|
| **鏁版嵁婧?* | REDCap | 涓村簥璇曢獙瀹炴椂鏁版嵁 |
| **鏁版嵁搴?* | PostgreSQL | 椤圭洰閰嶇疆銆佺敤鎴锋槧灏?|
| **ORM** | Prisma | 鏁版嵁搴撹<EFBFBD>闂?|
| **浼氳瘽绠$悊** | SessionMemory | 涓婁笅鏂囩淮鎶わ紙鏈€杩?杞<> |
| **閫氫俊** | 浼佷笟寰<EFBFBD>俊 | 娑堟伅鎺ユ敹涓庡彂閫?|
### 鍏抽敭璁捐<E79281>妯″紡
1. **鎰忓浘椹卞姩璺<E5A7A9>敱 (Intent-Based Routing)**
- 根据用户问题关键词识别意图
- 动态调用不同的数据源(Dify vs REDCap
- 鏍规嵁鐢ㄦ埛闂<E59F9B><E99782>鍏抽敭璇嶈瘑鍒<E79891>剰鍥?
- 鍔ㄦ€佽皟鐢ㄤ笉鍚岀殑鏁版嵁婧愶紙Dify vs REDCap锛?
2. **混合检索 (Hybrid Retrieval)**
- 结构化数据查询(REDCap
- 非结构化文档检索Dify
2. **娣峰悎妫€绱?(Hybrid Retrieval)**
- 缁撴瀯鍖栨暟鎹<E69A9F>煡璇<E785A1>REDCap锛?
- 闈炵粨鏋勫寲鏂囨。妫€绱<E282AC>紙Dify锛?
- 涓よ€呯粨鏋滅粺涓€娉ㄥ叆LLM Prompt
3. **RAG (Retrieval Augmented Generation)**
- 检索相关文档片段
- 注入到LLM上下文
- 减少幻觉Hallucination
- 妫€绱㈢浉鍏虫枃妗g墖娈?
- 娉ㄥ叆鍒癓LM涓婁笅鏂?
- 鍑忓皯骞昏<E9AA9E>锛圚allucination锛?
4. **浼氳瘽璁板繂 (Session Memory)**
- 保留最近3轮对话
- 支持多轮对话上下文
- 淇濈暀鏈€杩?杞<><E69D9E>璇?
- 鏀<>寔澶氳疆瀵硅瘽涓婁笅鏂?
---
@@ -549,13 +549,13 @@ REDCap API: exportRecords success { recordCount: 1 }
| 鎿嶄綔 | 骞冲潎鑰楁椂 | 澶囨敞 |
|------|---------|------|
| Dify检索 | ~1.5s | 语义检索 Top 5 |
| Dify妫€绱?| ~1.5s | <EFBFBD>箟妫€绱?Top 5 |
| REDCap鍗曟潯鏌ヨ<E98F8C> | ~1.2s | HTTP API |
| REDCap统计查询 | ~1.3s | 导出所有记录 |
| REDCap缁熻<EFBFBD>鏌ヨ<EFBFBD> | ~1.3s | 瀵煎嚭鎵€鏈夎<EFBFBD>褰?|
| LLM鎺ㄧ悊 | ~3.5s | DeepSeek-V3, 500 tokens |
| **总响应时间** | ~5-6s | 含网络传输 |
| **鎬诲搷搴旀椂闂?* | ~5-6s | <EFBFBD>綉缁滀紶杈?|
### Token消耗
### Token娑堣€?
| 鍦烘櫙 | Input Tokens | Output Tokens | Total |
|------|-------------|---------------|-------|
@@ -567,13 +567,13 @@ REDCap API: exportRecords success { recordCount: 1 }
## 馃幆 鍚庣画浼樺寲鏂瑰悜
### 短期优化1-2周
### <EFBFBD>湡浼樺寲锛?-2鍛<32>
1. **鎵╁睍鍏抽敭璇嶅簱**
- 鏀堕泦瀹為檯鐢ㄦ埛鎻愰棶
- 补充遗漏的医学术语
- 琛ュ厖閬楁紡鐨勫尰瀛︽湳璇?
2. **优化检索质量**
2. **浼樺寲妫€绱㈣川閲?*
- 璋冩暣Dify鐨刞top_k`鍙傛暟
- 璇曢獙涓嶅悓鐨刞search_method`
@@ -581,55 +581,56 @@ REDCap API: exportRecords success { recordCount: 1 }
- 浼樺寲System Prompt
- 澧炲姞寮曠敤鏉ユ簮灞曠ず
### 中期优化1-2个月
### <EFBFBD>湡浼樺寲锛?-2涓<32>湀锛?
1. **实现多项目支持**
1. **瀹炵幇澶氶」鐩<EFBFBD>敮鎸?*
- 鐢ㄦ埛缁戝畾澶氫釜椤圭洰
- 椤圭洰鍒囨崲鏈哄埗
2. **鏂囨。API涓婁紶**
- 开发自动上传接口
- 定时更新知识库
- 寮€鍙戣嚜鍔ㄤ笂浼犳帴鍙?
- 瀹氭椂鏇存柊鐭ヨ瘑搴?
3. **检索结果缓存**
3. **妫€绱㈢粨鏋滅紦瀛?*
- Redis缂撳瓨楂橀<E6A582><EFBFBD><E99782>
- 鍑忓皯Dify璋冪敤娆℃暟
### 长期优化3-6个月
### 闀挎湡浼樺寲锛?-6涓<36>湀锛?
1. **多知识库联合检索**
- 按文档类型分类方案、伦理、CRF
1. **澶氱煡璇嗗簱鑱斿悎妫€绱?*
- 鎸夋枃妗被鍨嬪垎绫伙紙鏂规<EFBFBD>銆佷鸡鐞嗐€丆RF锛?
- 鏅鸿兘璺<E58598>敱鍒板<E98D92>搴旂煡璇嗗簱
2. **混合检索增强**
2. **娣峰悎妫€绱㈠<EFBFBD>寮?*
- 鍚屾椂鏌ヨ<E98F8C>REDCap鍜孌ify
- 融合结构化+非结构化数据
- 铻嶅悎缁撴瀯鍖?闈炵粨鏋勫寲鏁版嵁
3. **瀵硅瘽璐ㄩ噺鐩戞帶**
- 用户满意度评分
- 答案准确性审计
- 鐢ㄦ埛婊℃剰搴﹁瘎鍒?
- 绛旀<EFBFBD>鍑嗙у<EFBFBD>璁?
---
## 馃摎 鐩稿叧鏂囨。
- [IIT Manager Agent 技术路径与架构设计](../02-技术设计/IIT%20Manager%20Agent%20技术路径与架构设计.md)
- [IIT Manager Agent 鎶€鏈<EFBFBD>矾寰勪笌鏋舵瀯璁捐<EFBFBD>](../02-鎶€鏈<EFBFBD><EFBFBD>璁?IIT%20Manager%20Agent%20鎶€鏈<EFBFBD>矾寰勪笌鏋舵瀯璁捐<EFBFBD>.md)
- [IIT Manager Agent 鎶€鏈<E282AC>€哄姟娓呭崟](../07-鎶€鏈<E282AC>€哄姟/IIT%20Manager%20Agent%20鎶€鏈<E282AC>€哄姟娓呭崟.md)
- [Phase1.5-AI对话能力开发计划](../04-开发计划/Phase1.5-AI对话能力开发计划.md)
- [Phase1.5-AI瀵硅瘽鑳藉姏寮€鍙戣<EFBFBD>鍒抅(../04-寮€鍙戣<E98D99>鍒?Phase1.5-AI瀵硅瘽鑳藉姏寮€鍙戣<E98D99>鍒?md)
---
## 👥 开发人员
## 馃懃 寮€鍙戜汉鍛?
- **开发者**: AI Assistant + FengZhiBo
- **寮€鍙戣€?*: AI Assistant + FengZhiBo
- **娴嬭瘯**: FengZhiBo锛堜紒涓氬井淇湡瀹炵幆澧冿級
- **鏂囨。**: AI Assistant
---
**✅ 开发完成时间**: 2026-01-04
**✅ 测试状态**: 全部通过
**✅ 部署状态**: 已部署到开发环境
**鉁?寮€鍙戝畬鎴愭椂闂?*: 2026-01-04
**鉁?娴嬭瘯鐘舵€?*: 鍏ㄩ儴閫氳繃
**鉁?閮ㄧ讲鐘舵€?*: 宸查儴缃插埌寮€鍙戠幆澧?

View File

@@ -1,41 +1,41 @@
# Day 2 - REDCap 实时集成开发完成记录
# Day 2 - REDCap 瀹炴椂闆嗘垚寮€鍙戝畬鎴愯<EFBFBD>褰?
> **开发日期**: 2026-01-02
> **开发者**: AI Assistant + 用户
> **寮€鍙戞棩鏈?*: 2026-01-02
> **寮€鍙戣€?*: AI Assistant + 鐢ㄦ埛
> **鏂囨。鐗堟湰**: v1.0
> **开发阶段**: Day 2 - REDCap对接与实时同步
> **寮€鍙戦樁娈?*: Day 2 - REDCap瀵规帴涓庡疄鏃跺悓姝?
---
## 📋 开发概述
## 馃搵 寮€鍙戞<E98D99>杩?
Day 2的核心目标是实现 **IIT Manager Agent REDCap 的实时数据集成**,采用 REDCap 原生的 **Data Entry Trigger (DET)** + **REST API** 技术方案,实现零延迟的数据同步和双向通信。
Day 2鐨勬牳蹇冪洰鏍囨槸瀹炵幇 **IIT Manager Agent 涓?REDCap 鐨勫疄鏃舵暟鎹<EFBFBD>泦鎴?*锛岄噰鐢?REDCap 鍘熺敓鐨?**Data Entry Trigger (DET)** + **REST API** 鎶€鏈<EFBFBD>柟妗堬紝瀹炵幇闆跺欢杩熺殑鏁版嵁鍚屾<EFBFBD>鍜屽弻鍚戦€氫俊銆?
### 核心价值
### 鏍稿績浠峰€?
1. **实时性**: Webhook响应时间<10ms数据录入后立即触发
2. **可靠性**: DET + 定时轮询双保险机制
3. **云原生**: 完全基于Postgres-Only架构使用pg-boss队列
4. **标准化**: 符合团队开发规范队列名称、Worker注册等
1. 鉁?**瀹炴椂鎬?*: Webhook鍝嶅簲鏃堕棿<10ms锛屾暟鎹<E69A9F>綍鍏ュ悗绔嬪嵆瑙﹀彂
2. 鉁?**鍙<>潬鎬?*: DET + 瀹氭椂杞<E6A482><E69D9E>鍙屼繚闄╂満鍒?
3. 鉁?**浜戝師鐢?*: 瀹屽叏鍩轰簬Postgres-Only鏋舵瀯锛屼娇鐢╬g-boss闃熷垪
4. 鉁?**鏍囧噯鍖?*: 绗﹀悎鍥㈤槦寮€鍙戣<E98D99>鑼冿紙闃熷垪鍚嶇О銆乄orker娉ㄥ唽绛夛級
---
## 🎯 完成的功能模块
## 馃幆 瀹屾垚鐨勫姛鑳芥ā鍧?
### 1. RedcapAdapter (API适配器)
### 1. RedcapAdapter (API閫傞厤鍣?
**鏂囦欢**: `backend/src/modules/iit-manager/adapters/RedcapAdapter.ts`
**鏍稿績鍔熻兘**:
- `testConnection()` - 连接测试
- `exportMetadata()` - 导出字段定义17个字段
- `exportRecords()` - 导出记录(支持全量/增量/指定记录)
- `importRecords()` - 导入记录Phase 2预留)
- 鉁?`testConnection()` - 杩炴帴娴嬭瘯
- 鉁?`exportMetadata()` - 瀵煎嚭瀛楁<EFBFBD>瀹氫箟锛?7涓<37>瓧娈碉級
- 鉁?`exportRecords()` - 瀵煎嚭璁板綍锛堟敮鎸佸叏閲?澧為噺/鎸囧畾璁板綍锛?
- 鉁?`importRecords()` - 瀵煎叆璁板綍锛圥hase 2棰勭暀锛?
**鍏抽敭鍙傛暟**:
- `baseUrl`: `http://localhost:8080`
- `apiToken`: `FCB30F9CBD12EE9E8E9B3E3A0106701B`
- `timeout`: 30
- `timeout`: 30绉?
**瀹為檯鎬ц兘**:
```
@@ -46,22 +46,22 @@ Day 2的核心目标是实现 **IIT Manager Agent 与 REDCap 的实时数据集
---
### 2. WebhookController (Webhook接收器)
### 2. WebhookController (Webhook鎺ユ敹鍣?
**鏂囦欢**: `backend/src/modules/iit-manager/controllers/WebhookController.ts`
**鏍稿績閫昏緫**:
```typescript
1. 200 OK<10ms
1. 200 OK?10ms锛?
2. project_id鏄<EFBFBD><EFBFBD>
3. 幂等性检查防止重复处理
4. 记录审计日志WEBHOOK_RECEIVED
5. 推送到质控队列iit_quality_check
3. ф<EFBFBD><EFBFBD><EFBFBD>?
4. ¤<EFBFBD>EBHOOK_RECEIVED?
5. it_quality_check?
```
**REDCap DET鏍煎紡鏀<E7B4A1>**:
- ✅ 添加了 `application/x-www-form-urlencoded` 解析器
- ✅ 支持REDCap原生POST格式
- 鉁?娣诲姞浜?`application/x-www-form-urlencoded` 瑙f瀽鍣?
- 鉁?鏀<>REDCap鍘熺敓POST鏍煎紡
**Webhook瀛楁<E7809B>**:
```json
@@ -77,19 +77,19 @@ Day 2的核心目标是实现 **IIT Manager Agent 与 REDCap 的实时数据集
---
### 3. SyncManager (轮询管理器)
### 3. SyncManager (<EFBFBD><EFBFBD>悊鍣?
**鏂囦欢**: `backend/src/modules/iit-manager/services/SyncManager.ts`
**鏍稿績鍔熻兘**:
- `initScheduledJob()` - 初始化定时任务每5分钟
- `handlePoll()` - 轮询所有active项目
- `manualSync()` - 手动同步指定项目
- `fullSync()` - 全量同步
- 鉁?`initScheduledJob()` - 鍒濆<EFBFBD>鍖栧畾鏃朵换鍔★紙姣?鍒嗛挓锛?
- 鉁?`handlePoll()` - <EFBFBD><EFBFBD>鎵€鏈塧ctive椤圭洰
- 鉁?`manualSync()` - 鎵嬪姩鍚屾<EFBFBD>鎸囧畾椤圭洰
- 鉁?`fullSync()` - 鍏ㄩ噺鍚屾<EFBFBD>
**澧為噺鍚屾<E98D9A>绛栫暐**:
```typescript
// 基于lastSyncAt时间戳
// 鍩轰簬lastSyncAt鏃堕棿鎴?
dateRangeBegin: lastSyncAt || createdAt - 24h
```
@@ -108,20 +108,20 @@ dateRangeBegin: lastSyncAt || createdAt - 24h
1. **iit_redcap_poll** (瀹氭椂杞<E6A482><E69D9E>)
- 闃熷垪鍚嶇О: `iit_redcap_poll`
- 触发频率: 每5分钟Cron: `*/5 * * * *`
- 并发数: 1
- 功能: 轮询所有active项目的增量数据
- 瑙﹀彂棰戠巼: 姣?鍒嗛挓锛圕ron: `*/5 * * * *`锛?
- 骞跺彂鏁? 1
- 鍔熻兘: 杞<><E69D9E>鎵€鏈塧ctive椤圭洰鐨勫<E990A8>閲忔暟鎹?
2. **iit_quality_check** (璐ㄦ帶浠诲姟)
- 闃熷垪鍚嶇О: `iit_quality_check`
- 触发方式: Webhook/SyncManager推送
- 功能: 质控逻辑Phase 1.5实现)
- 瑙﹀彂鏂瑰紡: Webhook/SyncManager鎺ㄩ€?
- 鍔熻兘: 璐ㄦ帶閫昏緫锛圥hase 1.5瀹炵幇锛?
**鍏抽敭淇<E695AD><E6B787>**:
- ❌ 初始: `await jobQueue.work('iit:redcap:poll', ...)`
- ✅ 修复: `jobQueue.process('iit_redcap_poll', ...)`
- ❌ 初始: 队列名称使用冒号 `iit:quality-check`
- ✅ 修复: 使用下划线 `iit_quality_check`
- 鉂?鍒濆<E98D92>: `await jobQueue.work('iit:redcap:poll', ...)`
- 鉁?淇<><E6B787>: `jobQueue.process('iit_redcap_poll', ...)`
- 鉂?鍒濆<E98D92>: 闃熷垪鍚嶇О浣跨敤鍐掑彿 `iit:quality-check`
- 鉁?淇<><E6B787>: 浣跨敤涓嬪垝绾?`iit_quality_check`
---
@@ -131,13 +131,13 @@ dateRangeBegin: lastSyncAt || createdAt - 24h
**娉ㄥ唽鐨凙PI绔<49>**:
| 端点 | 方法 | 功能 | 状态 |
| <EFBFBD>偣 | 鏂规硶 | 鍔熻兘 | 鐘舵€?|
|------|------|------|------|
| `/api/v1/iit/health` | GET | 健康检查 | ✅ |
| `/api/v1/iit/webhooks/redcap` | POST | DET回调接收 | |
| `/api/v1/iit/webhooks/health` | GET | Webhook健康检查 | ✅ |
| `/api/v1/iit/projects/:id/sync` | POST | 手动同步 | |
| `/api/v1/iit/projects/:id/full-sync` | POST | 全量同步 | |
| `/api/v1/iit/health` | GET | 鍋ュ悍妫€鏌?| 鉁?|
| `/api/v1/iit/webhooks/redcap` | POST | DET鍥炶皟鎺ユ敹 | 鉁?|
| `/api/v1/iit/webhooks/health` | GET | Webhook鍋ュ悍妫€鏌?| 鉁?|
| `/api/v1/iit/projects/:id/sync` | POST | 鎵嬪姩鍚屾<EFBFBD> | 鉁?|
| `/api/v1/iit/projects/:id/full-sync` | POST | 鍏ㄩ噺鍚屾<EFBFBD> | 鉁?|
---
@@ -150,7 +150,7 @@ dateRangeBegin: lastSyncAt || createdAt - 24h
Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@/common'
```
**原因**: 项目使用相对路径,而不是路径别名 `@/common`
**鍘熷洜**: 椤圭洰浣跨敤鐩稿<EFBFBD><EFBFBD>緞锛岃€屼笉鏄<EFBFBD>矾寰勫埆鍚?`@/common`
**瑙喅鏂规<E98F82>**:
```typescript
@@ -167,7 +167,7 @@ import { jobQueue } from '../../../common/jobs/index.js';
---
### 问题2: 数据库字段名称不一致
### <EFBFBD><EFBFBD>2: 鏁版嵁搴撳瓧娈靛悕绉颁笉涓€鑷?
**閿欒<E996BF>淇℃伅**:
```sql
@@ -176,16 +176,16 @@ ERROR: column "redcapProjectId" does not exist
**鍘熷洜**: Prisma浣跨敤camelCase锛屼絾PostgreSQL瀹為檯浣跨敤snake_case
**数据库真实情况**:
**鏁版嵁搴撶湡瀹炴儏鍐?*:
```sql
-- 琛ㄥ悕: iit_schema.projects (not IitProject)
-- 字段名: redcap_project_id (not redcapProjectId)
-- 瀛楁<EFBFBD>鍚? redcap_project_id (not redcapProjectId)
```
**瑙喅鏂规<E98F82>**:
1. TypeScript代码中继续使用Prisma的camelCase(自动映射)
2. ✅ 原始SQL语句改为snake_case
3. JSON字段使用 `'{}'::jsonb` 类型转换
1. 鉁?TypeScript爜涓<EFBFBD>户缁<EFBFBD>娇鐢≒risma鐨刢amelCase锛堣嚜鍔ㄦ槧灏勶級
2. 鉁?鍘熷<E98D98>SQL璇<4C>彞鏀逛负snake_case
3. 鉁?JSON瀛楁<EFBFBD>浣跨敤 `'{}'::jsonb` 绫诲瀷杞<EFBFBD>
**淇<>敼鏂囦欢**:
- 娴嬭瘯鑴氭湰涓<E6B9B0>殑SQL璇<4C>
@@ -200,18 +200,18 @@ ERROR: column "redcapProjectId" does not exist
Name can only contain alphanumeric characters, underscores, hyphens, or periods
```
**原因**: 初始使用连字符 `-`,但实际测试发现不稳定
**鍘熷洜**: 鍒濆<EFBFBD>浣跨敤杩炲瓧绗?`-`锛屼絾瀹為檯娴嬭瘯鍙戠幇涓嶇ǔ瀹?
**鍥㈤槦鏍囧噯**:
```typescript
'iit:quality-check' // 冒号
'iit-quality-check' // 连字符(不稳定)
'iit_quality_check' // 下划线(推荐)
?'iit:quality-check' // 鍐掑彿
?'iit-quality-check' // 杩炲瓧绗︼紙涓嶇ǔ瀹氾級
?'iit_quality_check' // 涓嬪垝绾匡紙鎺ㄨ崘锛?
```
**淇<>**:
- `iit:quality-check` `iit_quality_check`
- `iit:redcap:poll` `iit_redcap_poll`
- `iit:quality-check` 鈫?`iit_quality_check`
- `iit:redcap:poll` 鈫?`iit_redcap_poll`
**渚濇嵁鏂囨。**: `AIclinicalresearch\docs\02-閫氱敤鑳藉姏灞俓Postgres-Only寮傛<E5AFAE>浠诲姟澶勭悊鎸囧崡.md`
@@ -219,20 +219,20 @@ Name can only contain alphanumeric characters, underscores, hyphens, or periods
### 闂<><E99782>4: Worker娉ㄥ唽鏂规硶閿欒<E996BF>
**错误**: 使用了 `await jobQueue.work()`
**閿欒<EFBFBD>**: 浣跨敤浜?`await jobQueue.work()`
**姝g‘鏂规硶**: 浣跨敤 `jobQueue.process()`
**瀵规瘮**:
```typescript
// ❌ 错误
// 鉂?閿欒<E996BF>
await jobQueue.work(
'iit_redcap_poll',
{ teamSize: 1, teamConcurrency: 1 },
async (job) => { ... }
);
// ✅ 正确
// 鉁?姝g‘
jobQueue.process('iit_redcap_poll', async (job) => {
// ...
return { success: true };
@@ -241,7 +241,7 @@ jobQueue.process('iit_redcap_poll', async (job) => {
---
### 问题5: REDCap DET格式不兼容
### <EFBFBD><EFBFBD>5: REDCap DET鏍煎紡涓嶅吋瀹?
**閿欒<E996BF>淇℃伅**:
```
@@ -250,7 +250,7 @@ Unsupported Media Type: application/x-www-form-urlencoded
**鍘熷洜**: REDCap DET鍙戦€佺殑鏄<E6AE91>〃鍗曟牸寮忥紝鑰屼笉鏄疛SON
**解决方案**: 添加Content-Type解析器
**喅鏂规<EFBFBD>**: 娣诲姞Content-Type瑙f瀽鍣?
```typescript
fastify.addContentTypeParser(
'application/x-www-form-urlencoded',
@@ -274,23 +274,23 @@ fastify.addContentTypeParser(
### 闂<><E99782>6: Docker缃戠粶璁块棶闂<E6A3B6><E99782>
**问题**: REDCap容器无法通过 `localhost` 访问宿主机服务
**<EFBFBD><EFBFBD>**: REDCap瀹瑰櫒鏃犳硶閫氳繃 `localhost` 璁块棶瀹夸富鏈烘湇鍔?
**DET URL閰嶇疆**:
```
http://localhost:3001/api/v1/iit/webhooks/redcap
http://host.docker.internal:3001/api/v1/iit/webhooks/redcap
鉂?http://localhost:3001/api/v1/iit/webhooks/redcap
鉁?http://host.docker.internal:3001/api/v1/iit/webhooks/redcap
```
**楠岃瘉鏂规硶**:
```bash
docker exec redcap-apache curl http://host.docker.internal:3001/api/v1/iit/health
# ✅ 成功返回
# 鉁?鎴愬姛杩斿洖
```
---
## ✅ 测试验证
## 鉁?娴嬭瘯楠岃瘉
### 1. API杩炴帴娴嬭瘯
@@ -298,11 +298,11 @@ docker exec redcap-apache curl http://host.docker.internal:3001/api/v1/iit/healt
**缁撴灉**:
```
✅ 连接成功
✅ 元数据导出: 17个字段
✅ 记录导出: 6条记录 (ID: 1,2,3,4,5,6)
✅ 增量同步: 成功获取最近1小时数据
✅ 指定记录: 成功导出单条记录
鉁?杩炴帴鎴愬姛
鉁?鍏冩暟鎹<E69A9F><E98EB9>鍑? 17涓<37>瓧娈?
鉁?璁板綍瀵煎嚭: 6鏉¤<E98F89>褰?(ID: 1,2,3,4,5,6)
鉁?澧為噺鍚屾<E98D9A>: 鎴愬姛鑾峰彇鏈€杩?灏忔椂鏁版嵁
鉁?鎸囧畾璁板綍: 鎴愬姛瀵煎嚭鍗曟潯璁板綍
```
---
@@ -313,11 +313,11 @@ docker exec redcap-apache curl http://host.docker.internal:3001/api/v1/iit/healt
**缁撴灉**:
```
✅ 健康检查: ok
Webhook发送成功: 200
✅ 响应时间: <10ms (优秀)
✅ 幂等性检查: 通过
✅ 无效请求拦截: 400错误
鉁?鍋ュ悍妫€鏌? ok
鉁?Webhook鍙戦€佹垚鍔? 200
鉁?鍝嶅簲鏃堕棿: <10ms (浼樼<EFBFBD>)
鉁?骞傜瓑鎬ф<E98EAC>鏌? 閫氳繃
鉁?鏃犳晥璇锋眰鎷︽埅: 400閿欒<EFBFBD>
```
---
@@ -326,21 +326,21 @@ docker exec redcap-apache curl http://host.docker.internal:3001/api/v1/iit/healt
**娴嬭瘯鑴氭湰**: `test-redcap-integration.ts`
**结果**: **12/12 通过**
**缁撴灉**: **12/12 閫氳繃** 鉁?
```
1. 后端服务运行正常
2. 项目配置存在
3. REDCap API连接成功
4. 元数据获取成功
5. 记录获取成功
6. Webhook响应速度<100ms
7. 异步处理等待完成
8. 审计日志记录完整
9. 增量同步成功
10. 手动同步成功 ⭐
11. Webhook健康检查
12. 幂等性测试通过
鉁?1. 鍚庣<EFBFBD>鏈嶅姟杩愯<EFBFBD>
鉁?2. 椤圭洰閰嶇疆瀛樺湪
鉁?3. REDCap API杩炴帴鎴愬姛
鉁?4. 鍏冩暟鎹<EFBFBD>幏鍙栨垚鍔?
鉁?5. 璁板綍鑾峰彇鎴愬姛
鉁?6. Webhook鍝嶅簲閫熷害<100ms
鉁?7. 寮傛<EFBFBD>澶勭悊绛夊緟瀹屾垚
鉁?8. 瀹¤<EFBFBD>鏃ュ織璁板綍瀹屾暣
鉁?9. 澧為噺鍚屾<EFBFBD>鎴愬姛
鉁?10. 鎵嬪姩鍚屾<EFBFBD>鎴愬姛 猸?
鉁?11. Webhook鍋ュ悍妫€鏌?
鉁?12. 骞傜瓑鎬ф祴璇曢€氳繃
```
---
@@ -361,7 +361,7 @@ docker exec redcap-apache curl http://host.docker.internal:3001/api/v1/iit/healt
WEBHOOK_RECEIVED | 6 | instrument: demographics, project_id: 16
```
**验证结果**: ✅ 数据完全一致
**楠岃瘉缁撴灉**: 鉁?鏁版嵁瀹屽叏涓€鑷?
---
@@ -369,24 +369,24 @@ docker exec redcap-apache curl http://host.docker.internal:3001/api/v1/iit/healt
### API鍝嶅簲鏃堕棿
| 操作 | 耗时 | 数据量 |
| 鎿嶄綔 | 鑰楁椂 | 鏁版嵁閲?|
|------|------|--------|
| exportMetadata | 260-560ms | 17个字段 |
| exportRecords (全量) | 450-1,400ms | 6条记录 |
| exportMetadata | 260-560ms | 17<EFBFBD>瓧娈?|
| exportRecords (鍏ㄩ噺) | 450-1,400ms | 6鏉¤<EFBFBD>褰?|
| exportRecords (澧為噺) | 300-800ms | 鍙樺寲璁板綍 |
| Webhook鍝嶅簲 | **<10ms** | 绔嬪嵆杩斿洖 |
### 实时性验证
### 瀹炴椂鎬ч獙璇?
| 指标 | 目标 | 实际 | 状态 |
| 鎸囨爣 | 鐩<>爣 | 瀹為檯 | 鐘舵€?|
|------|------|------|------|
| Webhook响应时间 | <100ms | **7ms** | ✅ 优秀 |
| DET触发延迟 | 0| **0** | ✅ 完美 |
| 数据同步准确性 | 100% | **100%** | ✅ 完美 |
| Webhook鍝嶅簲鏃堕棿 | <100ms | **7ms** | 鉁?浼樼<E6B5BC> |
| DET瑙﹀彂寤惰繜 | 0绉?| **0绉?* | 鉁?瀹岀編 |
| 鏁版嵁鍚屾<EFBFBD>鍑嗙鎬?| 100% | **100%** | 鉁?瀹岀編 |
---
## 🗄️ 数据库配置
## 馃梽锔?鏁版嵁搴撻厤缃?
### REDCap椤圭洰閰嶇疆
@@ -418,7 +418,7 @@ INSERT INTO iit_schema.projects (
### REDCap椤圭洰淇℃伅
| 字段 | |
| 瀛楁<EFBFBD> | 鍊?|
|------|-----|
| **椤圭洰鍚嶇О** | test0102 |
| **Project ID** | 16 (int) |
@@ -435,8 +435,8 @@ INSERT INTO iit_schema.projects (
- height, weight, bmi
- comments, demographics_complete
**2. ddcd (自定义表单)**
- zhiliaoshi (治疗室)
**2. ddcd (<EFBFBD>畾涔夎〃鍗?**
- zhiliaoshi (娌荤枟瀹?
- shifou (鏄<>惁)
- ddcd_complete
@@ -480,37 +480,37 @@ INSERT INTO iit_schema.projects (
### 1. 鎶€鏈<E282AC>€夊瀷楠岃瘉
**REDCap DET + REST API方案优势**:
- 零开发成本REDCap原生支持
- 零延迟(实时触发)
**鉁?REDCap DET + REST API鏂规<EFBFBD>浼樺娍**:
- 闆跺紑鍙戞垚鏈<EFBFBD>紙REDCap鍘熺敓鏀<EFBFBD>寔锛?
- 闆跺欢杩燂紙瀹炴椂瑙﹀彂锛?
- 楂樺彲闈狅紙Webhook + 杞<><E69D9E>鍙屼繚闄╋級
- 易维护标准HTTP接口
- 鏄撶淮鎶わ紙鏍囧噯HTTP鎺ュ彛锛?
**❌ 放弃的方案**:
**鉂?鏀惧純鐨勬柟妗?*:
- External Module锛堥渶瑕丳HP寮€鍙戯級
- 纯轮询(延迟高,资源浪费)
- <EFBFBD>疆璇<EFBFBD>紙寤惰繜楂橈紝璧勬簮娴<EFBFBD>垂锛?
---
### 2. 开发规范遵循
### 2. 寮€鍙戣<EFBFBD>鑼冮伒寰?
**✅ 符合团队标准**:
- 队列名称: 使用下划线(`iit_quality_check`
**鉁?绗﹀悎鍥㈤槦鏍囧噯**:
- 闃熷垪鍚嶇О: 浣跨敤涓嬪垝绾匡紙`iit_quality_check`锛?
- Worker娉ㄥ唽: 浣跨敤 `jobQueue.process()`
- 审计日志: 记录所有关键操作
- 错误处理: 统一异常捕获和日志记录
- 瀹¤<EFBFBD>鏃ュ織: 璁板綍鎵€鏈夊叧閿<E58FA7>搷浣?
- 閿欒<EFBFBD>澶勭悊: 缁熶竴寮傚父鎹曡幏鍜屾棩蹇楄<E8B987>褰?
**参考文档**:
**鍙傝€冩枃妗?*:
- `Postgres-Only寮傛<E5AFAE>浠诲姟澶勭悊鎸囧崡.md`
- `REDCap瀵规帴鎶€鏈<E282AC>柟妗堜笌瀹炴柦鎸囧崡.md`
---
### 3. 调试技巧
### 3. 璋冭瘯鎶€宸?
**Docker瀹瑰櫒璋冭瘯**:
```bash
# 测试网络连通性
# 娴嬭瘯缃戠粶杩為€氭€?
docker exec redcap-apache curl http://host.docker.internal:3001/api/v1/iit/health
# 鏌ヨ<E98F8C>瀹¤<E780B9>鏃ュ織
@@ -522,7 +522,7 @@ docker exec ai-clinical-postgres psql -U postgres -d ai_clinical_research \
-c "SELECT name, redcap_project_id, status FROM iit_schema.projects;"
```
**REDCap数据库查询**:
**REDCap鏁版嵁搴撴煡璇?*:
```bash
docker exec redcap-mysql mysql -u redcap_user -predcap_pass_dev_456 redcap \
-e "SELECT project_id, app_title FROM redcap_projects WHERE project_id = 16;"
@@ -534,26 +534,26 @@ docker exec redcap-mysql mysql -u redcap_user -predcap_pass_dev_456 redcap \
| 鏂囨。鍚嶇О | 璺<>緞 | 璇存槑 |
|---------|------|------|
| REDCap对接技术方案 | `04-开发计划/REDCap对接技术方案与实施指南.md` | Day 2技术方案 |
| MVP开发任务清单 | `04-开发计划/MVP开发任务清单.md` | 整体开发计划 |
| Postgres-Only异步任务处理指南 | `docs/02-通用能力层/Postgres-Only异步任务处理指南.md` | 队列开发规范 |
| 模块当前状态 | `00-模块当前状态与开发指南.md` | 模块整体状态 |
| REDCap瀵规帴鎶€鏈<EFBFBD>柟妗?| `04-寮€鍙戣<E98D99>鍒?REDCap瀵规帴鎶€鏈<E282AC>柟妗堜笌瀹炴柦鎸囧崡.md` | Day 2鎶€鏈<EFBFBD>柟妗?|
| MVP寮€鍙戜换鍔℃竻鍗?| `04-寮€鍙戣<E98D99>鍒?MVP寮€鍙戜换鍔℃竻鍗?md` | 鏁翠綋寮€鍙戣<E98D99>鍒?|
| Postgres-Only寮傛<EFBFBD>浠诲姟澶勭悊鎸囧崡 | `docs/02-閫氱敤鑳藉姏灞?Postgres-Only寮傛<EFBFBD>浠诲姟澶勭悊鎸囧崡.md` | 闃熷垪寮€鍙戣<E98D99>鑼?|
| 妯″潡褰撳墠鐘舵€?| `00-妯″潡褰撳墠鐘舵€佷笌寮€鍙戞寚鍗?md` | 妯″潡鏁翠綋鐘舵€?|
---
## 🚀 下一步计划
## 馃殌 涓嬩竴姝ヨ<E5A79D>鍒?
### Phase 1.5 - 璐ㄦ帶閫昏緫瀹炵幇
**目标**: 实现AI驱动的数据质控
**<EFBFBD>**: 瀹炵幇AI椹卞姩鐨勬暟鎹<EFBFBD>川鎺?
**鏍稿績鍔熻兘**:
1. 瀹炵幇 `iit_quality_check` Worker鐨勮川鎺ч€昏緫
2. 调用Dify工作流进行数据验证
3. 生成质控建议shadow state
4. 返回结果给研究者
2. 璋冪敤Dify宸ヤ綔娴佽繘琛屾暟鎹<EFBFBD>獙璇?
3. 鐢熸垚璐ㄦ帶寤鸿<EFBFBD>锛坰hadow state锛?
4. 杩斿洖缁撴灉缁欑爺绌惰€?
**预估工作量**: 1-2
**棰勪及宸ヤ綔閲?*: 1-2澶?
---
@@ -565,26 +565,26 @@ docker exec redcap-mysql mysql -u redcap_user -predcap_pass_dev_456 redcap \
1. 瀹屽杽 `importRecords()` API
2. 瀹炵幇shadow state瀹℃壒娴佺▼
3. 缁忕爺绌惰€呯璁ゅ悗鍚屾<E98D9A>鍒癛EDCap
4. 处理冲突和版本控制
4. 澶勭悊鍐茬獊鍜岀増鏈<EFBFBD>帶鍒?
**预估工作量**: 2-3
**棰勪及宸ヤ綔閲?*: 2-3澶?
---
## ✅ 验收清单
## 鉁?楠屾敹娓呭崟
- [x] RedcapAdapter API适配器完成
- [x] WebhookController Webhook接收器完成
- [x] SyncManager 轮询管理器完成
- [x] Worker注册和队列配置完成
- [x] RedcapAdapter API閫傞厤鍣ㄥ畬鎴?
- [x] WebhookController Webhook鎺ユ敹鍣ㄥ畬鎴?
- [x] SyncManager <EFBFBD><EFBFBD>悊鍣ㄥ畬鎴?
- [x] Worker娉ㄥ唽鍜岄槦鍒楅厤缃<EFBFBD>畬鎴?
- [x]<>敱閰嶇疆鍜孋ontent-Type瑙瀽瀹屾垚
- [x] 单元测试脚本通过test-redcap-api.ts
- [x] Webhook测试通过test-redcap-webhook.ts
- [x] 集成测试通过test-redcap-integration.ts12/12
- [x] 真实场景测试通过(新增+编辑记录)
- [x] 鍗曞厓娴嬭瘯鑴氭湰閫氳繃锛坱est-redcap-api.ts锛?
- [x] Webhook娴嬭瘯閫氳繃锛坱est-redcap-webhook.ts锛?
- [x] 闆嗘垚娴嬭瘯閫氳繃锛坱est-redcap-integration.ts锛?2/12锛?
- [x] 鐪熷疄鍦烘櫙娴嬭瘯閫氳繃锛堟柊澧?缂栬緫璁板綍锛?
- [x] 瀹¤<E780B9>鏃ュ織璁板綍瀹屾暣
- [x] 性能指标达标Webhook<10ms
- [x] 符合团队开发规范
- [x] 鎬ц兘鎸囨爣杈炬爣锛圵ebhook<10ms锛?
- [x] 绗﹀悎鍥㈤槦寮€鍙戣<EFBFBD>鑼?
- [x] 鏂囨。鏇存柊瀹屾垚
---
@@ -594,7 +594,7 @@ docker exec redcap-mysql mysql -u redcap_user -predcap_pass_dev_456 redcap \
### A. 鐜<><E9909C>淇℃伅
```yaml
开发环境:
寮€鍙戠幆澧?
- OS: Windows 11
- Node.js: v22.18.0
- PostgreSQL: 16.1 (Docker)
@@ -604,8 +604,8 @@ docker exec redcap-mysql mysql -u redcap_user -predcap_pass_dev_456 redcap \
Docker瀹瑰櫒:
- redcap-apache: REDCap搴旂敤
- redcap-mysql: REDCap数据库
- ai-clinical-postgres: IIT数据库
- redcap-mysql: REDCap鏁版嵁搴?
- ai-clinical-postgres: IIT鏁版嵁搴?
```
### B. 鍏抽敭浠g爜鏂囦欢娓呭崟
@@ -613,26 +613,27 @@ Docker容器:
```
backend/src/modules/iit-manager/
鈹溾攢鈹€ adapters/
│ └── RedcapAdapter.ts (271行)
鈹? 鈹斺攢鈹€ RedcapAdapter.ts (271琛?
鈹溾攢鈹€ controllers/
│ └── WebhookController.ts (327行)
鈹? 鈹斺攢鈹€ WebhookController.ts (327琛?
鈹溾攢鈹€ services/
│ └── SyncManager.ts (398行)
鈹? 鈹斺攢鈹€ SyncManager.ts (398琛?
鈹溾攢鈹€ routes/
│ └── index.ts (203行)
├── index.ts (91行)
├── test-redcap-api.ts (189行)
├── test-redcap-webhook.ts (274行)
└── test-redcap-integration.ts (449行)
鈹? 鈹斺攢鈹€ index.ts (203琛?
鈹溾攢鈹€ index.ts (91琛?
鈹溾攢鈹€ test-redcap-api.ts (189琛?
鈹溾攢鈹€ test-redcap-webhook.ts (274琛?
鈹斺攢鈹€ test-redcap-integration.ts (449琛?
```
**总代码量**: ~2,200
**鎬讳唬鐮侀噺**: ~2,200琛?
---
**文档维护者**: 开发团队
**最后更新**: 2026-01-02
**状态**: ✅ Day 2 开发完成
**鏂囨。缁存姢鑰?*: 寮€鍙戝洟闃?
**鏈€鍚庢洿鏂?*: 2026-01-02
**鐘舵€?*: 鉁?Day 2 寮€鍙戝畬鎴?

View File

@@ -1,9 +1,9 @@
# Day 3 浼佷笟寰<E7AC9F>俊闆嗘垚涓庣<E6B693>鍒扮<E98D92>娴嬭瘯瀹屾垚璁板綍
> **日期**2026-01-03
> **开发阶段**MVP Week 1 - Day 3
> **核心目标**:打通 REDCap Node.js → 企业微信 的完整闭环
> **实际完成**:✅ 端到端测试通过MVP闭环打通
> **鏃ユ湡**锛?026-01-03
> **寮€鍙戦樁娈?*锛歁VP Week 1 - Day 3
> **鏍稿績鐩<EFBFBD>爣**锛氭墦閫?REDCap 鈫?Node.js 鈫?浼佷笟寰<E7AC9F>俊 鐨勫畬鏁撮棴鐜?
> **瀹為檯瀹屾垚**锛氣渽 绔<>埌绔<E59F8C>祴璇曢€氳繃锛孧VP闂<50>幆鎵撻€?
---
@@ -11,69 +11,69 @@
### 1.1 鏍稿績鐩<E7B8BE>
**最小闭环验证**
**鏈€灏忛棴鐜<EFBFBD>獙璇?*锛?
```
REDCap录入数据 → Node.js实时捕获 → 企业微信智能通知
质控分析 → 推送通知 → PI接收
REDCap褰曞叆鏁版嵁 鈫?Node.js瀹炴椂鎹曡幏 鈫?浼佷笟寰<E7AC9F>俊鏅鸿兘閫氱煡
鈫?
璐ㄦ帶鍒嗘瀽 鈫?鎺ㄩ€侀€氱煡 鈫?PI鎺ユ敹
```
### 1.2 瀹屾垚鎴愭灉
| 功能模块 | 状态 | 说明 |
| 鍔熻兘妯″潡 | 鐘舵€?| 璇存槑 |
|---------|------|------|
| ✅ 企业微信推送服务 | 完成 | `WechatService.ts`314行 |
| ✅ 企业微信回调处理 | 完成 | `WechatCallbackController.ts`501行 |
| ✅ 质控Worker逻辑 | 完成 | `iit_quality_check` Worker |
| Worker注册机制 | 完成 | `initIitManager()` 在启动时调用 |
| ✅ 端到端测试 | 通过 | REDCap Node.js → 企业微信 |
| ✅ 环境配置文档 | 完成 | `WECHAT_ENV_CONFIG.md`401行 |
| 鉁?浼佷笟寰<E7AC9F>俊鎺ㄩ€佹湇鍔?| 瀹屾垚 | `WechatService.ts`锛?14琛岋級 |
| 鉁?浼佷笟寰<E7AC9F>俊鍥炶皟澶勭悊 | 瀹屾垚 | `WechatCallbackController.ts`锛?01琛岋級 |
| 鉁?璐ㄦ帶Worker閫昏緫 | 瀹屾垚 | `iit_quality_check` Worker |
| 鉁?Worker娉ㄥ唽鏈哄埗 | 瀹屾垚 | `initIitManager()` 鍦ㄥ惎鍔ㄦ椂璋冪敤 |
| 鉁?绔<>埌绔<E59F8C>祴璇?| 閫氳繃 | REDCap 鈫?Node.js 鈫?浼佷笟寰<E7AC9F> |
| 鉁?鐜<><E9909C>閰嶇疆鏂囨。 | 瀹屾垚 | `WECHAT_ENV_CONFIG.md`锛?01琛岋級 |
---
## 📝 二、关键技术实现
## 馃摑 浜屻€佸叧閿<E58FA7>妧鏈<E5A6A7>疄鐜?
### 2.1 企业微信推送服务(WechatService
### 2.1 浼佷笟寰<EFBFBD>俊鎺ㄩ€佹湇鍔★紙WechatService锛?
**文件**`backend/src/modules/iit-manager/services/WechatService.ts`314行
**鏂囦欢**锛歚backend/src/modules/iit-manager/services/WechatService.ts`锛?14琛岋級
**核心功能**
**鏍稿績鍔熻兘**锛?
```typescript
class WechatService {
// 获取Access Token缓存2小时
// 鑾峰彇Access Token锛堢紦瀛?灏忔椂锛?
async getAccessToken(): Promise<string>
// 发送文本消息
// 鍙戦€佹枃鏈<EFBFBD>秷鎭?
async sendTextMessage(userId: string, content: string): Promise<void>
// 鍙戦€丮arkdown娑堟伅锛堥」鐩<E3808D>洿鏂般€佽川鎺ф姤鍛婏級
async sendMarkdownMessage(userId: string, content: string): Promise<void>
// 发送Textcard卡片消息(项目通知)
// 鍙戦€乀extcard墖娑堟伅锛堥」鐩<EFBFBD>€氱煡锛?
async sendTextcardMessage(userId: string, card: TextcardMessage): Promise<void>
}
```
**关键技术**
-Access Token缓存机制内存缓存2小时有效期
- ✅ 企业微信API调用`/cgi-bin/message/send`
- ✅ 完整的错误处理和日志记录
- ✅ 支持三种消息类型text/markdown/textcard
**鍏抽敭鎶€鏈?*锛?
- 鉁?Access Token缂撳瓨鏈哄埗锛堝唴瀛樼紦瀛橈紝2灏忔椂鏈夋晥鏈燂級
- 鉁?浼佷笟寰<E7AC9F>俊API璋冪敤锛坄/cgi-bin/message/send`锛?
- 鉁?瀹屾暣鐨勯敊璇<E6958A><E79287>鐞嗗拰鏃ュ織璁板綍
- 鉁?鏀<>寔涓夌<E6B693>娑堟伅绫诲瀷锛坱ext/markdown/textcard锛?
**测试验证**
- ✅ 使用企业微信官方开发工具测试(`access_token` + 消息API
- ✅ 文本消息测试通过
- Textcard卡片消息测试通过
- Markdown消息测试通过
- ✅ 手机端企业微信成功接收所有类型消息
**娴嬭瘯楠岃瘉**锛?
- 鉁?浣跨敤浼佷笟寰<E7AC9F>俊瀹樻柟寮€鍙戝伐鍏锋祴璇曪紙`access_token` + 娑堟伅API锛?
- 鉁?鏂囨湰娑堟伅娴嬭瘯閫氳繃
- 鉁?Textcard鍗$墖娑堟伅娴嬭瘯閫氳繃
- 鉁?Markdown娑堟伅娴嬭瘯閫氳繃
- 鉁?鎵嬫満绔<E6BA80>紒涓氬井淇℃垚鍔熸帴鏀舵墍鏈夌被鍨嬫秷鎭?
---
### 2.2 企业微信回调处理WechatCallbackController
### 2.2 浼佷笟寰<EFBFBD>俊鍥炶皟澶勭悊锛圵echatCallbackController锛?
**文件**`backend/src/modules/iit-manager/controllers/WechatCallbackController.ts`501行
**鏂囦欢**锛歚backend/src/modules/iit-manager/controllers/WechatCallbackController.ts`锛?01琛岋級
**核心功能**
**鏍稿績鍔熻兘**锛?
```typescript
class WechatCallbackController {
// URL楠岃瘉锛堜紒涓氬井淇¢<E6B787>娆¢厤缃<E58EA4>
@@ -93,19 +93,19 @@ class WechatCallbackController {
}
```
**关键技术**
- ✅ 企业微信消息加解密(`@wecom/crypto`
- ✅ XML消息解析`xml2js`
- ✅ 签名验证SHA1
- ✅ 异步回复模式(立即返回"success",后台处理)
- ✅ 使用 `setImmediate` 确保异步执行
- LLM意图识别Dify+ 多Agent路由
**鍏抽敭鎶€鏈?*锛?
- 鉁?浼佷笟寰<E7AC9F>俊娑堟伅鍔犺В瀵嗭紙`@wecom/crypto`锛?
- 鉁?XML娑堟伅瑙瀽锛坄xml2js`锛?
- 鉁?绛惧悕楠岃瘉锛圫HA1锛?
- 鉁?寮傛<E5AFAE>鍥炲<E98DA5>妯″紡锛堢珛鍗宠繑鍥?success"锛屽悗鍙板<E98D99>鐞嗭級
- 鉁?浣跨敤 `setImmediate` <EFBFBD>繚寮傛<EFBFBD>鎵ц<EFBFBD>
- 鉁?LLM鎰忓浘璇嗗埆锛圖ify锛? 澶欰gent<EFBFBD>
**测试验证**
- ✅ 企业微信回调URL验证通过
- natapp内网穿透配置成功(`http://iit.nat100.top`
- ✅ 消息加解密测试通过
- ⏸️ 用户消息处理逻辑(待后续扩展)
**娴嬭瘯楠岃瘉**锛?
- 鉁?浼佷笟寰<E7AC9F>俊鍥炶皟URL楠岃瘉閫氳繃
- 鉁?natapp鍐呯綉绌块€忛厤缃<EFBFBD>垚鍔燂紙`http://iit.nat100.top`锛?
- 鉁?娑堟伅鍔犺В瀵嗘祴璇曢€氳繃
- 鈴革笍 鐢ㄦ埛娑堟伅澶勭悊閫昏緫锛堝緟鍚庣画鎵╁睍锛?
---
@@ -113,7 +113,7 @@ class WechatCallbackController {
**鏂囦欢**锛歚backend/src/modules/iit-manager/index.ts`
**核心功能**
**鏍稿績鍔熻兘**锛?
```typescript
// Worker娉ㄥ唽
jobQueue.process<IitQualityCheckJob>('iit_quality_check', async (job) => {
@@ -125,7 +125,7 @@ jobQueue.process<IitQualityCheckJob>('iit_quality_check', async (job) => {
// 2. 鑾峰彇UserID锛堢幆澧冨彉閲忎紭鍏堬級
const piUserId = process.env.WECHAT_TEST_USER_ID || 'FengZhiBo';
// 3. 执行质控检查
// 3. 鎵ц<EFBFBD>璐ㄦ帶妫€鏌?
const qualityCheckResult = await performQualityCheck(...);
// 4. 鍙戦€佷紒涓氬井淇¢€氱煡
@@ -144,7 +144,7 @@ async function performQualityCheck(projectId, recordId, instrument) {
const issues = [];
const recommendations = [];
// 基础检查
// 鍩虹<EFBFBD>妫€鏌?
if (!recordId || recordId.trim() === '') {
issues.push('璁板綍ID鏃犳晥');
}
@@ -161,102 +161,102 @@ async function performQualityCheck(projectId, recordId, instrument) {
const timeDiff = Date.now() - recentLogs[0].created_at.getTime();
if (timeDiff < 3600000) {
recommendations.push('✅ 数据录入及时');
recommendations.push('鉁?鏁版嵁褰曞叆鍙婃椂');
}
return { issues, recommendations };
}
```
**测试验证**
- ✅ Worker成功注册到pg-boss
-REDCap DET触发 → 任务推送 → Worker执行
- ✅ 质控检查逻辑执行正常
- ✅ 企业微信通知发送成功
- ✅ 审计日志记录成功
**娴嬭瘯楠岃瘉**锛?
- 鉁?Worker鎴愬姛娉ㄥ唽鍒皃g-boss
- 鉁?REDCap DET瑙﹀彂 鈫?浠诲姟鎺ㄩ€?鈫?Worker鎵ц<EFBFBD>
- 鉁?璐ㄦ帶妫€鏌ラ€昏緫鎵ц<E98EB5>
- 鉁?浼佷笟寰<E7AC9F>俊閫氱煡鍙戦€佹垚鍔?
- 鉁?瀹¤<E780B9>鏃ュ織璁板綍鎴愬姛
---
### 2.4 Worker娉ㄥ唽鏈哄埗淇<E59F97><E6B787>
**问题**:之前 `initIitManager()` 函数未被调用导致Worker未注册
**<EFBFBD><EFBFBD>**锛氫箣鍓?`initIitManager()` 鍑芥暟鏈<E69A9F><E98F88>璋冪敤锛屽<E9949B>鑷碬orker鏈<72>敞鍐?
**淇<><E6B787>**锛歚backend/src/index.ts`
```typescript
// ✅ 修复前Worker未注册
// 鉁?淇<><E6B787>鍓嶏紙Worker鏈<72>敞鍐岋級
async function start() {
await jobQueue.start();
registerParseExcelWorker();
logger.info('DC Tool C parse excel worker registered');
logger.info('鉁?DC Tool C parse excel worker registered');
// ❌ 忘记调用 initIitManager()
// 鉂?蹇樿<E8B987>璋冪敤 initIitManager()
await new Promise(resolve => setTimeout(resolve, 3000));
}
// ✅ 修复后Worker正确注册
// 鉁?淇<><E6B787>鍚庯紙Worker姝娉ㄥ唽锛?
async function start() {
await jobQueue.start();
registerParseExcelWorker();
logger.info('DC Tool C parse excel worker registered');
logger.info('鉁?DC Tool C parse excel worker registered');
// ✅ 注册IIT Manager Workers
// 鉁?娉ㄥ唽IIT Manager Workers
await initIitManager();
logger.info('IIT Manager workers registered');
logger.info('鉁?IIT Manager workers registered');
await new Promise(resolve => setTimeout(resolve, 3000));
}
```
**验证**
- ✅ 启动日志显示 "IIT Manager workers registered"
- `iit_quality_check` Worker成功处理任务
- `iit_redcap_poll` Worker已注册(定时任务已暂时禁用)
**楠岃瘉**锛?
- 鉁?鍚<>姩鏃ュ織鏄剧ず "IIT Manager workers registered"
- 鉁?`iit_quality_check` Worker鎴愬姛澶勭悊浠诲姟
- 鉁?`iit_redcap_poll` Worker宸叉敞鍐岋紙瀹氭椂浠诲姟宸叉殏鏃剁<EFBFBD><EFBFBD>
---
### 2.5 鏁版嵁搴撳瓧娈靛悕淇<E68295><E6B787>
**问题1**`notification_config` 字段不存在
**<EFBFBD><EFBFBD>1**锛歚notification_config` 瀛楁<E7809B>涓嶅瓨鍦?
**鍘熷洜**锛歐orker浠爜鏌ヨ<E98F8C>浜嗘暟鎹<E69A9F>簱琛ㄤ腑涓嶅瓨鍦ㄧ殑瀛楁<E7809B>
**修复**
**<EFBFBD><EFBFBD>**锛?
```typescript
// ❌ 之前(查询不存在的字段)
// 鉂?涔嬪墠锛堟煡璇<E785A1>笉瀛樺湪鐨勫瓧娈碉級
SELECT id, name, redcap_project_id, notification_config
FROM iit_schema.projects
WHERE id = ${projectId}
// ✅ 现在(只查询存在的字段)
// 鉁?鐜板湪锛堝彧鏌ヨ<E98F8C>瀛樺湪鐨勫瓧娈碉級
SELECT id, name, redcap_project_id
FROM iit_schema.projects
WHERE id = ${projectId}
// UserID直接从环境变量获取(测试模式)
// UserID鐩存帴浠庣幆澧冨彉閲忚幏鍙栵紙娴嬭瘯妯″紡锛?
const piUserId = process.env.WECHAT_TEST_USER_ID || 'FengZhiBo';
```
**问题2**`action` 字段不存在(应为 `action_type`
**<EFBFBD><EFBFBD>2**锛歚action` 瀛楁<E7809B>涓嶅瓨鍦<E793A8>紙搴斾负 `action_type`锛?
**修复**
**<EFBFBD><EFBFBD>**锛?
```typescript
// ❌ 之前
// 鉂?涔嬪墠
INSERT INTO iit_schema.audit_logs (project_id, action, entity_id, details)
WHERE action = 'redcap_data_received'
// ✅ 现在
// 鉁?鐜板湪
INSERT INTO iit_schema.audit_logs (project_id, action_type, entity_id, details)
WHERE action_type = 'redcap_data_received'
```
**验证**
- Worker执行无数据库错误
- ✅ 审计日志记录成功
- ✅ 质控任务完整流程通过
**楠岃瘉**锛?
- 鉁?Worker鎵ц<EFBFBD>鏃犳暟鎹<EFBFBD>簱閿欒<EFBFBD>
- 鉁?瀹¤<E780B9>鏃ュ織璁板綍鎴愬姛
- 鉁?璐ㄦ帶浠诲姟瀹屾暣娴佺▼閫氳繃
---
@@ -264,24 +264,24 @@ WHERE action_type = 'redcap_data_received'
### 3.1 娴嬭瘯鐜<E798AF><E9909C>
| 组件 | 配置 | 状态 |
| 缁勪欢 | 閰嶇疆 | 鐘舵€?|
|------|------|------|
| REDCap | Docker 15.8.0 + 测试项目(PID 16) | ✅ 运行中 |
| Node.js Backend | Fastify + pg-boss + Prisma | ✅ 运行中 |
| PostgreSQL | Docker + iit_schema | ✅ 运行中 |
| 企业微信 | 自建应用 + 测试用户(FengZhiBo) | ✅ 已配置 |
| natapp | 内网穿透(iit.nat100.top) | ✅ 已配置 |
| REDCap | Docker 15.8.0 + 娴嬭瘯椤圭洰(PID 16) | 鉁?杩愯<E69DA9>涓?|
| Node.js Backend | Fastify + pg-boss + Prisma | 鉁?杩愯<E69DA9>涓?|
| PostgreSQL | Docker + iit_schema | 鉁?杩愯<E69DA9>涓?|
| 浼佷笟寰<EFBFBD>俊 | 鑷<>缓搴旂敤 + 娴嬭瘯鐢ㄦ埛(FengZhiBo) | 鉁?宸查厤缃?|
| natapp | 鍐呯綉绌块€?iit.nat100.top) | 鉁?宸查厤缃?|
### 3.2 娴嬭瘯娴佺▼
**测试步骤**
1. REDCap创建新记录(ID: 9
2. REDCap DET实时触发Webhook0秒延迟
3. Node.js WebhookController接收请求(<10ms响应
4. ✅ 推送任务到 `iit_quality_check` 队列
5. Worker执行质控检查
6. ✅ 发送企业微信通知
7. ✅ 手机端企业微信接收通知
**娴嬭瘯姝ラ<EFBFBD>**锛?
1. 鉁?REDCap鍒涘缓鏂拌<EFBFBD>褰曪紙ID: 9锛?
2. 鉁?REDCap DET瀹炴椂瑙﹀彂Webhook锛?绉掑欢杩燂級
3. 鉁?Node.js WebhookController鎺ユ敹璇锋眰锛?10ms鍝嶅簲锛?
4. 鉁?鎺ㄩ€佷换鍔″埌 `iit_quality_check` 闃熷垪
5. 鉁?Worker鎵ц<EFBFBD>璐ㄦ帶妫€鏌?
6. 鉁?鍙戦€佷紒涓氬井淇¢€氱煡
7. 鉁?鎵嬫満绔<E6BA80>紒涓氬井淇℃帴鏀堕€氱煡
**娴嬭瘯璁板綍**锛圛D: 9锛夛細
```
@@ -302,80 +302,80 @@ WHERE action_type = 'redcap_data_received'
2026-01-03 14:02:08.042 [aiclinical-backend] info: 馃搵 Quality check completed
{ issuesCount: 0, recommendationsCount: 3 }
2026-01-03 14:02:08.045 [aiclinical-backend] info: ✅ 审计日志记录成功
2026-01-03 14:02:08.045 [aiclinical-backend] info: 鉁?瀹¤<E780B9>鏃ュ織璁板綍鎴愬姛
{ recordId: "9" }
2026-01-03 14:02:08.048 [aiclinical-backend] info: Quality check completed and notification sent
2026-01-03 14:02:08.048 [aiclinical-backend] info: 鉁?Quality check completed and notification sent
{ piUserId: "FengZhiBo", hasIssues: false }
```
**企业微信接收内容**
**浼佷笟寰<EFBFBD>俊鎺ユ敹鍐呭<EFBFBD>**锛?
```
馃搳 IIT Manager 鏁版嵁褰曞叆閫氱煡
椤圭洰锛歵est0102
记录ID9
璁板綍ID锛?
琛ㄥ崟锛歞emographics
时间2026-01-03 14:02:08
鏃堕棿锛?026-01-03 14:02:08
💡 质控建议:
1. ✅ 数据录入及时
2. ✅ 记录ID有效
3. ✅ 表单demographics
馃挕 璐ㄦ帶寤鸿<E5AFA4>锛?
1. 鉁?鏁版嵁褰曞叆鍙婃椂
2. 鉁?璁板綍ID鏈夋晥
3. 鉁?琛ㄥ崟锛歞emographics
✅ 数据质量良好
鉁?鏁版嵁璐ㄩ噺鑹<E599BA>
馃挰 濡傛湁鐤戦棶锛岃<E9949B>鍥炲<E98DA5>"甯<>姪"鏌ョ湅鏇村<E98F87>鍔熻兘
```
### 3.3 娴嬭瘯缁撴灉
| 测试项 | 期望 | 实际 | 状态 |
| 娴嬭瘯椤?| 鏈熸湜 | 瀹為檯 | 鐘舵€?|
|-------|------|------|------|
| REDCap触发 | 保存后立即触发 | 0秒延迟 | ✅ |
| Webhook接收 | <10ms响应 | 5.8ms | |
| 任务推送 | 成功推送到队列 | 成功 | |
| Worker执行 | Worker处理任务 | 成功执行 | |
| 质控检查 | 返回质控结果 | 3条建议 | ✅ |
| 企业微信推送 | 发送通知成功 | 成功 | |
| 手机接收 | 接收到通知 | 成功接收 | |
| 审计日志 | 记录到数据库 | 成功记录 | |
| 循环发送 | 只发送一次 | 只发送一次 | ✅ |
| REDCap瑙﹀彂 | 淇濆瓨鍚庣珛鍗宠Е鍙?| 0绉掑欢杩?| 鉁?|
| Webhook鎺ユ敹 | <10ms鍝嶅簲 | 5.8ms | 鉁?|
| 浠诲姟鎺ㄩ€?| 鎴愬姛鎺ㄩ€佸埌闃熷垪 | 鎴愬姛 | 鉁?|
| Worker鎵ц<EFBFBD> | Worker澶勭悊浠诲姟 | 鎴愬姛鎵ц<E98EB5> | 鉁?|
| 璐ㄦ帶妫€鏌?| 杩斿洖璐ㄦ帶缁撴灉 | 3鏉″缓璁?| 鉁?|
| 浼佷笟寰<EFBFBD>俊鎺ㄩ€?| 鍙戦€侀€氱煡鎴愬姛 | 鎴愬姛 | 鉁?|
| 鎵嬫満鎺ユ敹 | 鎺ユ敹鍒伴€氱煡 | 鎴愬姛鎺ユ敹 | 鉁?|
| 瀹¤<EFBFBD>鏃ュ織 | 璁板綍鍒版暟鎹<E69A9F>簱 | 鎴愬姛璁板綍 | 鉁?|
| <EFBFBD>幆鍙戦€?| 鍙<>彂閫佷竴娆?| 鍙<>彂閫佷竴娆?| 鉁?|
**关键指标**
- ✅ 端到端延迟:<2秒REDCap保存 → 企业微信接收)
- Webhook响应时间5.8ms
- Worker执行时间:~50ms
- ✅ 消息发送成功率100%测试5次全部成功
- ✅ 无循环发送问题
**鍏抽敭鎸囨爣**锛?
- 鉁?绔<>埌绔<E59F8C>欢杩燂細<2绉掞紙REDCap淇濆瓨 鈫?浼佷笟寰<E7AC9F>俊鎺ユ敹锛?
- 鉁?Webhook鍝嶅簲鏃堕棿锛?.8ms
- 鉁?Worker鎵ц<EFBFBD>鏃堕棿锛殈50ms
- 鉁?娑堟伅鍙戦€佹垚鍔熺巼锛?00%锛堟祴璇?娆★紝鍏ㄩ儴鎴愬姛锛?
- 鉁?鏃犲惊鐜<E6838A>彂閫侀棶棰?
---
## 馃敡 鍥涖€佷复鏃舵帾鏂戒笌鎶€鏈<E282AC>€哄姟
### 4.1 临时措施MVP阶段
### 4.1 涓存椂鎺<EFBFBD>柦锛圡VP闃舵<EFBFBD>锛?
| 搴忓彿 | 涓存椂鎺<E6A482>柦 | 鍘熷洜 | 璁″垝鏀硅繘鏃堕棿 | 鏀硅繘鏂规<E98F82> |
|------|---------|------|------------|---------|
| 1 | **UserID硬编码** | 简化测试流程 | Phase 2 | 从项目配置表读取 `notification_config.wechat_user_id` |
| 2 | **定时轮询禁用** | MVP不需要,Webhook已足够 | Phase 2 | 实现 `jobQueue.schedule()` 或使用 `node-cron` |
| 3 | **质控逻辑简化** | 仅基础检查无AI质控 | Phase 1.5 | 集成Dify RAG + 规则引擎 |
| 4 | **审计日志字段** | `notification_config` 字段未创建 | Phase 2 | 添加JSONB字段存储企业微信配置 |
| 5 | **Access Token缓存** | 内存缓存,重启丢失 | Phase 2 | 使用Redis或数据库缓存 |
| 1 | **UserID<EFBFBD>紪鐮?* | 绠€鍖栨祴璇曟祦绋?| Phase 2 | 浠庨」鐩<E3808D>厤缃<E58EA4>〃璇诲彇 `notification_config.wechat_user_id` |
| 2 | **瀹氭椂杞<EFBFBD><EFBFBD>绂佺敤** | MVP涓嶉渶瑕侊紝Webhook宸茶冻澶?| Phase 2 | 瀹炵幇 `jobQueue.schedule()` 鎴栦娇鐢?`node-cron` |
| 3 | **璐ㄦ帶閫昏緫绠€鍖?* | 浠呭熀纭€妫€鏌ワ紝鏃燗I璐ㄦ帶 | Phase 1.5 | 闆嗘垚Dify RAG + 瑙勫垯寮曟搸 |
| 4 | **瀹¤<EFBFBD>鏃ュ織瀛楁<EFBFBD>** | `notification_config` 瀛楁<EFBFBD><EFBFBD>垱寤?| Phase 2 | 娣诲姞JSONB瀛楁<EFBFBD>瀛樺偍浼佷笟寰<EFBFBD>俊閰嶇疆 |
| 5 | **Access Token缂撳瓨** | 鍐呭瓨缂撳瓨锛岄噸鍚<EFBFBD>涪澶?| Phase 2 | 浣跨敤Redis鎴栨暟鎹<EFBFBD>簱缂撳瓨 |
**详细说明**
**璇︾粏璇存槑**锛?
#### 1. UserID硬编码(环境变量)
#### 1. UserID<EFBFBD>紪鐮侊紙鐜<EFBFBD><EFBFBD>鍙橀噺锛?
**当前实现**
**褰撳墠瀹炵幇**锛?
```typescript
// 直接从环境变量获取
// 鐩存帴浠庣幆澧冨彉閲忚幏鍙?
const piUserId = process.env.WECHAT_TEST_USER_ID || 'FengZhiBo';
```
**问题**
- ❌ 无法支持多项目、多PI
- ❌ 生产环境需要每个项目配置不同的UserID
**<EFBFBD><EFBFBD>**锛?
- 鉂?鏃犳硶鏀<E7A1B6>寔澶氶」鐩<E3808D>€佸<E282AC>PI
- 鉂?鐢熶骇鐜<E9AA87><E9909C>闇€瑕佹瘡涓<E798A1>」鐩<E3808D>厤缃<E58EA4>笉鍚岀殑UserID
**璁″垝鏀硅繘**锛圥hase 2锛夛細
```typescript
@@ -390,7 +390,7 @@ const piUserId = project.notificationConfig?.wechat_user_id
|| 'FengZhiBo';
```
**数据库Schema改进**
**鏁版嵁搴揝chema鏀硅繘**锛?
```sql
ALTER TABLE iit_schema.projects
ADD COLUMN notification_config JSONB DEFAULT '{}'::jsonb;
@@ -407,7 +407,7 @@ ADD COLUMN notification_config JSONB DEFAULT '{}'::jsonb;
#### 2. 瀹氭椂杞<E6A482><E69D9E>绂佺敤
**当前实现**
**褰撳墠瀹炵幇**锛?
```typescript
// 鈴革笍 鏆傛椂绂佺敤瀹氭椂杞<E6A482><E69D9E>锛圡VP闃舵<E99783>锛學ebhook宸茶冻澶燂級
// TODO: Phase 2 - 瀹炵幇瀹氭椂杞<E6A482><E69D9E>浣滀负琛ュ厖鏈哄埗
@@ -416,19 +416,19 @@ ADD COLUMN notification_config JSONB DEFAULT '{}'::jsonb;
logger.info('IIT Manager: Scheduled job registration skipped (using Webhook only for MVP)');
```
**问题**
**<EFBFBD><EFBFBD>**锛?
- 鈿狅笍 `jobQueue.schedule()` 鏂规硶涓嶅瓨鍦<E793A8>`PgBossQueue`<>疄鐜帮級
- 鈿狅笍 MVP闃舵<E99783>涓嶉渶瑕佸畾鏃惰疆璇<E79686>紙REDCap DET宸茶冻澶燂級
**璁″垝鏀硅繘鏂规<E98F82>**锛圥hase 2锛夛細
**方案A使用 `node-cron`(推荐)**
**鏂规<EFBFBD>A锛氫娇鐢?`node-cron`锛堟帹鑽愶級**
```typescript
import cron from 'node-cron';
// 每5分钟执行一次
// 姣?鍒嗛挓鎵ц<E98EB5>涓€娆?
cron.schedule('*/5 * * * *', async () => {
logger.info('REDCap定时轮询开始');
logger.info('鈴?REDCap瀹氭椂杞<EFBFBD><EFBFBD>寮€濮?);
const syncManager = new SyncManager();
await syncManager.handlePoll();
}, {
@@ -436,13 +436,13 @@ cron.schedule('*/5 * * * *', async () => {
});
```
**方案B扩展 `PgBossQueue` 实现 `schedule` 方法**
**鏂规<EFBFBD>B锛氭墿灞?`PgBossQueue` 瀹炵幇 `schedule` 鏂规硶**
```typescript
class PgBossQueue implements JobQueue {
async schedule(name: string, cron: string, data: any, options?: any): Promise<string> {
if (!this.boss) throw new Error('Queue not started');
// pg-boss 支持 cron 表达式
// pg-boss <EFBFBD> cron 琛ㄨ揪寮?
return await this.boss.send(name, data, {
...options,
startAfter: new Date(),
@@ -453,26 +453,26 @@ class PgBossQueue implements JobQueue {
}
```
**优先级**Webhook足够可靠定时轮询仅作为兜底
**浼樺厛绾?*锛氫綆锛圵ebhook瓒冲<E79392><EFBFBD>潬锛屽畾鏃惰疆璇<E79686>粎浣滀负鍏滃簳锛?
---
#### 3. 质控逻辑简化
#### 3. 璐ㄦ帶閫昏緫绠€鍖?
**当前实现**(基础检查):
**褰撳墠瀹炵幇**锛堝熀纭€妫€鏌ワ級锛?
```typescript
async function performQualityCheck(projectId, recordId, instrument) {
const issues = [];
const recommendations = [];
// ✅ 基础检查
// 鉁?鍩虹<E98DA9>妫€鏌?
if (!recordId) issues.push('璁板綍ID鏃犳晥');
if (!instrument) issues.push('琛ㄥ崟鍚嶇О鏃犳晥');
// ✅ 时效性检查
// 鉁?鏃舵晥鎬ф<E98EAC>鏌?
const timeDiff = Date.now() - lastUpdate;
if (timeDiff < 3600000) {
recommendations.push('✅ 数据录入及时');
recommendations.push('鉁?鏁版嵁褰曞叆鍙婃椂');
}
return { issues, recommendations };
@@ -481,10 +481,10 @@ async function performQualityCheck(projectId, recordId, instrument) {
**璁″垝鏀硅繘**锛圥hase 1.5锛夛細
**AI质控逻辑**
**AI璐ㄦ帶閫昏緫**锛?
```typescript
async function performQualityCheck(projectId, recordId, instrument) {
// 1. 获取项目的质控规则
// 1. 鑾峰彇椤圭洰鐨勮川鎺ц<EFBFBD>鍒?
const project = await prisma.iitProject.findUnique({
where: { id: projectId },
select: { cachedRules: true }
@@ -509,7 +509,7 @@ async function performQualityCheck(projectId, recordId, instrument) {
const result = await difyResponse.json();
// 4. 解析AI返回的质控结果
// 4. 瀽AI杩斿洖鐨勮川鎺х粨鏋?
return {
issues: result.issues || [],
recommendations: result.recommendations || [],
@@ -518,15 +518,15 @@ async function performQualityCheck(projectId, recordId, instrument) {
}
```
**优先级**:高(核心价值所在)
**浼樺厛绾?*锛氶珮锛堟牳蹇冧环鍊兼墍鍦<E5A28D>
---
#### 4. 瀹¤<E780B9>鏃ュ織瀛楁<E7809B>
**当前问题**
- `projects` 表缺少 `notification_config` 字段
- UserID暂时从环境变量读取
**褰撳墠闂<EFBFBD><EFBFBD>**锛?
- 鉂?`projects` 琛ㄧ己灏?`notification_config` 瀛楁<EFBFBD>
- 鉂?UserID鏆傛椂浠庣幆澧冨彉閲忚<EFBFBD>鍙?
**璁″垝鏀硅繘**锛圥hase 2锛夛細
```sql
@@ -542,13 +542,13 @@ CREATE INDEX idx_projects_notification_config
ON iit_schema.projects USING GIN (notification_config);
```
**优先级**:中(影响多项目支持)
**浼樺厛绾?*锛氫腑锛堝奖鍝嶅<E98D9D>椤圭洰鏀<E6B4B0>寔锛?
---
#### 5. Access Token缂撳瓨
**当前实现**(内存缓存):
**褰撳墠瀹炵幇**锛堝唴瀛樼紦瀛橈級锛?
```typescript
class WechatService {
private accessTokenCache: {
@@ -560,7 +560,7 @@ class WechatService {
};
async getAccessToken(): Promise<string> {
// 检查缓存
// 妫€鏌ョ紦瀛?
if (this.accessTokenCache.token &&
this.accessTokenCache.expiresAt &&
Date.now() < this.accessTokenCache.expiresAt) {
@@ -579,8 +579,8 @@ class WechatService {
}
```
**问题**
- ⚠️ 重启服务后缓存丢失
**<EFBFBD><EFBFBD>**锛?
- 鈿狅笍 閲嶅惎鏈嶅姟鍚庣紦瀛樹涪澶?
- 鈿狅笍 澶氬疄渚嬮儴缃叉椂鏃犳硶鍏变韩缂撳瓨
**璁″垝鏀硅繘**锛圥hase 2锛夛細
@@ -594,7 +594,7 @@ async getAccessToken(): Promise<string> {
const cached = await redis.get('wechat:access_token');
if (cached) return cached;
// 重新获取并缓存
// 閲嶆柊鑾峰彇骞剁紦瀛?
const response = await fetch(...);
await redis.setex('wechat:access_token', 7000, response.access_token);
@@ -614,176 +614,177 @@ CREATE TABLE iit_schema.wechat_tokens (
);
```
**优先级**:低(单实例部署可接受,内存缓存已足够)
**浼樺厛绾?*锛氫綆锛堝崟瀹炰緥閮ㄧ讲鍙<E8AEB2>帴鍙楋紝鍐呭瓨缂撳瓨宸茶冻澶燂級
---
### 4.2 鎶€鏈<E282AC>€哄姟娓呭崟
| 序号 | 技术债务 | 影响 | 优先级 | 计划时间 |
| 搴忓彿 | 鎶€鏈<E282AC>€哄姟 | 褰卞搷 | 浼樺厛绾?| 璁″垝鏃堕棿 |
|------|---------|------|-------|---------|
| 1 | **质控逻辑简化** | 无AI能力价值有限 | 🔴 高 | Phase 1.5 |
| 2 | **UserID硬编码** | 无法多项目部署 | 🟠 中 | Phase 2 |
| 3 | **notification_config字段缺失** | 无法灵活配置通知 | 🟠 中 | Phase 2 |
| 4 | **定时轮询未实现** | 无兜底机制 | 🟡 低 | Phase 2 |
| 5 | **Access Token内存缓存** | 重启丢失 | 🟡 低 | Phase 2 |
| 6 | **错误处理不完整** | 部分异常未捕获 | 🟠 中 | Phase 2 |
| 1 | **璐ㄦ帶閫昏緫绠€鍖?* | 鏃燗I鑳藉姏锛屼环鍊兼湁闄?| 馃敶 楂?| Phase 1.5 |
| 2 | **UserID<EFBFBD>紪鐮?* | 鏃犳硶澶氶」鐩<E3808D>儴缃?| 馃煚 涓?| Phase 2 |
| 3 | **notification_config瀛楁<EFBFBD>缂哄け** | 鏃犳硶鐏垫椿閰嶇疆閫氱煡 | 馃煚 涓?| Phase 2 |
| 4 | **瀹氭椂杞<EFBFBD><EFBFBD><EFBFBD>疄鐜?* | 鏃犲厹搴曟満鍒?| 馃煛 浣?| Phase 2 |
| 5 | **Access Token鍐呭瓨缂撳瓨** | 閲嶅惎涓㈠け | 馃煛 浣?| Phase 2 |
| 6 | **閿欒<EFBFBD>澶勭悊涓嶅畬鏁?* | 閮ㄥ垎寮傚父鏈<E788B6>崟鑾?| 馃煚 涓?| Phase 2 |
| 7 | **鏃ュ織绾у埆娣蜂贡** | info/debug/error娣风敤 | 馃煝 鏋佷綆 | Phase 3 |
---
### 4.3 风险与缓解措施
### 4.3 椋庨櫓涓庣紦瑙f帾鏂?
| 风险 | 影响 | 概率 | 缓解措施 | 状态 |
| 椋庨櫓 | 褰卞搷 | 姒傜巼 | 缂撹В<D092>柦 | 鐘舵€?|
|------|------|------|---------|------|
| Webhook失败导致数据丢失 | 🔴 高 | 🟡 中 | 定时轮询兜底 | ⏸️ 暂未实现 |
| 企业微信API限流 | 🟠 中 | 🟢 低 | 限流控制 + 重试机制 | ⏸️ 待实现 |
| Access Token过期 | 🟠 中 | 🟡 中 | 自动刷新机制 | ✅ 已实现 |
| 数据库连接失败 | 🔴 高 | 🟢 低 | 连接池 + 重试 | ✅ 已实现 |
| Worker执行失败 | 🟠 中 | 🟡 中 | pg-boss自动重试 | ✅ 已实现 |
| Webhook澶辫触瀵艰嚧鏁版嵁涓㈠け | 馃敶 楂?| 馃煛 涓?| 瀹氭椂杞<E6A482><E69D9E>鍏滃簳 | 鈴革笍 鏆傛湭瀹炵幇 |
| 浼佷笟寰<EFBFBD>俊API闄愭祦 | 馃煚 涓?| 馃煝 浣?| 闄愭祦鎺у埗 + 閲嶈瘯鏈哄埗 | 鈴革笍 寰呭疄鐜?|
| Access Token杩囨湡 | 馃煚 涓?| 馃煛 涓?| 鑷<>姩鍒锋柊鏈哄埗 | 鉁?宸插疄鐜?|
| 鏁版嵁搴撹繛鎺ュけ璐?| 馃敶 楂?| 馃煝 浣?| 杩炴帴姹?+ 閲嶈瘯 | 鉁?宸插疄鐜?|
| Worker鎵ц<EFBFBD>澶辫触 | 馃煚 涓?| 馃煛 涓?| pg-boss鑷<73>姩閲嶈瘯 | 鉁?宸插疄鐜?|
---
## 📊 五、代码统计
## 馃搳 浜斻€佷唬鐮佺粺璁?
### 5.1 核心代码量
### 5.1 鏍稿績浠g爜閲?
| 妯″潡 | 鏂囦欢 | 琛屾暟 | 璇存槑 |
|------|------|------|------|
| 企业微信推送 | `WechatService.ts` | 314 | Access Token + 消息推送 |
| 浼佷笟寰<EFBFBD>俊鎺ㄩ€?| `WechatService.ts` | 314 | Access Token + 娑堟伅鎺ㄩ€?|
| 浼佷笟寰<E7AC9F>俊鍥炶皟 | `WechatCallbackController.ts` | 501 | URL楠岃瘉 + 娑堟伅鎺ユ敹 |
| 璐ㄦ帶Worker | `index.ts` | 336 | Worker娉ㄥ唽 + 璐ㄦ帶閫昏緫 |
| 璺<>敱閰嶇疆 | `routes/index.ts` | 203 | 浼佷笟寰<E7AC9F>俊璺<E4BF8A>敱 |
| 鐜<><E9909C>閰嶇疆鏂囨。 | `WECHAT_ENV_CONFIG.md` | 401 | 浼佷笟寰<E7AC9F>俊閰嶇疆鎸囧崡 |
| **鎬昏<E98EAC>** | - | **1,755** | Day 3鏂板<E98F82>爜 |
### 5.2 累计代码量(Day 1-3
### 5.2 <EFBFBD><EFBFBD>爜閲忥紙Day 1-3锛?
| 阶段 | 代码量 | 说明 |
| 闃舵<EFBFBD> | 浠g爜閲?| 璇存槑 |
|------|-------|------|
| Day 1 | 223行 | 数据库Schema + 模块骨架 |
| Day 2 | 2,200| REDCap集成 + Worker注册 |
| Day 3 | 1,755行 | 企业微信集成 + 端到端测试 |
| **总计** | **4,178** | MVP核心代码 |
| Day 1 | 223琛?| 鏁版嵁搴揝chema + 妯″潡楠ㄦ灦 |
| Day 2 | 2,200琛?| REDCap闆嗘垚 + Worker娉ㄥ唽 |
| Day 3 | 1,755琛?| 浼佷笟寰<E7AC9F>俊闆嗘垚 + 绔<>埌绔<E59F8C>祴璇?|
| **鎬昏<EFBFBD>** | **4,178琛?* | MVP鏍稿績浠 |
---
## 🎯 六、测试覆盖
## 馃幆 鍏<>€佹祴璇曡<E79287>鐩?
### 6.1 鍔熻兘娴嬭瘯
| 测试场景 | 状态 | 说明 |
| 娴嬭瘯鍦烘櫙 | 鐘舵€?| 璇存槑 |
|---------|------|------|
| REDCap DET触发 | 通过 | 0秒延迟 |
| Webhook接收 | 通过 | <10ms响应 |
| ✅ 任务推送 | 通过 | 推送到pg-boss队列 |
| Worker执行 | 通过 | 质控逻辑执行 |
| ✅ 企业微信推送(文本) | 通过 | 手机接收成功 |
| ✅ 企业微信推送(卡片) | 通过 | 手机接收成功 |
| ✅ 企业微信推送Markdown | 通过 | 手机接收成功 |
| ✅ 审计日志记录 | 通过 | 数据库记录成功 |
| ✅ 循环发送问题 | 修复 | 只发送一次 |
| ⏸️ 企业微信回调消息 | 未测试 | URL验证通过用户消息待测试 |
| 鉁?REDCap DET瑙﹀彂 | 閫氳繃 | 0绉掑欢杩?|
| 鉁?Webhook鎺ユ敹 | 閫氳繃 | <10ms鍝嶅簲 |
| 鉁?浠诲姟鎺ㄩ€?| 閫氳繃 | 鎺ㄩ€佸埌pg-boss闃熷垪 |
| 鉁?Worker鎵ц<EFBFBD> | 閫氳繃 | 璐ㄦ帶閫昏緫鎵ц<E98EB5> |
| 鉁?浼佷笟寰<E7AC9F>俊鎺ㄩ€侊紙鏂囨湰锛?| 閫氳繃 | 鎵嬫満鎺ユ敹鎴愬姛 |
| 鉁?浼佷笟寰<E7AC9F>俊鎺ㄩ€侊紙鍗墖锛?| 閫氳繃 | 鎵嬫満鎺ユ敹鎴愬姛 |
| 鉁?浼佷笟寰<E7AC9F>俊鎺ㄩ€侊紙Markdown锛?| 閫氳繃 | 鎵嬫満鎺ユ敹鎴愬姛 |
| 鉁?瀹¤<E780B9>鏃ュ織璁板綍 | 閫氳繃 | 鏁版嵁搴撹<E690B4>褰曟垚鍔?|
| 鉁?寰<>幆鍙戦€侀棶棰?| 淇<><E6B787> | 鍙<>彂閫佷竴娆?|
| 鈴革笍 浼佷笟寰<E7AC9F>俊鍥炶皟娑堟伅 | 鏈<>祴璇?| URL楠岃瘉閫氳繃锛岀敤鎴锋秷鎭<E7A7B7>緟娴嬭瘯 |
### 6.2 鎬ц兘娴嬭瘯
| 指标 | 目标 | 实际 | 状态 |
| 鎸囨爣 | 鐩<>爣 | 瀹為檯 | 鐘舵€?|
|------|------|------|------|
| Webhook响应时间 | <10ms | 5.8ms | ✅ 超出预期 |
| Worker执行时间 | <100ms | ~50ms | ✅ 超出预期 |
| 端到端延迟 | <5| <2秒 | ✅ 超出预期 |
| 消息发送成功率 | >99% | 100% | ✅ 超出预期 |
| Webhook鍝嶅簲鏃堕棿 | <10ms | 5.8ms | 鉁?瓒呭嚭棰勬湡 |
| Worker鎵ц<EFBFBD>鏃堕棿 | <100ms | ~50ms | 鉁?瓒呭嚭棰勬湡 |
| <EFBFBD>埌绔<EFBFBD>欢杩?| <5绉?| <2绉?| 鉁?瓒呭嚭棰勬湡 |
| 娑堟伅鍙戦€佹垚鍔熺巼 | >99% | 100% | 鉁?瓒呭嚭棰勬湡 |
---
## 📚 七、文档更新
## 馃摎 涓冦€佹枃妗f洿鏂?
### 7.1 鏂板<E98F82>鏂囨。
1. **`WECHAT_ENV_CONFIG.md`**401行
1. **`WECHAT_ENV_CONFIG.md`**锛?01琛岋級
- 浼佷笟寰<E7AC9F>俊鐜<E4BF8A><E9909C>鍙橀噺閰嶇疆鎸囧崡
- IP白名单配置
- natapp内网穿透配置
- IP鐧藉悕鍗曢厤缃?
- natapp鍐呯綉绌块€忛厤缃?
- URL楠岃瘉姝ラ<E5A79D>
- 甯歌<E794AF><EFBFBD><E99782>鎺掓煡
### 7.2 鏇存柊鏂囨。
1. **`00-模块当前状态与开发指南.md`**
- 更新开发进度Day 3完成
1. **`00-妯″潡褰撳墠鐘舵€佷笌寮€鍙戞寚鍗?md`**
- 鏇存柊寮€鍙戣繘搴︼紙Day 3瀹屾垚锛?
- 鏇存柊浠爜缁熻<E7BC81>
- 鏇存柊娴嬭瘯缁撴灉
2. **`MVP开发任务清单.md`**
2. **`MVP寮€鍙戜换鍔℃竻鍗?md`**
- 鏍囪<E98F8D>Day 3浠诲姟涓哄凡瀹屾垚
- 更新任务状态
- 鏇存柊浠诲姟鐘舵€?
3. **`最小MVP闭环开发计划.md`**
- 更新开发进度
- 标记核心闭环已打通
3. **`鏈€灏廙VP闂<EFBFBD>幆寮€鍙戣<EFBFBD>鍒?md`**
- 鏇存柊寮€鍙戣繘搴?
- 鏍囪<EFBFBD>鏍稿績闂<EFBFBD>幆宸叉墦閫?
---
## 🚀 八、下一步计划(Day 4
## 馃殌 鍏<>€佷笅涓€姝ヨ<E5A79D>鍒掞紙Day 4锛?
### 8.1 优化与完善
### 8.1 浼樺寲涓庡畬鍠?
| 任务 | 优先级 | 预估时间 |
| 浠诲姟 | 浼樺厛绾?| 棰勪及鏃堕棿 |
|------|-------|---------|
| 完善错误处理 | 🟠 中 | 2小时 |
| 优化日志格式 | 🟡 低 | 1小时 |
| 添加监控指标 | 🟡 低 | 2小时 |
| 性能优化 | 🟡 低 | 1小时 |
| 瀹屽杽閿欒<EFBFBD>澶勭悊 | 馃煚 涓?| 2灏忔椂 |
| 浼樺寲鏃ュ織鏍煎紡 | 馃煛 浣?| 1灏忔椂 |
| 娣诲姞鐩戞帶鎸囨爣 | 馃煛 浣?| 2灏忔椂 |
| 鎬ц兘浼樺寲 | 馃煛 浣?| 1灏忔椂 |
### 8.2 Phase 1.5锛欰I璐ㄦ帶鑳藉姏
| 任务 | 优先级 | 预估时间 |
| 浠诲姟 | 浼樺厛绾?| 棰勪及鏃堕棿 |
|------|-------|---------|
| 集成Dify RAG | 🔴 高 | 4小时 |
| 上传研究方案 | 🔴 高 | 1小时 |
| 生成质控规则 | 🔴 高 | 2小时 |
| 测试AI质控 | 🔴 高 | 1小时 |
| 闆嗘垚Dify RAG | 馃敶 楂?| 4灏忔椂 |
| 涓婁紶鐮旂┒鏂规<EFBFBD> | 馃敶 楂?| 1灏忔椂 |
| 鐢熸垚璐ㄦ帶瑙勫垯 | 馃敶 楂?| 2灏忔椂 |
| 娴嬭瘯AI璐ㄦ帶 | 馃敶 楂?| 1灏忔椂 |
---
## ✅ 九、总结
## 鉁?涔濄€佹€荤粨
### 9.1 鏍稿績鎴愬氨
1. **MVP闭环打通**REDCap Node.js → 企业微信完整流程
2. **企业微信集成**:推送服务 + 回调处理 + URL验证
3. **质控Worker完善**:质控检查 + 通知推送 + 审计日志
4. **端到端测试通过**:实测<2秒延迟100%成功率
5. **文档体系完善**:环境配置 + 开发记录 + 进度跟踪
1. 鉁?**MVP<EFBFBD>幆鎵撻€?*锛歊EDCap 鈫?Node.js 鈫?浼佷笟寰<E7AC9F>俊瀹屾暣娴佺▼
2. 鉁?**浼佷笟寰<E7AC9F>俊闆嗘垚**锛氭帹閫佹湇鍔?+ 鍥炶皟澶勭悊 + URL楠岃瘉
3. 鉁?**璐ㄦ帶Worker瀹屽杽**锛氳川鎺ф<E98EBA>鏌?+ 閫氱煡鎺ㄩ€?+ 瀹¤<E780B9>鏃ュ織
4. 鉁?**绔<>埌绔<E59F8C>祴璇曢€氳繃**锛氬疄娴?2绉掑欢杩燂紝100%鎴愬姛鐜?
5. 鉁?**鏂囨。浣撶郴瀹屽杽**锛氱幆澧冮厤缃?+ 寮€鍙戣<E98D99>褰?+ 杩涘害璺熻釜
### 9.2 鍏抽敭鏁版嵁
- 📝 **新增代码**1,755行高质量生产代码
- ⏱️ **开发时间**1天8小时
- **测试通过率**100%9/9功能测试
- 馃摑 **鏂板<E98F82>爜**锛?,755琛岋紙楂樿川閲忕敓浜т唬鐮侊級
- 鈴憋笍 **寮€鍙戞椂闂?*锛?澶╋紙8灏忔椂锛?
- 鉁?**娴嬭瘯閫氳繃鐜?*锛?00%锛?/9鍔熻兘娴嬭瘯锛?
- 馃殌 **鎬ц兘琛ㄧ幇**锛氱<E9949B>鍒扮<E98D92><2绉掞紝瓒呭嚭棰勬湡
- 📚 **文档完善度**401行配置指南 + 开发记录
- 馃摎 **鏂囨。瀹屽杽搴?*锛?01琛岄厤缃<E58EA4>寚鍗?+ 寮€鍙戣<E98D99>褰?
### 9.3 技术亮点
### 9.3 鎶€鏈<EFBFBD>寒鐐?
1. **异步Worker架构**符合Postgres-Only最佳范式
2. **企业微信消息加解密**:完整实现签名验证和加解密
1. **寮傛<EFBFBD>Worker鏋舵瀯**锛氱<E9949B>鍚圥ostgres-Only鏈€浣宠寖寮?
2. **浼佷笟寰<EFBFBD>俊娑堟伅鍔犺В瀵?*锛氬畬鏁村疄鐜扮<E9909C>鍚嶉獙璇佸拰鍔犺В瀵?
3. **寮傛<E5AFAE>鍥炲<E98DA5>妯″紡**锛歚setImmediate` 纭<>繚5绉掑唴鍝嶅簲
4. **完整的错误处理**:审计日志失败不影响主流程
5. **pg-boss重试机制**自动重试3次确保可靠性
4. **瀹屾暣鐨勯敊璇<EFBFBD><EFBFBD>鐞?*锛氬<E9949B>璁℃棩蹇楀け璐ヤ笉褰卞搷涓绘祦绋?
5. **pg-boss閲嶈瘯鏈哄埗**锛氳嚜鍔ㄩ噸璇?娆★紝纭<E7B49D>繚鍙<E7B99A>潬鎬?
### 9.4 MVP价值验证
### 9.4 MVP浠峰€奸獙璇?
**实时感知**PI无需登录REDCap企业微信即时通知
**主动通知**:数据录入后<2秒推送零遗漏
**易扩展**闭环打通后可快速添加AI质控、任务提醒等
**生产就绪**:代码质量高,性能稳定,可直接部署
鉁?**瀹炴椂鎰熺煡**锛歅I鏃犻渶鐧诲綍REDCap锛屼紒涓氬井淇″嵆鏃堕€氱煡
鉁?**涓诲姩閫氱煡**锛氭暟鎹<E69A9F>綍鍏ュ悗<2绉掓帹閫侊紝闆堕仐婕?
鉁?**鏄撴墿灞?*锛氶棴鐜<E6A3B4>墦閫氬悗锛屽彲蹇<E5BDB2>€熸坊鍔燗I璐ㄦ帶銆佷换鍔℃彁閱掔瓑
鉁?**鐢熶骇灏辩华**锛氫唬鐮佽川閲忛珮锛屾€ц兘绋冲畾锛屽彲鐩存帴閮ㄧ讲
---
**维护者**IIT Manager开发团队
**最后更新**2026-01-03
**文档状态**:✅ 已完成
**缁存姢鑰?*锛欼IT Manager寮€鍙戝洟闃?
**鏈€鍚庢洿鏂?*锛?026-01-03
**鏂囨。鐘舵€?*锛氣渽 宸插畬鎴?

View File

@@ -1,65 +1,65 @@
# Day 3 - 企业微信集成开发完成记录
# Day 3 - <EFBFBD><EFBFBD>敺桐縑<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鞱扇敶?
**开发日期**2026-01-02
**开发者**AI + 用户协作
**<EFBFBD><EFBFBD>烐𠯫<EFBFBD>?*嚗?026-01-02
**<EFBFBD><EFBFBD>𤏸<EFBFBD>?*嚗鋫I + <20><EFBFBD><E586BD><EFBFBD>
**<EFBFBD><EFBFBD>𧋦**嚗鯝1.3
**状态**:✅ 企业微信URL验证成功基础集成完成
**<EFBFBD><EFBFBD>?*嚗尠<E59A97><><E99AA1>敺桐縑URL撉諹<E69289><E8ABB9>𣂼<EFBFBD><EFBFBD>抅蝖<E68A85><E89D96><EFBFBD><EFBFBD>摰峕<E691B0>
---
## 📊 开发概览
## <EFBFBD><EFBFBD><><E69298><EFBFBD>閫?
### <20><EFBFBD>
实现企业微信集成,包括消息推送和回调处理,为 IIT Manager Agent 建立与 PI 的沟通渠道。
摰䂿緵隡<EFBFBD><EFBFBD>敺桐縑<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>舀綫<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗䔶蛹 IIT Manager Agent 撱箇<EFBFBD>銝?PI <20><><EFBFBD><EFBFBD>𡁏<EFBFBD><F0A1818F><EFBFBD>?
### <20><EFBFBD>
- ✅ 企业微信消息推送服务(WechatService
- ✅ 企业微信回调处理WechatCallbackController
- URL验证测试通过
- ✅ 完善质控Worker支持企业微信推送
- natapp内网穿透配置成功
- <EFBFBD>?隡<><E99AA1>敺桐縑瘨<E7B891><E798A8><EFBFBD><EFBFBD><E588B8><EFBFBD><EFBFBD><EFBFBD>WechatService嚗?
- <EFBFBD>?隡<><E99AA1>敺桐縑<E6A190><EFBFBD><EFBFBD><E686AD>嚗ÁechatCallbackController嚗?
- <EFBFBD>?URL撉諹<EFBFBD>瘚贝<EFBFBD><EFBFBD><EFBFBD>
- <EFBFBD>?摰<><E691B0>韐冽綉Worker嚗峕𣈲<E5B395><F0A388B2><EFBFBD>銝𡁜凝靽⊥綫<E28AA5>?
- <EFBFBD>?natapp<EFBFBD><EFBFBD><EFBFBD>蝛輸<EFBFBD><EFBFBD>蝵格<EFBFBD><EFBFBD>?
### 餈𥕦漲
- 模块整体完成度:**35% 50%**
- 企业微信集成:**0% 80%**URL验证完成待端到端测试
- <EFBFBD><EFBFBD><EFBFBD>摰峕<EFBFBD>摨佗<EFBFBD>**35% <EFBFBD>?50%**
- <EFBFBD><EFBFBD>敺桐縑<EFBFBD><EFBFBD><EFBFBD>嚗?*0% <EFBFBD>?80%**嚗㇎RL撉諹<EFBFBD>摰峕<EFBFBD><EFBFBD><EFBFBD>蝡臬<EFBFBD>蝡舀<EFBFBD>霂𤏪<EFBFBD>
---
## 🏗️ 架构设计
## <EFBFBD><EFBFBD>儭?<3F><EFBFBD>霈曇恣
### <20><EFBFBD><EFBFBD>
```
┌─────────────────────────────────────────────────────────────┐
企业微信集成架构
├─────────────────────────────────────────────────────────────┤
REDCap DET ──→ WebhookController ──→ JobQueue
Audit Logs iit_quality_check
Worker
WechatService
企业微信 API
PI 手机
│ 企业微信消息 ──→ WechatCallbackController ──→ AI处理
WechatService ──→ 主动推送回复
└─────────────────────────────────────────────────────────────┘
<EFBFBD>𢞖<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
<EFBFBD>? <EFBFBD><EFBFBD>敺桐縑<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD>?
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
<EFBFBD>? <EFBFBD>?
<EFBFBD>? REDCap DET <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? WebhookController <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? JobQueue <EFBFBD>?
<EFBFBD>? <EFBFBD>? <EFBFBD>? <EFBFBD>?
<EFBFBD>? Audit Logs iit_quality_check <EFBFBD>?
<EFBFBD>? Worker <EFBFBD>?
<EFBFBD>? <EFBFBD>? <EFBFBD>?
<EFBFBD>? WechatService <EFBFBD>?
<EFBFBD>? <EFBFBD>? <EFBFBD>?
<EFBFBD>? <EFBFBD><EFBFBD>敺桐縑 API <EFBFBD>?
<EFBFBD>? <EFBFBD>? <EFBFBD>?
<EFBFBD>? PI <EFBFBD>𧢲㦤 <EFBFBD>?
<EFBFBD>? <EFBFBD>?
<EFBFBD>? 隡<><E99AA1>敺桐縑瘨<E7B891><E798A8> <20><><EFBFBD><EFBFBD><EFBFBD>? WechatCallbackController <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? AI憭<49><E686AD> <EFBFBD>?
<EFBFBD>? <EFBFBD>? <EFBFBD>?
<EFBFBD>? WechatService <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? 銝餃𢆡<E9A483><EFBFBD><E588B8><EFBFBD>憭? <EFBFBD>?
<EFBFBD>? <EFBFBD>?
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
```
### <20><><EFBFBD><EFBFBD><EFBFBD>
| 组件 | 技术方案 | 原因 |
| <EFBFBD>辣 | <20><><EFBFBD>舀䲮獢?| <20><EFBFBD> |
|------|----------|------|
| 消息加解密 | @wecom/crypto | 企业微信官方推荐库 |
| XML解析 | xml2js | 成熟稳定的XML解析库 |
| 内网穿透 | natapp | 本地开发调试 |
| 异步处理 | setImmediate | 规避5秒超时限制 |
| <EFBFBD><EFBFBD><EFBFBD>㰘圾撖?| @wecom/crypto | <EFBFBD><EFBFBD>敺桐縑摰䀹䲮<EFBFBD><EFBFBD>摨?|
| XML<EFBFBD><EFBFBD> | xml2js | <EFBFBD><EFBFBD>蝔喳<EFBFBD><EFBFBD><EFBFBD>ML閫<EFBFBD><EFBFBD>摨?|
| <EFBFBD><EFBFBD><EFBFBD>蝛輸<EFBFBD>?| natapp | <EFBFBD>砍𧑐撘<EFBFBD><EFBFBD>𤏸<EFBFBD>霂?|
| <EFBFBD>郊憭<EFBFBD><EFBFBD> | setImmediate | <EFBFBD><EFBFBD>5蝘坿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?|
---
@@ -68,18 +68,18 @@
### 1. WechatService.ts嚗<73><E59A97>銝𡁜凝靽⊥綫<E28AA5><E7B6AB><EFBFBD><EFBFBD><EFBFBD>
**<EFBFBD><EFBFBD>辣頝臬<EFBFBD>**嚗䫤backend/src/modules/iit-manager/services/WechatService.ts`
**代码行数**314行
**<EFBFBD><EFBFBD>銵峕㺭**嚗?14銵?
**核心功能**
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
```typescript
class WechatService {
// 1. Access Token 管理(缓存 + 自动刷新)
// 1. Access Token 蝞∠<EFBFBD><EFBFBD><EFBFBD>摮?+ <20>芸𢆡<E88AB8>瑟鰵嚗?
async getAccessToken(): Promise<string>
// 2. 发送文本消息
// 2. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
async sendTextMessage(userId: string, content: string): Promise<void>
// 3. 发送 Markdown 消息
// 3. <EFBFBD><EFBFBD>?Markdown <EFBFBD><EFBFBD>
async sendMarkdownMessage(userId: string, content: string): Promise<void>
// 4. 摰∟恣<E2889F><EFBFBD>霈啣<E99C88>
@@ -87,13 +87,13 @@ class WechatService {
}
```
**技术亮点**
-Access Token 缓存机制7200秒提前5分钟刷新
- ✅ 完整的错误处理和重试机制
- ✅ 详细的日志记录(corpId、agentId等)
- ✅ 审计日志自动记录
**<EFBFBD><EFBFBD><EFBFBD>臭漁<EFBFBD>?*嚗?
- <20>?Access Token 蝻枏<EFBFBD><EFBFBD><EFBFBD>嚗?200蝘𡜐<E89D98><F0A19C90>𣂼<EFBFBD>5<EFBFBD><35><EFBFBD><EFBFBD>瑟鰵嚗?
- <20>?摰峕㟲<E5B395><E39FB2><EFBFBD>霂臬<E99C82><E887AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6BBA9><EFBFBD>
- <20>?霂衣<E99C82><E8A1A3><EFBFBD>𠯫敹𡑒扇敶𤏪<E695B6>corpId<EFBFBD><EFBFBD>gentId蝑㚁<EFBFBD>
- <20>?摰∟恣<E2889F><EFBFBD><E4BA99>芸𢆡霈啣<E99C88>
**环境变量**
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
```env
WECHAT_CORP_ID=ww6ab493470ab4f377
WECHAT_AGENT_ID=1000002
@@ -105,21 +105,21 @@ WECHAT_CORP_SECRET=AZIVxMtoLb0rEszXS81e4dBRl-I9kgTjygIS0cFfENU
### 2. WechatCallbackController.ts嚗<73><E59A97>銝𡁜凝靽<E99DBD><EFBFBD><E99D9A><EFBFBD><EFBFBD><EFBFBD>
**<2A><>辣頝臬<E9A09D>**嚗䫤backend/src/modules/iit-manager/controllers/WechatCallbackController.ts`
**代码行数**501行
**<EFBFBD><EFBFBD>銵峕㺭**嚗?01銵?
**核心功能**
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
```typescript
class WechatCallbackController {
// 1. URL 验证GET 请求)
// 1. URL 撉諹<EFBFBD>嚗𠃑ET 霂瑟<E99C82>嚗?
async handleVerification(request, reply): Promise<void>
// 2. 消息接收POST 请求 + 异步处理)
// 2. <EFBFBD><EFBFBD><EFBFBD>交𤣰嚗㇊OST 霂瑟<E99C82> + 撘<>郊憭<E9838A><E686AD>嚗?
async handleCallback(request, reply): Promise<void>
// 3. 撘<>郊瘨<E9838A><E798A8><EFBFBD><E686AD>
private async processMessageAsync(...): Promise<void>
// 4. 用户消息处理(关键词匹配 + 业务逻辑)
// 4. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> + 銝𡁜𦛚<F0A1819C><EFBFBD>嚗?
private async processUserMessage(message): Promise<void>
// 5. 蝑曉<E89D91>撉諹<E69289>
@@ -127,14 +127,14 @@ class WechatCallbackController {
}
```
**技术亮点**
- **异步回复模式**:立即返回`"success"`后台异步处理规避5秒超时
- **消息解密**:使用 `@wecom/crypto` `decrypt(encodingAESKey, encrypt)` 函数
- **签名验证**:使用 `@wecom/crypto` `getSignature(token, timestamp, nonce, data)` 函数
- **意图识别**:支持"汇总"、"帮助"、"新患者"等关键词
- **主动推送**:处理完成后主动调用 WechatService 推送回复
**<EFBFBD><EFBFBD><EFBFBD>臭漁<EFBFBD>?*嚗?
- <EFBFBD>?**撘<><EFBFBD>𧼮<EFBFBD><E79285>**嚗𡁶<E59A97><F0A181B6><EFBFBD><E594BE>裇"success"`嚗<><E59A97><EFBFBD><EFBFBD>甇亙<E79487><E4BA99><EFBFBD><EFBFBD><EFBFBD><E996AB>5蝘坿<E89D98><E59DBF><EFBFBD>
- <EFBFBD>?**瘨<><E798A8><EFBFBD><E996AB>**嚗帋蝙<E5B88B>?`@wecom/crypto` <EFBFBD>?`decrypt(encodingAESKey, encrypt)` <EFBFBD>賣㺭
- <EFBFBD>?**蝑曉<E89D91>撉諹<E69289>**嚗帋蝙<E5B88B>?`@wecom/crypto` <EFBFBD>?`getSignature(token, timestamp, nonce, data)` <EFBFBD>賣㺭
- <EFBFBD>?**<2A>誩㦛霂<E3A69B><E99C82>**嚗𡁏𣈲<F0A1818F>?瘙<><E79899>?<3F>?撣桀𨭌"<22>?<3F><EFBFBD><E594B3>?蝑匧<E89D91><E58CA7><EFBFBD>
- <EFBFBD>?**銝餃𢆡<E9A483><EFBFBD>?*嚗𡁜<E59A97><F0A1819C><EFBFBD><EFBFBD><EFBFBD>𣂼<EFBFBD>銝餃𢆡靚<F0A286A1> WechatService <EFBFBD><EFBFBD><EFBFBD><EFBFBD>憭?
**环境变量**
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
```env
WECHAT_TOKEN=oXlRBm1YnvMy2SbDLbvAdDd5Gq3oBGq
WECHAT_ENCODING_AES_KEY=v88eT3O9bMW897h4btr7v7qvQImlMf31edTQCmuhOhO
@@ -142,9 +142,9 @@ WECHAT_ENCODING_AES_KEY=v88eT3O9bMW897h4btr7v7qvQImlMf31edTQCmuhOhO
---
### 3. 路由配置routes/index.ts
### 3. 頝舐眏<EFBFBD>滨蔭嚗ǐoutes/index.ts嚗?
**新增路由**
**<EFBFBD><EFBFBD>頝舐眏**嚗?
```typescript
// GET: URL撉諹<E69289><EFBFBD><E59A97>銝𡁜凝靽⊿<E99DBD>蝵桀<E89DB5><EFBFBD>RL<52>嗡蝙<E597A1><EFBFBD>
fastify.get('/api/v1/iit/wechat/callback',
@@ -159,19 +159,19 @@ fastify.post('/api/v1/iit/wechat/callback',
---
### 4. 完善质控Workerindex.ts
### 4. <EFBFBD><EFBFBD>韐冽綉Worker嚗ǎndex.ts嚗?
**<EFBFBD><EFBFBD>辣頝臬<EFBFBD>**嚗䫤backend/src/modules/iit-manager/index.ts`
**<2A><EFBFBD><E595A3><EFBFBD>**嚗朞捶<E69C9E><EFBFBD><E689B9>𣂼<EFBFBD><F0A382BC>芸𢆡<E88AB8><EFBFBD><E588B8><EFBFBD>銝𡁜凝靽⊿<E99DBD>𡁶䰻
**代码逻辑**
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
```typescript
jobQueue.process('iit_quality_check', async (job) => {
// 1. <20><EFBFBD>憿寧𤌍<E5AFA7>滨蔭
const project = await prisma.$queryRaw`...`;
const piUserId = project.notification_config.wechat_user_id;
// 2. 执行质控检查
// 2. <EFBFBD><EFBFBD>韐冽綉璉<EFBFBD><EFBFBD>?
const qualityCheckResult = await performSimpleQualityCheck(...);
// 3. <20><>遣隡<E981A3><E99AA1>敺桐縑<E6A190>𡁶䰻瘨<E4B0BB><E798A8>
@@ -182,21 +182,21 @@ jobQueue.process('iit_quality_check', async (job) => {
});
```
**通知消息格式**
**<EFBFBD>𡁶䰻瘨<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
```
<EFBFBD><EFBFBD> IIT Manager <20>唳旿敶訫<E695B6><E8A8AB>𡁶䰻
憿寧𤌍嚗魩est0102
霈啣<EFBFBD>ID嚗鯴xx
銵典<EFBFBD>嚗鯴xx
时间2026-01-02 23:55:00
<EFBFBD>園𡢿嚗?026-01-02 23:55:00
💡 质控建议 (3项)
1. ✅ 数据录入及时5分钟内
2. ✅ 记录ID有效
3. ✅ 表单demographics
<EFBFBD>働 韐冽綉撱箄悅 (3憿?嚗?
1. <EFBFBD>?<3F>唳旿敶訫<E695B6><E8A8AB>𦠜𧒄嚗?<3F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2. <EFBFBD>?霈啣<E99C88>ID<49><EFBFBD>
3. <EFBFBD>?銵典<E98AB5>嚗飱emographics
✅ 数据质量良好,无明显问题
<EFBFBD>?<3F>唳旿韐券<E99F90><E588B8>臬末嚗峕<E59A97><E5B395>擧遬<E693A7><EFBFBD>
<EFBFBD>俥 憒<><E68692><EFBFBD>煾䔮嚗諹窈<E8ABB9>𧼮<EFBFBD>"撣桀𨭌"<22><EFBFBD><E4BAA6><EFBFBD><E6B8B8><EFBFBD>
```
@@ -205,38 +205,38 @@ jobQueue.process('iit_quality_check', async (job) => {
## <20>圲 撘<><E69298>𤏸<EFBFBD>蝔衤<E89D94><E8A1A4><EFBFBD><EFBFBD><E996AB>
### 问题1环境变量名称不一致 ⚠️
### <EFBFBD><EFBFBD>1嚗𡁶㴓憓<EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝘唬<EFBFBD><EFBFBD><EFBFBD>?<3F>𩤃<EFBFBD>
**现象**
**<EFBFBD>啗情**嚗?
```
hasSecret: false
Error: 企业微信配置不完整,请检查环境变量
Error: <EFBFBD><EFBFBD>敺桐縑<EFBFBD>滨蔭銝滚<EFBFBD><EFBFBD><EFBFBD>霂瑟<EFBFBD><EFBFBD>亦㴓憓<EFBFBD><EFBFBD><EFBFBD>?
```
**原因**
**<EFBFBD><EFBFBD>**嚗?
- <20><EFBFBD><E887AC><EFBFBD>嚗䫤WECHAT_CORP_SECRET`
-<><E99A9E>霂餃<E99C82>嚗䫤WECHAT_AGENT_SECRET`
**解决方案**
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
```typescript
// 修改前
// 靽格㺿<EFBFBD>?
agentSecret: process.env.WECHAT_AGENT_SECRET
// 修改后
// 靽格㺿<EFBFBD>?
agentSecret: process.env.WECHAT_CORP_SECRET
```
---
### 问题2@wecom/crypto 导入方式错误 ❌
### <EFBFBD><EFBFBD>2嚗鋣wecom/crypto 撖澆<EFBFBD><EFBFBD><EFBFBD><EFBFBD>躰秤 <20>?
**现象**
**<EFBFBD>啗情**嚗?
```
TypeError: WXBizMsgCrypt is not a constructor
```
**原因**
`@wecom/crypto` 不是一个类而是导出了4个独立的函数
**<EFBFBD><EFBFBD>**嚗?
`@wecom/crypto` 銝齿糓銝<EFBFBD>銝芰掩嚗諹<EFBFBD>峕糓撖澆枂鈭?銝芰𡠺蝡讠<E89DA1><E8AEA0>賣㺭嚗?
```javascript
{
decrypt: [Function: decrypt],
@@ -246,33 +246,33 @@ TypeError: WXBizMsgCrypt is not a constructor
}
```
**解决方案**
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
```typescript
// 修改前(错误)
// 靽格㺿<EFBFBD><EFBFBD><EFBFBD>躰秤嚗?
import WXBizMsgCrypt from '@wecom/crypto';
this.wxcrypt = new WXBizMsgCrypt(token, aesKey, corpId);
// 修改后(正确)
// 靽格㺿<EFBFBD>𠬍<EFBFBD><EFBFBD>嚗?
const require = createRequire(import.meta.url);
const { decrypt, encrypt, getSignature } = require('@wecom/crypto');
```
---
### 问题3decrypt 函数参数错误 ❌
### <EFBFBD><EFBFBD>3嚗飱ecrypt <EFBFBD>賣㺭<EFBFBD><EFBFBD><EFBFBD>躰秤 <20>?
**现象**
**<EFBFBD>啗情**嚗?
```
Error: invalid encodingAESKey
```
**原因**
通过测试脚本发现,`decrypt` 函数只需要 **2个参数**
**<EFBFBD><EFBFBD>**嚗?
<EFBFBD><EFBFBD>瘚贝<EFBFBD><EFBFBD>𡁏𧋦<EFBFBD>𤑳緵嚗䈣decrypt` <20>賣㺭<E8B3A3><EFBFBD>閬?**2銝芸<E98A9D><E88AB8>?*嚗?
```javascript
function decrypt(encodingAESKey, encrypt) { ... }
```
**解决方案**
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
```typescript
// 靽格㺿<E6A0BC><EFBFBD><E3B5AA>躰秤 - 4銝芸<E98A9D><E88AB8><EFBFBD>
const result = decrypt(this.token, this.encodingAESKey, this.corpId, echostr);
@@ -285,51 +285,51 @@ const result = decrypt(this.encodingAESKey, echostr);
### <20><EFBFBD>4嚗関oken摮㛖泵霂<E6B3B5><E99C82><EFBFBD>躰秤 <20>𩤃<EFBFBD>
**现象**
**<EFBFBD>啗情**嚗?
```
<EFBFBD>𩤃<EFBFBD> 蝑曉<E89D91>撉諹<E69289>憭梯揖
expected: 0b7cf05d6cb23ab9ce2efca6fdc659f32051eabe
calculated: 6f79cabd3e9eea5eb10f55abdcf087ce6393d51d
```
**原因**
**<EFBFBD><EFBFBD>**嚗?
Token<EFBFBD><EFBFBD>洵3銝芸<EFBFBD>蝚血捆<EFBFBD>𤘪毽瘛<EFBFBD><EFBFBD>
- `oX1R...`数字1
- `oXlR...`小写字母l
- `oX1R...`嚗<>㺭摮?嚗?
- `oXlR...`嚗<><E59A97><EFBFBD><EFBFBD>瘥徃嚗?
后端日志显示的是 `oXlR...`小写l而调试工具中可能输入了数字1。
<EFBFBD>𡒊垢<EFBFBD><EFBFBD><EFBFBD>曄內<EFBFBD><EFBFBD>糓 `oXlR...`嚗<><E59A97><EFBFBD>耱嚗㚁<E59A97><E39A81><EFBFBD>霂訫極<E8A8AB>瑚葉<E7919A><EFBFBD>颲枏<E9A2B2><EFBFBD>㺭摮?<3F>?
**解决方案**
- 直接从 `.env` 文件复制粘贴,避免手动输入
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
- <20>湔𦻖隞?`.env` <20><>辣憭滚<E686AD>蝎䁅斐嚗屸<E59A97><E5B1B8>齿<EFBFBD><E9BDBF><EFBFBD><E588BB>?
- 蝖株恕 Token 銝綽<E98A9D>`oXlRBm1YnvMy2SbDLbvAdDd5Gq3oBGq`
---
### <20><EFBFBD>5嚗鍃ncodingAESKey <20>湔鰵 <20><>
**现象**
旧的 EncodingAESKey 可能格式有问题导致解密失败。
**<EFBFBD>啗情**嚗?
<EFBFBD><EFBFBD> EncodingAESKey <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>厰䔮憸睃紡<EFBFBD>渲圾撖<EFBFBD>仃韐乓<EFBFBD>?
**解决方案**
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
<EFBFBD><EFBFBD>銝𡁜凝靽∠恣<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
```
<EFBFBD><EFBFBD><EFBFBD>zE4tcdBeekCHPUV015jCh9RVUydnCITINqSmCzg9xtO
新值:v88eT3O9bMW897h4btr7v7qvQImlMf31edTQCmuhOhO43位格式正确
<EFBFBD><EFBFBD><EFBFBD>v88eT3O9bMW897h4btr7v7qvQImlMf31edTQCmuhOhO嚗?3雿㵪<E99BBF><E3B5AA><EFBFBD><EFBFBD>嚗?
```
---
### 问题6natapp 内网穿透配置 🌐
### <EFBFBD><EFBFBD>6嚗䭰atapp <20><><EFBFBD>蝛輸<E89D9B><EFBFBD>蝵?<3F><>
**需求**
本地开发环境需要公网 HTTPS URL 用于企业微信回调。
**<EFBFBD><EFBFBD>瘙?*嚗?
<EFBFBD>砍𧑐撘<EFBFBD><EFBFBD>𤑳㴓憓<EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝵?HTTPS URL <20><EFBFBD><EFBFBD><E99AA1>敺桐縑<E6A190><EFBFBD><E599BC>?
**解决方案**
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
1. 雿輻鍂 natapp <20>滚𦛚
2. 配置隧道:`http://iit.nat100.top` `127.0.0.1:3001`
2. <20>滨蔭<E6BBA8><EFBFBD>嚗䫤http://iit.nat100.top` <EFBFBD>?`127.0.0.1:3001`
3. natapp <20>芸𢆡<E88AB8>𣂷<EFBFBD> HTTPS <20><EFBFBD>
**验证**
**撉諹<EFBFBD>**嚗?
```bash
curl https://iit.nat100.top/api/v1/iit/health
# 餈𥪜<E9A488>嚗㝯"status":"ok","module":"iit-manager",...}
@@ -339,11 +339,11 @@ curl https://iit.nat100.top/api/v1/iit/health
## <20>妒 瘚贝<E7989A>撉諹<E69289>
### 测试1企业微信开发者调试工具验证 ✅
### 瘚贝<EFBFBD>1嚗帋<EFBFBD>銝𡁜凝靽<EFBFBD><EFBFBD>𤏸<EFBFBD><EFBFBD><EFBFBD>霂訫極<EFBFBD><EFBFBD>霂?<3F>?
**工具**:企业微信管理后台 → 开发者工具 → 测试回调模式
**撌亙<EFBFBD>**嚗帋<E59A97>銝𡁜凝靽∠恣<E288A0><E681A3><EFBFBD><EFBFBD>?<3F>?撘<><E69298>𤏸<EFBFBD><F0A48FB8><EFBFBD>?<3F>?瘚贝<E7989A><E8B49D><EFBFBD><E79285>
**配置**
**<EFBFBD>滨蔭**嚗?
```
URL: https://iit.nat100.top/api/v1/iit/wechat/callback
Token: oXlRBm1YnvMy2SbDLbvAdDd5Gq3oBGq
@@ -352,33 +352,33 @@ EchoStr: test12345678901234567890123
ToUserName: ww6ab493470ab4f377
```
**测试结果**
**瘚贝<EFBFBD>蝏𤘪<EFBFBD>**嚗?
```
✅ 返回状态:request: 成功
✅ 返回结果123456789012345678901 25解密后的23位字符
HTTP状态码200
<EFBFBD>?餈𥪜<E9A488><F0A5AA9C><EFBFBD><E59786><EFBFBD>request: <EFBFBD>𣂼<EFBFBD>
<EFBFBD>?餈𥪜<E9A488>蝏𤘪<E89D8F>嚗?23456789012345678901 25<EFBFBD>圾撖<EFBFBD><EFBFBD><EFBFBD>?3雿滚<E99BBF>蝚佗<E89D9A>
<EFBFBD>?HTTP<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗?00
```
**后端日志**
**<EFBFBD>𡒊垢<EFBFBD><EFBFBD>**嚗?
```
<EFBFBD>𢬢 <20><EFBFBD><EFBFBD><E99AA1>敺桐縑 URL 撉諹<E69289>霂瑟<E99C82>
nonce: "95zbplrrko5"
echostrLength: 88
URL 验证成功
<EFBFBD>?URL 撉諹<EFBFBD><EFBFBD>𣂼<EFBFBD>
decryptedLength: 23
statusCode: 200
```
---
### 测试2natapp 隧道连通性测试 ✅
### 瘚贝<EFBFBD>2嚗䭰atapp <20><EFBFBD>餈鮋<E9A488>𡁏<EFBFBD><EFBFBD>霂?<3F>?
**测试命令**
**瘚贝<EFBFBD><EFBFBD>賭誘**嚗?
```bash
curl https://iit.nat100.top/api/v1/iit/health
```
**返回结果**
**餈𥪜<EFBFBD>蝏𤘪<EFBFBD>**嚗?
```json
{
"status": "ok",
@@ -392,7 +392,7 @@ curl https://iit.nat100.top/api/v1/iit/health
## <20><> <20>滨蔭皜<E894AD><E79A9C>
### 后端环境变量backend/.env
### <EFBFBD>𡒊垢<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗Ê̄ackend/.env嚗?
```env
# ==========================================
@@ -404,14 +404,14 @@ WECHAT_CORP_ID=ww6ab493470ab4f377
WECHAT_AGENT_ID=1000002
WECHAT_CORP_SECRET=AZIVxMtoLb0rEszXS81e4dBRl-I9kgTjygIS0cFfENU
# 企业微信回调配置(消息加解密)
# <EFBFBD><EFBFBD>敺桐縑<EFBFBD><EFBFBD><EFBFBD>滨蔭嚗<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗?
WECHAT_TOKEN=oXlRBm1YnvMy2SbDLbvAdDd5Gq3oBGq
WECHAT_ENCODING_AES_KEY=v88eT3O9bMW897h4btr7v7qvQImlMf31edTQCmuhOhO
```
### 隡<><E99AA1>敺桐縑摨𠉛鍂<F0A0899B>滨蔭
**应用信息**
**摨𠉛鍂靽⊥<EFBFBD>**嚗?
-<><E99AA1>ID嚗䫤ww6ab493470ab4f377`
- 摨𠉛鍂<F0A0899B>滨妍嚗䫤IIT Manager Agent`
- AgentID嚗䫤1000002`
@@ -423,9 +423,9 @@ Token: oXlRBm1YnvMy2SbDLbvAdDd5Gq3oBGq
EncodingAESKey: v88eT3O9bMW897h4btr7v7qvQImlMf31edTQCmuhOhO
```
**可信域名**
**<EFBFBD>臭縑<EFBFBD><EFBFBD>**嚗?
```
iit.xunzhengyixue.comSAE生产环境
iit.xunzhengyixue.com嚗𠄎AE<EFBFBD>煺漣<EFBFBD><EFBFBD>嚗?
```
### natapp <20>滨蔭
@@ -433,8 +433,8 @@ iit.xunzhengyixue.comSAE生产环境
```
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Online
<EFBFBD><EFBFBD>URL嚗冴ttp://iit.nat100.top
本地端口127.0.0.1:3001
HTTPS:自动支持
<EFBFBD>砍𧑐蝡臬藁嚗?27.0.0.1:3001
HTTPS嚗朞䌊<EFBFBD>冽𣈲<EFBFBD>?
```
---
@@ -443,64 +443,64 @@ HTTPS自动支持
| <20><>辣 | 隞<><E99A9E>銵峕㺭 | 銝餉<E98A9D><E9A489><EFBFBD> |
|------|---------|---------|
| WechatService.ts | 314行 | 企业微信消息推送 |
| WechatCallbackController.ts | 501行 | 企业微信回调处理 |
| index.ts质控Worker | +80行 | 质控完成后推送通知 |
| routes/index.ts | +48行 | 企业微信路由注册 |
| **总计** | **~943行** | 企业微信集成核心代码 |
| WechatService.ts | 314銵?| 隡<><E99AA1>敺桐縑瘨<E7B891><E798A8><EFBFBD><EFBFBD>?|
| WechatCallbackController.ts | 501銵?| 隡<><E99AA1>敺桐縑<E6A190><EFBFBD><EFBFBD><E686AD> |
| index.ts<EFBFBD><EFBFBD>orker嚗?| +80銵?| 韐冽綉摰峕<E691B0><E5B395>擧綫<E693A7><E7B6AB><EFBFBD>𡁶䰻 |
| routes/index.ts | +48銵?| 隡<><E99AA1>敺桐縑頝舐眏瘜典<E7989C> |
| **<EFBFBD>餉恣** | **~943銵?* | <EFBFBD><EFBFBD>敺桐縑<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> |
---
## ✅ 已完成的功能
## <EFBFBD>?撌脣<E6928C><E884A3><EFBFBD><E99E9F><EFBFBD>
- [x] 企业微信 Access Token 管理(缓存+刷新)
- [x] <EFBFBD><EFBFBD>敺桐縑 Access Token 蝞∠<EFBFBD><EFBFBD><EFBFBD>摮?<3F>瑟鰵嚗?
- [x] <20><EFBFBD><E785BE><EFBFBD><EFBFBD><EFBFBD><E7A586><EFBFBD><EFBFBD><E99AA1>敺桐縑
- [x] 发送 Markdown 消息到企业微信
- [x] 企业微信 URL 验证GET请求处理
- [x] 企业微信消息接收POST请求处理
- [x] 消息解密(使用 @wecom/crypto
- [x] 签名验证(使用 @wecom/crypto
- [x] 异步回复模式规避5秒超时
- [x] <EFBFBD><EFBFBD>?Markdown <EFBFBD><EFBFBD><EFBFBD><EFBFBD>銝𡁜凝靽?
- [x] <EFBFBD><EFBFBD>敺桐縑 URL 撉諹<E69289>嚗𠃑ET霂瑟<E99C82><EFBFBD><E686AD>嚗?
- [x] <EFBFBD><EFBFBD>敺桐縑瘨<EFBFBD><EFBFBD><EFBFBD>交𤣰嚗㇊OST霂瑟<EFBFBD><EFBFBD><EFBFBD>嚗?
- [x] <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?@wecom/crypto?
- [x] 蝑曉<EFBFBD>撉諹<EFBFBD><EFBFBD><EFBFBD>?@wecom/crypto?
- [x] <EFBFBD><EFBFBD>𧼮<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?蝘坿<E89D98><E59DBF><EFBFBD>
- [x] <20>喲睸霂齿<E99C82><E9BDBF><EFBFBD><E69B87><EFBFBD><EFBFBD><E79899><EFBFBD><E9A2AF><EFBFBD><EFBFBD><E68ABC><EFBFBD><E9B0B5><EFBFBD><EFBFBD><EFBFBD>
- [x] 韐冽綉Worker<65><EFBFBD><E588B8><EFBFBD>銝𡁜凝靽⊿<E99DBD>𡁶䰻
- [x] 摰∟恣<E2889F><EFBFBD>霈啣<E99C88>
- [x] natapp 内网穿透配置
- [x] natapp <EFBFBD><EFBFBD><EFBFBD>蝛輸<EFBFBD><EFBFBD>蝵?
---
## ⏳ 待完成的功能
## <EFBFBD>?敺<><E695BA><EFBFBD><EFBFBD><E99E9F><EFBFBD>
- [ ] 靽嘥<E99DBD><EFBFBD><E79487><EFBFBD><EFBFBD><EFBFBD>銝𡁜凝靽<E99DBD><EFBFBD>RL<52>滨蔭
- [ ] 配置数据库中的 `wechat_user_id`PI的企业微信UserID
- [ ] 端到端测试REDCap → 企微推送)
- [ ] LLM意图识别(升级关键词匹配)
- [ ] <EFBFBD>滨蔭<EFBFBD>唳旿摨㮖葉<EFBFBD>?`wechat_user_id`嚗㇊I<EFBFBD><EFBFBD><EFBFBD>銝𡁜凝靽serID嚗?
- [ ] 蝡臬<EFBFBD>蝡舀<EFBFBD>霂𤏪<EFBFBD>REDCap <20>?隡<><EFBFBD><EFBFBD><E588B8><EFBFBD>
- [ ] LLM<EFBFBD>誩㦛霂<EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝥批<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗?
- [ ] 撖寡<E69296><E5AFA1><EFBFBD><EFBFBD><E691B0><EFBFBD>凒憭帋<E686AD><E5B88B><E288AA><EFBFBD>
- [ ] IP<49><EFBFBD><E8B3A2><EFBFBD>蝵殷<E89DB5><E6AEB7>函蔡<E587BD>訕AE<41><EFBFBD>
---
## 🚀 下一步计划
## <EFBFBD><EFBFBD> 銝衤<E98A9D>甇亥恣<E4BAA5>?
### Day 3 銝见<E98A9D>/<2F><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
1. **保存企业微信正式配置**5分钟
1. **靽嘥<EFBFBD><EFBFBD><EFBFBD>敺桐縑甇<EFBFBD><EFBFBD><EFBFBD>滨蔭**嚗?<3F><><EFBFBD>嚗?
- <20><EFBFBD>銝𡁜凝靽∠恣<E288A0><E681A3><EFBFBD><EFBFBD><EFBFBD>摮睃<E691AE><EFBFBD>RL<52>滨蔭
- <20><EFBFBD><EFBFBD><EFBFBD>𦻖<EFBFBD><EFBFBD><EFBFBD><E798A8>蝐餃<E89D90>
2. **配置项目通知**10分钟
- 获取 PI 的企业微信 UserID
- 更新数据库 `projects` 表的 `notification_config` 字段
2. **<EFBFBD>滨蔭憿寧𤌍<EFBFBD>𡁶䰻**嚗?0<><30><EFBFBD>嚗?
- <EFBFBD><EFBFBD> PI <EFBFBD><EFBFBD><EFBFBD>銝𡁜凝靽?UserID
- <EFBFBD>湔鰵<EFBFBD>唳旿摨?`projects` 銵函<EFBFBD> `notification_config` 摮埈挾
3. **端到端测试**30分钟
- REDCap 中录入测试数据
3. **蝡臬<EFBFBD>蝡舀<EFBFBD>霂?*嚗?0<><30><EFBFBD>嚗?
- <EFBFBD>?REDCap 銝剖<EFBFBD><EFBFBD><EFBFBD>霂閙㺭<EFBFBD>?
- 撉諹<E69289><EFBFBD><E99AA1>敺桐縑<E6A190><EFBFBD>摰墧𧒄<E5A2A7>𡁶䰻
- 测试对话功能(发送"帮助"、"汇总"等关键词)
- 瘚贝<EFBFBD>撖寡<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?撣桀𨭌"<22>?瘙<><E79899>?蝑匧<E89D91><E58CA7><EFBFBD>嚗?
### Day 4嚗<34><E59A97>蝏凋<E89D8F><E5878B><EFBFBD>
1. **LLM<4C>誩㦛霂<E3A69B><E99C82>**
- 接入 DeepSeek 或其他 LLM
- 实现真正的 AI Agent 对话
- <EFBFBD><EFBFBD> DeepSeek <EFBFBD><EFBFBD>隞?LLM
- 摰䂿緵<EFBFBD><EFBFBD><EFBFBD>?AI Agent 撖寡<EFBFBD>
2. **<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**
- <20><EFBFBD>撖寡<E69296><E5AFA1>箸艶嚗<E889B6><EFBFBD>格䰻霂<E99C82><EFBCB5><EFBFBD><E99C88><E288AA><EFBFBD>
@@ -514,12 +514,12 @@ HTTPS自动支持
---
## 📖 参考文档
## <EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>獢?
- [<EFBFBD><EFBFBD>敺桐縑API<EFBFBD><EFBFBD>](https://developer.work.weixin.qq.com/document/path/90664)
- [隡<><E99AA1>敺桐縑瘨<E7B891><E798A8><EFBFBD>㰘圾撖<E59CBE><EFBFBD>筕(https://developer.work.weixin.qq.com/document/path/90968)
- [@wecom/crypto GitHub](https://github.com/wecomteam/crypto)
- [最小MVP闭环开发计划](../04-开发计划/最小MVP闭环开发计划.md)
- [<EFBFBD><EFBFBD>撠𦬅VP<EFBFBD>剔㴓撘<EFBFBD><EFBFBD>𤏸恣<EFBFBD>哋(../04-撘<><E69298>𤏸恣<F0A48FB8>?<3F><>撠𦬅VP<56>剔㴓撘<E3B493><E69298>𤏸恣<F0A48FB8>?md)
---
@@ -527,19 +527,20 @@ HTTPS自动支持
Day 3 <20><><EFBFBD><EFBFBD>穃極雿𡏭蒾<F0A18FAD><EFBFBD><E59C92><EFBFBD>憭帋葵<E5B88B><E891B5><EFBFBD>舫䔮憸矋<E686B8><EFBFBD><E99BBF><EFBFBD><E89D8F><EFBFBD><EFBFBD><E7AC94>𣂷<EFBFBD><EFBFBD><E99AA1>敺桐縑<E6A190><E7B891><EFBFBD><EFBFBD><EFBFBD>瓲敹<E793B2><E695B9><EFBFBD><EFBFBD><E8B3AC><EFBFBD><EFBFBD><EFBFBD><E99D9A>撌亙<E6928C><E4BA99><EFBFBD><EFBFBD><EFBFBD><E99C82><EFBFBD><E99C82><EFBFBD><E988AD>
1. **技术方案可行**@wecom/crypto 库正常工作
2. **架构设计合理**:异步回复模式有效规避超时问题
3. **代码质量良好**:详细的日志和错误处理
4. **开发流程完善**:问题排查→测试验证→文档记录
1. <EFBFBD>?**<2A><><EFBFBD>舀䲮獢<E4B2AE>虾銵?*嚗鋣wecom/crypto 摨𤘪迤撣詨極雿?
2. <EFBFBD>?**<2A><EFBFBD>霈曇恣<E69B87><E681A3><EFBFBD>**嚗𡁜<E59A97>甇亙<E79487>憭齿芋撘𤩺<E69298><F0A4A9BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E8BCAF>園䔮憸?
3. <EFBFBD>?**隞<><E99A9E>韐券<E99F90><E588B8>臬末**嚗朞祕蝏<E7A595><E89D8F><EFBFBD><EFBFBD><E4BA99><EFBFBD>霂臬<E99C82><E887AC>?
4. <EFBFBD>?**撘<><E69298><EFBFBD>蝔见<E89D94><E8A781>?*嚗𡁻䔮憸䀹<E686B8><E480B9><EFBFBD>瘚贝<E7989A>撉諹<E69289><E8ABB9><EFBFBD><EFBFBD>扇敶?
**距离完整的 MVP 闭环只差最后的端到端测试了!**
**頝萘氖摰峕㟲<EFBFBD>?MVP <20>剔㴓<E58994>芸榆<E88AB8><E6A686><EFBFBD>𡒊<EFBFBD>蝡臬<E89DA1>蝡舀<E89DA1>霂蓥<E99C82>嚗?*
---
**记录人**AI Assistant
**审核人**:开发团队
**霈啣<EFBFBD>鈭?*嚗鋫I Assistant
**摰⊥瓲鈭?*嚗𡁜<E59A97><F0A1819C>穃𣪧<E7A983>?
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𧋦**嚗鯝1.0
**最后更新**2026-01-02 23:55:00
**<EFBFBD><EFBFBD><EFBFBD>擧凒<EFBFBD>?*嚗?026-01-02 23:55:00

View File

@@ -1,10 +1,9 @@
# **IIT Manager Agent <20><><EFBFBD>舀䲮獢<E4B2AE><EFBFBD><EFBFBD>銵乩<E98AB5> (V1.1)**
## **1\. 架构修正:解决医院内网连通性**
## **1\. <EFBFBD><EFBFBD>靽格迤嚗朞圾<EFBFBD>喳龫<EFBFBD><EFBFBD>蝵𤏸<EFBFBD><EFBFBD>𡁏<EFBFBD>?*
针对 **风险一 (网络连通性)**,建议在 3.1 REDCap 集成 中增加 **"混合同步模式"**
### **新增模块SyncManager (同步管理器)**
<EFBFBD><EFBFBD> **憌𡡞埯銝<EFBFBD> (蝵𤑳<E89DB5>餈鮋<E9A488>𡁏<EFBFBD>?**嚗<>遣霈桀銁 3.1 REDCap <20><><EFBFBD> 銝剖<E98A9D><E58996>?**"瘛瑕<E7989B><E79195>峕郊璅<E79285>"**<EFBFBD>?
### **<2A><EFBFBD><E79285>嚗锭yncManager (<28>峕郊蝞∠<E89D9E><E288A0>?**
// backend/src/modules/iit-manager/services/SyncManager.ts
@@ -21,13 +20,13 @@ export class SyncManager {
}
/\*\*
\* 轮询任务处理器
\* 頧株砭隞餃𦛚憭<EFBFBD><EFBFBD><EFBFBD>?
\*/
async handlePoll(projectId: string) {
// 1\. <20><EFBFBD>銝𦠜活<F0A6A09C>峕郊<E5B395>園𡢿
const lastSync \= await this.getLastSyncTime(projectId);
// 2\. 调用 REDCap API 获取在此之后修改的记录
// 2\. <EFBFBD> REDCap API <EFBFBD><EFBFBD><EFBFBD>冽迨銋见<EFBFBD>靽格㺿<EFBFBD><EFBFBD>扇敶?
// API: 'export', content: 'record', dateRangeBegin: lastSync
const records \= await this.redcapAdapter.fetchModifiedRecords(projectId, lastSync);
@@ -42,39 +41,31 @@ export class SyncManager {
}
}
**修改建议**
**靽格㺿撱箄悅**嚗?
* <20>?MVP <20>嗆挾嚗?*<EFBFBD><EFBFBD>摰䂿緵頧株砭 (Polling)**<2A><><EFBFBD><EFBFBD><E996AC><EFBFBD>駁堺<E9A781><E5A0BA><EFBFBD>蝏𦦵㴓憓<E3B493><E68693>?
## **2\. <20><EFBFBD>銵亙<E98AB5>嚗𡁜<E59A97><F0A1819C>脫㺭<E884AB><EFBFBD><E6A180>𤩺醌<F0A4A9BA>?*
* 在 MVP 阶段,**务必实现轮询 (Polling)**。不要赌医院的网络环境。
## **2\. 功能补充:历史数据全量扫描**
针对 **风险二 (存量数据)**,建议利用现有的 CheckpointService 实现全量扫描。
### **新增 API全量质控触发**
<EFBFBD><EFBFBD>笆 **憌𡡞埯鈭?(摮㗛<E691AE><E3979B>唳旿)**嚗<>遣霈桀⏚<E6A180>函緵<E587BD><EFBFBD> CheckpointService 摰䂿緵<E482BF><EFBFBD><E588B8><EFBFBD><E680A5>?
### **<2A><EFBFBD> API嚗𡁜<E59A97><F0A1819C>讛捶<E8AE9B>扯圻<E689AF>?*
**Endpoint**: POST /api/v1/iit/projects/:id/scan-all
**逻辑实现 (复用现有 ASL/DC 模块的批处理经验)**
1. 调用 REDCap API 仅下载所有 record\_id (轻量级)。
2. 将 ID 列表分片 (Chunk),每片 50 个 ID。
3. 利用 pg-boss 推送 iit:quality-check:batch 任务。
4. Worker 逐个拉取完整数据并运行 Agent。
**<EFBFBD><EFBFBD>摰䂿緵 (憭滨鍂<E6BBA8><EFBFBD> ASL/DC 璅<E79285><E288AA><EFBFBD>鸌憭<E9B88C><E686AD>蝏誯<E89D8F>)**嚗?
1.<>鍂 REDCap API 隞<><E99A9E>頧賣<E9A0A7><E8B3A3>?record\_id (頧駁<E9A0A7>蝥?<3F>?
2. 撠?ID <20>𡑒”<F0A19192><E2809D><EFBFBD> (Chunk)嚗峕<E59A97><E5B395>?50 銝?ID<49>?
3. <EFBFBD>拍鍂 pg-boss <20><EFBFBD>?iit:quality-check:batch 隞餃𦛚<E9A483>?
4. Worker <20>𣂷葵<F0A382B7><EFBFBD>摰峕㟲<E5B395>唳旿撟嗉<E6929F>銵?Agent<6E>?
## **3\. <20>滨垢<E6BBA8><E59EA2><EFBFBD><EFBFBD><E88880>𡒊**
方案中提到了 "微信小程序",但未明确技术栈。考虑到你们现有的 React 基因:
* **推荐方案**:使用 **Taro** (React 语法) 开发小程序。
* **理由**
1. 可以让前端团队复用 React 知识Hooks, Components
2. 可以复用 shared/components 中的部分逻辑(如数据格式化)。
3. Taro 支持一键编译为 微信小程序 \+ H5 (用于企微侧边栏)**一鱼两吃**。
## **4\. 数据库 Schema 微调**
在 IitUserMapping 表中,建议增加 Token 字段,用于小程序 Session 维护。
<EFBFBD><EFBFBD>銝剜<EFBFBD><EFBFBD><EFBFBD> "敺桐縑撠讐<E692A0>摨?嚗䔶<E59A97><E494B6><EFBFBD>蝖格<E89D96><E6A0BC><EFBFBD><E88880><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>隞祉緵<E7A589><EFBFBD> React <EFBFBD><EFBFBD>嚗?
* **<2A><EFBFBD><E588BB><EFBFBD>**嚗帋蝙<E5B88B>?**Taro** (React 霂剜<E99C82>) 撘<><E69298><EFBFBD>蝔见<E89D94><E8A781>?
* **<2A><>眏**嚗?
1. <20>臭誑霈拙<E99C88>蝡臬𣪧<E887AC><EFBFBD><E7AC94>?React <20><EFBFBD>嚗𠃍ooks, Components嚗剹<E59A97>?
2. <EFBFBD>臭誑憭滨鍂 shared/components 銝剔<E98A9D><E58994><EFBFBD><E585B8><EFBFBD><EFBFBD><E59A97><EFBFBD>唳旿<E594B3><EFBFBD><E6BE86><EFBFBD><E59094>?
3. Taro <20><EFBFBD><EFBFBD><E98A9D><EFBFBD>霂睲蛹 敺桐縑撠讐<E692A0>摨?\+ H5 (<28><EFBFBD><EFBFBD>凝靘扯器<E689AF>?嚗?*銝<>敼潔舅<E6BD94>?*<2A>?
## **4\. <20>唳旿摨?Schema 敺株<E695BA>**
<EFBFBD>?IitUserMapping 銵其葉嚗<E89189>遣霈桀<E99C88><E6A180>?Token 摮埈挾嚗𣬚鍂鈭𤾸<E988AD>蝔见<E89D94> Session 蝏湔擪<E6B994>?
model IitUserMapping {
// ... <20><EFBFBD>摮埈挾
@@ -85,21 +76,17 @@ model IitUserMapping {
@@index(\[miniProgramOpenId\])
}
## **5\. Dify RAG 性能优化 (预加载)**
PRD 提到 "Protocol 往往很长"。
* **风险**:每次质控都让 Dify 重新检索整个 PDF速度慢且 Token 消耗大。
* **优化**:在 ProtocolService 中增加 **"关键规则缓存"**。
* 在上传 Protocol 后,让 Agent 预先提取出 "入排标准" (Inclusion/Exclusion Criteria) 并存入 PostgreSQL JSONB 字段。
* 在做基础质控时,优先匹配 DB 里的规则,匹配不到再由 Agent 去 RAG 检索。
## **5\. Dify RAG <EFBFBD><EFBFBD>隡睃<EFBFBD> (憸<><E686B8>頧?**
PRD <20>𣂼<EFBFBD> "Protocol 敺<><EFBFBD><EFBFBD>鵭"<22>?
* **憌𡡞埯**嚗𡁏<E59A97>甈∟捶<E2889F><EFBFBD>霈?Dify <20>齿鰵璉<E9B0B5>㟲銝?PDF嚗屸<E59A97>笔漲<E7AC94><EFBFBD> Token 瘨<><E798A8>堒之<E5A092>?
* **隡睃<E99AA1>**嚗𡁜銁 ProtocolService 銝剖<E98A9D><E58996>?**"<22>喲睸閫<E79DB8><E996AB>蝻枏<E89DBB>"**<2A>?
* <20><EFBFBD>隡?Protocol <20>𠬍<EFBFBD>霈?Agent 憸<><E686B8><EFBFBD>𣂼<EFBFBD><F0A382BC>?"<22><EFBFBD><E4BAA4><EFBFBD><EFBFBD>" (Inclusion/Exclusion Criteria) 撟嗅<E6929F><E59785>?PostgreSQL JSONB 摮埈挾<E59F88>?
* <20><EFBFBD><E585B8><EFBFBD>韐冽綉<E586BD><EFBFBD>隡睃<E99AA1><E79D83><EFBFBD> DB <20>𣬚<EFBFBD><EFBFBD><E996AB><EFBFBD><EFBFBD><EFBFBD><E6BBA2><EFBFBD><E595A3>?Agent <20>?RAG 璉<><E89D9D>?
## **蝏栞捏**
**此方案 V1.0 可以通过评审,但必须补充上述 "Plan B" (轮询机制)**
**开发优先级调整建议**
1. **Day 1**: 数据库 & 基础架构 (不变)
2. **Day 2**: **优先实现 REDCap API Adapter (拉取能力)**,而不是 Webhook (推送能力)。因为 API 拉取更可控,且能解决历史数据问题。
3. **Day 3**: Webhook 补充实现 (作为即时性增强)。
**甇斗䲮獢?V1.0 <20>臭誑<E887AD><EFBFBD><EFBFBD>恣嚗䔶<E59A97><EFBFBD>◆銵亙<E98AB5>銝𡃏膩 "Plan B" (頧株砭<EFBFBD><EFBFBD>)**<EFBFBD>?
**撘<><E69298><EFBFBD><E79DB2><EFBFBD>漣靚<E6BCA3>㟲撱箄悅**嚗?
1. **Day 1**: <20>唳旿摨?& <20><EFBFBD><E7AE87><EFBFBD> (銝滚<E98A9D>)
2. **Day 2**: **隡睃<E99AA1>摰䂿緵 REDCap API Adapter (<28><EFBFBD><E58CA7><EFBFBD>)**嚗諹<E59A97><EFBFBD><E494B6>?Webhook (<28><EFBFBD><E588B8><EFBFBD><EFBFBD>?<3F><><EFBFBD>銝?API <20><EFBFBD><E58CA7>游虾<E6B8B8><EFBFBD>銝磰<E98A9D><EFBFBD><E996AB><EFBFBD><EFBFBD><EFBFBD>唳旿<E594B3><EFBFBD><E6A185>?
3. **Day 3**: Webhook 銵亙<E98AB5>摰䂿緵 (雿靝蛹<E99D9D>單𧒄<E596AE><EFBFBD>撘?<3F>

View File

@@ -1,20 +1,20 @@
# Phase 1.5: AI对话集成REDCap真实数据查询 - 开发完成记录
# Phase 1.5: AI瀵硅瘽闆嗘垚REDCap鐪熷疄鏁版嵁鏌ヨ<EFBFBD> - 寮€鍙戝畬鎴愯<E98EB4>褰?
**开发日期**: 2026-01-03
**开发人员**: AI Clinical Research Team
**寮€鍙戞棩鏈?*: 2026-01-03
**寮€鍙戜汉鍛?*: AI Clinical Research Team
**鐗堟湰**: Phase 1.5
**状态**: ✅ 已完成
**鐘舵€?*: 鉁?宸插畬鎴?
---
## 📋 **开发目标**
## 馃搵 **寮€鍙戠洰鏍?*
实现AI在企业微信中基于REDCap真实数据与PI进行智能对话解决LLM幻觉问题。
瀹炵幇AI鍦ㄤ紒涓氬井淇腑鍩轰簬REDCap鐪熷疄鏁版嵁涓嶱I杩涜<EFBFBD>鏅鸿兘瀵硅瘽锛岃В鍐矻LM骞昏<EFBFBD><EFBFBD><EFBFBD>銆?
### **核心需求**
### **鏍稿績闇€姹?*
1. AI鑳藉<E991B3>鏌ヨ<E98F8C>REDCap鐪熷疄鏁版嵁
2. AI涓嶇紪閫犳暟鎹<E69A9F>紝鍩轰簬浜嬪疄鍥炵瓟
3. 支持多轮对话上下文记忆
3. <EFBFBD>寔澶氳疆瀵硅瘽涓婁笅鏂囪<EFBFBD>蹇?
4. 鎻愪緵鍗虫椂"姝湪鏌ヨ<E98F8C>"鍙嶉<E98D99>
---
@@ -22,69 +22,69 @@
## 馃幆 **瀹屾垚鍔熻兘**
### **1. 鎰忓浘璇嗗埆**
- **查询特定记录**: 识别记录ID如"ID 7"、"记录7"
- **统计记录数**: 识别"多少"、"几个"、"几条"等关键词
- **项目信息**: 识别"项目名称"、"项目情况"等
- **普通对话**: 默认处理其他对话
- 鉁?**鏌ヨ<E98F8C>鐗瑰畾璁板綍**: 璇嗗埆璁板綍ID锛堝<EFBFBD>"ID 7"銆?璁板綍7"锛?
- 鉁?**缁熻<E7BC81>璁板綍鏁?*: 璇嗗埆"澶氬皯"銆?鍑犱釜"銆?鍑犳潯"绛夊叧閿<E58FA7>
- 鉁?**椤圭洰淇℃伅**: 璇嗗埆"椤圭洰鍚嶇О"銆?椤圭洰鎯呭喌"绛?
- 鉁?**鏅<>€氬<E282AC>璇?*: 榛樿<E6A69B>澶勭悊鍏朵粬瀵硅瘽
**实现方式**: 关键词匹配 + 正则表达式
**瀹炵幇鏂瑰紡**: 鍏抽敭璇嶅尮閰?+ 姝e垯琛ㄨ揪寮?
### **2. REDCap鏁版嵁鏌ヨ<E98F8C>**
- **queryRedcapRecord()**: 查询特定记录的详细信息
- **countRedcapRecords()**: 统计总记录数
- **getProjectInfo()**: 获取项目基本信息
- 鉁?**queryRedcapRecord()**: 鏌ヨ<EFBFBD>鐗瑰畾璁板綍鐨勮<EFBFBD>缁嗕俊鎭?
- 鉁?**countRedcapRecords()**: 缁熻<EFBFBD>鎬昏<EFBFBD>褰曟暟
- 鉁?**getProjectInfo()**: 鑾峰彇椤圭洰鍩烘湰淇℃伅
**数据来源**: 数据库 `iit_schema.projects` 表 → RedcapAdapter REDCap API
**鏁版嵁鏉ユ簮**: 鏁版嵁搴?`iit_schema.projects` 琛?鈫?RedcapAdapter 鈫?REDCap API
### **3. 鏁版嵁娉ㄥ叆LLM**
- ✅ 将查询结果注入System消息
- ✅ 新的System Prompt强调"基于真实数据,不编造"
- ✅ 错误处理:查询失败时友好提示
- 鉁?灏嗘煡璇㈢粨鏋滄敞鍏<E6959E>ystem娑堟伅
- 鉁?鏂扮殑System Prompt寮鸿皟"鍩轰簬鐪熷疄鏁版嵁锛屼笉缂栭€?
- 鉁?閿欒<E996BF>澶勭悊锛氭煡璇㈠け璐ユ椂鍙嬪ソ鎻愮ず
### **4. 上下文记忆**
- SessionMemory保存最近3轮对话
- ✅ 支持多轮对话理解(如"他"指代之前提到的患者)
### **4. 涓婁笅鏂囪<EFBFBD>蹇?*
- 鉁?SessionMemory淇濆瓨鏈€杩?杞<><E69D9E>璇?
- 鉁?鏀<>寔澶氳疆瀵硅瘽鐞嗚В锛堝<E9949B>"浠?鎸囦唬涔嬪墠鎻愬埌鐨勬偅鑰咃級
### **5. 鍗虫椂鍙嶉<E98D99>**
- ✅ 收到消息后立即回复"🫡 正在查询,请稍候..."
- ✅ 查询完成后推送最终结果
- 鉁?鏀跺埌娑堟伅鍚庣珛鍗冲洖澶?馃<>湪鏌ヨ<E98F8C>锛岃<E9949B>绋嶅€?.."
- 鉁?鏌ヨ<E98F8C>瀹屾垚鍚庢帹閫佹渶缁堢粨鏋?
---
## 🏗️ **技术架构**
## 馃彈锔?**鎶€鏈<E282AC>灦鏋?*
### **数据流**
### **鏁版嵁娴?*
```
鐢ㄦ埛娑堟伅锛堜紒涓氬井淇★級
鈫?
WechatCallbackController.handleMessage()
鈫?
ChatService.handleMessage()
鈫?
1. detectIntent() - 鎰忓浘璇嗗埆
鈫?
2. queryRedcapRecord() / countRedcapRecords() / getProjectInfo()
鈫?
prisma.iitProject.findFirst() - 浠庢暟鎹<E69A9F>簱鑾峰彇椤圭洰閰嶇疆
new RedcapAdapter(url, token) - 创建API适配器
鈫?
new RedcapAdapter(url, token) - 鍒涘缓API閫傞厤鍣?
鈫?
redcap.exportRecords() - 璋冪敤REDCap API
鈫?
杩斿洖鐪熷疄鏁版嵁
鈫?
3. buildMessagesWithData() - 鏋勫缓LLM娑堟伅锛堟敞鍏ユ暟鎹<E69A9F>
鈫?
4. llm.chat() - 璋冪敤DeepSeek-V3
鈫?
5. sessionMemory.addMessage() - 璁板綍鍒颁笂涓嬫枃
鈫?
AI鍥炲<EFBFBD>锛堜紒涓氬井淇★級
```
### **鍏抽敭浠g爜**
- **ChatService.ts**: 390琛岋紝鏂板<E98F82>REDCap鏌ヨ<E98F8C>鏂规硶
- **意图识别**: detectIntent(),正则匹配
- **鎰忓浘璇嗗埆**: detectIntent()锛屾<EFBFBD>鍒欏尮閰?
- **鏁版嵁娉ㄥ叆**: buildMessagesWithData()
- **System Prompt**: getSystemPromptWithData()
@@ -94,140 +94,140 @@ AI回复企业微信
### **娴嬭瘯鐜<E798AF><E9909C>**
- **椤圭洰**: test0102 (REDCap PID: 16)
- **记录数**: 10条(ID 1-10
- **璁板綍鏁?*: 10鏉★紙ID 1-10锛?
- **娴嬭瘯鐢ㄦ埛**: FengZhiBo
- **娴嬭瘯鏃堕棿**: 2026-01-03 22:28
### **测试场景1: 查询特定记录**
### **娴嬭瘯鍦烘櫙1: 鏌ヨ<E98F8C>鐗瑰畾璁板綍** 鉁?
**鐢ㄦ埛杈撳叆**:
```
帮我查询一下 记录 7的 所有信息
<EFBFBD>垜鏌ヨ<EFBFBD>涓€涓?璁板綍 7鐨?鎵€鏈変俊鎭?
```
**AI鍥炲<E98DA5>** (鍩轰簬鐪熷疄鏁版嵁):
```
根据REDCap查询结果记录7的信息如下
鏍规嵁REDCap鏌ヨ<EFBFBD>缁撴灉锛岃<EFBFBD>褰?鐨勪俊鎭<E4BF8A><E98EAD>涓嬶細
**鍩烘湰淇℃伅**
- 姓名企业微信7 企业微信7
- 出生日期2017-01-04
- 年龄8岁
- 濮撳悕锛氫紒涓氬井淇? 浼佷笟寰<E7AC9F>7
- 鍑虹敓鏃ユ湡锛?017-01-04
- 骞撮緞锛?宀?
- 鎬у埆锛氱敺
- 身高130 cm
- 体重50 kg
- BMI29.6
- <EFBFBD>珮锛?30 cm
- 浣撻噸锛?0 kg
- BMI锛?9.6
**鑱旂郴鏂瑰紡**
- 地址企业微信7
- 鍦板潃锛氫紒涓氬井淇?
- 閭<><E996AD>锛歡ofeng117@163.com
**鍏朵粬淇℃伅**
- 民族:西班牙裔或拉丁裔
- 姘戞棌锛氳タ鐝<EFBFBD>墮瑁旀垨鎷変竵瑁?
- 娌荤枟鍙诧細娴嬭瘯7777
- 鏄<>惁瀹屾垚锛氭槸
所有字段均已填写完成。如需查看完整表单建议登录REDCap系统。
鎵€鏈夊瓧娈靛潎宸插鍐欏畬鎴愩€傚<EFBFBD>闇€鏌ョ湅瀹屾暣琛ㄥ崟锛屽缓璁<EFBFBD>櫥褰昍EDCap绯荤粺銆?
```
**数据验证**: ✅ 完全匹配REDCap数据库
**鏁版嵁楠岃瘉**: 鉁?瀹屽叏鍖归厤REDCap鏁版嵁搴?
### **娴嬭瘯鍦烘櫙2: 缁熻<E7BC81>鏌ヨ<E98F8C>** (棰勬湡)
**鐢ㄦ埛杈撳叆**: "鎴戜滑绯荤粺涓<E7B2BA>凡缁忔湁鍑犳潯璁板綍浜嗭紵"
**预期回复**: "当前项目test0102已有 **10条** 患者数据记录"
**棰勬湡鍥炲<EFBFBD>**: "褰撳墠椤圭洰test0102宸叉湁 **10鏉?* 鎮€呮暟鎹<E69A9F><E98EB9>褰?
### **娴嬭瘯鍦烘櫙3: 椤圭洰淇℃伅** (棰勬湡)
**鐢ㄦ埛杈撳叆**: "鍜变滑褰撳墠鐨勯」鐩<E3808D>悕绉版槸浠€涔堬紵"
**预期回复**: "当前项目名称为 **test0102**"
**棰勬湡鍥炲<EFBFBD>**: "褰撳墠椤圭洰鍚嶇О涓?**test0102**"
### **鎬ц兘鎸囨爣**
- 鈴憋笍 **API鏌ヨ<E98F8C>**: 300-700ms
- ⏱️ **LLM响应**: 2-3
- ⏱️ **总响应时间**: 3-5
- 📊 **Token消耗**: 约500 tokens/
- 鈴憋笍 **LLM鍝嶅簲**: 2-3绉?
- 鈴憋笍 **鎬诲搷搴旀椂闂?*: 3-5绉?
- 馃搳 **Token娑堣€?*: 绾?00 tokens/娆?
---
## 馃啔 **瀵规瘮锛氳В鍐矻LM骞昏<E9AA9E>**
### **之前(编造数据)**
### **涔嬪墠锛堢紪閫犳暟鎹<EFBFBD>** 鉂?
```
AI: "ID 7的入组日期为 **2023-10-26**(即基线访视日期)"
❌ 完全编造
❌ 与真实数据不符
❌ 项目名称编造为"IIT-2023-001: XX干预对YY疾病..."
AI: "ID 7鐨勫叆缁勬棩鏈熶负 **2023-10-26**锛堝嵆鍩虹嚎璁胯<EFBFBD>鏃ユ湡锛?
鉂?瀹屽叏缂栭€?
鉂?涓庣湡瀹炴暟鎹<E69A9F>笉绗?
鉂?椤圭洰鍚嶇О缂栭€犱负"IIT-2023-001: XX骞查<EFBFBD>瀵筜Y鐤剧梾..."
```
### **现在(真实数据)**
### **鐜板湪锛堢湡瀹炴暟鎹<EFBFBD>** 鉁?
```
AI: "出生日期2017-01-04
年龄8岁
身高130 cm
体重50 kg"
100%真实
✅ 来自REDCap数据库
✅ 项目名称为test0102(真实)
AI: "鍑虹敓鏃ユ湡锛?017-01-04
骞撮緞锛?宀?
<EFBFBD>珮锛?30 cm
浣撻噸锛?0 kg"
鉁?100%鐪熷疄
鉁?鏉ヨ嚜REDCap鏁版嵁搴?
鉁?椤圭洰鍚嶇О涓簍est0102锛堢湡瀹烇級
```
---
## 💡 **技术亮点**
## 馃挕 **鎶€鏈<EFBFBD>寒鐐?*
### **1. 鏋舵瀯璁捐<E79281>**
- **从数据库读取配置**: 不使用环境变量,支持多项目
- **复用通用能力层**: LLMFactory零配置集成
- **分层清晰**: Controller Service Adapter API
- 鉁?**浠庢暟鎹<E69A9F>簱璇诲彇閰嶇疆**: 涓嶄娇鐢ㄧ幆澧冨彉閲忥紝鏀<EFBFBD>寔澶氶」鐩?
- 鉁?**澶嶇敤閫氱敤鑳藉姏灞?*: LLMFactory闆堕厤缃<EFBFBD>泦鎴?
- 鉁?**鍒嗗眰娓呮櫚**: Controller 鈫?Service 鈫?Adapter 鈫?API
### **2. 鎰忓浘璇嗗埆**
- **简单有效**: 关键词匹配 + 正则表达式
- **扩展性好**: 易于添加新意图
- **性能优秀**: <1ms识别时间
- 鉁?**绠€鍗曟湁鏁?*: 鍏抽敭璇嶅尮閰?+ 姝e垯琛ㄨ揪寮?
- 鉁?**鎵╁睍鎬уソ**: 鏄撲簬娣诲姞鏂版剰鍥?
- 鉁?**鎬ц兘浼樼<E6B5BC>**: <1ms璇嗗埆鏃堕棿
### **3. 鏁版嵁瀹夊叏**
- **Token加密存储**: 数据库中加密
- **动态获取**: 每次查询时从数据库读取
- **权限控制**: 基于项目状态过滤
- 鉁?**Token鍔犲瘑瀛樺偍**: 鏁版嵁搴撲腑鍔犲瘑
- 鉁?**鍔ㄦ€佽幏鍙?*: 姣忔<E5A7A3>鏌ヨ<E98F8C>鏃朵粠鏁版嵁搴撹<E690B4>鍙?
- 鉁?**鏉冮檺鎺у埗**: 鍩轰簬椤圭洰鐘舵€佽繃婊?
### **4. 鐢ㄦ埛浣撻獙**
- **即时反馈**: "正在查询"消息
- **准确回答**: 基于真实数据
- **上下文连贯**: 支持多轮对话
- 鉁?**鍗虫椂鍙嶉<E98D99>**: "湪鏌ヨ<EFBFBD>"娑堟伅
- 鉁?**鍑嗙‘鍥炵瓟**: 鍩轰簬鐪熷疄鏁版嵁
- 鉁?**涓婁笅鏂囪繛璐?*: 鏀<>寔澶氳疆瀵硅瘽
---
## 馃搳 **浠爜缁熻<E7BC81>**
### **鏂板<E98F82>鏂囦欢**
1. `SessionMemory.ts` - 170行 (上下文记忆)
2. `test-redcap-query-from-db.ts` - 250行 (测试脚本)
3. `check-test-project-in-db.ts` - 74行 (项目检查)
1. `SessionMemory.ts` - 170琛?(涓婁笅鏂囪<E98F82>蹇?
2. `test-redcap-query-from-db.ts` - 250琛?(娴嬭瘯鑴氭湰)
3. `check-test-project-in-db.ts` - 74琛?(椤圭洰妫€鏌?
### **淇<>敼鏂囦欢**
1. `ChatService.ts` - 新增200(REDCap集成)
1. `ChatService.ts` - 鏂板<EFBFBD>200琛?(REDCap闆嗘垚)
2. `WechatCallbackController.ts` - 鏂板<E98F82>鍗虫椂鍙嶉<E98D99>
3. `routes/index.ts` - 新增根路由
3. `routes/index.ts` - 鏂板<EFBFBD>鏍硅矾鐢?
### **鍒犻櫎鏂囦欢**
1. `test-redcap-query-for-ai.ts` (浣跨敤鐜<E695A4><E9909C>鍙橀噺锛屽凡搴熷純)
2. `check-env-config.ts` (环境变量检查,已废弃)
2. `check-env-config.ts` (<EFBFBD><EFBFBD>鍙橀噺妫€鏌ワ紝宸插簾寮?
---
## 鈿狅笍 **褰撳墠闄愬埗**
### **1. 鎰忓浘璇嗗埆**
- ❌ 仅支持关键词匹配
- ❌ 不支持复杂查询组合
- ❌ 不支持模糊匹配
- 鉂?浠呮敮鎸佸叧閿<E58FA7>瘝鍖归厤
- 鉂?涓嶆敮鎸佸<E98EB8>鏉傛煡璇㈢粍鍚?
- 鉂?涓嶆敮鎸佹ā绯婂尮閰?
### **2. 鏁版嵁鏌ヨ<E98F8C>**
- ❌ 仅支持单项目默认active项目
- ❌ 不支持字段名中文映射
- ❌ 不支持复杂过滤条件
- 鉂?浠呮敮鎸佸崟椤圭洰锛堥粯璁<E7B2AF>ctive椤圭洰锛?
- 鉂?涓嶆敮鎸佸瓧娈靛悕涓<E68295>枃鏄犲皠
- 鉂?涓嶆敮鎸佸<E98EB8>鏉傝繃婊ゆ潯浠?
### **3. 上下文记忆**
- ❌ 仅保存最近3轮对话
- ❌ 基于内存,服务重启丢失
- ❌ 不支持跨会话记忆
### **3. 涓婁笅鏂囪<EFBFBD>蹇?*
- 鉂?浠呬繚瀛樻渶杩?杞<><E69D9E>璇?
- 鉂?鍩轰簬鍐呭瓨锛屾湇鍔¢噸鍚<E599B8>涪澶?
- 鉂?涓嶆敮鎸佽法浼氳瘽璁板繂
---
@@ -235,9 +235,9 @@ AI: "出生日期2017-01-04
### **鐭<>湡浼樺寲**
1. **鎵╁睍鎰忓浘璇嗗埆**: 鏀<>寔鏇村<E98F87>鏌ヨ<E98F8C>妯″紡
2. **字段映射**: 中文字段名 → REDCap字段名
2. **瀛楁<EFBFBD>鏄犲皠**: <EFBFBD>枃瀛楁<EFBFBD>鍚?鈫?REDCap瀛楁<EFBFBD>鍚?
3. **閿欒<E996BF>浼樺寲**: 鏇村弸濂界殑閿欒<E996BF>鎻愮ず
4. **多项目支持**: 用户选择查询哪个项目
4. **澶氶」鐩<EFBFBD>敮鎸?*: 鐢ㄦ埛閫夋嫨鏌ヨ<E98F8C><EFBFBD>釜椤圭洰
### **涓<>湡鍗囩骇 (Phase 2)**
1. **Function Calling**: 鍗囩骇涓篖LM鑷<4D>富鍐崇瓥璋冪敤宸ュ叿
@@ -246,52 +246,52 @@ AI: "出生日期2017-01-04
4. **鎬ц兘鐩戞帶**: 璁板綍鏌ヨ<E98F8C>鑰楁椂銆侀敊璇<E6958A>
### **闀挎湡瑙勫垝**
1. **Dify知识库**: 查询研究方案、伦理文件
1. **Dify鐭ヨ瘑搴?*: 鏌ヨ<E98F8C>鐮旂┒鏂规<E98F82>銆佷鸡鐞嗘枃浠?
2. **鏅鸿兘璐ㄦ帶**: AI鍒嗘瀽鏁版嵁璐ㄩ噺闂<E599BA><E99782>
3. **H5鍓嶇<E98D93>**: 鏇翠赴瀵岀殑浜や簰浣撻獙
4. **多模态**: 支持图片、文档上传
4. **澶氭ā鎬?*: 鏀<>寔鍥剧墖銆佹枃妗笂浼?
---
## 馃摑 **鎶€鏈<E282AC>€哄姟**
### **1. 涓存椂鎺<E6A482>柦**
- ⚠️ 使用关键词匹配(应升级为Function Calling
- ⚠️ SessionMemory基于内存(应改为Redis
- ⚠️ 默认查询第一个active项目应支持项目选择
- 鈿狅笍 浣跨敤鍏抽敭璇嶅尮閰嶏紙搴斿崌绾т负Function Calling锛?
- 鈿狅笍 SessionMemory鍩轰簬鍐呭瓨锛堝簲鏀逛负Redis锛?
- 鈿狅笍 榛樿<E6A69B>鏌ヨ<E98F8C><EFBFBD>竴涓猘ctive椤圭洰锛堝簲鏀<E7B0B2>寔椤圭洰閫夋嫨锛?
### **2. 待实现功能**
- [ ] 字段名中文映射
### **2. 寰呭疄鐜板姛鑳?*
- [ ] 瀛楁<EFBFBD>鍚嶄腑鏂囨槧灏?
- [ ] 澶嶆潅鏌ヨ<E98F8C>
- [ ] 鏁版嵁缂撳瓨鏈哄埗
- [ ] 鏉冮檺鎺у埗
---
## 🎯 **里程碑意义**
## 馃幆 **閲岀▼纰戞剰涔?*
### **技术突破**
1. **解决LLM幻觉**: AI不再编造数据
2. **数据闭环**: 数据库 → REDCap AI → 用户
3. **架构验证**: 从数据库读取配置的方案可行
### **鎶€鏈<EFBFBD>獊鐮?*
1. 鉁?**瑙喅LLM骞昏<E9AA9E>**: AI涓嶅啀缂栭€犳暟鎹?
2. 鉁?**鏁版嵁闂<E5B581>**: 鏁版嵁搴?鈫?REDCap 鈫?AI 鈫?鐢ㄦ埛
3. 鉁?**鏋舵瀯楠岃瘉**: 浠庢暟鎹<EFBFBD>簱璇诲彇閰嶇疆鐨勬柟妗堝彲琛?
### **业务价值**
1. **提升效率**: PI无需登录REDCap即可查询数据
2. **增强信任**: AI基于事实回答,可信赖
3. **改善体验**: 企业微信直接对话,便捷
### **涓氬姟浠峰€?*
1. 鉁?**鎻愬崌鏁堢巼**: PI鏃犻渶鐧诲綍REDCap鍗冲彲鏌ヨ<EFBFBD>鏁版嵁
2. 鉁?**澧炲己淇′换**: AI鍩轰簬浜嬪疄鍥炵瓟锛屽彲淇¤禆
3. 鉁?**鏀瑰杽浣撻獙**: 浼佷笟寰<EFBFBD>俊鐩存帴瀵硅瘽锛屼究鎹?
### **鍥㈤槦鎴愰暱**
1. **架构能力**: 理解分层架构的重要性
2. **问题解决**: 从环境变量到数据库配置的演进
3. **测试驱动**: 先测试REDCap API,再集成AI
1. 鉁?**鏋舵瀯鑳藉姏**: 鐞嗚В鍒嗗眰鏋舵瀯鐨勯噸瑕佹€?
2. 鉁?**闂<><E99782>**: 浠庣幆澧冨彉閲忓埌鏁版嵁搴撻厤缃<EFBFBD>殑婕旇繘
3. 鉁?**娴嬭瘯椹卞姩**: 鍏堟祴璇昍EDCap API锛屽啀闆嗘垚AI
---
## 馃檹 **鑷磋阿**
鎰熻阿鍥㈤槦鎴愬憳鐨勮緵鍕や粯鍑猴細
- **需求分析**: 明确AI对话的核心价值
- **架构设计**: 选择从数据库读取配置的方案
- **闇€姹傚垎鏋?*: 鏄庣AI瀵硅瘽鐨勬牳蹇冧环鍊?
- **鏋舵瀯璁捐<EFBFBD>**: 閫夋嫨浠庢暟鎹<E69A9F>簱璇诲彇閰嶇疆鐨勬柟妗?
- **浠g爜瀹炵幇**: 楂樿川閲忕殑浠g爜鍜屾竻鏅扮殑娉ㄩ噴
- **娴嬭瘯楠岃瘉**: 瀹屾暣鐨勬祴璇曠敤渚嬪拰鐪熷疄鍦烘櫙楠岃瘉
@@ -299,16 +299,17 @@ AI: "出生日期2017-01-04
## 馃摎 **鐩稿叧鏂囨。**
- [Phase 1.5开发计划](../04-开发计划/Phase1.5-AI对话能力开发计划.md)
- [MVP任务清单](../04-开发计划/MVP开发任务清单.md)
- [模块当前状态](../00-模块当前状态与开发指南.md)
- [Phase 1.5寮€鍙戣<EFBFBD>鍒抅(../04-寮€鍙戣<E98D99>鍒?Phase1.5-AI瀵硅瘽鑳藉姏寮€鍙戣<E98D99>鍒?md)
- [MVP浠诲姟娓呭崟](../04-寮€鍙戣<EFBFBD>鍒?MVP寮€鍙戜换鍔℃竻鍗?md)
- [妯″潡褰撳墠鐘舵€乚(../00-妯″潡褰撳墠鐘舵€佷笌寮€鍙戞寚鍗?md)
- [Day 3寮€鍙戣<E98D99>褰昡(./Day3-浼佷笟寰<E7AC9F>俊闆嗘垚涓庣<E6B693>鍒扮<E98D92>娴嬭瘯瀹屾垚璁板綍.md)
---
**文档维护**: 开发团队
**最后更新**: 2026-01-03
**下一步**: Phase 2 - Function Calling + Dify知识库
**鏂囨。缁存姢**: 寮€鍙戝洟闃?
**鏈€鍚庢洿鏂?*: 2026-01-03
**涓嬩竴姝?*: Phase 2 - Function Calling + Dify鐭ヨ瘑搴?

View File

@@ -1,61 +1,61 @@
# IIT Manager Agent 技术方案 V1.1 更新完成报告
# IIT Manager Agent 鎶€鏈<EFBFBD>柟妗?V1.1 鏇存柊瀹屾垚鎶ュ憡
> **更新日期:** 2025-12-31
> **更新人员:** AI助手
> **审查依据:** `IIT Manager Agent 技术方案审查与补丁.md`
> **鏇存柊鏃ユ湡锛?* 2025-12-31
> **鏇存柊浜哄憳锛?* AI鍔╂墜
> **瀹℃煡渚濇嵁锛?* `IIT Manager Agent 鎶€鏈<EFBFBD>柟妗堝<EFBFBD>鏌ヤ笌琛ヤ竵.md`
---
## ✅ 更新完成
## 鉁?鏇存柊瀹屾垚
已成功将技术方案从 V1.0 升级到 V1.1,整合了架构评审的所有修正意见。
宸叉垚鍔熷皢鎶€鏈<EFBFBD>柟妗堜粠 V1.0 鍗囩骇鍒?V1.1锛屾暣鍚堜簡鏋舵瀯璇勫<EFBFBD>鐨勬墍鏈変慨姝剰瑙併€?
**更新文件**
- `02-技术设计/IIT Manager Agent 完整技术开发方案 (V1.1).md`2100+行)
**鏇存柊鏂囦欢**锛?
- `02-鎶€鏈<EFBFBD><EFBFBD>璁?IIT Manager Agent 瀹屾暣鎶€鏈<EFBFBD>紑鍙戞柟妗?(V1.1).md`锛?100+琛岋級
---
## 🔥 核心修正3大致命问题已解决
## 馃敟 鏍稿績淇<E7B8BE><E6B787>锛?澶ц嚧鍛介棶棰樺凡瑙e喅锛?
### 1. ✅ 网络连通性风险(致命级)- 已修正
### 1. 鉁?缃戠粶杩為€氭€ч<E282AC>闄╋紙鑷村懡绾э級- 宸蹭慨姝?
**问题**
- V1.0完全依赖Webhook推送
**<EFBFBD><EFBFBD>**锛?
- V1.0瀹屽叏渚濊禆Webhook鎺ㄩ€?
- 鍖婚櫌鍐呯綉REDCap鏃犳硶涓诲姩璁块棶鍏<E6A3B6>綉SAE
- Webhook机制会完全失效
- Webhook鏈哄埗浼氬畬鍏ㄥけ鏁?
**修正方案**
- ✅ 新增 `SyncManager`(混合同步模式)
- ✅ 优先使用Webhook实时性
- ✅ 定时轮询作为兜底(可靠性)
- ✅ 智能自适应:自动选择最佳模式
**<EFBFBD><EFBFBD>鏂规<EFBFBD>**锛?
- 鉁?鏂板<E98F82> `SyncManager`锛堟贩鍚堝悓姝ユā寮忥級
- 鉁?浼樺厛浣跨敤Webhook锛堝疄鏃舵€э級
- 鉁?瀹氭椂杞<E6A482><E69D9E>浣滀负鍏滃簳锛堝彲闈犳€э級
- 鉁?鏅鸿兘鑷<E58598>€傚簲锛氳嚜鍔ㄩ€夋嫨鏈€浣虫ā寮?
**代码增加**~400行完整实现
**浠g爜澧炲姞**锛殈400琛岋紙瀹屾暣瀹炵幇锛?
### 2. ✅ 历史数据缺失(功能级)- 已补充
### 2. 鉁?鍘嗗彶鏁版嵁缂哄け锛堝姛鑳界骇锛? 宸茶ˉ鍏?
**问题**
**<EFBFBD><EFBFBD>**锛?
- V1.0鍙<EFBFBD>洃鍚<EFBFBD>柊褰曞叆鏁版嵁
- 鍖婚櫌瀛橀噺鏁版嵁锛堝<E9949B>500涓<30>偅鑰咃級鏃犳硶璐ㄦ帶
**修正方案**
- ✅ 新增 `BulkScanService`(全量扫描)
- ✅ 支持<50条直接处理≥50条队列处理
- ✅ 支持断点续传(长时间任务)
- ✅ 新增API`POST /api/v1/iit/projects/:id/scan-all`
**<EFBFBD><EFBFBD>鏂规<EFBFBD>**锛?
- 鉁?鏂板<E98F82> `BulkScanService`锛堝叏閲忔壂鎻忥級
- 鉁?鏀<>寔<50鏉洿鎺ュ<E98EBA>鐞嗭紝鈮?0鏉¢槦鍒楀<E98D92>鐞?
- 鉁?鏀<>寔鏂<E5AF94>偣缁<E581A3>紶锛堥暱鏃堕棿浠诲姟锛?
- 鉁?鏂板<E98F82>API锛歚POST /api/v1/iit/projects/:id/scan-all`
**代码增加**~350行完整实现
**浠g爜澧炲姞**锛殈350琛岋紙瀹屾暣瀹炵幇锛?
### 3. ✅ 前端技术栈不明确(规范级)- 已明确
### 3. 鉁?鍓嶇<E98D93>鎶€鏈<E282AC>爤涓嶆槑纭<E6A791>紙瑙勮寖绾э級- 宸叉槑纭?
**问题**
- V1.0提到"微信小程序",但未明确技术栈
**<EFBFBD><EFBFBD>**锛?
- V1.0鎻愬埌"寰<>俊灏忕▼搴?锛屼絾鏈<E7B5BE>槑纭<E6A791>妧鏈<E5A6A7>
**修正方案**
- ✅ 明确使用 **Taro 4.x**React语法
- ✅ 支持一次开发,多端运行(小程序 + H5
- ✅ 可复用 shared/components 逻辑
- ✅ 团队熟悉React Hooks语法
**<EFBFBD><EFBFBD>鏂规<EFBFBD>**锛?
- 鉁?鏄庣‘浣跨敤 **Taro 4.x**锛圧eact璇<74>硶锛?
- 鉁?鏀<>寔涓€娆″紑鍙戯紝澶氱<E6BEB6>杩愯<E69DA9>锛堝皬绋嬪簭 + H5锛?
- 鉁?鍙<><E98D99>鐢?shared/components 閫昏緫
- 鉁?鍥㈤槦鐔熸倝React Hooks<EFBFBD>
---
@@ -68,7 +68,7 @@ model IitProject {
// ... 鍘熸湁瀛楁<E7809B>
// 馃敟 V1.1 鏂板<E98F82>
cachedRules Json? // Protocol关键规则缓存(性能优化)
cachedRules Json? // Protocol鍏抽敭瑙勫垯缂撳瓨锛堟€ц兘浼樺寲锛?
lastSyncAt DateTime? // 涓婃<E6B693>鍚屾<E98D9A>鏃堕棿锛堝<E9949B>閲忔媺鍙栵級
@@schema("iit")
@@ -97,24 +97,24 @@ model IitUserMapping {
### V1.0 鍘熻<E98D98>鍒掞紙鏈夐<E98F88>闄╋級
```
Day 1: 数据库
Day 2-3: REDCap EMWebhook推送)← 依赖医院网络
Day 4-5: Node.js Webhook接收器
Day 1: 鏁版嵁搴?
Day 2-3: REDCap EM锛圵ebhook鎺ㄩ€侊級鈫?渚濊禆鍖婚櫌缃戠粶
Day 4-5: Node.js Webhook鎺ユ敹鍣?
```
### V1.1 修正计划(更可靠)
### V1.1 <EFBFBD><EFBFBD>璁″垝锛堟洿鍙<EFBFBD>潬锛?
```
Day 1: 数据库
Day 2: 🔥 REDCap API Adapter(拉取能力)← 优先,主动拉取
Day 2: 🔥 SyncManager(轮询兜底)← 核心可靠性
Day 3: 🔥 全量扫描功能 ← 支持历史数据
Day 4: REDCap EMWebhook推送)← 作为增强,而非核心
Day 1: 鏁版嵁搴?
Day 2: 馃敟 REDCap API Adapter锛堟媺鍙栬兘鍔涳級鈫?浼樺厛锛屼富鍔ㄦ媺鍙?
Day 2: 馃敟 SyncManager锛堣疆璇㈠厹搴曪級鈫?鏍稿績鍙<E7B8BE>潬鎬?
Day 3: 馃敟 鍏ㄩ噺鎵<E599BA>弿鍔熻兘 鈫?鏀<>寔鍘嗗彶鏁版嵁
Day 4: REDCap EM锛圵ebhook鎺ㄩ€侊級鈫?浣滀负澧炲己锛岃€岄潪鏍稿績
```
**调整理由**
**璋冩暣鐞嗙敱**锛?
1. API鎷夊彇鏇村彲鎺э紙涓嶄緷璧栧尰闄㈢綉缁滐級
2. 能解决历史数据问题
2. 鑳借В鍐冲巻鍙叉暟鎹<EFBFBD>棶棰?
3. Webhook浣滀负澧炲己锛岃€岄潪鏍稿績渚濊禆
---
@@ -123,17 +123,17 @@ Day 4: REDCap EMWebhook推送← 作为增强,而非核心
### Dify RAG鎬ц兘浼樺寲
**优化前**
**浼樺寲鍓?*锛?
- 姣忔<E5A7A3>璐ㄦ帶閮借皟鐢―ify妫€绱㈡暣涓狿rotocol
- 閫熷害鎱<E5AEB3>紝Token娑堣€楀ぇ
**优化后**
- Protocol上传时,预提取关键规则
- 缓存到`cachedRules`字段JSONB
- 简单规则直接判断(无需调用Dify
**浼樺寲鍚?*锛?
- Protocol涓婁紶鏃讹紝棰勬彁鍙栧叧閿<EFBFBD><EFBFBD>鍒?
- 缂撳瓨鍒癭cachedRules`瀛楁<EFBFBD>锛圝SONB锛?
- 绠€鍗曡<EFBFBD>鍒欑洿鎺ュ垽鏂<EFBFBD>紙鏃犻渶璋冪敤Dify锛?
- 澶嶆潅瑙勫垯鎵嶈皟鐢―ify RAG
**性能提升**
**鎬ц兘鎻愬崌**锛?
- 绠€鍗曡<E98D97>鍒欐<E98D92>鏌ワ細<100ms锛堝師1-2绉掞級
- Token娑堣€楅檷浣庯細80%锛堝彧妫€绱㈠<E7BBB1>鏉傝<E98F89>鍒欙級
@@ -143,88 +143,88 @@ Day 4: REDCap EMWebhook推送← 作为增强,而非核心
| 淇<>敼鍐呭<E98D90> | 浠g爜琛屾暟 | 鏂囨。绔犺妭 |
|---------|---------|---------|
| SyncManager(混合同步) | ~400| 3.1.4 |
| BulkScanService(全量扫描) | ~350| 3.1.5 |
| SyncManager锛堟贩鍚堝悓姝ワ級 | ~400琛?| 3.1.4 |
| BulkScanService锛堝叏閲忔壂鎻忥級 | ~350琛?| 3.1.5 |
| 鏁版嵁搴揝chema鏇存柊 | +4瀛楁<E7809B> | 4.1 |
| API绔<49>偣鏂板<E98F82> | +1绔<31>偣 | 5.1 |
| 开发计划调整 | 重排优先级 | 7.1 |
| 寮€鍙戣<EFBFBD>鍒掕皟鏁?| 閲嶆帓浼樺厛绾?| 7.1 |
| 鍓嶇<E98D93>鎶€鏈<E282AC>爤鏄庣 | Taro 4.x | 7.2 |
| V1.1鏇存柊鎬荤粨 | 瀹屾暣璁板綍 | 鏂囨。鏈<E38082>熬 |
**总新增代码**~750
**文档更新**~300
**鎬绘柊澧炰唬鐮?*锛殈750琛?
**鏂囨。鏇存柊**锛殈300琛?
---
## ✅ 验收检查清单
## 鉁?楠屾敹妫€鏌ユ竻鍗?
- [x] SyncManager瀹屾暣瀹炵幇锛堟櫤鑳藉悓姝ャ€佽疆璇€€佸箓绛夋€э級
- [x] BulkScanService瀹屾暣瀹炵幇锛堝叏閲忔壂鎻忋€佹柇鐐圭画浼狅級
- [x] 数据库Schema更新4个新字段
- [x] API端点新增scan-all
- [x] 鏁版嵁搴揝chema鏇存柊锛?涓<>柊瀛楁<E7809B>锛?
- [x] API<EFBFBD>偣鏂板<EFBFBD>锛坰can-all锛?
- [x] 寮€鍙戣<E98D99>鍒掕皟鏁达紙浼樺厛绾ч噸鎺掞級
- [x] 前端技术栈明确Taro
- [x] 性能优化方案Dify缓存
- [x] 鍓嶇<EFBFBD>鎶€鏈<EFBFBD>爤鏄庣锛圱aro锛?
- [x] 鎬ц兘浼樺寲鏂规<EFBFBD>锛圖ify缂撳瓨锛?
- [x] V1.1鏇存柊鎬荤粨锛堝畬鏁磋<EFBFBD>褰曪級
- [x] 文件重命名(V1.0 V1.1
- [x] 鏂囦欢閲嶅懡鍚嶏紙V1.0 鈫?V1.1锛?
---
## 馃幆 鍏抽敭鎴愬氨
### 架构可靠性
### 鏋舵瀯鍙<EFBFBD>潬鎬?
**V1.0**
- ❌ 依赖Webhook(医院内网会失效)
- ❌ 只监听新数据(历史数据无法质控)
- Webhook丢失 = 数据遗漏
**V1.0**锛?
- 鉂?渚濊禆Webhook锛堝尰闄㈠唴缃戜細澶辨晥锛?
- 鉂?鍙<>洃鍚<E6B483>柊鏁版嵁锛堝巻鍙叉暟鎹<E69A9F>棤娉曡川鎺э級
- 鉂?Webhook涓㈠け = 鏁版嵁閬楁紡
**V1.1**
- ✅ 混合同步Webhook + 轮询双保险)
- ✅ 支持历史数据(全量扫描)
- ✅ 可靠性99.9%(不依赖医院网络)
**V1.1**锛?
- 鉁?娣峰悎鍚屾<E98D9A>锛圵ebhook + 杞<><E69D9E>鍙屼繚闄╋級
- 鉁?鏀<>寔鍘嗗彶鏁版嵁锛堝叏閲忔壂鎻忥級
- 鉁?鍙<>潬鎬э細99.9%锛堜笉渚濊禆鍖婚櫌缃戠粶锛?
### 开发效率
### 寮€鍙戞晥鐜?
- ✅ 完全复用平台能力storage/logger/jobQueue/cache
- Postgres-Only架构(无需Redis
- ✅ 断点续传CheckpointService通用化)
- ✅ 代码复用率:>80%
- 鉁?瀹屽叏澶嶇敤骞冲彴鑳藉姏锛坰torage/logger/jobQueue/cache锛?
- 鉁?Postgres-Only鏋舵瀯锛堟棤闇€Redis锛?
- 鉁?鏂<>偣缁<E581A3>紶锛圕heckpointService閫氱敤鍖栵級
- 鉁?浠g爜澶嶇敤鐜囷細>80%
### 鍖荤枟鍚堣<E98D9A>
- ✅ 影子状态机制AI只建议人类确权
- ✅ 完整审计日志符合FDA 21 CFR Part 11
- ✅ 可追溯(所有操作有trace_id
- 鉁?褰卞瓙鐘舵€佹満鍒讹紙AI鍙<49>缓璁<E7BC93>紝浜虹被纭<E8A2AB>潈锛?
- 鉁?瀹屾暣瀹¤<E780B9>鏃ュ織锛堢<E9949B>鍚團DA 21 CFR Part 11锛?
- 鉁?鍙<>拷婧<E68BB7>紙鎵€鏈夋搷浣滄湁trace_id锛?
---
## 📌 下一步建议
## 馃搶 涓嬩竴姝ュ缓璁?
### 绔嬪嵆琛屽姩
1. **浼佷笟寰<E7AC9F>俊娉ㄥ唽**锛堜粖澶╋級
- 注册开发者账号
- 娉ㄥ唽寮€鍙戣€呰处鍙?
- 鍒涘缓娴嬭瘯搴旂敤
- 鑾峰彇API鍑<49>
2. **鎶€鏈<E282AC>爤纭<E788A4><E7BAAD>**锛堜粖澶╋級
- Node.js 22
- PostgreSQL 15
- Taro 4.x(小程序) ✅
- Node.js 22 鉁?
- PostgreSQL 15 鉁?
- Taro 4.x锛堝皬绋嬪簭锛?鉁?
3. **鍒涘缓椤圭洰鐪嬫澘**锛堜粖澶╋級
- 按V1.1优先级排列任务
- 鎸塚1.1浼樺厛绾ф帓鍒椾换鍔?
- 姣忔棩绔欎細鍚屾<E98D9A>杩涘害
### MVP开发启动(明天)
### MVP寮€鍙戝惎鍔<EFBFBD>紙鏄庡ぉ锛?
**Week 1 优先级**V1.1版):
**Week 1 浼樺厛绾?*锛圴1.1鐗堬級锛?
1. Day 1: 鏁版嵁搴撳垵濮嬪寲 + 浼佸井娴嬭瘯
2. Day 2: REDCap API Adapter + SyncManager ← 核心
3. Day 3: 全量扫描功能 ← 支持历史数据
4. Day 4: REDCap EM + Webhook ← 增强
5. Day 5: 企微适配器 + 端到端测试
2. Day 2: REDCap API Adapter + SyncManager 鈫?鏍稿績
3. Day 3: 鍏ㄩ噺鎵<EFBFBD>弿鍔熻兘 鈫?鏀<>寔鍘嗗彶鏁版嵁
4. Day 4: REDCap EM + Webhook 鈫?澧炲己
5. Day 5: 浼佸井閫傞厤鍣?+ 绔<>埌绔<E59F8C>祴璇?
---
@@ -232,23 +232,24 @@ Day 4: REDCap EMWebhook推送← 作为增强,而非核心
**鏋舵瀯璇勫<E79287>鎰忚<E98EB0>**锛氣渽 **閫氳繃**
**核心修正**
- ✅ 致命风险(网络连通性):已解决
- ✅ 功能缺失(历史数据):已补充
- ✅ 技术栈不明(前端):已明确
**鏍稿績淇<EFBFBD><EFBFBD>**锛?
- 鉁?鑷村懡椋庨櫓锛堢綉缁滆繛閫氭€э級锛氬凡瑙e喅
- 鉁?鍔熻兘缂哄け锛堝巻鍙叉暟鎹<E69A9F>級锛氬凡琛ュ厖
- 鉁?鎶€鏈<E282AC>爤涓嶆槑锛堝墠绔<E5A2A0>級锛氬凡鏄庣
**方案状态**
**鏂规<EFBFBD>鐘舵€?*锛?
- 馃殌 **Ready to Code**
- 🎯 **可直接执行**
- 📋 **符合云原生规范**
- 馃幆 **鍙<>洿鎺ユ墽琛?*
- 馃搵 **绗﹀悎浜戝師鐢熻<E990A2>鑼?*
- 馃挭 **鍖荤枟鍚堣<E98D9A>灏辩华**
---
**报告完成日期**2025-12-31
**维护者**:架构团队
**审查状态**:✅ 通过
**可执行性**:✅ 可立即启动MVP开发
**鎶ュ憡瀹屾垚鏃ユ湡**锛?025-12-31
**缁存姢鑰?*锛氭灦鏋勫洟闃?
**瀹℃煡鐘舵€?*锛氣渽 閫氳繃
**<EFBFBD>墽琛屾€?*锛氣渽 鍙<>珛鍗冲惎鍔VP寮€鍙?