@microi.net/cli 5.2.2 → 5.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codebuddy-plugin/marketplace.json +2 -2
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.workbuddy-plugin/marketplace.json +2 -2
- package/.workbuddy-plugin/plugin.json +1 -1
- package/assets/build-meta.json +5 -5
- package/cordis.patch.yml +1 -1
- package/package.json +1 -1
- package/scripts/mcp-server.js +56 -56
- package/scripts/microi-codex-broker.js +12 -2
- package/scripts/microi-skills.meta.json +199 -199
- package/skills/.microi-skills-version.json +2 -2
- package/skills/.progressive-disclosure-manifest.json +6 -6
- package/skills/app-store/SKILL.md +81 -8
- package/skills/message-notification/references/contracts.md +2 -0
- package/skills/microi-ai-application/SKILL.md +4 -3
- package/skills/microi-db-schema/references/form-component-options.md +1 -1
- package/skills/microi-form-engine/SKILL.md +23 -1
- package/skills/microi-form-engine/references/component-catalog.md +75 -4
- package/skills/microi-frontend-sdk/references/progressive-01-token-/345/275/223/345/211/215/347/231/273/345/275/225/347/224/250/346/210/267/344/270/216/345/275/223/345/211/215/347/273/210/347/253/257/347/231/273/345/275/225/345/215/217/350/256/256.md +4 -0
- package/skills/microi-microservice/SKILL.md +1 -0
- package/skills/microi-mobile-app-quality/references/progressive-01-4-/351/207/215/350/246/201/346/214/211/351/222/256/345/277/205/351/241/273/345/270/246/345/233/276/346/240/207.md +4 -0
- package/skills/microi-uniapp-frontend/SKILL.md +9 -1
- package/skills/v8-export-import/SKILL.md +12 -9
- package/skills/v8-file-upload/SKILL.md +28 -3
- package/skills/v8-file-upload/references/progressive-01-/345/205/254/346/234/211/346/241/266-vs-/347/247/201/346/234/211/346/241/266.md +1 -1
- package/skills/v8-saas-multi-tenant/SKILL.md +8 -7
- package/skills/v8-security/SKILL.md +3 -1
- package/skills/workspace-conventions/SKILL.md +11 -0
|
@@ -23,6 +23,14 @@ description: Microi 应用商城开发、打包、安装和升级规范。用于
|
|
|
23
23
|
- 平台通用缺陷的交付证据必须分开记录:源码修复、官方母版资源、商城包发布后回读、目标租户后台安装任务、目标租户资源回读和真实 UI/接口验收;其中任一步未完成都不能笼统称为“已发布并安装”。
|
|
24
24
|
- 任何计划让全部吾码租户通过“安装/更新官方应用”获得的标准字段、布局、菜单、页面或种子数据,必须先在官方 `microi_itdos` 主租户创建并回读,再从该主租户按精确菜单/表资源导出新版 `AppPakcet`、单调递增应用版本并发布。禁止先只在客户/子租户补字段,再用本地手工 JSON 冒充官方母版;客户验证应发生在官方包发布之后。
|
|
25
25
|
- 同一标准能力若同时属于基础 SaaS 空库包和独立官方应用(例如系统设置、系统账号),两条交付链都要更新:基础包保证新租户初始化完整,独立应用保证存量租户可增量安装。发布后分别核对 `PackageInfo.Version`、物理列、`diy_field` 布局节点和商城行 `AppVersion/AppPakcet`,不能用其中一条替代另一条。
|
|
26
|
+
|
|
27
|
+
## 吾码创建人开发时的强制发布闭环
|
|
28
|
+
|
|
29
|
+
- 每次任务先检查工作区根的 `Microi.Server/Microi.net/`。只有目录存在且 `rg --files Microi.Server/Microi.net` 能找到至少一个真实源码文件时,才确认当前是吾码创建人在官方完整源码工作区开发;空目录不算,且不要求本次修改位于该目录。确认后,对任意目录中的平台基础能力执行修改、构建或交付时,官方应用数据包都不是“以后再补”的附加产物,而是本次实现的组成部分。目录缺失或为空时按普通用户工作区处理;纯审查、解释或诊断仍保持只读。
|
|
30
|
+
- 触发资源包括系统设置、表、字段、Tab、菜单、权限、接口引擎、事件、数据源、页面、打印、工作流、任务、平台内置微服务和可幂等种子数据。开始修改时就确定资源归属:系统设置、登录身份、个人中心等通常归 `app.microi.saas-engine`;表单引擎归 `app.microi.form-engine`;模块引擎归 `app.microi.module-engine`;应用商城归 `app.microi.store`。同一能力跨多个包时逐包更新,禁止只挑一个包。
|
|
31
|
+
- 强制闭环依次包含:①源码和定向测试;②通过绑定 `https://api.itdos.com + OsClient=iTdos` 的 `microi_itdos` 更新并回读官方母版资源;③从母版导出或按受审计发布契约生成本地应用包,单调提升包版本并核对资源数量、版本和 SHA-256;④发布对应官方 Platform 应用;⑤重新读取商城行和完整 `AppPakcet`,核对 `Published/IsApprove`、`AppVersion`、`PackageInfo.Version`、资源正文和内容哈希;⑥立即做一次同输入幂等重跑,确认无重复升版或漂移。任务还指定目标租户时,再安装/更新并等待后台任务 `Succeeded` 后回读真实资源。
|
|
32
|
+
- 本地包文件、生成器成功、单元测试通过、返回 TaskId 或 HTTP 200 都不能代替官方主数据库与商城回读。`.resource-sync-base` 只能在官网发布后逐项哈希一致时由同步器推进,不得与本地候选一起手工修改。若官方身份、MCP 登录或发布门禁失效,必须保留准确的未发布边界并修复链路;不得把本地 JSON 宣称为“其它吾码用户已经可以安装”。
|
|
33
|
+
- 应用包不得携带真实地图 Key、Token、连接串或其它租户秘密。浏览器供应商 Key 等配置只交付字段/设置模板和安全读取能力,实际值由每个目标租户在安装后自行填写。
|
|
26
34
|
|
|
27
35
|
## 包内容
|
|
28
36
|
|
|
@@ -76,14 +84,23 @@ description: Microi 应用商城开发、打包、安装和升级规范。用于
|
|
|
76
84
|
- 后端来源代理必须固定已保存的 `ApiBase + OsClient`,拒绝过期 Token、访问密钥会话、非超级管理员、非 HTTPS 外网地址、重定向漂移和超限响应;Token 不得返回浏览器、日志、审计或应用包。退出登录同步删除服务端密文。
|
|
77
85
|
- 商城主页面统一承载应用市场、已安装、我发布的应用、安装离线包和来源管理,不能再通过独立菜单或路由割裂上下文。来源增删改启停逐项自动保存;来源管理、详情和复杂配置使用平台统一 `80%` 可拖动大圆角 Dialog,遮罩服从正向开关 `sys_config.FormMaskBlur`,缺失或 `0/false` 默认关闭毛玻璃。
|
|
78
86
|
- 每张应用卡必须显示预览图、公开范围、分类、最新版本、当前租户已安装版本及状态色。来源卡必须显示其公开数和当前授权可访问总数;平台官方发布节点只显示“平台官方应用源”身份标记,不显示安装、更新或重新安装操作。
|
|
79
|
-
- 安装可明确选择 `sys_microistore` 当前版本或 `mic_data_version`
|
|
87
|
+
- 安装可明确选择 `sys_microistore` 当前版本或 `mic_data_version` 中仍含完整包正文的历史快照;后台任务在首次取包时必须把计划中的 `AppVersion` 解析为匹配且包含完整包正文的不可变 `StoreVersionId`,写入 checkpoint,并在全部后续分片一直传到详情取包。发布方中途升版时继续完成已锁定快照,新版留给下一轮盘点;快照缺失、版本不匹配、身份变化或快照 Id 漂移必须失败关闭,禁止退回易变当前行。实际安装版本写回 `sys_microistoreversion`。回退旧版属于重新安装,不得静默换成最新版。
|
|
80
88
|
- 应用详情的版本选择必须服务端分页和搜索,默认每页不超过 20 条;当前版本固定置顶,历史版本只返回仍包含完整包正文的可安装状态。禁止用 `_PageSize:500` 或一次加载全部版本后在浏览器过滤。翻页、搜索与页大小切换都必须保持已选版本语义并显示总数。
|
|
81
89
|
- 商城详情、来源管理等 Teleport 弹层必须使用宿主级固定遮罩,毛玻璃覆盖完整可视区域;标题栏拖动按弹层真实尺寸限制四边,窗口缩放后重新限制,不能依赖固定像素最大位移或允许内容越出视口。
|
|
82
90
|
- “我发布的应用”只读取当前登录用户拥有的记录,可以包含草稿和构建失败项;普通商城列表只读取已发布项。两者必须在服务端按 Owner 和发布状态过滤,不能依赖浏览器过滤后再分页。
|
|
83
91
|
|
|
84
|
-
## 发布版本与资源选择
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
## 发布版本与资源选择
|
|
93
|
+
|
|
94
|
+
### 每个应用版本必须有更新日志(强制)
|
|
95
|
+
|
|
96
|
+
- 本规则覆盖 `Platform / Regular / Web / UniApp / MicroService` 以及所有 AI 应用。任何创建、修改、升级、重新构建或重新发布,只要产生新的应用版本,就必须先在 `sys_microistore_changelog` 写入一条更新日志;不允许先发布后补写,也不允许因为只改了元数据、V8、路由、提示文案或内置运行产物而省略。
|
|
97
|
+
- 更新日志通过 `StoreId` 关联 `sys_microistore.Id`,`Version` 必须是规范化后的精确 `AppVersion`,且同一应用同一版本只能有一条。`Title`、`ChangeType`、`Content`、`ReleaseTime` 都是必填项;`Content` 要写清用户可感知的新增、优化、修复、兼容或安全影响,禁止只写“优化体验”“修复问题”等无法审计的空泛文字。
|
|
98
|
+
- 正确顺序固定为:确定目标版本 → 保存商城应用 → 写入或审阅该精确版本日志 → 同步源码与构建 → 制包/发布 → 回读商城行、安装包和日志。发布器发现日志缺失、软删除、版本不一致或任一必填项为空时必须失败关闭。
|
|
99
|
+
- `microi_publish_application_directory_stream`、V3 发布或其它支持变更摘要的工具必须显式传 `changeSummary`,且其含义与更新日志一致;`mci_ai_app_version.ChangeSummary`、`AppPakcet.PackageInfo.ChangeLog` 和商城子表不得互相矛盾。
|
|
100
|
+
- 应用商城包升级必须同时交付子表、真实 `StoreId` 外键字段、唯一约束/索引、隐藏子菜单、主表 `TableChild` 字段、详情时间线和发布门禁。历史商城源没有该能力时前端应明确显示“当前来源暂未提供更新日志”,不得伪造空日志为“暂无更新”。
|
|
101
|
+
- 验收至少回读“商城当前版本 + 对应日志 + 包内版本/ChangeLog”,再在真实商城详情弹层检查版本、类型、标题、时间和正文;重复执行相同版本写入应命中唯一记录而不产生重复行。
|
|
102
|
+
|
|
103
|
+
- 发布器必须把用户请求的精确版本传给资产准备器,并断言 `RequestedVersion == Prepared.PackageVersion == AppPakcet.PackageInfo.Version`;版本不存在就失败,禁止静默改用最新版本。
|
|
87
104
|
- `SelectMenu`、`SelectTable`、`SelectApiEngine` 必须从当前发布包的显式选择持久化;不能读取商城行上一次保存的选择来决定本次包内容。
|
|
88
105
|
- 发布完成后同时回读商城版本行、包正文和构建资产,逐项核对版本、数量与 SHA-256;任一处漂移即发布失败。
|
|
89
106
|
- 官方内置前端应用只能有一个发布源码根。默认租户工作副本与受审计的独立 Git 源码仓库不能同时成为事实源;若使用独立仓库,必须提交一个发布契约并让构建、跨工程测试、所有程序集内置包共同读取它,正式发布还要证明源码根来自无未提交修改的 Git 提交。前端主包只提供通用宿主、诊断和恢复入口,不复制完整业务源码。HDFS/CDN 运行镜像必须回读到同一 `RuntimeManifestHash` 后才可启用,不能用较新的镜像静默覆盖较旧数据库包,也不能用较新的数据库包静默覆盖未验签镜像。
|
|
@@ -91,8 +108,8 @@ description: Microi 应用商城开发、打包、安装和升级规范。用于
|
|
|
91
108
|
|
|
92
109
|
## MCP 工作流
|
|
93
110
|
|
|
94
|
-
1. 安装/更新现成商城应用时,先调用 `microi_install_store_application` / `microi_update_store_application` 且不传 `confirmExecution`,核对目标租户、商城源、StoreId 和幂等请求 Id
|
|
95
|
-
2. 用户明确确认后,把 `confirmExecution` 精确设为 `StoreId`,提交真实持久化后台任务;只传 StoreId、版本和商城源定位信息,不通过 MCP/HTTP 传完整 `AppPakcet`。
|
|
111
|
+
1. 安装/更新现成商城应用时,先调用 `microi_install_store_application` / `microi_update_store_application` 且不传 `confirmExecution`,核对目标租户、商城源、StoreId 和幂等请求 Id 的预检结果。恢复被商城升版打断的旧任务时,额外传入已回读且仍含完整包正文的 `storeVersionId`;不同快照必须使用新的 `requestId`。
|
|
112
|
+
2. 用户明确确认后,把 `confirmExecution` 精确设为 `StoreId`,提交真实持久化后台任务;只传 StoreId、可选不可变 StoreVersionId、版本和商城源定位信息,不通过 MCP/HTTP 传完整 `AppPakcet`。
|
|
96
113
|
3. 自建应用或低代码系统先用 `microi_list_applications` / `microi_get_application_context` 盘点源码,再用 `microi_get_manifest_schema`、`microi_plan_system` 与 `microi_generate_system(dryRun:true)` 干跑。
|
|
97
114
|
4. 安装任务必须回读至 `Succeeded`,再执行 `microi_validate_system`、远端资源回读和真实 UI 验收;仅返回 TaskId 不代表安装成功。
|
|
98
115
|
|
|
@@ -184,10 +201,66 @@ description: Microi 应用商城开发、打包、安装和升级规范。用于
|
|
|
184
201
|
- 通用规则:当包要求 `NOT NULL`、目标列仍可空且存在历史 `NULL` 时,必须先用包内明确声明的默认值参数化回填,再执行列约束变更;包未声明默认值时失败关闭并报告影响行数,禁止猜测业务值。该步骤必须可重复执行,并允许多节点并发重试后得到同一结果。
|
|
185
202
|
- 自动化检查:构造可空旧列及多条 `NULL` 行,断言导入器按“统计 NULL → 参数化回填 → `MODIFY ... NOT NULL`”顺序执行;覆盖字符串、整数、零行、缺失默认值、重复执行,以及商城包中全部发布协议状态字段。
|
|
186
203
|
|
|
187
|
-
## 复盘:应用新增菜单未自动授予系统管理员完整权限
|
|
204
|
+
## 复盘:应用新增菜单未自动授予系统管理员完整权限
|
|
188
205
|
|
|
189
206
|
- 触发场景:应用首次安装或版本更新新增了 `sys_menu`,菜单数据已经存在,但系统管理员看不到入口或只能执行部分按钮;再次人工到角色管理中勾选后才恢复。
|
|
190
207
|
- 根因:安装器只导入菜单,没有在同一事务内写入 `sys_rolelimit`;历史补丁又把单个管理员角色 Id 和五项旧权限硬编码,只能修复某个菜单,遗漏 `Read`、自定义按钮及其它 `Level >= 9999` 管理员角色。
|
|
191
208
|
- 通用规则:安装器只对本次真正新增或从删除状态重新引入的菜单自动授权,不扩大既有菜单的客户权限策略。目标角色必须从当前租户实时读取全部有效 `sys_role.Level >= 9999` 记录;基础权限固定为 `Read/Add/Edit/Del/Export/Import`,并合并菜单 `MoreBtns/ExportMoreBtns/BatchSelectMoreBtns/PageBtns/PageTabs/FormBtns` 中每个按钮的 `Id + Name`,不得加入 `NoDetail/NoSearch` 这类限制权限。
|
|
192
209
|
- 幂等与失败边界:已有 `sys_rolelimit` 只能合并、不得删除历史自定义权限;新增行使用“租户 + 角色 + 菜单”的确定性 Id,并在并发主键冲突后重新回读合并。找不到系统管理员、查询失败或任一权限写入失败必须让整个安装事务回滚,不能出现“菜单成功但管理员无权”的半成品。通过 FormEngine 写入以触发共享授权缓存失效。
|
|
193
|
-
- 自动化检查:覆盖多个系统管理员、已有部分权限、自定义按钮既有 JSON 字符串也有数组、删除菜单恢复、重复安装零新增、两个节点同时插入后合并,以及既有菜单更新不自动扩权;发布门同时校验独立导入器与商城包内嵌副本都包含该能力。
|
|
210
|
+
- 自动化检查:覆盖多个系统管理员、已有部分权限、自定义按钮既有 JSON 字符串也有数组、删除菜单恢复、重复安装零新增、两个节点同时插入后合并,以及既有菜单更新不自动扩权;发布门同时校验独立导入器与商城包内嵌副本都包含该能力。
|
|
211
|
+
|
|
212
|
+
## 复盘:商城发布升版打断所有后台分片安装
|
|
213
|
+
|
|
214
|
+
- 触发场景:主租户为大量子租户执行“安装/更新全部平台应用”时,某个平台包从 v7.5.17 发布到 v7.5.18;正在执行的任务在下一分片报“检查点版本与当前版本发生变化”,大量子租户同时失败。
|
|
215
|
+
- 根因:版本保护正确阻止两个包混装,但批量计划只持久化 `StoreId + AppVersion`,每个分片仍从 `sys_microistore` 易变当前行重新取包,没有使用已经存在的 `mic_data_version` 完整快照,也没有把 `StoreVersionId` 写进 checkpoint。
|
|
216
|
+
- 通用规则:后台安装首次取包必须按计划 `AppVersion` 锁定匹配的完整历史快照,并在每个分片复用同一 `StoreVersionId`;应用商城自身必须排在平台批量计划首位,先自举最新版导入器。发布中途升版不能改变既有任务的包体,也不能让既有任务自动追新;下一次批量盘点再安装新版本。
|
|
217
|
+
- 自动化检查:构造计划版本 v1.0.0、商城当前版本在分片间升到 v1.0.1,断言首次选择 v1.0.0 快照 Id,恢复分片仍请求同一 Id且成功;覆盖快照尚未生成、显式 Id 与期望版本不符、身份不符均失败关闭,并断言批量计划第一项为 `app.microi.store`。
|
|
218
|
+
|
|
219
|
+
## 复盘:父任务 Monitor 重复自举误判同版本工作器
|
|
220
|
+
|
|
221
|
+
- 触发场景:全部子租户安装任务已经创建并持续执行,父任务在 Monitor 分片中再次调用租户发现/工作器自举;子租户刚从应用包写入的商城工作器与主租户版本相同,仅 BOM 或 CRLF/LF 不同,却被判为“同版本源码不同、疑似租户定制”,父任务失败,而子任务仍在后台运行。
|
|
222
|
+
- 根因:父编排器在解析 checkpoint 阶段前无条件读取租户目录,导致 Monitor 也重复执行只应发生在 Queue 的有副作用自举;服务端源码比较又直接使用 Ordinal 原文比较,没有先消除跨平台文本格式差异。
|
|
223
|
+
- 通用规则:租户发现与商城工作器自举只允许在 Queue 阶段执行;Monitor 必须只汇总 checkpoint 中已经持久化的 `ChildTasks`。同版本源码比较只可规范化 UTF-8 BOM、CRLF/LF 和文件末尾空白;任何其它字符差异仍按租户定制失败关闭,禁止用去注释、压缩空白或模糊标记绕过保护。
|
|
224
|
+
- 自动化检查:覆盖同版本 LF/CRLF/BOM 等价且不刷新、同版本真实代码差异继续拒绝、旧版官方谱系允许升级、新版目标保留;接口引擎资源断言 Monitor 检查点标记存在且 `GetChildTenantPlatformAppMaintenanceTargets` 只位于 Queue 分支。
|
|
225
|
+
|
|
226
|
+
## 复盘:资源数量小但工作量重的应用被合并为单事务
|
|
227
|
+
|
|
228
|
+
- 触发场景:子租户批量安装进度停在“系统设置”或“系统帐号”十多分钟,心跳和 CPU 仍活跃但没有新检查点;重启后同一现象只会转移到下一个租户。
|
|
229
|
+
- 根因:批量工作器请求 `BulkAdaptiveSingleSlice`,导入器仅按表、字段、菜单和数据行数量判断“小包”,没有计入 DDL、实体生成、权限回填和历史数据迁移的真实成本,因而关闭了内部后台分片。
|
|
230
|
+
- 通用规则:后台商城安装必须始终保留有界分片和持久化检查点;旧工作器仍传单片参数时,新导入器必须安全忽略。已排队的跨租户任务在真正运行目标 V8 前,应按进程缓存执行一次官方安装器自愈,使平台修复能从原检查点接管。
|
|
231
|
+
- 自动化检查:断言批量工作器显式关闭单片参数、导入器不存在 `backgroundChunkingEnabled=false` 路径、旧单片参数只记录忽略诊断;后台执行器在子租户工作器运行前调用受信自举,并继续保留同版本真实源码差异的失败关闭保护。
|
|
232
|
+
|
|
233
|
+
## 复盘:旧租户前置物理列逐列重建耗尽首片超时
|
|
234
|
+
|
|
235
|
+
- 触发场景:已启用后台分片后,旧租户首次更新“系统设置”仍长时间没有 `ChildCheckpoint`;心跳与 CPU 正常,接近单片超时后才推进。实时 Schema 回读显示 `sys_apiengine` 与 `diy_table` 同时缺少多项生成实体固定列。
|
|
236
|
+
- 根因:导入器为兼容历史空库,在第一次 FormEngine 调用前逐列执行 `ALTER TABLE ADD`。MySQL 每个语句都可能重新准备或重建同一张元数据表,多个固定列的累计耗时发生在首个可持久化检查点之前。
|
|
237
|
+
- 通用规则:MySQL 同一张表缺少多个受信固定前置列时,必须先完整盘点,再用单条 `ALTER TABLE ... ADD ..., ADD ...` 原子补齐并回读;可信后台任务每个分片最多修改一张前置元数据表,提交 `Prerequisites` 检查点后再继续下一张。没有缺列的现代租户直接进入原 DDL 阶段,不制造空分片。并发节点已完整补齐时按幂等成功,否则保留真实表名、未补齐列和数据库错误并失败关闭。SQL Server 与 Oracle 使用各自已验证语法,不得直接套用 MySQL 批量语句。
|
|
238
|
+
- 自动化检查:独立导入器和商城包内嵌副本都必须携带批量前置列及检查点标记;断言 MySQL 路径先收集 `pendingDefinitions`、每表只拼接一次批量 ALTER、后台每片写表上限为一,且失败后逐项回读所有待补列。真实旧租户验收需证明前置列分片已提交、随后不可变 `StoreVersionId` 与字段阶段检查点继续推进。
|
|
239
|
+
|
|
240
|
+
## 复盘:父级监控遇到数据库死锁被误判为业务失败
|
|
241
|
+
|
|
242
|
+
- 触发场景:父级 Monitor 已持久化全部子任务 Id,子任务仍在正常执行且 checkpoint 中没有业务失败;父任务汇总进度时偶发数据库死锁,却因调用方配置 `MaxAttempts=1` 立即进入 `Failed`,通知中心因此把仍可成功收敛的整批任务标红。
|
|
243
|
+
- 根因:后台任务把数据库死锁、锁等待超时等基础设施瞬态竞争与接口返回失败共用同一业务重试预算。低业务重试次数无法覆盖工作器自身的领取、心跳、检查点或结果持久化竞争,也没有保留父子任务的真实运行语义。
|
|
244
|
+
- 通用规则:后台任务存储层只对已知数据库死锁、锁等待超时、序列化竞争等稳定特征启用独立的有界基础设施重试;即使业务 `MaxAttempts=1`,也允许最多三次基础设施执行机会。重试必须保留原 TaskId、父子关系、checkpoint 和已产生的副作用,不得重新创建子任务;成功后清除瞬态错误,第三次仍竞争才按原业务规则终止。普通业务错误、数据冲突和 `Value cannot be null` 等非竞争错误不得借用该预算。
|
|
245
|
+
- 自动化检查:覆盖嵌套 ProviderException 与外层包装异常、MySQL/SQL Server/PostgreSQL/Oracle 的稳定错误码或消息;断言第一次和第二次竞争回到可领取状态且不消耗业务 AttemptCount,第三次进入原终态,非竞争异常仍按 `MaxAttempts` 立即失败。真实验收必须等待原 8 个子任务全部收敛,再以 `MaxAttempts=1` 连续执行一轮完整汇总和一轮立即无操作重跑,父任务均应得到 `SucceededCount=8、FailedCount=0`。
|
|
246
|
+
|
|
247
|
+
## 复盘:字段分片完成后后台安装卡在缓存失效广播
|
|
248
|
+
|
|
249
|
+
- 触发场景:字段分片的数据库写入和 Schema 回读已经精确完成,但 `ChildCheckpoint` 长时间停在同一字段索引;任务取消也无法及时结束,进程内存、线程数和 CPU 持续增长。
|
|
250
|
+
- 根因证据:两次托管转储的调用链都停在 `V8.ApiEngine.Run -> GetApiEngineModelInternal -> MicroiTwoLevelCache.SetAsync -> PublishInvalidateAsync -> PublishWithRetryAsync`。权威 Redis 写入已经成功,随后用于通知其它节点清理一级缓存的 Pub/Sub 广播没有完成时限,因而把业务调用永久挂住;与此同时,单字段元数据更新即使只变更 Label、Remark、布局或 V8,也会重复执行物理列 DDL,放大旧租户升级成本。
|
|
251
|
+
- 通用规则:Redis 权威值写入成功后,跨节点一级缓存失效广播只能是有界、尽力而为的附属动作。队列等待和实际发布都必须有独立短超时,超时后观察迟到异常并开启短暂熔断冷却,防止悬挂发布任务无界堆积;不得因此回滚已经成功的权威写入。`UptDiyField` 只有列名或物理类型变化时才允许调用 `ChangeColumn`,显示名称、说明、布局和事件代码等纯元数据变化禁止触发 DDL。
|
|
252
|
+
- 自动化与真实验收:缓存测试必须覆盖发布永久不返回时的有界退出、迟到异常观察和冷却期抑制;字段测试必须断言只有 Name/Type 变化才进入物理 DDL。应用商城资源契约测试、后台任务与 SaaS 回归测试通过后,还必须在真实主租户完成 8/8 子租户收敛并立即执行一轮 8/8 无操作重跑。验收期间若官方应用发布了新版本,应以新的不可变 `StoreVersionId` 启动独立追赶批次,禁止混入已经开始的旧版本分片。
|
|
253
|
+
|
|
254
|
+
## 复盘:最新版后端仍放行未锁快照的旧商城工作器
|
|
255
|
+
|
|
256
|
+
- 触发场景:目标租户已经部署最新版前后端,但数据库中的 `import-microi-store-package v2.2.9` 与 `bulk-import-microi-store-packages v1.2.4` 被启动完整性检查判为合格;平台应用批量任务开始后,官方商城恰好升版,首个应用在下一分片仍从易变当前行取包并失败。
|
|
257
|
+
- 根因:后端自举门槛只校验早期版本和历史标记,没有把不可变快照、禁止自适应单片、前置物理列分片检查点及商城自举优先级纳入能力契约;MCP 单应用恢复工具也只能传 `StoreId`,无法显式锁定已经回读的 `mic_data_version` 快照。
|
|
258
|
+
- 通用规则:后端启动必须同时校验导入器最低版本与固定快照/有界分片/前置列检查点标记、批量工作器最低版本与 `StoreVersionId + BulkAdaptiveSingleSlice:false`、商城列表的自举优先级;任一缺失都必须从受信升级资源刷新,不能仅看后端二进制版本。MCP 安装/更新允许传受校验的可选 `storeVersionId`,审计同样记录该 Id;不同快照使用不同幂等请求 Id,禁止把旧任务静默改指新包。
|
|
259
|
+
- 自动化与真实验收:单元测试同时拒绝旧版本和缺标记的伪新版工作器;在真实旧租户先用固定快照完成应用商城自举,再执行全部平台应用更新并立即做零更新复跑。验收期间出现的新官方版本只进入下一独立批次,历史失败任务保留作审计,不删除或篡改。
|
|
260
|
+
|
|
261
|
+
## 复盘:本租户自助批量被误判为主租户跨租户任务
|
|
262
|
+
|
|
263
|
+
- 触发场景:普通租户在自己的应用商城点击“全部安装/更新”,后台执行器仅按固定批量工作器 Key 触发跨租户自愈,把 `owner=当前租户、target=当前租户` 当成主→子任务;旧导入器只能从自己复制自己,随后被新能力门禁拒绝,并错误提示“先更新主租户应用商城”。
|
|
264
|
+
- 根因:跨租户自愈没有校验由服务端控制面持久化的目标租户保留标记,也没有要求任务拥有者与执行租户不同;把同租户自助批量和主租户代子租户执行混成了同一作用域。
|
|
265
|
+
- 通用规则:运行前强制自愈只允许用于固定批量工作器、非空服务端目标标记、`owner != execution` 且标记精确等于执行租户的主→子任务。普通租户自助批量必须跳过跨租户复制,让持久计划按官方列表顺序优先安装/更新应用商城自身,再由新版导入器继续后续应用;不能要求官方发布源安装自己。
|
|
266
|
+
- 自动化与真实验收:单元测试覆盖同租户无标记、同租户伪标记、跨租户正确标记、标记漂移和错误工作器 Key;真实旧租户先保留旧导入器发起自助批量,断言不再出现“子租户商城工作器执行前自愈失败”,计划第一项为应用商城,全部任务成功后立即执行零更新复跑。
|
|
@@ -73,6 +73,8 @@
|
|
|
73
73
|
- 仅返回 `V8.CurrentUser.Id` 的 `ChannelType=平台内部` 记录。
|
|
74
74
|
- 支持 `PageIndex/PageSize`,`PageSize` 最大 100。
|
|
75
75
|
- `DataAppend.UnreadCount` 返回同一用户权威未读数。
|
|
76
|
+
- 每条记录统一投影 `SenderUserId/Account=AI`、`SenderName=AI助手`、`ReadOnly=false`;聊天侧只能固定一个 AI 助手联系人,并将通知权威历史与 AI 聊天历史按时间合并。
|
|
77
|
+
- 兼容旧 `MICROI_PLATFORM_ADMIN/admin` 元数据时只改显示投影,不批量删除或改写 `mic_msg_event_log` 历史事实。
|
|
76
78
|
|
|
77
79
|
### `msg_internal_mark_read`
|
|
78
80
|
|
|
@@ -80,9 +80,10 @@ UniApp 使用 Vue 3 + TypeScript 的官方 Vite 工具链,并同时遵守 `mic
|
|
|
80
80
|
2. 依次执行类型检查、单元测试、生产构建和产物静态扫描。
|
|
81
81
|
3. 检查 `dist/build` 不含源码、Token、密钥、localhost、source map 或陈旧 chunk。
|
|
82
82
|
4. 同步私有源码,再流式发布公有构建目录;源码同步失败不得继续发布。发布前回读并冻结应用的 `CurrentVersion` 与 `AppVersion`,stage 只上传不可变版本资产,finalize 必须同时提交 `ExpectedCurrentVersion` 与 `ExpectedAppVersion` 做 compare-and-set;缺一项、状态漂移或回读不一致都停止,不能自动覆盖较新发布。
|
|
83
|
-
5.
|
|
84
|
-
6.
|
|
85
|
-
7. `SharedPublicRuntime.EntryUrl`
|
|
83
|
+
5. 每次创建、修改、升级或重新发布 AI 应用,必须在任何源码同步、stage、finalize 或商城制包之前,为目标精确 `AppVersion` 写入 `sys_microistore_changelog`。日志的 `StoreId / Version / Title / ChangeType / Content / ReleaseTime` 必须完整;发布工具显式传入含义一致且非空的 `changeSummary`,发布后同时回读商城子表与 `mci_ai_app_version.ChangeSummary`。缺日志或版本不一致必须停止发布。
|
|
84
|
+
6. Web/UniApp 使用 `/{OsClient}/ai-app-publish/{AppKey}/index.html`;MicroService 使用 `/micro-app/{OsClient}/{AppKey}/index.html`。不要因技术栈相同而混淆运行类型。
|
|
85
|
+
7. 官网、二维码、分享链接和商城“立即体验”只能使用不含 `/releases/`、`/requests/`、`/versions/` 与语义版本号的稳定当前入口;不得使用 `SharedPublicRuntime.EntryUrl` 或发布结果中的不可变版本 URL。固定入口必须以代理或全屏加载壳保持浏览器地址不变,不能用 30x、`meta refresh` 或 `location.replace` 把地址栏跳到版本产物。
|
|
86
|
+
8. `SharedPublicRuntime.EntryUrl` 和 `/versions/{Version}/index.html` 仅用于历史记录、回滚、摘要校验与审计。回读应用、版本、active 文件清单和 SHA-256;旧清单文件只能可逆归档,不能删除。再分别直接请求稳定当前入口、不可变版本入口及主要 JS/CSS,并断言前者完成加载后地址栏仍不含版本段。
|
|
86
87
|
|
|
87
88
|
## 完成定义
|
|
88
89
|
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
| 组件 | 推荐类型 | 配置项 |
|
|
79
79
|
| --- | --- | --- |
|
|
80
80
|
| `RichText` | `mediumtext` | 富文本内容,图片上传遵循平台上传配置。 |
|
|
81
|
-
| `CodeEditor` | `mediumtext` | `CodeEditor.Height`。 |
|
|
81
|
+
| `CodeEditor` | `mediumtext` | `CodeEditor.Height`;`CodeEditor.DisplayMode=Inline/Dialog`,配置项很多或同页多个代码字段时优先 `Dialog`。 |
|
|
82
82
|
| `JsonTable` | `mediumtext` | JSON 表格展示/编辑,保存结构化 JSON;配置必须写在 `Config.JsonTable`。 |
|
|
83
83
|
| `ImgUpload` | `mediumtext` | `ImgUpload.Limit`、`Multiple`、`Tips`、`MaxCount`、`ShowFileList`、`Preview`、`MaxSize`。 |
|
|
84
84
|
| `FileUpload` | `mediumtext` | `FileUpload.Limit`、`Multiple`、`Tips`、`MaxCount`、`ShowFileList`、`MaxSize`。 |
|
|
@@ -36,7 +36,29 @@ Config/Data、菜单查询列与缓存保持一致。
|
|
|
36
36
|
`FormWidth=24`,普通字段省略。`CollapseGroup` 属于整行控件,必须显式保存
|
|
37
37
|
`FormWidth=24`,且 `Config.CollapseGroup.ShowFieldCount` 默认补为 `true`。
|
|
38
38
|
6. 绑定菜单后补齐/允许平台推断列表列、搜索列、隐藏列、排序列、移动端列和默认排序。
|
|
39
|
-
7. 回读 `diy_field`、刷新 schema 缓存,再在真实新增/编辑/查看表单中验收。
|
|
39
|
+
7. 回读 `diy_field`、刷新 schema 缓存,再在真实新增/编辑/查看表单中验收。
|
|
40
|
+
|
|
41
|
+
## 上传字段配置(AI 生成时强制)
|
|
42
|
+
|
|
43
|
+
- 图片使用 `Config.ImgUpload`,至少明确 `Limit`、`Multiple`、`MaxCount`、`Preview`、
|
|
44
|
+
`MaxSize` 和 `Crop`;文件使用 `Config.FileUpload`,至少明确 `Limit`、`Multiple`、
|
|
45
|
+
`MaxCount`、`MaxSize`。完整键和值域读取 `references/component-catalog.md`。
|
|
46
|
+
- `ImgUpload.Preview` 未配置时默认开启压缩;普通业务图片优先保持开启。裁剪前的原图无论
|
|
47
|
+
展示图配置为公有或私有、是否压缩,都必须保存在 HDFS 私有桶,业务字段不得保存原图路径。
|
|
48
|
+
- `ImgUpload.Crop.Enabled` 只控制表单打开时是否默认选中裁剪。运行时的裁剪开关、存储范围、
|
|
49
|
+
单/多图数量、压缩状态和最大体积统一显示在紧凑上传面板中;不得把 `Enabled=false` 误解为
|
|
50
|
+
禁止用户裁剪。`Mode` 只允许 `free/fixed/select`。
|
|
51
|
+
- 图片和文件的拖放区都使用同一紧凑配置面板。`Multiple=true` 时必须设置业务合理的
|
|
52
|
+
`MaxCount`;`MaxSize` 单位为 MB,字段限制只能收紧租户/平台上限,不能放大。
|
|
53
|
+
- 富文本使用 `Config.RichText`:必须明确 `Limit`,并按需配置
|
|
54
|
+
`Image.Enabled/MaxSize/MaxCount/Preview/CompressMaxSize/CompressMaxWidth`、
|
|
55
|
+
`Video.Enabled/MaxSize/MaxCount`、`File.Enabled/MaxSize/MaxCount/Accept`。公开公告、商品详情
|
|
56
|
+
等匿名正文显式使用 `Limit=false`;内部正文使用 `true`。旧字段缺失配置时安全默认为私有桶,
|
|
57
|
+
图片默认压缩到约 500 KB、最长边 1920 px。
|
|
58
|
+
- 私有富文本只能持久化稳定对象标识,禁止把 HDFS 签名 URL、审计代理 Ticket 或 DiyToken 写入
|
|
59
|
+
HTML。每次查看/编辑按当前菜单、表、记录和字段权限换取新短效地址;外部匿名页面没有此权限
|
|
60
|
+
上下文,因此不能把私有 RichText 当作公开正文。普通交互式帐号也不能用 `Limit=false` 绕过
|
|
61
|
+
后端强制私有策略。
|
|
40
62
|
|
|
41
63
|
新建表/模块时,除非用户显式指定或表单达到极重阈值(约 36+ 业务字段、2+ 子表或同等
|
|
42
64
|
重型控件密度),默认保存 `diy_table.FormOpenType=Dialog` 与 `FormOpenWidth=80%`。
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
| `StaticText` | 静态文本 | 不承载业务状态 |
|
|
37
37
|
| `Html` | 可信 HTML 展示 | 必须净化,不拼接不可信内容 |
|
|
38
38
|
| `RichText` | 富文本 | `mediumtext`;输出需净化 |
|
|
39
|
-
| `CodeEditor` | 代码/JSON/SQL 编辑 | `mediumtext`;通常 `FormWidth=24` |
|
|
39
|
+
| `CodeEditor` | 代码/JSON/SQL 编辑 | `mediumtext`;通常 `FormWidth=24`;长配置表单使用 `Config.CodeEditor.DisplayMode=Dialog`,默认只渲染“编辑代码(N字)”按钮;代码工作台可用 `Inline` |
|
|
40
40
|
| `JsonTable` | JSON 表格 | `mediumtext`;定义结构与大小上限 |
|
|
41
41
|
|
|
42
42
|
## 文件与高级输入
|
|
@@ -62,12 +62,23 @@
|
|
|
62
62
|
| `JoinTable` | 关联集合展示 | 查询与权限在服务端完成 |
|
|
63
63
|
| `JoinForm` | 嵌入一个独立记录的完整表单 | 主表字段保存一个目标 Id;目标表不能与当前表相同 |
|
|
64
64
|
| `TableChild` | 主表内嵌 0..N 条明细列表 | 独立子表、子表真实外键、隐藏子菜单、回查索引 |
|
|
65
|
-
| `Map` | 点位 |
|
|
66
|
-
| `MapArea` | 区域 | `mediumtext
|
|
65
|
+
| `Map` | 点位 | 高德/百度/腾讯;`Config.MapCompany=System/AMap/Baidu/Tencent`;凭据只进租户“安全与服务接入”,不得写字段配置或公开 SysConfig |
|
|
66
|
+
| `MapArea` | 区域 | 与 `Map` 共用供应商安全配置;`mediumtext` 保存 `Paths`,限制路径、点数和体积 |
|
|
67
67
|
| `Qrcode` | 二维码卡片展示 | 优先 `IsVirtual=1`;扫码原文另存普通 `varchar` 字段 |
|
|
68
68
|
| `FontAwesome` | 图标选择 | `varchar(200)` |
|
|
69
69
|
| `DevComponent` | 主前端定制 Vue 控件 | 仅用于长期复用且标准控件无法满足的场景 |
|
|
70
70
|
|
|
71
|
+
### `Map / MapArea` 运行时与安全边界
|
|
72
|
+
|
|
73
|
+
- 渲染事实源是 `Microi.Client/src/views/form-engine/diy-field-component/diy-map.vue`;公共错误分类与安全配置请求在同目录 `map-runtime.js`。
|
|
74
|
+
- 字段只保存 `Config.MapCompany`,值为 `System / AMap / Baidu / Tencent`。禁止把 Key、securityJsCode、Secret 或代理凭据写入 `diy_field.Config`、V8 前端事件、公开 `sys_config` 投影或前端构建变量。
|
|
75
|
+
- 租户凭据使用 `mci_system_setting` 的 `Map.*` 模板,在“系统设置 → 安全与服务接入”由超级管理员维护。运行时由可信后端按 DiyToken 租户和当前供应商做白名单投影,只返回一家的 `ClientKey`,必须 `no-store` 并拒绝访问密钥会话。
|
|
76
|
+
- 旧 `sys_config.AMapKey / AMapSecret / BaiduAK` 仅在对应新设置未启用时兼容回退。不要为迁移直接重新公开这些字段。
|
|
77
|
+
- 旧字段 `Config` 中的 `MapKey / MapSecret / AMapKey / AMapSecret / BaiduAK / TencentMapKey` 等明文属性不属于运行时配置;设计器保存地图配置时必须清除。迁移顺序固定为“先写入并启用租户 `Map.*` Secret,再清理字段元数据”。
|
|
78
|
+
- 浏览器 JS Key 天然可见,必须配置供应商域名/Referer 白名单;高德生产环境优先配置 `Map.AMap.ServiceHost`,存在代理时不得再返回 `SecurityJsCode`。
|
|
79
|
+
- 加载中、缺少 Key、运行时接口不匹配、SDK 网络/超时/鉴权/域名/WebGL/容器尺寸错误必须在控件区域显示明确原因码和重试入口,禁止只 `console.warn/error` 后留下空白地图。
|
|
80
|
+
- `Map` 保持 `{Name}_Lng / {Name}_Lat / {Name}.{Address,Center,Zoom}`;`MapArea` 保持 `{Name}.{Paths,Center,Zoom}`。三家供应商切换不得改变持久化格式。
|
|
81
|
+
|
|
71
82
|
### `JoinForm` 不是子表
|
|
72
83
|
|
|
73
84
|
- `JoinForm` 渲染 `diy-form`,通过 `Config.JoinForm.JoinFieldName` 从当前表单取出一个
|
|
@@ -132,13 +143,73 @@ if (V8.LoadMode !== 'Design') {
|
|
|
132
143
|
| CodeEditor / JsonTable | `CodeEditor.Height`、`JsonTable.Columns`、`JsonTable.Columns[].Config` |
|
|
133
144
|
| JoinForm | `JoinForm.TableId`、`JoinForm.TableName`、`JoinForm.JoinFieldName`、`JoinForm.FormMode`、`JoinForm.Id`、`JoinForm._SearchEqual` |
|
|
134
145
|
| TableChild | Config 根节点的 `TableChildTableId`、`TableChildSysMenuId`、`TableChildFkFieldName`;`TableChild.PrimaryTableFieldName`(默认 `Id`)及分页/导入选项 |
|
|
135
|
-
| ImgUpload | `ImgUpload.Multiple
|
|
146
|
+
| ImgUpload | `ImgUpload.Limit/Multiple/MaxCount/Tips/Preview/MaxSize/SaveFullPath`;`ImgUpload.Crop.Enabled` 仅表示默认开启,另有 `Mode=free/fixed/select`、`Ratio`、`CustomWidth/CustomHeight`、`AllowZoom/AllowRotate/AllowFlip`;运行时在上传面板内提供裁剪开关,裁剪弹层提供“不裁剪直接上传”;导出时会按最大图片数展开列 |
|
|
147
|
+
| FileUpload | `FileUpload.Limit/Multiple/MaxCount/Tips/MaxSize/SaveFullPath`,以及 Office 预览/编辑/版本配置;文件不使用 `ImgUpload.Preview/Crop` |
|
|
148
|
+
| RichText | `RichText.Limit`;`Image.Enabled/MaxSize/MaxCount/Preview/CompressMaxSize/CompressMaxWidth`;`Video.Enabled/MaxSize/MaxCount`;`File.Enabled/MaxSize/MaxCount/Accept`;私有正文存稳定标识而不是临时 URL |
|
|
136
149
|
| Qrcode | `Qrcode.DisplayWidth`、`Qrcode.ShowDownload`、`Qrcode.DownloadText`;扫码内容使用运行态 `DataAppend.Code` |
|
|
137
150
|
|
|
138
151
|
其余选择、树、上传、关联和布局选项以当前字段设计器和
|
|
139
152
|
`microi-db-schema/references/form-component-options.md` 为事实源;不要凭旧截图
|
|
140
153
|
发明配置键。
|
|
141
154
|
|
|
155
|
+
### `ImgUpload / FileUpload` 生成与运行时规则
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"ImgUpload": {
|
|
160
|
+
"Limit": true,
|
|
161
|
+
"Multiple": true,
|
|
162
|
+
"MaxCount": 6,
|
|
163
|
+
"Tips": "支持 JPG、PNG、WebP",
|
|
164
|
+
"Preview": true,
|
|
165
|
+
"MaxSize": 10,
|
|
166
|
+
"SaveFullPath": false,
|
|
167
|
+
"Crop": {
|
|
168
|
+
"Enabled": true,
|
|
169
|
+
"Mode": "select",
|
|
170
|
+
"Ratio": "16:9",
|
|
171
|
+
"CustomWidth": 1,
|
|
172
|
+
"CustomHeight": 1,
|
|
173
|
+
"AllowZoom": true,
|
|
174
|
+
"AllowRotate": true,
|
|
175
|
+
"AllowFlip": true
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
- `Limit=true` 表示字段配置为私有桶,`false` 表示配置为公有桶;最终访问仍服从后端租户权限和上传安全策略。
|
|
182
|
+
- `Multiple=true` 时 `MaxCount` 必须是正整数;`MaxSize` 单位为 MB。`Preview` 未配置时按 `true` 压缩,普通列表、卡片、商品图不要关闭。
|
|
183
|
+
- `Crop.Enabled` 只决定运行时裁剪开关的初始状态;`false` 或缺失时用户仍可在紧凑上传面板主动开启。裁剪前原图始终进入 HDFS 私有桶,业务字段只保存展示图元数据。
|
|
184
|
+
- 图片和文件都把拖放提示、存储范围、单/多文件、最大数量、处理方式和最大体积合并到同一个紧凑面板;不要在字段外再生成重复说明卡片。
|
|
185
|
+
|
|
186
|
+
### `RichText` 生成与运行时规则
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"RichText": {
|
|
191
|
+
"EditorProduct": "WangEditor",
|
|
192
|
+
"Limit": true,
|
|
193
|
+
"Image": {
|
|
194
|
+
"Enabled": true,
|
|
195
|
+
"MaxSize": 20,
|
|
196
|
+
"MaxCount": 10,
|
|
197
|
+
"Preview": true,
|
|
198
|
+
"CompressMaxSize": 500,
|
|
199
|
+
"CompressMaxWidth": 1920
|
|
200
|
+
},
|
|
201
|
+
"Video": { "Enabled": true, "MaxSize": 200, "MaxCount": 3 },
|
|
202
|
+
"File": { "Enabled": true, "MaxSize": 100, "MaxCount": 10, "Accept": "" }
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
- 公开公告、商品详情等匿名网页内容显式用 `Limit=false`;内部公告、合同说明等用 `true`。旧字段缺失时默认私有,不能由 AI 猜成公有。
|
|
208
|
+
- `MaxSize` 单位 MB,`CompressMaxSize` 单位 KB。图片压缩开启时原图仍先进入 HDFS 私有桶,正文只引用展示图。
|
|
209
|
+
- 私有正文只保存 `/__microi_richtext_private__/...` 稳定标识;运行时携带当前菜单、表、记录和字段上下文换取短效代理 URL,禁止把临时 Token/Ticket 回写字段。
|
|
210
|
+
- 普通文件通过富文本工具栏附件入口插入 `a.href`;私有授权只接受真实 `img/video/source.src` 与 `a.href` 的精确路径,不接受正文文字、`data-*` 或脚本标签。
|
|
211
|
+
- RichText 通常使用 `FormWidth=24`,配置摘要保持单行紧凑,不要再生成独立的大说明卡。
|
|
212
|
+
|
|
142
213
|
## 宽度与重字段
|
|
143
214
|
|
|
144
215
|
- 普通 Text、Select、NumberText、DateTime 默认不写 `FormWidth`。
|
|
@@ -169,3 +169,7 @@ if (ctx.token && ctx.token !== appliedHostToken) {
|
|
|
169
169
|
|
|
170
170
|
普通 `request`、浏览器 `fetch(FormData)` 上传和 `uni.uploadFile` 都必须读取响应头的新 Token。验收时必须连续执行至少两个需要登录态的请求(前一个允许发生 Token 轮换),确认后一个仍返回 `Code=1`;不能只看页面首屏渲染成功。
|
|
171
171
|
<!-- /microi-progressive:chunk -->
|
|
172
|
+
|
|
173
|
+
## 运行时 ApiBase / OsClient 切换
|
|
174
|
+
|
|
175
|
+
允许用户切换平台的客户端必须把 `ApiBase + OsClient` 视为完整安全边界,而不是只替换请求 URL。候选端点应先匿名探测,成功后再原子更新配置并清除旧 Token、用户和平台派生缓存;账号、RSA 密文、菜单、表元数据和页面状态不得跨边界复用。SDK 每次修改 `apiBase` 或 `osClient` 都必须推进端点代次,请求记录发起时代次,并在处理响应头 Token、鉴权失效或响应体之前拒绝旧代次的迟到响应。验收至少覆盖“旧平台登录请求未返回 -> 切换平台 -> 旧响应携带 Token 返回”,并确认旧 Token 没有写入、新请求只发送一个新 `osclient`。
|
|
@@ -104,6 +104,7 @@ AppKey 稳定且只含安全字符。`microi.routes.json` 是页面事实源,
|
|
|
104
104
|
- 创建/更新元数据:`microi_create_microservice`。
|
|
105
105
|
- 同步私有源码:`microi_sync_microservice_source`;本地工程必须优先传 `directory`,不构造 Base64 文件数组。
|
|
106
106
|
- 真实编译目录优先 `microi_publish_application_directory_stream` 流式发布。
|
|
107
|
+
- 每次创建、修改、升级或重新发布微服务,必须先为目标精确 `AppVersion` 在 `sys_microistore_changelog` 写入完整日志,再同步源码、stage、finalize 或制作商城包。日志必须关联真实 `StoreId`,包含 `Title / ChangeType / Content / ReleaseTime`;流式发布显式传入与日志含义一致的非空 `changeSummary`。发布后同时回读商城日志、`mci_ai_app_version.ChangeSummary` 与包内 `PackageInfo.ChangeLog`;缺失或版本不一致必须失败关闭。
|
|
107
108
|
- 发布动作必须明确区分两种模式:默认“源码+编译产物”先把完整工程同步到私有桶并逐文件回读 SHA-256,再把 `dist` 流式发布到公有桶;显式“仅编译产物”只更新公有桶,必须在界面中告知其他用户仍会拉取上一次私有源码,禁止暗示源码已同步。
|
|
108
109
|
- 私有源码同步使用 `ReplacePrivateSourceOnly` 精确清理过期源码;兼容调用可以继续接受 `replace`,但实现不得用旧式全表 `Replace=true` 删除同一应用的公有运行产物元数据。
|
|
109
110
|
- `mci_ai_app_file` 同时存在私有源码和公有编译产物。源码拉取/差异比较必须优先按 `StorageScope=PublicBuildStream|PublicBuildStreamArchived|PublicBuildOnly` 排除公有产物,并保留旧数据中 `HdfsPath == PublishHdfsPath` 的兼容判断;不能仅靠两个路径相等识别,否则版本路径与稳定别名不同的流式产物会被误读成私有源码。
|
|
@@ -207,3 +207,7 @@ Microi.Client 的标准模块移动端不应把 PC 表格字段机械纵向堆
|
|
|
207
207
|
- 构建 H5 和微信小程序目标。
|
|
208
208
|
|
|
209
209
|
<!-- /microi-progressive:chunk -->
|
|
210
|
+
|
|
211
|
+
## 平台方通用 App 的登录连接器例外
|
|
212
|
+
|
|
213
|
+
“登录页不要展示 ApiBase / OsClient”仍是 H5、小程序与客户专属 App 的默认规则。只有用户明确要求、并由平台方提交一个聚合多租户的通用 `APP-PLUS` 安装包时,才允许把平台连接器作为登录页次级折叠卡片;必须保留清晰的当前连接摘要、固定协议下拉、HTTP 风险提示、带图标的应用按钮、连接 loading/disabled 状态,并在展开后通过滚动和安全区保证小屏设备不裁切登录操作。连接器不能伪装成调试面板,也不能展示 Token、密码或其它秘密。
|
|
@@ -9,7 +9,15 @@ description: Microi 吾码 UniApp/H5 前端通用规范。用于构建或修复
|
|
|
9
9
|
|
|
10
10
|
本 Skill 适用于任何 Microi 吾码 UniApp/H5 项目,包括商城、OA、ERP、MES、CRM、互联网项目、预约项目等。不要把规则写成某一个业务应用专属规范。
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## 图片上传默认参数(强制)
|
|
13
|
+
|
|
14
|
+
UniApp/H5/小程序必须通过项目统一 `microi.v8.js` 的 `V8.uploadFile` / `V8.uploadFiles` 上传图片。调用方省略 `options.preview` 时,SDK 必须发送 `Preview=true` 并默认使用 `img` 路径;只有显式 `preview:false` 才允许关闭。服务端仍是最终事实源:即使旧客户端完全不传该字段,也要默认压缩到约 `500 KB`、最长边约 `1920 px`,并在 HDFS 私有桶保留一份 `_origin` 原图。页面不得为了“上传成功”自行改成 `preview:false`,也不得把私有原图或临时签名地址保存进业务字段。
|
|
15
|
+
|
|
16
|
+
## 平台方通用 App 登录连接器(明确例外)
|
|
17
|
+
|
|
18
|
+
登录页默认不得展示 ApiBase、OsClient 或调试配置;但用户明确要求、且安装包由 Microi 平台方作为多租户聚合客户端发布时,允许仅在 `APP-PLUS` 登录页提供通用连接器。协议必须使用固定 `https://` / `http://` 下拉框,地址框禁止重复输入协议,HTTPS 默认,HTTP 显示明文风险并二次确认;H5、小程序和客户专属包不得因此自动开放。候选地址先匿名读取 `GetSysConfig`,验证成功后再持久化。真正切换时必须清除旧 DiyToken、用户、SignalR、菜单/元数据/页面缓存,按 `ApiBase + OsClient` 隔离记住的账号及 RSA 密文,并用端点代次拒绝切换前的迟到响应。支持任意 HTTP 时,最终 IPA 必须显式包含 ATS 例外,Android 安装包必须显式包含 cleartext 例外;不需要任意 HTTP 的正式包应保持平台默认安全策略,iOS ATS 例外还必须在 App Store 审核中说明。
|
|
19
|
+
|
|
20
|
+
<!-- microi-progressive:begin -->
|
|
13
21
|
<!-- microi-progressive:chunk id=microi-uniapp-frontend-000 sha256=ecb0fc85b5c3b15ac79c9049ca86de8c586d4ce3a6c975255464069d89f87ac4 -->
|
|
14
22
|
## 移动端质量门禁必须先读
|
|
15
23
|
|
|
@@ -150,7 +150,7 @@ return {
|
|
|
150
150
|
| `NumberFormat/HeaderStyle/Style` | 数字格式与列级样式 |
|
|
151
151
|
|
|
152
152
|
<!-- /microi-progressive:chunk -->
|
|
153
|
-
<!-- microi-progressive:chunk id=v8-export-import-003 sha256=
|
|
153
|
+
<!-- microi-progressive:chunk id=v8-export-import-003 sha256=75977093346f025e91041b36bdb7887e2cacee854800c1f43e407e8fc037a166 -->
|
|
154
154
|
## 解析上传的 Excel(导入)
|
|
155
155
|
|
|
156
156
|
```javascript
|
|
@@ -160,23 +160,26 @@ if (!filesByteBase64) return { Code: 0, Msg: '请上传 Excel 文件' };
|
|
|
160
160
|
|
|
161
161
|
var base64 = Object.values(filesByteBase64)[0];
|
|
162
162
|
|
|
163
|
-
//
|
|
164
|
-
var parsed = V8.Office.ExcelToList({
|
|
165
|
-
FileByteBase64: base64,
|
|
166
|
-
SheetIndex: 0
|
|
163
|
+
// 可直接解析旧的首行表头模板
|
|
164
|
+
var parsed = V8.Office.ExcelToList({
|
|
165
|
+
FileByteBase64: base64,
|
|
166
|
+
SheetIndex: 0
|
|
167
167
|
});
|
|
168
168
|
if (parsed.Code !== 1) return parsed;
|
|
169
169
|
|
|
170
|
-
var dataList = parsed.Data; // [{ 列标题: 值, ... }, ...]
|
|
170
|
+
var dataList = parsed.Data; // [{ 列标题: 值, ... }, ...]
|
|
171
171
|
return { Code: 1, Data: dataList, DataCount: dataList.length };
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
+
`ExcelToList` 的增强参数为 `HeaderStartRow/HeaderEndRow/DataStartRow/DataEndRow/Columns/MaxDataRows/MaxColumns`。除 `SheetIndex` 和 `Columns[].ColumnIndex` 从 `0` 开始外,行号都从 `1` 开始;传增强范围后每行带 `_ExcelRow`。参数全省略时继续兼容“首行表头、第二行开始数据”。
|
|
175
|
+
|
|
174
176
|
### 固定版式模板与后台自定义导入
|
|
175
177
|
|
|
176
|
-
|
|
178
|
+
通用【导入】和 `V8.OpenImportDialog` 共用智能导入弹层:默认宽度 `80%`,选择文件后自动识别工作表、单行/多级合并表头、首条与末条数据行和字段映射;先按每页 `15` 条预览,用户确认后才写入。低可信度时必须允许用户人工指定表头/数据起止行和逐列映射。模板顶部图片、标题、说明文字以及 A 列为空的数据行都不能破坏识别。
|
|
177
179
|
|
|
178
|
-
- 页面 V8
|
|
179
|
-
- 后台接口引擎从 `V8.Param._ImportRowsJson` 和 `_ImportMetaJson`
|
|
180
|
+
- 页面 V8 可只声明 `ApiEngineKey`;`Workbook.Cells/Columns/HeaderStartRow/HeaderEndRow/DataStartRow/DataEndRow/KeyField` 均为模板提示或固定约束,不传时自动识别。不得拼上传 DOM、传完整工作簿 Base64 或自行轮询。
|
|
181
|
+
- `V8.OpenImportDialog` 后台接口引擎从 `V8.Param._ImportRowsJson` 和 `_ImportMetaJson` 取值;必须重做模板、权限、字段、唯一性和状态校验。
|
|
182
|
+
- 菜单【导入接口替换】仍接收原始文件 `V8.FilesByteBase64`,并新增 `_ImportMetaJson`。接口引擎必须把元数据里的 `SheetIndex/HeaderStartRow/HeaderEndRow/DataStartRow/DataEndRow/Columns` 传给 `V8.Office.ExcelToList`,由服务端按同一范围重读原文件,不能只信任浏览器预览,也不能固定读取第一行。
|
|
180
183
|
- 先校验全部行再写入;接口引擎返回 `Code != 1` 时依靠平台事务整体回滚,禁止手动 Commit/Rollback。
|
|
181
184
|
- 用 `V8.Method.UpdateBackgroundTask({Current,Total,Msg,Log})` 上报真实校验/写入工作量;未知总量保持不确定进度,不伪造百分比。
|
|
182
185
|
- 业务幂等键使用后台任务 Id 或明确的导入操作 Id;重试前回读批次,避免重复写入。
|
|
@@ -10,8 +10,33 @@ description: Microi V8 与 MCP 文件上传下载指南。用于处理流式 AI
|
|
|
10
10
|
你正在为 Microi 吾码平台编写文件上传/下载/返回相关代码。平台分布式存储(HDFS)支持阿里云OSS、MinIO、亚马逊S3,存储方案由 SaaS 引擎按租户配置。
|
|
11
11
|
|
|
12
12
|
公开入口覆盖 `V8.uploadFile`、多文件 `V8.uploadFiles` 与 MCP `microi_upload_file_base64`。多文件上传必须限制并发、逐文件返回结果;Base64 工具只接受明确文件名、大小和租户内目标范围,写后回读路径、大小与哈希。
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
|
|
14
|
+
## 交互式图片默认压缩(强制)
|
|
15
|
+
|
|
16
|
+
- `ImgUpload`、PC、UniApp/H5/小程序以及 MCP 普通图片上传在未显式传 `Preview` 时,必须按 `Preview=true` 处理;字段设计器新配置默认开启。只有业务明确要求公开原始画质时才允许显式关闭,不能把“客户端漏传”解释为关闭。
|
|
17
|
+
- 默认展示图目标为不超过约 `500 KB`、最长边不超过 `1920 px`;可按真实用途进一步收紧。压缩必须使用 Windows/Linux/容器一致的跨平台实现,并限制输入字节、像素总量与解码并发,避免超大图触发 OOM。
|
|
18
|
+
- 压缩流程固定为“先将原始字节写入当前租户 HDFS 私有桶的 `_origin` 对象 → 生成压缩展示图 → 写入目标公有/私有位置 → 回读大小与格式”。即使展示图是公有资源,原图也只能保存在私有桶。
|
|
19
|
+
- 压缩、解码或编码失败时必须失败关闭,返回可诊断错误;禁止静默把几十 MB 的未压缩原图发布到公有桶。返回字段中的 `Size` 应表示展示图实际字节数,`OriginalSize` 可用于管理员审计,但业务字段不得保存私有桶真实地址或签名 URL。
|
|
20
|
+
- 历史治理只迁移超过目标体积的图片:先为旧对象补齐私有原图副本,再上传压缩展示图、原子更新全部业务引用并逐条回读。确认没有引用后才删除旧公有对象;批量任务要有清单、检查点、幂等映射和失败重试,不能边扫描边不可逆覆盖。
|
|
21
|
+
|
|
22
|
+
## 表单引擎图片裁剪(强制)
|
|
23
|
+
|
|
24
|
+
- `ImgUpload.Crop` 支持 `Enabled`、`Mode=free/fixed/select`、`Ratio`、`CustomWidth/CustomHeight`以及 `AllowZoom/AllowRotate/AllowFlip`。`Enabled` 只表示表单用户的默认状态,不得当作裁剪能力总开关;新增/编辑表单把裁剪开关合并到紧凑上传面板,旁边同时显示公有/私有桶、单/多图与最大数量、压缩状态和最大体积。旧字段未配置时该开关默认关闭,但用户仍可主动开启。
|
|
25
|
+
- 裁剪弹层必须同时提供“取消本次上传”“不裁剪直接上传”“应用裁剪并上传”三个不同动作。多图选择按队列逐张处理;直接上传只跳过当前图片的裁剪,不能取消或阻塞后续图片。
|
|
26
|
+
- 多图模式下后端可能为每个单文件请求返回 `Data: [{...}]`,单图模式返回 `Data: {...}`。PC/移动端必须先归一化对象/数组,再按客户端 `uid` 替换上传占位项并生成预览 URL,禁止把接口成功误显示成空列表。
|
|
27
|
+
- 开启裁剪时,前端必须上传最终裁剪图,并在同一 multipart 请求中以 `MicroiOriginalFile` 附带同名、未改动的原图及 `CropEnabled=true`。不得仅传坐标后由后端重演,否则 EXIF 方向、旋转或镜像可能导致前后端结果不一致。
|
|
28
|
+
- 后端必须校验裁剪图与原图一一同名,两者字节数都计入单次限制和每日配额,但原图不计为第二个业务文件。未宣告裁剪却传原图、宣告裁剪却漏传/错配原图都要失败关闭。
|
|
29
|
+
- HDFS 写入顺序固定为“未改动原图写入私有 `_origin` 对象 → 可选压缩裁剪图 → 写入业务展示图”。裁剪原图写入失败时不得发布展示图;即使 `Preview=false`,裁剪原图仍必须私有保留。不得返回或持久化原图真实路径。
|
|
30
|
+
|
|
31
|
+
## 富文本图片、视频与附件(强制)
|
|
32
|
+
|
|
33
|
+
- `RichText.Limit=false` 只用于需匿名长期访问的官网公告、商品详情等公开正文;内部内容用 `true`。普通交互式帐号即使传 `false`,后端仍可按安全策略强制私有,客户端必须以上传响应的实际 `Limit` 为准。
|
|
34
|
+
- RichText 分别配置 `Image`、`Video`、`File` 的 `Enabled/MaxSize/MaxCount`;图片另传 `Preview/CompressMaxSize/CompressMaxWidth`,并继续遵循“原图私有、展示图公有或私有”的压缩链路。附件类型白名单用 `File.Accept` 进一步收紧,不能放宽服务端白名单。
|
|
35
|
+
- 私有正文持久化 `/__microi_richtext_private__/...` 稳定对象标识,严禁保存对象存储签名 URL、`OpenPrivateFile` Ticket、DiyToken 或其它会过期的凭据。每次打开记录时携带 `FormEngineKey/FormDataId/FieldId/SysMenuId` 批量换取短效审计代理地址。
|
|
36
|
+
- 私有文件后端授权必须重新校验当前租户、菜单、表、行和 RichText 字段,并确认所请求路径精确存在于 `img/video/source.src` 或 `a.href`;正文文字、`data-src/data-href`、脚本标签和前缀相似路径都必须失败关闭。
|
|
37
|
+
- 外部匿名页面没有后台记录权限上下文,不能解析私有标识。公开文章必须由有权发布公有资产的超级管理员显式使用公有桶,不得通过延长私有 URL 有效期模拟公开资源。
|
|
38
|
+
|
|
39
|
+
<!-- microi-progressive:begin -->
|
|
15
40
|
<!-- microi-progressive:chunk id=v8-file-upload-000 sha256=b48ce09f93a43efd30e700af637db3881355e8d2baaf45165ea2bd0bdfda25cf -->
|
|
16
41
|
## 核心 API
|
|
17
42
|
|
|
@@ -87,7 +112,7 @@ Unity `Data`、WASM、Windows 安装包、视频模型等发布资产不得进
|
|
|
87
112
|
1. **租户业务配置**:有效正数/布尔值按 `sys_osclients` 当前租户 → 代码默认值解析。租户可以按业务需要提高或降低默认值,不要求安装者维护额外环境变量或修改 `appsettings`。
|
|
88
113
|
2. **平台绝对上限**:最终业务值再与代码内固定灾难保护上限取较小值,租户和安装参数都不能放大。
|
|
89
114
|
3. **HTTP 解析上限**:Kestrel 请求正文与 Multipart 固定为 2048 MB,普通表单单值固定为 128 MB,是所有租户共享的请求解析硬顶。
|
|
90
|
-
4. **字段级限制**:前端 `FileUpload` / `ImgUpload` 的 `MaxSize`、`MaxCount` 等只能与当前租户有效值取更小值,不能提高后端上限,也不能替代服务端校验。
|
|
115
|
+
4. **字段级限制**:前端 `FileUpload` / `ImgUpload` / `RichText` 的 `MaxSize`、`MaxCount` 等只能与当前租户有效值取更小值,不能提高后端上限,也不能替代服务端校验。
|
|
91
116
|
|
|
92
117
|
业务配置与固定边界:
|
|
93
118
|
|
|
@@ -134,7 +134,7 @@ var url = V8.Method.GetPrivateFileUrl({
|
|
|
134
134
|
```
|
|
135
135
|
|
|
136
136
|
- 普通客户端调用 `/api/HDFS/GetPrivateFileUrl` 时,不能只提交 `FilePathName`,必须同时提交 `FormEngineKey`、`FormDataId`、`FieldId`、`SysMenuId`。服务端校验菜单、菜单绑定表、记录数据范围、字段归属以及字段值确实引用该路径后,才签发临时票据。
|
|
137
|
-
- `FieldId` 必须属于目标表,且组件为 `FileUpload` 或 `
|
|
137
|
+
- `FieldId` 必须属于目标表,且组件为 `FileUpload`、`ImgUpload` 或 `RichText`;`SysMenuId` 必须是当前用户真实拥有、并绑定目标表的菜单。RichText 还必须在真实 `img/video/source.src` 或 `a.href` 中精确引用请求路径,普通文字、`data-*` 和脚本标签不算授权依据。
|
|
138
138
|
- 普通用户禁止通过该入口直接取得私有文件 `Byte` / `Stream`。签发失败时不能回退裸路径、真实对象存储签名地址或公有 URL。
|
|
139
139
|
- 私有文件访问必须经过后端短期票据代理:签发链接时记录当前登录用户,实际 `GET/HEAD` 打开或下载时再记录一次访问行为;支持 `Range` 流式响应,并对同一次分片请求做短时去重,不能把文件完整读入内存。
|
|
140
140
|
- 审计代理由平台后端回源对象存储,必须使用服务端内网端点生成上游地址,不能先生成公网 MinIO 签名地址再让后端绕公网回源。否则同一对象经内网上传成功后,可能在公网端点表现为 404。
|
|
@@ -32,7 +32,7 @@ V8.ClientModel // OsClientModel 的兼容别名,同样是脱敏副本
|
|
|
32
32
|
V8.SysConfig // 当前租户系统配置根对象;不存在 PublicSettings 属性
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
前端 V8 的 `V8.SysConfig` 是匿名 `GetSysConfig`
|
|
35
|
+
前端 V8 的 `V8.SysConfig` 是匿名 `GetSysConfig` 的独立脱敏 `sys_config` 副本;`mci_system_setting` 的任何记录都不会进入浏览器。后端接口引擎与后端 V8 事件的 `V8.SysConfig` 包含当前租户完整、独立的 `sys_config`,后端私密设置统一位于 `V8.SysConfig.ServerPrivateSettings`,其中 Secret 由可信后端解密。两端都不存在 `PublicSettings` 包装层。后端可使用 Secret,但严禁返回前端、写日志或写审计。子租户显式传其它 `OsClient` 仍会被强制改回当前租户。
|
|
36
36
|
|
|
37
37
|
### V8.OsClientModel 常用字段
|
|
38
38
|
|
|
@@ -41,7 +41,7 @@ V8.OsClientModel.SysTitle // 租户系统标题
|
|
|
41
41
|
V8.OsClientModel.DbType // 非敏感数据库类型
|
|
42
42
|
V8.OsClientModel.HDFS // 'Aliyun' / 'MinIO' / 'S3'
|
|
43
43
|
V8.OsClientModel.AliOssPublicDomain // 可公开的文件域名
|
|
44
|
-
//
|
|
44
|
+
// 当前租户自行扩展的业务字段只作存量兼容;新增公开配置使用 sys_config,后端私密参数使用 mci_system_setting
|
|
45
45
|
|
|
46
46
|
// 以下基础设施字段不会注入 V8:
|
|
47
47
|
// DbConn / DbReadConn / AuthSecret
|
|
@@ -55,7 +55,7 @@ V8.OsClientModel.AliOssPublicDomain // 可公开的文件域名
|
|
|
55
55
|
|
|
56
56
|
- 所有可变业务逻辑默认必须由接口引擎编排,包括但不限于租户开通、开库、初始化、归属修复、官网个人中心、付费额度等 SaaS 业务流程。C# 后端只暴露原子 V8 能力,例如建库、导入空库模板、复制 `sys_config`、刷新 SaaS 缓存、补偿回滚、字段兜底等;不要把可变业务分支写死到 Controller 或 `TenantProvisioningService` 这类后端定制代码里。接口引擎缺少能力时,优先扩展 `V8.Method`/V8 引擎原子函数,再由接口引擎调用。
|
|
57
57
|
- 主租户由运行环境决定:优先读取环境变量 `OsClient`,其次读取 `appsettings.json` 的 `AppSettings:OsClient`。只有这条主租户 `sys_osclients` 数据中的平台级字段会作为全局配置生效。
|
|
58
|
-
- API 启动配置只有十项白名单:`OsClient`、`OsClientType`、`OsClientNetwork`、`OsClientDbType`、`OsClientDbConn`、`OsClientRedisHost`、`OsClientRedisPort`、`OsClientRedisPwd`、`OsClientRedisDataBase`、`OsClientDbMongoConn`。除这十项外,部署/节点级运行参数与基础设施秘密从主控 `sys_osclients`
|
|
58
|
+
- API 启动配置只有十项白名单:`OsClient`、`OsClientType`、`OsClientNetwork`、`OsClientDbType`、`OsClientDbConn`、`OsClientRedisHost`、`OsClientRedisPort`、`OsClientRedisPwd`、`OsClientRedisDataBase`、`OsClientDbMongoConn`。除这十项外,部署/节点级运行参数与基础设施秘密从主控 `sys_osclients` 读取;允许子租户自行维护且需要浏览器判断的业务开关、入口显示和公开交互配置使用该租户 `sys_config` 实体字段,OAuth/第三方集成的凭据、RP/Origin/Issuer/Scope 与仅后端参数使用 `mci_system_setting`,未配置时使用代码安全默认值。官方 License 恢复次数/间隔与固定私钥挂载 `/app/microi_private.pem` 是信任链例外。禁止再增加 `MICROI_*`、`DOS_ORM_*`、自定义 `AppSettings` 节点或动态名称的环境变量读取。节点身份由平台自动生成。
|
|
59
59
|
- `ASPNETCORE_*`、`DOTNET_*` 仅用于 .NET 宿主;构建、安装、测试、MCP、发布脚本可使用自身进程变量,但 API 生产代码不得把它们当业务配置。新增 SaaS 运行字段必须配套独立或既有 Tab、幂等升级、缓存刷新、敏感字段脱敏、子租户不继承和源码扫描测试。
|
|
60
60
|
- 文件上传的租户业务开关与额度按“当前租户 `sys_osclients` → 代码默认值”解析;平台固定灾难保护、HTTP/Multipart/Form 和反向代理上限不可由租户覆盖,也不要求安装者维护额外上传环境变量。
|
|
61
61
|
- 类似 MQTT 端口、PressureGuard、V8Limits、OrmLimits、StartupLimits、SecurityGuard 这类影响整进程资源的配置,不能让每个子租户各自抬高全局上限。子租户同名隔离字段只能降低自己的并发、等待时间或资源额度,用于隔离弱租户、试用租户或异常租户。
|
|
@@ -147,15 +147,16 @@ var erpUrl = (V8.OsClientNetwork === 'Intranet')
|
|
|
147
147
|
// ❌ 危险:密钥写在代码里,所有租户共用,无法独立轮换
|
|
148
148
|
var ak = 'AKIDxxxxxxxx';
|
|
149
149
|
|
|
150
|
-
// ✅
|
|
151
|
-
var
|
|
150
|
+
// ✅ 浏览器需要判断的开关:使用 sys_config 实体字段
|
|
151
|
+
var giteeEnabled = V8.SysConfig.GiteeLoginEnabled === 1;
|
|
152
152
|
|
|
153
153
|
// ✅ 后端 V8 可读取当前租户 Secret 并直接调用供应商
|
|
154
|
-
var
|
|
154
|
+
var privateSettings = V8.SysConfig.ServerPrivateSettings || {};
|
|
155
|
+
var secret = privateSettings['Login.Gitee.ClientSecret'];
|
|
155
156
|
// 禁止 return secret、console.log(secret) 或写入前端可读字段。
|
|
156
157
|
```
|
|
157
158
|
|
|
158
|
-
> `mci_system_setting`
|
|
159
|
+
> `mci_system_setting` 位于每个租户自己的数据库,只保存不能公开或仅供后端执行的配置;普通值与 Secret 都不会下发浏览器。Secret 保存认证密文,只在后端 V8 的当前租户 `ServerPrivateSettings` 中解密使用。能力开关和入口显示必须建成 `sys_config` 实体字段,禁止通过 `IsPublic` 或其它运行时勾选把私密记录公开。前端 V8、普通 FormEngine HTTP、匿名/访问密钥会话不能读取私密设置,后端 V8 也不能获得通用解密器。`sys_osclients` 自定义业务字段只保留存量兼容;共享基础设施字段由服务端强制移除,不能用自定义同义字段绕过安全代理。
|
|
159
160
|
|
|
160
161
|
## 用户扩展字段访问(同理)
|
|
161
162
|
|
|
@@ -15,7 +15,9 @@ description: Microi V8 安全指南。用于审查 DiyToken 与权限、可逆
|
|
|
15
15
|
<!-- microi-progressive:chunk id=v8-security-000 sha256=0346bd9ca3fe98dd2b589d1777aa1e55cd24cf7dedc69ee65d4ca91461db7dee -->
|
|
16
16
|
## 0. 租户动态系统设置与密钥边界
|
|
17
17
|
|
|
18
|
-
第三方密钥(微信、支付宝、OpenAI、阿里云、ERP、SMTP)**禁止**硬编码在 V8 代码或前端。公开的租户配置必须建成当前租户 `sys_config` 的实体字段;敏感或仅供后端使用的租户业务配置保存到 `mci_system_setting`。数据库、Redis、MongoDB、MinIO、MQ 等部署控制面仍由主库 `sys_osclients` 托管,子租户不能修改。
|
|
18
|
+
第三方密钥(微信、支付宝、OpenAI、阿里云、ERP、SMTP)**禁止**硬编码在 V8 代码或前端。公开的租户配置必须建成当前租户 `sys_config` 的实体字段;敏感或仅供后端使用的租户业务配置保存到 `mci_system_setting`。数据库、Redis、MongoDB、MinIO、MQ 等部署控制面仍由主库 `sys_osclients` 托管,子租户不能修改。
|
|
19
|
+
|
|
20
|
+
能力是否启用、入口是否显示、公开交互模式等 Bool/Enum 配置即使属于登录或第三方集成,也必须放在 `sys_config`;API Key、ClientSecret、RP ID、Origin、Issuer、Scope、供应商地址等后端参数才放在 `mci_system_setting`。禁止给同一个新配置双写两张表。迁移旧开关时采用“新 `sys_config` 显式值 → 旧私密 Key → 存量安全默认”的只读回退,并从私密设置的列表、保存和删除入口移除旧 Key。
|
|
19
21
|
|
|
20
22
|
```javascript
|
|
21
23
|
// ✅ 浏览器/前端 V8 只读取 sys_config 的浏览器安全投影
|
|
@@ -119,6 +119,10 @@ AI 在工作区任意任务中生成的**一次性临时脚本、诊断文件、
|
|
|
119
119
|
| 吾码后台系统前端移动端自适应源码 | `Microi.Client/src/views/mobile/` |
|
|
120
120
|
| 吾码低代码后端源码 | `Microi.Server/` |
|
|
121
121
|
| 吾码表单引擎源码 | `Microi.Client/src/views/form-engine/` |
|
|
122
|
+
| 吾码表单设计器源码 | `Microi.Client/src/views/form-engine/diy-design.vue` |
|
|
123
|
+
| 吾码数据表格渲染源码 | `Microi.Client/src/views/form-engine/diy-table.vue` |
|
|
124
|
+
| 吾码表单渲染源码 | `Microi.Client/src/views/form-engine/diy-form.vue` |
|
|
125
|
+
| 吾码地图控件源码 | `Microi.Client/src/views/form-engine/diy-field-component/diy-map.vue` |
|
|
122
126
|
| 吾码界面引擎源码 | `Microi.Client/src/views/page-engine/` |
|
|
123
127
|
| 吾码打印引擎源码 | `Microi.Client/src/views/print-engine/` |
|
|
124
128
|
| 吾码 App 源码 | `microi.app/` |
|
|
@@ -128,6 +132,13 @@ AI 在工作区任意任务中生成的**一次性临时脚本、诊断文件、
|
|
|
128
132
|
|
|
129
133
|
以上路径只作为通用工作区相对路径规范,不写入具体本机盘符。跨仓库、空工作区或普通用户项目中,如果路径不存在,以插件生成的 `AGENTS.md`、MCP 配置和实际文件树为准。
|
|
130
134
|
|
|
135
|
+
### 吾码创建人身份识别(强制)
|
|
136
|
+
|
|
137
|
+
- 每次开始处理吾码任务时,都先检查工作区根的 `Microi.Server/Microi.net/`:目录必须存在,并且 `rg --files Microi.Server/Microi.net` 至少返回一个真实源码文件,空目录不成立。满足条件即确认当前是“吾码创建人在官方完整源码工作区开发”;这是工作区级开发者身份标记,不要求本次代码恰好修改在该目录内。目录缺失或为空时按普通吾码用户工作区处理,不得假设拥有官方主库权限。
|
|
138
|
+
- 确认创建人身份后,处理平台基础能力的修改、构建或交付任务时,必须同时读取 `app-store` Skill,并把官方母版资源、对应平台应用数据包、应用商城发布及发布后回读纳入完成边界;不得只改源码、本地租户或本地 JSON 后结束。
|
|
139
|
+
- 触发表现包括但不限于:新增或修改系统设置、表、字段、Tab、菜单、权限、接口引擎、表单事件、数据源、页面、打印、工作流、任务、平台内置微服务及可幂等种子数据。先判断资源归属的一个或多个官方平台应用,基础空库包与存量租户增量应用都涉及时必须同时更新。
|
|
140
|
+
- 纯审查、解释和诊断任务保持只读;目录识别只决定交付链路和事实源,不授权与当前任务无关的线上写入。当前任务属于平台功能修改/交付且官方 `microi_itdos` 权限可用时,官方应用包发布与版本、状态、内容哈希回读属于正常收尾步骤,不得再次降级成可选建议。
|
|
141
|
+
|
|
131
142
|
每个 `AI应用/{appKey}` 必须只有一个可编辑事实源,统一承载界面、微服务、Manifest、接口引擎、资源策略、测试、构建脚本与商城上传素材。普通应用默认使用当前连接下的 `Microi-V8-Engine` 目录;受审计的官方内置应用若由独立 Git 仓库维护,必须由版本管理的发布契约唯一指向该源码根,并让构建、跨工程测试和发行包共同读取契约。此时同名 `Microi-V8-Engine` 目录只是远端同步镜像,不得回退为构建源。禁止靠目录探测在多份副本之间自动择新,也禁止另建无契约的 `microi.apps/` 平行发行根。
|
|
132
143
|
|
|
133
144
|
<!-- /microi-progressive:chunk -->
|