feat(asl): Complete Deep Research V2.0 core development
Backend: - Add SSE streaming client (unifuncsSseClient) replacing async polling - Add paragraph-based reasoning parser with mergeConsecutiveThinking - Add requirement expansion service (DeepSeek-V3 PICOS+MeSH) - Add Word export service with Pandoc, inline hyperlinks, reference link expansion - Add deep research V2 worker with 2s log flush and Chinese source prompt - Add 5 curated data sources config (PubMed/ClinicalTrials/Cochrane/CNKI/MedJournals) - Add 4 API endpoints (generate-requirement/tasks/task-status/export-word) - Update Prisma schema with 6 new V2.0 fields on AslResearchTask - Add DB migration for V2.0 fields - Simplify ASL_DEEP_RESEARCH_EXPANSION prompt (remove strategy section) Frontend: - Add waterfall-flow DeepResearchPage (phase 0-4 progressive reveal) - Add LandingView, SetupPanel, StrategyConfirm, AgentTerminal, ResultsView - Add react-markdown + remark-gfm for report rendering - Add custom link component showing visible URLs after references - Add useDeepResearchTask polling hook - Add deep research TypeScript types Tests: - Add E2E test, smoke test, and Chinese data source test scripts Docs: - Update ASL module status (v2.0 - core features complete) - Update system status (v6.1 - ASL V2.0 milestone) - Update Unifuncs DeepSearch API guide (v2.0 - SSE mode + Chinese source results) - Update module auth specification (test script guidelines) - Update V2.0 development plan Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -157,9 +157,114 @@ interface DecodedToken {
|
||||
| IIT | N/A (企业微信) | N/A | ✅ 企业微信userId | ✅ |
|
||||
| Prompt管理 | ✅ getAuthHeaders | ✅ authenticate | ✅ getUserId | ✅ |
|
||||
|
||||
## 5. 常见错误和解决方案
|
||||
## 5. 测试脚本认证规范
|
||||
|
||||
### 5.1 401 Unauthorized
|
||||
> 编写 API 测试脚本时,需要先通过登录接口获取 Token,再携带到后续请求中。
|
||||
|
||||
### 5.1 登录接口
|
||||
|
||||
```
|
||||
POST /api/v1/auth/login/password
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"phone": "13800000001",
|
||||
"password": "123456"
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 登录响应结构
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"user": { "id": "...", "name": "...", "role": "SUPER_ADMIN" },
|
||||
"tokens": {
|
||||
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
|
||||
"refreshToken": "..."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Token 提取路径**:`res.data.data.tokens.accessToken`
|
||||
|
||||
### 5.3 测试脚本通用模板
|
||||
|
||||
```typescript
|
||||
const BASE_URL = process.env.TEST_BASE_URL || 'http://localhost:3001';
|
||||
const API_PREFIX = `${BASE_URL}/api/v1`;
|
||||
|
||||
const TEST_PHONE = process.env.TEST_PHONE || '13800000001';
|
||||
const TEST_PASSWORD = process.env.TEST_PASSWORD || '123456';
|
||||
|
||||
let authToken = '';
|
||||
|
||||
async function api(path: string, options: RequestInit = {}) {
|
||||
const res = await fetch(`${API_PREFIX}${path}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
||||
...(options.headers || {}),
|
||||
},
|
||||
});
|
||||
const contentType = res.headers.get('content-type') || '';
|
||||
const data = contentType.includes('json') ? await res.json() : await res.text();
|
||||
return { status: res.status, data };
|
||||
}
|
||||
|
||||
// 登录获取 Token
|
||||
async function login() {
|
||||
const res = await api('/auth/login/password', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ phone: TEST_PHONE, password: TEST_PASSWORD }),
|
||||
});
|
||||
if (res.status !== 200 || !res.data.success) {
|
||||
throw new Error(`登录失败: ${JSON.stringify(res.data)}`);
|
||||
}
|
||||
authToken = res.data.data.tokens.accessToken;
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 测试账号说明
|
||||
|
||||
| 手机号 | 密码 | 角色 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| 13800000001 | 123456 | SUPER_ADMIN | 超级管理员,可访问所有模块 |
|
||||
| 13800000000 | 123456 | USER | 普通测试用户 |
|
||||
|
||||
> **注意**:`SUPER_ADMIN` 和 `PROMPT_ENGINEER` 角色在 `requireModule()` 中间件中自动豁免模块权限检查,无需在 `user_modules` 表中分配模块。普通 `USER` 角色需要先在 `platform_schema.user_modules` 中分配对应模块才能访问。
|
||||
|
||||
### 5.5 运行测试脚本
|
||||
|
||||
```bash
|
||||
# 前置条件:后端服务运行中 + PostgreSQL 运行中
|
||||
cd backend
|
||||
|
||||
# 方式一:使用默认测试账号
|
||||
npx tsx src/modules/xxx/__tests__/test-script.ts
|
||||
|
||||
# 方式二:通过环境变量指定账号
|
||||
$env:TEST_PHONE="13800000001"; $env:TEST_PASSWORD="123456"; npx tsx src/modules/xxx/__tests__/test-script.ts
|
||||
```
|
||||
|
||||
### 5.6 用户表说明
|
||||
|
||||
用户数据存储在 `platform_schema.users` 表中(**不是** `public.users`)。Prisma schema 中的 `User` model 映射到此表。关键字段:
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `phone` | 登录手机号(唯一) |
|
||||
| `password` | bcrypt 哈希密码 |
|
||||
| `role` | 角色:SUPER_ADMIN / HOSPITAL_ADMIN / DEPARTMENT_ADMIN / PROMPT_ENGINEER / USER 等 |
|
||||
| `tenant_id` | 租户 ID |
|
||||
| `status` | active / disabled |
|
||||
|
||||
## 6. 常见错误和解决方案
|
||||
|
||||
### 6.1 401 Unauthorized
|
||||
|
||||
**原因**: 前端没有携带 JWT Token 或 Token 过期
|
||||
|
||||
@@ -168,24 +273,38 @@ interface DecodedToken {
|
||||
2. 检查 localStorage 中是否有 `accessToken`
|
||||
3. 如果 Token 过期,尝试刷新或重新登录
|
||||
|
||||
### 5.2 User not authenticated
|
||||
### 6.2 User not authenticated
|
||||
|
||||
**原因**: 后端路由没有添加 `authenticate` 中间件
|
||||
|
||||
**解决**: 在路由定义中添加 `preHandler: [authenticate]`
|
||||
|
||||
### 5.3 TypeError: Cannot read property 'userId' of undefined
|
||||
### 6.3 TypeError: Cannot read property 'userId' of undefined
|
||||
|
||||
**原因**: 使用了错误的属性名(`request.user.id` 而非 `request.user.userId`)
|
||||
|
||||
**解决**: 使用 `(request as any).user?.userId`
|
||||
|
||||
## 6. 参考文件
|
||||
### 6.4 测试脚本 Token 为 NULL
|
||||
|
||||
**原因**: 登录返回的 Token 路径不对
|
||||
|
||||
**解决**: Token 位于 `res.data.data.tokens.accessToken`,不是 `res.data.data.accessToken` 或 `res.data.data.token`
|
||||
|
||||
### 6.5 测试脚本登录成功但 API 返回 401
|
||||
|
||||
**排查步骤**:
|
||||
1. 确认 Token 提取路径:`res.data.data.tokens.accessToken`
|
||||
2. 确认 Authorization header 格式:`Bearer <token>`(注意空格)
|
||||
3. 确认后端服务使用的 JWT_SECRET 与签发时一致
|
||||
|
||||
## 7. 参考文件
|
||||
|
||||
- 前端 axios 实例: `frontend-v2/src/common/api/axios.ts`
|
||||
- 前端 Token 管理: `frontend-v2/src/framework/auth/api.ts`
|
||||
- 后端认证中间件: `backend/src/common/auth/auth.middleware.ts`
|
||||
- 后端 JWT 服务: `backend/src/common/auth/jwt.service.ts`
|
||||
- 测试脚本示例: `backend/src/modules/asl/__tests__/deep-research-v2-smoke.ts`
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user