# 插件数据面 · **运行时取数口**落地(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 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 的既有缺口,⛔ 不在本单范围)。