@microi.net/cli 4.6.4 → 4.6.8
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/dist/mcp-server.js +98 -92
- package/dist/microi-cli.js +177 -26
- package/dist/microi-skills.meta.json +148 -142
- package/dist/microi.skills/.microi-skills-version.json +2 -2
- package/dist/microi.skills/README.md +3 -2
- package/dist/microi.skills/ai-engine/SKILL.md +38 -11
- package/dist/microi.skills/app-store/SKILL.md +134 -104
- package/dist/microi.skills/microi-ai-application/SKILL.md +8 -0
- package/dist/microi.skills/microi-client-frontend/SKILL.md +413 -398
- package/dist/microi.skills/microi-db-schema/SKILL.md +165 -165
- package/dist/microi.skills/microi-deployment/SKILL.md +29 -3
- package/dist/microi.skills/microi-docs-coverage/references/capability-map.md +4 -3
- package/dist/microi.skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +10 -3
- package/dist/microi.skills/microi-form-engine/SKILL.md +165 -165
- package/dist/microi.skills/microi-microservice/SKILL.md +24 -0
- package/dist/microi.skills/microi-system-delivery/SKILL.md +207 -200
- package/dist/microi.skills/microi-ui/SKILL.md +330 -330
- package/dist/microi.skills/microi.v8.js +1818 -1758
- package/dist/microi.skills/ocr-engine/SKILL.md +111 -0
- package/dist/microi.skills/ocr-engine/agents/openai.yaml +4 -0
- package/dist/microi.skills/page-engine/SKILL.md +2 -0
- package/dist/microi.skills/performance-testing/SKILL.md +2 -2
- package/dist/microi.skills/playwright-e2e/SKILL.md +14 -40
- package/dist/microi.skills/print-engine/SKILL.md +9 -3
- package/dist/microi.skills/report-engine/SKILL.md +1 -1
- package/dist/microi.skills/translate-engine/SKILL.md +47 -5
- package/dist/microi.skills/ui-design/SKILL.md +1596 -1596
- package/dist/microi.skills/ui-design/assets/templates/MCI-DESIGN.md +199 -199
- package/dist/microi.skills/ui-design/references/design-pattern-library.md +184 -184
- package/dist/microi.skills/ui-design/references/mci-design-contract.md +163 -163
- package/dist/microi.skills/v8-file-upload/SKILL.md +8 -0
- package/dist/microi.skills/v8-frontend-events/SKILL.md +4 -1
- package/dist/microi.skills/v8-frontend-events/references/bluetooth-print.md +28 -22
- package/dist/microi.skills/v8-http-integration/SKILL.md +22 -1
- package/dist/microi.skills/v8-saas-multi-tenant/SKILL.md +2 -1
- package/dist/microi.skills/v8-security/SKILL.md +7 -6
- package/dist/microi.skills/v8-utilities/references/server-api-index.md +1 -0
- package/dist/microi.skills/workspace-conventions/SKILL.md +15 -23
- package/package.json +1 -1
|
@@ -14,8 +14,8 @@ description: Microi 吾码从自然语言交付完整系统的总控规范。用
|
|
|
14
14
|
3. **平台通用层禁止项目定制**:Microi.Server、Microi.Client、MCP、VS Code 插件、microi.skills 中不得写某个项目专属文案、专属上传限制、专属业务规则。项目规则应在租户表、接口引擎、业务配置、前端项目或业务蓝图中。
|
|
15
15
|
4. **本地改完必须远端验收**:V8 文件、表单事件、菜单按钮、数据源、工作流、页面配置等不能只改本地文件。必须写入远端数据库,并通过 HTTP 或平台工具回读确认。
|
|
16
16
|
5. **测试不等于接口能通**:交付前必须跑构建、接口契约、真实登录、核心写流程、截图、人眼复核、网络 404/5xx 守卫、远端同步状态。
|
|
17
|
-
6. **生产数据谨慎优先**:涉及真实会员、余额、积分、订单、库存、卡券、收益、佣金、分润等资金/资产数据时,先确认服务器、租户、目标表、筛选条件和影响范围,再执行 MCP、接口引擎或 SQL 写操作。除用户明确要求清理/重置或必须修复错误数据外,不得擅自批量改真实数据。
|
|
18
|
-
7. **默认按分布式交付**:任何后端能力都假设会有至少两个节点连接同一数据库和 Redis,并经历滚动升级、重复投递与节点硬重启。定时任务/消费者使用分布式租约且业务本身幂等;会话、票据和任务状态使用共享存储;新旧版本并存时采用“先扩展、后迁移、再收缩”。只在单节点验证通过不能视为完整交付。
|
|
17
|
+
6. **生产数据谨慎优先**:涉及真实会员、余额、积分、订单、库存、卡券、收益、佣金、分润等资金/资产数据时,先确认服务器、租户、目标表、筛选条件和影响范围,再执行 MCP、接口引擎或 SQL 写操作。除用户明确要求清理/重置或必须修复错误数据外,不得擅自批量改真实数据。
|
|
18
|
+
7. **默认按分布式交付**:任何后端能力都假设会有至少两个节点连接同一数据库和 Redis,并经历滚动升级、重复投递与节点硬重启。定时任务/消费者使用分布式租约且业务本身幂等;会话、票据和任务状态使用共享存储;新旧版本并存时采用“先扩展、后迁移、再收缩”。只在单节点验证通过不能视为完整交付。
|
|
19
19
|
|
|
20
20
|
## 用户问题编号跟踪(强制)
|
|
21
21
|
|
|
@@ -40,35 +40,35 @@ description: Microi 吾码从自然语言交付完整系统的总控规范。用
|
|
|
40
40
|
- 用户新增或纠正规则后,立即同步到蓝图/方案文档,避免后续实现忘记业务口径。
|
|
41
41
|
- 生成系统前,用 MCP 读取现有 `diy_table`、`diy_field`、`sys_menu`、`sys_apiengine`,不要重复造表或编造字段。
|
|
42
42
|
|
|
43
|
-
### 2. MCP 建模阶段
|
|
44
|
-
|
|
45
|
-
- 开始任何 MCP 盘点前先调用 `microi_get_status` 验证当前连接、API Server
|
|
46
|
-
与 `OsClient`,再读取结构;“配置文件里有 MCP”不能证明当前真实可用。
|
|
47
|
-
- 创建复杂系统优先使用 Manifest:表、字段、菜单、按钮、接口引擎、权限、页面、打印、工作流、任务统一规划。
|
|
43
|
+
### 2. MCP 建模阶段
|
|
44
|
+
|
|
45
|
+
- 开始任何 MCP 盘点前先调用 `microi_get_status` 验证当前连接、API Server
|
|
46
|
+
与 `OsClient`,再读取结构;“配置文件里有 MCP”不能证明当前真实可用。
|
|
47
|
+
- 创建复杂系统优先使用 Manifest:表、字段、菜单、按钮、接口引擎、权限、页面、打印、工作流、任务统一规划。
|
|
48
48
|
- 先 dry-run:`microi_plan_system` / `microi_generate_system dryRun:true`。
|
|
49
49
|
- 用户确认后真实写入,并立即 `microi_validate_system`。
|
|
50
50
|
- 所有写操作前必须确认 MCP 绑定的 API Server、OsClient 和用户指定租户一致;多个 MCP 同时存在时,读写不能跨服务器混用。
|
|
51
51
|
- 对资金/资产类生产数据执行清理、重算、修复、补发、扣减前,必须留下可审计痕迹:中文备注 SQL、维护接口说明、执行时间、影响行数、回读验证结果。能用小范围条件时不要全表更新。
|
|
52
52
|
- 写入菜单时,业务按钮一次性配齐 `MoreBtns`、`FormBtns`、`PageBtns`、`BatchSelectMoreBtns`、`PageTabs`,按钮前端只负责交互,后端逻辑放接口引擎。
|
|
53
|
-
- 写入后台菜单时必须至少规划两级菜单树:先创建业务域父菜单,再把 CRUD、报表、日志、设置模块挂到对应父菜单。不要把客户、设备、工单、报告、日志、配置等所有模块直接创建为一级菜单。Manifest dry-run 和最终交付说明都必须列出菜单树。
|
|
54
|
-
- 新建前端 MicroService 时,必须先 `microi_list_applications` 盘点,再用 `microi_scaffold_vue_microservice` 在当前租户 `AI应用/{appKey}` 做预演和确认创建;构建后依次同步私有源码、发布公有产物、回读页面 Id。每个菜单通过 `microi_create_module` 一次绑定 `MicroServiceId/MicroServicePageId/MicroServiceRoutePath/MicroServiceKey`,写后用 `microi_get_module` 回读,不得把普通 URL 菜单的创建成功误报成微服务菜单已交付。
|
|
55
|
-
- Windows 上脚手架从临时目录原子改名时,杀毒软件或索引器可能短暂返回 `EPERM/EACCES/EBUSY`;MCP 应做有上限的短重试并保持原子改名,重试仍失败才清理临时目录并报错,禁止改成逐文件覆盖目标目录。
|
|
56
|
-
- 编译产物优先调用 `microi_publish_application_directory_stream`。流式端点失败时必须检查 `uploadedCount/retrySafe`:只有 `uploadedCount=0` 且 `retrySafe=true`、并且产物较小时,才可临时回退 `microi_publish_microservice`;已上传部分文件时先按版本和哈希回读,禁止无判断重复发布。回退与远端版本缺口必须写进交付结论。
|
|
57
|
-
- `microi_get_application_context` 返回文件清单不等于源码可读;必须检查 `ContentsComplete/ContentErrorCount` 以及逐文件 `ContentReadError`。MinIO 服务端读取私有源码应走内网端点,不能因公网代理拒绝私有桶而把 `IncludedContents=true` 误判为完整上下文。
|
|
58
|
-
- 用户明确要求通过 MCP 修正当前后台菜单时,不能只更新 Skill 或文档后停下。必须回读 `sys_menu`,创建缺失的父级 `SecondMenu`,更新现有子菜单 `ParentId` / `Sort`,给管理员角色补父菜单权限,最后再次回读验证树结构。
|
|
59
|
-
- 表单布局默认遵守平台约定,例如 PC 双列;字段显示顺序要跟业务表单顺序一致。
|
|
60
|
-
- 平台通用功能除了改源码,还必须同步到官方主租户 `iTdos` 的应用商城母版并回读验证;项目专属视图、字段和业务动作只写目标租户,不能混入官方母版。
|
|
61
|
-
|
|
62
|
-
### 2.1 物理字段与跨端视图
|
|
63
|
-
|
|
64
|
-
- `diy_table.DiyConfig`、`diy_field.DiyConfig`、`sys_menu.DiyConfig` 均为废弃兼容字段。MCP、Manifest、应用包和手工更新都不得向其中写入新配置。
|
|
65
|
-
- 新配置必须先增加业务语义清晰的物理字段,再通过 `diy_field` 元数据暴露控件;不得把多个无关能力重新塞进一个通用 JSON 口袋字段。
|
|
66
|
-
- Detail/Edit/List/Card 统一视图属于模块场景,使用 `sys_menu.EnableViewSchema`、`ViewSchemaVersion`、`ViewConfigVersion`、`ViewSchema`。
|
|
67
|
-
- `ViewSchema` 可按 PC/Mobile/All 和 RoleIds 选择视图;禁用、缺失、损坏或客户端不支持时必须回退到现有模块/表单。
|
|
68
|
-
- EntityHero、MetricStrip、ActionGrid、ResponsiveSection 是独立视图区块,不是 `diy_field` 数据字段,也不能用 DevComponent 或虚拟字段模拟。
|
|
69
|
-
- 小程序仅执行白名单 ActionSchema 和声明式显隐/参数映射,不执行任意前端 V8。复杂业务动作调用接口引擎,重要校验进入后端表单事件。
|
|
70
|
-
|
|
71
|
-
绑定 `diyTableId` 创建 CRUD 菜单时,必须配置或允许 MCP/后端自动推断 `TableDiyFieldIds`、`SelectFields`、`SearchFieldIds`、`SortFieldIds`、`NotShowFields`、`StatisticsFields`、`MobileListFields`、`CardTitleTagFields`、`CardBottomTagFields`、`DefaultOrderBy`。列表列、搜索列、移动端卡片列不能为空白;`Id/XxxId/XxxIds`、系统字段、布局控件和富文本/上传/地图/子表等重字段默认不展示在列表。
|
|
53
|
+
- 写入后台菜单时必须至少规划两级菜单树:先创建业务域父菜单,再把 CRUD、报表、日志、设置模块挂到对应父菜单。不要把客户、设备、工单、报告、日志、配置等所有模块直接创建为一级菜单。Manifest dry-run 和最终交付说明都必须列出菜单树。
|
|
54
|
+
- 新建前端 MicroService 时,必须先 `microi_list_applications` 盘点,再用 `microi_scaffold_vue_microservice` 在当前租户 `AI应用/{appKey}` 做预演和确认创建;构建后依次同步私有源码、发布公有产物、回读页面 Id。每个菜单通过 `microi_create_module` 一次绑定 `MicroServiceId/MicroServicePageId/MicroServiceRoutePath/MicroServiceKey`,写后用 `microi_get_module` 回读,不得把普通 URL 菜单的创建成功误报成微服务菜单已交付。
|
|
55
|
+
- Windows 上脚手架从临时目录原子改名时,杀毒软件或索引器可能短暂返回 `EPERM/EACCES/EBUSY`;MCP 应做有上限的短重试并保持原子改名,重试仍失败才清理临时目录并报错,禁止改成逐文件覆盖目标目录。
|
|
56
|
+
- 编译产物优先调用 `microi_publish_application_directory_stream`。流式端点失败时必须检查 `uploadedCount/retrySafe`:只有 `uploadedCount=0` 且 `retrySafe=true`、并且产物较小时,才可临时回退 `microi_publish_microservice`;已上传部分文件时先按版本和哈希回读,禁止无判断重复发布。回退与远端版本缺口必须写进交付结论。
|
|
57
|
+
- `microi_get_application_context` 返回文件清单不等于源码可读;必须检查 `ContentsComplete/ContentErrorCount` 以及逐文件 `ContentReadError`。MinIO 服务端读取私有源码应走内网端点,不能因公网代理拒绝私有桶而把 `IncludedContents=true` 误判为完整上下文。
|
|
58
|
+
- 用户明确要求通过 MCP 修正当前后台菜单时,不能只更新 Skill 或文档后停下。必须回读 `sys_menu`,创建缺失的父级 `SecondMenu`,更新现有子菜单 `ParentId` / `Sort`,给管理员角色补父菜单权限,最后再次回读验证树结构。
|
|
59
|
+
- 表单布局默认遵守平台约定,例如 PC 双列;字段显示顺序要跟业务表单顺序一致。
|
|
60
|
+
- 平台通用功能除了改源码,还必须同步到官方主租户 `iTdos` 的应用商城母版并回读验证;项目专属视图、字段和业务动作只写目标租户,不能混入官方母版。
|
|
61
|
+
|
|
62
|
+
### 2.1 物理字段与跨端视图
|
|
63
|
+
|
|
64
|
+
- `diy_table.DiyConfig`、`diy_field.DiyConfig`、`sys_menu.DiyConfig` 均为废弃兼容字段。MCP、Manifest、应用包和手工更新都不得向其中写入新配置。
|
|
65
|
+
- 新配置必须先增加业务语义清晰的物理字段,再通过 `diy_field` 元数据暴露控件;不得把多个无关能力重新塞进一个通用 JSON 口袋字段。
|
|
66
|
+
- Detail/Edit/List/Card 统一视图属于模块场景,使用 `sys_menu.EnableViewSchema`、`ViewSchemaVersion`、`ViewConfigVersion`、`ViewSchema`。
|
|
67
|
+
- `ViewSchema` 可按 PC/Mobile/All 和 RoleIds 选择视图;禁用、缺失、损坏或客户端不支持时必须回退到现有模块/表单。
|
|
68
|
+
- EntityHero、MetricStrip、ActionGrid、ResponsiveSection 是独立视图区块,不是 `diy_field` 数据字段,也不能用 DevComponent 或虚拟字段模拟。
|
|
69
|
+
- 小程序仅执行白名单 ActionSchema 和声明式显隐/参数映射,不执行任意前端 V8。复杂业务动作调用接口引擎,重要校验进入后端表单事件。
|
|
70
|
+
|
|
71
|
+
绑定 `diyTableId` 创建 CRUD 菜单时,必须配置或允许 MCP/后端自动推断 `TableDiyFieldIds`、`SelectFields`、`SearchFieldIds`、`SortFieldIds`、`NotShowFields`、`StatisticsFields`、`MobileListFields`、`CardTitleTagFields`、`CardBottomTagFields`、`DefaultOrderBy`。列表列、搜索列、移动端卡片列不能为空白;`Id/XxxId/XxxIds`、系统字段、布局控件和富文本/上传/地图/子表等重字段默认不展示在列表。
|
|
72
72
|
|
|
73
73
|
搜索字段默认覆盖名称/标题/编号、状态/类型/分类、负责人/部门/客户、日期时间;金额、价格、数量、积分、余额、人数等数值字段默认进入 `StatisticsFields`。选择类、开关、部门、树、级联、地址等字段应尽量使用等值筛选。
|
|
74
74
|
|
|
@@ -94,25 +94,25 @@ description: Microi 吾码从自然语言交付完整系统的总控规范。用
|
|
|
94
94
|
|
|
95
95
|
表单控件选择必须参考 `Microi.Client/src/views/form-engine/diy-field-component/diy-component-list.json`,包括文本、数字、日期、选择、树、部门、地址、关联表单、弹窗选表、子表、上传、富文本、代码、地图、二维码、布局控件等;普通字段不手动设置 `FormWidth`,整行控件才设 `24`。
|
|
96
96
|
|
|
97
|
-
### 3. 主子表与关联表单设计
|
|
98
|
-
|
|
99
|
-
先判定关系基数,再生成字段:
|
|
100
|
-
|
|
101
|
-
- “子表、明细、清单、条目、行项目、多个记录”默认是主表 1:N 子表,使用
|
|
102
|
-
`TableChild`。创建独立子表,在子表放真实父级外键,建立 `(OsClient, ParentId)`
|
|
103
|
-
回查索引,并创建 `Display=0`、`AppDisplay=0`、`HasChild=0` 的子表菜单。
|
|
104
|
-
- `JoinForm` 只用于主表保存一个目标 Id、并嵌入一条独立目标记录完整表单的 N:1/1:1
|
|
105
|
-
场景;目标表不能是当前表。需要列表、多行增删改或可能有多条记录时禁止使用。
|
|
106
|
-
- `TableChild` 的 `TableChildTableId`、`TableChildSysMenuId`、`TableChildFkFieldName`
|
|
107
|
-
必须引用回读后的真实资源。资源尚未创建时分两阶段写入,禁止猜 Id,禁止退化成
|
|
108
|
-
`JoinForm`。
|
|
109
|
-
- 基数不清楚时必须在远端写入前询问用户。调用 `microi_plan_system` / `dryRun` 前先做
|
|
110
|
-
关系语义审查;即使工具没有报错,AI 发现“1:N + JoinForm”、缺子表外键、缺隐藏
|
|
111
|
-
子菜单或缺回查索引时仍必须阻断。
|
|
112
|
-
|
|
113
|
-
`JoinForm` / `OpenTable` 等单记录关联仍需兼顾可读字段,不能只生成一个裸 `XxxId`。
|
|
114
|
-
|
|
115
|
-
推荐模式:
|
|
97
|
+
### 3. 主子表与关联表单设计
|
|
98
|
+
|
|
99
|
+
先判定关系基数,再生成字段:
|
|
100
|
+
|
|
101
|
+
- “子表、明细、清单、条目、行项目、多个记录”默认是主表 1:N 子表,使用
|
|
102
|
+
`TableChild`。创建独立子表,在子表放真实父级外键,建立 `(OsClient, ParentId)`
|
|
103
|
+
回查索引,并创建 `Display=0`、`AppDisplay=0`、`HasChild=0` 的子表菜单。
|
|
104
|
+
- `JoinForm` 只用于主表保存一个目标 Id、并嵌入一条独立目标记录完整表单的 N:1/1:1
|
|
105
|
+
场景;目标表不能是当前表。需要列表、多行增删改或可能有多条记录时禁止使用。
|
|
106
|
+
- `TableChild` 的 `TableChildTableId`、`TableChildSysMenuId`、`TableChildFkFieldName`
|
|
107
|
+
必须引用回读后的真实资源。资源尚未创建时分两阶段写入,禁止猜 Id,禁止退化成
|
|
108
|
+
`JoinForm`。
|
|
109
|
+
- 基数不清楚时必须在远端写入前询问用户。调用 `microi_plan_system` / `dryRun` 前先做
|
|
110
|
+
关系语义审查;即使工具没有报错,AI 发现“1:N + JoinForm”、缺子表外键、缺隐藏
|
|
111
|
+
子菜单或缺回查索引时仍必须阻断。
|
|
112
|
+
|
|
113
|
+
`JoinForm` / `OpenTable` 等单记录关联仍需兼顾可读字段,不能只生成一个裸 `XxxId`。
|
|
114
|
+
|
|
115
|
+
推荐模式:
|
|
116
116
|
|
|
117
117
|
- `XxxId`:隐藏字段,保存真实 Id。
|
|
118
118
|
- `XxxName`:可见 Select/OpenTable/JoinForm,显示业务名称。
|
|
@@ -139,21 +139,21 @@ description: Microi 吾码从自然语言交付完整系统的总控规范。用
|
|
|
139
139
|
### 5. V8 接口引擎与事件
|
|
140
140
|
|
|
141
141
|
- 接口引擎代码必须格式化、语义版本可追踪、可回读。
|
|
142
|
-
- 保存后必须走 HTTP 稳定路径 `/apiengine/{ApiEngineKey}` 并通过 `osclient` Header 传租户做 smoke test;只用内部 run 通过不够。普通 POST/PUT/PATCH/DELETE 禁止追加 `--OsClient--...--`。
|
|
142
|
+
- 保存后必须走 HTTP 稳定路径 `/apiengine/{ApiEngineKey}` 并通过 `osclient` Header 传租户做 smoke test;只用内部 run 通过不够。普通 POST/PUT/PATCH/DELETE 禁止追加 `--OsClient--...--`。
|
|
143
143
|
- 返回必须是标准 DosResult,除明确文件/HTML场景外,不允许返回字符串 `null`、空响应、非 JSON。
|
|
144
144
|
- 业务异常必须给用户可理解的 `Msg`,不能吞异常或只 `catch(e){}`。
|
|
145
145
|
- 定时任务、超时取消、VIP 过期、自动拒绝、库存释放等跨时间逻辑,必须建 Job 或可被 Job 调用的接口引擎。
|
|
146
146
|
- 交易、库存、积分、余额、审批状态流转必须做后端幂等和权限校验。
|
|
147
147
|
|
|
148
|
-
### 6. VS Code 插件同步纪律
|
|
149
|
-
|
|
150
|
-
VS Code 插件必须让用户清楚知道本地和远端是否一致。
|
|
151
|
-
|
|
152
|
-
- 每次准备推送接口引擎、表单/字段 V8、模块按钮或流程节点 V8 前,必须先运行当前服务器及对应引擎分类的同步状态检测。直接“推送当前文件”也必须自动预检;远端较新、双方冲突、没有同步基线或预检失败时一律停止覆盖。
|
|
153
|
-
- 同步状态接口若超时、限流、返回 `Code != 1` 或数据不完整,必须按“检查失败”停止拉取和推送;禁止将缺失的远端结果解释成“服务器无修改”。命令行可用 `npm run sync:status -- --os-client <tenant> --scope <api|form|module|workflow> --conflict-dir <dir>` 保存冲突双方供 AI 合并;确认本地修改与冲突均为 0 后,可用 `--pull --confirm <tenant>` 复用插件拉取链路,禁止绕开预检。
|
|
154
|
-
- 单文件推送预检只查询目标文件对应的接口、表、模块或流程节点,不得为推送一个文件扫描整个分类;全量同步状态使用低并发、短间隔批次,避免多人并行开发时触发服务器安全限流。
|
|
155
|
-
- AI 只修改少量 V8 文件时,收尾优先逐个执行 `sync:status -- --file <path>`;只有需要做服务器基线盘点或多人交接时才运行全量状态检查。
|
|
156
|
-
- 同步状态要显示本地修改数、远端较新数、服务器已删除数、冲突数,以及接口引擎、表单/字段 V8、模块按钮、流程节点的分类数量。
|
|
148
|
+
### 6. VS Code 插件同步纪律
|
|
149
|
+
|
|
150
|
+
VS Code 插件必须让用户清楚知道本地和远端是否一致。
|
|
151
|
+
|
|
152
|
+
- 每次准备推送接口引擎、表单/字段 V8、模块按钮或流程节点 V8 前,必须先运行当前服务器及对应引擎分类的同步状态检测。直接“推送当前文件”也必须自动预检;远端较新、双方冲突、没有同步基线或预检失败时一律停止覆盖。
|
|
153
|
+
- 同步状态接口若超时、限流、返回 `Code != 1` 或数据不完整,必须按“检查失败”停止拉取和推送;禁止将缺失的远端结果解释成“服务器无修改”。命令行可用 `npm run sync:status -- --os-client <tenant> --scope <api|form|module|workflow> --conflict-dir <dir>` 保存冲突双方供 AI 合并;确认本地修改与冲突均为 0 后,可用 `--pull --confirm <tenant>` 复用插件拉取链路,禁止绕开预检。
|
|
154
|
+
- 单文件推送预检只查询目标文件对应的接口、表、模块或流程节点,不得为推送一个文件扫描整个分类;全量同步状态使用低并发、短间隔批次,避免多人并行开发时触发服务器安全限流。
|
|
155
|
+
- AI 只修改少量 V8 文件时,收尾优先逐个执行 `sync:status -- --file <path>`;只有需要做服务器基线盘点或多人交接时才运行全量状态检查。
|
|
156
|
+
- 同步状态要显示本地修改数、远端较新数、服务器已删除数、冲突数,以及接口引擎、表单/字段 V8、模块按钮、流程节点的分类数量。
|
|
157
157
|
- 已成功推送到数据库的文件不能继续显示为已修改。
|
|
158
158
|
- Web 端改过远端代码时,插件要支持检测冲突、查看 diff、手动选择本地/远端/合并。
|
|
159
159
|
- Token 过期时优先自动 refresh token;不要频繁让用户重新登录。
|
|
@@ -162,8 +162,8 @@ VS Code 插件必须让用户清楚知道本地和远端是否一致。
|
|
|
162
162
|
- 生成 MCP Server 后,插件应自动启动或提示一键启动,不要让用户每次手工右键启动。
|
|
163
163
|
- “查看同步状态”必须能从数量下钻到具体资源。若提示本地未推送,必须列出接口引擎/表单V8事件/字段V8事件/模块按钮/流程节点V8的 Key、名称、文件路径、本地修改时间和同步基准时间,不能只弹出总数。
|
|
164
164
|
- 插件判断本地修改时,若远端代码和本地代码内容一致,应自动对齐 `.microi-meta.json` 与文件 `mtime`;表单事件等 Key 匹配要大小写兼容,避免真实无差异却长期提示“本地未推送”。
|
|
165
|
-
- AI 交付前要使用插件口径或完全等价的插件状态复核;最终说明中必须写明本地未推送、远端差异、冲突是否为 0。
|
|
166
|
-
- 多人并行开发时按状态处理:`localModified` 才允许推送;`remoteModified` 先拉取;`remoteDeleted` 表示服务器已删除且本地未改,全量拉取必须先备份再清理;服务器已删除但本地也修改时按 `conflict` 处理;`conflict` 必须比较基线、本地和远端后人工合并。正文一致仅时间戳不同则自动校准 meta/mtime。处理后再次检测,不能以“已点击同步”代替结果回读。
|
|
165
|
+
- AI 交付前要使用插件口径或完全等价的插件状态复核;最终说明中必须写明本地未推送、远端差异、冲突是否为 0。
|
|
166
|
+
- 多人并行开发时按状态处理:`localModified` 才允许推送;`remoteModified` 先拉取;`remoteDeleted` 表示服务器已删除且本地未改,全量拉取必须先备份再清理;服务器已删除但本地也修改时按 `conflict` 处理;`conflict` 必须比较基线、本地和远端后人工合并。正文一致仅时间戳不同则自动校准 meta/mtime。处理后再次检测,不能以“已点击同步”代替结果回读。
|
|
167
167
|
- AI 使用 MCP、接口引擎 API 或手写脚本直接写远端 V8 后,必须立刻把远端当前生效代码回读到本地 V8 文件,并同步更新 `.microi-meta.json` 的 `updateTime/filePath` 与文件 `mtime`。只推远端、不校准本地时间戳,会被插件判定为“本地未推送”,属于未完成交付。
|
|
168
168
|
- 同步检查不能只看总数。若数量不为 0,必须按“正文一致仅 meta/mtime 不一致 / 远端较新需拉回 / 本地较新需推送 / 冲突需人工合并”分类列出具体文件,并在处理后再次复核到 0 或说明原因。
|
|
169
169
|
- 生产环境资金、积分、资产、订单相关 V8 代码不得为了清空同步状态而盲目覆盖远端。远端 `UpdateTime` 晚于本地基线且正文不同,默认先拉远端或做人工合并;只有确认本地是未推送修复时才推送。
|
|
@@ -175,93 +175,93 @@ VS Code 插件必须让用户清楚知道本地和远端是否一致。
|
|
|
175
175
|
1. 已有 MCP 工具直接完成。
|
|
176
176
|
2. MCP 缺工具但后端有 API:补 MCP 封装。
|
|
177
177
|
3. 后端也缺通用 API:补 `V8EngineController` 或对应平台控制器的通用能力,再补 MCP。
|
|
178
|
-
4. 只有租户私有业务逻辑才新建接口引擎。
|
|
179
|
-
|
|
180
|
-
交付包含 DIY 表时,验收固定审计物理列与 `diy_field` 元数据一致;发现 `Id/CreateTime/UpdateTime/UserId/UserName/IsDeleted` 被列为异常字段时,调用通用修复接口或 MCP `microi_repair_audit_fields` 幂等修复并回读。交付用户个性化首页时,同时验收 Token 绑定保存、站内路由规范化、权限失效回退,以及账号密码、Token 与 SSO 三种登录入口的一致性。
|
|
181
|
-
|
|
182
|
-
不要用租户接口引擎修平台设计器、全局上传限制、VS Code 插件同步、MCP 元数据写入等平台级问题。
|
|
183
|
-
|
|
184
|
-
## 平台安全与存量兼容验收(强制)
|
|
185
|
-
|
|
186
|
-
AI 零代码交付不能只验证管理员帐号和页面能打开。任何涉及 FormEngine、菜单、角色、子表、文件、SaaS 或登录协议的交付,都必须按以下服务端边界设计和验收:
|
|
187
|
-
|
|
188
|
-
### FormEngine 混合授权
|
|
189
|
-
|
|
190
|
-
- Token 只完成身份认证,不是任意表的访问凭证。浏览器、UniApp、SDK 等外部请求必须继续校验表、菜单、角色、操作权限和数据范围。
|
|
191
|
-
- 显式 `_SysMenuId` / `ModuleEngineKey` 进入精确菜单校验;伪造、传错或借用其它表菜单时失败关闭,不能退回兼容推断。
|
|
192
|
-
- 为兼容存量前端 V8,无菜单请求由后端从当前用户真正拥有的菜单授权快照中推断目标表权限。没有候选菜单、范围无法安全合并或解析失败时失败关闭;不要要求所有历史项目一次性补 `_SysMenuId`。
|
|
193
|
-
- 标准 PC facade 只给当前菜单绑定的当前表注入菜单 Id,跨表调用不借用主表菜单。没有菜单入口的 SDK/定制页才使用最小【高级表权限】。
|
|
194
|
-
- 后端接口引擎、后端表单 V8 和平台内部调用由服务端建立可信上下文,不要求 `_SysMenuId`;客户端伪造 `_TrustedServerInvocation` 或 `_InvokeType:'Server'` 不能获得信任。
|
|
195
|
-
- `TableChild` 使用父记录范围内委托:验证父菜单、父表字段配置、子菜单、父记录数据范围和外键,并由服务端强制注入外键。隐藏子菜单不要求存量角色逐个补权限。
|
|
196
|
-
- 菜单 `SqlWhere` / `SqlJoin` 只约束列表、计数、导出等集合查询;单行详情只校验同表菜单访问权。主表写入由 `Add` / `Edit` / `Del` / `Import` 专项权限控制,不把查询范围追加到写入 SQL,也不因查询 Join 拒绝。行级写业务限制放在后端表单 V8 或专用接口引擎。
|
|
197
|
-
|
|
198
|
-
### 保护表、控制面与缓存
|
|
199
|
-
|
|
178
|
+
4. 只有租户私有业务逻辑才新建接口引擎。
|
|
179
|
+
|
|
180
|
+
交付包含 DIY 表时,验收固定审计物理列与 `diy_field` 元数据一致;发现 `Id/CreateTime/UpdateTime/UserId/UserName/IsDeleted` 被列为异常字段时,调用通用修复接口或 MCP `microi_repair_audit_fields` 幂等修复并回读。交付用户个性化首页时,同时验收 Token 绑定保存、站内路由规范化、权限失效回退,以及账号密码、Token 与 SSO 三种登录入口的一致性。
|
|
181
|
+
|
|
182
|
+
不要用租户接口引擎修平台设计器、全局上传限制、VS Code 插件同步、MCP 元数据写入等平台级问题。
|
|
183
|
+
|
|
184
|
+
## 平台安全与存量兼容验收(强制)
|
|
185
|
+
|
|
186
|
+
AI 零代码交付不能只验证管理员帐号和页面能打开。任何涉及 FormEngine、菜单、角色、子表、文件、SaaS 或登录协议的交付,都必须按以下服务端边界设计和验收:
|
|
187
|
+
|
|
188
|
+
### FormEngine 混合授权
|
|
189
|
+
|
|
190
|
+
- Token 只完成身份认证,不是任意表的访问凭证。浏览器、UniApp、SDK 等外部请求必须继续校验表、菜单、角色、操作权限和数据范围。
|
|
191
|
+
- 显式 `_SysMenuId` / `ModuleEngineKey` 进入精确菜单校验;伪造、传错或借用其它表菜单时失败关闭,不能退回兼容推断。
|
|
192
|
+
- 为兼容存量前端 V8,无菜单请求由后端从当前用户真正拥有的菜单授权快照中推断目标表权限。没有候选菜单、范围无法安全合并或解析失败时失败关闭;不要要求所有历史项目一次性补 `_SysMenuId`。
|
|
193
|
+
- 标准 PC facade 只给当前菜单绑定的当前表注入菜单 Id,跨表调用不借用主表菜单。没有菜单入口的 SDK/定制页才使用最小【高级表权限】。
|
|
194
|
+
- 后端接口引擎、后端表单 V8 和平台内部调用由服务端建立可信上下文,不要求 `_SysMenuId`;客户端伪造 `_TrustedServerInvocation` 或 `_InvokeType:'Server'` 不能获得信任。
|
|
195
|
+
- `TableChild` 使用父记录范围内委托:验证父菜单、父表字段配置、子菜单、父记录数据范围和外键,并由服务端强制注入外键。隐藏子菜单不要求存量角色逐个补权限。
|
|
196
|
+
- 菜单 `SqlWhere` / `SqlJoin` 只约束列表、计数、导出等集合查询;单行详情只校验同表菜单访问权。主表写入由 `Add` / `Edit` / `Del` / `Import` 专项权限控制,不把查询范围追加到写入 SQL,也不因查询 Join 拒绝。行级写业务限制放在后端表单 V8 或专用接口引擎。
|
|
197
|
+
|
|
198
|
+
### 保护表、控制面与缓存
|
|
199
|
+
|
|
200
200
|
- SaaS、接口引擎、表/字段、菜单角色、用户、任务、数据源、MQ/MQTT、页面、打印、工作流、数据库、应用商城、AI 与安全审计等保护表,普通客户端 `Level < 9999` 硬拒绝;菜单或表权限不能覆盖。
|
|
201
|
-
- 创建 V8、接口引擎、任务、数据源和 Redis 管理等控制面 API 继续要求 `Level >= 9999`。不能只靠前端隐藏菜单。
|
|
202
|
-
- 权限缓存使用按 `OsClient` 隔离的共享 Redis `epoch`、用户快照、短 TTL L1/L2。用户/角色/菜单/权限变化后提升 `epoch`;验收至少使用两个节点确认无需清 Redis或重启即可生效。
|
|
203
|
-
- Upgrade15 只清理普通角色的保护表直接授权,不能删除正常业务菜单权限。
|
|
204
|
-
|
|
205
|
-
### 上传、私有文件与 SaaS
|
|
206
|
-
|
|
207
|
-
- 上传业务默认值为 100 MB/文件、200 MB/次、10 文件、2 GB/帐号/日、20 GB
|
|
208
|
-
- 普通交互式上传强制私有桶,一级目录只能是 `file`、`img`、`avatar`、`editor`。可信后端 V8 仍受全局文件大小硬上限。
|
|
209
|
-
- 普通客户端私有文件签名必须提交 `FormEngineKey`、`FormDataId`、`FieldId`、`SysMenuId` 并验证记录字段真实引用;不能把后端 `V8.Method.GetPrivateFileUrl({FilePathName})` 的可信调用方式照搬到浏览器。
|
|
210
|
-
- Upgrade16 六个上传字段全部可空,空值保持老租户兼容;升级后回读字段元数据、租户值并刷新 SaaS 缓存。
|
|
211
|
-
- `V8.OsClientModel` / `V8.SysConfig` 只使用脱敏副本,不返回整个对象。新租户不能复制主租户整条 `sys_osclients`;数据库、认证、Redis、存储、MQ/MQTT、搜索凭据必须独立创建或由服务端托管。
|
|
212
|
-
- Redis 管理器只允许超级管理员使用当前租户或已保存连接;匿名/temporary 任意 Host 连接必须拒绝,MCP 写操作必须 `confirmExecution`,禁止传递 Redis 密码。
|
|
213
|
-
|
|
214
|
-
### 网络、登录和发布兼容
|
|
215
|
-
|
|
216
|
-
- `CorsAllowOrigins` 和全局 CORS 来源都为空时默认允许任意来源;配置后才按精确来源/通配符收紧。CORS 不是鉴权边界。
|
|
217
|
-
- 严格 SSRF 默认关闭,未配置时不得拒绝存量非 HTTP(S)、URL 凭据、私网、云元数据和重定向调用;显式启用后才执行严格拦截与精确主机白名单。
|
|
218
|
-
- 登录 RSA 仅避免密码在请求体直接显示,HTTPS 才是安全边界。必须保留历史 RSA fallback,专属公私钥成对切换,不能因删除旧常量造成所有客户无法登录。
|
|
219
|
-
- 登录传 `_ClientType`,请求携带稳定 `did`,每次响应接收 `authorization`。多标签续签 single-flight;`TokenReplaced` 先检查新 Token,旧响应不能清掉新登录态。
|
|
220
|
-
- 安全升级不得删除私有子 Git 的 `Microi.Server/Microi.net/License/keys/`。授权签名资产与登录 RSA 用途不同,禁止以安全清理为由混删。
|
|
221
|
-
- 不得修改默认 CORS/SSRF/RSA 行为后只用新装环境验收;必须覆盖旧前端、历史 V8、滚动升级和至少两个节点。
|
|
222
|
-
|
|
223
|
-
### 安全自动化最低断言
|
|
224
|
-
|
|
225
|
-
1. 普通角色保护表读写、伪造菜单、伪造可信标记均失败。
|
|
226
|
-
2. 真实菜单、历史无菜单推断和父记录范围内 TableChild 均成功,跨父记录失败。
|
|
227
|
-
3. 查询范围在列表、计数、导出中生效;详情按同表菜单访问权成功;有写权限的单表/Join 模块写入成功,无写权限失败,后端 V8 行级业务校验可回滚。
|
|
228
|
-
4. 节点 A 改权限后节点 B 无需重启生效。
|
|
229
|
-
5. 上传大小/数量/双日额度、多节点并发和 Redis 故障行为正确。
|
|
230
|
-
6. 私有文件跨菜单/记录/字段失败,授权访问成功,匿名失败。
|
|
231
|
-
7. CORS 空配置兼容、配置后收紧;SSRF 默认兼容、严格模式拦截。
|
|
232
|
-
8. 历史 RSA fallback 和专属匹配密钥均可登录;并发续签不反复退出。
|
|
233
|
-
9. SaaS 脱敏投影不包含基础设施密钥,Redis anonymous/temporary/非管理员管理失败。
|
|
234
|
-
|
|
235
|
-
## 自动化测试必须覆盖的坑
|
|
236
|
-
|
|
237
|
-
### 后端统一测试与发布门禁
|
|
238
|
-
|
|
239
|
-
- 吾码后端统一测试入口是 `Microi.Server/Microi.Tests/Microi.Tests.csproj`,
|
|
240
|
-
不得重新创建 `Dos.Common.Tests`、`Dos.ORM.Tests` 等分散入口。
|
|
241
|
-
- 日常源码验证运行
|
|
242
|
-
`Microi.Server/Microi.Tests/run-tests.ps1 -Mode Quick`。Quick 只做
|
|
243
|
-
单元/组件回归,不连接远端、不写数据库,不能称为“全量生产验收”。
|
|
244
|
-
- 发布 API 前运行 `-Mode Full`。默认提供隔离测试租户、专用测试表、
|
|
245
|
-
测试 ApiEngine、测试 Token,并显式设置
|
|
246
|
-
`MICROI_TEST_ALLOW_WRITES=YES`。只有用户明确授权时才可对真实租户执行;
|
|
247
|
-
真实租户默认只做登录和只读烟测,写入必须限定到名称/说明明确为自动化
|
|
248
|
-
测试用途的专用表,并使用唯一前缀、`finally` 清理和清理回读。
|
|
249
|
-
- Full 至少覆盖完整 Release 构建、FormEngine 单条/批量/按条件 CRUD、
|
|
250
|
-
查询和计数、ApiEngine GET/JSON POST、API 实际启动与健康检查、真实登录、
|
|
251
|
-
匿名系统配置脱敏、清理回读、NuGet 漏洞/弃用审计。NuGet 全面升级后不能
|
|
252
|
-
只看编译;必须捕获程序集 ABI 不一致、旧连接串枚举值失效等启动/运行时问题。
|
|
253
|
-
新增后端公共操作时,同步扩展统一测试入口和 FullStack 闭环。
|
|
254
|
-
- 真实账号、密码和 Token 只能来自进程环境变量、CI Secret 或已被 Git 忽略
|
|
255
|
-
的本机配置;不得写入 `Microi.Tests`、README、命令行参数、TRX、覆盖率报告
|
|
256
|
-
或失败消息。测试输出还要验证私有 `appsettings.*.json` 未被复制发布。
|
|
257
|
-
- 交付报告必须分别写明:源码检查、项目/解决方案构建、Quick 结果、
|
|
258
|
-
FullStack 结果、两节点分布式故障结果。未提供测试环境而未运行 Full,
|
|
259
|
-
必须明确写“未运行”,不能用 Quick 通过代替。
|
|
260
|
-
- 即使 Full 通过,涉及定时任务、消息消费、共享缓存、迁移或滚动发布时,
|
|
261
|
-
仍需两个节点连接同一 Redis/数据库,覆盖重复投递、锁持有者退出、
|
|
262
|
-
Redis/MongoDB 短暂故障、响应前重启和新旧版本共存。
|
|
263
|
-
|
|
264
|
-
### 登录与账号密码
|
|
201
|
+
- 创建 V8、接口引擎、任务、数据源和 Redis 管理等控制面 API 继续要求 `Level >= 9999`。不能只靠前端隐藏菜单。
|
|
202
|
+
- 权限缓存使用按 `OsClient` 隔离的共享 Redis `epoch`、用户快照、短 TTL L1/L2。用户/角色/菜单/权限变化后提升 `epoch`;验收至少使用两个节点确认无需清 Redis或重启即可生效。
|
|
203
|
+
- Upgrade15 只清理普通角色的保护表直接授权,不能删除正常业务菜单权限。
|
|
204
|
+
|
|
205
|
+
### 上传、私有文件与 SaaS
|
|
206
|
+
|
|
207
|
+
- 上传业务默认值为 100 MB/文件、200 MB/次、10 文件、2 GB/帐号/日、20 GB/租户/日。有效值只按当前租户 `sys_osclients` → 代码安全默认值解析,租户可以提高或降低业务默认值;不得为上传开关、额度或硬上限新增 API 环境变量或 `appsettings` 节点。最终仍受代码内不可突破的灾难保护、HTTP/Multipart/Form 和反向代理上限约束。共享 Redis 原子预留,Redis 故障失败关闭。
|
|
208
|
+
- 普通交互式上传强制私有桶,一级目录只能是 `file`、`img`、`avatar`、`editor`。可信后端 V8 仍受全局文件大小硬上限。
|
|
209
|
+
- 普通客户端私有文件签名必须提交 `FormEngineKey`、`FormDataId`、`FieldId`、`SysMenuId` 并验证记录字段真实引用;不能把后端 `V8.Method.GetPrivateFileUrl({FilePathName})` 的可信调用方式照搬到浏览器。
|
|
210
|
+
- Upgrade16 六个上传字段全部可空,空值保持老租户兼容;升级后回读字段元数据、租户值并刷新 SaaS 缓存。
|
|
211
|
+
- `V8.OsClientModel` / `V8.SysConfig` 只使用脱敏副本,不返回整个对象。新租户不能复制主租户整条 `sys_osclients`;数据库、认证、Redis、存储、MQ/MQTT、搜索凭据必须独立创建或由服务端托管。
|
|
212
|
+
- Redis 管理器只允许超级管理员使用当前租户或已保存连接;匿名/temporary 任意 Host 连接必须拒绝,MCP 写操作必须 `confirmExecution`,禁止传递 Redis 密码。
|
|
213
|
+
|
|
214
|
+
### 网络、登录和发布兼容
|
|
215
|
+
|
|
216
|
+
- `CorsAllowOrigins` 和全局 CORS 来源都为空时默认允许任意来源;配置后才按精确来源/通配符收紧。CORS 不是鉴权边界。
|
|
217
|
+
- 严格 SSRF 默认关闭,未配置时不得拒绝存量非 HTTP(S)、URL 凭据、私网、云元数据和重定向调用;显式启用后才执行严格拦截与精确主机白名单。
|
|
218
|
+
- 登录 RSA 仅避免密码在请求体直接显示,HTTPS 才是安全边界。必须保留历史 RSA fallback,专属公私钥成对切换,不能因删除旧常量造成所有客户无法登录。
|
|
219
|
+
- 登录传 `_ClientType`,请求携带稳定 `did`,每次响应接收 `authorization`。多标签续签 single-flight;`TokenReplaced` 先检查新 Token,旧响应不能清掉新登录态。
|
|
220
|
+
- 安全升级不得删除私有子 Git 的 `Microi.Server/Microi.net/License/keys/`。授权签名资产与登录 RSA 用途不同,禁止以安全清理为由混删。
|
|
221
|
+
- 不得修改默认 CORS/SSRF/RSA 行为后只用新装环境验收;必须覆盖旧前端、历史 V8、滚动升级和至少两个节点。
|
|
222
|
+
|
|
223
|
+
### 安全自动化最低断言
|
|
224
|
+
|
|
225
|
+
1. 普通角色保护表读写、伪造菜单、伪造可信标记均失败。
|
|
226
|
+
2. 真实菜单、历史无菜单推断和父记录范围内 TableChild 均成功,跨父记录失败。
|
|
227
|
+
3. 查询范围在列表、计数、导出中生效;详情按同表菜单访问权成功;有写权限的单表/Join 模块写入成功,无写权限失败,后端 V8 行级业务校验可回滚。
|
|
228
|
+
4. 节点 A 改权限后节点 B 无需重启生效。
|
|
229
|
+
5. 上传大小/数量/双日额度、多节点并发和 Redis 故障行为正确。
|
|
230
|
+
6. 私有文件跨菜单/记录/字段失败,授权访问成功,匿名失败。
|
|
231
|
+
7. CORS 空配置兼容、配置后收紧;SSRF 默认兼容、严格模式拦截。
|
|
232
|
+
8. 历史 RSA fallback 和专属匹配密钥均可登录;并发续签不反复退出。
|
|
233
|
+
9. SaaS 脱敏投影不包含基础设施密钥,Redis anonymous/temporary/非管理员管理失败。
|
|
234
|
+
|
|
235
|
+
## 自动化测试必须覆盖的坑
|
|
236
|
+
|
|
237
|
+
### 后端统一测试与发布门禁
|
|
238
|
+
|
|
239
|
+
- 吾码后端统一测试入口是 `Microi.Server/Microi.Tests/Microi.Tests.csproj`,
|
|
240
|
+
不得重新创建 `Dos.Common.Tests`、`Dos.ORM.Tests` 等分散入口。
|
|
241
|
+
- 日常源码验证运行
|
|
242
|
+
`Microi.Server/Microi.Tests/run-tests.ps1 -Mode Quick`。Quick 只做
|
|
243
|
+
单元/组件回归,不连接远端、不写数据库,不能称为“全量生产验收”。
|
|
244
|
+
- 发布 API 前运行 `-Mode Full`。默认提供隔离测试租户、专用测试表、
|
|
245
|
+
测试 ApiEngine、测试 Token,并显式设置
|
|
246
|
+
`MICROI_TEST_ALLOW_WRITES=YES`。只有用户明确授权时才可对真实租户执行;
|
|
247
|
+
真实租户默认只做登录和只读烟测,写入必须限定到名称/说明明确为自动化
|
|
248
|
+
测试用途的专用表,并使用唯一前缀、`finally` 清理和清理回读。
|
|
249
|
+
- Full 至少覆盖完整 Release 构建、FormEngine 单条/批量/按条件 CRUD、
|
|
250
|
+
查询和计数、ApiEngine GET/JSON POST、API 实际启动与健康检查、真实登录、
|
|
251
|
+
匿名系统配置脱敏、清理回读、NuGet 漏洞/弃用审计。NuGet 全面升级后不能
|
|
252
|
+
只看编译;必须捕获程序集 ABI 不一致、旧连接串枚举值失效等启动/运行时问题。
|
|
253
|
+
新增后端公共操作时,同步扩展统一测试入口和 FullStack 闭环。
|
|
254
|
+
- 真实账号、密码和 Token 只能来自进程环境变量、CI Secret 或已被 Git 忽略
|
|
255
|
+
的本机配置;不得写入 `Microi.Tests`、README、命令行参数、TRX、覆盖率报告
|
|
256
|
+
或失败消息。测试输出还要验证私有 `appsettings.*.json` 未被复制发布。
|
|
257
|
+
- 交付报告必须分别写明:源码检查、项目/解决方案构建、Quick 结果、
|
|
258
|
+
FullStack 结果、两节点分布式故障结果。未提供测试环境而未运行 Full,
|
|
259
|
+
必须明确写“未运行”,不能用 Quick 通过代替。
|
|
260
|
+
- 即使 Full 通过,涉及定时任务、消息消费、共享缓存、迁移或滚动发布时,
|
|
261
|
+
仍需两个节点连接同一 Redis/数据库,覆盖重复投递、锁持有者退出、
|
|
262
|
+
Redis/MongoDB 短暂故障、响应前重启和新旧版本共存。
|
|
263
|
+
|
|
264
|
+
### 登录与账号密码
|
|
265
265
|
|
|
266
266
|
- E2E 必须支持提前录入测试账号密码:`PW_TEST_ACCOUNT`、`PW_TEST_PASSWORD`、`PW_LOGIN_ENGINE`。
|
|
267
267
|
- 登录优先调用租户登录接口拿 Token,再注入 localStorage/sessionStorage/Cookie。
|
|
@@ -314,11 +314,11 @@ AI 零代码交付不能只验证管理员帐号和页面能打开。任何涉
|
|
|
314
314
|
- 校验每个可见 Tab 都有可见字段或可见子表内容,不能只检查 `Tabs` JSON 合法。
|
|
315
315
|
- 校验字段按钮 V8Code 中引用的字段名真实存在,尤其是历史 `TableChildxxx`、`Textxxx`、`Buttonxxx` 重命名后不能遗留旧引用。
|
|
316
316
|
- 字段按钮点击后必须守卫前端错误提示、`pageerror`、控制台 `TypeError/ReferenceError/SyntaxError`,并截图保留展开后的关联子表。
|
|
317
|
-
- 详情页测试选择器要限定在当前表格操作列和当前详情弹层内部,避免误点侧边菜单或其它同名按钮。
|
|
318
|
-
- `TableChild` 验收必须在父记录 A 新增/编辑/删除多条子记录,再打开父记录 B 验证
|
|
319
|
-
不串数据且不能跨父记录操作;同时回读子表外键、隐藏子菜单和组合索引。
|
|
320
|
-
- `JoinForm` 验收必须确认目标表与当前表不同,`JoinFieldName` 的值确实是目标记录 Id,
|
|
321
|
-
并分别覆盖空 Id 与有效 Id 的渲染行为。
|
|
317
|
+
- 详情页测试选择器要限定在当前表格操作列和当前详情弹层内部,避免误点侧边菜单或其它同名按钮。
|
|
318
|
+
- `TableChild` 验收必须在父记录 A 新增/编辑/删除多条子记录,再打开父记录 B 验证
|
|
319
|
+
不串数据且不能跨父记录操作;同时回读子表外键、隐藏子菜单和组合索引。
|
|
320
|
+
- `JoinForm` 验收必须确认目标表与当前表不同,`JoinFieldName` 的值确实是目标记录 Id,
|
|
321
|
+
并分别覆盖空 Id 与有效 Id 的渲染行为。
|
|
322
322
|
|
|
323
323
|
### 视觉与布局
|
|
324
324
|
|
|
@@ -378,7 +378,7 @@ AI 零代码交付不能只验证管理员帐号和页面能打开。任何涉
|
|
|
378
378
|
7. Playwright 账号登录、接口契约、网络守卫、业务闭环、截图复核均通过。
|
|
379
379
|
8. 生成或修改的通用经验已写回 microi.skills,且不能包含项目专属措辞;不能只写本地 memory、聊天记录或项目临时文档。
|
|
380
380
|
|
|
381
|
-
## 复盘记录格式
|
|
381
|
+
## 复盘记录格式
|
|
382
382
|
|
|
383
383
|
每次用户手工测出问题,修复后都要把问题写入对应通用 Skill,格式如下:
|
|
384
384
|
|
|
@@ -391,58 +391,65 @@ AI 零代码交付不能只验证管理员帐号和页面能打开。任何涉
|
|
|
391
391
|
- 自动化检查:哪个测试或截图能提前发现。
|
|
392
392
|
```
|
|
393
393
|
|
|
394
|
-
不要只在本次项目文档或记忆里记录;能通用的经验必须沉淀到 `microi.skills`。如果发现的是 VS Code 插件、MCP、Microi.Client、V8、FormEngine、Playwright 或性能测试的通用坑,必须更新对应 Skill 或新增 Skill,让插件下一次打包后能同步给所有用户。
|
|
395
|
-
|
|
396
|
-
### 复盘:授权文件已生效但插件仍缓存开源版
|
|
397
|
-
|
|
398
|
-
- 触发场景:授权管理接口已经返回个人版或企业版,相关插件仍提示开源版;重启服务后也可能因授权文件挂载、写入或数据库恢复晚于插件首次检查而复现。
|
|
399
|
-
- 根因:宿主授权接口与功能插件各自持有静态授权状态或各自重新验签;当插件来自旧 NuGet、独立程序集上下文或残留发布文件时,两边即使读取同一文件也可能长期分叉。让插件“自行再验一次”仍然保留了两套事实源,不能根治。
|
|
400
|
-
- 通用规则:宿主必须提供唯一的 DI 授权服务,负责缓存刷新、HID、有效期和 RSA 签名验证;所有 Controller、AI、工作流等付费功能只读取这个实例,插件禁止自行缓存或再次创建 `LicenseValidator`。授权验证接口必须返回功能实际读取的 `OnlineFeatureLicensed/ProductType` 与宿主、插件程序集版本。核心插件接口应包含授权状态契约,使旧插件混入新发布包时直接启动/类型加载失败并暴露版本不一致,禁止静默退回开源版。
|
|
401
|
-
- 自动化检查:先以无授权状态启动,再写入或挂载有效签名文件,验证统一服务限频刷新后授权接口与真实付费功能同时恢复;替换为旧插件 DLL 时启动必须失败或健康检查明确报版本不兼容,不能出现“Verify=Enterprise、功能=OpenSource”。无效签名、错误 HID、过期文件必须继续拒绝。
|
|
402
|
-
|
|
403
|
-
### 复盘:全局版本已升级但基础应用并未完整安装
|
|
404
|
-
|
|
405
|
-
- 触发场景:客户旧库的 `ServerVersion` 已被后续步骤推进,但应用商城、导入器、菜单权限或关键元数据仍缺失;客户服务器不通外网时,重启也无法自愈。
|
|
406
|
-
- 根因:升级器把全局版本号当成所有步骤成功的证明,单步失败后仍继续执行并更新版本;基础应用只依赖在线资源,且完整性检查继续走可能已经失真的 FormEngine 元数据。
|
|
407
|
-
- 通用规则:后端发布包必须内置可启动的基础应用基线,在线资源只能整组校验成功后作为最新版覆盖,断网或任一资源失败时整组回退;迁移步骤必须失败即停且失败时禁止推进版本。导入器、必要表、菜单和权限等启动前置能力要独立做幂等完整性检查,老库检查以参数化物理表只读查询为准,不能只依赖全局版本或低代码元数据。
|
|
408
|
-
- 自动化检查:选择一个版本号偏高但故意缺基础应用的旧库,以禁止外网模式启动,验证后端自动安装基础应用、管理员可见并打开应用商城、插件列表接口可拉取;再次冷启动不得重复导入。再注入任一步骤失败,验证后续步骤不执行且 `ServerVersion` 不前进。
|
|
409
|
-
|
|
410
|
-
### 复盘:平台升级覆盖客户菜单的移动端显隐
|
|
411
|
-
|
|
412
|
-
- 触发场景:旧租户切换到新版后端并执行自动升级后,移动端工作台整棵菜单消失;顶级 `sys_menu.AppDisplay` 为 `NULL` 或被升级包写成 `0` 时,所有下级菜单即使为 `1` 也无法展示。
|
|
413
|
-
- 根因:旧 `UptSysMenu` 部分更新接口读取旧菜单后又丢弃旧实体,重新创建非空 `int` 字段默认为 `0` 的 `SysMenu` 再全字段更新;仅修改排序或父级也会把未传的 `Display/AppDisplay` 清零。历史加列迁移的不可重入多语句 SQL、应用包全量覆盖目标菜单,以及移动端把 `NULL/未配置` 当作隐藏,都会进一步放大影响。
|
|
414
|
-
- 通用规则:实体型部分更新必须把非空参数合并到已读取的旧实体,禁止新建实体后全字段更新;新增菜单的 `Display/AppDisplay` 默认均为 `1`。移动端只有明确的 `0/false` 才表示隐藏,`NULL/未配置` 按兼容可见处理;升级开始前先把 `NULL` 按同一行 `Display` 归一,再快照所有既有菜单的 `AppDisplay`,升级结束无论成功失败都要恢复发生变化的旧菜单。应用包只能给新增菜单写包内显隐值,更新既有菜单时必须保留目标库 `Display/AppDisplay`。加列迁移必须按“查列、单条加列、单条回填”幂等执行。
|
|
415
|
-
- 自动化检查:先用只含 `Id/Sort/ParentId` 的旧菜单更新请求验证 `Display/AppDisplay` 不变,并验证新增菜单默认双端可见。再构造含 `AppDisplay=NULL/0/1`、顶级和子级菜单的旧库,运行升级并验证空值按 `Display` 归一、既有 `0/1` 原样保留、新增包菜单采用包内值;升级中途失败时快照仍恢复。应用包导入测试必须断言存在 `preserve_existing_menu_visibility_` 保护标记,移动端测试必须覆盖 `undefined/null/0/"0"/false/1` 六种输入。
|
|
416
|
-
|
|
417
|
-
### 复盘:Compose 升级脚本按目录推导 project 后误判旧容器不存在
|
|
418
|
-
|
|
419
|
-
- 触发场景:客户历史服务由另一个工作目录或显式 project name 启动;升级脚本虽然拿到现存 `docker-compose.yml`,但执行 `docker compose -p <目录名> ps -q <服务>` 返回空,随后误报旧容器不存在。继续用错误 project 启动还会与旧容器的宿主机端口冲突。
|
|
420
|
-
- 根因:把 Compose 文件路径或当前目录推导出的 project name 当成运行态事实源,没有从现有容器的 `com.docker.compose.project` 标签回读真实 project,也没有用宿主机 published port 和 service 标签交叉定位旧容器。
|
|
421
|
-
- 通用规则:生产 Compose 升级先按目标 published port、当前 project、`com.docker.compose.service` 三层发现唯一运行容器,并校验服务标签或镜像身份;再读取并复用其 `com.docker.compose.project`。完成原 yml 和旧镜像不可变备份、拉取并校验新镜像后,先检查所有新增服务的宿主机发布端口;端口可顺延时必须设置明确起点、步长和有限重试上限,把最终端口写入实际 Compose 与审计记录,确认可用后才停止旧容器。启动瞬间再次发生端口竞争时,只重试冲突服务;非端口错误立即回滚。再由同一 project 执行 `up --force-recreate`,且不在新镜像就绪和端口预检通过前删除旧容器。后续手工拉取 `latest` 做日常更新时,必须把当前编排、实际 project、发布端口以及 API/前端两个运行镜像 ID 同时备份并打不可变回滚标签;失败时回到本次更新前的两个镜像,禁止误用首次跨版本升级的旧基线。Compose v2 的 `version is obsolete` 只可在命令成功时作为已知非致命告警过滤,其它 stderr 和非零退出码必须保留。
|
|
422
|
-
- 自动化检查:模拟当前 project 查询为空、目标宿主机端口仍有旧 API、容器标签带另一个 project 的场景;断言脚本识别旧容器、保存并复用真实 project、在覆盖 yml 前完成备份、拉取校验后执行 stop,并覆盖新增端口连续占用时按上限顺延、重试耗尽时旧服务不停止,以及新服务启动失败后的自动还原。日常更新另测 API/前端双镜像拉取、当前动态端口保持、强制重建成功,以及任一重建/健康检查失败后两个镜像都恢复到本次更新前的 ID。
|
|
423
|
-
|
|
424
|
-
### 复盘:新旧 Compose 双版本并行部署误伤旧服务或产生重叠网络
|
|
425
|
-
|
|
426
|
-
- 通用规则:需要保留旧版本并并行安装新版本时,新版必须使用独立 Compose 文件、独立 project 和独立 service 名;旧编排与旧容器在安装路径中只读。新版若必须保持原内网通信,应从旧容器回读并校验实际 Docker 网络,再通过 `external` 网络引用其真实名称,禁止由第二个 project 重复声明同一 IPAM 子网。动态端口必须写回 API 自身公开地址及前端 `ApiBase`;先启动并确认 API,再启动前端。失败清理只能 `down` 新 project,完成后还要回读旧端口对应的容器 ID 和运行状态,确认未被替换。并行项目后续更新必须使用另一份专用命令,固定读取新版 Compose/project/service,保留现场动态端口,备份新版 API/前端两个运行镜像 ID 并打不可变标签;先更新 API、再更新前端,任一步失败时只恢复新版双镜像,禁止复用会读取旧编排的历史日常更新脚本。进程、端口和 project 隔离不代表数据隔离;若新旧后端共用数据库、Redis 或租户,新版迁移、缓存与基础数据变化仍可能影响旧版,交付时必须明确警告并准备数据库级恢复方案。
|
|
427
|
-
- 自动化检查:模拟新版起始端口连续占用、新版 API 启动失败和前端健康检查失败;断言旧 yml 字节不变、旧容器未执行 stop/rm/recreate、新版使用独立 project、实际 API 端口同时写入 `AuthServer` 与 `ApiBase`、新版 API 先于前端启动,失败时只清理新 project,并保存端口、网络、镜像 ID 和失败日志。并行日常更新另测动态端口不变、API/前端按序重建、任一服务失败后两个镜像都恢复到本次更新前的 ID,且旧端口容器 ID 始终不变。
|
|
428
|
-
|
|
394
|
+
不要只在本次项目文档或记忆里记录;能通用的经验必须沉淀到 `microi.skills`。如果发现的是 VS Code 插件、MCP、Microi.Client、V8、FormEngine、Playwright 或性能测试的通用坑,必须更新对应 Skill 或新增 Skill,让插件下一次打包后能同步给所有用户。
|
|
395
|
+
|
|
396
|
+
### 复盘:授权文件已生效但插件仍缓存开源版
|
|
397
|
+
|
|
398
|
+
- 触发场景:授权管理接口已经返回个人版或企业版,相关插件仍提示开源版;重启服务后也可能因授权文件挂载、写入或数据库恢复晚于插件首次检查而复现。
|
|
399
|
+
- 根因:宿主授权接口与功能插件各自持有静态授权状态或各自重新验签;当插件来自旧 NuGet、独立程序集上下文或残留发布文件时,两边即使读取同一文件也可能长期分叉。让插件“自行再验一次”仍然保留了两套事实源,不能根治。
|
|
400
|
+
- 通用规则:宿主必须提供唯一的 DI 授权服务,负责缓存刷新、HID、有效期和 RSA 签名验证;所有 Controller、AI、工作流等付费功能只读取这个实例,插件禁止自行缓存或再次创建 `LicenseValidator`。授权验证接口必须返回功能实际读取的 `OnlineFeatureLicensed/ProductType` 与宿主、插件程序集版本。核心插件接口应包含授权状态契约,使旧插件混入新发布包时直接启动/类型加载失败并暴露版本不一致,禁止静默退回开源版。
|
|
401
|
+
- 自动化检查:先以无授权状态启动,再写入或挂载有效签名文件,验证统一服务限频刷新后授权接口与真实付费功能同时恢复;替换为旧插件 DLL 时启动必须失败或健康检查明确报版本不兼容,不能出现“Verify=Enterprise、功能=OpenSource”。无效签名、错误 HID、过期文件必须继续拒绝。
|
|
402
|
+
|
|
403
|
+
### 复盘:全局版本已升级但基础应用并未完整安装
|
|
404
|
+
|
|
405
|
+
- 触发场景:客户旧库的 `ServerVersion` 已被后续步骤推进,但应用商城、导入器、菜单权限或关键元数据仍缺失;客户服务器不通外网时,重启也无法自愈。
|
|
406
|
+
- 根因:升级器把全局版本号当成所有步骤成功的证明,单步失败后仍继续执行并更新版本;基础应用只依赖在线资源,且完整性检查继续走可能已经失真的 FormEngine 元数据。
|
|
407
|
+
- 通用规则:后端发布包必须内置可启动的基础应用基线,在线资源只能整组校验成功后作为最新版覆盖,断网或任一资源失败时整组回退;迁移步骤必须失败即停且失败时禁止推进版本。导入器、必要表、菜单和权限等启动前置能力要独立做幂等完整性检查,老库检查以参数化物理表只读查询为准,不能只依赖全局版本或低代码元数据。
|
|
408
|
+
- 自动化检查:选择一个版本号偏高但故意缺基础应用的旧库,以禁止外网模式启动,验证后端自动安装基础应用、管理员可见并打开应用商城、插件列表接口可拉取;再次冷启动不得重复导入。再注入任一步骤失败,验证后续步骤不执行且 `ServerVersion` 不前进。
|
|
409
|
+
|
|
410
|
+
### 复盘:平台升级覆盖客户菜单的移动端显隐
|
|
411
|
+
|
|
412
|
+
- 触发场景:旧租户切换到新版后端并执行自动升级后,移动端工作台整棵菜单消失;顶级 `sys_menu.AppDisplay` 为 `NULL` 或被升级包写成 `0` 时,所有下级菜单即使为 `1` 也无法展示。
|
|
413
|
+
- 根因:旧 `UptSysMenu` 部分更新接口读取旧菜单后又丢弃旧实体,重新创建非空 `int` 字段默认为 `0` 的 `SysMenu` 再全字段更新;仅修改排序或父级也会把未传的 `Display/AppDisplay` 清零。历史加列迁移的不可重入多语句 SQL、应用包全量覆盖目标菜单,以及移动端把 `NULL/未配置` 当作隐藏,都会进一步放大影响。
|
|
414
|
+
- 通用规则:实体型部分更新必须把非空参数合并到已读取的旧实体,禁止新建实体后全字段更新;新增菜单的 `Display/AppDisplay` 默认均为 `1`。移动端只有明确的 `0/false` 才表示隐藏,`NULL/未配置` 按兼容可见处理;升级开始前先把 `NULL` 按同一行 `Display` 归一,再快照所有既有菜单的 `AppDisplay`,升级结束无论成功失败都要恢复发生变化的旧菜单。应用包只能给新增菜单写包内显隐值,更新既有菜单时必须保留目标库 `Display/AppDisplay`。加列迁移必须按“查列、单条加列、单条回填”幂等执行。
|
|
415
|
+
- 自动化检查:先用只含 `Id/Sort/ParentId` 的旧菜单更新请求验证 `Display/AppDisplay` 不变,并验证新增菜单默认双端可见。再构造含 `AppDisplay=NULL/0/1`、顶级和子级菜单的旧库,运行升级并验证空值按 `Display` 归一、既有 `0/1` 原样保留、新增包菜单采用包内值;升级中途失败时快照仍恢复。应用包导入测试必须断言存在 `preserve_existing_menu_visibility_` 保护标记,移动端测试必须覆盖 `undefined/null/0/"0"/false/1` 六种输入。
|
|
416
|
+
|
|
417
|
+
### 复盘:Compose 升级脚本按目录推导 project 后误判旧容器不存在
|
|
418
|
+
|
|
419
|
+
- 触发场景:客户历史服务由另一个工作目录或显式 project name 启动;升级脚本虽然拿到现存 `docker-compose.yml`,但执行 `docker compose -p <目录名> ps -q <服务>` 返回空,随后误报旧容器不存在。继续用错误 project 启动还会与旧容器的宿主机端口冲突。
|
|
420
|
+
- 根因:把 Compose 文件路径或当前目录推导出的 project name 当成运行态事实源,没有从现有容器的 `com.docker.compose.project` 标签回读真实 project,也没有用宿主机 published port 和 service 标签交叉定位旧容器。
|
|
421
|
+
- 通用规则:生产 Compose 升级先按目标 published port、当前 project、`com.docker.compose.service` 三层发现唯一运行容器,并校验服务标签或镜像身份;再读取并复用其 `com.docker.compose.project`。完成原 yml 和旧镜像不可变备份、拉取并校验新镜像后,先检查所有新增服务的宿主机发布端口;端口可顺延时必须设置明确起点、步长和有限重试上限,把最终端口写入实际 Compose 与审计记录,确认可用后才停止旧容器。启动瞬间再次发生端口竞争时,只重试冲突服务;非端口错误立即回滚。再由同一 project 执行 `up --force-recreate`,且不在新镜像就绪和端口预检通过前删除旧容器。后续手工拉取 `latest` 做日常更新时,必须把当前编排、实际 project、发布端口以及 API/前端两个运行镜像 ID 同时备份并打不可变回滚标签;失败时回到本次更新前的两个镜像,禁止误用首次跨版本升级的旧基线。Compose v2 的 `version is obsolete` 只可在命令成功时作为已知非致命告警过滤,其它 stderr 和非零退出码必须保留。
|
|
422
|
+
- 自动化检查:模拟当前 project 查询为空、目标宿主机端口仍有旧 API、容器标签带另一个 project 的场景;断言脚本识别旧容器、保存并复用真实 project、在覆盖 yml 前完成备份、拉取校验后执行 stop,并覆盖新增端口连续占用时按上限顺延、重试耗尽时旧服务不停止,以及新服务启动失败后的自动还原。日常更新另测 API/前端双镜像拉取、当前动态端口保持、强制重建成功,以及任一重建/健康检查失败后两个镜像都恢复到本次更新前的 ID。
|
|
423
|
+
|
|
424
|
+
### 复盘:新旧 Compose 双版本并行部署误伤旧服务或产生重叠网络
|
|
425
|
+
|
|
426
|
+
- 通用规则:需要保留旧版本并并行安装新版本时,新版必须使用独立 Compose 文件、独立 project 和独立 service 名;旧编排与旧容器在安装路径中只读。新版若必须保持原内网通信,应从旧容器回读并校验实际 Docker 网络,再通过 `external` 网络引用其真实名称,禁止由第二个 project 重复声明同一 IPAM 子网。动态端口必须写回 API 自身公开地址及前端 `ApiBase`;先启动并确认 API,再启动前端。失败清理只能 `down` 新 project,完成后还要回读旧端口对应的容器 ID 和运行状态,确认未被替换。并行项目后续更新必须使用另一份专用命令,固定读取新版 Compose/project/service,保留现场动态端口,备份新版 API/前端两个运行镜像 ID 并打不可变标签;先更新 API、再更新前端,任一步失败时只恢复新版双镜像,禁止复用会读取旧编排的历史日常更新脚本。进程、端口和 project 隔离不代表数据隔离;若新旧后端共用数据库、Redis 或租户,新版迁移、缓存与基础数据变化仍可能影响旧版,交付时必须明确警告并准备数据库级恢复方案。
|
|
427
|
+
- 自动化检查:模拟新版起始端口连续占用、新版 API 启动失败和前端健康检查失败;断言旧 yml 字节不变、旧容器未执行 stop/rm/recreate、新版使用独立 project、实际 API 端口同时写入 `AuthServer` 与 `ApiBase`、新版 API 先于前端启动,失败时只清理新 project,并保存端口、网络、镜像 ID 和失败日志。并行日常更新另测动态端口不变、API/前端按序重建、任一服务失败后两个镜像都恢复到本次更新前的 ID,且旧端口容器 ID 始终不变。
|
|
428
|
+
|
|
429
429
|
### 复盘:容器已删除但残留 Compose 文件阻止安全重装
|
|
430
|
-
|
|
431
|
-
- 触发场景:用户删除某个独立 Compose project 的全部容器后重新执行一键安装,脚本只因目标 yml 仍存在就报错退出;用户不得不手工删除文件,且容易误删其它编排。
|
|
432
|
-
- 根因:安装保护只检查文件存在性,没有区分“仍有运行/停止容器的活跃环境”“容器已清空但本交付 yml 残留”和“身份不明的其它 yml”。
|
|
433
|
-
- 通用规则:可重装脚本应先用 `docker ps -a` 按 project 标签检查全部运行及停止容器;只要存在任何容器就拒绝覆盖。容器为零但目标 yml 存在时,必须确认它是普通文件,校验预期 service、镜像和 `docker compose config`,保存 SHA-256 并归档原文件后才允许重新生成;身份不符、符号链接或语法错误一律停止。不得直接 `rm -f` 未确认身份的生产 yml。
|
|
430
|
+
|
|
431
|
+
- 触发场景:用户删除某个独立 Compose project 的全部容器后重新执行一键安装,脚本只因目标 yml 仍存在就报错退出;用户不得不手工删除文件,且容易误删其它编排。
|
|
432
|
+
- 根因:安装保护只检查文件存在性,没有区分“仍有运行/停止容器的活跃环境”“容器已清空但本交付 yml 残留”和“身份不明的其它 yml”。
|
|
433
|
+
- 通用规则:可重装脚本应先用 `docker ps -a` 按 project 标签检查全部运行及停止容器;只要存在任何容器就拒绝覆盖。容器为零但目标 yml 存在时,必须确认它是普通文件,校验预期 service、镜像和 `docker compose config`,保存 SHA-256 并归档原文件后才允许重新生成;身份不符、符号链接或语法错误一律停止。不得直接 `rm -f` 未确认身份的生产 yml。
|
|
434
434
|
- 自动化检查:先安装并留下有效 yml,再模拟容器全部被删除,断言重复安装会归档旧 yml、保存哈希、重新选端口并保持旧项目不变;再模拟仍有停止容器,断言安装拒绝继续且原 yml 字节不变。
|
|
435
435
|
|
|
436
|
-
###
|
|
437
|
-
|
|
438
|
-
- 触发场景:国内服务器能够拉取平台自有镜像,但 Docker Hub、GitHub、`dl.min.io` 等海外源超时;某个可选服务镜像或安装后的初始化工具下载失败,导致整套一键安装中途退出。
|
|
439
|
-
- 根因:只迁移了 Redis、MySQL 等主要服务镜像,没有把 Compose 中的全部 `image:`、变量镜像和 `curl/wget` 二进制依赖纳入同一份交付清单;辅助 CLI 仍被当作临时下载项,且本机单架构 `docker pull/tag/push` 被误认为已完整复制上游多架构镜像。
|
|
440
|
-
- 通用规则:发布一键安装脚本前必须盘点全部容器镜像和运行期下载 URL。海外服务镜像与辅助 CLI 优先按上游固定版本完整复制到平台国内仓库,脚本引用固定版本标签;适合容器化的 CLI 用短生命周期工具容器执行,并把临时配置目录及时清理。迁移时先核对上游 manifest digest 和平台列表,再保留所有受支持架构及 attestation,禁止用仅 `linux/amd64` 的本地推送冒充多架构镜像。
|
|
441
|
-
- 自动化检查:静态扫描安装脚本,断言业务 `image:` 不再引用未批准的海外仓库、关键初始化不再依赖海外二进制直链;对国内固定标签执行远端 manifest 回读和真实 `docker pull`,核对 digest、平台和容器内版本;运行完整 `bash -n`,并用隔离临时服务跑通辅助 CLI 的连接、写入和回读闭环,最后确认测试容器、网络、卷均已清理。
|
|
442
|
-
|
|
443
|
-
### 复盘:程序能启动但 Obfuscar 找不到共享框架程序集
|
|
436
|
+
### 复盘:现场 Compose 文件名或 project 漂移导致专用更新脚本误报不存在
|
|
444
437
|
|
|
445
|
-
-
|
|
446
|
-
-
|
|
447
|
-
-
|
|
448
|
-
-
|
|
438
|
+
- 触发场景:运维人员手工调整端口、外网 API 地址或重启脚本后,Compose 文件出现历史拼写变体,或容器被目录默认 project 启动;更新脚本仍硬编码标准文件名和初始 project,先报编排不存在,修正文件名后又可能报找不到容器。
|
|
439
|
+
- 根因:把首次安装时的文件名和 project 当成长期不变事实,没有从当前磁盘与运行容器标签回读现场状态。
|
|
440
|
+
- 通用规则:更新脚本应优先采用显式参数;未显式指定时可兼容已知历史文件名,但两个候选同时存在必须停止,禁止猜测。Compose 文件负责配置事实,运行容器的 `com.docker.compose.project` 与 `com.docker.compose.service` 标签负责运行态事实;应先按 service 标签唯一定位运行容器,再分别回读真实 project,并用各自 project 执行 `compose ps/port/up`。若 API 与前端历史上分属不同 project,更新和回滚可在服务身份唯一、project 合法且未显式限定 project 的前提下分别原地执行,禁止通过删除、迁移或改名强行合并拓扑。更新只拉镜像与重建,不得为了适配现场漂移而重新生成或覆盖端口、AuthServer、ApiBase 和网络配置。
|
|
441
|
+
- 自动化检查:覆盖仅标准文件、仅历史拼写文件、两个文件并存、运行 project 使用安装默认值、运行 project 使用目录默认值、API/前端 project 不一致六类场景;断言兼容分支保留现场 yml 字节和动态端口,分别记录 API/前端 project,并在跨 project 成功与失败回滚路径中都使用各自 project;文件歧义及显式 project 不匹配仍应失败关闭。
|
|
442
|
+
|
|
443
|
+
### 复盘:一键安装脚本仍直接拉取海外镜像或工具二进制
|
|
444
|
+
|
|
445
|
+
- 触发场景:国内服务器能够拉取平台自有镜像,但 Docker Hub、GitHub、`dl.min.io` 等海外源超时;某个可选服务镜像或安装后的初始化工具下载失败,导致整套一键安装中途退出。
|
|
446
|
+
- 根因:只迁移了 Redis、MySQL 等主要服务镜像,没有把 Compose 中的全部 `image:`、变量镜像和 `curl/wget` 二进制依赖纳入同一份交付清单;辅助 CLI 仍被当作临时下载项,且本机单架构 `docker pull/tag/push` 被误认为已完整复制上游多架构镜像。
|
|
447
|
+
- 通用规则:发布一键安装脚本前必须盘点全部容器镜像和运行期下载 URL。海外服务镜像与辅助 CLI 优先按上游固定版本完整复制到平台国内仓库,脚本引用固定版本标签;适合容器化的 CLI 用短生命周期工具容器执行,并把临时配置目录及时清理。迁移时先核对上游 manifest digest 和平台列表,再保留所有受支持架构及 attestation,禁止用仅 `linux/amd64` 的本地推送冒充多架构镜像。
|
|
448
|
+
- 自动化检查:静态扫描安装脚本,断言业务 `image:` 不再引用未批准的海外仓库、关键初始化不再依赖海外二进制直链;对国内固定标签执行远端 manifest 回读和真实 `docker pull`,核对 digest、平台和容器内版本;运行完整 `bash -n`,并用隔离临时服务跑通辅助 CLI 的连接、写入和回读闭环,最后确认测试容器、网络、卷均已清理。
|
|
449
|
+
|
|
450
|
+
### 复盘:程序能启动但 Obfuscar 找不到共享框架程序集
|
|
451
|
+
|
|
452
|
+
- 触发场景:框架依赖型 `dotnet publish` 的程序冒烟启动正常,但 Obfuscar 处理某个插件 DLL 时报告 `Unable to resolve dependency: Microsoft.Extensions.*`;此前同一脚本可用,插件新增 `BackgroundService`、Hosted Service 或其它共享框架类型后开始失败。
|
|
453
|
+
- 根因:ASP.NET Core 运行时从 `Microsoft.AspNetCore.App` / `Microsoft.NETCore.App` 共享框架加载程序集,这些 DLL 默认不复制到 framework-dependent 的发布目录;Obfuscar 是离线元数据处理器,只搜索 `InPath` 时无法解析新增基类。同时,插件直接使用的 NuGet API 若只由其它项目传递带入,项目依赖契约也不完整。
|
|
454
|
+
- 通用规则:项目直接使用的包必须在自身 `.csproj` 声明直接 `PackageReference`,但不能把“补 NuGet 引用”误当作 Obfuscar 搜索路径修复。混淆脚本应从发布目录的 `runtimeconfig.json` 读取目标 .NET 主版本,再从 `dotnet --list-runtimes` 动态选择同主版本的最新 `Microsoft.AspNetCore.App` 和 `Microsoft.NETCore.App` 目录,生成绝对路径 `AssemblySearchPath`;禁止硬编码补丁版本,也不要为了混淆把共享框架 DLL 强行复制进最终发布目录。错误提示应保留 Obfuscar 的真实依赖解析错误,不能统一误报“工具未安装”。
|
|
455
|
+
- 自动化检查:使用实际 Git Bash 执行脚本语法检查;定向构建插件并检查 nupkg 明确包含直接依赖;对全部受保护 DLL 执行混淆并验证哈希变化;最后必须启动混淆后的发布目录,断言插件注入、平台初始化和 Kestrel 监听成功,且日志不存在 `FileNotFoundException`、`TypeLoadException`、`Unable to resolve dependency` 或 `Could not load file or assembly`。
|