Files
AIclinicalresearch/docs/03-业务模块/IIT Manager Agent/06-开发记录/Day3-企业微信集成与端到端测试完成记录.md
HaHafeng 1b53ab9d52 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%)
2026-01-14 19:15:01 +08:00

22 KiB
Raw Blame History

Day 3 隡<><E99AA1>敺桐縑<E6A190><E7B891><EFBFBD>銝𡒊垢<F0A1928A>啁垢瘚贝<E7989A>摰峕<E691B0>霈啣<E99C88>

**<2A><EFBFBD>**嚗?026-01-03
**撘<><E69298>煾𧫴畾?*嚗鐝VP Week 1 - Day 3
**<2A><EFBFBD><E8A9A8><EFBFBD>**嚗𡁏<E59A97><F0A1818F>?REDCap <20>?Node.js <20>?隡<><E99AA1>敺桐縑 <20><><EFBFBD><EFBFBD>湧𡡒<E6B9A7>? **摰鮋<E691B0>摰峕<E691B0>**嚗尠<E59A97> 蝡臬<E89DA1>蝡舀<E89DA1>霂閖<E99C82><EFBFBD>嚗愢VP<56>剔㴓<E58994><EFBFBD>?


<EFBFBD>㴓 銝<><E98A9D><EFBFBD><EFBFBD><EFBFBD>𤑳𤌍<F0A491B3><F0A48C8D><EFBFBD><EFBFBD><EFBFBD>

1.1 <20><EFBFBD><E8A9A8><EFBFBD>

**<2A><>撠誯𡡒<E8AAAF><EFBFBD>霂?*嚗?

REDCap敶訫<EFBFBD><EFBFBD>唳旿 <20>?Node.js摰墧𧒄<E5A2A7>閗繮 <20>?隡<><E99AA1>敺桐縑<E6A190><EFBFBD><E7AE84>𡁶䰻
                 <20>?
          韐冽綉<E586BD><E7B689><EFBFBD> <20>?<3F><EFBFBD><E588B8><EFBFBD>𡁶䰻 <20>?PI<50>交𤣰

1.2 摰峕<E691B0><E5B395><EFBFBD>

<EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD>? 霂湔<EFBFBD>
<EFBFBD>?隡<><E99AA1>敺桐縑<E6A190><EFBFBD><E588B8><EFBFBD><EFBFBD>? 摰峕<EFBFBD> WechatService.ts嚗?14銵䕘<E98AB5>
<EFBFBD>?隡<><E99AA1>敺桐縑<E6A190><EFBFBD><EFBFBD><E686AD> 摰峕<EFBFBD> WechatCallbackController.ts嚗?01銵䕘<E98AB5>
<EFBFBD>?韐冽綉Worker<65><EFBFBD> 摰峕<EFBFBD> iit_quality_check Worker
<EFBFBD>?Worker瘜典<E7989C><E585B8><EFBFBD> 摰峕<EFBFBD> initIitManager() <20>典鍳<E585B8>冽𧒄靚<F0A79284>
<EFBFBD>?蝡臬<E89DA1>蝡舀<E89DA1>霂? <EFBFBD><EFBFBD> REDCap <20>?Node.js <20>?隡<><E99AA1>敺桐縑
<EFBFBD>?<3F><EFBFBD><E887AC>滨蔭<E6BBA8><E894AD> 摰峕<EFBFBD> WECHAT_ENV_CONFIG.md嚗?01銵䕘<E98AB5>

<EFBFBD><EFBFBD> 鈭䎚<E988AD><E48E9A><EFBFBD><EFBFBD><EFBFBD><E6A0BC><EFBFBD><E887AC>?

2.1 隡<><E99AA1>敺桐縑<E6A190><EFBFBD><E588B8><EFBFBD><EFBFBD><EFBFBD>WechatService嚗?

<EFBFBD><EFBFBD>嚗䫤backend/src/modules/iit-manager/services/WechatService.ts`嚗?14銵䕘<E98AB5>

**<2A><EFBFBD><E8A9A8><EFBFBD>**嚗?

class WechatService {
  // <20><EFBFBD>Access Token嚗<6E><E59A97>摮?撠𤩺𧒄嚗?
  async getAccessToken(): Promise<string>
  
  // <20><EFBFBD><E785BE><EFBFBD><EFBFBD><EFBFBD><E7A586>?
  async sendTextMessage(userId: string, content: string): Promise<void>
  
  // <20><EFBFBD><E785BE>arkdown瘨<6E><E798A8><EFBFBD><EFBFBD>格凒<E6A0BC><EFBFBD><E5959C><EFBFBD>扳𥁒<E689B3>𠺪<EFBFBD>
  async sendMarkdownMessage(userId: string, content: string): Promise<void>
  
  // <20><EFBFBD><E785BE>extcard<72><EFBFBD><EFBFBD><E798A8><EFBFBD><EFBFBD><EFBFBD>𡁶䰻嚗?
  async sendTextcardMessage(userId: string, card: TextcardMessage): Promise<void>
}

**<2A>喲睸<E596B2><E79DB8><EFBFBD>?*嚗?

  • <EFBFBD>?Access Token蝻枏<E89DBB><E69E8F><EFBFBD><EFBFBD><E59A97>摮条<E691AE>摮矋<E691AE>2撠𤩺𧒄<F0A4A9BA><EFBFBD><E39787><EFBFBD><EFBFBD>
  • <EFBFBD>?隡<><E99AA1>敺桐縑API靚<49>鍂嚗Ǒ/cgi-bin/message/send`嚗?
  • <EFBFBD>?摰峕㟲<E5B395><E39FB2><EFBFBD>霂臬<E99C82><E887AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>霈啣<E99C88>
  • <EFBFBD>?<3F><EFBFBD>銝厩<E98A9D><EFBFBD><E798A8>蝐餃<E89D90>嚗ōext/markdown/textcard嚗?

**瘚贝<E7989A>撉諹<E69289>**嚗?

  • <EFBFBD>?雿輻鍂隡<E98D82><E99AA1>敺桐縑摰䀹䲮撘<E4B2AE><E69298>穃極<E7A983><EFBFBD>霂𤏪<E99C82>access_token + 瘨<><E798A8>API嚗?
  • <EFBFBD>?<3F><>𧋦瘨<F0A78BA6><E798A8>瘚贝<E7989A><E8B49D><EFBFBD>
  • <EFBFBD>?Textcard<72><EFBFBD><EFBFBD><E798A8>瘚贝<E7989A><E8B49D><EFBFBD>
  • <EFBFBD>?Markdown瘨<6E><E798A8>瘚贝<E7989A><E8B49D><EFBFBD>
  • <EFBFBD>?<3F>𧢲㦤蝡臭<E89DA1>銝𡁜凝靽⊥<E99DBD><E28AA5><EFBFBD>𦻖<EFBFBD><EFBFBD><E59786>厩掩<E58EA9>𧢲<EFBFBD><F0A7A2B2>?

2.2 隡<><E99AA1>敺桐縑<E6A190><EFBFBD><EFBFBD><E686AD>嚗ÁechatCallbackController嚗?

