> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# DB Redesign 需求分析(场景清单 + 查询清单)

> 6 阶段设计流程(需求分析 → 概念设计 → 选型 → 逻辑设计 → 物理设计 → 实现调优)的**第 1 阶段**产出。来源:2026-07-02 会议 transcript、[`entity-relationship-map.md`](/system-design/multi-tenant/entity-relationship-map.md) / [`why-tenant.md`](/system-design/multi-tenant/why-tenant.md) / [`v1-gaps.md`](/system-design/multi-tenant/v1-gaps.md)、studio-api 代码实扫(apps/api 全部读路径)、test 库实测量级。
> 状态:DRAFT — 待 Max/Peter 确认频率与补充遗漏场景;§C 的 4 个问题正在用 brainstorming 流程逐个敲定。

## A0. 能力需求总表(需求的锚点:一套系统的两个面)

retaintive 是**一套系统的两个面**,谁也不能缺:

- **Revenue 引擎**(帮客户从电话/lead 里找到钱):信号进入 → AI 理解 → 派任务 → 执行 → 度量 → 变现放大
- **管理面**(我们经营这套 SaaS):onboarding → 身份权限 → 计费套餐 → 客户生命周期 → 内部运营 → 合规

两面咬合:Revenue 引擎的每行数据都 stamp 着管理面定义的边界(tenant / store / person);管理面的每次变更(挪店、转让、churn)都不许弄脏引擎的历史。**数据地基必须同时撑住两面——只修管理面是为架构而架构,只做引擎功能就是回到现在这个状态。**

判定口径:✅ 骨架已撑住(只差机制收口)/ ⚠️ 方向对但缺前置 / ❌ 模型缺概念。

### Revenue 引擎(R 侧)

| #  | 能力    | 现在 → 未来                                    | 撑得住? | 差什么                                                               |
| -- | ----- | ------------------------------------------ | :--: | ----------------------------------------------------------------- |
| R1 | 信号进入  | 电话/SMS/lead email → 全渠道(email/IG/web chat) |  ⚠️  | 多渠道身份没地方挂——person 层(顾客身份从"某店某号码"升级成"人")                           |
| R2 | AI 理解 | 转录、单通/客户级分析、身份裁决(system-worldview)         |   ✅  | pipeline 已跑;历史 backfill 按当前映射误 stamp 要修(S22)                      |
| R3 | 任务派发  | 9 类任务;57 golden cases 已体系化,96.5% 准确率       |   ✅  | lead↔task 桥接补齐中(会上 Max 认领)                                        |
| R4 | 执行    | 员工 today → AI agent(Vapi 语音/SMS 助手)future  |  ⚠️  | 记账(timeline)/policy guard 已有;**DNC/consent person 层是 AI 触达的合规前置** |
| R5 | 度量复盘  | 老板一眼看清钱在哪漏(dashboard/funnel/trend)         |   ❌  | **指标语义层**:同名指标 3 套口径("intro booked" 三个定义),一个指标必须一个定义              |
| R6 | 变现放大  | AI daily report、收购尽调产品、对外 API、coaching 资产化 |   ❌  | R5 是前置;尽调需要"评估型访问"概念;资产化和尽调都需要**历史不可被改写**(temporal 归属)            |

### 管理面(M 侧)

| #  | 能力         | 现在 → 未来                                                            | 撑得住? | 差什么                                                                                                             |
| -- | ---------- | ------------------------------------------------------------------ | :--: | --------------------------------------------------------------------------------------------------------------- |
| M1 | Onboarding | admin-led(signup→连 RC→建店→建 tenant)→ self-serve;评估型 onboarding(尽调用) |  ⚠️  | 设计已有([tenant-onboarding.md](/system-design/multi-tenant/tenant-onboarding.md));"onboarding 不建 tenant"待落地;评估型无模型 |
| M2 | 身份与权限      | user / tenant member / store grants;离职、转让                          |  ⚠️  | role 双轨要统一(D2);转让撞 one-active-tenant 约束(D1);OAuth 连接挂个人,人走管道断(S15)                                              |
| M3 | 计费与套餐      | tier / quota / Stripe;按店计费、超额加钱(Peter 的 basic/plus 愿景)             |   ✅  | 模型预留正确(全挂 tenant),缺 quota enforcement——机制活,不动模型                                                                 |
| M4 | 客户生命周期     | provisioning→active→suspended→churned;店的买卖 / M\&A                  |   ❌  | status 无语义(3 个 tenant 全卡 provisioning);store 无 archive/lineage,转让语义未定义                                          |
| M5 | 内部运营       | control-plane-admin、对账、告警、audit                                    |  ⚠️  | admin 工具已有;对账 job 与 NULL 率告警缺([v1-gaps](/system-design/multi-tenant/v1-gaps.md) 缺口 2-4)                         |
| M6 | 合规         | DNC/consent;审计;future 航空垂直(企业级,PCI/SOC2,单租户搬 pod)                  |   ❌  | person 级 DNC 缺;audit 有底子(config\_change\_log/timeline);航空垂直另需 temporal 证据链 + DB placement(deferred 有触发条件)       |

