mcpField
M
multi-tenant-architecture

multi-tenant-architecture

github.com/mblode开发1691.7k 次安装1 天前更新
代码仓库

关于 multi-tenant-architecture

这是一项用于在 Cloudflare 或 Vercel 上设计多租户平台的开发技能,指导租户识别、路由、计算与数据隔离、域名及平台限制等决策,并提供平台参考资料和验证检查。

主要功能

  1. 01选择 Cloudflare 或 Vercel 架构
  2. 02规划租户域名与识别方式
  3. 03设计计算和数据隔离
  4. 04制定路由及租户上下文传递
  5. 05处理自定义域名与平台限制
  6. 06用证据命令验证边界

适用场景

  1. 01规划多租户 SaaS 平台
  2. 02设计租户路由与隔离
  3. 03准备自定义域名接入流程
  4. 04检查租户边界实现

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mblode/agent-skills --skill multi-tenant-architecture

安装后在 Claude Code 中输入/multi-tenant-architecture确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
cloudflare-platform.md
data-isolation.md
limits-and-quotas.md
psl.md
vercel-domains.md
vercel-platform.md

详细介绍

多租户平台架构(Cloudflare 或 Vercel)

  • **涵盖:**平台选择、域名策略和 PSL、租户识别、计算与数据隔离、主机名路由、租户上下文传播、自定义域名和 SSL、每租户静态文件,以及将平台限制映射到套餐。
  • **不涵盖:**通用文件夹结构或模块契约(使用 codebase-architecture)、搭建新仓库(使用 scaffold-nextjs),或在路由动态提供服务后每租户 SEO 文件的内容:站点地图条目、规范 URL、结构化数据、索引策略(使用 seo)。

目录

  • 平台分流(先决定)
  • 参考文件
  • 工作流(顺序很重要)
  • 注意事项
  • 输出架构
  • 证据命令
  • 相关技能

平台分流(先决定)

特征平台模型
租户上传或生成自己的代码;代码级隔离;在 KV、D1、Durable Objects、R2 上进行边缘计算Cloudflare在每租户 Worker 的分发命名空间前放置分发 Worker;自定义主机名使用 Cloudflare for SaaS
每个租户运行相同的 Next.js 代码库,仅在内容、品牌和套餐上有所不同;使用 ISR、Server Components、Vercel 部署Vercel单一部署;proxy.ts 根据主机名解析租户;项目上配置通配符域名和自定义域名
  • 每个产品只选择一个平台。用 Cloudflare 代理置于 Vercel 应用前,会叠加 TLS 和重定向层,通常会导致重定向循环和证书签发失败。
  • 在 Vercel 上让租户部署自己的代码属于多项目模型(每个租户一个 Vercel 项目,通过 SDK 创建)。其隔离逻辑与 Cloudflare 行相同;本技能中的 Vercel 参考仅涵盖单一部署模型。

参考文件

文件阅读时机
cloudflare-platform.md选择 Cloudflare 时:分发命名空间、路由、Cloudflare for SaaS 自定义主机名、隔离模式、KV 和 D1(步骤 3 到 7)
vercel-platform.md选择 Vercel 时:proxy.ts 解析、App Router 布局、Global Config 查询、每租户静态文件、自定义子路径、本地开发(步骤 4 到 7)
vercel-domains.md选择 Vercel 时:SDK 域名生命周期、DNS 目标、验证、通配符名称服务器、SSL、故障排除(步骤 7)
data-isolation.md任一平台的步骤 3:共享架构搭配 RLS、每租户一个架构、每租户一个数据库,以及 Postgres/Supabase/Drizzle 策略模式
psl.md步骤 1:当租户在同级子域名上发布内容或运行代码时,了解资格要求、提交方式和过渡期 Cookie 控制
limits-and-quotas.md步骤 8:Cloudflare、Vercel 和 Neon 的限制名称及各自官方来源,用于映射到套餐

工作流(顺序很重要)

复制此清单以跟踪进度:

