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,125 @@
# **AI智能审稿系统 (期刊SaaS版) 域名架构与多租户落地技术指南**
**文档受众:** 架构师、前端研发、后端研发、运维工程师
**文档目的:** 明确期刊 SaaS 业务的域名规范规范单点登录SSO及多租户鉴权的开发标准排查并规避泛域名 SSL 证书与第三方回调等运维/安全隐患。
## **🏗️ 一、 核心架构决策:三级子域名隔离方案**
经过商业定位与工程复杂度的综合评估,系统采用**基于功能属性的三级子域名方案**
**\[tenantId\].review.xunzhengyixue.com** (例如jtim.review.xunzhengyixue.com)
### **为什么选择这个方案?**
1. **商业心智精准**:使用 review 明确了我们是“AI 辅助审稿工具”,而非沉重的全流程投审稿系统,降低客户防备心。
2. **品牌与视觉隔离**:彻底抛弃 URL路径隔离为每个期刊提供独立的门户网址。
3. **架构解耦**:与现有的临床研究主站(.yanjiu. 或主域)及临床试验项目(.iit.)在命名空间上完美平行,为未来的 SaaS 矩阵拓展留足空间。
## **🛠️ 二、 运维团队 (DevOps) 执行清单**
运维团队需在阿里云环境中完成以下配置,**该方案无需为每个新增期刊重新发布或修改配置**。
### **1\. DNS 云解析配置 (阿里云)**
无需每次新增期刊都修改 DNS。请添加一条**泛解析**记录:
* **主机记录**\*.review
* **记录类型**A 或 CNAME
* **记录值**:指向 SAE 现有的前端 CLB 负载均衡公网 IP目前为 8.140.53.236)。
### **2\. ⚠️ 致命避坑SSL 证书采购与挂载**
* **红线提醒**:现有的 \*.xunzhengyixue.com 泛域名证书**绝对无法覆盖**四级域名(即无法覆盖 jtim.review.xunzhengyixue.com直接使用会导致浏览器报红。
* **执行动作**:必须重新申请/购买一张专门针对 **\*.review.xunzhengyixue.com** 的泛域名 SSL 证书,并挂载到网关或 CLB 上。
### **3\. Nginx 路由代理配置**
前端 frontend-v2 镜像的 nginx.conf 需要配置匹配规则,将所有子域名的请求导向同一个 SPA单页应用入口API 请求依然打向 Node.js 后端。
server {
listen 80;
\# 匹配所有的 review 子域名
server\_name \~^(?\<tenant\>.+)\\.review\\.xunzhengyixue\\.com$;
location / {
root /usr/share/nginx/html;
index index.html;
\# 将所有未匹配静态资源的路由回退给 index.html交由 React Router 处理
try\_files $uri $uri/ /index.html;
}
\# 后端 API 转发保持现有配置不变
location /api/ {
proxy\_pass \[http://172.17.173.73:3001\](http://172.17.173.73:3001);
\# ...
}
}
## **💻 三、 前端研发 (FE) 执行清单**
前端代码库保持同一套,依靠初始化时截取 window.location.hostname 来实现“千刊千面”。
### **1\. 动态截取 TenantID**
在应用挂载层(如 App.tsx 或路由初始化钩子中)注入租户识别逻辑:
const host \= window.location.hostname; // e.g., jtim.review.xunzhengyixue.com
let currentTenantId \= 'default';
// 严格判断当前是否处于期刊审查工作台环境
if (host.endsWith('.review.xunzhengyixue.com')) {
// 提取第一个分段作为 tenantId
currentTenantId \= host.split('.')\[0\];
}
// 拿到 currentTenantId (如 'jtim') 后:
// 1\. 发起请求GET /api/v1/tenants/public-info/jtim 获取 Logo、主题色
// 2\. 存入全局状态 (Zustand/Redux),应用定制化 UI
### **2\. 模块级路由屏蔽**
利用现有的 moduleRegistry.ts如果当前 tenantId 为期刊客户,隐藏顶部导航中的 AIA、DC、PKB 模块,仅暴露 RVW 模块视图。
## **⚙️ 四、 后端研发 (BE) 执行清单**
后端核心挑战在于**跨域资源共享 (CORS)** 以及 **防范多租户架构下的数据越权**
### **1\. CORS 动态白名单**
禁止写死 Origin在 Fastify / Express 的 CORS 插件中启用正则匹配:
// 允许主站以及所有的 review 泛域名跨域访问
cors: {
origin: \[
/^https?:\\/\\/(\[a-zA-Z0-9-\]+\\.)?xunzhengyixue\\.com$/,
/^https?:\\/\\/(\[a-zA-Z0-9-\]+\\.)?review\\.xunzhengyixue\\.com$/
\],
credentials: true
}
### **2\. ⚠️ 致命避坑SSO 单点登录与防越权 (IDOR 防护)**
由于我们采用底层复用 platform\_schema.users 的机制JWT Cookie 会在主域下共享。这带来极大的越权风险。
* **SSO 签发**:登录时,后端校验用户身份后,必须将当前所在的 tenantId 压入 JWT Payload。
* **双重校验防线 (必须写进中间件 auth.middleware.ts)**
当一个请求打到 /api/v2/rvw/tasks 时,中间件必须校验两件事:
1. Token 解析出的 userId 是否有效。
2. **跨域校验**:该用户是否有权限访问当前 HTTP 请求 Header 中声明的 x-tenant-id或者通过请求域名解析出的 tenant。如果张医生是 iit 的用户,但拿着 Token 试图请求 jtim 租户的数据,**必须直接拦截并返回 403 Forbidden**。
* **ORM 级隔离**:所有针对 RVW 模块的 Prisma 查询,必须强制附带 where: { tenantId: request.tenantId },严禁“裸查”。
## **🔮 五、 未来架构扩展预警:第三方登录限制**
**【风险说明】**
如果您未来计划在 jtim.review... 等域名上引入“微信扫码登录”或微信支付。微信开放平台的安全机制通常要求配置**绝对精准的回调域名**,往往不支持通配符(\*.review...),且回调域名数量有严格上限。
**【架构预案:统一认证网关】**
为了应对该问题,平台在未来演进时,应规划统一的 Auth Center
1. 任何期刊页面点击“微信登录”,统一 302 Redirect 跳转至主站网关(如 login.xunzhengyixue.com/wechat
2. 主站统一处理微信回调,生成系统内部的 JWT SSO Token。
3. 主站将 Token 携带在参数或安全 Cookie 中,再次 302 Redirect 飞回 jtim.review.xunzhengyixue.com/callback完成身份同步。
(目前 MVP 阶段账号密码登录不受此限制,仅作未来规划记录)。