### 判定汇总:骨架合理,五个概念级的洞

tenant/store/事件表三层骨架不用推倒。但 5 个"模型缺概念"的洞,不补则上表一半撑不住:

| 洞                                                  | 卡住的能力                                                                 | 性质                                                             |
| -------------------------------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------- |
| ① 指标语义层(一个指标一个定义)                                  | R5 → R6 全链                                                            | **杠杆最高、工程量最小**(定义问题,非重构)                                       |
| ② temporal 归属 + 搬家/纠错二分(phone→store)               | R6 尽调、M4 M\&A、航空证据链、Peter P2                                          | 概念缺失,ER map §四 #1 的目标策略                                        |
| ③ person 层(顾客 = 人,不是某店某号码)                         | R1 全渠道、R4 AI 触达合规                                                     | 概念缺失(D4)                                                       |
| ④ tenant 模型两个口子(D1 多 membership、D5 评估型访问)          | R6 尽调产品线、M2 转让、BPO 商业模式                                               | 决策待拍(D1/D5)                                                    |
| ⑤ location 生命周期(店的身份连续性:archived/reattach/lineage) | M4 店买卖与 M\&A、Peter P3;根在 `rc_stores` unique key 含 user\_id+connection | 概念缺失,独立于 ②——phone 的时间轴解不了店自身的生死与传承(2026-07-03 codex review 提出) |

不用现在还的债(有触发条件,提前做是浪费):v2/v3 双平面合并(跟 DDB 退役走)、`rc_*` 改名(Final)、DB placement(第一个 Silo 客户来时)。

### 场景 SoT 索引(已有的成体系场景库,不在本文重复)

| 场景库                               | 条数        | 位置                                                                                      |
| --------------------------------- | --------- | --------------------------------------------------------------------------------------- |
| Task 决策 golden eval cases(C1-C57) | 57        | `docs/ai/product/task-accuracy/baseline-v1-scenario-review.md`                          |
| Task 业务场景(V1 lifecycle)           | 12        | `docs/product-design/v1/tasks-feature/task-lifecycle.md` §四                             |
| Task flow 终态 + 人机竞争 + 冲突决策        | 11+5+6    | `docs/product-design/v2/tasks-feature/design/task-pipeline-deliverable-codex.md` §8-§10 |
| Store 隔离已覆盖场景                     | 13        | [`store-level-isolation.md`](/system-design/store-level-isolation.md) §2                |
| 电话类型与跟进机制(业务语义底座)                 | 6 类 × 子场景 | `docs/industry-knowledge/`                                                              |
| 全局 flow 骨架                        | —         | `docs/product-design/system-worldview.md` + `north-star.md`                             |

## A. 变更/完整性场景清单(A0 的证据层:会发生什么事)

### A1. 店与电话拓扑(高危区,全部有实锤)

