Files
dsh_ai1net_server/交付物/插件数据面-运行时取数口落地-20260925.md
admin 318430c9e9 chore(工作区): 插件投放与分库线收口入库(第 35 棒 + 22:44 拍板落盘)
范围 = 本线(插件投放与分库线)产物 + 记忆类,共 27 件:
- 接续入口_插件投放与分库线(1 件):§0 新增 22:44 拍板行;§2 第 36 棒范围改 5 步、条件步转无条件
- 交付物(22 件):MCN 数据面接入阶段一/阶段二系列(含 B 案落地与 shadow 读数)、
  P0 修通与移动端真机验收、pnpm-EPERM、两机 lib 差异、共享层台账语义、
  基础插件身份与回滚、插件接入验收、插件数据面取数口、移动端迁包与字号扩面、跨机错误消息
- 记忆(4 件):2026-09-24 / 2026-09-25 日志、MEMORY.md、本棒 automation 执行记录

⛔ 未含他线在途改动(只报告、不代提交):机制层 CODEBUDDY.md / state.py /
.codebuddy/rules/server-ops.md、接续入口_IM线、接续入口_StoryForge验收线、
其余 29 个 automation 目录、docs/规则与载体/、归档/、接续包_*。
2026-09-25 23:06:29 +08:00

90 lines
7.0 KiB
Markdown
Raw Permalink 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-09-25)
> **一句话**:插件会话说的"平台面向插件的数据库接入面没建成、取数这条链路不通"**属实**;
> 本单把缺失的那一半(**运行时取数**)补齐 —— 库建好了但插件读不到写不进,现在通了。
> **归属线**:插件投放与分库线(插件数据面取数口)|**会话**:`aliyun-dsh-server-插件数据面`
> **代码基线**:`D:\github\dsh_shenxian`(生产口径 `dshs`)|⛔ 未 commit / 未 push / **未部署**
---
## 一、缺口的真身(先定性,再动手)
| 层 | 本单前状态 | 证据 |
|---|---|---|
| 建库/管理面 | ✅ 已建成(09-23) | `src/db/plugin-data/{schema,diff,datastore}.ts`;47 真机建库 `created` 71 ms |
| **运行时取数** | 🔴 **零实现** | `ImDataPort` 全仓 **4 处命中**(接口定义 + 引入 + 两个可选字段),**无 `implements`/无实例化**;`new ImSdkHost()` 只在 `test/` 出现;**全仓无一处传 `data:`** ⇒ 插件调 `insert` 一律 `not-registered` |
| 平台替代通路 | 🔴 无 | `datastore` 系列路由全是 `requireAdmin` **管理动作**,没有业务数据读写口 |
缺口成因是**接缝两不管**:IM 线 D 单原话「落成的是 `ImDataPort` 注入式端口(**真库端口属建库面,本棒不越界**)」
⇒ 运行时实现被推给建库面,而建库面只做了管理面。两边都以为对方做。
## 二、交付物(5 新 + 2 改)
| 文件 | 作用 |
|---|---|
| `src/db/plugin-data/runtime.ts`(新) | **端口实现**:SQL 生成(标识符一律引用)、**归属强制注入**、房间 ACL、游标分页、配额、逐次审计、失败具名(⛔ 不抛给插件) |
| `src/db/plugin-data/registry.ts`(新) | **装配**:声明现解(按 TTL 缓存,⛔ 不信记录字段)+ 库名**三处一致性**校验 + 每插件库连接池(`max=2`,照定稿 §五)+ 就绪判读 |
| `src/web/routes/plugin-data.ts`(新) | **实例可达的 HTTP 面**:`/api/im/plugin-data/status` + `/api/im/data/*`(查/计/写/改/删) |
| `sdk/im-plugin-client/index.mjs` + `package.json`(新) | **插件侧 SDK v1(REST 面)**:零依赖、可 vendoring、⛔ 不含平台实现与凭据 |
| `test/plugin-data-runtime.test.mjs`(新 18 例) | 端口判据回归(假执行器,⛔ 不连 PG,可机械复现) |
| `test/im-plugin-client.test.mjs`(新 6 例) | SDK 契约(头注入 / 失败折形 / 未配置即拒) |
| `package.json`(改) | 两组新测试挂进 `test` / `verify` 清单 |
| `src/web/server.ts`(改) | 注册 `pluginDataRoutes`(1 行 + 注释) |
**文档**(同批落文):`01-规范/08-插件开发与对接规范.md §3-4`(**重写 —— 插件会话照这节写**)|
`03-数据库/DB-03-插件数据面规范.md §五`(落地状态 + **`id` 语义** + 三条偏差)+ §十(待定项按实况更新)|
`01-规范/09-IM插件SDK与扩展点契约.md §3-1`、`02-架构设计/数据-分库与权威存储架构.md §六`(加落地指针)。
## 三、四条关键判据(本单的"不许含糊")
1. **`id` = 声明里的第一列**(主键是 `(归属列, 第一列)` 的复合键,**无代理 id 列**)⇒ 第一列必须选稳定唯一业务键;
该列**不可被 `patch` 改**。这条此前**没有任何文档写明**,是本次从 `createTableSql` 反推后**写进 DB-03 §五** 的。
2. **归属由内核写,插件覆盖不了**:`scope:user` 给他人 `user_id` ⇒ `bad-args`;`scope:room` 必带 `room_id`
且过成员判定(未注入成员判定 ⇒ **fail-closed**,不是放行)。
3. **库名只信平台**:台账库名与声明换算**不一致即拒**(`db-name-mismatch`)⇒ 防"猜库名"与其后的一切。
4. **失败具名**:契约失败一律 **200 + `{ok:false,reason,detail}`**(与 `ImDataPort` 同形);`4xx` 只留给身份/就绪。
## 四、验收证据(可复现)
```
npm run build → rc=0(tsc 干净)
node --test test/plugin-data-runtime.test.mjs → 18/18 过
node --test test/im-plugin-client.test.mjs → 6/6 过
node scripts/check-layering.mjs → ✅ 无新增违规
```
⚠️ **全量 `npm test` 现状**:567 例中 **7 例失败,全部是环境性 `spawnSync <git|tar> EBUSY`**
(本例只发生在调用 `execFileSync` 的子进程上;本单新增的 24 例零失败)。
受影响文件 = `test/im-sdk.test.mjs`(3 例)+ `test/shared-layer-sync.test.mjs`(4 例),
**与本单改动无关**(那两处代码路径本单未碰);在无该限制的环境下应可全绿。
## 五、权限影响评估(R5:新增对外面,故须出件)
- **新增面**=两个端点族:`/api/im/data/*`(业务数据读写)+ `/api/im/plugin-data/status`(只读判读)。
- **鉴权**=**会话优先 + 实例凭据补位**(与 IM 面同序、同一本 `app.imInstanceTokens` 登记簿;
头名与拒绝原因码取自 `src/im/instance-token.ts`,⛔ 不另写字面量)。
- **可见面收窄三条**:① 只有**已建库**(台账 `state='ready'`)的插件能取数;② 归属列强制注入
⇒ 越权得 0 行;③ 房间表复用内核成员表,非成员得 0 行。
- **审计**:逐次落 `plugin_data_audit`(谁 / 自称哪个插件 / 动作 / 表 / 影响行数 / 拒绝原因);
⛔ **不记行内容**(不把插件数据抄进平台日志)。
- 🔴 **已知残余**:同一用户的实例内,插件 A 可**自称**插件 B(越不出用户边界)⇒ 补法 = 每插件令牌;
**本期以逐次审计兜底**(可对账、可追责)。
## 六、未做(⛔ 不许看成"已闭环")
1. 🔴 **未部署到 47 / 106,未做真机验收** —— 代码与单测就绪 ≠ 生产可用。部署清单:
`scp` 构建产物 → `restart dshs` → **真机自测四拒一空**(写他人 `user_id`/room 表缺 `room_id`/
缺主键列/带 `created_at` 应各拒;非成员读 room 表应得 0 行)+ 一次成功的 `insert` + `find` 回读。
2. **跨节点形态仍不通**:worker 上的实例 → Manager 侧数据面缺"实例→控制面"身份通道(`DB-03 §六` 自认)
⇒ 当前可用形态 = **同机 / 本机**。
3. 本期**未提供**:`im.data.tx`(同库多表事务)、聚合查询、软删 + 30 天保留、`memberRooms` 接线、
与 agent 同族的写入预算。
4. 本单**刻意不改** `src/web/routes/im.ts`(IM 线 D 单的验收判据 2 冻结了该文件 diff)
⇒ 鉴权口径在 `plugin-data.ts` 独立实现。⚠️ **长期成本**:IM 线若改鉴权语义,本文件必须同步跟进;
将来要"一份实现两处用",须把鉴权提成 `src/web/im-auth.ts` 由两边 import(那要先解 D 单那条冻结判据)。
## 七、下一棒(建议,等排)
**部署 + 真机验收**(一条,做完即闭环):按上面 §六-1 清单在 47 落地并逐条取证;
若同时排"跨节点",则先做身份通道(属 IM 线 / 序47 的既有缺口,⛔ 不在本单范围)。