<EFBFBD><EFBFBD>嚗䫤backend/src/modules/iit-manager/controllers/WechatCallbackController.ts`嚗?01銵䕘<E98AB5>

**<2A><EFBFBD><E8A9A8><EFBFBD>**嚗?

class WechatCallbackController {
  // URL撉諹<E69289><EFBFBD><E59A97>銝𡁜凝靽⊿<E99DBD>甈⊿<E79488>蝵殷<E89DB5>
  async verifyUrl(request, reply): Promise<void>
  
  // <20>交𤣰<E4BAA4><EFBFBD><EFBFBD><E798A8><EFBFBD><E59A97>甇亙<E79487>憭齿芋撘𧶏<E69298>
  async handleCallback(request, reply): Promise<void>
  
  // 瘨<><E798A8><EFBFBD><E996AB>
  private decryptMessage(encryptedMsg: string): any
  
  // 瘨<><E798A8><EFBFBD><EFBFBD>
  private encryptMessage(msg: string): string
  
  // <20><><EFBFBD>蝑曉<E89D91>
  private generateSignature(token, timestamp, nonce, encrypt): string
}

**<2A>喲睸<E596B2><E79DB8><EFBFBD>?*嚗?

  • <EFBFBD>?隡<><E99AA1>敺桐縑瘨<E7B891><E798A8><EFBFBD>㰘圾撖<E59CBE><E69296>@wecom/crypto嚗?
  • <EFBFBD>?XML瘨<4C><E798A8><EFBFBD><E996AB>嚗Ǒxml2js`嚗?
  • <EFBFBD>?蝑曉<E89D91>撉諹<E69289>嚗𠄎HA1嚗?
  • <EFBFBD>?撘<><EFBFBD>𧼮<EFBFBD><E79285><EFBFBD><E59A97><EFBFBD><EFBFBD><E594BE>?success"嚗<><E59A97><EFBFBD><EFBFBD><E595A3><EFBFBD><EFBFBD>
  • <EFBFBD>?雿輻鍂 setImmediate 蝖桐<E89D96><EFBFBD><EFBFBD><EFBFBD>
  • <EFBFBD>?LLM<4C>誩㦛霂<E3A69B><E99C82>嚗㇄ify嚗? 憭鋫gent頝舐眏

**瘚贝<E7989A>撉諹<E69289>**嚗?

  • <EFBFBD>?隡<><E99AA1>敺桐縑<E6A190><EFBFBD>URL撉諹<E69289><E8ABB9><EFBFBD>
  • <EFBFBD>?natapp<70><70><EFBFBD>蝛輸<E89D9B><EFBFBD>蝵格<E89DB5><E6A0BC><EFBFBD><EFBFBD>http://iit.nat100.top嚗?
  • <EFBFBD>?瘨<><E798A8><EFBFBD>㰘圾撖<E59CBE><E69296>霂閖<E99C82><EFBFBD>
  • <EFBFBD><EFBFBD> <20><EFBFBD><EFBFBD><E798A8><EFBFBD><E686AD><EFBFBD><EFBFBD><EFBFBD><E59A97><EFBFBD>𡒊賒<F0A1928A><EFBFBD>嚗?

2.3 韐冽綉Worker<65><EFBFBD><EFBFBD><E691B0>

<EFBFBD><EFBFBD>嚗䫤backend/src/modules/iit-manager/index.ts`

**<2A><EFBFBD><E8A9A8><EFBFBD>**嚗?

// Worker瘜典<E7989C>
jobQueue.process<IitQualityCheckJob>('iit_quality_check', async (job) => {
  const { projectId, recordId, instrument } = job.data;
  
  // 1. <20><EFBFBD>憿寧𤌍靽⊥<E99DBD>
  const project = await prisma.$queryRaw`...`;
  
  // 2. <20><EFBFBD>UserID嚗<44>㴓憓<E3B493><E68693><EFBFBD><EFBFBD><E8AD8D><EFBFBD><EFBFBD>
  const piUserId = process.env.WECHAT_TEST_USER_ID || 'FengZhiBo';
  
  // 3. <20><EFBFBD>韐冽綉璉<E7B689><E79289>?
  const qualityCheckResult = await performQualityCheck(...);
  
  // 4. <20><EFBFBD><E785BE><EFBFBD>銝𡁜凝靽⊿<E99DBD>𡁶䰻
  await wechatService.sendMarkdownMessage(piUserId, message);
  
  // 5. 霈啣<E99C88>摰∟恣<E2889F><EFBFBD>
  await prisma.$executeRaw`INSERT INTO audit_logs ...`;
  
  return { status: 'success' };
});

**韐冽綉<E586BD><EFBFBD>**嚗<><E59A97><EFBFBD>𣇉<EFBFBD>嚗㚁<E59A97>

async function performQualityCheck(projectId, recordId, instrument) {
  const issues = [];
  const recommendations = [];
  
  // <20><EFBFBD><EFBFBD><E79289>?
  if (!recordId || recordId.trim() === '') {
    issues.push('霈啣<E99C88>ID<49><EFBFBD>');
  }
  
  if (!instrument || instrument.trim() === '') {
    issues.push('銵典<E98AB5><E585B8>滨妍<E6BBA8><EFBFBD>');
  }
  
  // <20><EFBFBD><E59786><EFBFBD><E689B3><EFBFBD>隞𤾸恣霈⊥𠯫敹𡑒繮<F0A19192><EFBFBD>
  const recentLogs = await prisma.$queryRaw`
    SELECT created_at FROM audit_logs
    WHERE action_type = 'redcap_data_received' ...
  `;
  
  const timeDiff = Date.now() - recentLogs[0].created_at.getTime();
  if (timeDiff < 3600000) {
    recommendations.push('<27>?<3F>唳旿敶訫<E695B6><E8A8AB>𦠜𧒄');
  }
  
  return { issues, recommendations };
}

**瘚贝<E7989A>撉諹<E69289>**嚗?

  • <EFBFBD>?Worker<65>𣂼<EFBFBD>瘜典<E7989C><E585B8>郡g-boss
  • <EFBFBD>?REDCap DET閫血<E996AB> <20>?隞餃𦛚<E9A483><EFBFBD>?<3F>?Worker<65><EFBFBD>
  • <EFBFBD>?韐冽綉璉<E7B689><E79289>仿<EFBFBD><EFBFBD><E9A489><EFBFBD><EFBFBD>
  • <EFBFBD>?隡<><E99AA1>敺桐縑<E6A190>𡁶䰻<F0A181B6><EFBFBD><E785BE><EFBFBD><EFBFBD>?
  • <EFBFBD>?摰∟恣<E2889F><EFBFBD>霈啣<E99C88><E595A3>𣂼<EFBFBD>

2.4 Worker瘜典<E7989C><E585B8><EFBFBD>靽桀<E99DBD>

**<2A><EFBFBD>**嚗帋<E59A97><E5B88B>?initIitManager() <20>賣㺭<E8B3A3>芾◤靚<E297A4>鍂嚗<E98D82><EFBFBD>幃orker<65>芣釣<E88AA3>?

**靽桀<E99DBD>**嚗䫤backend/src/index.ts`

// <20>?靽桀<E99DBD><E6A180><EFBFBD>Worker<65>芣釣<E88AA3><EFBFBD>
async function start() {
  await jobQueue.start();
  
  registerParseExcelWorker();
  logger.info('<27>?DC Tool C parse excel worker registered');
  
  // <20>?敹䁅扇靚<E68987>鍂 initIitManager()
  
  await new Promise(resolve => setTimeout(resolve, 3000));
}

