Features: - Migrate 10 agent prompts from hardcoded to database - Add grayscale preview support (DRAFT/ACTIVE distribution) - Implement 3-tier fallback (DB -> Cache -> Hardcoded) - Add version management and rollback capability Files changed: - backend/scripts/migrate-aia-prompts.ts (new migration script) - backend/src/common/prompt/prompt.fallbacks.ts (add AIA fallbacks) - backend/src/modules/aia/services/agentService.ts (integrate PromptService) - backend/src/modules/aia/services/conversationService.ts (pass userId) - backend/src/modules/aia/types/index.ts (fix AgentStage type) Documentation: - docs/03-业务模块/AIA-AI智能问答/06-开发记录/2026-01-18-Prompt管理系统集成.md - docs/02-通用能力层/00-通用能力层清单.md (add FileCard, Prompt management) - docs/00-系统总体设计/00-系统当前状态与开发指南.md (update to v3.6) Prompt codes: - AIA_SCIENTIFIC_QUESTION, AIA_PICO_ANALYSIS, AIA_TOPIC_EVALUATION - AIA_OUTCOME_DESIGN, AIA_CRF_DESIGN, AIA_SAMPLE_SIZE - AIA_PROTOCOL_WRITING, AIA_METHODOLOGY_REVIEW - AIA_PAPER_POLISH, AIA_PAPER_TRANSLATE Tested: Migration script executed, all 10 prompts inserted successfully
310 lines
10 KiB
TypeScript
310 lines
10 KiB
TypeScript
/**
|
||
* 验证PKB和RVW的数据库Schema状态
|
||
*
|
||
* 目的:
|
||
* 1. 检查pkb_schema是否存在及其表结构
|
||
* 2. 检查rvw_schema是否存在
|
||
* 3. 检查ReviewTask在哪个Schema中
|
||
* 4. 检查是否有旧数据需要迁移
|
||
*
|
||
* 运行方式:
|
||
* npx tsx scripts/verify-pkb-rvw-schema.ts
|
||
*/
|
||
|
||
import { PrismaClient } from '@prisma/client';
|
||
|
||
const prisma = new PrismaClient();
|
||
|
||
interface SchemaInfo {
|
||
schema_name: string;
|
||
}
|
||
|
||
interface TableInfo {
|
||
table_schema: string;
|
||
table_name: string;
|
||
}
|
||
|
||
interface ColumnInfo {
|
||
column_name: string;
|
||
data_type: string;
|
||
is_nullable: string;
|
||
column_default: string | null;
|
||
}
|
||
|
||
interface RowCount {
|
||
count: bigint;
|
||
}
|
||
|
||
async function verifySchemas() {
|
||
console.log('🔍 开始验证PKB和RVW的数据库Schema状态...\n');
|
||
console.log('='.repeat(80));
|
||
|
||
try {
|
||
// ========================================
|
||
// 1. 检查所有Schema
|
||
// ========================================
|
||
console.log('\n📦 1. 检查数据库中所有的Schema');
|
||
console.log('='.repeat(80));
|
||
|
||
const schemas = await prisma.$queryRaw<SchemaInfo[]>`
|
||
SELECT schema_name
|
||
FROM information_schema.schemata
|
||
WHERE schema_name IN ('pkb_schema', 'rvw_schema', 'public', 'platform_schema')
|
||
ORDER BY schema_name
|
||
`;
|
||
|
||
console.log('✅ 找到以下Schema:');
|
||
schemas.forEach(s => console.log(` - ${s.schema_name}`));
|
||
|
||
const hasRvwSchema = schemas.some(s => s.schema_name === 'rvw_schema');
|
||
const hasPkbSchema = schemas.some(s => s.schema_name === 'pkb_schema');
|
||
|
||
console.log(`\n📊 Schema存在性检查:`);
|
||
console.log(` pkb_schema: ${hasPkbSchema ? '✅ 存在' : '❌ 不存在'}`);
|
||
console.log(` rvw_schema: ${hasRvwSchema ? '✅ 存在' : '❌ 不存在'}`);
|
||
|
||
// ========================================
|
||
// 2. 检查PKB相关表
|
||
// ========================================
|
||
console.log('\n');
|
||
console.log('='.repeat(80));
|
||
console.log('📚 2. 检查PKB相关表(在pkb_schema中)');
|
||
console.log('='.repeat(80));
|
||
|
||
if (hasPkbSchema) {
|
||
const pkbTables = await prisma.$queryRaw<TableInfo[]>`
|
||
SELECT table_schema, table_name
|
||
FROM information_schema.tables
|
||
WHERE table_schema = 'pkb_schema'
|
||
ORDER BY table_name
|
||
`;
|
||
|
||
console.log(`✅ pkb_schema中共有 ${pkbTables.length} 个表:`);
|
||
pkbTables.forEach(t => console.log(` - ${t.table_name}`));
|
||
|
||
// 检查每个表的行数
|
||
console.log('\n📊 PKB表数据统计:');
|
||
for (const table of pkbTables) {
|
||
try {
|
||
const result = await prisma.$queryRaw<RowCount[]>`
|
||
SELECT COUNT(*) as count FROM pkb_schema.${prisma.$queryRawUnsafe(table.table_name)}
|
||
`;
|
||
const count = Number(result[0]?.count || 0);
|
||
console.log(` - ${table.table_name}: ${count} 行`);
|
||
} catch (error) {
|
||
console.log(` - ${table.table_name}: 查询失败`);
|
||
}
|
||
}
|
||
} else {
|
||
console.log('❌ pkb_schema不存在!需要创建!');
|
||
}
|
||
|
||
// ========================================
|
||
// 3. 检查RVW相关表
|
||
// ========================================
|
||
console.log('\n');
|
||
console.log('='.repeat(80));
|
||
console.log('📝 3. 检查RVW相关表(review_tasks)');
|
||
console.log('='.repeat(80));
|
||
|
||
// 查找review_tasks表在哪个schema
|
||
const reviewTaskLocation = await prisma.$queryRaw<TableInfo[]>`
|
||
SELECT table_schema, table_name
|
||
FROM information_schema.tables
|
||
WHERE table_name = 'review_tasks'
|
||
`;
|
||
|
||
if (reviewTaskLocation.length > 0) {
|
||
console.log('✅ 找到review_tasks表:');
|
||
reviewTaskLocation.forEach(t => {
|
||
console.log(` - 位置: ${t.table_schema}.${t.table_name}`);
|
||
});
|
||
|
||
// 查看review_tasks表结构
|
||
const reviewSchema = reviewTaskLocation[0].table_schema;
|
||
console.log(`\n📋 review_tasks表结构(在${reviewSchema}中):`);
|
||
|
||
const reviewColumns = await prisma.$queryRaw<ColumnInfo[]>`
|
||
SELECT column_name, data_type, is_nullable, column_default
|
||
FROM information_schema.columns
|
||
WHERE table_schema = ${reviewSchema}
|
||
AND table_name = 'review_tasks'
|
||
ORDER BY ordinal_position
|
||
`;
|
||
|
||
console.log('='.repeat(80));
|
||
console.log(
|
||
'Column Name'.padEnd(25) +
|
||
'Data Type'.padEnd(20) +
|
||
'Nullable'.padEnd(12) +
|
||
'Default'
|
||
);
|
||
console.log('='.repeat(80));
|
||
|
||
reviewColumns.forEach(col => {
|
||
const colName = col.column_name.padEnd(25);
|
||
const dataType = col.data_type.padEnd(20);
|
||
const nullable = (col.is_nullable === 'YES' ? 'YES' : 'NO').padEnd(12);
|
||
const defaultVal = col.column_default || '';
|
||
console.log(`${colName}${dataType}${nullable}${defaultVal}`);
|
||
});
|
||
|
||
console.log('='.repeat(80));
|
||
console.log(`总计: ${reviewColumns.length} 个字段`);
|
||
|
||
// 查询数据量
|
||
const reviewCount = await prisma.$queryRaw<RowCount[]>`
|
||
SELECT COUNT(*) as count FROM ${prisma.$queryRawUnsafe(reviewSchema)}.review_tasks
|
||
`;
|
||
const count = Number(reviewCount[0]?.count || 0);
|
||
console.log(`\n📊 review_tasks表数据量: ${count} 行`);
|
||
|
||
if (reviewSchema === 'public') {
|
||
console.log('\n⚠️ WARNING: review_tasks当前在public schema中!');
|
||
console.log(' 建议迁移到rvw_schema以保持架构一致性!');
|
||
}
|
||
} else {
|
||
console.log('❌ 未找到review_tasks表!');
|
||
}
|
||
|
||
// ========================================
|
||
// 4. 检查rvw_schema状态
|
||
// ========================================
|
||
console.log('\n');
|
||
console.log('='.repeat(80));
|
||
console.log('🔍 4. 检查rvw_schema状态');
|
||
console.log('='.repeat(80));
|
||
|
||
if (hasRvwSchema) {
|
||
const rvwTables = await prisma.$queryRaw<TableInfo[]>`
|
||
SELECT table_schema, table_name
|
||
FROM information_schema.tables
|
||
WHERE table_schema = 'rvw_schema'
|
||
ORDER BY table_name
|
||
`;
|
||
|
||
if (rvwTables.length > 0) {
|
||
console.log(`✅ rvw_schema中共有 ${rvwTables.length} 个表:`);
|
||
rvwTables.forEach(t => console.log(` - ${t.table_name}`));
|
||
} else {
|
||
console.log('⚠️ rvw_schema存在但为空(未创建任何表)');
|
||
}
|
||
} else {
|
||
console.log('❌ rvw_schema不存在!需要创建!');
|
||
}
|
||
|
||
// ========================================
|
||
// 5. 检查User表状态
|
||
// ========================================
|
||
console.log('\n');
|
||
console.log('='.repeat(80));
|
||
console.log('👤 5. 检查User表状态');
|
||
console.log('='.repeat(80));
|
||
|
||
const userTables = await prisma.$queryRaw<TableInfo[]>`
|
||
SELECT table_schema, table_name
|
||
FROM information_schema.tables
|
||
WHERE table_name = 'users'
|
||
AND table_schema IN ('public', 'platform_schema')
|
||
`;
|
||
|
||
console.log('✅ 找到以下users表:');
|
||
for (const userTable of userTables) {
|
||
console.log(` - ${userTable.table_schema}.${userTable.table_name}`);
|
||
|
||
const userCount = await prisma.$queryRaw<RowCount[]>`
|
||
SELECT COUNT(*) as count FROM ${prisma.$queryRawUnsafe(userTable.table_schema)}.users
|
||
`;
|
||
const count = Number(userCount[0]?.count || 0);
|
||
console.log(` 数据量: ${count} 行`);
|
||
}
|
||
|
||
// ========================================
|
||
// 6. 总结和建议
|
||
// ========================================
|
||
console.log('\n');
|
||
console.log('='.repeat(80));
|
||
console.log('📋 6. 迁移建议总结');
|
||
console.log('='.repeat(80));
|
||
|
||
console.log('\n✅ PKB模块迁移建议:');
|
||
if (hasPkbSchema && pkbTables.length > 0) {
|
||
console.log(' 1. ✅ pkb_schema已存在且有表');
|
||
console.log(' 2. ✅ 可以直接迁移代码到新架构');
|
||
console.log(' 3. ⚠️ 注意检查旧代码是否连接到正确的schema');
|
||
} else {
|
||
console.log(' 1. ❌ 需要先创建pkb_schema和相关表');
|
||
console.log(' 2. ❌ 需要运行Prisma迁移');
|
||
}
|
||
|
||
console.log('\n⚠️ RVW模块迁移建议:');
|
||
if (reviewTaskLocation.length > 0) {
|
||
const currentSchema = reviewTaskLocation[0].table_schema;
|
||
if (currentSchema === 'public') {
|
||
console.log(' 1. ⚠️ review_tasks当前在public schema');
|
||
console.log(' 2. 🔄 建议:先完整迁移功能,后续再迁移Schema');
|
||
console.log(' 3. 📋 迁移步骤:');
|
||
console.log(' a. 创建rvw_schema(如果不存在)');
|
||
console.log(' b. 在rvw_schema中创建新表');
|
||
console.log(' c. 迁移数据');
|
||
console.log(' d. 更新代码');
|
||
console.log(' e. 删除旧表');
|
||
} else if (currentSchema === 'rvw_schema') {
|
||
console.log(' 1. ✅ review_tasks已在rvw_schema中');
|
||
console.log(' 2. ✅ 可以直接迁移代码');
|
||
}
|
||
} else {
|
||
console.log(' 1. ❌ review_tasks表不存在');
|
||
console.log(' 2. ❌ 需要从头创建');
|
||
}
|
||
|
||
console.log('\n💡 推荐迁移策略:');
|
||
console.log(' 【方案A:渐进式迁移(推荐)】');
|
||
console.log(' 1. PKB: 直接迁移代码到新架构(Schema已就绪)');
|
||
console.log(' 2. RVW: 先迁移代码保持在public schema');
|
||
console.log(' 3. 验证功能完整性');
|
||
console.log(' 4. 后续独立任务:将RVW迁移到rvw_schema');
|
||
console.log('');
|
||
console.log(' 【方案B:一步到位(风险较高)】');
|
||
console.log(' 1. 同时迁移代码+Schema');
|
||
console.log(' 2. 需要数据迁移脚本');
|
||
console.log(' 3. 需要更长的测试时间');
|
||
|
||
console.log('\n='.repeat(80));
|
||
console.log('✅ 验证完成!');
|
||
console.log('='.repeat(80));
|
||
|
||
} catch (error) {
|
||
console.error('❌ 验证过程中出错:', error);
|
||
throw error;
|
||
} finally {
|
||
await prisma.$disconnect();
|
||
}
|
||
}
|
||
|
||
// 运行验证
|
||
verifySchemas()
|
||
.catch((error) => {
|
||
console.error('Fatal error:', error);
|
||
process.exit(1);
|
||
});
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|