Files
ZY-Agent/docs/multi-tenant-redesign/README.zh-CN.md
T
1445043649 45efba50e4 docs(db): 补充数据库设计落地版(as-built)并登记进 README
新增 docs/multi-tenant-redesign/01-redesign/database-schema-as-built.zh-CN.md:
对照实现代码(persistence/*/model.py + base.py/engine.py + alembic 0001-0003)
生成的事实参考,补齐之前只有「锁定版」(动手前决策)而缺失的落地 schema 文档。

涵盖:
- 持久化层总览:memory/sqlite/postgres 三后端、create_all vs Alembic、
  Postgres 库自愈、SQLite WAL、JSON ensure_ascii=False、partial index 双 where 兼容
- LangGraph checkpointer/store 表不归 ORM 管的说明
- ER 图(mermaid)+ 10 张表全字段参考(users/workspaces/workspace_memberships/
  threads_meta/runs/run_events/feedback/service_accounts/api_keys/external_users)
- 外键与删除策略矩阵(CASCADE/RESTRICT/SET NULL)
- 迁移历史 0001-0003(含 0002→0003 两段式上线:可空列→回填→锁 NOT NULL)
- 与锁定版的差异(run_events 已确认为 DB 表、runs token 分项列、status 状态机等)

README.zh-CN.md 的「文档总图」与「状态表」登记该文档,并注明
与锁定版冲突时以落地版为准。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 22:55:01 +08:00

322 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 多租户改造 · 总览与汇总索引
> 写于 2026-05-10。把 7 份 ADR + 2 份 spike/审计 + 4 份 rollout / schema 文档,按"ADR 状态 + 5 阶段(Stage 0–4)的业务目标 / 技术路径 / 验证方式"重新串一遍,让团队从任何角度切入都能找到对应位置。
>
> **范围**:仅汇总与导航,不引入新决策。具体决策正文在各自的 ADR / rollout 文档里。
>
> **目标客户画像**(来自 [phased-rollout-by-scale §0](./02-rollout/phased-rollout-by-scale.zh-CN.md)):以个人用户为主、少量小团队;**统一只有 workspace 概念**(个人 = 1 人 workspace);**中心化 SaaS 主线**schema 兼容 on-prem,按合同启用);**Freemium**DeerFlow 付 LLM 账单)。
---
## 0. 文档总图
```
docs/multi-tenant-redesign/
├── README.zh-CN.md ← 本文档(入口)
├── 00-current-state/
│ └── architecture-overview.zh-CN.md 现状架构鸟瞰
├── 01-redesign/ 决策(ADR)+ 锁定文档
│ ├── adr-001-data-isolation 数据隔离(行级 + RLS)
│ ├── adr-002-sandbox-isolation 沙箱隔离(K8s + gVisor
│ ├── adr-003-llm-key-billing LLM Key 与计费(混合 BYO
│ ├── adr-004-tenant-rbac 租户 RBACowner/admin/member
│ ├── adr-005-storage-topology 存储拓扑(DB + S3 + emptyDir
│ ├── adr-006-runtime-channel-tenancy 运行时夹层 + IM 渠道
│ ├── adr-007-routing-frontend URL / Cookie / 前端
│ ├── adr-spike-langgraph-postgres spikeLangGraph PG 注入能力
│ ├── adr-vs-code-audit 审计:ADR vs 现状代码
│ ├── multi-tenant-phase-0-plan Phase-0 时间盒 / 产出物
│ ├── workspace-schema-design **Stage 0 schema 锁定版**(不可逆决策点)
│ └── database-schema-as-built **数据库设计落地版**(对照实现代码的事实参考)
└── 02-rollout/ 落地路线 + 集成轨道
├── phased-rollout-by-scale **Stage 04 主线** 路线图
├── stage-0-code-map Stage 0 现状代码地图(行号锚点)
└── headless-api-track 业务系统集成轨道(Pattern A / B
```
---
## 1. ADR 与配套文档状态表
| # | 文档 | 状态 | 最近修订 | 核心决策摘要 |
|---|---|---|---|---|
| **ADR-001** | [数据隔离](./01-redesign/adr-001-data-isolation.zh-CN.md) | 草稿 · 据 spike 修订 | 2026-05-09 | 行级 `workspace_id` + Postgres RLS(仅 DeerFlow 自有表);LangGraph 表走应用层强校验 + `UNIQUE(wid, thread_id)` 兜底 |
| **ADR-002** | [沙箱隔离](./01-redesign/adr-002-sandbox-isolation.zh-CN.md) | 草稿 | 2026-05-08 | K8s namespace + gVisor + NetworkPolicy 默认禁出网;premium 切 Kata-Firecracker。**Stage 1 仅做 AioSandbox 加固,K8s 推迟到 Stage 3** |
| **ADR-003** | [LLM Key & 计费](./01-redesign/adr-003-llm-key-billing.zh-CN.md) | 草稿 · 据审计修订 §4.2/§4.3/§4.4.2 | 2026-05-09 | 混合 BYOFree/Pro 用平台 key + quotaEnterprise BYO;悲观预扣防"幽灵 token"Memory/Title/Summarization 内部 LLM 全计入 workspace |
| **ADR-004** | [租户 RBAC](./01-redesign/adr-004-tenant-rbac.zh-CN.md) | 草稿 | 2026-05-08 | 二级 RBACowner/admin/member);JWT 带 role + 30s LRU cache + 敏感操作 `strict=True` 必查 DB`token_version` bump 触发失效 |
| **ADR-005** | [存储拓扑](./01-redesign/adr-005-storage-topology.zh-CN.md) | 草稿 | 2026-05-08 | 三层:Postgres(结构化)+ S3(大对象 + presigned+ emptyDir(临时);沙箱 pod 真正无状态 |
| **ADR-006** | [运行时夹层 + 渠道](./01-redesign/adr-006-runtime-channel-tenancy.zh-CN.md) | 草稿 · 据 spike + 审计修订 | 2026-05-09 | LangGraph 表走应用层校验;MCP cache per-workspaceOAuth token 入 KMS DBIM 渠道加 `channel_bindings(workspace_id)` |
| **ADR-007** | [URL / 前端](./01-redesign/adr-007-routing-frontend.zh-CN.md) | 草稿 · Better Auth 假设作废 | 2026-05-09 | path-based slug `/{slug}/...`;扩现有自签 JWT 加 `wid/role`,不引入 Better Auth;切换 workspace 硬刷新 |
| spike | [LangGraph PG 注入](./01-redesign/adr-spike-langgraph-postgres.zh-CN.md) | 已结论 | 2026-05-09 | `langgraph-checkpoint-postgres==3.0.5` **不存在 connection_factory**;改走应用层强校验 + 自有表 RLS 的两层模型 |
| 审计 | [ADR vs 代码](./01-redesign/adr-vs-code-audit.zh-CN.md) | 已结论 | 2026-05-09 | 代码库 0 处 `tenant`Better Auth 不存在;ObjectStorage / KMS / Postgres 测试夹具全缺;底座先行 §3.5 |
| 锁定 | [workspace-schema-design](./01-redesign/workspace-schema-design.zh-CN.md) | **Stage 0 锁定版** | 2026-05-10 | `workspace_id` 命名 + 7 项不可逆决策;Stage 0 PR1 动手前必读 |
| 参考 | [database-schema-as-built](./01-redesign/database-schema-as-built.zh-CN.md) | **落地版(as-built** | 2026-06-27 | 对照实现代码的 10 张表全字段 / 外键 / 索引 / 迁移参考;与锁定版冲突以本文为准 |
| 计划 | [phase-0-plan](./01-redesign/multi-tenant-phase-0-plan.zh-CN.md) | 计划 | 2026-05-09 | Phase-0 时间盒 3 周;含底座先行(§3.5) |
| 路线 | [phased-rollout-by-scale](./02-rollout/phased-rollout-by-scale.zh-CN.md) | **当前主线路线图** | 2026-05-09 | Stage 04 + 触发/退出/时间盒/Go-No-Go |
| 锚点 | [stage-0-code-map](./02-rollout/stage-0-code-map.zh-CN.md) | Stage 0 用 | 2026-05-09 | 当前代码文件:行号锚点 + Stage 0 改动落点 |
| 集成 | [headless-api-track](./02-rollout/headless-api-track.zh-CN.md) | Stage 1 内并行轨道 | 2026-05-10 | API key + service account + Pattern A/B(不做嵌入式 widget |
---
## 2. Stage 04 速览矩阵
| Stage | 触发 | 退出 | 时间盒 | 主要 ADR 章节 |
|---|---|---|---|---|
| **0** | 现在 / 准备开第一个付费客户 | 外部用户能登入、看到自己 workspace、隔离干净;**生产已跑在 Postgres 上** | 45 周(含 Postgres 切换 + testcontainers| ADR-001 §4.1.2 / ADR-001 §4.4Postgres 切换)/ ADR-004 §1-§3owner-only 简化)/ ADR-007 §1-§5 / workspace-schema-design 全篇 |
| **1** | 首批付费 (1050 / 5002k free) + 1-2 业务系统集成 | 可放心曝光 + 业务系统 go-live | 813 周(双轨并行;Postgres 已在 Stage 0 切完)| ADR-001 §4.1(应用层校验完整)+ ADR-002 §3 轻量 + ADR-003 §4.3-§4.4 + ADR-007 §6-§8 + headless-api 全篇 |
| **2** | 100500 付费 / 5k20k 用户 | 架构能撑用户 ×10 | 1016 周 | ADR-001 §4.2DeerFlow 表 RLS+ ADR-003 §4.1-§4.2KMS+ ADR-004 §5(完整 RBAC+ ADR-005 §1-§5 + ADR-006 §2.2/§2.5/§2.6 |
| **3** | 1k+ 付费 / 50k+ 用户 **或** 安全/成本事故 | 撑到 enterprise 销售前夕 | 1626 周 | ADR-002 §1-§5K8s 完整)+ ADR-003 §4.6BYO+ ADR-006 §2.4prewarm 池)+ ADR-007 §9custom domain 预留) |
| **4** | 单 enterprise 合同(合规 / SSO / 自定义域名) | 长期持续 | 单客户 4–8 周 | ADR-001 §6per-tenant DB+ ADR-002 §5gVisor+ ADR-007 §8 SSO 段 + §9 |
---
## 3. 各阶段详细:业务目标 / 技术路径 / 验证方式
### Stage 0 · workspace 模型立起来 + Postgres 切换 + auth 收紧
**业务目标**
- 把 workspace 概念落到 schema 层、auth 层、入口路由层,给"开第一个付费客户"准备好底座
- **生产 backend 切到 Postgres**——Stage 0 没有生产数据,迁移阻力最小;省 Stage 1 重 ALTER 一遍的返工
- 不追求真隔离(无 RLS、无 K8s、无 KMS),追求**模型立得住**——后续每个 Stage 加东西都不需要重写 Stage 0 的产物
**技术路径**(按 PR 拆分)
1. **Postgres 接入 + testcontainers**docker-compose 加 PG service、`make doctor` / CI 兼容;testcontainers 集成到 backend 测试套;现有 SQLite dev 数据导入(如有)
2. **将默认 backend 切到 Postgres**`make setup` / `make dev` / `.env.example` 默认指向 PG;SQLite 保留为可选 dev 兜底
3. 新建 `workspaces` + `workspace_memberships` 表 + 仓储([workspace-schema-design §2.1-§2.2](./01-redesign/workspace-schema-design.zh-CN.md)
4. 注册 / `/auth/initialize` 改造:每个新用户自动建 1 人 workspaceowner=自己);JWT 扩 `wid` + `role`owner-only 简化)
5. 现有 4 张表 ALTER 加 `workspace_id` 列(直接在 Postgres 上加,先 nullable+ 数据回填脚本("legacy_workspace")→ 改 NOT NULL
6. 入口路由 `(workspace_id, thread_id)` 强校验 — `threads.py` + `thread_runs.py`ADR-001 §4.1.2
7. CI boundary 测试:禁止任何路径绕过入口直连 LangGraph saverADR-006 §2.1
8. Stage 0 末追加:`service_accounts` / `api_keys` / `external_users` schema only(不接路径,为 Stage 1 准备)
**验证方式**
- 单测:`test_workspace_repo.py` / `test_workspace_membership_repo.py`partial unique、CASCADE、slug 黑名单)
- 集成:注册新用户 → DB 中可见 1 个 workspace + 1 条 owner membership + JWT cookie 含 `wid`
- 回归:Stage 0 部署到生产 ≥ 2 周,无 workspace 隔离 bug 报告;Postgres 上稳定运行 ≥ 2 周,无 schema / 性能 regression
- CI boundary`test_langgraph_access_boundary.py` 静态扫描不能命中绕过路径
- testcontainers 夹具:CI 跑通至少 1 个 Postgres 集成测试模板(policy Stage 2 才启用,但夹具 Stage 0 就位)
---
### Stage 1 · 第一批付费客户 + 业务系统集成(双轨并行)
**业务目标**
- **付费 SaaS 轨道**:上线 quota + 计费 + 基础沙箱收紧,让"开放注册"不会被滥用刷爆 LLM 账单
- **Headless API 轨道**:让 1-2 个业务系统能用 API key 调通核心 endpoint go-live,含浏览器直连场景(streaming 友好)
**技术路径**
**轨道 A · 付费 SaaS**Postgres 已在 Stage 0 切完,本轨道直接从 quota 起):
1. `workspace_quotas` / `workspace_usage_daily` 表 + 仓储(ADR-003 §4.3
2. `TokenUsageMiddleware` 升级为持久化 + 4 类 `usage_category`ADR-003 §4.4 + ADR-006 §2.5
3. `QuotaMiddleware` 加入中间件链 + 悲观预扣防幽灵 tokenADR-003 §4.4.1
4. Stripe webhook + 订阅状态同步到 `workspace_quotas.plan`
5. AioSandbox egress 白名单 + cgroup CPU/memory 限额(ADR-002 §3 轻量版,**不上 K8s**
6. 基础监控:per-workspace token 用量、quota 命中率、异常告警
**轨道 B · Headless API Pattern A**(与 A 并行;无前置依赖):
1-10. service_accounts / api_keys / external_users 仓储 → APIKeyAuthBackend 双路径 → CSRF skip on bearer → `/api/v1/` 切换 → external_user_id 透传 → identity_mode 三态 → `@require_permission` 升级 → 基础 rate limit → API key 管理 CLI/UI → idempotency keys(详 [headless-api §6 Stage 1 PR 顺序](./02-rollout/headless-api-track.zh-CN.md#6-与-stage-1-的整合)
**轨道 C · Headless API Pattern B**(依赖轨道 B 的 1-7Stage 1 末 1-2 周):
1-5. `workspaces.allowed_origins` 列 → `WorkspaceAwareCORSMiddleware``POST /api/v1/auth/exchange-token``ServiceTokenAuthBackend` → SSE 跨域 streaming 验证 + 业务方接入示例
**验证方式**
- 单测:quota 中间件硬限/软限/预扣/释放;APIKey 哈希存储;ServiceTokenPayload 签发与验证
- 集成:`test_billing_stream_abort.py`(客户端断流仍记 token);2 个 workspace 互调 thread 必 404
- 端到端:业务系统 demo 应用用 API key 跑通 thread 创建 / SSE / external_user_id 透传
- 业务事实:1-2 个业务系统集成 go-live 并稳定运行 ≥ 1 个月;月活付费 ≥ 50 或免费 ≥ 1k;出现一次"差点超额"事件证明 quota gate 在工作
---
### Stage 2 · 增长期,安全与隔离深化
**业务目标**
- 把 Stage 1 的"应用层兜底"升级为"DB 层兜底"——RLS、KMS、ObjectStorage 三大底座落地
- 团队 workspace 真正可用(invitation + 完整 RBAC
- 内部 LLM 计费透明化、per-user skill 覆盖支持小团队个性化
**技术路径**PR 顺序)
1. testcontainers + Postgres CI 跑通(phase-0 §3.5 底座之一)
2. ObjectStorage Protocol + LocalObjectStorage + 端到端打通(ADR-005 §4-§5
3. KMS 抽象 + AWS/阿里云 KMS 实现 + 已有 secret 灰度迁移(ADR-003 §4.1
4. **DeerFlow 自有表启用 RLS**testcontainers 验证后上生产;ADR-001 §4.2
5. S3ObjectStorage 实现 + 上传/产物迁 S3
6. 多档付费(Free/Pro/Team+ invitation 流程 + role 扩到 owner/admin/member
7. `WorkspaceMCPCache` + OAuth token 落 KMS 加密 DBADR-006 §2.2
8. per-user skill 覆盖(`user_skill_overrides`+ per-user skill configKMS 加密;ADR-005 §5.4 扩展)
9. 内部 LLM 计费分类(Memory/Title/Summarization usage_categoryADR-006 §2.5
10. Webhook outboundStage 1 推迟过来;headless-api §1+ 分维度 rate limit(引入 Redis
11. 基础 audit log(写业务 DBStage 3 才拆)
**验证方式**
- RLS 冒烟:testcontainers 起 Postgres,跨 workspace SELECT 必返空;跨 workspace UPDATE 必拒绝
- KMSsecret 写入后 DB 列只见密文;rotate 流程不破坏旧密文解密
- 计费分项:UI 报表能区分 main / memory / title / summarizationBYO key 走自己额度
- 业务事实:跨 workspace 数据访问尝试 0 次(哪怕日志里);客户开始问 BYO key
---
### Stage 3 · 成熟期,K8s 隔离 + BYO
**业务目标**
- 沙箱从"AioSandbox 加固"升级到"K8s + namespace + NetworkPolicy",杜绝单进程资源争用
- BYO LLM key 作为付费档福利交付
- 拆分 audit DB、加跨 region 备份,为 enterprise 销售铺路
**技术路径**
1. K8s 集群部署 + per-workspace namespace + ResourceQuota / LimitRange + NetworkPolicy 默认禁出网(ADR-002 §5
2. `K8sSandboxProvider` 全新建 + Cosign 镜像签名 + Pod Security Standard restrictedADR-002 §5.1-§5.5
3. per-workspace prewarm 池 controller,按 plan 大小(ADR-006 §2.4
4. BYO LLM key 路径:`workspace_secrets` 解密 → `create_chat_model()` 优先用 tenant keyADR-003 §4.2 + §4.6
5. presigned URL 全量启用 + S3 lifecycle(按 plan 设保留期)
6. audit DB 拆分(独立连接池或独立实例;ADR-006 §2.4 脚注)
7. 跨 region 备份 / DRRTO ≤ 4h
8. 完整监控栈:Grafana + Prometheus + APM + per-workspace SLA
**验证方式**
- 安全:渗透测试容器逃逸场景(gVisor 启用前后对比);NetworkPolicy 阻断 169.254.169.254 / 内网 IP
- 性能:Pod 冷启动 P50 < 2s / P99 < 5sprewarm 命中率 > 80%
- 业务:BYO 客户 ≥ 5 个;K8s 切换零数据丢失;audit DB 写入与业务 DB 解耦验证
---
### Stage 4 · 企业化,按需开启
**业务目标**
- 单客户合同驱动,不为"万一"提前投资
- SSO / 自定义域名 / per-tenant DB / gVisor / 合规审计——按客户付费决定做哪几样
**技术路径**(按合同选做)
- **SSOSAML/OIDC**:复用现有 oauth_provider 字段;新建 `workspace_sso_configs`IdP 用户/组映射到 workspace_membershipsADR-007 §8 SSO 段)
- **自定义域名**`workspaces.custom_domain` 列 + ACME 动态签证 + nginx vhost 路由(ADR-007 §9
- **物理数据隔离**:仅该客户切 per-tenant DBADR-001 §6 推翻条件)
- **私有部署**:打 enterprise tier docker 镜像 + 部署文档;放弃中心化运维优势
- **gVisor / Kata 切换**K8s 切对应 RuntimeClassADR-002 §5
- **合规审计报告(SOC2/ISO**:强化 audit log 留存 + 评估机构对接
**验证方式**
- 合同里写明的 SLA / 合规条款逐条验收
- 安全审计 / 渗透测试报告(如客户要求)
- SSO IdP 端到端登录测试
---
## 4. Stage ↔ ADR 章节细粒度对照
| Stage | ADR-001 | ADR-002 | ADR-003 | ADR-004 | ADR-005 | ADR-006 | ADR-007 | headless-api |
|---|---|---|---|---|---|---|---|---|
| 0 | §4.1.2 入口校验 + §4.4 Postgres 切换 | — | — | §1-§3 owner-only | — | — | §1-§5(无 slug 路由可暂缓) | §2 schema only |
| 1 | §4.1 应用层校验完整版(**不含 RLS**Postgres 已 Stage 0 切完)| §3 轻量(egress + cgroup | §4.3-§4.4 quota + 持久化 + 预扣 | — | — | §2.5 usage_category | §6-§8 slug + JWT 扩字段 | §2-§5 全(Pattern A+ §3.5 全(Pattern B|
| 2 | §4.2 DeerFlow 表 RLS | — | §4.1-§4.2 KMS + create_chat_model 改造 | §5 完整 RBAC + invitation | §1-§5 ObjectStorage 完整 | §2.2 / §2.5 / §2.6 | — | §1 Webhook outbound |
| 3 | — | §1-§5 K8s 完整 | §4.6 BYO | — | §5 第 2 阶段(presigned + lifecycle| §2.4 prewarm 池 | §9 custom domain 预留 | — |
| 4 | §6 per-tenant DB | §5 gVisor / Kata | — | §5.7 SSO/SCIM | — | — | §8 SSO 段 + §9 落地 | — |
---
## 5. 不可逆决策一览(按 Stage 集中)
| Stage | 决策 | 文档锚点 | 反悔代价 |
|---|---|---|---|
| 0 | **Postgres 切换**dev + 生产)| [phased-rollout Stage 0](./02-rollout/phased-rollout-by-scale.zh-CN.md#stage-0--workspace-模型立起来--postgres-切换--auth-收紧) + [phase-0-plan §3.5](./01-redesign/multi-tenant-phase-0-plan.zh-CN.md#35-底座先行phase-0-之前--并行的基础设施) | Stage 0 选这个时机:没有生产数据,迁移阻力最小;切完不回头 |
| 0 | `workspace_id` 列加到所有业务表(直接 Postgres) | [workspace-schema-design §3](./01-redesign/workspace-schema-design.zh-CN.md#3-alter-现有表) | 漏一张 → Stage 1 补;不再走 SQLite → Postgres 二次迁移 |
| 0 | `workspaces` 表字段(id 类型 / slug 字符集 / owner_id 冗余) | [workspace-schema-design §5](./01-redesign/workspace-schema-design.zh-CN.md#5-不可逆决策清单) | 7 项已锁定;任何一项改主意 → revert PR1 重写 |
| 0 | JWT TokenPayload 字段集 `{sub, wid, role, exp, iat, ver}` | [workspace-schema-design §4](./01-redesign/workspace-schema-design.zh-CN.md#4-jwt-tokenpayload--一次到位的字段集) | 加新字段 → bump `token_version` 全用户重登;Stage 0 一次性加齐省一次 churn |
| 0 | 文件系统路径形态 `workspaces/{wid}/threads/{tid}/...` | [stage-0-code-map §4](./02-rollout/stage-0-code-map.zh-CN.md#4-threaddatamiddleware--路径系统) | 改了所有用户产物 URL 失效 |
| 0 | API Key 格式(`dfk_live_*` / `dfk_test_*`+ `service_accounts` 不跨 workspace | [headless-api §8](./02-rollout/headless-api-track.zh-CN.md#8-不可逆决策动手前想清楚) | 业务系统接入后改格式所有 key 失效 |
| 1 | `/api/v1/` mount prefix + deprecation 时间 | [headless-api §4](./02-rollout/headless-api-track.zh-CN.md#4-核心设计api-版本化) | 业务系统接了之后改 prefix 全部联调 |
| 1 | identity_mode 三态语义(collapsed / external / both | [headless-api §3](./02-rollout/headless-api-track.zh-CN.md#3-核心设计两种身份模式) | 改语义所有业务系统集成重测 |
| 1 | memory 隔离粒度(SA 共享 vs per external_user | 同上 | 客户用上后迁移 memory 数据极麻烦 |
| 2 | ObjectStorage prefix 形态 `workspaces/{wid}/...` | [ADR-005 §2.1](./01-redesign/adr-005-storage-topology.zh-CN.md#21-各类数据的归属) | 改了所有用户产物 URL 失效 |
| 3 | K8s namespace 命名规则(`ws-{wid}` vs `tenant-{wid}` | [ADR-002 §5.2](./01-redesign/adr-002-sandbox-isolation.zh-CN.md#52-k8s-资源每租户-namespace-一份)(落代码读 `ws-{wid}` | 改了所有 NetworkPolicy / RBAC / 监控 dashboard |
---
## 6. 用语映射速查
> ADR 与 02-rollout 系列因写作时序不同,存在两组用语并行。这里给一张一次性映射表,避免读不同文档时反复对照。
| ADR 用语 | 落代码 / 02-rollout 用语 | 备注 |
|---|---|---|
| `tenant_id`(数据库列、Python 变量) | `workspace_id` | workspace-schema-design §1 锁定 |
| `tenants` 表 | `workspaces` 表 | 同上 |
| `tenant_memberships` | `workspace_memberships` | 同上 |
| `tenant_secrets` | `workspace_secrets` | 同上 |
| `tenant_quotas` / `tenant_usage_daily` | `workspace_quotas` / `workspace_usage_daily` | 同上 |
| `tenant_skill_state` / `tenant_mcp_configs` | `workspace_skill_state` / `workspace_mcp_configs` | 同上 |
| JWT `tid` claim | JWT `wid` claim | workspace-schema-design §4 锁定 |
| K8s `tenant-{tenant_id}` namespace | `ws-{workspace_id}` | ADR-002 §5.2 → 落代码读 |
| ObjectStorage `tenants/{tid}/...` prefix | `workspaces/{wid}/...` | ADR-005 §2.1 → 落代码读 |
| `TenantMCPCache` 类名 | `WorkspaceMCPCache` | ADR-006 §2.2 → 落代码读 |
| ADR 用语 "v1 / v2 路线图" | rollout Stage 04 | "v1" ≈ Stage 0+1"v2" ≈ Stage 2+;具体见每条决策的 Stage 标注 |
| ADR-005 §5 "第 1 阶段 / 第 2 阶段" | rollout Stage 2 / Stage 3 | ADR-005 §5 已加映射注 |
| ADR-006 §3 "约 14 人周" | 对应 rollout Stage 2 必做项里的 §2.2/§2.5/§2.6 | — |
---
## 7. 阅读路径建议
**第一次进项目(30 min**
1. 本 README
2. [00-current-state/architecture-overview](./00-current-state/architecture-overview.zh-CN.md) — 现状是什么样的
3. [phased-rollout-by-scale](./02-rollout/phased-rollout-by-scale.zh-CN.md) §0 + §总览 + §Stage 0 — 现在在哪、下一步做什么
**准备动手做 Stage 0(半天)**
1. [workspace-schema-design](./01-redesign/workspace-schema-design.zh-CN.md) **全文** — 不可逆决策、PR 拆分
2. [stage-0-code-map](./02-rollout/stage-0-code-map.zh-CN.md) **全文** — 当前代码锚点
3. [ADR-001 §4.1.2](./01-redesign/adr-001-data-isolation.zh-CN.md) + [ADR-007 §8](./01-redesign/adr-007-routing-frontend.zh-CN.md)
4. [ADR-006 §2.1](./01-redesign/adr-006-runtime-channel-tenancy.zh-CN.md) + [adr-spike-langgraph-postgres](./01-redesign/adr-spike-langgraph-postgres.zh-CN.md) — 为什么 LangGraph 表不挂 RLS
**准备动手做 Stage 1(一天)**
1. [phased-rollout Stage 1](./02-rollout/phased-rollout-by-scale.zh-CN.md) — 双轨并行
2. [headless-api-track](./02-rollout/headless-api-track.zh-CN.md) **全文** — Pattern A/B 完整设计
3. [ADR-003 §4.3-§4.4](./01-redesign/adr-003-llm-key-billing.zh-CN.md) — quota + 悲观预扣
4. [ADR-002 §3](./01-redesign/adr-002-sandbox-isolation.zh-CN.md) — Stage 1 用 §3 轻量版(**不**读 §5 K8s 完整版)
**做安全/合规评审**
1. ADR-001 / ADR-002 / ADR-003 §4.6BYO/ ADR-004 §5.4strict 装饰器)
2. [adr-vs-code-audit](./01-redesign/adr-vs-code-audit.zh-CN.md) cross-cutting risks 全部
3. headless-api §3.5 + §8(短期 JWT TTL / Token revoke 策略)
**做架构评审**
1. ADR-001 全 + ADR-005 全 + ADR-006 全
2. spike + audit
3. workspace-schema-design §5 不可逆清单
---
## 8. 常见问题(FAQ
**QPostgres 切换在哪个 Stage**
A**Stage 0**。原稿放 Stage 1,但 Stage 0 已经要 ALTER 4 张表加 `workspace_id`,先 SQLite 加列再 Stage 1 重 ALTER 是纯返工;Stage 0 没有生产数据,迁移阻力最小,且 phase-0 §3.5 早已把 Postgres testcontainers 列为底座。详见 [phased-rollout Stage 0](./02-rollout/phased-rollout-by-scale.zh-CN.md#stage-0--workspace-模型立起来--postgres-切换--auth-收紧) + [phase-0-plan §3.5](./01-redesign/multi-tenant-phase-0-plan.zh-CN.md#35-底座先行phase-0-之前--并行的基础设施)。SQLite 仅保留为可选 dev 兜底。
**QADR 写 `tenant_id`,代码写 `workspace_id`,到底哪个是对的?**
A:代码以 `workspace_id` 为准([workspace-schema-design §1](./01-redesign/workspace-schema-design.zh-CN.md) 锁定)。ADR 不重命名是为了节省成本,每份 ADR 顶部已加交叉提示。
**QADR-002 写要上 K8s + gVisor,是不是 Stage 1 就要做?**
A:不是。Stage 1 只做 ADR-002 §3 的"AioSandbox 出网白名单 + cgroup 限额"。K8s + gVisor 的完整方案推迟到 Stage 3。ADR-002 §1 已加分期落地提示。
**QLangGraph 表为什么不挂 RLS**
Aspike 验证 `langgraph-checkpoint-postgres==3.0.5` 不存在 `connection_factory`,无法注入 `SET LOCAL app.tenant_id`。改走应用层强校验(`threads.py` + `thread_runs.py` 入口)+ `threads_meta` `UNIQUE(workspace_id, thread_id)` 兜底。详见 [spike 报告](./01-redesign/adr-spike-langgraph-postgres.zh-CN.md) §3.3 / [ADR-001 §4.1.1](./01-redesign/adr-001-data-isolation.zh-CN.md)。
**Q:是否引入 Better Auth**
A:不引入。审计发现前端实际不用 Better Auth;扩现有 `app/gateway/auth/jwt.py``wid` + `role` 字段比引入框架的破坏面小得多。详见 [ADR-007 §8](./01-redesign/adr-007-routing-frontend.zh-CN.md)。
**Q:业务系统集成走哪种 pattern?**
A:默认 Pattern A(业务 backend 代理,长期 API key);自研 web 页面 + streaming 延迟敏感的走 Pattern B(短期 JWT,浏览器直连)。**不做 Pattern C 嵌入式 widget**。详见 [headless-api §0 速览](./02-rollout/headless-api-track.zh-CN.md#集成-pattern-速览)。
**Qon-prem 怎么定位?**
ASaaS 是产品主线;Stage 0 的 schema 设计同时兼容 on-prem`workspaces.id` 1:1 对应 self-host 安装),按 enterprise 客户合同启用,不作为并行产品线投入。详见 [phased-rollout §0](./02-rollout/phased-rollout-by-scale.zh-CN.md) + [headless-api §7](./02-rollout/headless-api-track.zh-CN.md#7-saas-vs-on-prem-差异saas-是主线)。
---
## 9. 推翻条件(什么会让整个分期方案重排)
来自 [phased-rollout §推翻条件](./02-rollout/phased-rollout-by-scale.zh-CN.md#推翻条件)
- **目标客户画像突变**:拿到 enterprise 合同要求 SSO + 自定义域名 → Stage 4 部分提前到 Stage 2
- **出现安全事故**:跨 workspace 泄露 / sandbox 逃逸 → 跳过未启动 Stage,直接做 Stage 3 的 K8s + RLS
- **付费转化远不及预期**:Stage 1 上线 6 个月付费 < 10 → 重评 freemium 模型,可能不需要走完 Stage 2/3
- **LLM 价格大跌 / 自部署模型成熟**:成本控制优先级下降 → quota 与 BYO 可简化
> 单条 ADR 的"推翻条件"在每份 ADR 末尾,触发时只重排该 ADR 涉及的 Stage。