Skip to content
··阅读时间4分钟

我知道代理公司真正需要什么,所以我在第 2 天就做了多租户

在代理公司行业 20 年后,我知道多租户架构不能等,所以在只有一个可用 AI agent 的第 2 天,我把开发复杂度提升了 3 倍,以避免未来重写。

2025 年 8 月 21 日。构建 STRAŦUM 的第 2 天。

我坐在桌前,手里只有一个可用的 AI agent(Business Strategy)、基础认证和一个非常简单的数据模型。咖啡已经快凉了。我非常清楚自己想服务谁:需要 AI 营销帮助的 SMEs,以及希望在多个客户上复用能力的代理公司。

两个受众。从 Day 1 就都要覆盖。

我在代理公司侧工作了 20 年,我很清楚代理公司真正需要什么,不是宣传材料里的漂亮版本,而是同时管理 10-15 个客户时那种混乱现实:不同策略、不同品牌规范、几乎所有东西都不同。我也知道 SMEs 极度需要可负担的战略支持。

但在第 2 天,当我盯着这份简单模型时,我意识到一件不太舒服的事:如果要同时服务这两类受众,就必须现在就做多租户架构。不是以后。

到当天结束时,我做了一个决定:它会把开发复杂度拉到 3 倍,并把时间线拉长数周。

我在第 2 天就做了多租户架构。

这是野心还是疯狂?坦白说,当时我不确定。现在也还没 100% 确定。但这个几乎在“产品还没成型”时做出的决定,后来成了我最关键的技术选择之一。

为什么同时做两类受众?因为 20 年代理公司经验

我的愿景从来不是只做 SME。从一开始,我就想服务两类不同受众:

SMEs(小企业,1-30 人) — 你负担得起的战略联合创始人:

- 付不起营销代理公司或顾问

- 缺少战略营销能力

- 需要不必经历长学习曲线的快速成果

代理公司(管理 5-15+ 客户) — 扩的是战略产能,不是人头:

- 在多个客户的策略工作里被淹没

- 需要可规模化的统一方法论

- 需要客户之间的绝对数据隔离

为什么做代理公司?因为我在这一侧干了 20 年,痛点我亲身经历。

我见过策略师同时处理 12 个客户、12 套品牌规范,在不同工具间复制粘贴上下文,还要祈祷不要把错误策略发给错误客户。我也见过代理公司因为无法在不增加人头的情况下扩大战略能力,最终把优秀人才耗走。

说实话?我也想挑战自己。只做 SME 会简单得多——一个用户、一个组织、路由直接。但做代理公司意味着多客户看板、数据隔离、基于角色的权限、所有内容都要 client-scoped。

我想做复杂一点的东西。真正解决我看了二十年的难问题。

第 2 天的认知:多租户无法后补

在第 2 天盯着那份简单模型时,我明白了:

SME 架构(我当时已有):

```
users → campaigns → agent_outputs
```

多租户架构(代理公司需要):

```
organizations (SME or AGENCY)
  ↓
clients (agencies only)
  ↓
campaigns
  ↓
agent_outputs (with org_id AND client_id)
```

这不是“多加几列”那么简单,而是完全不同的数据模型。

如果先做 SME,再补代理公司,我将面临:

- 给所有现有表迁移增加 org_id

- 整库补齐 RLS 策略

- 前端路由重写以支持 client 上下文

- 所有功能在多租户场景下重测

这不是加功能,这是重写。

拖得越久,补起来越贵。Day 2 成本低。Day 60 会很痛。Day 200 可能会变成“要不干脆给代理公司做个独立产品”。

所以我做了决定:第 2 天就做多租户,或者接受代理公司永远不会是一等公民。

取舍:多租户真实代价是什么

这部分我本该停下来问自己:“你确定吗?你现在只有一个可用 agent。一个。”

但我没停。我直接开始像疯子一样写 SQL schema。第 2 天做多租户,意味着接受这些让理性人会再三犹豫的成本:

成本 1:开发复杂度(3 倍)

每张表都要 org_id。代理公司相关表还要 client_id。RLS 策略要双重过滤。每个查询、每个 API、每条前端路由都必须具备多租户意识。

预估复杂度提升:同样功能,开发时间 3 倍。

(剧透:实际更接近 4 倍。我低估了。典型我自己。 :P)

成本 2:开发周期延长