// <20>?靽桀<E99DBD><E6A180>𠬍<EFBFBD>Worker甇<72>瘜典<E7989C>嚗?
async function start() {
  await jobQueue.start();
  
  registerParseExcelWorker();
  logger.info('<27>?DC Tool C parse excel worker registered');
  
  // <20>?瘜典<E7989C>IIT Manager Workers
  await initIitManager();
  logger.info('<27>?IIT Manager workers registered');
  
  await new Promise(resolve => setTimeout(resolve, 3000));
}

**撉諹<E69289>**嚗?

  • <EFBFBD>?<3F>臬𢆡<E887AC><EFBFBD><E4BA99>曄內 "IIT Manager workers registered"
  • <EFBFBD>?iit_quality_check Worker<65>𣂼<EFBFBD><EFBFBD><E686AD>隞餃𦛚
  • <EFBFBD>?iit_redcap_poll Worker撌脫釣<E884AB><EFBFBD>摰𡁏𧒄隞餃𦛚撌脫<E6928C><E884AB><EFBFBD><E597A5><EFBFBD>

2.5 <20>唳旿摨枏<E691A8>畾萄<E795BE>靽桀<E99DBD>

<EFBFBD><EFBFBD>1嚗䫤notification_config` 摮埈挾銝滚<E98A9D><E6BB9A>?

**<2A><EFBFBD>**嚗阳orker隞<72><E99A9E><EFBFBD>亥砭鈭<E7A0AD><EFBFBD><EFBFBD>銵其葉銝滚<E98A9D><E6BB9A><EFBFBD>摮埈挾

**靽桀<E99DBD>**嚗?

// <20>?銋见<E98A8B><EFBFBD>䰻霂<E99C82>摮睃銁<E79D83><E98A81><EFBFBD>畾蛛<E795BE>
SELECT id, name, redcap_project_id, notification_config
FROM iit_schema.projects
WHERE id = ${projectId}

// <20>?<3F>啣銁嚗<E98A81><EFBFBD>亥砭摮睃銁<E79D83><E98A81><EFBFBD>畾蛛<E795BE>
SELECT id, name, redcap_project_id
FROM iit_schema.projects
WHERE id = ${projectId}

// UserID<49>湔𦻖隞𡒊㴓憓<E3B493><E68693><EFBFBD>讛繮<E8AE9B><EFBFBD>瘚贝<E7989A><E79285>嚗?
const piUserId = process.env.WECHAT_TEST_USER_ID || 'FengZhiBo';

<EFBFBD><EFBFBD>2嚗䫤action摮埈挾銝滚<EFBFBD><EFBFBD><EFBFBD>摨𥪯蛹action_type`嚗?

**靽桀<E99DBD>**嚗?

// <20>?銋见<E98A8B>
INSERT INTO iit_schema.audit_logs (project_id, action, entity_id, details)
WHERE action = 'redcap_data_received'

// <20>?<3F>啣銁
INSERT INTO iit_schema.audit_logs (project_id, action_type, entity_id, details)
WHERE action_type = 'redcap_data_received'

**撉諹<E69289>**嚗?

  • <EFBFBD>?Worker<65><EFBFBD><E689AF>䭾㺭<E4ADBE><EFBFBD><E6A180>躰秤
  • <EFBFBD>?摰∟恣<E2889F><EFBFBD>霈啣<E99C88><E595A3>𣂼<EFBFBD>
  • <EFBFBD>?韐冽綉隞餃𦛚摰峕㟲瘚<E39FB2><E7989A><EFBFBD><EFBFBD>

<EFBFBD>妒 銝剹<E98A9D><E589B9><EFBFBD>啁垢瘚贝<E7989A>

3.1 瘚贝<E7989A><E8B49D><EFBFBD>

<EFBFBD> <EFBFBD>滨蔭 <EFBFBD><EFBFBD>?
REDCap Docker 15.8.0 + 瘚贝<E7989A>憿寧𤌍(PID 16) <EFBFBD>?餈鞱<E9A488>銝?
Node.js Backend Fastify + pg-boss + Prisma <EFBFBD>?餈鞱<E9A488>銝?
PostgreSQL Docker + iit_schema <EFBFBD>?餈鞱<E9A488>銝?
<EFBFBD><EFBFBD>敺桐縑 <EFBFBD>芸遣摨𠉛鍂 + 瘚贝<E7989A><E8B49D><EFBFBD>(FengZhiBo) <EFBFBD>?撌脤<E6928C>蝵?
natapp <EFBFBD><EFBFBD><EFBFBD>蝛輸<EFBFBD>?iit.nat100.top) <EFBFBD>?撌脤<E6928C>蝵?

3.2 瘚贝<E7989A><EFBFBD><E7989A>

瘚贝<EFBFBD>甇仿炊嚗?

  1. <EFBFBD>?REDCap<61>𥕦遣<F0A595A6>啗扇敶𤏪<E695B6>ID: 9嚗?
  2. <EFBFBD>?REDCap DET摰墧𧒄閫血<E996AB>Webhook嚗?蝘鍦辣餈<E8BEA3><E9A488>
  3. <EFBFBD>?Node.js WebhookController<65>交𤣰霂瑟<E99C82>嚗?10ms<6D><EFBFBD>嚗?
  4. <EFBFBD>?<3F><EFBFBD><E588B8><EFBFBD><EFBFBD> iit_quality_check <20><EFBFBD>
  5. <EFBFBD>?Worker<65><EFBFBD>韐冽綉璉<E7B689><E79289>?
  6. <EFBFBD>?<3F><EFBFBD><E785BE><EFBFBD>銝𡁜凝靽⊿<E99DBD>𡁶䰻
  7. <EFBFBD>?<3F>𧢲㦤蝡臭<E89DA1>銝𡁜凝靽⊥𦻖<E28AA5><EFBFBD>𡁶䰻

**瘚贝<E7989A>霈啣<E99C88>**嚗㇆D: 9嚗㚁<E59A97>

2026-01-03 14:02:07.995 [aiclinical-backend] info: REDCap Webhook received
  { project_id: "16", record: "9", instrument: "demographics" }

2026-01-03 14:02:08.026 [aiclinical-backend] info: Record data fetched from REDCap
  { recordCount: 1 }

[PgBossQueue] Job pushed: 7a5da656-85d2-4885-bc2d-625fce74d926 (type: iit_quality_check)

2026-01-03 14:02:08.037 [aiclinical-backend] info: <20><> Quality check job started
  { jobId: "7a5da656...", projectId: "40062738...", recordId: "9" }

2026-01-03 14:02:08.039 [aiclinical-backend] info: <20>㨩 Preparing to send WeChat notification
  { piUserId: "FengZhiBo", source: "env_variable_direct" }

2026-01-03 14:02:08.042 [aiclinical-backend] info: <20><> Quality check completed
  { issuesCount: 0, recommendationsCount: 3 }

2026-01-03 14:02:08.045 [aiclinical-backend] info: <20>?摰∟恣<E2889F><EFBFBD>霈啣<E99C88><E595A3>𣂼<EFBFBD>
  { recordId: "9" }

2026-01-03 14:02:08.048 [aiclinical-backend] info: <20>?Quality check completed and notification sent
  { piUserId: "FengZhiBo", hasIssues: false }

