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:
125
docs/03-业务模块/RVW-稿件审查系统/00-系统设计/V3.0/AI智能审稿域名与多租户技术指南.md
Normal file
125
docs/03-业务模块/RVW-稿件审查系统/00-系统设计/V3.0/AI智能审稿域名与多租户技术指南.md
Normal 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 阶段账号密码登录不受此限制,仅作未来规划记录)。
|
||||
Reference in New Issue
Block a user