← 返回文档

多租户架构

租户隔离、数据范围、默认租户与单租户模式

平台从设计之初就是多租户的:一套部署服务多个互不干扰的租户,每个租户有自己的站点、 用户和数据。

什么是租户

租户(Tenant)是数据隔离的顶层边界,一个租户对应一个组织或客户,拥有:

  • 自己的营销站点(页面、文档、主题)
  • 自己的用户与角色权限
  • 自己的站点会员
  • 自己的业务数据(按 tenant_id 隔离)

在租户侧与公开面,界面文案不出现「租户」「Tenant」字样——对终端用户来说,它就 是「站点」或「组织」。这不是措辞洁癖:同一套代码要能作为单客户私有部署交付,那时 「租户」是一个客户根本不该看见的内部概念。

数据隔离

所有业务表都带 tenant_id 列,查询统一走 withTenantScope(tenant_id) 注入租户范围:

const records = await prisma.siteDoc.findMany({
  where: withTenantScope(tenant_id, { status: "published" }),
});

隔离靠统一的查询入口保证,而不是靠每个调用点自觉。绕过它直接写 where 会被 模块契约校验挡下来。

默认租户

slug 为 rewindom 的租户是产品主域隐式绑定的组织。访问 FRONTEND_URL(本地 localhost)看到的就是它的站点。

它的站点与文档库在服务端启动时自动初始化,幂等且按语言分别判断:某种语言已经有 已发布文档就跳过,不覆盖后续编辑。所以升级部署不会把你改过的首页冲掉,而新增一门 语言的初始内容会在下次启动时自动补上。

租户的创建与管理

新租户在平台控制台(PLATFORM_URL,本地 127.0.0.1)创建。新建出来的租户是 active 的;创建时会自动铺好默认页头 / 页脚与主题(initializeTenantSite)。

首页与会员页的版式不预建:站点未必要用它们,预建出来就是几张删不掉的空版式。 访客访问时仍由内置版式兜底渲染,站点管理员在「官网 → 页面」下方的版式区点「初始化 版式」,那张页面才成为可编辑的记录;开通某项功能(如会员)时它名下的版式会自动建好。

单租户模式

面向私有部署,设 SINGLE_TENANT=true

  • 隐藏平台控制台与租户管理入口
  • 禁止新建租户;自助注册与 OAuth 首次登录一律并入默认租户
  • 界面上不暴露多租户概念

单租户与多租户共用同一套代码,区别只是运行时配置——不需要为私有部署维护单独的 分支。

路由由 Host 决定

  • FRONTEND_URL → 默认租户
  • {slug}.{TENANT_BASE_DOMAIN} → 对应 slug 的租户
  • 租户自定义域名 → 绑定的那个租户

详见 Host 分流机制