# 多数据源声明(SQLite / MySQL / 飞书多维表) 本文说明技能如何向匠厂宿主**声明**业务数据库,以及技能 CLI / Action 如何与宿主读写**同一物理库**(或同一飞书表)。 **产品定位:** 默认仍是本地 SQLite(`{skill_slug}.db`)。需要多用户共享、集中运维或云库时,可显式声明 **MySQL**。需要以飞书多维表格为权威数据时,声明 **`feishu_bitable`**。UI / API 契约尽量一致;SQLite/MySQL 的 `_jiangchang_*` 展示元数据写在同一逻辑库中,飞书源用本文件的 **`columns` 覆盖**声明展示。 **宿主版本:** | 能力 | 最低 Host | |------|-----------| | `data-sources.json` + MySQL | **≥ 6.9.28** | | `kind: feishu_bitable` + `columns` 展示覆盖 | 以当前匠厂 Host 为准(task-plaza 等已落地;发布说明见 Host changelog) | **完整参考实现:** - MySQL:[`process-work-order`](https://git.jc2009.com/client-commons/process-work-order) @ v1.0.2 - 飞书:业务技能 `task-plaza`(外包任务板) --- ## 何时用哪种后端 | 场景 | 推荐 | |------|------| | 单机、离线、小数据量、便携部署 | **SQLite**(默认,不配声明文件亦可) | | 多用户共享、运维集中管库、与外部系统共库 | **MySQL 云库**(显式 opt-in) | | 权威数据已在飞书多维表、多人在线协作 | **`feishu_bitable`**(显式 opt-in) | **硬规则:一个 `sourceId` 对应一个物理库 / 一张飞书业务表声明。** 禁止双写、禁止 SQLite 与 MySQL / 飞书同步镜像。 --- ## 文件位置 均在**用户数据目录**(不是安装包目录): ``` {JIANGCHANG_DATA_ROOT}/{JIANGCHANG_USER_ID}/{skill_slug}/ ├── data-sources.json # 声明式数据源(可选;见下) ├── .env # MYSQL_DSN / 飞书凭证等连接配置 └── {skill_slug}.db # SQLite 模式下的本地库文件 ``` 安装/升级时,若用户目录尚无 `data-sources.json` 且技能包内有 `assets/data-sources.example.json`,宿主会**复制一次**示例(不覆盖已有文件)。 模板默认示例为 **SQLite 显式声明**(与自动扫描 `{skill_slug}.db` 等价)。改走 MySQL / 飞书时,请参照 `assets/examples/` 下对应示例手工替换用户目录中的 `data-sources.json`,并在 `.env` 配置密钥。 若不需要声明式接入,可删除用户目录中的 `data-sources.json`,宿主恢复自动扫描 `.db` 文件。 --- ## `data-sources.json` 格式 根对象: | 字段 | 类型 | 说明 | |------|------|------| | `version` | `1` | 固定为 1 | | `sources` | 数组 | 至少一条数据源 | 每条 `sources[]`: | 字段 | 必填 | 说明 | |------|------|------| | `id` | 是 | 英文标识,如 `primary` | | `kind` | 是 | `sqlite` \| `mysql` \| `feishu_bitable` | | `displayName` | 否 | 侧栏展示名;多库时建议填写 | | `path` | sqlite 必填 | 相对技能数据目录的路径;可用 `{skillSlug}` 占位 | | `connectionEnv` | mysql 必填 | `.env` 中 DSN 的环境变量名,如 `MYSQL_DSN` | | `appIdEnv` / `appSecretEnv` / `appTokenEnv` | feishu 必填 | `.env` 中飞书应用与多维表 app_token 的变量名 | | `tableIdEnv` | feishu 常用 | `.env` 中业务表 table_id 的变量名(或宿主约定的等价字段) | | `columns` | 否 | **列展示覆盖**(源无关;见下节) | ### SQLite 示例(模板默认) 见 [`../assets/data-sources.example.json`](../assets/data-sources.example.json)。 ### MySQL 示例 见 [`../assets/examples/data-sources.mysql.example.json`](../assets/examples/data-sources.mysql.example.json)。 ### 飞书多维表示例 见 [`../assets/examples/data-sources.feishu_bitable.example.json`](../assets/examples/data-sources.feishu_bitable.example.json)。 --- ## `columns` 展示覆盖(源无关) 连接器先按后端生成列 schema(SQLite `_jiangchang_columns` / MySQL 元数据 / 飞书字段映射),再叠加 `sources[].columns`: ```json "columns": { "状态": { "editable": false, "searchable": true }, "结果链接": { "displayType": "url", "editable": false, "searchable": false }, "发单人": { "displayType": "userId", "editable": false, "formVisible": false, "defaultValueFrom": "currentUser.userId", "searchable": true }, "平台": { "searchable": true, "optionsWhen": { "dependsOn": "任务类型", "map": { "文章发布": ["头条号", "搜狐号"], "视频发布": ["抖音", "视频号"] } } } } ``` | 字段 | 类型 | 作用 | |------|------|------| | `displayType` | string | 覆盖展示类型(如 `url`、`textarea`、`userId`、`currency`) | | `displayName` | string | 覆盖列显示名 | | `defaultValue` | string/number/boolean/null | 新增表单默认值 | | `defaultValueFrom` | string | 从宿主会话预填:`currentUser.userId` / `currentUser.username` / `currentUser.usernameOrUserId` | | `optionsWhen` | object | 依赖另一字段当前值过滤下拉:`dependsOn` + `map` | | `createable` | boolean | `false` = 不进新增表单 / 不进 create payload | | `editable` | boolean | `false` = 不进编辑表单 / 不进 update payload(状态机字段常用) | | `formVisible` | boolean | `false` = 表单不展示但仍可按 createable/editable 写入(如静默 `defaultValueFrom`) | | `requiredOnCreate` | boolean | 新增必填 | | `searchable` | boolean | 是否进**列筛选**与**顶栏全局搜索**(覆盖连接器默认) | **与 `_jiangchang_columns` 的关系:** | 后端 | 主声明位置 | |------|------------| | SQLite / MySQL | `_jiangchang_columns`(`searchable` / `editable` / `display_type` 等);`data-sources.columns` 可再覆盖 | | 飞书 | **无** `_jiangchang_*` 表;**以 `data-sources.json` 的 `columns` 为准**覆盖飞书字段映射默认值 | 飞书连接器默认:明文与单选等常见字段可筛;技能用 `searchable: true/false` 收紧或放开筛选列(避免「全表可筛」噪音)。详见 [`SCHEMA.md`](SCHEMA.md)「列筛选与全局搜索」与「`display_type: url` 外开」。 --- ## `.env` 与连接串 密钥写在用户 `.env`(或进程环境变量),**不要**写进 `data-sources.json`: ```env # MySQL 云库连接(不配则走本地 SQLite) MYSQL_DSN=mysql://user:password@192.168.0.20:3306/your_database # 飞书多维表(变量名须与 data-sources.json 中 *Env 一致) FEISHU_APP_ID=cli_xxx FEISHU_APP_SECRET=xxx FEISHU_BITABLE_APP_TOKEN=bascnxxx FEISHU_TASK_TABLE_ID=tblxxx ``` MySQL 格式:`mysql://` 或 `mysql2://`,须含库名。注释写法须符合 [`../development/CONFIG.md`](../development/CONFIG.md)。 技能 Python 侧(SQLite/MySQL):`scripts/db/backend.py` 读取同一 `MYSQL_DSN`;有值则 `resolve_backend()` 为 `mysql`,否则 `sqlite`。飞书读写由技能自备 SDK / HTTP,与宿主连接器并行遵守同一张表、同一凭证 env。 --- ## 技能代码职责 ### 宿主 UI(数据管理) 宿主读取用户目录 `data-sources.json` + `.env`,经 Host 内置连接器访问库 / 飞书表。**不依赖**技能 `connection.py`。 ### CLI / Action / `init-db` **必须**与宿主使用同一后端策略,否则会出现「UI 看云库、CLI 写本地 `.db`」的分裂。 模板已提供(SQLite / MySQL): | 模块 | 作用 | |------|------| | `scripts/db/backend.py` | `resolve_backend()`、`parse_mysql_dsn()` | | `scripts/db/cursor_compat.py` | 统一 `?` 占位符与 `executescript` | | `scripts/db/connection.py` | `get_conn()` 双分支;`init_db()` 幂等建 `_jiangchang_*` | 业务表 DDL / 迁移仍在技能自己的 `schema` / `init_db()` 中按 `conn.backend` 分支处理(见工单参考实现)。飞书技能无本地业务 DDL,但仍须提供 `health` / Action 与宿主同一表。 可选:`describe_active_store()` 用于 health / 排障。 --- ## MySQL / 飞书 当前限制(Host) **MySQL:** - 不支持 `tableAdmin`(建表/改表 UI) - 不支持 `cellPresentation` - 元数据与 CRUD 与 SQLite 路径一致 **飞书:** - 不支持本地式 `tableAdmin` / 随意改物理 DDL(字段以飞书后台为准) - 筛选/排序能力受飞书 API 约束;用 `columns.searchable` 控制筛选项 - 附件 / 人员等字段依赖宿主映射的 `displayType`(如 `attachment`、`userId`) 表结构变更:SQLite/MySQL 由技能 `init-db` / 迁移负责;飞书在飞书后台改字段后,同步更新 `columns` 覆盖与技能读写字段名。 --- ## 开发 Checklist(云库 / 飞书) 复制新业务技能并选择 MySQL 时: 1. Host ≥ 6.9.28 2. 用户目录放置 `data-sources.json`(mysql 源 + `connectionEnv`) 3. `.env` 配置 `MYSQL_DSN`(或你在 json 里声明的 env 名) 4. `requirements.txt` 含 `PyMySQL>=1.1.0`(模板已声明) 5. 业务 DDL 同时支持 sqlite / mysql 分支(或仅部署 mysql) 6. **抽测**:数据管理 UI 与 CLI(如 list / create)读写同一库 7. 见 [`../development/CHECKLIST.md`](../development/CHECKLIST.md) A6-16 选择飞书时: 1. Host 已支持 `feishu_bitable` 2. `data-sources.json` + `.env` 凭证齐全 3. `columns` 收紧 `searchable` / `editable`,结果链接用 `displayType: url` 4. CLI / Action 与数据管理抽测同一 `app_token` + `table_id` 5. 见 CHECKLIST **A6-17** --- ## 与 SCHEMA / ACTIONS 的关系 - [`SCHEMA.md`](SCHEMA.md):`_jiangchang_*` 适用于 SQLite/MySQL 已注册表;飞书用本文件 `columns`。`url` 外开、列筛选语义两边对齐。 - [`ACTIONS.md`](ACTIONS.md):无 `replaces` 时宿主直写**已注册数据源**;状态机表常用 Policy 关裸编辑 + `replaces: delete` + `visibleWhen`。 - [`CLI.md`](CLI.md):`init-db` 对当前 active backend(sqlite/mysql)幂等初始化元数据。