从 Day 1 就兼顾双受众,意味着更长的上线路径:

时间线:

- 8 月 20 日:开工(从 Day 1 就是多租户)

- 9 月 15 日:第 4 周,3 个 agents 可用,目标 10 月上线

- 10 月:我病了 10 天,无法写代码

- 11 月 5 日:Private Alpha 上线(总计 75 天)

多租户增加的工作:

- public 与 agency 表之间的 schema 路由

- 每张表的 RLS 策略(最终 26 张表共 83 条)

- client 上下文在每个 agent 流程里传递

- 双路由模式(SME 与 agency URL)

如果当时走 SME-only,会不会快 3-4 周上线?大概率会。但那之后代理公司一来,我就要面对重写。

成本 3:安全要求(风险更高)

SME 的数据隔离是基本盘。代理公司的数据隔离是生死线。

新增要求:

- 26 张表 83 条 RLS 策略

- schema 级隔离(public vs agency)

- 每个 CRUD 操作都要数据库路由函数

- 全面审计日志

- 多因素认证选项

安全复杂度:比 SME-only 高 5 倍。

有些周里,我花在 Row-Level Security 上的时间比 AI agent 开发还多。你可以感受下这个权重。

成本 4:测试复杂度(用例翻倍)

每个功能都要测:

- ✅ SME 流程(更简单)

- ✅ Agency 流程(带 client 范围)

- ✅ 数据隔离(Nike ≠ Adidas)

- ✅ 权限边界(agency 能看到 SME 数据吗?不能)

测试维护成本:翻倍。

最“有趣”的事情是什么?同一套测试在不同上下文里写两遍。没人会真的喜欢这个。

---

我为什么仍然接受这个取舍

我再复述一遍:3 倍复杂度、延长周期、5 倍安全开销、测试翻倍……我还是做了?

是的。我的思路如下:

原因 1:后补是噩梦

Day 2:代码几乎没写,模型还很灵活,没有用户要迁移。

Day 60:45 张表、20 万行代码、15 个 alpha 用户。此时加多租户等于重写半个代码库。

结论:架构决策越晚改,成本呈指数级上升。

Day 2 成本:约 5 小时重画数据模型。

Day 60 成本:约 200 小时重构全链路。

我见过公司后补多租户,真的很 brutal。等于在飞行中重造飞机,而且机上乘客还在付费。

原因 2:我真的懂代理公司

这不是纸面市场调研。我花了 20 年看代理公司在这个问题上挣扎。

我知道他们需要:

- 绝对数据隔离(客户 1 不能看到客户 2 策略)

- 所有核心对象都 client-scoped(品牌规范、persona、campaign)

- 基于角色的访问控制(AM 与策略师权限不同)

- 支持白标展示给客户的潜力

我能把这个做对,因为我经历过。不想把这个优势浪费在“先做 SME,代理公司以后再说”。

原因 3:挑战本身就是目的

这点我不常说:我就是做点难的。

我是有家庭的中年创始人,不是 22 岁可以靠能量饮料和少睡硬扛的人。如果我要花一年做一件事,它必须足够有挑战,也让我技术上有成就感。

多租户 + 数据隔离 + RLS + schema 路由,这很难,也很有意思。这类工程问题会让我凌晨两点还保持投入。

做 SME-only 会更快,但我是否还能保持同样动力穿过所有难关?大概率不会。

原因 4:两类受众会互相增强

SME 和代理公司不是竞争关系,而是互补关系:

- 代理公司验证产品:如果代理公司敢把客户数据放进来,SME 也更敢用

- SME 提供规模反馈:用户更多,反馈更快,迭代更快

- 同一架构服务两边:团队账号、角色权限、白标能力两边都能用

双受众意味着从一开始做的是完整解法,而不是迟早会过时的简化版。

原因 5:面向未来的选择权

即便不谈代理公司,多租户架构也解锁了:

- 团队账号(SME 多成员)

- 分销/代理伙伴模式

- 白标机会

- 企业销售通道(如果未来要走)

选择权价值:多租户在 Day 2 就解锁了我当时甚至还没完全想到的商业可能性。

落地实现:Day 2 的架构决策到底长什么样

这是 8 月 21 日我实际做的内容:

数据库 Schema(核心决策)