| #  | 场景                          | 触发者                  | 估计频率  | 当前系统行为                                                        | 证据                     |
| -- | --------------------------- | -------------------- | ----- | ------------------------------------------------------------- | ---------------------- |
| S1 | 电话被分错店,需要挪到正确的店(**纠错**)     | 我们(RC 拓扑不可信,配置系手工复制) | 已发生多次 | 历史 calls 的 store\_id 不跟着改,全部变错                                | Peter 会上实锤             |
| S2 | 电话真实换店(**搬家**,店重组/号码转移)     | 客户                   | 低频但必然 | 与 S1 无法区分,系统只有"覆盖"                                            | codex 指出二者语义相反         |
| S3 | 删店重建(误删/重整)                 | 客户或我们                | 已发生   | lead email 绑定丢、mapping 变 orphan、历史断链                          | Peter 实操;6 条 orphan 实测 |
| S4 | 新店 onboarding(RC sync 或手动建) | 我们/客户                | 每新客户  | 建店写 mapping 已闭环(#516);但 onboarding 不建 tenant(会上 assign Peter) | 会议 01:15               |
| S5 | number porting / 号码回收再分配    | 电话商                  | 低频    | 未定义                                                           | codex 补充               |
| S6 | 同一号码同时绑多店                   | 配置错误                 | 可能    | 无唯一性约束防护(P0 泄漏风险)                                             | codex 引 repo 文档        |
| S7 | 店合并 / 拆分                    | 客户(M\&A、重组)          | 低频    | 未定义(无 lineage 概念)                                             | overview 8 问 + codex   |

### A2. 客户/租户生命周期

| #   | 场景                             | 触发者                | 频率              | 当前行为                                            | 证据               |
| --- | ------------------------------ | ------------------ | --------------- | ----------------------------------------------- | ---------------- |
| S8  | tenant 转让给另一个人(接手方已有 tenant)   | 客户                 | Peter 已提出       | 撞 one-active-tenant-per-user,当场 workaround=再建账号 | 会议 01:36(→决策 D1) |
| S9  | 客户扩张 1→N 店 / 缩小 N→1            | 客户                 | 常态              | mapping 支持;quota 无 enforcement                  | why-tenant       |
| S10 | tier 升降 / 改付款人                 | 客户                 | 常态(billing 上线后) | tenants.tier 有列,无 enforcement;Stripe future     | why-tenant §六    |
| S11 | 客户 churn / suspend             | 我们                 | 必然              | status 有枚举无语义,3 个 tenant 全卡 provisioning        | v1-gaps 缺口 5     |
| S12 | 评估型访问:潜在买家拿目标店的 RC login 做收购尽调 | 销售(Oliver/Will 场景) | 已出现             | 无模型("不支持访客"),但这是真实销售场景                          | 会议 01:19         |
| S13 | 一个客户多个 RC accounts / 换电话商      | 客户                 | 必然              | provider connection 挂个人 OAuth,无 tenant 级归属      | deferred 表触发条件   |

### A3. 人员与权限

| #   | 场景                              | 触发者      | 频率     | 当前行为                                                      | 证据       |
| --- | ------------------------------- | -------- | ------ | --------------------------------------------------------- | -------- |
| S14 | 老板给经理只开某几家店的权限(Alan 7 店)        | 客户       | 已有真实需求 | store\_members 支持;但 role 双轨混乱(→决策 D2)                     | 会议 01:35 |
| S15 | 员工离职/换店(含 owner 本人离开)           | 客户       | 常态     | user\_connections 挂个人,人走 OAuth 断                          | codex 补充 |
| S16 | staff 名字归属(通话→staff,task→staff) | pipeline | 每通电话   | staff 归属靠 AI 识别名字;tasks.closed\_by\_staff 基本是 system/NULL | 代码实扫 §6  |

### A4. 顾客(contact)生命周期

| #   | 场景                                     | 触发者   | 频率            | 当前行为                                           | 证据                |
| --- | -------------------------------------- | ----- | ------------- | ---------------------------------------------- | ----------------- |
| S17 | 顾客在同客户多店消费 / 换店                        | 顾客    | 常态            | (store\_id, phone) 主键 → 跨店档案分裂                 | Peter P4(→决策 D4)  |
| S18 | 顾客换手机号 / 家庭共享号码 / 号码易主                 | 顾客    | 低频必然          | phone 即身份,无 person 层                           | codex             |
| S19 | DNC / consent(拒绝联系)                    | 顾客    | 合规敏感          | 挂 contacts(店级);跨店不生效                           | codex:若自动触达已开=立刻修 |
| S20 | lead 从 email 进来 → 归到店 → 生成任务 → 跟进 → 转化 | 顾客+系统 | 313 条/周(test) | lead email 绑死 store 行;lead↔task 桥接缺失(Max 会上认领) | 会议 01:07-01:17    |

### A5. 数据管道(写入侧场景)

| #   | 场景                                                  | 频率                               | 当前行为                                                                                                         |
| --- | --------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| S21 | 正常事件流:call/SMS → 转录 → AI 分析 → contact/task/timeline | calls \~1.7k/周,msgs \~5k/周(test) | phone→store 反查(Neon `rc_store_phones`,phone-identity 0.36.0 起;DDB 已不读)+ store\_id/tenant\_id stamp,fail-open |
| S22 | late event / 历史 backfill / 管道重跑                     | 每次修 bug 都会发生                     | 按"当前"映射 stamp 老事件 = 误 stamp(codex:必须现在修)                                                                     |
| S23 | 部署积压/管道断供后补数                                        | 已发生(lead-tracking 6 周)           | NULL 累积,靠 sweeper 底座(未定时化)                                                                                   |

### A6. 平台化(future,设计时留口即可)

对外 API(per-tenant key + rate limit)、AI agent 介入(MCP)、3 方 CPaaS、BPO 转售、Pool/Silo 搬家 —— 均以 tenant\_id 为锚,见 why-tenant §十一。

## B. 查询清单(workload inventory,来自 apps/api 代码实扫)

### B1. 隔离键机制(现状)

- 三层中间件:auth(Cognito JWT→userId)→ tenant-context(control-plane 查 user→tenant)→ store-guard(**storeId 从请求参数提取**,只校验归属,`TENANT_GUARD_ENFORCE=false` 时 fail-open)
- 真正的授权兜底在每个 route 的 `getStoreContext()`:rc\_stores.user\_id(owner)→ store\_members(shared)→ 取 store\_phones
- **双数据平面**:v2 路由读 DynamoDB(phone-keyed),v3 读 Neon(store\_id-keyed)

### B2. 主要读路径(按页面)

| 页面                  | 表                                               | 隔离键                              | 聚合维度                                      |
| ------------------- | ----------------------------------------------- | -------------------------------- | ----------------------------------------- |
| Dashboard overview  | contacts+calls+messages(6 并行查)                  | store\_id                        | 30 天窗、按天趋势、lifecycle\_stage 分桶            |
| Dashboard summary   | calls + tasks                                   | store\_id                        | 周/月窗,current vs previous                  |
| Leads funnel        | **tasks**(cohort)+calls+messages+timeline+leads | store\_id                        | 5 层漏斗、期间对比、speed-to-lead 中位数              |
| Leads pipeline/list | **contacts**(=lead)+ leads 表                    | store\_id **和 account\_id 混用**   | lead\_status 分组                           |
| Tasks trend         | tasks                                           | store\_id                        | 按天 × type\_category,open/closed/AI vs 人工  |
| Tasks list          | tasks+contacts+calls+messages+timeline          | account\_id AND store\_id 双键     | status/group/tab/priority                 |
| Multi-store         | 6 批查,全表                                         | user\_id 发现店集合→per-store 窗口      | GROUP BY store\_id,Team Productivity 跨表比值 |
| Staff               | calls(主)+tasks                                  | store\_id                        | GROUP BY staff\_name                      |
| Coaching            | calls+coaching\_reviews+contacts                | store\_id + tenant\_id(review 层) | tab/staff/read 状态                         |
| control-plane-admin | tenants/members/mappings                        | 内部工具直连 control plane             | —                                         |

### B3. 口径冲突(代码实扫发现,6 条)

1. **"intro booked" 三个源**:summary 从 calls(outcome=success+revenue\_impacting);multi-store/funnel 从 tasks(close\_result='booked');lead-tracker 从 inbound calls
2. **lead funnel 三套实现**:task-based / contacts-based / inbound-call-based —— 同名指标不同分母
3. **"leads 数"分裂**:dashboard 从 `contacts.lifecycle_stage='lead'`;pipeline incoming 从 `leads` 表(account 级)—— 永远对不上(= 会上 Vivian 报的问题的完整版)
4. **store\_id vs account\_id 隔离混用**:leads/lead-communications/contacts-profile 按 account\_id,其余按 store\_id;多处 `store_id=$1 OR (store_id IS NULL AND account_id=$x)` 兜底
5. **v2(DDB/phone)vs v3(Neon/store\_id)双平面**,calls 数两边可能不一致
6. **staff 的 task 归属缺失**:closed\_by\_staff\_name 基本是 system/NULL,staff 绩效只能 call-based

### B4. 写路径

写路径分两类,不能混成"全部 phone→store 反查":

| 类别                   | 写入方                                                                                                                          | `store_id` 来源                                                                                                                | redesign 关注点                                                                                                              |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **事件 / pipeline 写入** | message-processor / transcribe-processor / ai-analysis-processor / contacts-analyzer / lead-processor / lead-tracking poller | Call/SMS 走 phone→store 解析;lead email 走 leadEmail→store 路由;写入时 stamp `store_id` / `tenant_id`,rollout 期 `tenant_id` fail-open | temporal assignment、late event/backfill point-in-time resolve、NULL/错值监控与 repair                                           |
| **手动 / API 写入**      | studio-api task 操作、coaching review、store 管理                                                                                  | `storeId` 来自 request/session 选中的店,再由 `getStoreContext()` / store guard 验证访问权                                                 | request-store authorization、selected store 有效性、tenant/store guard enforcement;不是 phone-derived,也不该套用 phone assignment fix |

## C. 待 Max/Peter 回答(第 1 步收口条件)

1. A1-A4 每个场景的频率/重要性确认;有没有漏的场景?
2. **指标口径的业务定义**(这是需求不是实现):"intro booked" 以哪个源为准?lead funnel 以哪套分母为准?—— 定一次,全站遵守
3. S12(评估型访问)要不要支持?这决定 tenant 模型要不要 guest 概念
4. S19:SMS 自动触达现在开了吗?(决定 DNC person 层的优先级)

## 下一步(第 2 步预告)

场景清单收口后 → 从场景提炼 entity 表(名词 + 关系 + 会不会变),对齐 5 个 open decisions(D1-D5),产出目标概念模型。参考:[`entity-relationship-map.md`](/system-design/multi-tenant/entity-relationship-map.md)(现状 + D1-D5)+ codex 审计(目标方向,`.claude/specs/2026-07-02-codex-table-relationship-audit.md`)+ postgres skill schema-design reference(第 3 步用)。
