feat(rvw): deliver tenant portal v4 flow and config foundation

Implement RVW V4.0 tenant-aware backend/frontend flow with tenant routing, config APIs, and full portal UX updates. Sync system/RVW/deployment docs to capture verified upload-review-report workflow and next-step admin configuration work.

Made-with: Cursor
This commit is contained in:
2026-03-14 22:29:40 +08:00
parent ba464082cb
commit 16179e16ca
45 changed files with 4753 additions and 93 deletions

View File

@@ -0,0 +1,40 @@
-- RVW V4.0:给 review_tasks 表添加 tenant_id 字段(历史数据平滑迁移两步走)
-- ⚠️ 部署前检查:执行前请确保 platform_schema.tenants 中已存在 code='yanjiu' 的默认租户
-- Migration: 20260314_add_tenant_id_to_review_tasks
-- ============================================================
-- Step 1: 新增 tenant_id 列(先设为 NULL允许历史数据缺失
-- ============================================================
ALTER TABLE "rvw_schema"."review_tasks"
ADD COLUMN "tenant_id" TEXT;
-- ============================================================
-- Step 2: 将历史数据批量回填为默认主站租户
-- 查询 code='yanjiu' 的租户ID回填到所有历史记录
-- 若无 yanjiu 租户,历史记录 tenant_id 保持 NULL不影响运行
-- ============================================================
UPDATE "rvw_schema"."review_tasks"
SET "tenant_id" = (
SELECT "id" FROM "platform_schema"."tenants"
WHERE "code" = 'yanjiu'
LIMIT 1
)
WHERE "tenant_id" IS NULL;
-- ============================================================
-- 添加索引(无论是否有值,索引先建好供 V4.0 查询使用)
-- ============================================================
CREATE INDEX "idx_review_tasks_tenant_id"
ON "rvw_schema"."review_tasks"("tenant_id");
-- ============================================================
-- ⚠️ Step 3可选延后执行确认历史数据已全部回填后再加 NOT NULL 约束
-- 在生产环境手动执行以下 SQL或在后续迁移中加入
--
-- ALTER TABLE "rvw_schema"."review_tasks"
-- ALTER COLUMN "tenant_id" SET NOT NULL;
--
-- ALTER TABLE "rvw_schema"."review_tasks"
-- ADD CONSTRAINT "review_tasks_tenant_id_fkey"
-- FOREIGN KEY ("tenant_id") REFERENCES "platform_schema"."tenants"("id");
-- ============================================================

View File

@@ -0,0 +1,28 @@
-- RVW V4.0:新增期刊租户级审稿配置表
-- 每个期刊租户独立配置稿约规则、方法学/临床专家提示词、Handlebars 展示模板
-- Migration: 20260314_add_tenant_rvw_configs
CREATE TABLE "platform_schema"."tenant_rvw_configs" (
"id" TEXT NOT NULL,
"tenant_id" TEXT NOT NULL,
"editorial_rules" JSONB,
"methodology_expert_prompt" TEXT,
"methodology_handlebars_template" TEXT,
"data_forensics_level" TEXT NOT NULL DEFAULT 'L2',
"finer_weights" JSONB,
"clinical_expert_prompt" TEXT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "tenant_rvw_configs_pkey" PRIMARY KEY ("id")
);
-- Unique constraint: 每个租户只有一份配置
CREATE UNIQUE INDEX "tenant_rvw_configs_tenant_id_key"
ON "platform_schema"."tenant_rvw_configs"("tenant_id");
-- Foreign key to tenants同 schema 内,可用标准外键)
ALTER TABLE "platform_schema"."tenant_rvw_configs"
ADD CONSTRAINT "tenant_rvw_configs_tenant_id_fkey"
FOREIGN KEY ("tenant_id") REFERENCES "platform_schema"."tenants"("id")
ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -325,10 +325,14 @@ model ReviewTask {
// 注意userId 暂不添加外键约束,因为用户来自不同 schema (platform_schema.users)
// 跨 schema 外键在 PostgreSQL 中需要特殊处理
/// RVW V4.0 多租户:期刊租户 IDnullable历史数据通过迁移补填
tenantId String? @map("tenant_id")
@@index([userId])
@@index([status])
@@index([createdAt])
@@index([isArchived])
@@index([tenantId], map: "idx_review_tasks_tenant_id")
@@map("review_tasks")
@@schema("rvw_schema")
}
@@ -1929,6 +1933,7 @@ model tenants {
users User[]
user_modules user_modules[]
iitProjects IitProject[]
tenantRvwConfig TenantRvwConfig?
@@index([code], map: "idx_tenants_code")
@@index([status], map: "idx_tenants_status")
@@ -1951,6 +1956,39 @@ model verification_codes {
@@schema("platform_schema")
}
/// RVW V4.0 智能审稿 SaaS — 租户级审稿配置
/// 每个期刊租户独立一份控制4个审查维度的评估标准与展示模板
/// 关联 platform_schema.tenants
model TenantRvwConfig {
id String @id @default(uuid())
tenantId String @unique @map("tenant_id")
tenant tenants @relation(fields: [tenantId], references: [id], onDelete: Cascade)
/// 稿约规范评估:规则数组,每条规则含 code/description/fatal
editorialRules Json? @map("editorial_rules")
/// 方法学评估专家业务评判标准纯文本可自由编辑不需懂JSON
methodologyExpertPrompt String? @map("methodology_expert_prompt") @db.Text
/// 方法学评估Handlebars 报告展示模板(可覆盖系统默认模板)
methodologyHandlebarsTemplate String? @map("methodology_handlebars_template") @db.Text
/// 数据验证:验证深度 L1/L2/L3
dataForensicsLevel String @default("L2") @map("data_forensics_level")
/// 临床评估FINER 五维权重 {feasibility, innovation, ethics, relevance, novelty}
finerWeights Json? @map("finer_weights")
/// 临床评估:专科特色补充要求(纯文本)
clinicalExpertPrompt String? @map("clinical_expert_prompt") @db.Text
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("tenant_rvw_configs")
@@schema("platform_schema")
}
enum job_state {
created
retry