<EFBFBD><EFBFBD>敺桐縑<EFBFBD>交𤣰<EFBFBD><EFBFBD>嚗?

<EFBFBD><EFBFBD> IIT Manager <20>唳旿敶訫<E695B6><E8A8AB>𡁶䰻

憿寧𤌍嚗魩est0102
霈啣<E99C88>ID嚗?
銵典<E98AB5>嚗飱emographics
<0A>園𡢿嚗?026-01-03 14:02:08

<0A>働 韐冽綉撱箄悅嚗?
1. <20>?<3F>唳旿敶訫<E695B6><E8A8AB>𦠜𧒄
2. <20>?霈啣<E99C88>ID<49><EFBFBD>
3. <20>?銵典<E98AB5>嚗飱emographics

<0A>?<3F>唳旿韐券<E99F90><E588B8>臬末

<0A>俥 憒<><E68692><EFBFBD>煾䔮嚗諹窈<E8ABB9>𧼮<EFBFBD>"撣桀𨭌"<22><EFBFBD><E4BAA6><EFBFBD><E6B8B8><EFBFBD>

3.3 瘚贝<E7989A>蝏𤘪<E89D8F>

瘚贝<EFBFBD>憿? <EFBFBD><EFBFBD><EFBFBD> 摰鮋<EFBFBD> <EFBFBD><EFBFBD>?
REDCap閫血<EFBFBD> 靽嘥<EFBFBD><EFBFBD>𡒊<EFBFBD><EFBFBD>唾圻<EFBFBD>? 0蝘鍦辣餈? <EFBFBD>?
Webhook<EFBFBD>交𤣰 <10ms<6D><EFBFBD> 5.8ms <EFBFBD>?
隞餃𦛚<EFBFBD><EFBFBD>? <EFBFBD>𣂼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD>𣂼<EFBFBD> <EFBFBD>?
Worker<EFBFBD><EFBFBD> Worker憭<EFBFBD><EFBFBD>隞餃𦛚 <EFBFBD>𣂼<EFBFBD><EFBFBD><EFBFBD> <EFBFBD>?
韐冽綉璉<EFBFBD><EFBFBD>? 餈𥪜<EFBFBD>韐冽綉蝏𤘪<EFBFBD> 3<EFBFBD>遣霈? <EFBFBD>?
<EFBFBD><EFBFBD>敺桐縑<EFBFBD><EFBFBD>? <EFBFBD><EFBFBD><EFBFBD><EFBFBD>𡁶䰻<EFBFBD>𣂼<EFBFBD> <EFBFBD>𣂼<EFBFBD> <EFBFBD>?
<EFBFBD>𧢲㦤<EFBFBD>交𤣰 <EFBFBD>交𤣰<EFBFBD><EFBFBD>𡁶䰻 <EFBFBD>𣂼<EFBFBD><EFBFBD>交𤣰 <EFBFBD>?
摰∟恣<EFBFBD><EFBFBD> 霈啣<EFBFBD><EFBFBD>唳㺭<EFBFBD><EFBFBD> <EFBFBD>𣂼<EFBFBD>霈啣<EFBFBD> <EFBFBD>?
敺芰㴓<EFBFBD><EFBFBD>? <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>甈? <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>甈? <EFBFBD>?

**<2A>喲睸<E596B2><E79DB8><EFBFBD>**嚗?

  • <EFBFBD>?蝡臬<E89DA1>蝡臬辣餈<E8BEA3><E9A488><2蝘𡜐<E89D98>REDCap靽嘥<E99DBD> <20>?隡<><E99AA1>敺桐縑<E6A190>交𤣰嚗?
  • <EFBFBD>?Webhook<6F><EFBFBD><E6BB9A>園𡢿嚗?.8ms
  • <EFBFBD>?Worker<65><EFBFBD><E689AF>園𡢿嚗鰺50ms
  • <EFBFBD>?瘨<><E798A8><EFBFBD><EFBFBD><E785BE><EFBFBD><EFBFBD><EFBFBD>嚗?00%嚗<><E59A97>霂?甈∴<E79488><E288B4><EFBFBD><E588B8>𣂼<EFBFBD>嚗?
  • <EFBFBD>?<3F>惩儐<E683A9><EFBFBD><E887AC><EFBFBD>䔮憸?

<EFBFBD><20><EFBFBD><E49C98><EFBFBD>嗆綳<E59786><EFBFBD><E8B3AD><EFBFBD><EFBFBD><EFBFBD>箏𦛚

4.1 銝湔𧒄<E6B994>芣鴌嚗㇈VP<56>嗆挾嚗?

摨誩噡 銝湔𧒄<EFBFBD>芣鴌 <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD>園𡢿 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
1 *UserID蝖祉<EFBFBD><EFBFBD>? <EFBFBD><EFBFBD>𡝗<EFBFBD>霂閙<EFBFBD>蝔? Phase 2 隞𡡞★<EFBFBD><EFBFBD>蝵株”霂餃<EFBFBD> notification_config.wechat_user_id
2 摰𡁏𧒄頧株砭蝳<EFBFBD> MVP銝漤<EFBFBD><EFBFBD><EFBFBD>Webhook撌脰雲憭? Phase 2 摰䂿緵 jobQueue.schedule() <20>碶蝙<E7A2B6>?node-cron
3 *韐冽綉<EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <EFBFBD>抅蝖<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鼦I韐冽綉 Phase 1.5 <EFBFBD><EFBFBD><EFBFBD>Dify RAG + 閫<><E996AB>撘閙<E69298>
4 摰∟恣<EFBFBD><EFBFBD>摮埈挾 notification_config 摮埈挾<E59F88><EFBFBD>撱? Phase 2 瘛餃<EFBFBD>JSONB摮埈挾摮睃<EFBFBD><EFBFBD><EFBFBD>敺桐縑<EFBFBD>滨蔭
5 Access Token蝻枏<E89DBB> <EFBFBD><EFBFBD><EFBFBD>蝻枏<EFBFBD>嚗屸<EFBFBD><EFBFBD>臭腺憭? Phase 2 雿輻鍂Redis<EFBFBD>𡝗㺭<EFBFBD><EFBFBD>蝻枏<EFBFBD>

**霂衣<E99C82>霂湔<E99C82>**嚗?

1. UserID蝖祉<E89D96><E7A589><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E887AC><EFBFBD>嚗?

敶枏<EFBFBD>摰䂿緵嚗?

// <20>湔𦻖隞𡒊㴓憓<E3B493><E68693><EFBFBD>讛繮<E8AE9B>?
const piUserId = process.env.WECHAT_TEST_USER_ID || 'FengZhiBo';

**<2A><EFBFBD>**嚗?

  • <EFBFBD>?<3F><EFBFBD><E4ADBE><EFBFBD>憭𡁻★<F0A181BB><EFBFBD><E69FB4><EFBFBD>PI
  • <EFBFBD>?<3F>煺漣<E785BA><EFBFBD><E887AC><EFBFBD><EFBFBD><E996AC>銝芷★<E88AB7><EFBFBD>蝵桐<E89DB5><E6A190>𣬚<EFBFBD>UserID

**霈<E99C88><E288AA><EFBFBD>**嚗㇊hase 2嚗㚁<E59A97>

