47 KiB
LangBot Workspace 多用户与 SaaS 多租户架构
状态:ARCHITECTURE BASELINE — isolation kernel implemented; SaaS activation gates remain
本文描述 Cloud v2 的目标架构和安全边界。详细的 Runtime、Box、PostgreSQL、pgvector 与 stdio MCP 决策以 pending-architecture-decisions.md 为权威来源;已经落地的实现选择记录在 implementation-decisions.md。
“隔离内核已实现”仅表示开源 Core/SDK 已具备多租户数据和运行时隔离所需的基础能力, 不表示闭源控制面、计费、生产部署或 Cloud v2 已经可以上线。
1. 架构决策摘要
Cloud v2 采用以下模型:
SaaS 对外只有一个逻辑 LangBot 实例,全部 Workspace 都是该实例内的租户; 开源 Core 提供完整隔离内核,闭源 Cloud Control Plane 管理 SaaS 目录、订阅、权益和计费。
核心决策如下:
Workspace是数据、成员、权限、用量和不可信执行的租户边界,不是一个 Pod、namespace、数据库或独立 LangBot 部署。- SaaS 注册 Account 时自动创建个人 Workspace;这只新增目录与业务记录,不创建租户专属服务、数据库、队列或 Runtime。
- OSS 每个 LangBot 实例只能存在一个 Workspace,但该 Workspace 可以有多个 Account、邀请和固定角色。
- SaaS 才允许一个 Account 拥有或加入多个 Workspace,并在 WebUI 中切换当前 Workspace。
- MVP 可以各运行一个 Core、Plugin Runtime 和 Box Runtime 进程;未来增加副本或 PostgreSQL shard 仍属于同一个逻辑实例的内部扩展,不改变产品模型和外部 API。
- 一个共享 Plugin Runtime 控制面管理所有 Workspace,但每个运行中的 plugin installation 独占一个 nsjail 进程;enabled-resident 是 desired semantics,只读代码和依赖可按已验证摘要共享。
- 一个共享 Box Runtime 管理所有 Workspace;首期符合 entitlement 的 Workspace 最多拥有一个持久
global逻辑 sandbox,实际命令继续以 nsjail 子进程执行。 - SaaS 业务数据使用 PostgreSQL shared schema、应用层 scope 与 RLS 双重隔离;pgvector 位于同一个业务数据库并作为 SaaS 默认向量后端。
- stdio MCP 有独立实例开关,Cloud v2 首期强制关闭,不能由 Box availability 或套餐能力隐式开启。
- 闭源 Control Plane 可以作为模块化单体复用现有账户、支付和运营能力,但历史 Cloud 的租户专属部署模型不进入新架构。
- Workspace 创建、释放、export、单 Workspace restore 和在线迁移的具体流程仍待后续决策。
本轮重构的最高目标是:
共享可信控制面和基础设施池,隔离不可信执行单元;减少独立部署和常驻组件,使新增 Account 或空 Workspace 的静态成本接近零。
减少组件数量不意味着合并安全边界。插件进程、sandbox、secret、可写文件和租户数据仍必须严格隔离。
2. 范围与非目标
2.1 本方案覆盖
- OSS 单 Workspace 多用户、邀请和固定 RBAC。
- SaaS 多 Workspace 账户、成员和 Workspace 切换模型。
- HTTP、WebSocket、API Key、Bot、Webhook、后台任务和内部调用的可信 Workspace 上下文。
- Bot、Pipeline、Provider、Knowledge、Plugin、MCP、RAG、Session、Storage 和 Monitoring 的租户隔离。
- Plugin Runtime 与 Box Runtime 的共享控制面和进程级隔离。
- SaaS PostgreSQL shared schema、RLS 与 pgvector 边界。
- 开源 Core 与闭源 Control Plane 的职责、协议和故障边界。
- 当前单副本运行和未来同一逻辑实例内横向扩展的兼容约束。
- 分阶段实施、激活门禁和验收策略。
2.2 本方案不覆盖
- 兼容或原地升级历史 Cloud 的租户专属部署方案。
- 为每个 Workspace 创建独立服务、数据库、schema、role、bucket、PVC、队列或 Runtime。
- 当前阶段实现多副本调度、跨地域 active-active 或 PostgreSQL 在线分片迁移。
- 第一版自定义角色、SAML、SCIM 或企业离线授权。
- 第一版 Workspace 级 BYOK E2B WebUI 配置。
- Cloud v2 首期 stdio MCP。
- Workspace export、释放、单租户恢复和在线迁移的具体产品流程。
历史客户数据、账户和财务记录如需迁移,应单独立项;旧部署拓扑不作为本架构的设计约束。
3. 术语与不变量
3.1 术语
| 术语 | 定义 |
|---|---|
| Account | 登录主体。OSS 中是实例本地账户;SaaS 中是全局账户 |
| Workspace | 逻辑 LangBot 实例内的租户,是资源、成员、权限、用量和不可信执行的首要边界 |
| Membership | Account 与 Workspace 的关系,包含固定角色、状态和权限版本 |
| Invitation | 邀请一个 Account 或邮箱加入 Workspace 的一次性凭证 |
| Logical Instance | 对外唯一的 LangBot 服务与安全域,拥有稳定 instance_uuid,不等同于某个进程或 Pod |
| Replica | Core、Plugin Runtime 或 Box Runtime 的短期内部运行副本,不是产品实体 |
| Execution Generation | Workspace 执行所有权和撤销的单调代数,用于隔离旧任务、旧连接和故障转移 |
| Billing Account | SaaS 付款主体,可以为一个或多个 Workspace 付费 |
| Entitlement | Control Plane 签发、Core 与 Runtime 本地执行的功能和数值额度快照 |
| Cloud Control Plane | 闭源 SaaS 控制面,管理全局身份、Workspace 目录、订阅、权益、计费和生命周期 |
| LangBot Core | 开源数据面,执行 Bot、Pipeline、Plugin、MCP、RAG 等业务并实施最终授权与隔离 |
当前代码中的 placement_generation 字段在迁移完成前保留兼容;其架构语义和目标命名均为
execution_generation,不表达 Workspace 属于某个产品级部署单元。
3.2 必须始终成立的不变量
- SaaS 只有一个稳定
instance_uuid;所有副本共享该身份。 replica_id、worker_id、Pod 名称、进程地址和数据库连接地址都是短期运行信息,不能进入业务资源的永久主键或外部 URL。workspace_uuid是租户数据、任务、缓存、文件、日志、用量和运行时隔离的稳定键,也是未来内部路由与分片的候选键。- OSS 一个实例最多一个 Workspace;SaaS 才能激活多个 Workspace。
- 一个 Workspace 可以有多个 Account;一个 SaaS Account 可以加入多个 Workspace。
- 所有租户业务资源都具有非空
workspace_uuid,并使用(workspace_uuid, resource_uuid)定位。 - Workspace 选择器只是路由输入,不是授权凭证;服务端必须重新验证 Account、Membership、资源所有权和权限。
- API Key、Bot、Webhook、后台任务、Plugin 与 Box 调用从可信所有权或绑定派生 Workspace,不能信任调用方自报 scope。
- SaaS 缺少有效 Workspace 上下文时必须失败关闭,不能回退到第一个、最近或 OSS 默认 Workspace。
- Core 是资源访问、运行时授权和 entitlement 执行的最后一道边界;Control Plane 不同步代理每条消息或普通资源请求。
- 一个不可信插件进程只能属于一个 installation;一个 sandbox/session 只能属于一个 Workspace。
- execution generation 失效后,旧任务、连接、回调和副作用必须被拒绝。
- 本地进程表、缓存和临时目录都可重建,不能成为 desired state、撤销状态或业务数据的唯一真相。
- 创建空 Workspace 不启动插件 worker、sandbox 或租户专属常驻组件。
- 未来横向扩展不能改变 Workspace UUID、外部 API、权限模型或隔离语义。
4. 产品与部署模型
4.1 SaaS 逻辑拓扑
flowchart LR
User["Browser / API / Bot traffic"] --> Edge["SaaS Edge"]
User --> CP["Closed Cloud Control Plane<br/>directory + subscription + billing"]
Edge --> Core["One logical LangBot instance<br/>Core replica pool; MVP = 1"]
CP -->|"signed manifest, directory projection,<br/>entitlement and desired state"| Core
Core -->|"usage outbox and observed state"| CP
Core --> PG["Shared PostgreSQL business database<br/>RLS + pgvector"]
Core --> PluginRT["Shared Plugin Runtime<br/>trusted supervisor"]
Core --> BoxRT["Shared Box Runtime<br/>trusted supervisor"]
PluginRT --> PluginA["Workspace A installation<br/>isolated nsjail process"]
PluginRT --> PluginB["Workspace B installation<br/>isolated nsjail process"]
BoxRT --> SandboxA["Workspace A<br/>persistent global logical sandbox"]
BoxRT --> SandboxB["Workspace B<br/>persistent global logical sandbox"]
Core --> ObjectStore["Shared durable object storage<br/>Workspace-scoped keys"]
这里的“一个逻辑实例”是一个服务、安全域和稳定身份,不是“永远只有一个 OS 进程”。 MVP 不实现分布式,但从第一天保留内部扩展所需的身份、幂等、generation 和 owner 抽象。
4.2 容量演进
| 阶段 | 内部部署形态 | 新 Workspace 静态成本 | 启用条件 |
|---|---|---|---|
| M0 单副本 MVP | 一个 Core、一个共享 Plugin Runtime、一个共享 Box Runtime、一个 PostgreSQL business database | 只新增目录和业务行 | 当前目标 |
| M1 同逻辑实例横向扩展 | 按容量增加 Core/Runtime 副本;使用 owner lease、fencing 和 generation;PostgreSQL 可增加 shared shard | 不创建 Workspace 专属部署 | 出现容量或可用性证据后 |
| M2 Dedicated 资源等级 | 特定 workload 使用独享 worker pool、sandbox class 或 database shard,但沿用相同身份、协议和 schema | 仅购买该等级的客户承担 | 合规、驻留或超大负载需求 |
M1 是 M0 的透明扩容,M2 是相同架构下的资源等级。外部 API 只认识稳定的
instance_uuid 和 workspace_uuid,不认识 replica、worker、pool 或 shard。
4.3 当前不做分布式时必须预留的能力
- 运行时协议携带稳定
instance_uuid、workspace_uuid和execution_generation,不依赖进程地址表达身份。 - Plugin installation 和 Box session 使用稳定 owner 抽象;启用第二个副本前再实现带 expiry、CAS 和 fencing token 的 lease。
- 创建、重试、回调、worker 注册和 outbox 使用稳定 idempotency key,重复投递不能产生第二个 owner 或副作用。
- Repository/UoW 不允许无边界跨 Workspace 事务;
workspace_uuid可直接作为未来 shard key。 - schema migration、后台任务扫描、监控聚合和运维接口不能假设永远只有一个 Core 进程。
- Runtime 重启通过 durable desired state reconciliation 恢复,不依赖原进程或本地 cache。
- 只有出现容量、可用性、地域或合规证据后才增加副本、lease store 或 shard router;预留协议不等于提前部署组件。
4.4 组件边界
- Core、Plugin Runtime 和 Box Runtime 可以由发布与故障域决定是否共用 Pod,但必须保持独立进程身份、容器和 security context。
- Core 不能继承 nsjail、cgroup 或 mount namespace 所需的高权限。
- Plugin Runtime 与 Box Runtime 不合并为一个高权限进程。
- MVP 不新增 Runtime 专用数据库、Box 专用数据库、Kafka、Redis、租户级 scheduler 或 artifact service。
- 可信 supervisor、数据库连接池、只读 artifact cache 和基础容量可以多租户共享。
5. OSS 与 SaaS 产品行为
5.1 能力矩阵
| 能力 | OSS | SaaS |
|---|---|---|
| Workspace 数量 | 实例固定一个 | Account 可拥有或加入多个,受 ProductPolicy 约束 |
| Workspace 成员 | 多用户 | 多用户,受 entitlement 约束 |
| 邀请成员 | 支持 | 支持 |
| 固定 RBAC | 支持 | 支持 |
| 自定义角色 | 不支持 | 后续商业能力 |
| Workspace 创建 | 首次初始化创建唯一 Workspace | 注册自动创建个人 Workspace;后续创建受 ProductPolicy 约束 |
| Workspace 切换 | 无需展示 | 支持 |
| 订阅与计费 | 无远端依赖 | 闭源 Control Plane 管理 |
| 租户隔离 | 完整实现 | 完整实现 |
OSS edition policy 应表达为:
workspace_limit = 1
members_enabled = true
invitations_enabled = true
fixed_rbac_enabled = true
multi_workspace_enabled = false
不能用 member_limit = 1、关闭邀请或移除 RBAC 来实现单租户限制。
5.2 OSS 初始化和邀请
首次初始化在一个事务中完成:
- 创建本地 Account。
- 创建实例唯一 Workspace。
- 创建 owner Membership。
- 创建默认 Pipeline、metadata 等 Workspace 初始资源。
- 标记实例初始化完成。
初始化后默认关闭公开注册。后续用户由 owner/admin 创建一次性 Invitation,注册或登录后接受邀请并加入唯一 Workspace。 OSS 后续注册不创建第二个 Workspace。未配置 SMTP 时,系统返回只展示一次的邀请链接供管理员通过可信渠道发送。
5.3 SaaS 注册和邀请
普通注册由 Control Plane 通过幂等工作流完成:
- 创建或确认全局 Account 与 AuthIdentity。
- 创建 personal Workspace 和 owner Membership。
- 创建初始 Subscription/Entitlement 投影。
- 完成 verified email、速率限制和基础风控。
- 将 Account、Workspace 和 Membership 投影到 Core。
- Core 达到要求的目录 revision 后返回可访问 route。
注册只创建逻辑记录,不启动 Runtime 或租户专属基础设施。
通过邀请注册的新用户也创建自己的 personal Workspace,同时加入受邀 Workspace;已注册用户接受邀请时只新增目标 Membership。 个人 Workspace 与团队 Workspace 的付费关系必须由 ProductPolicy 明确,不允许代码根据名称或创建路径隐式推断。
5.4 Invitation 安全规则
- token 使用至少 256-bit 加密安全随机数,数据库只保存 hash。
- token 具有
expires_at、accepted_at、revoked_at,只能使用一次。 - Membership 创建与 token 消费在同一事务中提交。
- Invitation 不能授予 owner;owner 转移使用独立流程。
- SaaS 接受邀请时必须验证目标邮箱;OAuth 邮箱相同不能跳过 token 和显式确认。
- Workspace 必须始终至少有一个 active owner;admin 不能移除或降级 owner。
- 浏览器邀请链接把 secret 放在 URL fragment 中,页面读取后立即清除 fragment,并只短期保存在
sessionStorage。
5.5 固定 RBAC
Core 权威定义 owner、admin、developer、operator 和 viewer 固定角色。
权限按能力划分,例如资源查看、资源管理、运行操作、成员管理、provider secret 管理、审计查看和数据导出。
规则:
- 普通资源可见性不自动授予 secret 可见性。
- 跨 Workspace 猜测资源 UUID 返回 404,不泄露存在性。
- 同 Workspace 资源存在但缺少权限时返回 403。
- 最后一个 owner 不能被删除或降级。
- 前端隐藏或禁用无权限入口只改善体验;后端仍必须执行所有授权检查。
6. 开源与闭源职责边界
6.1 LangBot Core OSS
Core 负责:
- 本地 Account、Workspace、Membership 和 OSS Invitation。
- 固定 RBAC 与单 Workspace edition policy。
- 业务资源及其 Workspace scope。
- HTTP、WebSocket、后台任务和运行时请求上下文。
- Plugin、MCP、RAG、Box、Session、Storage 和 Monitoring 隔离。
- SaaS Account/Workspace/Membership 的版本化执行投影。
- InstanceManifest、EntitlementSnapshot 和 Runtime 控制通道验证。
- 通用 capability 与数值 quota enforcement。
- UsageEvent/business outbox 和基础安全审计。
Core 是 Bot、Pipeline、Model、Knowledge、Plugin installation、MCP configuration 和 Monitoring 数据的权威来源, 也是每个业务和运行时请求的最终授权边界。
6.2 Closed Cloud Control Plane
Control Plane 负责:
- SaaS 全局 Account、AuthIdentity、Session、OIDC 和后续 SSO。
- SaaS Workspace、Membership 和 Invitation 的权威目录。
- Workspace 创建、暂停、归档和删除工作流。
- BillingAccount、Product、PlanVersion、Price、Subscription、Invoice、Refund 和 provider event。
- Entitlement 计算、签名与版本。
- Usage ledger、聚合、额度和欠费策略。
- 实例 manifest、release、capacity、内部 desired state 和 observed state。
- SaaS 运营后台、平台角色和高级审计。
首期不把这些职责拆成多个租户、计费和调度微服务。推荐以一个独立于 Core 的闭源模块化单体承载, 并通过模块边界复用已有账户、OAuth、支付、邮件和运营能力。历史 Cloud 的租户专属部署代码不复用。
Control Plane 不保存 Bot、Pipeline、Model 或 Knowledge 等业务内容,也不代理普通消息执行。
6.3 SaaS Adapter
Core 中只保留薄的协议适配层:
- 验证 InstanceManifest、Account token 和 JWKS。
- 消费 DirectoryEvent 并写入本地投影。
- 缓存并验证 EntitlementSnapshot。
- 将 UsageEvent 写入 durable outbox。
- 接收 execution desired state 并上报 observed state。
适配层不得 monkey patch ORM、绕过 Core 权限检查或在普通资源请求中同步调用 Control Plane。
6.4 Source of Truth
| 数据 | OSS | SaaS |
|---|---|---|
| Account、Workspace、Membership | Core 本地数据库 | Control Plane 权威,Core 保存版本化投影 |
| Invitation | Core 本地数据库 | Control Plane 权威,不向 Core 投影 pending secret |
| Bot、Pipeline、Model、KB、Plugin、MCP | Core | Core |
| Subscription、Payment、Invoice、Usage ledger | 无远端依赖 | Control Plane |
| Feature 和 quota | 本地 edition policy | Control Plane 签发,Core/Runtime 验证执行 |
| Execution generation | OSS 固定本地值 | Control Plane desired state,Core 执行 |
| 运行时授权 | Core | Core 根据本地投影和 entitlement 执行 |
SaaS 不维护两套可写目录。Control Plane 是目录权威写模型;Core 只保存带 revision 的执行投影。
7. 控制面协议
7.1 InstanceManifest
仅设置 system.edition=cloud、环境变量或前端 feature flag 不得启用 SaaS 多 Workspace。
Cloud bootstrap 必须验证由预置根信任签名的 InstanceManifest,并据此安装闭源 Workspace policy。
Manifest 至少绑定:
iss, aud, sub, jti, iat, nbf, exp
instance_uuid
release
capabilities
tenant_isolation_version
execution_generation
delegated issuers and keyset revision
签名错误、audience 不匹配、过期、generation 回滚或信任链缺失时必须失败关闭,不能降级为 OSS 默认 Workspace。
7.2 DirectoryEvent 与目录新鲜度
Control Plane 通过 transactional outbox 发布 Account、Workspace 和 Membership 的版本化事件。
Core 使用 inbox 按 event_id 去重,以 aggregate revision 拒绝旧写,并追踪连续应用水位。
要求:
- 事件和 batch 经过实例绑定的强认证与签名。
- 重复、乱序、延迟、断流和全量 replay 都安全。
- 删除使用 tombstone。
- 新实例先导入带 high watermark 的 snapshot,再消费增量。
- projection 未就绪或落后于授权 lease 要求时,交互与自动化请求按策略失败关闭。
- SaaS pending Invitation、email 和 token hash 不进入 Core 投影。
MVP 可采用一个共享、原子且可恢复的 Control Plane store;未来多副本不能继续使用进程内状态承担一次性 token 或目录水位。
7.3 EntitlementSnapshot
Entitlement 使用版本化签名快照,至少绑定:
instance_uuid
workspace_uuid
plan_revision
entitlement_revision
status
features
limits
nbf, exp, grace_until
Core 校验 issuer、audience、subject、instance、revision、时间和签名;旧 revision 不覆盖新快照。 套餐名称和价格规则只存在于闭源 Control Plane,Core 与 Runtime 只理解通用 capability 和数值限额。
Control Plane 故障时,已缓存且仍有效的快照可继续执行;过期后只能进入明确、有限的 grace 模式或失败关闭。
7.4 UsageEvent 与 outbox
用量事件 append-only、至少一次投递,Control Plane 按 event_id 去重。事件至少包含:
event_id
instance_uuid
workspace_uuid
execution_generation
meter
quantity_integer
unit
source
occurred_at
entitlement_revision
schema_version
Core 不计算账单金额,也不在普通请求中同步扣费。业务写入与相应 business outbox 必须在同一事务中提交; generation-aware write fence 与 outbox 原子性尚是 SaaS 激活门禁。
7.5 Desired state 与 observed state
闭源控制面发布版本化的 release、capacity 和 execution desired state,Core/Runtime 幂等 reconcile 并上报 observed state。 desired state 只描述同一逻辑实例内部的执行所有权和容量,不产生新的产品级实例或租户实体。
Workspace 安全状态由 directory revision 决定,订阅状态由 entitlement revision 决定,执行撤销由 execution generation 决定。三者取最严格有效状态,但任何通道都不能修改另一个通道的权威字段。
8. 身份、鉴权与请求上下文
8.1 上下文模型
租户业务入口统一解析不可变的 RequestContext:
@dataclass(frozen=True)
class RequestContext:
instance_uuid: str
workspace_uuid: str
execution_generation: int
principal_type: str
principal_uuid: str
permissions: frozenset[str]
auth_method: str
entitlement_revision: int | None
request_id: str
不同入口的 Workspace 来源:
| 入口 | Workspace 来源 |
|---|---|
| Browser Account token | X-Workspace-Id 只作候选;服务端校验 Membership |
| API Key | key 记录绑定的 Workspace,忽略 caller selector |
| Public Bot / Webhook | Bot 或 webhook route 的可信所有权 |
| Background job | durable payload 中的完整 scope,执行前重新验证 generation |
| Plugin Host API | 认证控制连接和 immutable action context |
| Box operation | 已验证 entitlement、admission grant 和 Runtime namespace |
| System operation | 显式、最小能力的 SystemContext,禁止隐式全局上下文 |
禁止从模块全局变量、进程默认 Workspace、请求 payload 或“第一个 Workspace”推断 scope。
8.2 Account token 与 Workspace discovery
- 新 JWT 使用稳定 Account UUID 作为
sub,并绑定 issuer、当前instance_uuidaudience 和 expiry。 - 账户级 Workspace discovery 是一个窄 bootstrap capability,只列出该 Account 的 active Membership,不能执行租户业务。
- multi-Workspace 模式下,tenant route 缺少 selector 必须拒绝;OSS singleton 模式可由 policy 选择唯一 Workspace。
- Account token 不直接证明任一 Workspace 权限;Membership 必须在服务端解析并验证状态与 revision。
8.3 API Key、WebSocket 与长任务
- API Key 只持久化 hash,raw secret 仅返回一次;记录绑定 Workspace、固定 scopes、状态、expiry 和 creator。
- Dashboard WebSocket 在升级后认证,并在每条入站消息前重新验证 Account、Membership、权限、资源所有权和 generation。
- 长时间 LLM、MCP、Plugin 或 Box 调用在产生副作用或接受结果前再次校验 execution generation。
- 临时凭证交换绑定发起者、Workspace、instance 和 generation;其他 scope 查询返回与不存在相同的 404。
8.4 错误语义
| 场景 | 语义 |
|---|---|
| 未认证或 token 无效 | 401 |
| 同 Workspace 资源存在但权限不足 | 403 |
| 资源不存在或属于其他 Workspace | 404 |
| edition / entitlement / quota 禁止 | 稳定领域错误码,不伪装为 500 |
| execution generation 过期 | fail closed,并停止旧运行态 |
| 未处理异常 | 稳定 internal_error + request ID;细节只进入服务端日志 |
9. Core 数据模型
9.1 Account、Workspace 与 Membership
核心实体至少包含:
Account
uuid
email_normalized
display_name
status
auth bindings
Workspace
uuid
name
status
source: local | cloud_projection
directory_revision
WorkspaceExecutionState
workspace_uuid
instance_uuid
execution_generation
status
write_fenced_at
revision
WorkspaceMembership
workspace_uuid
account_uuid
role
status
directory_revision
约束:
- Membership 对
(workspace_uuid, account_uuid)唯一。 - Workspace 的 source 不允许通过可变本地配置从 local 升级成 cloud projection。
- Cloud projection 只有在 manifest、instance binding、目录 revision 和 execution state 均有效时才可路由。
- OSS bootstrap 只创建或修复 local singleton Workspace。
9.2 Invitation
OSS Invitation 存在 Core 本地数据库;SaaS Invitation 只存在于闭源目录。
WorkspaceInvitation
uuid
workspace_uuid
email_normalized
role
token_hash
expires_at
accepted_at
revoked_at
created_by
数据库约束必须保证同一 Workspace 与邮箱只有一个有效邀请,并保证 token hash 全局唯一。
9.3 业务资源
所有租户资源显式包含 workspace_uuid,包括但不限于:
- Bot、Pipeline、Provider、Model、Knowledge Base 和 vector record。
- Plugin installation、MCP configuration、API Key 和 webhook binding。
- Query、Message、Session、Monitoring、Usage 和 AuditEvent。
- Upload、ObjectRef、Skill、Runtime desired state 和 temporary credential session。
唯一键、索引、缓存 key、object key、日志维度和幂等键都必须包含 Workspace scope。
服务层不得暴露可绕过 Workspace 条件的普通 get(id)、list() 或 delete(id)。
9.4 防御性约束
- tenant table 的
workspace_uuid非空并有外键。 - SaaS PostgreSQL 关键表启用并强制 RLS。
- 需要全局唯一的 opaque token 使用 hash 唯一索引,不依赖 Workspace 内唯一。
- owner 保底、Membership revision、invitation one-shot 等规则同时由 service 和数据库事务保护。
- 任何跨 Workspace 运维操作必须走显式受审计的 system capability,不得复用普通 repository。
10. PostgreSQL、pgvector 与存储
10.1 数据库边界
- OSS 继续默认 SQLite,并可显式选择自托管 PostgreSQL。
- SaaS 使用一个 PostgreSQL business database、一个
publicshared schema 和共享连接池。 - 创建 Workspace 不创建 database、schema、role 或专属连接池。
- 每个 tenant transaction 使用
SET LOCAL建立 scope,并由统一 TenantUnitOfWork 保证 context 与 SQL 使用同一事务和连接。 - 应用层 Workspace scope 是第一道边界,
ENABLE+FORCE ROW LEVEL SECURITY是第二道边界。 - runtime role 必须是非 owner、最小权限、无 superuser、无
BYPASSRLS、无 role membership 和跨 schema 权限。 - schema、extension、policy 和 ACL 只由独立 release migrator 创建与验证;Cloud runtime 不执行 DDL。
- PostgreSQL 仅承载业务数据和 pgvector,不成为 Plugin/Box 通用协调数据库、进程目录或新的控制面数据库。
首期 migrator 和 runtime URL 必须连接同一个 host、port、database,但使用不同 role。 生产部署还必须证明 runtime credential 无法连接 PostgreSQL 集群中的其他 database;专用 endpoint 或经验证的 HBA/proxy 隔离仍是激活门禁。
10.2 Transaction 与后台任务
- 一个 TenantUnitOfWork 只绑定一个 Workspace、一个 execution generation 和一个事务所有者任务。
- 子任务不能继承并提交、回滚或关闭父任务的 tenant session。
- 长时间 LLM 或网络等待不持有数据库连接;每次数据库 helper 打开短事务。
- detached task 只在父事务提交后启动,并自行建立新 scope;父事务回滚时取消待启动任务。
- generation-aware write fence 必须保持到 commit,并与 business outbox 原子提交;该能力完成前不得激活 SaaS 写流量。
10.3 pgvector
- SaaS 默认使用同一业务 PostgreSQL 中的 pgvector,不静默回退到 Chroma。
- 向量身份至少为
(workspace_uuid, knowledge_base_uuid, vector_id)。 - 向量操作使用相同 tenant context 与 RLS 契约。
- embedding 维度显式存储和校验;不匹配时失败关闭,不截断、补齐或改用无界扫描。
- extension、表、constraint 和 ANN index 由 release migration 创建。
- OSS 默认仍可使用 SQLite + Chroma;选择 pgvector 时遵守相同 scope。
10.4 Object storage
- 大对象、plugin artifact、upload、knowledge 文件和 sandbox 文件不作为 PostgreSQL blob 存储。
- durable object key 和 metadata 都包含 Workspace scope;临时 staging 可包含 generation,但稳定业务引用不能因未来 generation 切换而永久失效。
- 现有 generation-scoped opaque key 在固定 generation 的 OSS 中安全,但 Cloud cutover 前必须实现稳定 final identity 或原子引用迁移。
- public image 与 private document 使用不同 capability;不能把通用 upload key 当作公开读取凭证。
11. Plugin Runtime
11.1 共享 supervisor、独立 worker
整个逻辑实例共享一个可信 Plugin Runtime 逻辑控制面;M0 由一个 supervisor replica 承担。新 Workspace 不创建专属 Runtime、连接、卷或进程。
每个运行中的 plugin installation 独占一个 nsjail worker process tree;enabled-resident 是 desired semantics。worker 运行期间永久绑定:
instance_uuid
workspace_uuid
execution_generation
installation_uuid
runtime_revision
artifact_digest
插件不能通过 payload、Host API 参数、环境变量或重连改变该绑定。Supervisor 不在自身解释器中加载第三方插件代码。 停用、删除、revision/generation 变化或 entitlement 撤销时,旧 worker 必须停止并失去 Host API 权限。
11.2 文件和进程边界
data/plugin-runtime/
├── artifacts/sha256/<artifact_digest>/code/ # 已验证、只读共享
├── environments/sha256/<environment_digest>/ # 原子发布、只读共享
└── installations/<installation_uuid>/
├── home/ # 私有可写
├── tmp/ # 私有可写
└── data/ # 私有持久数据
- 同插件同版本只有在 package digest 完全相同且完整性已验证时才共享只读代码。
- dependency environment key 包含 artifact/requirements digest、Python ABI、Runtime version 和 installer schema。
- installation 进程、配置、secret、home、tmp、data 和日志永不合并。
- namespace、private
/proc、mount、PID、IPC、UTS、cgroup 与 rlimit 阻止读取其他文件、枚举或 signal 其他进程。 - Cloud 不从 artifact 自动加载
.env;secret 只由可信控制面按 installation 注入。 - 插件 egress 必须阻止访问 Core loopback、Box Runtime、数据库和平台 metadata endpoint。
11.3 统一资源上限
资源限制只来自实例级 data/config.yaml,并支持现有环境变量覆写;plugin manifest 不能声明、放宽或覆盖。
plugin:
worker:
max_cpus: 1.0
max_memory_mb: 512
max_pids: 128
max_open_files: 256
max_file_size_mb: 512
require_hard_limits: true
CPU、内存和 PID 使用 cgroup 硬限制,open files 和单文件大小使用 rlimit。 Cloud deployment profile 强制 nsjail;硬限制不可用时 readiness 失败,不能降级为普通子进程。 installation 总磁盘配额需要可原子拒绝写入的 quota provider,不能以目录扫描冒充硬限制。
11.4 Desired state 与恢复
- PostgreSQL 中的 installation desired state 与 durable binary storage 是权威状态。
- Runtime 本地进程表、nsjail 目录、artifact/venv cache 都可重建。
- Runtime 重连执行实例范围 full reconciliation,清理 stale worker 并恢复 enabled installation。
- dependency preparation 失败记录在对应 installation,不启动半就绪 worker,也不阻塞其他 installation。
- desired semantics 要求 enabled installation 常驻,不做 idle eviction;是否按负载回收以后再决定。
- 当前 Supervisor 可在 Runtime 重连或 Core apply/reconcile 时恢复 desired state,但尚未为意外退出的 worker 实现带有界 backoff 的 completion callback;这项可靠性缺口在 Cloud 激活前必须补齐并验证。
真实 Linux/nsjail/cgroup 与受控 egress 的 Cloud 部署验证尚未完成,是生产激活门禁。
12. Box Runtime 与 stdio MCP
12.1 共享 Box 控制面
整个逻辑实例共享一个可信 Box Runtime 逻辑控制面;M0 由一个 Runtime replica 承担。Core 与 Runtime 控制通道绑定稳定 instance identity,
每个 operation 绑定 workspace_uuid、execution_generation、session revision 和短期 admission grant。
首期 entitlement 模型:
{
"features": {
"managed_sandbox": true,
"external_sandbox": false
},
"limits": {
"managed_sandbox_sessions": 1
}
}
闭源订阅模块把套餐映射为该通用 capability;Core 与 Runtime 不判断 plan == pro。
预期 Pro 得到 managed_sandbox_sessions = 1,其他套餐为 0。
12.2 Sandbox 模型
- 合资格 Workspace 首次使用时懒创建一个持久
global逻辑 session。 global表示 Workspace 内默认逻辑 sandbox,不表示跨 Workspace 共享。- session TTL 不自动回收;Runtime 重启后进程和临时目录失效,但
/workspace持久数据保留。 - 每次普通命令在 Box Runtime 容器内启动一个 one-shot nsjail 子进程。
- 首期禁止 managed background process 和 network,避免 session 被当成常驻共享主机。
- Core 与 Runtime 通过认证 random-marker challenge 证明看到同一 durable volume,不能只比较路径字符串。
- 文件同步、attachment 和 skill mount 沿用现有 nsjail 机制,但所有 host path 解析必须由可信 Workspace context 派生并防止 symlink/path escape。
Cloud readiness 必须证明 cgroup、namespace、mount、Workspace/Skill/ephemeral byte quota 和 inode quota 均为硬限制。 当前普通 nsjail backend 不具备全部硬磁盘能力,因此 Cloud Box 应失败关闭,直到绿地部署提供并验证真实 quota provider; 不能把软目录扫描写成“生产已就绪”。
12.3 外部 E2B
非 Pro 用户后续可在 WebUI 配置 Workspace 自有的远程 E2B sandbox。该功能尚未实现,首期不纳入。 未来 credential 必须属于 Workspace、加密存储且读取受 secret 权限保护,不消耗 Cloud managed sandbox 配额。
12.4 stdio MCP 独立开关
mcp:
stdio:
enabled: true
- OSS 默认
true保持兼容。 - Cloud v2 通过
MCP__STDIO__ENABLED=false强制关闭。 - 该 gate 独立于
box.enabled、managed sandbox entitlement 和 session quota。 - gate 同时覆盖 create、update、test、bootstrap load 和最终 Runtime execution。
- 已有 stdio 配置在 gate 关闭时保留但不启动,并返回明确的 feature-disabled 错误。
- HTTP/SSE 等远程 MCP transport 不受影响。
13. HTTP API 与 WebUI
13.1 Core API
OSS 与 SaaS 执行面共用通用 Workspace API:
GET /api/v1/workspaces
GET /api/v1/workspaces/{workspace_uuid}
GET /api/v1/workspaces/{workspace_uuid}/members
POST /api/v1/workspaces/{workspace_uuid}/invitations
PATCH /api/v1/workspaces/{workspace_uuid}/members/{account_uuid}
DELETE /api/v1/workspaces/{workspace_uuid}/members/{account_uuid}
Cloud policy 下,目录 mutation 由闭源 Control Plane 负责;Core 对本地创建、邀请和成员修改返回稳定的
control_plane_required,只提供执行投影的安全读取。
所有 tenant resource route 必须经过统一 decorator/middleware:
- 认证 principal。
- 解析可信 Workspace。
- 校验 Workspace/ExecutionState。
- 校验 Membership 或资源绑定。
- 校验 permission 和 entitlement。
- 创建 RequestContext 与 TenantUnitOfWork。
13.2 SaaS Control Plane API
SaaS 产品 API 包含:
POST /cloud/workspaces
GET /cloud/workspaces
POST /cloud/workspaces/{workspace_uuid}/invitations
POST /cloud/invitations/{token}/accept
GET /cloud/workspaces/{workspace_uuid}/subscription
POST /cloud/workspaces/{workspace_uuid}/checkout
GET /cloud/workspaces/{workspace_uuid}/usage
这些 API 管理目录、产品和计费,不直接操作 Bot/Pipeline 等 Core 业务资源。
13.3 WebUI
OSS:
- 首次注册进入唯一 Workspace。
- owner/admin 可邀请成员并管理固定角色。
- 不展示 Workspace 切换器和创建第二 Workspace 的入口。
SaaS:
- 登录先获取 Account 级 Workspace 列表,再显式选择当前 Workspace。
- 当前 Workspace UUID 保存在受控客户端状态中;所有 tenant request 自动附带 selector。
- 切换 Account 或 Workspace 时清理缓存、WebSocket、上传、表单、错误和 optimistic state,不能显示前一租户数据。
- 页面 refresh、新 tab 和邀请跳转恢复同一个经过授权的 Workspace;失效 Membership 不回退到其他 Workspace。
- UI 权限变化必须响应式更新,但 API 仍是最终授权边界。
14. 故障、安全与降级
14.1 Fail-closed 场景
以下情况必须拒绝新的租户业务和副作用:
- Cloud manifest 缺失、签名失败、audience 错误或回滚。
- Account token、Membership、Workspace status 或 execution generation 无效。
- 目录投影未就绪或落后于有效 lease 要求。
- Entitlement 缺失、过期且不在明确 grace 范围内。
- Runtime 控制通道认证失败或实例绑定不一致。
- Plugin nsjail/cgroup hard limit 在 Cloud profile 下不可用。
- Box 的任一硬存储或 namespace capability 无法证明。
- PostgreSQL RLS、runtime role、schema、catalog 或 endpoint 隔离校验失败。
- stdio MCP 在 Cloud profile 下被尝试启用。
不能把上述错误静默降级为 OSS singleton、普通子进程、Chroma、软 quota 或 caller-supplied Workspace。
14.2 撤销语义
- Membership 删除或降权必须影响下一次 HTTP 请求,并使长连接在下一条消息前重新授权。
- Workspace 暂停禁止新交互、自动化工作负载和新副作用;恢复只允许当前 generation。
- entitlement 到期按 capability 明确停止新创建或新执行,不隐式删除已有数据。
- generation 变化使旧 worker、session、callback、cached runtime object 和 outbox publisher 失效。
- 控制面暂时不可达时,只能在有效签名快照和本地投影允许的范围内继续;过期后失败关闭。
14.3 安全清单
- 所有 identifier 使用不可猜 UUID,但不把随机性当成授权。
- 所有 token/secret 只存 hash 或加密值,raw secret 一次展示。
- 日志、trace、metric、cache 和 object key 都包含 Workspace 维度并过滤 secret。
- Provider、Bot、Plugin、MCP 配置的 read response 递归遮蔽 credential。
- Runtime control、debug、registration 和 attachment capability 分离,不能复用万能 secret。
- untrusted code 不访问 Core loopback、数据库、其他 Runtime、宿主文件系统或 metadata endpoint。
- bulk operation、后台扫描和 monitoring 聚合使用显式 tenant/system capability。
- 所有跨 Workspace 运维操作记录 principal、reason、scope、request ID 和结果。
15. 实现状态与 SaaS 激活门禁
15.1 已实现的隔离内核
当前分支已经实现或具备基础的部分包括:
- OSS singleton Workspace、多 Account、Invitation 和固定 RBAC。
- trusted RequestContext、Workspace-scoped repository 和资源所有权检查。
- tenant-aware Plugin SDK protocol 与 Runtime installation binding。
- shared Plugin Runtime / Box Runtime 控制协议和 execution generation fence。
- stdio MCP 独立 gate。
- PostgreSQL shared schema、transaction-local scope、FORCE RLS 与 pgvector adapter。
- Cloud bootstrap 默认不可由普通配置激活,并对缺失安全能力失败关闭。
这些是代码能力边界,不等于完成闭源 SaaS 产品或生产部署验收。
15.2 尚未完成的激活门禁
以下事项完成并取得真实环境证据前,不得宣称 Cloud v2 production-ready:
- 闭源 Control Plane 的全局目录、注册、邀请、订阅、计费、entitlement 签发和签名 manifest bootstrap;横向扩展前 OAuth exchange 与目录投影还必须使用原子共享存储。
- 普通业务写入贯穿 commit 的 generation-aware fence,以及与外部副作用同事务的 business outbox。
- generation cutover 后稳定的 durable object identity 或原子对象引用迁移。
- 所有 tenant-configurable outbound URL 的 SSRF 防护与 tenant-safe egress;Plugin Runtime 还需在真实 Linux/nsjail/cgroup v2 环境验证 namespace、资源限制和文件隔离。
- Plugin Runtime 对意外退出的 enabled worker 实现 completion callback、有界 backoff 和自动恢复,并验证不会形成跨租户重启风暴。
- Plugin installation data 的 production hard disk quota provider,能够在写入边界原子拒绝超额,不能以目录扫描代替。
- Box Runtime 的 production hard quota provider,包括 Workspace、Skill、root/tmp/home 的 byte 与 inode quota;真实部署还必须在启动和重连时通过共享卷 marker challenge。
- PostgreSQL runtime credential 的专用 endpoint 或 HBA/proxy 跨 database 隔离证明、生产 migration/rollback 流程,以及 legacy pgvector migration 失败后精确恢复 RLS/FORCE 并可安全重试的集成证据。
- 闭源目录事件、lease、snapshot、entitlement 和 usage/outbox 的重放、断流与灾难恢复验证。
- 真实浏览器多 Account/RBAC/邀请/刷新场景已完成;仍需生产 Runtime 重启、worker crash、断流、异常回滚和闭源 Control Plane 的 fault-injection 验收。
15.3 有意暂缓的产品决策
- Workspace 创建后的休眠、释放、删除和保留策略。
- Workspace export 与单 Workspace restore。
- 非 Pro Workspace 的 BYOK E2B WebUI。
- 多副本 owner lease 的 store、TTL、fencing token 和转移顺序。
- PostgreSQL shard resolver、在线迁移和 dedicated shard 产品规则。
- artifact/cache 的签名来源、撤销、GC 和磁盘配额机制。
- custom roles、SSO、SCIM 和企业合规能力。
暂缓项不得被实现代码用隐式默认值提前固化。
16. 实施顺序
Phase 0:契约和基线
- 固定术语、RequestContext、角色矩阵、edition policy 和错误语义。
- 建立升级备份、回滚和跨租户负向测试基线。
Phase 1:OSS tenancy kernel
- Account、Workspace、Membership、Invitation。
- singleton bootstrap、多用户邀请、RBAC 和前端权限。
Phase 2:数据与入口隔离
- 为所有资源补充 Workspace scope。
- HTTP、API Key、Bot、Webhook、WebSocket、后台任务和 storage 统一上下文。
- SQLite migration recovery 与 PostgreSQL RLS 集成测试。
Phase 3:Runtime 与 SDK 隔离
- Plugin installation binding、nsjail、资源上限和 artifact replay。
- Box admission、session namespace、skill/attachment 文件边界。
- MCP gate、RAG/vector 与 long-running generation revalidation。
Phase 4:闭源 SaaS 控制面
- signed manifest bootstrap。
- 全局目录、注册、邀请、Subscription、Entitlement 和 Usage ledger。
- projection、lease、outbox、reconciliation 和运维后台。
Phase 5:生产部署激活
- 真实 Linux Plugin/Box hard isolation。
- PostgreSQL credential、migration、backup 和 rollback 验证。
- 完整浏览器/API/Runtime E2E 和故障注入。
- 所有激活门禁通过后才开启多 Workspace Cloud policy。
Phase 6:同逻辑实例内部扩展
- 有容量证据后增加副本、owner lease 和 fencing。
- 有地域、合规或规模证据后增加 shared/dedicated shard。
- 保持外部身份、API 和 Workspace URL 不变。
17. 测试与验收
17.1 数据隔离
- 两个 Workspace 使用相同 resource UUID、name、vector ID 和 cache key,不发生冲突或越权。
- 故意遗漏应用层 Workspace filter 时,PostgreSQL RLS 仍阻止跨租户读写。
- 连接池复用、异常回滚、子任务、后台任务和 transaction pooling 不残留 tenant context。
- 跨 Workspace 猜测返回 404;同租户缺权限返回 403。
17.2 产品行为
- OSS 首个 Account 创建唯一 Workspace;第二个 Account 只能通过邀请加入;创建第二 Workspace 返回 edition error。
- 邀请覆盖有效、已使用、撤销、过期、邮箱不匹配和并发接受。
- owner/admin/developer/operator/viewer 的 API 和 WebUI 权限一致。
- SaaS 普通注册和邀请注册都创建个人 Workspace,但不创建专属部署或 Runtime。
17.3 Runtime
- 两个 Workspace 安装同一已验证 artifact 时只共享只读 code/env,进程、secret、home/tmp/data、日志和 Host API 完全隔离。
- cgroup、rlimit、namespace、egress 和 generation fence 在真实 Linux 环境生效。
- Runtime restart/cache loss 通过 durable desired state 与 binary storage 恢复。
- 两个 Workspace 的 Box session、files、process、skill、attachment 和 quota 完全隔离。
- stdio MCP gate 对 UI、API、bootstrap 和最终 execution 同时生效。
17.4 Control Plane 与故障
- DirectoryEvent 重复、乱序、缺口、snapshot + replay 和过期 lease 均安全。
- Entitlement 旧 revision、签名错误、过期和撤销均失败关闭。
- UsageEvent 重放不重复计费;业务事务回滚不发送副作用。
- Runtime、Core 或 Control Plane 重启不创建重复 Workspace、worker 或 sandbox。
- manifest、数据库安全校验或 hard quota 缺失时实例保持不可激活,而不是静默降级。
17.5 浏览器端到端
真实浏览器至少覆盖:
- clean database 首位 owner 注册与 singleton Workspace bootstrap。
- owner 创建邀请,第二个用户注册/登录并接受。
- 角色在 viewer/operator/developer/admin 间变化时,导航、控制项和 API 结果同步变化。
- Account/Workspace 切换清空前一 scope 状态,refresh 和新 tab 恢复正确 Workspace。
- 第二 Workspace edition limit,以及 invitation used/revoked/expired/email mismatch 的可见错误。
- 直接 API 越权、伪造 selector 和跨租户 UUID 猜测不能绕过 UI。
18. 最终结论
Cloud v2 的产品模型只有一个逻辑 LangBot 实例和实例内多个 Workspace。 当前选择单副本 MVP 是为了减少组件和新增租户成本,不是把单进程假设写进业务身份或协议。 未来需要容量或高可用时,在同一逻辑实例内部增加 Core/Runtime 副本和 PostgreSQL shard, Workspace 的 UUID、权限、数据边界和外部 API 均保持不变。
开源 Core 必须完整实现安全的 Workspace 隔离和 OSS 单 Workspace 多用户;闭源 Control Plane 管理 SaaS 的全局目录、订阅、权益、计费和生命周期。共享可信控制面、连接池、只读 artifact 和数据库组件, 同时让每个不可信插件进程、sandbox、secret、可写文件和 tenant transaction 保持独占边界, 才能在不增加每租户部署的前提下最大化降低新增用户成本。
在闭源控制面、事务 fence/outbox、真实 Runtime hard isolation、Box hard quota 和 PostgreSQL 生产隔离等门禁完成之前, 本架构仍处于隔离内核阶段,不应被描述为可上线的 SaaS 多租户部署。