Features - User Management (Phase 4.1): - Database: Add user_modules table for fine-grained module permissions - Database: Add 4 user permissions (view/create/edit/delete) to role_permissions - Backend: UserService (780 lines) - CRUD with tenant isolation - Backend: UserController + UserRoutes (648 lines) - 13 API endpoints - Backend: Batch import users from Excel - Frontend: UserListPage (412 lines) - list/filter/search/pagination - Frontend: UserFormPage (341 lines) - create/edit with module config - Frontend: UserDetailPage (393 lines) - details/tenant/module management - Frontend: 3 modal components (592 lines) - import/assign/configure - API: GET/POST/PUT/DELETE /api/admin/users/* endpoints Architecture Upgrade - Module Permission System: - Backend: Add getUserModules() method in auth.service - Backend: Login API returns modules array in user object - Frontend: AuthContext adds hasModule() method - Frontend: Navigation filters modules based on user.modules - Frontend: RouteGuard checks requiredModule instead of requiredVersion - Frontend: Remove deprecated version-based permission system - UX: Only show accessible modules in navigation (clean UI) - UX: Smart redirect after login (avoid 403 for regular users) Fixes: - Fix UTF-8 encoding corruption in ~100 docs files - Fix pageSize type conversion in userService (String to Number) - Fix authUser undefined error in TopNavigation - Fix login redirect logic with role-based access check - Update Git commit guidelines v1.2 with UTF-8 safety rules Database Changes: - CREATE TABLE user_modules (user_id, tenant_id, module_code, is_enabled) - ADD UNIQUE CONSTRAINT (user_id, tenant_id, module_code) - INSERT 4 permissions + role assignments - UPDATE PUBLIC tenant with 8 module subscriptions Technical: - Backend: 5 new files (~2400 lines) - Frontend: 10 new files (~2500 lines) - Docs: 1 development record + 2 status updates + 1 guideline update - Total: ~4900 lines of code Status: User management 100% complete, module permission system operational
11 KiB
11 KiB
API设计规范
版本: v2.0
最后更新: 2025-11-06
API风格: RESTful API
基础URL:http://localhost:3001/api/v1
适用范围: 平台层 + 能力层 + 业务模块层
📋 设计原则
API First原则
- ✅ 先设计API,再实现功能
- ✅ API是前后端的契约
- ✅ API变更需要版本控制
- ✅ 所有API都要有文档
RESTful设计
- ✅ 使用HTTP动词表示操作(GET、POST、PUT、DELETE)
- ✅ URL表示资源,不表示动作
- ✅ 使用复数名词表示资源集合
- ✅ 嵌套资源不超过2层
- ✅ 使用HTTP状态码表示结果
命名规范
- ✅ URL使用小写字母和连字符(kebab-case)
- ✅ 查询参数使用驼峰命名(camelCase)
- ✅ JSON字段使用驼峰命名(camelCase)
🎯 URL设计规范
路径格式
/api/v{version}/{module}/{resource}/{id?}/{action?}
示例:
/api/v1/literature/projects # 获取文献项目列表
/api/v1/literature/projects/123 # 获取ID=123的项目
/api/v1/literature/projects/123/export # 导出项目(动作)
模块前缀
| 模块 | 路由前缀 | 示例 |
|---|---|---|
| 认证 | /auth |
/api/v1/auth/login |
| 用户 | /users |
/api/v1/users/me |
| AI问答 | /chat |
/api/v1/chat/conversations |
| 智能体 | /agents |
/api/v1/agents |
| AI文献 | /literature |
/api/v1/literature/projects |
| 知识库 | /knowledge-bases |
/api/v1/knowledge-bases |
| 数据清洗 | /data-cleaning |
/api/v1/data-cleaning/projects |
| 统计分析 | /analysis |
/api/v1/analysis/projects |
| 统计工具 | /tools |
/api/v1/tools |
| 稿件审查 | /review |
/api/v1/review/tasks |
| LLM网关 | /llm |
/api/v1/llm/chat |
| 管理端 | /admin |
/api/v1/admin/users |
资源命名
✅ 正确示例:
GET /api/v1/literature/projects # 获取列表
GET /api/v1/literature/projects/:id # 获取详情
POST /api/v1/literature/projects # 创建
PUT /api/v1/literature/projects/:id # 更新
DELETE /api/v1/literature/projects/:id # 删除
GET /api/v1/literature/projects/:id/items # 获取项目下的文献
POST /api/v1/literature/projects/:id/items/import # 导入文献
POST /api/v1/literature/projects/:id/screening/execute # 执行筛选
❌ 错误示例:
POST /api/v1/literature/getProjects # 使用动词
POST /api/v1/literature/createProject # 使用动词
GET /api/v1/literature/project # 单数形式
GET /api/v1/literatureProjectList # 驼峰命名
🔧 HTTP方法规范
方法使用
| 方法 | 用途 | 是否幂等 | 是否安全 |
|---|---|---|---|
| GET | 获取资源 | ✅ | ✅ |
| POST | 创建资源 | ❌ | ❌ |
| PUT | 完整更新资源 | ✅ | ❌ |
| PATCH | 部分更新资源 | ❌ | ❌ |
| DELETE | 删除资源 | ✅ | ❌ |
方法示例
# 获取资源列表
GET /api/v1/literature/projects
# 获取单个资源
GET /api/v1/literature/projects/123
# 创建资源
POST /api/v1/literature/projects
Content-Type: application/json
{ "name": "新项目", "description": "..." }
# 完整更新资源(所有字段)
PUT /api/v1/literature/projects/123
Content-Type: application/json
{ "name": "更新", "description": "..." }
# 部分更新资源(部分字段)
PATCH /api/v1/literature/projects/123
Content-Type: application/json
{ "name": "只更新名称" }
# 删除资源
DELETE /api/v1/literature/projects/123
📊 状态码规范
标准状态码
| 状态码 | 含义 | 使用场景 |
|---|---|---|
| 200 | OK | 成功返回数据 |
| 201 | Created | 成功创建资源 |
| 204 | No Content | 成功但无返回数据(如删除) |
| 400 | Bad Request | 请求参数错误 |
| 401 | Unauthorized | 未认证(没有Token或Token过期) |
| 403 | Forbidden | 无权限(已认证但权限不足) |
| 404 | Not Found | 资源不存在 |
| 409 | Conflict | 资源冲突(如重复创建) |
| 422 | Unprocessable Entity | 语义错误(如验证失败) |
| 429 | Too Many Requests | 请求过于频繁(限流) |
| 500 | Internal Server Error | 服务器错误 |
状态码使用示例
// 200 OK - 成功获取数据
res.status(200).json({ success: true, data: projects });
// 201 Created - 成功创建资源
res.status(201).json({ success: true, data: newProject });
// 204 No Content - 成功删除(无内容返回)
res.status(204).send();
// 400 Bad Request - 参数错误
res.status(400).json({
success: false,
error: { code: 'INVALID_PARAMS', message: '参数错误' }
});
// 401 Unauthorized - 未认证
res.status(401).json({
success: false,
error: { code: 'UNAUTHORIZED', message: '请先登录' }
});
// 403 Forbidden - 无权限
res.status(403).json({
success: false,
error: { code: 'FORBIDDEN', message: '无权访问' }
});
// 404 Not Found - 资源不存在
res.status(404).json({
success: false,
error: { code: 'NOT_FOUND', message: '资源不存在' }
});
// 422 Unprocessable Entity - 验证失败
res.status(422).json({
success: false,
error: {
code: 'VALIDATION_ERROR',
message: '参数验证失败',
details: [...]
}
});
📝 响应格式规范
统一响应格式 ⭐ 必须遵守
成功响应:
{
"success": true,
"data": {
// 实际数据
},
"message": "操作成功"
}
错误响应:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "错误信息",
"details": [...] // 可选,详细错误信息
}
}
列表数据响应
{
"success": true,
"data": {
"items": [
{ "id": 1, "name": "项目1" },
{ "id": 2, "name": "项目2" }
],
"pagination": {
"page": 1,
"pageSize": 10,
"total": 100,
"totalPages": 10,
"hasNext": true,
"hasPrev": false
}
},
"message": "获取成功"
}
验证错误响应
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "参数验证失败",
"details": [
{
"field": "email",
"message": "邮箱格式不正确"
},
{
"field": "password",
"message": "密码长度必须大于6位"
}
]
}
}
🔑 认证与授权规范
JWT认证
1. 登录获取Token
POST /api/v1/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "password123"
}
# Response
{
"success": true,
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 604800, // 7天(秒)
"user": {
"id": 123,
"email": "user@example.com",
"name": "张三",
"role": "user"
}
}
}
2. 使用Token访问API
GET /api/v1/literature/projects
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
3. Token过期处理
# Token过期,返回401
{
"success": false,
"error": {
"code": "TOKEN_EXPIRED",
"message": "Token已过期,请重新登录"
}
}
# 使用refreshToken刷新
POST /api/v1/auth/refresh
Content-Type: application/json
{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
权限控制
| 端点类型 | 需要认证 | 角色要求 |
|---|---|---|
| 公开端点 | ❌ | 无 |
| 用户端点 | ✅ | user |
| 管理端点 | ✅ | admin |
示例:
// 公开端点(无需认证)
POST /api/v1/auth/login
POST /api/v1/auth/register
// 用户端点(需要认证,user角色)
GET /api/v1/literature/projects
POST /api/v1/literature/projects
// 管理端点(需要认证,admin角色)
GET /api/v1/admin/users
POST /api/v1/admin/users/:id/disable
📄 分页规范
请求参数
GET /api/v1/literature/projects?page=1&pageSize=20&sortBy=createdAt&sortOrder=desc
Query参数:
- page: 页码(默认1)
- pageSize: 每页数量(默认10,最大100)
- sortBy: 排序字段(默认createdAt)
- sortOrder: 排序方向(asc/desc,默认desc)
响应格式
{
"success": true,
"data": {
"items": [...],
"pagination": {
"page": 1,
"pageSize": 20,
"total": 100,
"totalPages": 5,
"hasNext": true,
"hasPrev": false
}
}
}
🔍 筛选与搜索规范
筛选参数
GET /api/v1/literature/projects?status=active&keyword=骨质疏松
Query参数:
- status: 状态筛选(active/inactive)
- keyword: 关键词搜索(搜索name和description字段)
- userId: 用户ID筛选(管理端)
- startDate/endDate: 日期范围筛选
搜索响应
{
"success": true,
"data": {
"items": [...],
"pagination": {...},
"filters": {
"status": "active",
"keyword": "骨质疏松"
}
}
}
⚠️ 错误码设计
标准错误码
| 错误码 | HTTP状态 | 说明 |
|---|---|---|
VALIDATION_ERROR |
422 | 参数验证失败 |
UNAUTHORIZED |
401 | 未认证 |
TOKEN_EXPIRED |
401 | Token过期 |
FORBIDDEN |
403 | 无权限 |
NOT_FOUND |
404 | 资源不存在 |
ALREADY_EXISTS |
409 | 资源已存在 |
QUOTA_EXCEEDED |
429 | 配额超限 |
INTERNAL_ERROR |
500 | 服务器错误 |
业务错误码
// 模块特定错误码(前缀区分)
ASL_IMPORT_FAILED // AI文献:导入失败
ASL_SCREENING_IN_PROGRESS // AI文献:筛选进行中
PKB_QUOTA_EXCEEDED // 知识库:配额超限
LLM_QUOTA_EXCEEDED // LLM:配额超限
🚀 性能优化规范
1. 分页必须
所有列表接口必须支持分页:
- 默认pageSize=10
- 最大pageSize=100
- 禁止一次性返回全部数据
2. 字段过滤
GET /api/v1/users/me?fields=id,name,email
只返回需要的字段,减少数据传输
3. 缓存策略
# 设置缓存头
Cache-Control: public, max-age=300
# 使用ETag
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
# 返回304 Not Modified
✅ 检查清单
设计新API时必须检查:
- URL符合RESTful规范(使用名词+复数)
- 使用正确的HTTP方法(GET/POST/PUT/DELETE)
- 使用正确的HTTP状态码
- 响应格式符合统一规范(success + data/error)
- 需要认证的接口检查JWT Token
- 需要权限的接口检查用户角色
- 列表接口支持分页
- 列表接口支持排序
- 错误响应包含明确的错误码和错误信息
- 所有API都有文档说明
🔗 相关文档
总览:
- API路由总览 ⭐ 查看所有API端点
模板:
各模块设计:
最后更新: 2025-11-06
维护人: 技术架构师
版本: v2.0