// 隞𡡞★<F0A1A19E><EFBFBD>蝵株”霂餃<E99C82>
const project = await prisma.iitProject.findUnique({
  where: { id: projectId },
  select: { notificationConfig: true }
});

const piUserId = project.notificationConfig?.wechat_user_id 
                 || process.env.WECHAT_TEST_USER_ID 
                 || 'FengZhiBo';

**<2A>唳旿摨廍chema<6D><EFBFBD>**嚗?

ALTER TABLE iit_schema.projects 
ADD COLUMN notification_config JSONB DEFAULT '{}'::jsonb;

-- 蝷箔<E89DB7><E7AE94>唳旿
{
  "wechat_user_id": "FengZhiBo",
  "wechat_department_id": 1,
  "notification_types": ["data_entry", "quality_issue", "task_reminder"]
}

2. 摰𡁏𧒄頧株砭蝳<E7A0AD>

敶枏<EFBFBD>摰䂿緵嚗?

// <20><EFBFBD> <20><>𧒄蝳<F0A79284>鍂摰𡁏𧒄頧株砭嚗㇈VP<56>嗆挾嚗𡦀ebhook撌脰雲憭<E99BB2><E686AD>
// TODO: Phase 2 - 摰䂿緵摰𡁏𧒄頧株砭雿靝蛹銵亙<E98AB5><E4BA99><EFBFBD>
// await syncManager.initScheduledJob();

logger.info('IIT Manager: Scheduled job registration skipped (using Webhook only for MVP)');

**<2A><EFBFBD>**嚗?

  • <EFBFBD>𩤃<EFBFBD> jobQueue.schedule() <20><EFBFBD>銝滚<E98A9D><E6BB9A><EFBFBD>PgBossQueue <20><EFBFBD><E88AB8><EFBFBD>
  • <EFBFBD>𩤃<EFBFBD> MVP<56>嗆挾銝漤<E98A9D><EFBFBD><E996AC><EFBFBD>嗉蔭霂<E99C82>REDCap DET撌脰雲憭<E99BB2><E686AD>

**霈<E99C88><E288AA><EFBFBD><E5AFA1><EFBFBD>**嚗㇊hase 2嚗㚁<E59A97>

<EFBFBD><EFBFBD>A嚗帋蝙<EFBFBD>?node-cron<EFBFBD><EFBFBD><EFBFBD>

import cron from 'node-cron';

// 瘥?<3F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>甈?
cron.schedule('*/5 * * * *', async () => {
  logger.info('<27>?REDCap摰𡁏𧒄頧株砭撘<E7A0AD>憪?);
  const syncManager = new SyncManager();
  await syncManager.handlePoll();
}, {
  timezone: 'Asia/Shanghai'
});

<EFBFBD><EFBFBD>B嚗𡁏<EFBFBD>撅?PgBossQueue 摰䂿緵 schedule <20><EFBFBD>

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 <20><EFBFBD> cron 銵刻噢撘?
    return await this.boss.send(name, data, {
      ...options,
      startAfter: new Date(),
      singletonKey: name,
      priority: 1
    });
  }
}

**隡睃<E99AA1>蝥?*嚗帋<E59A97>嚗Áebhook頞喳<E9A09E><E596B3><EFBFBD><EFBFBD><E59A97><EFBFBD>嗉蔭霂<E99C82>雿靝蛹<E99D9D>𨅯<EFBFBD>嚗?


3. 韐冽綉<E586BD><EFBFBD><EFBFBD><E89D9E>?

敶枏<EFBFBD>摰䂿緵<EFBFBD>抅蝖<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗?

async function performQualityCheck(projectId, recordId, instrument) {
  const issues = [];
  const recommendations = [];
  
  // <20>?<3F><EFBFBD><EFBFBD><E79289>?
  if (!recordId) issues.push('霈啣<E99C88>ID<49><EFBFBD>');
  if (!instrument) issues.push('銵典<E98AB5><E585B8>滨妍<E6BBA8><EFBFBD>');
  
  // <20>?<3F><EFBFBD><E59786><EFBFBD><E689B3>?
  const timeDiff = Date.now() - lastUpdate;
  if (timeDiff < 3600000) {
    recommendations.push('<27>?<3F>唳旿敶訫<E695B6><E8A8AB>𦠜𧒄');
  }
  
  return { issues, recommendations };
}

**霈<E99C88><E288AA><EFBFBD>**嚗㇊hase 1.5嚗㚁<EFBFBD>

**AI韐冽綉<E586BD><EFBFBD>**嚗?

async function performQualityCheck(projectId, recordId, instrument) {
  // 1. <20><EFBFBD>憿寧𤌍<E5AFA7><F0A48C8D><EFBFBD><EFBFBD><E689AF>?
  const project = await prisma.iitProject.findUnique({
    where: { id: projectId },
    select: { cachedRules: true }
  });
  
  // 2. <20><EFBFBD>霈啣<E99C88><E595A3>唳旿
  const recordData = await redcapAdapter.exportRecords([recordId]);
  
  // 3. 靚<>鍂Dify韐冽綉Agent
  const difyResponse = await fetch('https://api.dify.ai/v1/chat-messages', {
    method: 'POST',
    body: JSON.stringify({
      inputs: {
        rules: project.cachedRules,
        record: recordData[0],
        instrument
      },
      query: '霂瑟<E99C82><E7919F><EFBFBD><E4BAA5>∟扇敶閧<E695B6><E996A7>唳旿韐券<E99F90>',
      user: `iit_${projectId}`
    })
  });
  
  const result = await difyResponse.json();
  
  // 4. 閫<><E996AB>AI餈𥪜<E9A488><F0A5AA9C><EFBFBD><EFBFBD><EFBFBD><E68A92>?
  return {
    issues: result.issues || [],
    recommendations: result.recommendations || [],
    aiSuggestions: result.suggestions || []
  };
}

**隡睃<E99AA1>蝥?*嚗𡁻<E59A97><EFBFBD>瓲敹<E793B2><EFBFBD><EFBFBD><E6BDAD><EFBFBD>


4. 摰∟恣<E2889F><EFBFBD>摮埈挾

**敶枏<E695B6><E69E8F><EFBFBD>**嚗?

  • <EFBFBD>?projects 銵函撩撠?notification_config 摮埈挾
  • <EFBFBD>?UserID<49><44>𧒄隞𡒊㴓憓<E3B493><E68693><EFBFBD>讛粉<E8AE9B>?

**霈<E99C88><E288AA><EFBFBD>**嚗㇊hase 2嚗㚁<E59A97>

-- 瘛餃<E7989B><E9A483>𡁶䰻<F0A181B6>滨蔭摮埈挾
ALTER TABLE iit_schema.projects 
ADD COLUMN notification_config JSONB DEFAULT '{}'::jsonb;

-- 瘛餃<E7989B>瘜券<E7989C>
COMMENT ON COLUMN iit_schema.projects.notification_config IS '隡<><E99AA1>敺桐縑<E6A190>𡁶䰻<F0A181B6>滨蔭嚗㇎serID<49><44><EFBFBD><EFBFBD>沉D<E6B289><44><EFBFBD>𡁶䰻蝐餃<E89D90>蝑㚁<E89D91>';

