Backend fixes: - Fix PgBoss task infinite loop on SAE (root cause: missing queue table constraints) - Add singletonKey to prevent duplicate job enqueueing - Add idempotency check in reviewWorker (skip completed tasks) - Add optimistic locking in reviewService (atomic status update) Frontend fixes: - Add isSubmitting state to prevent duplicate submissions in RVW Dashboard - Fix API baseURL in knowledgeBaseApi (relative path) Cleanup (removed): - Old frontend/ directory (migrated to frontend-v2) - python-microservice/ (unused, replaced by extraction_service) - Root package.json and node_modules (accidentally created) - redcap-docker-dev/ (external dependency) - Various temporary files and outdated docs in root New documentation: - docs/07-运维文档/01-PgBoss队列监控与维护.md - docs/07-运维文档/02-故障预防检查清单.md - docs/07-运维文档/03-数据库迁移注意事项.md Database fix applied to RDS: - Added PRIMARY KEY to platform_schema.queue - Added 3 missing foreign key constraints Tested: Local build passed, RDS constraints verified
961 lines
30 KiB
Markdown
961 lines
30 KiB
Markdown
# PKB(个人知识库)和 RVW(审稿功能)迁移计划
|
||
|
||
> **创建日期:** 2025-12-28
|
||
> **维护者:** 技术团队
|
||
> **目标:** 将已开发的PKB和RVW功能迁移到最新的模块化架构上
|
||
|
||
---
|
||
|
||
## 📋 执行摘要
|
||
|
||
### 迁移目标
|
||
将旧版本(`frontend` + `backend/src/legacy`)中的**个人知识库(PKB)**和**审稿功能(RVW)**迁移到新架构(`frontend-v2` + `backend/src/modules`),使其符合最新的模块化、云原生设计规范。
|
||
|
||
### 当前状态
|
||
|
||
| 功能 | 旧架构位置 | 完成度 | 数据库Schema | 前端UI |
|
||
|------|-----------|--------|-------------|--------|
|
||
| **PKB 个人知识库** | `backend/src/legacy` + `frontend/src` | ✅ 100% | `pkb_schema` | ✅ 完整UI |
|
||
| **RVW 审稿功能** | `backend/src/legacy` + `frontend/src` | ✅ 100% | `public.ReviewTask` | ✅ 完整UI |
|
||
|
||
### 迁移优先级
|
||
1. **P0(最高优先级)**: PKB个人知识库 - 已100%完成,迁移风险低
|
||
2. **P1(高优先级)**: RVW审稿功能 - 已100%完成,迁移风险低
|
||
|
||
---
|
||
|
||
## 🔍 已有功能深度分析
|
||
|
||
### 一、PKB(个人知识库)功能详情
|
||
|
||
#### 1.1 功能特性
|
||
|
||
**核心能力:**
|
||
- ✅ **知识库CRUD**:创建、查看、编辑、删除知识库
|
||
- ✅ **配额管理**:每用户3个知识库,每库50个文档
|
||
- ✅ **文档上传**:支持PDF、Word、TXT、Markdown
|
||
- ✅ **文档状态追踪**:uploading → parsing → indexing → completed/error
|
||
- ✅ **Dify RAG集成**:基于Dify平台的向量检索
|
||
- ✅ **语义检索**:支持多知识库联合检索,top_k=15
|
||
- ✅ **统计信息**:文档数、Token数、段落数统计
|
||
- ✅ **全文阅读模式**(Phase2):Token限制、智能文档选择
|
||
|
||
**技术亮点:**
|
||
- 🏆 **Python微服务集成**:调用`extraction_service`提取文档文本
|
||
- 🏆 **Dify Dataset管理**:每个知识库对应一个Dify Dataset
|
||
- 🏆 **Token精确计算**:使用tiktoken计算Token数,双重限制(50文件 + 980K tokens)
|
||
- 🏆 **智能文档选择**:基于Token容量的智能推荐算法
|
||
|
||
#### 1.2 数据库结构
|
||
|
||
**PKB Schema(`pkb_schema`):**
|
||
```prisma
|
||
model KnowledgeBase {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
name String
|
||
description String?
|
||
difyDatasetId String // 映射到Dify
|
||
fileCount Int @default(0)
|
||
totalSizeBytes BigInt @default(0)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
documents Document[]
|
||
batchTasks BatchTask[]
|
||
}
|
||
|
||
model Document {
|
||
id String @id @default(uuid())
|
||
kbId String
|
||
userId String
|
||
filename String
|
||
fileType String
|
||
fileSizeBytes BigInt
|
||
fileUrl String
|
||
difyDocumentId String
|
||
status String // uploading/parsing/indexing/completed/error
|
||
progress Int @default(0)
|
||
errorMessage String?
|
||
segmentsCount Int?
|
||
tokensCount Int?
|
||
extractionMethod String? // nougat/pymupdf/mammoth
|
||
extractionQuality Float?
|
||
charCount Int?
|
||
language String? // chinese/english
|
||
extractedText String? // Phase2:全文存储
|
||
uploadedAt DateTime @default(now())
|
||
processedAt DateTime?
|
||
}
|
||
|
||
model BatchTask {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
kbId String
|
||
name String
|
||
templateType String
|
||
templateId String?
|
||
prompt String
|
||
status String
|
||
totalDocuments Int
|
||
completedCount Int @default(0)
|
||
failedCount Int @default(0)
|
||
modelType String
|
||
concurrency Int @default(3)
|
||
startedAt DateTime?
|
||
completedAt DateTime?
|
||
durationSeconds Int?
|
||
|
||
results BatchResult[]
|
||
}
|
||
```
|
||
|
||
#### 1.3 后端代码结构
|
||
|
||
**服务层(`backend/src/legacy/services/`):**
|
||
```typescript
|
||
knowledgeBaseService.ts (365行)
|
||
├── createKnowledgeBase() // 创建知识库(Dify Dataset)
|
||
├── getKnowledgeBases() // 获取列表
|
||
├── getKnowledgeBaseById() // 获取详情
|
||
├── updateKnowledgeBase() // 更新
|
||
├── deleteKnowledgeBase() // 删除(级联删除Dify Dataset)
|
||
├── searchKnowledgeBase() // 语义检索(调用Dify API)
|
||
├── getKnowledgeBaseStats() // 统计信息
|
||
└── getDocumentSelection() // 智能文档选择(Phase2)
|
||
|
||
documentService.ts
|
||
├── uploadDocument() // 上传文档
|
||
├── getDocuments() // 获取文档列表
|
||
├── deleteDocument() // 删除文档
|
||
├── reprocessDocument() // 重新处理
|
||
└── pollDocumentStatus() // 轮询状态
|
||
|
||
tokenService.ts (243行)
|
||
├── calculateDocumentTokens() // 计算Token
|
||
├── selectDocumentsForFullText() // 智能选择
|
||
└── TOKEN_LIMITS 常量
|
||
```
|
||
|
||
**控制器层(`backend/src/legacy/controllers/`):**
|
||
```typescript
|
||
knowledgeBaseController.ts (341行)
|
||
├── POST /knowledge-bases
|
||
├── GET /knowledge-bases
|
||
├── GET /knowledge-bases/:id
|
||
├── PUT /knowledge-bases/:id
|
||
├── DELETE /knowledge-bases/:id
|
||
├── GET /knowledge-bases/:id/search
|
||
├── GET /knowledge-bases/:id/stats
|
||
└── GET /knowledge-bases/:id/document-selection
|
||
|
||
documentController.ts
|
||
├── POST /knowledge-bases/:kbId/documents
|
||
├── GET /knowledge-bases/:kbId/documents
|
||
├── GET /documents/:id
|
||
├── GET /documents/:id/full-text
|
||
├── DELETE /documents/:id
|
||
└── POST /documents/:id/reprocess
|
||
```
|
||
|
||
#### 1.4 前端代码结构
|
||
|
||
**主页面(`frontend/src/pages/KnowledgePage.tsx`):** 281行
|
||
- 知识库列表视图
|
||
- 知识库详情视图(Tabs:文档管理 + 统计信息)
|
||
- 双进度条容量显示(文件数 + Token数)
|
||
|
||
**组件(`frontend/src/components/knowledge/`):**
|
||
```
|
||
KnowledgeBaseList.tsx // 知识库卡片列表
|
||
CreateKBDialog.tsx // 创建对话框
|
||
EditKBDialog.tsx // 编辑对话框
|
||
DocumentList.tsx // 文档列表(含状态徽章)
|
||
DocumentUpload.tsx // 文件上传(拖拽支持)
|
||
```
|
||
|
||
**状态管理(`frontend/src/stores/useKnowledgeBaseStore.ts`):**
|
||
- Zustand状态管理
|
||
- API调用封装
|
||
- 实时状态轮询(5秒间隔)
|
||
|
||
---
|
||
|
||
### 二、RVW(审稿功能)功能详情
|
||
|
||
#### 2.1 功能特性
|
||
|
||
**核心能力:**
|
||
- ✅ **稿件上传**:支持Word文档(.doc/.docx),最大5MB
|
||
- ✅ **双维度评估**:
|
||
- 稿约规范性评估(11项标准)
|
||
- 方法学评估(3大部分)
|
||
- ✅ **基于真实期刊标准**:《中华医学超声杂志》稿约
|
||
- ✅ **智能分析**:使用LLM进行结构化评估
|
||
- ✅ **完整报告**:JSON格式结果,支持导出PDF/复制文本
|
||
- ✅ **模型选择**:DeepSeek-V3 / Qwen3-72B / Qwen-Long
|
||
- ✅ **任务管理**:任务列表、状态追踪、进度显示
|
||
|
||
**评估标准:**
|
||
|
||
**稿约规范性评估(11项):**
|
||
1. 文题(Title)
|
||
2. 作者(Authors)
|
||
3. 中文摘要(Chinese Abstract)
|
||
4. 英文摘要(English Abstract)
|
||
5. 中文关键词(Chinese Keywords)
|
||
6. 英文关键词(English Keywords)
|
||
7. 正文(Main Text)
|
||
8. 参考文献(References)
|
||
9. 图表(Figures and Tables)
|
||
10. 利益冲突(Conflict of Interest)
|
||
11. 伦理审查(Ethics Approval)
|
||
|
||
**方法学评估(3部分):**
|
||
1. 科研设计(Research Design)
|
||
2. 统计方法(Statistical Methods)
|
||
3. 统计分析(Statistical Analysis)
|
||
|
||
#### 2.2 数据库结构
|
||
|
||
**ReviewTask表(当前在`public` schema,需迁移到`rvw_schema`):**
|
||
```prisma
|
||
model ReviewTask {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
fileName String
|
||
fileSize BigInt
|
||
extractedText String?
|
||
wordCount Int?
|
||
status String // pending/extracting/reviewing_editorial/reviewing_methodology/completed/failed
|
||
modelUsed String
|
||
overallScore Float?
|
||
editorialReview Json? // 稿约规范性评估结果
|
||
methodologyReview Json? // 方法学评估结果
|
||
errorMessage String?
|
||
startedAt DateTime?
|
||
completedAt DateTime?
|
||
durationSeconds Int?
|
||
createdAt DateTime @default(now())
|
||
}
|
||
```
|
||
|
||
#### 2.3 后端代码结构
|
||
|
||
**服务层(`backend/src/legacy/services/reviewService.ts`):** 453行
|
||
```typescript
|
||
reviewManuscript() // 主入口(异步执行)
|
||
processReviewTask() // 后台处理任务
|
||
reviewEditorialStandards() // 稿约规范性评估
|
||
reviewMethodology() // 方法学评估
|
||
parseJSONFromLLMResponse() // 容错JSON解析
|
||
getReviewTask() // 获取任务状态
|
||
getReviewTasks() // 获取任务列表(分页)
|
||
deleteReviewTask() // 删除任务
|
||
getReviewReport() // 获取完整报告
|
||
```
|
||
|
||
**Prompt设计(`backend/prompts/`):**
|
||
```
|
||
review_editorial_system.txt (210行)
|
||
└── 11个评估维度的详细标准
|
||
|
||
review_methodology_system.txt (231行)
|
||
└── 3个部分的评估标准
|
||
```
|
||
|
||
**控制器层(`backend/src/legacy/controllers/reviewController.ts`):** 265行
|
||
```typescript
|
||
POST /review/upload // 上传稿件并开始审查
|
||
GET /review/tasks/:taskId // 获取任务状态
|
||
GET /review/tasks/:taskId/report // 获取审查报告
|
||
GET /review/tasks // 获取任务列表(分页)
|
||
DELETE /review/tasks/:taskId // 删除任务
|
||
```
|
||
|
||
#### 2.4 前端代码结构
|
||
|
||
**主页面(`frontend/src/pages/ReviewPage.tsx`):** 625行
|
||
- 渐变色标题卡片
|
||
- 3步流程:上传稿件 → 选择模型 → 开始审查
|
||
- 5步进度展示:上传 → 提取文本 → 稿约评估 → 方法学评估 → 生成报告
|
||
- 报告展示(Tabs切换)
|
||
- 导出功能(PDF生成 + 文本复制)
|
||
|
||
**组件(`frontend/src/components/review/`):**
|
||
```
|
||
ScoreCard.tsx // 分数卡片(颜色编码)
|
||
EditorialReview.tsx // 稿约规范性评估详情
|
||
MethodologyReview.tsx // 方法学评估详情
|
||
```
|
||
|
||
**视觉设计:**
|
||
- 渐变色主题:`linear-gradient(135deg, #667eea 0%, #764ba2 100%)`
|
||
- 分数颜色编码:≥90优秀(绿)、≥80良好(蓝)、≥70中等(黄)、<70需改进(红)
|
||
- 拖拽上传支持
|
||
- 响应式布局
|
||
|
||
---
|
||
|
||
## 🎯 迁移策略
|
||
|
||
### 迁移原则
|
||
1. **保持功能完整性**:100%保留现有功能,不做删减
|
||
2. **遵循新架构规范**:符合模块化、Schema隔离、云原生设计
|
||
3. **复用平台能力**:使用`common`层的存储、日志、LLM、文档处理服务
|
||
4. **渐进式迁移**:先后端再前端,确保每步可测试
|
||
5. **保持数据兼容**:数据库表结构平滑迁移,不丢失数据
|
||
|
||
---
|
||
|
||
## 📋 迁移任务清单
|
||
|
||
### Phase 1: PKB个人知识库迁移(优先)
|
||
|
||
#### Task 1.1:后端代码迁移 ⏱️ 预计2-3小时
|
||
|
||
**目标目录:** `backend/src/modules/pkb/`
|
||
|
||
**迁移步骤:**
|
||
|
||
1. **创建模块结构** (30分钟)
|
||
```bash
|
||
backend/src/modules/pkb/
|
||
├── README.md # 模块说明
|
||
├── controllers/
|
||
│ ├── knowledgeBaseController.ts # 从legacy迁移
|
||
│ └── documentController.ts # 从legacy迁移
|
||
├── services/
|
||
│ ├── knowledgeBaseService.ts # 从legacy迁移
|
||
│ ├── documentService.ts # 从legacy迁移
|
||
│ └── tokenService.ts # 从legacy迁移
|
||
├── routes/
|
||
│ └── index.ts # 路由注册
|
||
└── types/
|
||
└── index.ts # 类型定义
|
||
```
|
||
|
||
2. **复制并更新服务层** (60分钟)
|
||
- 从`backend/src/legacy/services/`复制文件
|
||
- 更新导入路径:
|
||
```typescript
|
||
// ❌ 旧代码
|
||
import { prisma } from '../../config/database.js';
|
||
import { difyClient } from '../../common/rag/DifyClient.js';
|
||
|
||
// ✅ 新代码
|
||
import { prisma } from '@/config/database';
|
||
import { difyClient } from '@/common/rag/DifyClient';
|
||
```
|
||
- 使用平台能力:
|
||
```typescript
|
||
// ✅ 使用storage抽象层(如果需要文件存储)
|
||
import { storage } from '@/common/storage';
|
||
|
||
// ✅ 使用logger(替换console.log)
|
||
import { logger } from '@/common/logging';
|
||
|
||
// ✅ 使用extractionClient(已有)
|
||
import { extractionClient } from '@/common/document/ExtractionClient';
|
||
```
|
||
|
||
3. **复制并更新控制器层** (30分钟)
|
||
- 从`backend/src/legacy/controllers/`复制文件
|
||
- 更新导入路径
|
||
- 移除`MOCK_USER_ID`,从`request.user`获取(待实现认证中间件)
|
||
|
||
4. **创建路由文件** (30分钟)
|
||
```typescript
|
||
// backend/src/modules/pkb/routes/index.ts
|
||
import type { FastifyInstance } from 'fastify';
|
||
import * as knowledgeBaseController from '../controllers/knowledgeBaseController';
|
||
import * as documentController from '../controllers/documentController';
|
||
|
||
export default async function pkbRoutes(fastify: FastifyInstance) {
|
||
// 知识库管理
|
||
fastify.post('/api/v1/pkb/knowledge-bases', knowledgeBaseController.createKnowledgeBase);
|
||
fastify.get('/api/v1/pkb/knowledge-bases', knowledgeBaseController.getKnowledgeBases);
|
||
fastify.get('/api/v1/pkb/knowledge-bases/:id', knowledgeBaseController.getKnowledgeBaseById);
|
||
fastify.put('/api/v1/pkb/knowledge-bases/:id', knowledgeBaseController.updateKnowledgeBase);
|
||
fastify.delete('/api/v1/pkb/knowledge-bases/:id', knowledgeBaseController.deleteKnowledgeBase);
|
||
fastify.get('/api/v1/pkb/knowledge-bases/:id/search', knowledgeBaseController.searchKnowledgeBase);
|
||
fastify.get('/api/v1/pkb/knowledge-bases/:id/stats', knowledgeBaseController.getKnowledgeBaseStats);
|
||
fastify.get('/api/v1/pkb/knowledge-bases/:id/document-selection', knowledgeBaseController.getDocumentSelection);
|
||
|
||
// 文档管理
|
||
fastify.post('/api/v1/pkb/knowledge-bases/:kbId/documents', documentController.uploadDocument);
|
||
fastify.get('/api/v1/pkb/knowledge-bases/:kbId/documents', documentController.getDocuments);
|
||
fastify.get('/api/v1/pkb/documents/:id', documentController.getDocumentById);
|
||
fastify.get('/api/v1/pkb/documents/:id/full-text', documentController.getDocumentFullText);
|
||
fastify.delete('/api/v1/pkb/documents/:id', documentController.deleteDocument);
|
||
fastify.post('/api/v1/pkb/documents/:id/reprocess', documentController.reprocessDocument);
|
||
}
|
||
```
|
||
|
||
5. **在主入口注册路由** (10分钟)
|
||
```typescript
|
||
// backend/src/index.ts
|
||
import pkbRoutes from './modules/pkb/routes';
|
||
|
||
// 注册PKB路由
|
||
await fastify.register(pkbRoutes);
|
||
```
|
||
|
||
6. **创建模块README** (20分钟)
|
||
```markdown
|
||
# PKB 个人知识库模块
|
||
|
||
## 功能概述
|
||
- 知识库CRUD
|
||
- 文档上传与管理
|
||
- Dify RAG检索
|
||
- 批处理任务
|
||
|
||
## API端点
|
||
...
|
||
|
||
## 数据库Schema
|
||
- pkb_schema.knowledge_bases
|
||
- pkb_schema.documents
|
||
- pkb_schema.batch_tasks
|
||
- pkb_schema.batch_results
|
||
```
|
||
|
||
#### Task 1.2:前端代码迁移 ⏱️ 预计2-3小时
|
||
|
||
**目标目录:** `frontend-v2/src/modules/pkb/`
|
||
|
||
**迁移步骤:**
|
||
|
||
1. **创建模块结构** (30分钟)
|
||
```bash
|
||
frontend-v2/src/modules/pkb/
|
||
├── index.tsx # 模块入口(路由配置)
|
||
├── api/
|
||
│ └── index.ts # API封装
|
||
├── pages/
|
||
│ ├── KnowledgeBasePage.tsx # 知识库列表页
|
||
│ └── KnowledgeBaseDetail.tsx # 知识库详情页
|
||
├── components/
|
||
│ ├── KnowledgeBaseList.tsx
|
||
│ ├── CreateKBDialog.tsx
|
||
│ ├── EditKBDialog.tsx
|
||
│ ├── DocumentList.tsx
|
||
│ └── DocumentUpload.tsx
|
||
├── hooks/
|
||
│ └── useKnowledgeBase.ts # 状态管理
|
||
└── types/
|
||
└── index.ts # 类型定义
|
||
```
|
||
|
||
2. **复制并更新API层** (30分钟)
|
||
- 从`frontend/src/api/knowledgeBaseApi.ts`复制
|
||
- 更新API路径:`/api/knowledge-bases` → `/api/v1/pkb/knowledge-bases`
|
||
|
||
3. **复制并更新组件** (90分钟)
|
||
- 从`frontend/src/components/knowledge/`复制所有组件
|
||
- 更新导入路径
|
||
- 使用新的`request`实例(如果有)
|
||
- 保持Ant Design 6.0组件兼容性
|
||
|
||
4. **复制并更新主页面** (60分钟)
|
||
- 从`frontend/src/pages/KnowledgePage.tsx`复制
|
||
- 拆分为两个页面:列表页 + 详情页(可选)
|
||
- 更新状态管理:Zustand → React Query或保持Zustand
|
||
|
||
5. **创建模块入口** (30分钟)
|
||
```typescript
|
||
// frontend-v2/src/modules/pkb/index.tsx
|
||
import { lazy } from 'react';
|
||
import { ModuleConfig } from '@/framework/modules/types';
|
||
|
||
const KnowledgeBasePage = lazy(() => import('./pages/KnowledgeBasePage'));
|
||
|
||
const pkbModule: ModuleConfig = {
|
||
id: 'pkb',
|
||
name: '个人知识库',
|
||
icon: 'FileTextOutlined',
|
||
routes: [
|
||
{
|
||
path: '/pkb',
|
||
element: <KnowledgeBasePage />,
|
||
permission: 'pkb:view',
|
||
},
|
||
],
|
||
};
|
||
|
||
export default pkbModule;
|
||
```
|
||
|
||
6. **在框架中注册模块** (10分钟)
|
||
```typescript
|
||
// frontend-v2/src/framework/modules/moduleRegistry.ts
|
||
import pkbModule from '@/modules/pkb';
|
||
|
||
registerModule(pkbModule);
|
||
```
|
||
|
||
#### Task 1.3:数据库Schema验证 ⏱️ 预计30分钟
|
||
|
||
**检查事项:**
|
||
- ✅ `pkb_schema.knowledge_bases` 表结构完整
|
||
- ✅ `pkb_schema.documents` 表结构完整
|
||
- ✅ `pkb_schema.batch_tasks` 表结构完整
|
||
- ✅ `pkb_schema.batch_results` 表结构完整
|
||
- ✅ 外键关系正确
|
||
- ✅ 索引齐全
|
||
|
||
**Prisma Schema已存在,无需修改。**
|
||
|
||
#### Task 1.4:集成测试 ⏱️ 预计1小时
|
||
|
||
**测试清单:**
|
||
1. ✅ 创建知识库
|
||
2. ✅ 上传文档(PDF/Word)
|
||
3. ✅ 文档状态轮询
|
||
4. ✅ 语义检索
|
||
5. ✅ 删除文档
|
||
6. ✅ 删除知识库
|
||
7. ✅ Token计算和智能选择
|
||
8. ✅ 批处理任务创建和执行
|
||
|
||
---
|
||
|
||
### Phase 2: RVW审稿功能迁移
|
||
|
||
#### Task 2.1:后端代码迁移 ⏱️ 预计2-3小时
|
||
|
||
**目标目录:** `backend/src/modules/rvw/`
|
||
|
||
**迁移步骤:**
|
||
|
||
1. **创建模块结构** (30分钟)
|
||
```bash
|
||
backend/src/modules/rvw/
|
||
├── README.md
|
||
├── controllers/
|
||
│ └── reviewController.ts
|
||
├── services/
|
||
│ └── reviewService.ts
|
||
├── routes/
|
||
│ └── index.ts
|
||
├── prompts/
|
||
│ ├── editorial_system.txt # 从backend/prompts/复制
|
||
│ └── methodology_system.txt # 从backend/prompts/复制
|
||
└── types/
|
||
└── index.ts
|
||
```
|
||
|
||
2. **复制并更新服务层** (60分钟)
|
||
- 从`backend/src/legacy/services/reviewService.ts`复制
|
||
- 更新导入路径
|
||
- 使用平台能力:
|
||
```typescript
|
||
import { logger } from '@/common/logging';
|
||
import { extractionClient } from '@/common/document/ExtractionClient';
|
||
import { LLMFactory } from '@/common/llm/adapters/LLMFactory';
|
||
```
|
||
- 移动Prompt文件到模块内部
|
||
|
||
3. **复制并更新控制器层** (30分钟)
|
||
- 从`backend/src/legacy/controllers/reviewController.ts`复制
|
||
- 更新导入路径
|
||
|
||
4. **创建路由文件** (30分钟)
|
||
```typescript
|
||
// backend/src/modules/rvw/routes/index.ts
|
||
import type { FastifyInstance } from 'fastify';
|
||
import * as reviewController from '../controllers/reviewController';
|
||
|
||
export default async function rvwRoutes(fastify: FastifyInstance) {
|
||
fastify.post('/api/v1/rvw/upload', reviewController.uploadManuscript);
|
||
fastify.get('/api/v1/rvw/tasks/:taskId', reviewController.getTaskStatus);
|
||
fastify.get('/api/v1/rvw/tasks/:taskId/report', reviewController.getTaskReport);
|
||
fastify.get('/api/v1/rvw/tasks', reviewController.getTaskList);
|
||
fastify.delete('/api/v1/rvw/tasks/:taskId', reviewController.deleteTask);
|
||
}
|
||
```
|
||
|
||
5. **在主入口注册路由** (10分钟)
|
||
```typescript
|
||
// backend/src/index.ts
|
||
import rvwRoutes from './modules/rvw/routes';
|
||
|
||
await fastify.register(rvwRoutes);
|
||
```
|
||
|
||
#### Task 2.2:数据库Schema迁移 ⏱️ 预计1小时
|
||
|
||
**当前问题:** `ReviewTask`表在`public` schema,需迁移到`rvw_schema`
|
||
|
||
**迁移步骤:**
|
||
|
||
1. **更新Prisma Schema** (20分钟)
|
||
```prisma
|
||
// backend/prisma/schema.prisma
|
||
model ReviewTask {
|
||
id String @id @default(uuid())
|
||
userId String @map("user_id")
|
||
fileName String @map("file_name")
|
||
fileSize BigInt @map("file_size")
|
||
extractedText String? @map("extracted_text")
|
||
wordCount Int? @map("word_count")
|
||
status String @default("pending")
|
||
modelUsed String @map("model_used")
|
||
overallScore Float? @map("overall_score")
|
||
editorialReview Json? @map("editorial_review")
|
||
methodologyReview Json? @map("methodology_review")
|
||
errorMessage String? @map("error_message")
|
||
startedAt DateTime? @map("started_at")
|
||
completedAt DateTime? @map("completed_at")
|
||
durationSeconds Int? @map("duration_seconds")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([userId], map: "idx_rvw_tasks_user_id")
|
||
@@index([status], map: "idx_rvw_tasks_status")
|
||
@@index([createdAt], map: "idx_rvw_tasks_created_at")
|
||
@@map("review_tasks")
|
||
@@schema("rvw_schema") // ⭐ 迁移到rvw_schema
|
||
}
|
||
```
|
||
|
||
2. **创建迁移脚本** (20分钟)
|
||
```sql
|
||
-- backend/prisma/migrations/migrate_review_to_rvw_schema.sql
|
||
|
||
-- 1. 创建rvw_schema(如果不存在)
|
||
CREATE SCHEMA IF NOT EXISTS rvw_schema;
|
||
|
||
-- 2. 在rvw_schema中创建新表
|
||
CREATE TABLE rvw_schema.review_tasks (
|
||
-- 复制public.ReviewTask表结构
|
||
-- 添加蛇形命名(user_id, file_name等)
|
||
);
|
||
|
||
-- 3. 迁移数据
|
||
INSERT INTO rvw_schema.review_tasks
|
||
SELECT * FROM public."ReviewTask";
|
||
|
||
-- 4. 创建索引
|
||
CREATE INDEX idx_rvw_tasks_user_id ON rvw_schema.review_tasks(user_id);
|
||
CREATE INDEX idx_rvw_tasks_status ON rvw_schema.review_tasks(status);
|
||
CREATE INDEX idx_rvw_tasks_created_at ON rvw_schema.review_tasks(created_at);
|
||
|
||
-- 5. 验证数据
|
||
SELECT COUNT(*) FROM rvw_schema.review_tasks;
|
||
|
||
-- 6. 备份后删除旧表(可选)
|
||
-- DROP TABLE public."ReviewTask";
|
||
```
|
||
|
||
3. **运行迁移** (20分钟)
|
||
```bash
|
||
# 生成Prisma Client
|
||
cd backend
|
||
npx prisma generate
|
||
|
||
# 运行手动迁移脚本
|
||
psql $DATABASE_URL < prisma/migrations/migrate_review_to_rvw_schema.sql
|
||
|
||
# 验证
|
||
npm run test:db
|
||
```
|
||
|
||
#### Task 2.3:前端代码迁移 ⏱️ 预计2-3小时
|
||
|
||
**目标目录:** `frontend-v2/src/modules/rvw/`
|
||
|
||
**迁移步骤:**
|
||
|
||
1. **创建模块结构** (30分钟)
|
||
```bash
|
||
frontend-v2/src/modules/rvw/
|
||
├── index.tsx
|
||
├── api/
|
||
│ └── index.ts
|
||
├── pages/
|
||
│ ├── ReviewPage.tsx
|
||
│ └── ReviewList.tsx (可选)
|
||
├── components/
|
||
│ ├── ScoreCard.tsx
|
||
│ ├── EditorialReview.tsx
|
||
│ └── MethodologyReview.tsx
|
||
├── hooks/
|
||
│ └── useReviewTask.ts
|
||
└── types/
|
||
└── index.ts
|
||
```
|
||
|
||
2. **复制并更新API层** (30分钟)
|
||
- 从`frontend/src/api/reviewApi.ts`复制
|
||
- 更新API路径:`/api/review` → `/api/v1/rvw`
|
||
|
||
3. **复制并更新组件** (60分钟)
|
||
- 从`frontend/src/components/review/`复制所有组件
|
||
- 保持视觉设计(渐变色、颜色编码)
|
||
|
||
4. **复制并更新主页面** (90分钟)
|
||
- 从`frontend/src/pages/ReviewPage.tsx`复制
|
||
- 保持完整UI流程
|
||
- 更新CSS导入(如果需要)
|
||
|
||
5. **创建模块入口** (30分钟)
|
||
```typescript
|
||
// frontend-v2/src/modules/rvw/index.tsx
|
||
import { lazy } from 'react';
|
||
import { ModuleConfig } from '@/framework/modules/types';
|
||
|
||
const ReviewPage = lazy(() => import('./pages/ReviewPage'));
|
||
|
||
const rvwModule: ModuleConfig = {
|
||
id: 'rvw',
|
||
name: '稿件审查',
|
||
icon: 'FileTextOutlined',
|
||
routes: [
|
||
{
|
||
path: '/rvw',
|
||
element: <ReviewPage />,
|
||
permission: 'rvw:view',
|
||
},
|
||
],
|
||
};
|
||
|
||
export default rvwModule;
|
||
```
|
||
|
||
6. **在框架中注册模块** (10分钟)
|
||
|
||
#### Task 2.4:集成测试 ⏱️ 预计1小时
|
||
|
||
**测试清单:**
|
||
1. ✅ 上传Word稿件
|
||
2. ✅ 状态轮询(5个步骤)
|
||
3. ✅ 稿约规范性评估(11项)
|
||
4. ✅ 方法学评估(3部分)
|
||
5. ✅ 总体评分计算
|
||
6. ✅ 报告展示(Tabs切换)
|
||
7. ✅ 导出PDF
|
||
8. ✅ 复制报告文本
|
||
9. ✅ 任务列表查询
|
||
10. ✅ 删除任务
|
||
|
||
---
|
||
|
||
## 🔧 技术细节补充
|
||
|
||
### 关键依赖复用
|
||
|
||
**已有平台能力(可直接复用):**
|
||
```typescript
|
||
// ✅ 文档提取服务(已有)
|
||
import { extractionClient } from '@/common/document/ExtractionClient';
|
||
// 支持:PDF、Word、TXT,已集成Python微服务
|
||
|
||
// ✅ LLM网关(已有)
|
||
import { LLMFactory } from '@/common/llm/adapters/LLMFactory';
|
||
// 支持:DeepSeek-V3, Qwen-Max, GPT-5-Pro, Claude-4.5
|
||
|
||
// ✅ 存储服务(已有)
|
||
import { storage } from '@/common/storage';
|
||
// 支持:LocalAdapter ↔ OSSAdapter零代码切换
|
||
|
||
// ✅ 日志系统(已有)
|
||
import { logger } from '@/common/logging';
|
||
|
||
// ✅ RAG服务(已有,PKB需要)
|
||
import { difyClient } from '@/common/rag/DifyClient';
|
||
```
|
||
|
||
### 外部依赖
|
||
|
||
**PKB模块额外依赖:**
|
||
- ✅ **Dify平台**:已部署,提供RAG检索能力
|
||
- ✅ **tiktoken**:Token计算,已安装(`@dqbd/tiktoken`)
|
||
- ✅ **Python微服务**:文档提取,已部署
|
||
|
||
**RVW模块额外依赖:**
|
||
- ✅ **html2canvas**:PDF导出(前端),需安装
|
||
- ✅ **jspdf**:PDF生成(前端),需安装
|
||
|
||
### API路径规范
|
||
|
||
**新架构API路径:**
|
||
```
|
||
PKB模块:
|
||
/api/v1/pkb/knowledge-bases/*
|
||
/api/v1/pkb/documents/*
|
||
|
||
RVW模块:
|
||
/api/v1/rvw/upload
|
||
/api/v1/rvw/tasks/*
|
||
```
|
||
|
||
**旧架构API路径(需向后兼容):**
|
||
```
|
||
/api/knowledge-bases/* (可保留,重定向到新路径)
|
||
/api/review/* (可保留,重定向到新路径)
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 数据迁移与向后兼容
|
||
|
||
### PKB模块
|
||
- ✅ **无需数据迁移**:`pkb_schema`已存在且结构完整
|
||
- ✅ **API向后兼容**:保留旧路径`/api/knowledge-bases`,内部转发到新路径
|
||
|
||
### RVW模块
|
||
- ⚠️ **需要数据迁移**:`public.ReviewTask` → `rvw_schema.review_tasks`
|
||
- ⚠️ **字段名调整**:驼峰命名 → 蛇形命名(`userId` → `user_id`)
|
||
- ✅ **API向后兼容**:保留旧路径`/api/review`,内部转发到新路径
|
||
|
||
**迁移脚本模板:**
|
||
```sql
|
||
-- 创建新Schema
|
||
CREATE SCHEMA IF NOT EXISTS rvw_schema;
|
||
|
||
-- 创建新表(蛇形命名)
|
||
CREATE TABLE rvw_schema.review_tasks AS
|
||
SELECT
|
||
id,
|
||
"userId" AS user_id,
|
||
"fileName" AS file_name,
|
||
"fileSize" AS file_size,
|
||
"extractedText" AS extracted_text,
|
||
"wordCount" AS word_count,
|
||
status,
|
||
"modelUsed" AS model_used,
|
||
"overallScore" AS overall_score,
|
||
"editorialReview" AS editorial_review,
|
||
"methodologyReview" AS methodology_review,
|
||
"errorMessage" AS error_message,
|
||
"startedAt" AS started_at,
|
||
"completedAt" AS completed_at,
|
||
"durationSeconds" AS duration_seconds,
|
||
"createdAt" AS created_at
|
||
FROM public."ReviewTask";
|
||
|
||
-- 创建索引
|
||
CREATE INDEX idx_rvw_tasks_user_id ON rvw_schema.review_tasks(user_id);
|
||
CREATE INDEX idx_rvw_tasks_status ON rvw_schema.review_tasks(status);
|
||
CREATE INDEX idx_rvw_tasks_created_at ON rvw_schema.review_tasks(created_at);
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ 验收标准
|
||
|
||
### PKB模块迁移完成标准
|
||
1. ✅ 后端代码在`backend/src/modules/pkb/`
|
||
2. ✅ 前端代码在`frontend-v2/src/modules/pkb/`
|
||
3. ✅ API路径为`/api/v1/pkb/*`
|
||
4. ✅ 所有功能测试通过(知识库CRUD、文档上传、检索、批处理)
|
||
5. ✅ 前端UI完全迁移(列表、详情、上传、对话框)
|
||
6. ✅ 复用平台能力(logger、storage、extractionClient、difyClient)
|
||
7. ✅ 文档完整(README.md、API文档)
|
||
|
||
### RVW模块迁移完成标准
|
||
1. ✅ 后端代码在`backend/src/modules/rvw/`
|
||
2. ✅ 前端代码在`frontend-v2/src/modules/rvw/`
|
||
3. ✅ API路径为`/api/v1/rvw/*`
|
||
4. ✅ 数据已迁移到`rvw_schema.review_tasks`
|
||
5. ✅ 所有功能测试通过(上传、评估、报告、导出)
|
||
6. ✅ 前端UI完全迁移(上传、进度、报告、导出)
|
||
7. ✅ 复用平台能力(logger、extractionClient、LLMFactory)
|
||
8. ✅ Prompt文件在模块内部(`modules/rvw/prompts/`)
|
||
|
||
---
|
||
|
||
## 📚 文档更新清单
|
||
|
||
### 需要更新的文档
|
||
|
||
1. **系统当前状态与开发指南**
|
||
- 文件:`docs/00-系统总体设计/00-系统当前状态与开发指南.md`
|
||
- 更新:PKB和RVW模块状态从"已完成(旧架构)"改为"✅ 100%(新架构)"
|
||
|
||
2. **模块README创建**
|
||
- `backend/src/modules/pkb/README.md`
|
||
- `backend/src/modules/rvw/README.md`
|
||
|
||
3. **前端模块文档**
|
||
- `frontend-v2/src/modules/pkb/README.md`
|
||
- `frontend-v2/src/modules/rvw/README.md`
|
||
|
||
4. **API文档更新**
|
||
- `docs/04-开发规范/04-API路由总览.md`
|
||
- 添加PKB和RVW的API端点清单
|
||
|
||
5. **迁移完成报告**
|
||
- 新建:`docs/08-项目管理/PKB和RVW迁移完成报告.md`
|
||
- 记录:迁移时间、遇到的问题、解决方案、测试结果
|
||
|
||
---
|
||
|
||
## 🎯 总结
|
||
|
||
### 迁移优势
|
||
1. ✅ **架构统一**:所有模块遵循相同的模块化结构
|
||
2. ✅ **易于维护**:代码组织清晰,职责明确
|
||
3. ✅ **复用平台能力**:减少重复代码,提升代码质量
|
||
4. ✅ **支持独立部署**:每个模块可独立打包、部署、销售
|
||
5. ✅ **Schema隔离**:数据库层面模块独立,降低耦合
|
||
|
||
### 预计总耗时
|
||
- **PKB模块迁移**:6-8小时
|
||
- **RVW模块迁移**:7-9小时(含数据迁移)
|
||
- **总计**:13-17小时(约2个工作日)
|
||
|
||
### 风险评估
|
||
- ✅ **风险低**:功能已100%完成,代码质量高
|
||
- ✅ **测试覆盖**:有完整的手动测试流程
|
||
- ✅ **向后兼容**:保留旧API路径,不影响现有前端
|
||
|
||
---
|
||
|
||
**文档维护者:** 技术团队
|
||
**最后更新:** 2025-12-28
|
||
**下一步:** 执行迁移任务,按TODO清单逐项完成
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|