Multi-tenant progress:
- [ ] Step 1: Domain strategy and PSL decision
- [ ] Step 2: Tenant identification strategy
- [ ] Step 3: Isolation model (compute and data)
- [ ] Step 4: Deterministic routing
- [ ] Step 5: Tenant context propagation
- [ ] Step 6: Tenant config and least-privilege bindings
- [ ] Step 7: Custom domains and per-tenant static files
- [ ] Step 8: Limits mapped to plans, evidence captured
  1. 选择域名策略
  • 将租户工作负载放在专用的可注册域名上(租户使用 acme.app,品牌使用 acme.com)。一个进行钓鱼活动的租户若位于 x.acme.com,就可能导致整个域名被列入屏蔽列表;而设置了 Domain=acme.com 的租户 Cookie 则可以访问你的控制台。
  • 将控制台和身份验证放在与租户子域名不同的顶级域名下(控制台使用 app.acme.com,租户使用 *.acme.app)。
  • 如果租户在同级子域名上发布内容或运行代码,请将租户名称正上方的标签提交到 PSL(acme.app,或者 <tenant>.sites.acme.app 对应的 sites.acme.app),并立即开始:没有服务级别协议。租户自有的自定义域名无需 PSL 条目。否则,记录 No PSL 并说明原因。
  1. 选择租户标识方式(一个主要方式;自定义域名作为升级路径)
  • 子域名 tenant.acme.app:通配符 DNS 加通配符证书。默认选项。
  • 自定义域名 tenant.com:租户将 CNAME 指向你。适用于付费租户;声誉归属转移给他们;需要完成第 7 步中的入驻生命周期。
  • 路径 acme.app/tenant:无需为每个租户配置 DNS 或证书,但无法隔离 Cookie,也没有品牌标识。仅当租户永远不会获得主机名时才选择此方式。
  1. 定义隔离模型
  • **计算,Cloudflare:**在非可信模式下使用单个 dispatch 命名空间;按计划限制每次调用的 cpuMs 和 subRequests;如果租户代码可能访问互联网,则使用出站 Worker。
  • **计算,Vercel:**使用单个部署,绝不执行租户代码。如果租户必须发布代码,请改用 Vercel 多项目或 Cloudflare,而不要在应用内进行沙箱隔离。
  • **数据:**默认采用共享架构,每个面向租户的表都包含 tenant_id,并启用 RLS;对于受监管或资源占用较大的租户,可按计划选择每租户一个数据库。参见 data-isolation.md。
  1. 确定性路由(租户绝不影响路由,也无法看到彼此的数据)
  • **Cloudflare:**在 SaaS 区域上设置单个 */* 路由,指向 dispatch Worker;主机名 -> 租户记录(KV,未命中时查询 D1)-> env.DISPATCHER.get(script);Worker not found -> 404。
  • Vercel:proxy.ts(Next.js 16;在 15 中使用 runtime: 'nodejs' 的 middleware.ts)读取 host,在 Global Config 或数据库中查找租户,并重写到租户路径段;未知主机名 -> 404,绝不指向品牌站点。
  • 在任何租户重写之前放行 /.well-known。将 robots.txt、sitemap.xml 和 llms.txt 路由到租户路径段,使其内容因租户而异。
  1. 从单一权威来源传递租户上下文
  • 删除所有传入的 x-tenant-* 标头,根据已解析的租户设置 x-tenant-id、x-tenant-slug、x-tenant-plan,并在请求中转发这些标头(NextResponse.next({ request: { headers } }))。服务器组件读取 await headers();路由处理程序读取 request.headers。Cloudflare:dispatch Worker 设置标头,或在 fetch 前传递参数。
  • 代理负责路由,而非授权。Server Functions、路由处理程序和作业都必须从会话重新解析租户,并由数据层强制执行租户隔离(RLS 或 tenant_id 谓词)。
  1. 仅绑定租户所需的内容
  • **Cloudflare:**每个用户 Worker 都有自己的绑定(KV 命名空间、D1 数据库、R2 前缀);添加绑定必须显式重新部署。不要使用共享全局变量。
  • **Vercel:**Global Config 仅存储 hostname -> { id, slug, plan };数据库是事实来源,域名验证通过后执行写穿。功能标志和品牌信息从以租户 ID 为键的数据库中读取。
  1. 支持自定义域名和每租户静态文件
  • 需要设计并记录的生命周期:添加域名 -> 显示 DNS 目标 -> 验证所有权 -> 颁发证书 -> 激活映射 -> 删除或故障处理路径。
  • **Cloudflare:**在 SaaS 区域上使用 Cloudflare for SaaS 自定义主机名、代理回退源、customers.<you>.com CNAME 目标、http 或 txt 验证,并在 DNS 切换前预先验证。参见 cloudflare-platform.md。
  • Vercel:projectsAddProjectDomain -> 项目域名卡片中的 DNS 值 -> 仅当域名已在 Vercel 上时添加 _vercel TXT -> projectsVerifyProjectDomain -> Let's Encrypt HTTP-01。参见 vercel-domains.md。
  • robots.txt、sitemap.xml、llms.txt 是租户路径段中的路由处理程序,需明确指定 Content-Type;/public 中不得存放任何租户专属内容。这些内容属于 seo 范畴。
  1. 将限制呈现为计划并收集证据
  • 根据 limits-and-quotas.md 填写限制与计划对照表,从各自的来源 URL 读取当前值并注明日期;在路由层实施限制(Cloudflare limits、Vercel 计划标头加服务端检查)。
  • 不要在请求路径中执行任何长时间运行的操作:使用 Cloudflare Queues 或 Workflows、Vercel 后台函数或 cron。
  • 每项租户操作(创建租户、添加域名、验证、移除)都能通过 HTTP 完成,且权限与 UI 相同;如果某项操作只能在控制面板中进行,平台逻辑就渗入了 UI。
  • 运行证据命令并将结果粘贴到输出中。

注意事项

与平台和数据相关的注意事项位于相应步骤的参考资料中;这些问题会在加载任何参考资料前触发。

  • 转发传入的租户标头:执行 curl -H "x-tenant-id: <other>" 后会提供另一个租户的数据。在代理或分发 Worker 的每条路径上(包括跳过解析的路径,如 /.well-known 和品牌站点),都要删除或覆盖 x-tenant-*。
  • 如果主机名映射以受限字符集为键(Global Config 仅允许 ^[\w-]+$),则需要无冲突的编码方式或哈希;将点替换为下划线会使 a-b.example.com 和 a.b-example.com 映射到同一个键。在记录中保留原始主机名,并在读取时进行比对。
  • 如果一开始采用基于路径的方案,同时将自定义域名列入后续计划,那么之后就需要进行 URL 重写、Cookie 修改和 DNS 迁移。

输出架构

内容长度取决于决策:删除项目不会涉及的章节,不要为了填充而保留。

# Multi-tenant architecture

## Platform decision
- Platform: Cloudflare | Vercel
- Why this platform:
- Rejected platform and reason:

## Domain map
- Brand domain:
- Tenant domain:
- Tenant subdomains:
- Custom domains:
- PSL decision: Submit (suffix, owner, PR link, _psl TXT date) | No PSL (reason)

## Routing matrix
| Host pattern | Resolver | Destination | Unknown tenant behavior |
|---|---|---|---|

## Tenant context flow
- Authority: proxy.ts | dispatch Worker
- Headers set and stripped:
- Server read path:
- Data-layer enforcement:

## Isolation model
- Compute isolation:
- Data isolation (and per-plan variant):
- Config/binding isolation:

## Custom-domain lifecycle
1. DNS target:
2. Ownership verification:
3. Certificate provisioning:
4. Routing activation:
5. Removal/failure path:

## Limits-to-plan table
| Limit | Source URL / access date | Free | Pro | Enterprise | Enforcement point |
|---|---|---:|---:|---:|---|

## Validation evidence
| Check | Command | Expected | Result |
|---|---|---|---|

证据命令

在确定设计完成前,针对本地环境或预览环境运行;如标记为 N/A,请说明原因。

检查项命令预期结果
代码中存在租户边界rg -n "x-tenant-id|CREATE POLICY|FORCE ROW LEVEL SECURITY|DISPATCHER.get" .在代理或分发 Worker 以及架构中均有匹配项
未知主机返回 404curl -sI -H "Host: nope.acme.app" <url>404
忽略伪造的标头curl -s -H "Host: a.acme.app" -H "x-tenant-id: tenant-b" <url>/api/whoami租户 A
静态文件内容有所不同curl -s -H "Host: a.acme.app" <url>/robots.txt 与 -H "Host: b.acme.app"内容不同,Content-Type: text/plain
应用角色的 RLS 有效psql -c "BEGIN; SET LOCAL ROLE app_user; SELECT set_config('app.tenant_id','<t1>',true); SELECT count(*) FROM posts; ROLLBACK;"仅包含租户 t1 的行
ACME 路径可访问curl -sI -H "Host: tenant.com" <url>/.well-known/acme-challenge/test不会重定向到租户路径段
限制信息为最新在限制表的各个 URL 旁注明访问日期日期位于规划周期内

相关技能

  • codebase-architecture:应用本身的文件夹结构、模块契约和请求上下文流水线。
  • scaffold-nextjs:先引导 Next.js turborepo,再应用这些多租户模式。
  • seo:路由开始提供相应内容后,各租户 robots.txt、sitemap.xml、llms.txt 的内容、规范 URL 和结构化数据。

仅用于维护:evals/evals.json 包含此技能变更的回归场景;用户任务期间不会加载该文件。

评论

支持 Markdown