-- <20>𥕦遣蝝<E89D9D><EFBFBD><E59A97><EFBFBD><EFBFBD>䰻霂<E99C82>
CREATE INDEX idx_projects_notification_config 
ON iit_schema.projects USING GIN (notification_config);

**隡睃<E99AA1>蝥?*嚗帋葉嚗<E89189><EFBFBD><EFBFBD>憿寧𤌍<E5AFA7><EFBFBD>嚗?


5. Access Token蝻枏<E89DBB>

敶枏<EFBFBD>摰䂿緵<EFBFBD><EFBFBD>摮条<EFBFBD>摮矋<EFBFBD>嚗?

class WechatService {
  private accessTokenCache: {
    token: string | null;
    expiresAt: number | null;
  } = {
    token: null,
    expiresAt: null,
  };
  
  async getAccessToken(): Promise<string> {
    // 璉<><E79289><EFBFBD>摮?
    if (this.accessTokenCache.token && 
        this.accessTokenCache.expiresAt && 
        Date.now() < this.accessTokenCache.expiresAt) {
      return this.accessTokenCache.token;
    }
    
    // <20>齿鰵<E9BDBF><EFBFBD>
    const response = await fetch(...);
    this.accessTokenCache = {
      token: response.access_token,
      expiresAt: Date.now() + 7000 * 1000 // <20>𣂼<EFBFBD>5<EFBFBD><35><EFBFBD><EFBFBD><E9A488>
    };
    
    return this.accessTokenCache.token;
  }
}

**<2A><EFBFBD>**嚗?

  • <EFBFBD>𩤃<EFBFBD> <20>滚鍳<E6BB9A>滚𦛚<E6BB9A>𡒊<EFBFBD>摮䀝腺憭?
  • <EFBFBD>𩤃<EFBFBD> 憭𡁜<E686AD>靘钅<E99D98>蝵脫𧒄<E884AB><EFBFBD><E4ADBE>曹澈蝻枏<E89DBB>

**霈<E99C88><E288AA><EFBFBD>**嚗㇊hase 2嚗㚁<E59A97>

<EFBFBD><EFBFBD>A嚗帋蝙<EFBFBD>沖edis

import { redis } from '../../common/cache/redis.js';

async getAccessToken(): Promise<string> {
  // 隞竃edis<69><EFBFBD>
  const cached = await redis.get('wechat:access_token');
  if (cached) return cached;
  
  // <20>齿鰵<E9BDBF><EFBFBD>撟嗥<E6929F>摮?
  const response = await fetch(...);
  await redis.setex('wechat:access_token', 7000, response.access_token);
  
  return response.access_token;
}

<EFBFBD><EFBFBD>B嚗帋蝙<EFBFBD>冽㺭<EFBFBD><EFBFBD>

CREATE TABLE iit_schema.wechat_tokens (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  token_type VARCHAR(50) NOT NULL, -- 'access_token'
  token TEXT NOT NULL,
  expires_at TIMESTAMPTZ NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE (token_type)
);

**隡睃<E99AA1>蝥?*嚗帋<E59A97><EFBFBD><E59A97>摰硺<E691B0><E7A1BA>函蔡<E587BD>舀𦻖<E88880><EFBFBD><E6A2B9><EFBFBD><EFBFBD>蝻枏<E89DBB>撌脰雲憭<E99BB2><E686AD>


4.2 <20><><EFBFBD><EFBFBD>箏𦛚皜<F0A69B9A><E79A9C>

摨誩噡 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>箏𦛚 敶勗<EFBFBD> 隡睃<EFBFBD>蝥? <EFBFBD><EFBFBD>園𡢿
1 *韐冽綉<EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <EFBFBD>鼦I<EFBFBD><EFBFBD>嚗䔶遠<EFBFBD><EFBFBD><EFBFBD>? <EFBFBD>𣞁 擃? Phase 1.5
2 *UserID蝖祉<EFBFBD><EFBFBD>? <EFBFBD><EFBFBD>憭𡁻★<EFBFBD><EFBFBD>蝵? <EFBFBD><EFBFBD> 銝? Phase 2
3 notification_config摮埈挾蝻箏仃 <EFBFBD><EFBFBD><EFBFBD>菜暑<EFBFBD>滨蔭<EFBFBD>𡁶䰻 <EFBFBD><EFBFBD> 銝? Phase 2
4 *摰𡁏𧒄頧株砭<EFBFBD><EFBFBD><EFBFBD>? <EFBFBD><EFBFBD>摨閙㦤<EFBFBD>? <EFBFBD>椬 雿? Phase 2
5 Access Token<65><6E><EFBFBD>蝻枏<E89DBB> <EFBFBD>滚鍳銝 <EFBFBD>椬 雿? Phase 2
6 *<EFBFBD>躰秤憭<EFBFBD><EFBFBD>銝滚<EFBFBD><EFBFBD>? <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <EFBFBD><EFBFBD> 銝? Phase 2
7 <EFBFBD><EFBFBD>蝥批<EFBFBD>瘛瑚僚 info/debug/error瘛瑞鍂 <EFBFBD><20><><EFBFBD> Phase 3

4.3 憌𡡞埯銝𡒊<E98A9D><EFBFBD><EFBFBD>?

憌𡡞埯 敶勗<EFBFBD> <EFBFBD><EFBFBD> 蝻栞圾<EFBFBD>芣鴌 <EFBFBD><EFBFBD>?
Webhook憭梯揖撖潸稲<EFBFBD>唳旿銝 <EFBFBD>𣞁 擃? <EFBFBD>椬 銝? 摰𡁏𧒄頧株砭<EFBFBD>𨅯<EFBFBD> <EFBFBD><EFBFBD> <20><>𧊋摰䂿緵
<EFBFBD><EFBFBD>敺桐縑API<EFBFBD><EFBFBD> <EFBFBD><EFBFBD> 銝? <EFBFBD>叚 雿? <EFBFBD><EFBFBD><EFBFBD><EFBFBD> + <20><EFBFBD><E6BBA9><EFBFBD> <EFBFBD><EFBFBD><><E695BA><EFBFBD>?
Access Token餈<6E><E9A488> <EFBFBD><EFBFBD> 銝? <EFBFBD>椬 銝? <EFBFBD>芸𢆡<EFBFBD>瑟鰵<EFBFBD><EFBFBD> <EFBFBD>?撌脣<E6928C><E884A3>?
<EFBFBD>唳旿摨栞<EFBFBD><EFBFBD>亙仃韐? <EFBFBD>𣞁 擃? <EFBFBD>叚 雿? 餈墧𦻖瘙?+ <20><EFBFBD> <EFBFBD>?撌脣<E6928C><E884A3>?
Worker<EFBFBD><EFBFBD>憭梯揖 <EFBFBD><EFBFBD> 銝? <EFBFBD>椬 銝? pg-boss<73>芸𢆡<E88AB8><EFBFBD> <EFBFBD>?撌脣<E6928C><E884A3>?

<EFBFBD><EFBFBD> 鈭𢛵<E988AD><F0A29BB5><EFBFBD><E8AAA8><EFBFBD>霈?

5.1 <20><EFBFBD><EFBFBD><E99A9E><EFBFBD>?