```sql
-- Organizations table (SME or AGENCY)
CREATE TABLE organizations (
  id UUID PRIMARY KEY,
  name TEXT,
  type TEXT CHECK (type IN ('SME', 'AGENCY')),  -- Critical distinction
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Clients table (agencies only)
CREATE TABLE clients (
  id UUID PRIMARY KEY,
  org_id UUID REFERENCES organizations(id),  -- Which agency owns this
  company_name TEXT,
  slug TEXT UNIQUE,  -- For URL routing
  created_at TIMESTAMPTZ DEFAULT NOW(),

  -- Constraint: Only agencies can have clients
  CONSTRAINT clients_agency_only CHECK (
    (SELECT type FROM organizations WHERE id = org_id) = 'AGENCY'
  )
);

-- Campaigns table (multi-tenant aware)
CREATE TABLE campaigns (
  id UUID PRIMARY KEY,
  org_id UUID REFERENCES organizations(id),  -- Always required
  client_id UUID REFERENCES clients(id),      -- Required for agencies, null for SMEs
  name TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Agent outputs (multi-tenant + client-scoped)
CREATE TABLE agent_outputs (
  id UUID PRIMARY KEY,
  org_id UUID REFERENCES organizations(id),
  client_id UUID REFERENCES clients(id),
  campaign_id UUID REFERENCES campaigns(id),
  agent_type TEXT,
  content JSONB,
  created_at TIMESTAMPTZ DEFAULT NOW()
);
```

Day 2 的关键决策:

- 每张表都带 org_id(便于 RLS)

- client_id 可空(SME 没有 clients)

- organizations 用 type 区分(SME vs AGENCY)

- 约束:只有 agency 能创建 clients

Row-Level Security(Day 2 规划)

```sql
-- RLS policy for campaigns (multi-tenant isolation)
CREATE POLICY campaigns_org_isolation ON campaigns
  FOR ALL TO authenticated
  USING (
    org_id = get_user_org_id() AND
    (client_id IS NULL OR client_id IN (SELECT id FROM clients WHERE org_id = get_user_org_id()))
  );
```

这条策略保证:

- ✅ 用户只能看到自己组织下的 campaigns

- ✅ Agency 用户看不到 SME 的 campaigns

- ✅ 代理公司之间互相看不到客户数据

代价: Day 2 先写了 5 条 RLS,发布时增长到 83 条。

URL 路由(从 Day 1 就按多租户设计)

```typescript
// Frontend routing structure (planned Day 2)

// SME routes (simple)
/campaigns/:campaignId
/agents/strategy/:campaignId

// Agency routes (client-scoped)
/clients/:clientSlug/campaigns/:campaignId
/clients/:clientSlug/agents/strategy/:campaignId
```

这套 URL 结构带来的能力:

- ✅ agency 场景里每个 URL 都带 client 上下文

- ✅ SME 与 agency 流程清晰分离

- ✅ URL 可收藏、可分享

- ✅ 可按 client 做分析追踪

结果:这笔账划算吗?

上线时间:2025 年 11 月 5 日(开工后第 75 天)

多租户额外开发负担:

- schema 设计与迁移

- 26 张表 83 条 RLS 策略

- 数据库路由函数

- 双路由模式(SME vs agency)

- client 上下文全链路传递

在 Claude Code 和 Gemini 2.5 Pro 帮助下,纯编码速度比我单打独斗快了不少。但那些“看起来应该能跑却就是不跑”的 RLS 调试,凌晨两点照样痛苦,AI 也不能替你完全省掉。

我现在拥有的:

- 组织之间完整数据隔离

- 支持 client scope 的 agency-ready 架构

- 26 张表 83 条 RLS 策略

- schema 级路由(public vs agency)

- Day 1 内建白标潜力

- 一个真的能同时服务 SME 与 agency 的产品底座

值不值?

6 个月后再问我,那时如果有真实客户付费,答案会更硬。现在我还在 private alpha(15+ 用户),继续摸索哪些有效、哪些无效。

但有一件事我确定:我已经有了同时服务两类受众的架构。如果当初先做 SME 再补 agency,此刻我大概率正在面对 3 个月重写。现在我可以把精力放在 PMF,而不是架构债。

这个取舍,对我来说是对的。

一个判断框架:什么时候该早做多租户

不是每个产品都要在 Day 2 做多租户。可以用这个框架:

这些情况建议尽早做:

目标市场包含代理/分销商(单客户价值更高)

数据隔离要求高(法律/合规驱动)

B2B 且高概率有团队账号(Slack、Figma 这种模式)

存在白标机会(分销 GTM 策略)

可能走企业销售(Day 1 就需要多客户能力)

这些情况建议先不做:

B2C 产品(个人用户、无组织层级)

MVP 首要目标是速度(先验证 PMF)

没有团队/代理场景(单人工具)

数据模型很简单(后续加 org_id 成本可控)

独立开发者仍在学习期(复杂度可能过高)

经验总结:按你的真实专长建架构

1. 受众认知应驱动架构

不要为假想用户设计,要为你真正懂的用户设计。

我的优势:20 年代理公司经验,让我非常清楚他们需要数据隔离、client scope、角色权限。

错误做法:“先做 SME,以后懂了再加代理公司。”

正确做法:“我已经懂代理公司了,趁便宜现在就做。”

如果你在某个细分市场有深度认知,就用它,不要机械服从“先做简单版”。

2. 早期复杂度,胜过后期重构

Day 2 架构成本:5 小时重画模型。

Day 60 架构成本:200 小时重构全局。

40 倍差距。

如果你有 80% 把握未来会需要多租户,就早点做。越晚越贵。

3. 技术挑战本身可以成为驱动力

这点比较个人化:我就是做难题。

多租户 + RLS + schema 路由 + 真正数据隔离,这是足够有挑战的工程问题。它让我在难关里保持投入。

如果你是 solo founder,不要低估“动力”这个变量。做一个能持续挑战你的东西,价值可能比“先快点上线”更大。

4. 架构会直接决定商业模式

多租户不只是技术决策,它直接开启了:

- 代理公司定价层级(等我把定价摸透)

- 白标机会

- 企业销售潜力

- SME 团队账号

架构 = 写在代码里的商业选择权。

5. Solo Founder 也能做多租户

“多租户太复杂,一个人做不了” → 错。

有了现代工具(Supabase RLS、数据库函数、AI 辅助开发),solo founder 完全可以做出企业级多租户。

时间成本:70 天(兼职节奏)。

得到的东西:真正数据隔离,而不是将来会后悔的临时 hack。

如果你认真想同时服务两类受众,这笔投入是值得的。

最后想法

Day 2 时其实太早了,根本无法知道 STRAŦUM 会不会成功。我只有一个 agent,没有用户,没有验证,只有 20 年代理公司经验告诉我代理公司到底需要什么。

延长时间线在一些时刻非常痛苦。别人都在发新版本时,我还在调 RLS、写数据库路由函数。那种挫败感不是一句“有点烦”能概括的。确实有些天我会怀疑:这一切复杂度真的值吗?

但现在我知道:从 Day 1 同时为两类受众设计,是正确决定。不是因为我算出了多漂亮的单元经济模型——我现在还没完全确认定价。是因为我已经拥有了真正服务两边的架构。

第 2 天做多租户,不只是技术选择。它是一个下注:为我真正理解的用户而建,而不是为“以后再研究”的假想用户而建。

这个下注回本了吗?

我还在 Private Alpha(15+ 用户),还没有最终答案。

但我可以确定一件事:当代理公司来问“你们能不能在多客户场景下做严格数据隔离?”时,我能直接说“可以”。不需要说“我们正在做”。

这就是一个正确的基础。

时间会证明我是有远见还是只是顽固。(很可能两者都有。) :)

你有没有做过一个当时看起来“太激进”的早期架构下注?最后回本了吗?很想听听你的故事。

致敬,

Chandler

STRAŦUM 架构系列: Day 2 的这个决定只是开头。到 Day 67,我不得不重建整套多租户层,因为一次安全审计暴露了架构缺陷。接着出现了 31 个由导航上下文丢失引发的空白屏,随后我又发现数据库 技术上正确但慢了 296 倍

---

正在构建多租户 SaaS? STRAŦUM 的架构从 Day 1 就支持 SME 与 Agency 两类客户。申请 alpha: https://stratum.chandlernguyen.com/request-invitation

---

Still learning that architecture decisions are business decisions in disguise. Still debugging RLS policies. Still questioning my Day 2 choices (but less so now). More building adventures at https://www.chandlernguyen.com/.

---

继续阅读

我的旅程
联系
语言
偏好设置