起因:Jeff 2026-10-06 22:00 语音「他不需要碰到我们的代码……调用我们能力给他」,23:11 定「我们做 A」。 这份取代
LOOP分代码方案.md里「把核心代码交给 LOOP」那条路(hoop-core 仓库暂不用,A3 暂停)。 那份里已经做完的 A1–A1d(登录按产品配置、品牌和签发者由使用方传入)在这条路上照样用得上。 状态:方案,还没动一行代码。 设计评审 ≠ 运行验证:实施时第 4 / 8 节的空库迁移、路由、/ws、隔离都要真跑过才算数。第 9 节是要 Jeff 定的事。
0. 一句话
LOOP 拿不到我们的代码。我们在自己这边给 LOOP 单独跑一套后端(同一份 HOOP 代码,LOOP 自己的数据库、钥匙、品牌、域名), LOOP 只做自己的 App 界面,通过一份有版本、有范围的公开接口调用我们的登录和聊天。
1. 边界(Cora 10-06 23:06 / 23:12 两次补的,照收)
- 两套部署,各管各的:代码同一份,但 LOOP 那套单独上线、单独跑迁移、单独回滚。修一个 bug 两边都受益,但要分别升级、分别验,不是同时生效。LOOP 出问题不能牵连 HOOP。
- 只开放需要的接口:LOOP 用户的票只能打第 3 节白名单里的接口;管理后台、内部接口、MCP、驻兵、城堡 / 游戏 / 钱包这些一律打不到。
- 手机 App 里不放任何秘密:装在用户手机上的东西都能被拆出来,所以「App 专属钥匙」证明不了调用来自 LOOP。 手机端只用用户登录后拿到的短期票(现有 access 15 分钟 + refresh)。真要合作方密钥,只放在 LOOP 自己的服务器上做服务器间调用,能轮换、限额、撤销(第一版不需要,见第 2 节 b)。
- 运维归我们:限流、封禁、日志、用户资料删除 / 导出由我们做;可用性、费用、资料处理责任两家写进约定。
- 现在只有登录拆干净了。聊天、通话、工作房、AI 里还有没有 HOOP 专属依赖,要逐块查(第 4 节)。
2. 登录怎么做
a)第一版:LOOP 用户直接在 LOOP 那套后端上注册登录(现有流程,换 LOOP 的配置)
- 邮箱验证码 / 手机验证码 / Apple / Google 四条路照旧,接口路径不变。
- LOOP 那套的 auth.Config:LOOP 自己的 JWT 密钥和签发者(不是 hoop)、LOOP App 的 bundle id 和 Google Client ID、LOOP 的发信 / 短信凭据、LOOP 的 Brand(邮件模板、短信文案、兜底昵称……)。A1c / A1d 已经让这些都能按产品给。
- 两套的票互不认(A1d 已有测试:不同密钥、或同密钥不同签发者都互拒)。
b)以后,如果 LOOP 有自己的账号系统:LOOP 服务器拿合作方密钥调我们「给某个 LOOP 用户签一张票」,App 再拿这张票来调我们(Stream / Sendbird 的做法)。第一版不做。
3. 第一版开放的接口(白名单)
第一版只做私聊、只做文字。 建群、群成员管理、图片 / 文件、通话放下一版(Jeff 要改范围就改这张表,验收跟着改)。
找人 = 按手机号、邮箱或用户名精确找到对方(现有 GET /v1/users/search 就是精确匹配这三样,不是模糊搜),找到就直接开私聊;第一版没有好友 / 好友申请。
| 块 | HTTP 接口 | 备注 |
|---|---|---|
| 登录 | POST /v1/auth/otp/request POST /v1/auth/otp/verify POST /v1/auth/apple POST /v1/auth/google POST /v1/auth/refresh POST /v1/auth/logout |
现有 |
| 账号 | GET /v1/users/me PATCH /v1/users/me DELETE /v1/users/me |
删号是上架必需 |
| 找人 | GET /v1/users/search GET /v1/users/{id} |
精确匹配 |
| 会话 | GET /v1/conversations GET /v1/conversations/sync POST /v1/conversations |
POST /v1/conversations 现有代码只建私聊;建群是另一条 POST /v1/groups,不开 |
| 消息 | GET /v1/conversations/{id}/messages POST /v1/conversations/{id}/text POST /v1/conversations/{id}/read |
只有文字 |
| 实时 | GET /ws |
另有一层限制,见 3.1 |
推送不在这张表里:第 9 节第 4 条 Jeff 选做,才把 POST /v1/devices/push-token 加进白名单、把「推送」加进第 8 节验收(用 LOOP 自己的 APNs / FCM 证书);没选就放下一版。
3.0 发文字的两个入口都要按字段白名单
「只做普通文字」光看消息类型挡不住:现有 /ws 的 message.send 直接整份收 SendInput,HTTP POST /v1/conversations/{id}/text 也收 subtype、room_invite 等字段 ——
类型还是 text,却能生成通话记录、HOOP 房间邀请卡这类 HOOP 专属的消息。
LOOP 那套在服务端对这两个入口都按字段 / 语义白名单处理:只留第一版真要用的(正文、引用回复、@ 点名、客户端消息号;
/ws 再加目标会话 conversation_id —— HTTP 的目标在路径里,不用这个字段),
服务端核 conversation_id 必须是 LOOP 的私聊、发送者必须是成员,否则拒。
第一版不收 to_user_id(「不建会话直接发给某人」):要先 POST /v1/conversations 建私聊再发;以后要开它,单独写进来并补测试。
subtype、room_invite 以及其它 HOOP 专属形状一律拒绝(回 400,不悄悄丢掉后照发)。
验收:合法 LOOP 票分别从 HTTP 和 /ws 带这些字段(含 to_user_id、别人的或非私聊的 conversation_id)发,全部被拒,对方收不到、库里没有;
只带白名单字段的正常文字从两个入口都能发出、对方实时收到。
其余全部不开。怎么挡:服务端自己挡——LOOP 那套启动时按配置只注册白名单路由,其余路径根本不存在(404);外层网关白名单只是第二道兜底。 验收:拿合法的 LOOP 用户票去打白名单外的路径(管理、MCP、驻兵、城堡、建群、通话……),一律 404 / 403。
3.1 实时连接 /ws 也要按白名单(HTTP 路径白名单挡不住它)
/ws 里面还有一层「命令」:现在服务端除了 message.send、正在输入,还接 tool.event、call.offer / call.end / call.reject 和扩展类型。
LOOP 那套要在服务端分开限制三样:
- 上行命令:只收 message.send(仅文字、仅私聊、字段按 3.0 白名单)和正在输入;其余命令一律拒绝并回错误,不落库、不转发。
- 下行事件:只推白名单功能会产生的事件(新消息、已读、正在输入、会话变化),HOOP 专属事件(城堡、温度、游戏房、驻兵……)不推。
- 可建 / 可写的房型:只有私聊。
验收:合法 LOOP 用户票连上 /ws,逐个发非白名单命令,全部被拒,对方收不到、库里没有。
4. 开放前要查清的(逐块,像登录那样拆线)
- 消息:现在牵着 帖子 / 房间 / 风控 / 温度 / 在线状态 / 通话(
LOOP分代码方案§3 的表)。发文字这一路哪些在 LOOP 上必须关掉或换成空实现。 - 注册后钩子:HOOP 接了「开钱包」「进官方频道」,LOOP 那套不接(或接 LOOP 自己的)。
- 数据库迁移先实测:在一次性空库上把全部迁移跑一遍,确认能跑完(里面有种数据、改约束的迁移,不能假设没问题),再定 LOOP 库是跑全套还是瘦身。
- 启动时会跑起来的东西要列清、关掉或隔离:
router.go现在会起十几个后台任务(删号清理、eKYC 照片清理、邀请码过期、在线状态、开发者对账、驻兵中继 / 释放、运维巡检、消息发件箱中继、风控、游戏房调度……),还有新闻、狼人杀、音乐等启动项。逐个判:LOOP 要的留着(如发件箱中继、删号清理),HOOP 专属的在 LOOP 那套上不启动。 - 实时连接、推送、文件存储、邮件短信:每样都给 LOOP 单独配,不能借 HOOP 的。
5. 部署
LOOP 那套 = 独立的:服务器(或独立容器)、Postgres、Redis、对象存储桶、APNs / FCM、发信 / 短信、域名(例 api.<loop 域名>)、
密钥(全部新生成,一个都不从 HOOP 拿)。上线 / 迁移 / 回滚和 HOOP 分开走。
6. 版本和运维
- 接口带版本
/v1;改动先发说明,不兼容的改动走/v2,旧版保留一段时间。 - 限流、封禁、日志、监控、资料删除 / 导出:我们做。
- 两家的约定:可用性、费用、资料处理(LOOP 用户的资料存在我们这边)。
7. 以后的选项(第一版不做)
SDK(给 LOOP App 的现成工具包)、测试环境、事件通知(我们主动通知 LOOP 服务器)、合作方密钥(第 2 节 b)、一套服务器同时服务多家。
8. 第一版验收(真实用户链路,在 LOOP 那套上)
注册 → 登录 → 续期 → 按手机号 / 邮箱找到对方 → 建私聊 → 互发文字、实时收到 → 已读 → 退出 → 删号(Jeff 选做推送时,再加「推送」一步);
同时:
- HOOP 照常;两边的票互不认;
- 白名单外的 HTTP 接口、/ws 命令和发文字时的 HOOP 专属字段,用合法 LOOP 票去打一律被拒(3 / 3.0 / 3.1);
- 隔离要实测,不是看配置清单:LOOP 实例跑完整条链路后,HOOP 的数据库、Redis、对象存储、推送里没有任何来自 LOOP 的写入
(做法:LOOP 那套根本拿不到 HOOP 的地址和凭据,网络上也不通;再对比 HOOP 那边的写入记录确认为零)。
9. 要 Jeff 定的
- LOOP 那套放哪台机器?(不和 HOOP 生产共用)
- LOOP 的域名。
- 第一版范围:只私聊 + 按手机号 / 邮箱找人(本稿的默认),还是要加群 / 好友?
- 第一版要不要推送。要:LOOP 先准备自己的 App ID 和推送证书,推送进白名单和验收;不要:放下一版。
- LOOP 的 App 谁做、用什么技术(决定以后 SDK 用什么语言)。