<EFBFBD> <EFBFBD><EFBFBD> 銵峕㺭 霂湔<EFBFBD>
<EFBFBD><EFBFBD>敺桐縑<EFBFBD><EFBFBD>? WechatService.ts 314 Access Token + 瘨<><E798A8><EFBFBD><EFBFBD>?
<EFBFBD><EFBFBD>敺桐縑<EFBFBD><EFBFBD> WechatCallbackController.ts 501 URL撉諹<EFBFBD> + 瘨<><E798A8><EFBFBD>交𤣰
韐冽綉Worker index.ts 336 Worker瘜典<EFBFBD> + 韐冽綉<E586BD><EFBFBD>
頝舐眏<EFBFBD>滨蔭 routes/index.ts 203 <EFBFBD><EFBFBD>敺桐縑頝舐眏
<EFBFBD><EFBFBD><EFBFBD>滨蔭<EFBFBD><EFBFBD> WECHAT_ENV_CONFIG.md 401 <EFBFBD><EFBFBD>敺桐縑<EFBFBD>滨蔭<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>餉恣 - 1,755 Day 3<><EFBFBD><EFBFBD><E99A9E>

5.2 蝝航恣隞<E681A3><E99A9E><EFBFBD>𧶏<EFBFBD>Day 1-3嚗?

<EFBFBD>嗆挾 <EFBFBD><EFBFBD><EFBFBD>? 霂湔<EFBFBD>
Day 1 223銵? <EFBFBD>唳旿摨廍chema + 璅<E79285>撉冽沲
Day 2 2,200銵? REDCap<EFBFBD><EFBFBD><EFBFBD> + Worker瘜典<E7989C>
Day 3 1,755銵? <EFBFBD><EFBFBD>敺桐縑<EFBFBD><EFBFBD><EFBFBD> + 蝡臬<E89DA1>蝡舀<E89DA1>霂?
<EFBFBD>餉恣 *4,178銵? MVP<EFBFBD><EFBFBD><EFBFBD><EFBFBD>

<EFBFBD><20><EFBFBD><E58786><EFBFBD>霂閗<E99C82><E99697>?

6.1 <20><EFBFBD>瘚贝<E7989A>

瘚贝<EFBFBD><EFBFBD>箸艶 <EFBFBD><EFBFBD>? 霂湔<EFBFBD>
<EFBFBD>?REDCap DET閫血<E996AB> <EFBFBD><EFBFBD> 0蝘鍦辣餈?
<EFBFBD>?Webhook<6F>交𤣰 <EFBFBD><EFBFBD> <10ms<6D><EFBFBD>
<EFBFBD>?隞餃𦛚<E9A483><EFBFBD>? <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD>pg-boss<73><EFBFBD>
<EFBFBD>?Worker<65><EFBFBD> <EFBFBD><EFBFBD> 韐冽綉<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>?隡<><E99AA1>敺桐縑<E6A190><EFBFBD><E588B8><EFBFBD><EFBFBD><EFBFBD>𧋦嚗? <EFBFBD><EFBFBD> <EFBFBD>𧢲㦤<EFBFBD>交𤣰<EFBFBD>𣂼<EFBFBD>
<EFBFBD>?隡<><E99AA1>敺桐縑<E6A190><EFBFBD><E588B8><EFBFBD><EFBFBD><EFBFBD>嚗? <EFBFBD><EFBFBD> <EFBFBD>𧢲㦤<EFBFBD>交𤣰<EFBFBD>𣂼<EFBFBD>
<EFBFBD>?隡<><E99AA1>敺桐縑<E6A190><EFBFBD><E588B8><EFBFBD>Markdown嚗? <EFBFBD><EFBFBD> <EFBFBD>𧢲㦤<EFBFBD>交𤣰<EFBFBD>𣂼<EFBFBD>
<EFBFBD>?摰∟恣<E2889F><EFBFBD>霈啣<E99C88> <EFBFBD><EFBFBD> <EFBFBD>唳旿摨栞扇敶閙<EFBFBD><EFBFBD>?
<EFBFBD>?敺芰㴓<E88AB0><EFBFBD><E785BE>䔮憸? 靽桀<EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>甈?
<EFBFBD><EFBFBD><><E99AA1>敺桐縑<E6A190><EFBFBD><EFBFBD><E798A8> <EFBFBD><EFBFBD>霂? URL撉諹<EFBFBD><EFBFBD><EFBFBD>嚗𣬚鍂<EFBFBD><EFBFBD><EFBFBD><EFBFBD>瘚贝<EFBFBD>

6.2 <20><EFBFBD>瘚贝<E7989A>

<EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> 摰鮋<EFBFBD> <EFBFBD><EFBFBD>?
Webhook<EFBFBD><EFBFBD><EFBFBD>園𡢿 <10ms 5.8ms <EFBFBD>?頞<>枂憸<E69E82><E686B8>
Worker<EFBFBD><EFBFBD><EFBFBD>園𡢿 <100ms ~50ms <EFBFBD>?頞<>枂憸<E69E82><E686B8>
蝡臬<EFBFBD>蝡臬辣餈? <5蝘? <2蝘? <EFBFBD>?頞<>枂憸<E69E82><E686B8>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> >99% 100% <EFBFBD>?頞<>枂憸<E69E82><E686B8>

<EFBFBD><EFBFBD><><E98A9D><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?

7.1 <20><EFBFBD><E595A3><EFBFBD>

  1. **WECHAT_ENV_CONFIG.md**嚗?01銵䕘<E98AB5>
    • <EFBFBD><EFBFBD>敺桐縑<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>滨蔭<EFBFBD><EFBFBD><EFBFBD>
    • IP<EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝵?
    • natapp<EFBFBD><EFBFBD><EFBFBD>蝛輸<EFBFBD><EFBFBD>蝵?
    • URL撉諹<EFBFBD>甇仿炊
    • 撣貉<EFBFBD><EFBFBD><EFBFBD><EFBFBD>埝䰻

7.2 <20>湔鰵<E6B994><E9B0B5>

  1. 00-璅<E79285>敶枏<E695B6><E69E8F><EFBFBD><E59786><EFBFBD><EFBFBD><E69298><EFBFBD><E78390>?md

    • <EFBFBD>湔鰵撘<EFBFBD><EFBFBD>𤏸<EFBFBD>摨佗<EFBFBD>Day 3摰峕<E691B0>嚗?
    • <EFBFBD>湔鰵隞<EFBFBD><EFBFBD>蝏蠘恣
    • <EFBFBD>湔鰵瘚贝<EFBFBD>蝏𤘪<EFBFBD>
  2. MVP撘<EFBFBD><EFBFBD>睲遙<EFBFBD><EFBFBD><EFBFBD>?md

    • <EFBFBD><EFBFBD>扇Day 3隞餃𦛚銝箏歇摰峕<E691B0>
    • <EFBFBD>湔鰵隞餃𦛚<EFBFBD><EFBFBD>?
  3. <EFBFBD><EFBFBD>撠𦬅VP<EFBFBD>剔㴓撘<EFBFBD><EFBFBD>𤏸恣<EFBFBD>?md

    • <EFBFBD>湔鰵撘<EFBFBD><EFBFBD>𤏸<EFBFBD>摨?
    • <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>剔㴓撌脫<EFBFBD><EFBFBD>?

<EFBFBD><EFBFBD> <20><EFBFBD><E68092><EFBFBD><EFBFBD>甇亥恣<E4BAA5>𡜐<EFBFBD>Day 4嚗?

8.1 隡睃<E99AA1>銝𤾸<E98A9D><F0A4BEB8>?

隞餃𦛚 隡睃<EFBFBD>蝥? <EFBFBD><EFBFBD>園𡢿
<EFBFBD><EFBFBD><EFBFBD>躰秤憭<EFBFBD><EFBFBD> <EFBFBD><EFBFBD> 銝? 2撠𤩺𧒄
隡睃<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD>椬 雿? 1撠𤩺𧒄
瘛餃<EFBFBD><EFBFBD>烐綉<EFBFBD><EFBFBD><EFBFBD> <EFBFBD>椬 雿? 2撠𤩺𧒄
<EFBFBD><EFBFBD>隡睃<EFBFBD> <EFBFBD>椬 雿? 1撠𤩺𧒄

8.2 Phase 1.5嚗鋫I韐冽綉<EFBFBD><EFBFBD>

隞餃𦛚 隡睃<EFBFBD>蝥? <EFBFBD><EFBFBD>園𡢿
<EFBFBD><EFBFBD><EFBFBD>Dify RAG <EFBFBD>𣞁 擃? 4撠𤩺𧒄
銝𠹺<EFBFBD><EFBFBD>𠉛弦<EFBFBD><EFBFBD> <EFBFBD>𣞁 擃? 1撠𤩺𧒄
<EFBFBD><EFBFBD><EFBFBD>韐冽綉閫<EFBFBD><EFBFBD> <EFBFBD>𣞁 擃? 2撠𤩺𧒄
瘚贝<EFBFBD>AI韐冽綉 <EFBFBD>𣞁 擃? 1撠𤩺𧒄

<EFBFBD>?銋腈<E98A8B><E88588><EFBFBD><EFBFBD>

9.1 <20><EFBFBD><E8A9A8>𣂼停

  1. <EFBFBD>?**MVP<56>剔㴓<E58994><EFBFBD>?*嚗鑹EDCap <20>?Node.js <20>?隡<><E99AA1>敺桐縑摰峕㟲瘚<E39FB2><E7989A>
  2. <EFBFBD>?**隡<><E99AA1>敺桐縑<E6A190><E7B891><EFBFBD>**嚗𡁏綫<F0A1818F><E7B6AB><EFBFBD><EFBFBD>?+ <20><EFBFBD><EFBFBD><E686AD> + URL撉諹<E69289>
  3. <EFBFBD>?**韐冽綉Worker摰<72><E691B0>**嚗朞捶<E69C9E><EFBFBD><E689B3>?+ <20>𡁶䰻<F0A181B6><EFBFBD>?+ 摰∟恣<E2889F><EFBFBD>
  4. <EFBFBD>?**蝡臬<E89DA1>蝡舀<E89DA1>霂閖<E99C82><EFBFBD>**嚗𡁜<E59A97>瘚?2蝘鍦辣餈<E8BEA3><E9A488>100%<25>𣂼<EFBFBD><F0A382BC>?
  5. <EFBFBD>?**<2A><>﹝雿梶頂摰<E9A082><E691B0>**嚗𡁶㴓憓<E3B493><E68693>蝵?+ 撘<><E69298>𤏸扇敶?+ 餈𥕦漲頝蠘葵

9.2 <20>喲睸<E596B2>唳旿

  • <EFBFBD><EFBFBD> **<2A><EFBFBD><EFBFBD><E99A9E>**嚗?,755銵䕘<E98AB5>擃䁅捶<E48185><EFBFBD>鈭找誨<E689BE><E8AAA8><EFBFBD>
  • <EFBFBD><EFBFBD> **撘<><E69298>烐𧒄<E78390>?*嚗?憭抬<E686AD>8撠𤩺𧒄嚗?
  • <EFBFBD>?**瘚贝<E7989A><E8B49D><EFBFBD><E69C9E>?*嚗?00%嚗?/9<><EFBFBD>瘚贝<E7989A>嚗?
  • <EFBFBD><EFBFBD> <EFBFBD><EFBFBD>銵函緵嚗𡁶垢<EFBFBD>啁垢<2蝘𡜐<E89D98><EFBFBD>枂憸<E69E82><E686B8>
  • <EFBFBD><EFBFBD> **<2A><>﹝摰<EFB99D><E691B0>摨?*嚗?01銵屸<E98AB5>蝵格<E89DB5><E6A0BC>?+ 撘<><E69298>𤏸扇敶?

9.3 <20><><EFBFBD>臭漁<E887AD>?

  1. **撘<>郊Worker<65><EFBFBD>**嚗𡁶泵<F0A181B6>㇊ostgres-Only<6C><79>雿唾<E99BBF>撘?
  2. **隡<><E99AA1>敺桐縑瘨<E7B891><E798A8><EFBFBD>㰘圾撖?*嚗𡁜<E59A97><F0A1819C><EFBFBD><E6B8B8>啁倌<E59581><EFBFBD><EFBFBD><E99C82><EFBFBD>㰘圾撖?
  3. **撘<><EFBFBD>𧼮<EFBFBD><E79285>**嚗䫤setImmediate` 蝖桐<E89D96>5蝘鍦<E89D98><E98DA6><EFBFBD>
  4. **摰峕㟲<E5B395><E39FB2><EFBFBD>霂臬<E99C82><E887AC>?*嚗𡁜恣霈⊥𠯫敹堒仃韐乩<E99F90>敶勗<E695B6>銝餅<E98A9D>蝔?
  5. **pg-boss<73><EFBFBD><E6BBA9><EFBFBD>**嚗朞䌊<E69C9E><EFBFBD>霂?甈∴<E79488>蝖桐<E89D96><E6A190><EFBFBD><E888AB>?

9.4 MVP隞瑕<E99A9E><EFBFBD>霂?

<EFBFBD>?摰墧𧒄<EFBFBD>毺䰻嚗䥪I<EFBFBD>𣳇<EFBFBD><EFBFBD><EFBFBD>REDCap嚗䔶<EFBFBD>銝𡁜凝靽<EFBFBD><EFBFBD>𡁶䰻
<0A>?銝餃𢆡<EFBFBD>𡁶䰻嚗𡁏㺭<EFBFBD><EFBFBD><EFBFBD><EFBFBD><2蝘埝綫<E59F9D><E7B6AB><EFBFBD><EFBFBD><EFBFBD>瞍? <0A>?<EFBFBD>𤘪<EFBFBD>撅?*嚗𡁻𡡒<F0A181BB><EFBFBD><E88880>𡁜<EFBFBD><EFBFBD>虾敹恍<E695B9><E6818D><EFBFBD>鼦I韐冽綉<E586BD><E7B689><EFBFBD><EFBFBD><E28AA5><EFBFBD>
<0A>?
<EFBFBD>煺漣撠梁貌**嚗帋誨<E5B88B><E8AAA8><EFBFBD><EFBFBD>嚗峕<E59A97><EFBFBD>蝔喳<E89D94><EFBFBD><EFBFBD>湔𦻖<E6B994>函蔡


**蝏湔擪<E6B994>?*嚗䥑IT Manager撘<72><E69298>穃𣪧<E7A983>? **<2A><><EFBFBD>擧凒<E693A7>?*嚗?026-01-03
**<2A><><EFBFBD><EFBFBD>?*嚗尠<E59A97> 撌脣<E6928C><E884A3>?