@microi.net/cli 5.8.5 → 5.8.7
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/LICENSE +21 -21
- package/README.md +71 -71
- package/assets/build-meta.json +7 -7
- package/assets/feature-matrix.json +138 -138
- package/assets/logo.svg +4 -4
- package/cordis.patch.yml +1 -1
- package/package.json +1 -1
- package/scripts/mcp-codex-stdio-adapter.js +0 -0
- package/scripts/mcp-server.js +1 -1
- package/scripts/microi-cli.js +66 -65
- package/scripts/microi-codex-broker.js +450 -450
- package/scripts/microi-codex-router.js +618 -618
- package/scripts/microi-skills.meta.json +384 -384
- package/skills/.microi-skills-version.json +2 -2
- package/skills/.progressive-disclosure-manifest.json +21 -21
- package/skills/README.md +287 -287
- package/skills/ai-engine/SKILL.md +269 -265
- package/skills/ai-engine/agents/openai.yaml +4 -4
- package/skills/ai-engine/references/ai-employees.md +48 -48
- package/skills/ai-engine/references/self-hosted-digital-human.md +59 -59
- package/skills/ai-platform-governance/SKILL.md +177 -177
- package/skills/ai-platform-governance/references/progressive-01-/345/212/237/350/203/275/345/274/200/345/205/263.md +190 -190
- package/skills/app-store/SKILL.md +525 -525
- package/skills/app-store/agents/openai.yaml +4 -4
- package/skills/business-blueprint/SKILL.md +193 -193
- package/skills/datasource-engine/SKILL.md +93 -93
- package/skills/datasource-engine/agents/openai.yaml +4 -4
- package/skills/dos-orm/SKILL.md +97 -95
- package/skills/dos-orm/references/api-reference.md +229 -229
- package/skills/email-engine/SKILL.md +81 -81
- package/skills/email-engine/references/v8-email.md +34 -34
- package/skills/job-engine/SKILL.md +176 -176
- package/skills/job-engine/agents/openai.yaml +4 -4
- package/skills/message-notification/SKILL.md +156 -156
- package/skills/message-notification/agents/openai.yaml +5 -5
- package/skills/message-notification/references/contracts.md +102 -102
- package/skills/microi/SKILL.md +14 -14
- package/skills/microi-ai-app-auth.js +652 -652
- package/skills/microi-ai-application/SKILL.md +115 -115
- package/skills/microi-ai-application/agents/openai.yaml +4 -4
- package/skills/microi-ai-application/references/frontend-baseline.md +164 -164
- package/skills/microi-client-frontend/SKILL.md +246 -244
- package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +144 -144
- package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +196 -196
- package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +167 -167
- package/skills/microi-codex/SKILL.md +102 -100
- package/skills/microi-codex-installer/SKILL.md +231 -231
- package/skills/microi-codex-installer/agents/openai.yaml +7 -7
- package/skills/microi-datasource-mapping/SKILL.md +122 -122
- package/skills/microi-db-schema/SKILL.md +175 -175
- package/skills/microi-db-schema/agents/openai.yaml +4 -4
- package/skills/microi-db-schema/references/core-tables.md +695 -695
- package/skills/microi-db-schema/references/form-component-options.md +256 -256
- package/skills/microi-db-schema/references/schema-overview.md +202 -202
- package/skills/microi-db-schema/references/schema.md +646 -646
- package/skills/microi-db-schema/references/table-catalog.md +1599 -1599
- package/skills/microi-deployment/SKILL.md +222 -220
- package/skills/microi-deployment/references/deployment-matrix.md +109 -109
- package/skills/microi-docs-coverage/SKILL.md +133 -133
- package/skills/microi-docs-coverage/references/capability-map.md +91 -91
- package/skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +894 -894
- package/skills/microi-form-engine/SKILL.md +333 -333
- package/skills/microi-form-engine/references/component-catalog.md +218 -218
- package/skills/microi-form-engine/references/data-source-events.md +124 -124
- package/skills/microi-form-layout/SKILL.md +205 -205
- package/skills/microi-form-layout/references/progressive-01-3-/344/270/211/347/247/215/345/210/206/347/273/204/347/232/204/345/255/230/345/202/250/344/270/216/351/205/215/347/275/256.md +235 -235
- package/skills/microi-frontend-sdk/SKILL.md +194 -194
- 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 +176 -176
- package/skills/microi-left-right-layout/SKILL.md +141 -141
- package/skills/microi-microservice/SKILL.md +328 -326
- package/skills/microi-microservice/references/runtime-delivery.md +278 -278
- package/skills/microi-mobile-app-quality/SKILL.md +185 -185
- 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 +213 -213
- package/skills/microi-mobile-app-quality/references/progressive-02-9-/344/270/273/351/242/230/345/210/207/346/215/242/345/277/205/351/241/273/347/234/237/345/256/236/344/270/224/345/205/250/345/261/200/347/224/237/346/225/210.md +128 -128
- package/skills/microi-solution-quotation/SKILL.md +78 -78
- package/skills/microi-solution-quotation/agents/openai.yaml +4 -4
- package/skills/microi-solution-quotation/scripts/build_solution_quote.py +296 -296
- package/skills/microi-sso/SKILL.md +96 -90
- package/skills/microi-sso/references/acceptance.md +49 -49
- package/skills/microi-sso/references/configuration-and-security.md +53 -53
- package/skills/microi-sso/references/inbound.md +53 -53
- package/skills/microi-sso/references/outbound.md +39 -39
- package/skills/microi-system-delivery/SKILL.md +137 -137
- package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +193 -193
- package/skills/microi-system-delivery/references/progressive-02-/350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/345/277/205/351/241/273/350/246/206/347/233/226/347/232/204/345/235/221.md +217 -217
- package/skills/microi-ui/SKILL.md +192 -192
- package/skills/microi-ui/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/234/272/346/231/257/350/223/235/345/233/276.md +183 -183
- package/skills/microi-uniapp-frontend/SKILL.md +193 -193
- package/skills/microi-uniapp-frontend/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/210/206/347/261/273-/345/217/214/346/240/217/345/210/227/350/241/250/347/213/254/347/253/213/346/273/232/345/212/250.md +225 -225
- package/skills/microi-uniapp-frontend/references/progressive-02-/345/205/263/351/224/256/344/270/232/345/212/241/350/265/204/344/272/247/344/270/215/345/276/227/351/273/230/350/256/244/351/200/211/344/270/255.md +154 -154
- package/skills/microi.v8.js +1921 -1921
- package/skills/module-engine/SKILL.md +255 -255
- package/skills/module-engine/references/module-config.md +204 -204
- package/skills/ocr-engine/SKILL.md +113 -113
- package/skills/ocr-engine/agents/openai.yaml +4 -4
- package/skills/page-engine/SKILL.md +206 -206
- package/skills/page-engine/examples/compact-dashboard.json +1444 -1444
- package/skills/page-engine/references/progressive-01-/346/211/200/346/234/211/347/273/204/344/273/266/347/261/273/345/236/213.md +234 -234
- package/skills/page-engine/references/progressive-02-/347/211/210/346/234/254/345/216/206/345/217/262-/345/271/266/345/217/221/344/277/235/345/255/230/344/270/216/345/233/236/346/273/232.md +60 -60
- package/skills/performance-testing/SKILL.md +221 -221
- package/skills/playwright-e2e/SKILL.md +196 -196
- package/skills/playwright-e2e/references/progressive-01-/345/205/250/350/207/252/345/212/250/347/231/273/345/275/225-/345/205/215/351/252/214/350/257/201/347/240/201-/344/275/206/344/270/215/345/205/215/345/257/206/347/240/201-/345/277/205/350/257/273.md +173 -173
- package/skills/playwright-e2e/references/progressive-02-/346/226/207/345/255/227/345/257/271/346/257/224/345/272/246/344/270/216/345/217/257/350/257/273/346/200/247/350/207/252/345/212/250/345/214/226/346/243/200/346/237/245-/345/277/205/345/201/232.md +183 -183
- package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +221 -221
- package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +115 -115
- package/skills/print-engine/SKILL.md +259 -259
- package/skills/production-readonly-audit/SKILL.md +41 -41
- package/skills/report-engine/SKILL.md +71 -71
- package/skills/report-engine/agents/openai.yaml +4 -4
- package/skills/scripts/optimize-progressive-disclosure.mjs +204 -204
- package/skills/scripts/refresh-progressive-disclosure.mjs +64 -64
- package/skills/scripts/sync-embedded-skills.mjs +46 -46
- package/skills/scripts/validate-progressive-disclosure.mjs +57 -57
- package/skills/search-engine/SKILL.md +75 -75
- package/skills/search-engine/agents/openai.yaml +4 -4
- package/skills/spider-engine/SKILL.md +190 -190
- package/skills/system-observability/SKILL.md +249 -246
- package/skills/system-observability/references/memory-incident-triage.md +77 -77
- package/skills/translate-engine/SKILL.md +140 -140
- package/skills/translate-engine/agents/openai.yaml +4 -4
- package/skills/ui-design/SKILL.md +223 -223
- package/skills/ui-design/assets/pattern-showcase/app.js +54 -54
- package/skills/ui-design/assets/pattern-showcase/index.html +163 -163
- package/skills/ui-design/assets/pattern-showcase/styles.css +311 -311
- package/skills/ui-design/assets/templates/MCI-DESIGN.md +206 -206
- package/skills/ui-design/references/design-pattern-library.md +184 -184
- package/skills/ui-design/references/mci-design-contract.md +163 -163
- package/skills/ui-design/references/motion-and-media.md +78 -78
- package/skills/ui-design/references/product-flow-recipes.md +94 -94
- package/skills/ui-design/references/progressive-01-/351/242/234/350/211/262/344/275/223/347/263/273-css-variables-/346/224/257/346/214/201/344/270/273/351/242/230/345/210/207/346/215/242.md +218 -218
- package/skills/ui-design/references/progressive-02-/345/255/227/344/275/223.md +164 -164
- package/skills/ui-design/references/progressive-03-/345/212/250/346/225/210/350/247/204/350/214/203-/344/270/260/345/257/214/344/275/206/344/270/215/345/215/241.md +235 -235
- package/skills/ui-design/references/progressive-04-/347/273/204/344/273/266/351/243/216/346/240/274/351/200/237/346/237/245.md +152 -152
- package/skills/ui-design/references/progressive-05-/347/247/273/345/212/250/347/253/257/344/270/223/347/224/250/350/247/204/350/214/203.md +238 -238
- package/skills/ui-design/references/progressive-06-/344/270/273/351/242/230/345/210/207/346/215/242/345/256/236/347/216/260.md +194 -194
- package/skills/ui-design/references/progressive-07-/351/200/237/346/237/245-/344/273/216/345/244/264/346/220/255/345/273/272/344/270/200/344/270/252/347/247/273/345/212/250/347/253/257/351/241/265/351/235/242.md +207 -207
- package/skills/ui-design/references/progressive-08-/350/241/250/345/215/225/345/210/206/347/273/204/350/247/204/350/214/203-tabs-vs-collapsegroup-/345/274/272/345/210/266.md +142 -142
- package/skills/uniapp-mall-assets/SKILL.md +176 -176
- package/skills/unity-integration/SKILL.md +171 -171
- package/skills/unity-integration/agents/openai.yaml +4 -4
- package/skills/unity-integration/references/ai-app-delivery.md +119 -119
- package/skills/unity-integration/references/sdk-api.md +82 -82
- package/skills/unity-integration/references/toolbox-migration.md +66 -66
- package/skills/unity-integration/references/webgl-hosting.md +57 -57
- package/skills/v8-api-config/SKILL.md +388 -388
- package/skills/v8-cache-pattern/SKILL.md +312 -312
- package/skills/v8-crud-api/SKILL.md +178 -178
- package/skills/v8-crud-api/references/progressive-01-/346/237/245/350/257/242/345/210/227/350/241/250-/345/210/206/351/241/265.md +226 -226
- package/skills/v8-crud-api/references/progressive-02-where-/346/235/241/344/273/266/350/257/255/346/263/225/351/200/237/346/237/245.md +49 -49
- package/skills/v8-debugging/SKILL.md +284 -284
- package/skills/v8-explorer-tree/SKILL.md +228 -228
- package/skills/v8-export-import/SKILL.md +219 -219
- package/skills/v8-export-import/references/progressive-01-excellayout-/351/253/230/347/272/247/350/207/252/347/224/261/345/270/203/345/261/200.md +211 -211
- package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +202 -202
- package/skills/v8-export-import/references/progressive-03-/345/256/211/345/205/250-/346/200/247/350/203/275/346/263/250/346/204/217.md +42 -42
- package/skills/v8-file-upload/SKILL.md +284 -284
- 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 +263 -263
- package/skills/v8-file-upload/references/progressive-02-office-/346/226/207/344/273/266/345/234/250/347/272/277/347/274/226/350/276/221/347/211/210/346/234/254/345/217/267/350/247/204/345/210/231.md +161 -161
- package/skills/v8-formengine-http/SKILL.md +238 -238
- package/skills/v8-frontend-events/SKILL.md +180 -180
- package/skills/v8-frontend-events/references/bluetooth-print-api.md +135 -135
- package/skills/v8-frontend-events/references/bluetooth-print.md +258 -258
- package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +219 -219
- package/skills/v8-http-integration/SKILL.md +182 -182
- package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +220 -220
- package/skills/v8-http-integration/references/progressive-02-/351/224/231/350/257/257/345/244/204/347/220/206/346/250/241/345/274/217.md +44 -44
- package/skills/v8-image-processing/SKILL.md +190 -190
- package/skills/v8-image-processing/agents/openai.yaml +4 -4
- package/skills/v8-image-processing/references/api-reference.md +623 -623
- package/skills/v8-menu-buttons/SKILL.md +186 -186
- package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +222 -222
- package/skills/v8-menu-buttons/references/progressive-02-8-/346/250/241/345/274/217-f-/345/220/216/345/217/260/344/273/273/345/212/241/346/214/211/351/222/256-/351/225/277/344/273/273/345/212/241.md +228 -228
- package/skills/v8-menu-buttons/references/progressive-03-10-/345/217/215/346/250/241/345/274/217-/351/201/277/345/205/215.md +104 -104
- package/skills/v8-mongodb/SKILL.md +200 -200
- package/skills/v8-mq-mqtt/SKILL.md +176 -176
- package/skills/v8-mq-mqtt/references/mqtt-production.md +342 -342
- package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +181 -181
- package/skills/v8-mq-mqtt/scripts/check-mqtt-skill-coverage.mjs +203 -203
- package/skills/v8-saas-multi-tenant/SKILL.md +305 -305
- package/skills/v8-security/SKILL.md +210 -210
- package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +200 -200
- package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +160 -160
- package/skills/v8-sql-query/SKILL.md +302 -302
- package/skills/v8-table-event/SKILL.md +176 -176
- package/skills/v8-table-event/references/progressive-01-informv8-js-/350/241/250/345/215/225/346/211/223/345/274/200/344/272/213/344/273/266.md +216 -216
- package/skills/v8-table-event/references/progressive-02-/345/211/215/347/253/257/344/272/213/344/273/266/345/220/215-v8-eventname-/345/217/257/350/203/275/347/232/204/345/200/274.md +46 -46
- package/skills/v8-tcp-integration/SKILL.md +147 -147
- package/skills/v8-tcp-integration/agents/openai.yaml +4 -4
- package/skills/v8-template-engine/SKILL.md +167 -167
- package/skills/v8-utilities/SKILL.md +104 -104
- package/skills/v8-utilities/references/client-api-index.md +143 -143
- package/skills/v8-utilities/references/platform-http-routes.md +83 -83
- package/skills/v8-utilities/references/server-api-index.md +188 -188
- package/skills/v8-workflow/SKILL.md +252 -252
- package/skills/v8-workflow/references/progressive-01-/350/212/202/347/202/271/345/274/200/345/247/213-v8-/344/272/213/344/273/266.md +180 -180
- package/skills/v8-workflow/references/workflow-configuration.md +49 -49
- package/skills/vision-engine/SKILL.md +160 -160
- package/skills/vision-engine/agents/openai.yaml +4 -4
- package/skills/vision-engine/references/architecture-and-acceptance.md +194 -194
- package/skills/workspace-conventions/SKILL.md +273 -273
- package/skills/workspace-conventions/references/progressive-01-/347/211/210/346/234/254/346/233/264/346/226/260/346/227/245/345/277/227/344/277/235/346/212/244/350/247/204/345/210/231-/345/274/272/345/210/266.md +209 -209
- package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +217 -217
- package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +27 -27
|
@@ -1,525 +1,525 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: app-store
|
|
3
|
-
description: Microi 应用商城开发、打包、安装和升级规范。用于官方/社区应用、Manifest、源码与构建产物、依赖、后台安装任务、租户隔离、增量升级、回滚和验收。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
> **Microi吾码基础规范(强制):** 任何 AI 模型与宿主每次新建或接续吾码任务,先完整读取 `../workspace-conventions/SKILL.md`,必须执行版本播报、`@microi.net/cli` 后台自动升级、Skills/MCP 同步和进度播报。安装与诊断读取 `../microi-codex-installer/SKILL.md`;更新失败延后重试,不阻断当前工作。
|
|
7
|
-
|
|
8
|
-
# Microi 应用商城
|
|
9
|
-
|
|
10
|
-
## 核心原则
|
|
11
|
-
|
|
12
|
-
应用包是可审计、可重复安装、可增量升级的交付单元。运行类型使用 `ApplicationType`:普通平台包的新建默认值是 `Regular`,既有商城平台应用/通知仍使用 `Platform`,另外还有 `MicroService`、`UniApp`、`Web`;读取端必须兼容 `Regular/Platform`,不能在迁移完成前强制改单值。官方/社区来源使用 `PublisherType`。
|
|
13
|
-
|
|
14
|
-
`AppType` 是历史复用字段:旧包/接口曾把它用于官方/社区来源,也曾把它作为运行类型回退。新代码不能把 `AppType` 当事实源;只在读取旧数据时回退,写入新数据使用 `ApplicationType + PublisherType`。
|
|
15
|
-
|
|
16
|
-
应用包是声明式资源的权威交付边界:当前包标记为 `Managed` 的表单元数据、菜单、字段、接口引擎等资源按包覆盖;当前包标记为 `CreateIfMissing` 或 `InsertIfMissing` 的租户扩展/配置只补缺。覆盖安装不等于整表清空,仍禁止把发布方租户业务数据、密钥或连接配置原样复制到目标租户。
|
|
17
|
-
|
|
18
|
-
## 平台升级的应用商城边界(强制)
|
|
19
|
-
|
|
20
|
-
- 表、字段、Tab、菜单、权限、接口引擎、事件、数据源、页面、打印、工作流、任务和可幂等种子数据都应通过应用包升级;不得为这些资源在 `Microi.Server/Microi.Upgrade/` 新增租户定制 .NET 代码。
|
|
21
|
-
- 有官方 MCP 权限时,固定使用 `microi_itdos`(`https://api.itdos.com`、`OsClient=iTdos`)更新官方母版、制作并发布对应应用,按内容哈希/包版本回读后,再由目标租户 MCP 安装或更新。无官方权限时只通过当前用户自己的 MCP/Manifest 更新其数据库并回读,不得假借通用升级器越权发布官方应用。
|
|
22
|
-
- `Microi.Upgrade` 只保留应用商城/安装器启动前必需的核心物理兼容或协议迁移,并要求持久化版本门、共享租约、幂等、失败不推进版本。禁止每次启动对每个租户重跑不断增长的历史迁移清单。
|
|
23
|
-
- 新增升级点前必须完成“商城不可表达性”证明:逐项说明为什么 `DiyTables/DiyFields/DDLStatements/PhysicalColumns/DataSets`、菜单、接口引擎、工作流或 AI 应用包无法交付,以及为什么该结构在登录/商城恢复入口可用前就必须存在。不能证明时一律升级对应官方应用包;客户租户缺少某张业务表不得写成全平台 `.NET` 启动迁移。
|
|
24
|
-
- 历史升级点不能因为今天可由商城表达就直接删除:若后续步骤依赖其物理结果,须保留为冻结兼容链,或把必要前置检查显式并入后续步骤。新增步骤必须使用高于当前目标的唯一四段版本并追加到链末尾,不得抬高旧步骤版本造成非单调执行顺序。
|
|
25
|
-
- 租户协调器必须先只读 `ServerVersion`:已达到当前一次性基线时不得取得升级租约、重放历史不变量或刷新缓存;落后租户取得共享租约后必须再次读取版本,防止多节点重复执行。启动成本应近似“每租户一次版本读取 + 实际待执行迁移”,不得近似“租户数 × 历史升级点总数”。主租户接流量前的最小物理/商城引导门禁可独立保留,但不得扩展成全部子租户的永久全量扫描。
|
|
26
|
-
- 同一批历史漂移确需修复时,用一个新版本的“一次性基线”在租约内幂等封口,并仅在全部步骤强回读成功后前向推进版本;失败不得推进。基线完成后,任何新增核心迁移都必须再升版本,任何业务资源修复都必须再升应用包版本,禁止恢复为每次启动复检。
|
|
27
|
-
- 平台通用缺陷的交付证据必须分开记录:源码修复、官方母版资源、商城包发布后回读、目标租户后台安装任务、目标租户资源回读和真实 UI/接口验收;其中任一步未完成都不能笼统称为“已发布并安装”。
|
|
28
|
-
- 任何计划让全部吾码租户通过“安装/更新官方应用”获得的标准字段、布局、菜单、页面或种子数据,必须先在官方 `microi_itdos` 主租户创建并回读,再从该主租户按精确菜单/表资源导出新版包、单调递增应用版本并发布。包正文以 `PackageHdfsPath + PackageSha256 + PackageSize` 为事实源;`AppPakcet` 只作旧版读取兼容,验证完成后应为空。禁止先只在客户/子租户补字段,再用本地手工 JSON 冒充官方母版;客户验证应发生在官方包发布之后。
|
|
29
|
-
- 同一标准能力若同时属于基础 SaaS 空库包和独立官方应用(例如系统设置、系统账号),两条交付链都要更新:基础包保证新租户初始化完整,独立应用保证存量租户可增量安装。表、字段和初始化模板可按这两个目标分别交付,但同一个 Managed ApiEngineKey 必须只有一个官方包所有者,禁止 SaaS、Store 与独立应用重复携带后互相覆盖。发布后分别核对 `PackageInfo.Version`、物理列、`diy_field` 布局节点、接口引擎单一归属、商城行 `AppVersion` 和 HDFS 包指针/下载哈希,不能用其中一条替代另一条。
|
|
30
|
-
|
|
31
|
-
## 吾码创建人开发时的强制发布闭环
|
|
32
|
-
|
|
33
|
-
- 每项平台功能先执行 [工作区基础规范](../workspace-conventions/SKILL.md) 的“平台功能四项同步检查”,不能把商城包发布当成官方文档、Skills、MCP 同步的替代。本节细化其中需要发布应用包时的流程;没有可打包资源变化时记录依据,不为凑检查项空升版。
|
|
34
|
-
- 每次任务先检查工作区根的 `Microi.Server/Microi.net/`。只有目录存在且 `rg --files Microi.Server/Microi.net` 能找到至少一个真实源码文件时,才确认当前是吾码创建人在官方完整源码工作区开发;空目录不算,且不要求本次修改位于该目录。确认后,对任意目录中的平台基础能力执行修改、构建或交付时,官方应用数据包都不是“以后再补”的附加产物,而是本次实现的组成部分。目录缺失或为空时按普通用户工作区处理;纯审查、解释或诊断仍保持只读。
|
|
35
|
-
- 触发资源包括系统设置、表、字段、Tab、菜单、权限、接口引擎、事件、数据源、页面、打印、工作流、任务、平台内置微服务和可幂等种子数据。开始修改时就确定资源归属:租户开通、启动投影与基础空库归 `app.microi.saas-engine`;用户偏好、个人资料及其租户 Hook 归 `app.microi.sys_user`;租户系统设置编排及其 Hook 归 `app.microi.sys-config`;表单引擎归 `app.microi.form-engine`;模块引擎归 `app.microi.module-engine`;应用商城归 `app.microi.store`。同一能力跨多个包时逐包更新,但同一 Managed ApiEngineKey 仍须单一归属。
|
|
36
|
-
- 强制闭环依次包含:①源码和定向测试;②通过绑定 `https://api.itdos.com + OsClient=iTdos` 的 `microi_itdos` 更新并回读官方母版资源;③从母版导出或按受审计发布契约生成本地应用包,单调提升包版本并核对资源数量、版本和 SHA-256;④发布对应官方 Platform 应用;⑤重新读取商城行的小型 HDFS 指针,用公有下载或受权私有下载取得原始 JSON,核对 `Published/IsApprove`、`AppVersion`、`PackageInfo.Version`、UTF-8 字节数、SHA-256 和资源正文;⑥立即做一次同输入幂等重跑,确认无重复升版或漂移。任务还指定目标租户时,再安装/更新并等待后台任务 `Succeeded` 后回读真实资源。
|
|
37
|
-
- 本地包文件、生成器成功、单元测试通过、返回 TaskId 或 HTTP 200 都不能代替官方主数据库与商城回读。`.resource-sync-base` 只能在官网发布后逐项哈希一致时由同步器推进,不得与本地候选一起手工修改。若官方身份、MCP 登录或发布门禁失效,必须保留准确的未发布边界并修复链路;不得把本地 JSON 宣称为“其它吾码用户已经可以安装”。
|
|
38
|
-
- 应用包不得携带真实地图 Key、Token、连接串或其它租户秘密。浏览器供应商 Key 等配置只交付字段/设置模板和安全读取能力,实际值由每个目标租户在安装后自行填写。
|
|
39
|
-
|
|
40
|
-
### 后台原生规则的两种可信来源证明
|
|
41
|
-
|
|
42
|
-
普通租户的编译证明默认 `TenantInstallation`,保留真实 Installed 回执及旧摘要。官方同租户发布源禁止安装自己,只能由后端发行组合明确固定 `OfficialPublishedSnapshot`:`InstallRecordId` 绑定 `mic_data_version.Id`,原始 `Data` 的UTF-8 SHA-256另固定于编译回执并参与独立审批摘要。该类别与快照摘要不从Param或自由表字段选择、不新增表字段、不伪造Installed。受信官方身份、当前Published/审批有效指针、Verified包hash/size/HDFS、不可变快照、V3 Completed源码hash及实际DLL依赖须全部匹配;当前状态变化、软删或主库不可用下次调用立即拒绝,旧历史存在不足以授权。跨租户仍拒绝,结构发布不等于后端安装或代码审批。审批表纳入通用强制管理员清单,普通用户即使误授表/菜单权限仍不得改授权状态;V8Limit和ReadPrimary不是写权限。
|
|
43
|
-
|
|
44
|
-
## 包内容
|
|
45
|
-
|
|
46
|
-
### 仅共享编译运行产物
|
|
47
|
-
|
|
48
|
-
- 消费者只需运行应用、无需安装业务资源时,显式传 `RuntimeAssetsOnly=true`;只接受 `ProtocolVersion=3 + ApplicationType=Web + 显式 IncludeSource=false` 和通过现有 `CommittedProof`、运行清单校验的 `SharedPublicRuntime`。不能把“不包含源码”自动等同于此模式;省略或 `false` 保持原有打包行为。
|
|
49
|
-
- 请求的菜单、表、接口、移除接口、工作流、任务、数据、路由、页面及资源策略选择均必须为空;既有商城行的 `SelectMenu/SelectTable/SelectApiEngine/SelectData` 和 `PreparedAssets.MenuContract` 非空时拒绝,禁止静默清理历史选择。不能与 `DatabaseOnlyBuild` 混用。
|
|
50
|
-
- 现有 `microi_run_engine` 的 `params` 是动态对象,可传此开关,无需增加工具参数。对 `ai_app_publish_store` 的 `Action=InspectResourceSnapshot` 和 `Action=Publish` 都使用同一组冻结模式、版本、资产及提交证明,后者将前者返回的 `ResourceSnapshotHash` 作为 `ExpectedResourceSnapshotHash` 传入。MCP 的 `confirmExecution` 仍必须匹配引擎 Key。
|
|
51
|
-
- 下载真实发布包后,断言 `DDLStatements/PhysicalColumns/DiyTables/DiyFields/DataSets/SysMenus/WfFlowDesigns/WfNodes/WfLines/SysApiEngines/ScheduleJobs` 十一项数组全部为零,`SourceFiles/BuildAssets` 为零,`SourceZip/BuildZip` 为空,唯一运行交付为 `SharedPublicRuntime`。源码分发、服务端业务迁移和共享运行入口是独立事实,不能将共享公有编译产物当成目标租户已有业务接口或权限。
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
#发布器 `v2.1.2` 修复受管接口更新后的重复发布摘要漂移:源码、`Managed` 策略和所有权均与已发布包相同时,保留该包的有效基线;真正的源码变更仍推进基线并保留历史兼容摘要。缺失或无效基线从实际旧源码重新建立,`CreateIfMissing` 租户 Hook 保持原策略。`Inspect` 与 `Publish` 必须使用相同的冻结 `PreparedAssets` 和资源选择,并在发布后立即重放原请求,独立核对包 SHA-256、字节数和不可变快照 Id;重放被 CAS 拒绝仍算失败,不能仅以首次成功声称幂等。
|
|
55
|
-
|
|
56
|
-
## 共享表的稀疏字段选集
|
|
57
|
-
|
|
58
|
-
应用只扩展已有共享表的少数字段时,标准导出器和 `ai_app_publish_store` 接收
|
|
59
|
-
`SparseTableSelections: [{ TableId, FieldIds }]`。Id 必须来自当前租户权威元数据,
|
|
60
|
-
最多 32 张表、每表 512 个非重复字段;不接受调用方传表正文、DDL 或布局覆盖。
|
|
61
|
-
同一表不能同时进入完整 `TableIds` 与稀疏选集,安装基础设施表不能被裁剪。
|
|
62
|
-
|
|
63
|
-
导出只保留表 `Id/Name`、所选字段和对应物理列;不携带共享 `Tabs/Column`、
|
|
64
|
-
其它字段、建表或索引。数据只允许 `InsertIfMissing`,行与冲突字段必须在选集中。
|
|
65
|
-
没有数据行的共享表自动生成标准零行 `DataSet`,复用安装前置检查:缺物理表或
|
|
66
|
-
共享表元数据时,在资源写入前失败;不是自动安装依赖,也不是空库建表契约。
|
|
67
|
-
|
|
68
|
-
旧导入器会拒绝受保护共享表的零行 DataSet。须先升级包含
|
|
69
|
-
`EMPTY_SHARED_TABLE_PREREQUISITE_V1` 的商城安装器,再安装混合应用。
|
|
70
|
-
新分支仅接受严格零行形状,不给受保护表业务数据增加写权限。
|
|
71
|
-
普通 DataSet 仍要求完整建表资源,不能借稀疏分支绕过结构闭包。
|
|
72
|
-
|
|
73
|
-
导出器 `v1.3.8` 修复稀疏默认数据的序列化形状:未声明实际父绑定时,
|
|
74
|
-
必须完全省略 `ParentBinding` 键,不能用 `undefined` 让宿主转成 `null`;
|
|
75
|
-
普通配置子表的显式绑定保持原契约,稀疏导入安全门不放宽。
|
|
76
|
-
仅保留稀疏选集中字段在源记录上真实存在的空字符串;NULL、缺失字段、
|
|
77
|
-
未选字段不推断默认值,跨租户与隐藏元数据仍排除,普通全表导出保持旧行为。
|
|
78
|
-
数值 `0` 原本就保留;秘密状态必须经已有可信设置入口规范源数据,
|
|
79
|
-
不能由导出参数或包正文合成。升级后重新 Inspect 并冻结新摘要,旧快照不可改写。
|
|
80
|
-
|
|
81
|
-
安装器 `v3.0.5` 同时执行 `SPARSE_TABLE_IMPORT_PREFLIGHT_V2`:直接传包和下载包均在进度持久化、物理兼容自举及资源写入前核验原始稀疏正文和目标。严格零行依赖不能由同包 `CREATE` 自行满足;带默认数据的稀疏表也必须已有实体表及唯一未删除的表单元数据。MySQL/SQL Server 查询要求 `BASE TABLE`,Oracle 使用 `USER_TABLES`。共享表只接受 `Id/Name`、精确字段与物理列及 `InsertIfMissing` 数据,不接受布局、其它字段、字段退役或该表 DDL;非空数据集可保留标准导出的 `TableDescription`,该描述不授权更新共享表布局。
|
|
82
|
-
|
|
83
|
-
`DECLARATIVE_PACKAGE_DDL_PREFLIGHT_V1` 在同一写前门禁逐字符识别引号和注释,按实际 SQL 目标核对声明表名,只接受受支持的 `CREATE TABLE`、`CREATE INDEX` 与列/索引 `ALTER TABLE`。DML、动态执行、多语句、未知声明、MySQL/MariaDB 可执行注释及提示一律拒绝。字符串内部的分号和普通注释可保留;含反斜杠的引号内容因 SQL mode/方言歧义拒绝,改用 SQL 标准重复引号。现有官方包 DDL 已做字节绑定的解析回归;这不等于所有数据库版本上的实际 SQL 执行验收,未支持的方言模板须先补明确语法和回归,不能降级原样执行。
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
Web 应用可用 `RuntimeAssetsOnly=false + IncludeSource=false` 同时携带
|
|
87
|
-
`SharedPublicRuntime` 和声明式资源,六张标准应用基础设施表仍按权威闭包导出。
|
|
88
|
-
Inspect 和 Publish 使用完全相同的选择、`CommittedProof` 及运行清单,Publish
|
|
89
|
-
再传 `ExpectedResourceSnapshotHash`;旧稀疏选集必须显式刷新,不能退化为整表。
|
|
90
|
-
`RuntimeAssetsOnly=true` 继续拒绝任何资源选集。
|
|
91
|
-
|
|
92
|
-
现有 `microi_run_engine.params` 为通用对象,已能原样透传此选集,仍须
|
|
93
|
-
`confirmExecution`。这不代表线上导出器已升级,也不能以私有源码含 Manifest
|
|
94
|
-
代替正式包资源。接口默认禁用须另按实时能力配置并独立回读;当前
|
|
95
|
-
`microi_generate_system` 的引擎 upsert 不会透传 `IsEnable/StopHttp`。
|
|
96
|
-
|
|
97
|
-
后台规则审批表 `mci_runtime_installation` 的结构可由责任包安装,但审批业务行
|
|
98
|
-
禁止经导出/导入 DataSets 种入、覆盖或恢复;只有严格零行依赖允许通过。
|
|
99
|
-
可信程序集注册与管理员审批是独立动作,不能以商城发布或包安装代替。
|
|
100
|
-
|
|
101
|
-
标准官方控制面现将 `export-package.js` 纳入固定单资源白名单,沿用
|
|
102
|
-
`Resources[{Name,Content,ExpectedRemoteSha256}]`、可信官方授权、同事务行锁及回读。
|
|
103
|
-
先 CAS 升级控制面,再 CAS 发布导出/导入/发布器,最后从完整母版发行归属商城包;
|
|
104
|
-
源码、包正文、不可变快照和公开下载都须独立验证,不能只更新本地镜像。
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
### 物理索引闭包
|
|
108
|
-
|
|
109
|
-
标准导出器必须同时导出责任表的真实唯一索引和普通复合索引,按列顺序生成独立
|
|
110
|
-
`CREATE INDEX` DDL。组合 AI 应用包按“表 + 索引名”区分物理对象;不能只按表名
|
|
111
|
-
合并 DDL,否则建表语句会吞掉全部索引。同名索引定义冲突须失败,不能任选一条。
|
|
112
|
-
|
|
113
|
-
当前标准物理结构导出支持 MySQL/MariaDB 的完整列升序 BTREE 与 Id 主键;前缀、
|
|
114
|
-
表达式、全文、降序或其它源数据库需使用已审计的专用包,标准导出须明确拒绝,不能
|
|
115
|
-
静默发布缺约束包。此边界指源库导出,不等同于目标安装器的数据库支持范围。
|
|
116
|
-
|
|
117
|
-
发布前使用 `microi_get_table_indexes` 对照包内独立 DDL;安装完成后再次核对索引名称、
|
|
118
|
-
唯一性和有序列集合,并测试业务重复键拒绝及重复安装不复制索引。母版存在索引、
|
|
119
|
-
应用页面正常、安装任务成功均不能单独证明目标库的索引完整。
|
|
120
|
-
|
|
121
|
-
### 空库清理与开发期应用
|
|
122
|
-
|
|
123
|
-
安装包应显式登记菜单、表、接口、工作流、任务和微服务的完整归属,供导出、升级和空库制作共同使用。开发期只发布运行资产而尚未制包时,不能假定商城选集已经覆盖新建业务表;应通过现有空库规则接口预览,逐项核对实际物理表、DIY元数据、菜单后代与接口Key。缺失时在责任清理器补充有限、明确的业务归属识别,保留平台核心白名单,读取失败停止制作。只生成SQL与在隔离临时库执行清理是不同动作,禁止在源主库执行脱敏SQL。
|
|
124
|
-
|
|
125
|
-
清理业务应用时同时按StoreId移除其HDFS包索引,再删除商城主记录,保留平台包索引;历史库缺少索引表时兼容跳过。数据库清理不等于删除HDFS对象,禁止借制作空库清除正式已发布文件。
|
|
126
|
-
|
|
127
|
-
空库安装历史须能对应保留平台应用的稳定身份,显式 `StoreId` 优先,缺失时才使用非空的旧应用身份;不能按名称或应用前缀猜测归属。角色清理须同时覆盖业务角色、保留账号的角色绑定、角色权限快照及孤立菜单权限,并验证初始模板角色等级与新租户登录。不能把空库清理策略用于卸载应用或清理正在使用的租户。
|
|
128
|
-
|
|
129
|
-
空库还须清理源租户的业务组织和旧版账号关系,按已校验的初始组织模板重建保留账号部门;平台组织和关系表只清理数据,保留结构。新租户组织树与账号部门必须实际回读和浏览器验收,不能因角色、菜单已清理就推定部门也已清理。
|
|
130
|
-
|
|
131
|
-
旧布局字段的退役使用可选 `DiyFieldRetirements` 数组,声明 `TableName / Name / ExpectedComponent`,按需用 `ExpectedConfig` 限定组件路径。安装器只允许退役当前包声明表中的 `DevComponent / Divider / Tabs / CollapseGroup`;核心字段、仍在包内声明的字段或控件配置不匹配必须拒绝。先安装支持此协议的商城,再安装声明退役的业务包。退役只软删字段元数据并回读、刷新缓存,不删除物理列或业务数据;已经退役或尚未安装的字段重复执行不产生副作用。
|
|
132
|
-
|
|
133
|
-
- Manifest:应用 Key、版本、兼容平台版本、依赖和资源清单。
|
|
134
|
-
- 数据模型:表、字段、菜单、角色权限、接口引擎、事件、数据源、页面、打印、工作流、任务。
|
|
135
|
-
- 源码与构建:私有源码包与可部署构建包分离,记录 SHA-256。源码 ZIP 必须按当前应用
|
|
136
|
-
`PrivateSourcePath` 的已提交活动根选择当前私有行(`VersionId` 为空、`StorageScope=Private`、
|
|
137
|
-
非目录且未删除),禁止把历史版本、未提交源、上传会话或 `upload/v*` 编译文件混入。
|
|
138
|
-
已完成原子同步后的活动根可以仍在 staged 目录,不能只按目录名猜测提交状态。
|
|
139
|
-
安装器必须把包内源码复制到当前租户私有桶中的清单摘要根
|
|
140
|
-
`ai-app-source-staged/{AppId}/store-{SourceManifestHash}`,对象地址精确等于该根加原始
|
|
141
|
-
`FilePath`,保留大小写、中文与空格。时间戳上传地址不能作为活动源码;旧对象必须保留。
|
|
142
|
-
使用既有 `CopyObject/ObjectExist/GetObjectSha256` 校验复制目标的原始字节与长度后再更新
|
|
143
|
-
当前元数据。同版本重装也修正旧路径;复制响应未知先回读目标,目标不同或能力缺失失败
|
|
144
|
-
关闭。复制及当前游标的对象验签计入分片预算,持久前缀只复用同一包摘要根的精确元数据。
|
|
145
|
-
安装器从 `Build/BuildRepair` 或后续应用检查点恢复时,已完成的源码前缀仍按同一
|
|
146
|
-
清单摘要根复用,不能重新消耗源码分片预算并退回 `Source`。未知资产类型、当前及
|
|
147
|
-
后续未校验条目、非规范根或元数据差异仍需验证;升级导入器后恢复原任务及原请求键。
|
|
148
|
-
ZIP 导出前后必须以原始 `FilePath/ContentHash/Size` 的完整当前清单重新核对 `store-` 根
|
|
149
|
-
摘要;分片切换后的部分旧根、清单漂移和摘要根格式错误均拒绝。去掉 `source/` 的归档名
|
|
150
|
-
不能代替安装根摘要的原始路径。
|
|
151
|
-
安装成功后仍须下载并核验原生源码 ZIP,不能削弱其权限、租户、路径或字节校验。
|
|
152
|
-
大型 UTF8 源码应复用既有 `GetPrivateFileText/Sha256Hex/StringToBase64` 字符串边界,
|
|
153
|
-
在原字节摘要一致后才采用,避免 CLR byte[] 逐字节复制到 Jint。二进制或有损解码继续
|
|
154
|
-
保留原字节路径;文本读取失败或异常不能退回另一条存储路径。Base64 长度与最终 ZIP
|
|
155
|
-
实际条目仍严格验证,旧宿主缺少文本/编码能力时才直接沿用原兼容路径。
|
|
156
|
-
缺失基线不回退历史;分页不完整、重复路径(含大小写)、对象后缀与归档路径不一致、
|
|
157
|
-
大小或原始字节 SHA 漂移均停止。使用当前租户可信私有字节与已有 ZIP 原子,优先对同一
|
|
158
|
-
返回归档调用可信 `ExtractZip`(兼容 `ReadZip`),完整核对每条路径、大小、原始字节 SHA、
|
|
159
|
-
文件数与总量;原子存在但失败或不完整时不能回退。仅旧节点缺少解压核验原子时,逐文件
|
|
160
|
-
校验真实字节,原生 CLR SHA 不可用则复用既有编译 ZIP 的 ES5 算法,不得跳过验签。
|
|
161
|
-
前后重读权威账号、应用指针及清单;普通非拥有者、访问密钥会话、撤权、跨租户或存储错误
|
|
162
|
-
不输出文件。节点缺少字节摘要能力时失败关闭。清单摘要沿用序数排序后的
|
|
163
|
-
`Path\tSha256\tSize` UTF-8 SHA-256;原始 ZIP 摘要与资产准备器 Base64 文本摘要分别核验。
|
|
164
|
-
传输超时先回读对象和完整条目,已有正确 Build ZIP 可复用,但错误 Source ZIP 必须保留
|
|
165
|
-
拒绝发布证据;新源码合格后通过既有准备器单独上传 Source,禁止盲目重跑未知写操作。
|
|
166
|
-
- 编译 ZIP 优先按 `ApplicationType` 选择运行类型,历史 `AppType` 只作缺少该字段时的兼容。真实文件仅接受 HTTP 200,调用既有 `RequireSsrfProtection:true` 禁止自动重定向;合法 JSON 与业务错误响应按已冻结的实际字节大小和 SHA-256 区分,不能把任何含 `Code` 的 JSON 一律拒绝。每个新 ZIP 的版本元数据必须包含非空 `RuntimeManifestHash`,等于完整已验文件清单的 `Path\tSha256\tSize` UTF-8 摘要;当前 V3 还须与精确所属应用的权威 `Completed` 版本和微服务清单一致,前后复读提交指针、请求指纹和行版本,漂移失败关闭。旧缺失哈希 ZIP 保留失败证据,不用于新正式包。
|
|
167
|
-
- 完整制包的现代 `.mjs/.cjs/.mts/.cts` 模块与既有脚本按 UTF-8 文本读取,优先调用当前租户私有文本原子且必须 `Code=1`。旧节点缺少原子或读取失败时保留既有审计 URL 回退,票据异常仍停止;不得以性能为由绕审计。二进制不转文本,最终模型逐项验证实际字节、大小与冻结 SHA。超时先查原执行链与失败原因,不并发重入。
|
|
168
|
-
- 独立源码 ZIP 必须在全新目录安装依赖并执行应用声明的全部责任测试,再核对类型与生产构建;仅构建通过不能证明测试闭包。默认测试不得依赖发布者临时树、兄弟应用或平台仓库 marker。历史兼容所需纯模块应从已发布真实源码按原字节随 owned fixtures 交付,记录版本、原路径、大小和完整 SHA;保留原业务断言,不构造替代历史行为。中央多应用契约检查继续由中央 Full 入口执行,不能重新成为独立下载源码的外部依赖。
|
|
169
|
-
- 安装/升级脚本:幂等、可恢复、可回读;不包含租户密钥、Token、连接串或 License keys。
|
|
170
|
-
- 历史微服务的版本目录正确而 root/latest 缺失时,使用后端已安装投影恢复能力,不重发原安装或补写 V3 身份。恢复必须从当前租户主库读取已发布应用、唯一同版本 LegacyUnverified 历史行、启用文件服务与全部公开文件,逐项核对规范路径、大小和 SHA-256;存在安装任务在途或 V3 指针即停止。复用应用发布租约,每次副作用前后验租并复读完整权威投影,先验全部不可变源,再复制并完整回读目标;同版本漂移、失租和歧义不能报告完成。无条件对象复制可能迟到,须持续从已提交元数据和真实对象收敛,不能声称永久原子切换。商城无新增声明资源时仍需说明原安装包与新后端能力的关系,并分别保留后端镜像、源码 ZIP、版本/固定/API 字节、真实页面操作和业务保全的验收证据。沿用状态、应用上下文和原生只读表工具核对原任务和完整清单,缺少线上证据仍属未完成。
|
|
171
|
-
- 迁移采用“先扩展、后迁移、再收缩”,支持新旧节点短暂并存。
|
|
172
|
-
|
|
173
|
-
制包读取全局 v3 运行对象时,租户私有 HDFS 代理继续保持租户目录边界。发布器仅从当前
|
|
174
|
-
`sys_microistore.CommittedPublishVersionId` 精确读取一条所属应用的 Completed 版本,核对
|
|
175
|
-
`VersionNo / RuntimeManifestHash / RequestFingerprint`、微服务清单和每个文件的不可变完整路径、
|
|
176
|
-
大小及 SHA-256,再由当前 `V8.SysConfig.ApiBase` 的可信 origin 与当前租户、应用 Key、文件
|
|
177
|
-
相对路径构造 `/micro-app/v3/tenants/.../kinds/runtime/apps/.../assets/...` 读取地址。不能从较新的
|
|
178
|
-
staged 行、请求参数、`StableFilePathName` 或外部 CDN URL 推断版本和域名。HTTP 使用既有
|
|
179
|
-
严格 SSRF 原子禁用自动重定向,只接受 200;提供的 ETag 必须等于文件 SHA-256。文本可使用
|
|
180
|
-
解压后的 Content,二进制使用 RawBytes,两者仍须分别通过实际字节大小和 SHA-256 校验。
|
|
181
|
-
清单、提交身份、HTTP 或字节不一致时停止制包;旧无 v3 提交字段的微服务保留原校验路径。
|
|
182
|
-
|
|
183
|
-
## 接口引擎资源所有权(强制)
|
|
184
|
-
|
|
185
|
-
- 新发布包必须声明 `ResourcePolicies.ApiEngines`。不可随租户修改的核心使用 `{ Ownership:'Platform'|'Application', UpgradePolicy:'Managed' }`;提供给租户改业务的 Hook 使用 `{ Ownership:'Tenant', UpgradePolicy:'CreateIfMissing' }`。策略以本次选定且通过身份、版本、大小和 SHA-256 校验的包正文为准。
|
|
186
|
-
- 发布器仍从上一版安装包计算 `BaseHash`,导入成功后把本版摘要写入 `sys_microistoreversion.InstallResult.ResourceState.ApiEngines`,但 `Base/Local/Incoming` 只用于审计。所有官方、社区和普通应用的 `Managed` 接口均按 Incoming 覆盖;本地源码较新、同版本不同源码、历史所有权不同或安装记录缺失都不得形成安装冲突。
|
|
187
|
-
- 当前包声明为 `CreateIfMissing` 时,只在目标 Key 完全不存在时创建;存在时不得对齐 Id、源码、启用状态或其它字段,软删除也算存在。若未来包明确把同一 Key 声明为 `Managed`,则以当前包策略执行覆盖,不再因历史所有权阻断;发布方应在更新日志中明确这一行为变化。
|
|
188
|
-
- 官方功能仍优先采用“Managed 核心 + CreateIfMissing Hook”。核心提供稳定协议和默认行为并随包覆盖;客户日志、写表、通知和业务动作放 Hook,并以稳定 `EventId`、唯一约束或 outbox 幂等。这样覆盖式升级核心时无需自动合并客户可执行代码。
|
|
189
|
-
- 每个官方包内的接口引擎源码顶部都必须有醒目所有权提示。Managed 提示必须写明所属官方应用、从可信官方源安装/更新/重新安装会恢复官方代码,并指向该应用的 CreateIfMissing Hook;CreateIfMissing 提示必须写明首次创建后归租户维护、官方升级不得覆盖。官方 SSO、登录、通知等核心在安全阶段调用 Hook 时,只传脱敏上下文,禁止传 Token、Secret、密码或原始协议断言。
|
|
190
|
-
- 兼容旧 Controller/移动端地址时,在唯一 Managed 接口的 `ApiRoutes` 中用英文分号声明全部旧路径。主地址被其它接口占用时,安装器清除旧占用者的该地址并让当前包收回;稳定 Id 被其它 Key 占用时为当前包资源生成新 Id。每次都要清理旧缓存别名并强回读 `ApiAddress + ApiRoutes + ApiV8Code + Version`。
|
|
191
|
-
- 历史包未声明策略时按旧 `LegacyOverwrite` 覆盖兼容;重新发布时发布器必须生成策略。验收至少覆盖首次安装、官方/社区/普通 Managed 本地差异覆盖、同版本重装、软删除恢复、Id/地址自动重映射、Hook 被改后保持原样、两节点竞态,以及官方发布数据库连 `ValidateOnly` 也禁止执行安装器。
|
|
192
|
-
|
|
193
|
-
## 工作流定义与目标审批绑定
|
|
194
|
-
|
|
195
|
-
- 安装器 `v2.9.9` 对声明 `Installation.ConfigurationPolicy='PreserveTenantValues'` 的包,
|
|
196
|
-
在共享事务内先读取目标流程配置。相同业务表、节点 Id/用途和连线结构的更新保留 `IsEnable`
|
|
197
|
-
以及节点的 `Users/Roles/Depts`;V8、按钮规则等受管定义继续按当前包更新,不保留租户代码差异。
|
|
198
|
-
- 业务表、节点用途或连线结构变化时,保留仍兼容的节点绑定并停用流程,记录需要重新配置的诊断;
|
|
199
|
-
有真实 `Todo` 待办时拒绝改图,不能自动完成、撤回审批或删除历史。管理员须检查包含历史多余
|
|
200
|
-
节点/连线的完整图形后再启用。未声明该策略的历史包保持原覆盖语义。
|
|
201
|
-
- 节点稳定 Id 跨流程占用、配置读取失败、写入失败或字段/V8回读不一致均失败关闭。
|
|
202
|
-
发布包只交付停用模板,目标用户、岗位、部门及业务配置不能从官方测试环境复制。
|
|
203
|
-
- 空绑定或停用模板仍须真实结构声明。预制包发布前逐项核对流程、节点和连线的全部属性
|
|
204
|
-
与目标支持的物理列及类型;新增列必须由同包声明交付,未知属性即拒绝。`0`、空字符串
|
|
205
|
-
或 `[]` 不能证明未知字段可落库,不得凭相近名称发明控制项或补默认值绕过严格回读。
|
|
206
|
-
- 导出器在原生导出及 `PreparedPersistPackageByteBase64` 持久发布中,从可信当前租户
|
|
207
|
-
数据库读取 `wf_flowdesign/wf_node/wf_line` 的真实物理列,按大小写不敏感的字段名检查
|
|
208
|
-
全部资源属性;包自报 `PhysicalColumns` 不授予字段合法性。实际数据库已有的定制列保持
|
|
209
|
-
合法;新增列先由正规结构交付并回读,再制包。未知字段、大小写重复、列读取失败或数据库
|
|
210
|
-
类型缺失/不支持均在 HDFS 上传、日志、发布 CAS 与指针更新前失败关闭。MySQL/MariaDB、
|
|
211
|
-
SQL Server 当前解析表和 Oracle 当前用户表使用各自目录,无工作流的老包不要求该目录。
|
|
212
|
-
- 生成安装模板时,只从当前母版定义提取业务正文,从历史映射提取稳定资源 Id;构建前逐节点
|
|
213
|
-
核对完整 V8 正文与条件代码。私有源码同步、普通 Manifest 生成或管理员测试通过,不能证明
|
|
214
|
-
实际安装包中的内联正文已更新。发布前核对正式包,升级后再以目标普通岗位核对原业务请求。
|
|
215
|
-
- 验收必须包含已绑定审批人的真实租户升级与同版本重装,核对启用状态、目标绑定、受管代码
|
|
216
|
-
更新、在途待办保护及业务配置未变;空模板安装成功不能替代该验收。
|
|
217
|
-
- 安装器 `v3.0.0` 起,流程、节点、连线的新增、更新与配置/结果回读均显式传入同一个
|
|
218
|
-
`V8.DbTrans`,由外层接口决定提交或回滚。不能把共享事务内的读取与独立提交的写入混用:
|
|
219
|
-
可重复读快照可能看不到刚写入的数据,并导致失败后残留部分流程。遇到“工作流写入后回读不存在”
|
|
220
|
-
先升级应用商城安装器,再按原已校验包和任务状态恢复;保留失败审计,不删业务数据或审批历史。
|
|
221
|
-
回归须模拟事务快照,覆盖首次安装、更新后可见性及节点/连线失败时整个流程回滚。
|
|
222
|
-
|
|
223
|
-
## 安装流程
|
|
224
|
-
|
|
225
|
-
1. 校验签名/哈希、包版本、平台兼容性、依赖和磁盘/配额。
|
|
226
|
-
2. 创建全局唯一 `InstallationId` 和稳定幂等键。
|
|
227
|
-
3. 使用后台任务执行,阶段性持久化进度与 checkpoint。
|
|
228
|
-
4. 按 Manifest 创建缺失资源;已有 `Managed` 资源覆盖为包声明值,`CreateIfMissing`/`InsertIfMissing` 既有值保持原样。
|
|
229
|
-
5. `PostSchema` 完成后,在独立 `ScheduleJobs` checkpoint 中幂等安装定时任务并回读 Quartz 运行元数据。
|
|
230
|
-
6. 写入成功后刷新共享缓存版本。
|
|
231
|
-
7. 回读表、字段、引擎、菜单、权限、页面、定时任务等关键资源。
|
|
232
|
-
8. 做 HTTP、UI 和权限冒烟;全部成功后才标记安装版本。
|
|
233
|
-
|
|
234
|
-
安装中断后从 checkpoint 幂等恢复;不能依赖当前 API 节点内存。
|
|
235
|
-
|
|
236
|
-
后台任务中心的 `POST /api/BackgroundTask/List` 只返回有界分页的状态、进度、时间和 `HasLog/HasResult` 摘要;日志、结果、参数、可信用户快照与 checkpoint 必须按任务所有权在详情接口按需读取,不能为列表轮询重复返回大字段。
|
|
237
|
-
|
|
238
|
-
## 权限与租户
|
|
239
|
-
|
|
240
|
-
- 商城定义、安装、升级、卸载和应用源码只允许 `Level >= 9999`。
|
|
241
|
-
- “吾码官方平台”不能只按 `OsClient`、域名或前端变量判断:服务端必须同时校验官方 `OsClient`,并确认当前节点固定只读挂载 `/app/microi_private.pem` 的公钥部分与内嵌官方 License 信任根匹配;本地源码开发可从私有子仓库兼容查找。任意自建私钥不能建立官方身份。官方平台前端隐藏安装、更新、重新安装、离线安装和批量安装入口,后端仍必须拒绝这些写操作。
|
|
242
|
-
- 官方平台是应用发布源,连安装器的 `ValidateOnly` 也必须拒绝,避免通过“只验证”绕过发布源隔离。发布源只做包正文、版本和资产 Hash 回读;真实安装、更新及预检必须切换到非官方目标租户或本地非发布源环境。
|
|
243
|
-
- 所有资源按目标 `OsClient` 写入;包内不能携带源租户 `OsClient`、数据库、Redis、对象存储、MQ/MQTT、AI 或第三方密钥。
|
|
244
|
-
- 按钮调用后台安装接口时,前端只传应用/版本/安装 Id;目标租户和管理员身份由 Token 确定。
|
|
245
|
-
- 每次安装、更新、重新安装生成稳定 `OperationId`。官方计数服务用共享数据库事件表唯一约束去重,并在同一事务内登记事件和递增 `InstallCount`;重试、跨节点和响应丢失不得重复计数。
|
|
246
|
-
- 安装次数回传属于非阻塞幂等遥测,不是应用导入事务的成功条件。来源节点返回旧格式 `True`、空响应、非 JSON、业务失败或请求异常时,只能写入带 `OperationId`/`InstallationKey` 的 warning 诊断,不得用 `_error_` 标记或回滚已经成功导入的应用;重试仍须复用同一幂等键。
|
|
247
|
-
- “全部安装/更新”固定只处理 `ApplicationType=Platform` 的官方平台应用中未安装与存在新版本的项目,不得把 UniApp、Web、MicroService 或其它社区/AI 应用整库安装;已是最新版的应用不重新安装。批量计划、子项状态、checkpoint 和进度必须持久化到共享数据库/后台任务,支持多节点抢占、失败重试和重启恢复,不能依赖进程内集合或浏览器状态。
|
|
248
|
-
- 主租户批量维护全部子租户时,前端入口和接口引擎都必须校验主租户上下文及 `Level >= 9999`,再由可信控制面为每个启用子租户创建独立持久后台任务;父任务必须按子任务真实百分比聚合进度,等全部子任务终态后才成功或失败,并在通知中心保留每个租户、阶段和原始失败原因。所有子任务可立即创建,但固定商城工作器必须通过配置租户 Redis 的集群并发租约跨租户串行执行,避免共享物理库并发 DDL/元数据写入死锁;分片幂等任务使用足以覆盖短时死锁和滚动重启的有界重试预算,禁止无限重试。`MaxAttempts` 表示连续失败预算:任一分片成功写入 checkpoint 后必须把 `AttemptCount` 与陈旧 `LastError` 清零,不能让数百个成功分片之间偶发的网络错误按任务生命周期累计并误终结。分片重新入队后必须按 `COALESCE(NextRunTime, CreateTime)` 选取最早就绪任务,禁止只按 `CreateTime` 让最早长任务重复抢占全部分片。商城包属于只读权威数据,可对空响应做有界退避重试,并优先用完整响应的 `Content`、`RawBytes`、HTTP 状态和传输错误诊断;不得把该规则扩展到安装写入请求。目标租户固定商城工作器必须锁定并校验精确包快照;同版本重装、显式选择历史版本或目标端存在更新源码时,仍以所选包的 `Managed` 资源覆盖,不得用版本/源码差异制造冲突。历史空库缺少生成实体所需物理列时,导入器须在首次 FormEngine 调用前幂等补齐并回读,不能再把真实表结构错误包装成 `Value cannot be null (source)`。
|
|
249
|
-
- 批量维护的权威目录按当前节点 `OsClientType + OsClientNetwork` 隔离;同一主租户同时存在 Internal、Internet 或其它活动分区时,必须在每个分区对应的主租户节点独立发起并验收,不能用一个分区的成功任务推断全平台成功。每个分区先回读精确预期租户数与名单,等待父子任务全部终态且 `SucceededCount=ExpectedCount、FailedCount=0`,再用新幂等键立即执行一次无操作复跑并确认零安装/零更新。禁止修改 `sys_osclients` 的网络字段来把租户临时塞进另一分区,也禁止让两个分区同时维护可能指向同一物理库的重复租户记录。
|
|
250
|
-
- 启动自动恢复的范围严格限制为正常启动、普通登录、菜单导航和商城安装/更新。完整官方应用源码、包、生成器和同步器位于 `Microi.Server/OfficialApplications/Resource/`;`build-bootstrap-package.mjs` 按显式清单生成 `Microi.Upgrade/Resource/app.microi.bootstrap.json` 与 `import-package.js`,升级程序集只嵌入这两项。SSO、AI、通知、备份、OCR、翻译等可选应用只由用户在商城手动安装更新,不能作为启动就绪或版本推进条件。必要共享物理列与安装元数据可恢复,但不导入业务种子、可选菜单、任务或租户配置值。
|
|
251
|
-
- 启动恢复使用共享租约、持久版本门、幂等和强回读;只有登录接口、商城菜单/服务/页面绑定及真实内联资产就绪后才前向推进版本。满足必要路由和安全标志的更高版本 Managed 接口及完整商城资产保留,不能降级用户的手动更新;这项规则仅适用于启动恢复,用户显式选择商城历史版本仍以所选包为准。生成资源变动后必须重新生成并用 `--check` 和完整门禁验证,不能在 Full 后悄悄改包。
|
|
252
|
-
- 完整 SaaS、系统账号、系统设置等官方包继续按其独立归属发布;商城页面之外的平台设置和个人中心由对应包交付。`Source=NotIncluded + Build=DatabaseOnly + StorageMode=db` 的小型恢复资产接受 256 文件/5MB 和逐文件哈希门禁。客户明确要求手动更新时,官方发布不得扩张为客户自动安装或服务器部署。
|
|
253
|
-
- 批量任务已经以“一个应用”为外层持久化恢复单元。规模可控的小型官方包应在一个事务中完成,避免对同一包体按 8 个字段反复下载、解析和重新排队;超过字段、表、DDL、流程、随包数据或资产安全阈值的大包继续使用内部 checkpoint 分片。热更新发现旧版批量计划不含 `ApplicationType` 时,必须丢弃旧计划并重新盘点,不能继续安装历史计划中的社区应用。
|
|
254
|
-
- MySQL 宽表触发 65,535 字节行内上限时,只允许把不参与索引的 `varchar` 配置列无损提升为 `mediumtext`,并把类型覆盖持久化到后台任务 checkpoint;索引列和非行宽错误必须失败关闭。发布包对长连接串、密钥、回调地址、域名/白名单等字段应直接使用 `mediumtext`,同时更新 `DiyFields` 与建表 DDL,不能长期依赖安装时猜测。
|
|
255
|
-
- 历史表连新增 TEXT 行内指针都无法容纳时,仅修改新增字段不够。导入器需支持本次长列行外化后,对本包明确拥有的表内、包声明的既有可空且无默认值/生成属性的长 VARCHAR 有界扩宽。先查询目标 `INFORMATION_SCHEMA.STATISTICS` 保护全部真实索引列(含复合索引非首列),再按长度降序最多调整八次;保留内容、字符集、排序规则、可空性和注释,逐条 DDL 强回读。引用表、未声明列、非文本声明、索引读取失败和其它 DDL 错误禁止自动扩宽;全量验证声明后才修改包对象,不得部分修改或缩窄 LONGTEXT。
|
|
256
|
-
- 行宽修复回归必须先复现旧表中 VARCHAR 与 TEXT 新增都失败,再证明新导入器保留短列类型、长列行外存储、旧数据和列属性不变、检查点恢复以及立即重装零 DDL。MySQL DDL 不随事务回滚,回读不一致必须失败且不得推进安装版本;后续安装依据真实物理容量与检查点覆盖保持兼容。真实租户先更新商城导入器,再验收全部平台应用成功和立即零安装/零更新重跑。
|
|
257
|
-
- 卸载是破坏性操作,必须明确列出将删除/保留的资源、二次确认并优先软删除/归档业务数据。
|
|
258
|
-
|
|
259
|
-
## 联邦商城源、公开范围与历史版本(强制)
|
|
260
|
-
|
|
261
|
-
- 每个主租户和子租户都可以发布自己的应用;应用行用 `IsPublic` 表达公开范围,缺省/历史空值按公开兼容。公开应用允许未登录来源读取和安装,私有应用只允许来源登录成功后的授权身份读取,列表、详情、版本接口都必须重复执行这一权限判断。
|
|
262
|
-
- 组合包的 `ApplicationBundles[].Application` 必须由发布器从源应用实际记录携带 `IsPublic/IsApprove`,不接受请求参数替代。安装器只接受 `0/1`、`"0"/"1"` 和布尔值,显式源标记优先;未审批的源不能因 Build 成功变成已审批。历史包无公开标记时,已有目标保持原值(含历史空值),首次新增运行应用显式 `IsPublic=0`,不能继承目标 Switch 默认1。无效声明在直接包入口任何 I/O 前失败;下载包在读取正文后、该包资源/文件写入前失败,旧库既有物理前置兼容检查不因此重排。父商品 AppId/公开范围、目标拥有者和源码下载独立鉴权不得随运行标记改变;验收必须覆盖新私有、已有私有/公开、显式公开、旧包新建/重装、非法类型零包写入和即时撤权。
|
|
263
|
-
- 新版安装包正文不得长期内联在 `sys_microistore.AppPakcet`,也不得随 `mic_data_version.Data` 重复复制。公开应用写入 HDFS 公有桶并记录 `HdfsPublic`,私有应用写入私有桶并记录 `HdfsPrivate`;数据库只保存 `PackageId/PackageHdfsPath/PackageSha256/PackageSize/PackageContentType/PackageFormatVersion/PackageUploadedAt`。`IsPublic` 历史空值按公开兼容,但所有新建应用必须显式落为 `1/0`。
|
|
264
|
-
- 发布顺序必须是“UTF-8 JSON 上传 → HDFS 回读 → 字节数和 SHA-256 一致 → 写入不可变包索引及商城指针 → 以原值 CAS 清空 `AppPakcet`”。普通发布不得仅凭 Redis 命中跳过 HDFS 回读;只有受控历史压缩可复用内容寻址缓存,安装端仍必须独立下载并校验。公开包可通过 FileServer/CDN 公有地址读取;私有包只能由来源后端在当前授权身份下签发短期下载地址,Token、签名 URL 和包正文不得进入浏览器配置、日志或后台任务参数。
|
|
265
|
-
- `mic_data_version` 历史快照保留不可变 `StoreVersionId` 和同一组包指针,因此旧版本仍可精确安装,不再要求 `Data` 内含完整 JSON。导入器先校验快照版本/应用身份,再按指针下载并在解析前核对大小与哈希;指针缺失时才回退旧版内联字段,禁止快照不匹配时退回当前版本。
|
|
266
|
-
- 旧库容量治理使用 `compact-microi-store-packages` 超级管理员持久后台任务:先幂等补齐物理列,再用有界 `Id` 游标逐批处理;每个包都先上传回读,随后 CAS 清理当前行或历史快照。禁止对数 GB `mic_data_version.Data` 执行全表 `LIKE`/包正文计数。逻辑大字段清空后,MySQL 表空间文件是否立即缩小取决于存储引擎;`OPTIMIZE TABLE` 只能在备份完成的维护窗口由管理员另行执行,不能由应用安装或压缩任务自动触发。
|
|
267
|
-
- 商城来源以 `ApiBase + OsClient` 唯一定位。添加来源先只读发现系统标题、验证码策略和公开应用数;需要私有应用时再登录。帐号、密码、Token 不能写浏览器配置或商城来源 JSON;密码只用于本次登录,长会话 Token 以 `MCP/Mobile` 非 PC 客户端签发,并由当前租户后端加密保存到 `mci_system_setting`,浏览器只持有不具备取密能力的凭据 Key。
|
|
268
|
-
- 后端来源代理必须固定已保存的 `ApiBase + OsClient`,拒绝过期 Token、访问密钥会话、非超级管理员、非 HTTPS 外网地址、重定向漂移和超限响应;Token 不得返回浏览器、日志、审计或应用包。退出登录同步删除服务端密文。
|
|
269
|
-
- 商城源业务由 `app.microi.store` 单一拥有的 `platform-marketplace-source`(`Managed`)编排,租户扩展只写 `platform-marketplace-source-hook`(`CreateIfMissing`,默认可执行正文精确为 `return { Code : 1 };`)。登录必须在远端配置读取、密码发送和凭据保存之前执行 `BeforeMarketplaceSourceLogin`;断开必须在删除服务端凭据之前执行 `BeforeMarketplaceSourceDisconnect`。Hook 失败直接阻断操作。Before Hook 仅允许 `Stage / SourceApiEngineKey / Action / SourceId`,不得传 `ApiBase`、远端 `OsClient`、账号、密码、Token、签名地址或凭据密文;协议、加密和密钥隔离继续由可信网关负责。
|
|
270
|
-
- 商城主页面统一承载应用市场、已安装、我发布的应用、安装离线包和来源管理,不能再通过独立菜单或路由割裂上下文。来源增删改启停逐项自动保存;来源管理、详情和复杂配置使用平台统一 `80%` 可拖动大圆角 Dialog,遮罩服从正向开关 `sys_config.FormMaskBlur`,缺失或 `0/false` 默认关闭毛玻璃。
|
|
271
|
-
- 每张应用卡必须显示预览图、公开范围、分类、最新版本、当前租户已安装版本及状态色。来源卡必须显示其公开数和当前授权可访问总数;平台官方发布节点只显示“平台官方应用源”身份标记,不显示安装、更新或重新安装操作。
|
|
272
|
-
- 安装可明确选择 `sys_microistore` 当前版本或 `mic_data_version` 中仍含完整包正文或已验证包指针的历史快照;后台任务在首次取包时必须把计划中的 `AppVersion` 解析为匹配且可安装的不可变 `StoreVersionId`,写入 checkpoint,并在全部后续分片一直传到详情取包。发布方中途升版时继续完成已锁定快照,新版留给下一轮盘点;快照缺失、版本不匹配、身份变化或快照 Id 漂移必须失败关闭,禁止退回易变当前行。实际安装版本写回 `sys_microistoreversion`。回退旧版属于重新安装,不得静默换成最新版。
|
|
273
|
-
- 应用详情的版本选择必须服务端分页和搜索,默认每页不超过 20 条;当前版本固定置顶,历史版本只返回含完整旧包或有效 HDFS 指针的可安装状态。禁止用 `_PageSize:500` 或一次加载全部版本后在浏览器过滤。翻页、搜索与页大小切换都必须保持已选版本语义并显示总数。
|
|
274
|
-
- 商城详情、来源管理等 Teleport 弹层必须使用宿主级固定遮罩,毛玻璃覆盖完整可视区域;标题栏拖动按弹层真实尺寸限制四边,窗口缩放后重新限制,不能依赖固定像素最大位移或允许内容越出视口。
|
|
275
|
-
- “我发布的应用”只读取当前登录用户拥有的记录,可以包含草稿和构建失败项;普通商城列表只读取已发布项。两者必须在服务端按 Owner 和发布状态过滤,不能依赖浏览器过滤后再分页。
|
|
276
|
-
|
|
277
|
-
## 发布版本与资源选择
|
|
278
|
-
|
|
279
|
-
### 每个应用版本必须有更新日志(强制)
|
|
280
|
-
|
|
281
|
-
- 本规则覆盖 `Platform / Regular / Web / UniApp / MicroService` 以及所有 AI 应用。任何创建、修改、升级、重新构建或重新发布,只要产生新的应用版本,就必须先在 `sys_microistore_changelog` 写入一条更新日志;不允许先发布后补写,也不允许因为只改了元数据、V8、路由、提示文案或内置运行产物而省略。
|
|
282
|
-
- 更新日志通过 `StoreId` 关联 `sys_microistore.Id`,`Version` 必须是规范化后的精确 `AppVersion`,且同一应用同一版本只能有一条。`Title`、`ChangeType`、`Content`、`ReleaseTime` 都是必填项;`Content` 要写清用户可感知的新增、优化、修复、兼容或安全影响,禁止只写“优化体验”“修复问题”等无法审计的空泛文字。
|
|
283
|
-
- 正确顺序固定为:确定目标版本 → 保存商城应用 → 写入或审阅该精确版本日志 → 同步源码与构建 → 制包/发布 → 回读商城行、安装包和日志。发布器发现日志缺失、软删除、版本不一致或任一必填项为空时必须失败关闭。
|
|
284
|
-
- `microi_publish_application_directory_stream`、V3 发布或其它支持变更摘要的工具必须显式传 `changeSummary`,且其含义与更新日志一致;`mci_ai_app_version.ChangeSummary`、`AppPakcet.PackageInfo.ChangeLog` 和商城子表不得互相矛盾。
|
|
285
|
-
- 应用商城包升级必须同时交付子表、真实 `StoreId` 外键字段、唯一约束/索引、隐藏子菜单、主表 `TableChild` 字段、详情时间线和发布门禁。历史商城源没有该能力时前端应明确显示“当前来源暂未提供更新日志”,不得伪造空日志为“暂无更新”。
|
|
286
|
-
- 验收至少回读“商城当前版本 + 对应日志 + 包内版本/ChangeLog”,再在真实商城详情弹层检查版本、类型、标题、时间和正文;重复执行相同版本写入应命中唯一记录而不产生重复行。
|
|
287
|
-
|
|
288
|
-
- 发布器必须把用户请求的精确版本传给资产准备器,并断言 `RequestedVersion == Prepared.PackageVersion == AppPakcet.PackageInfo.Version`;版本不存在就失败,禁止静默改用最新版本。
|
|
289
|
-
- `SelectMenu`、`SelectTable`、`SelectApiEngine` 必须从当前发布包的显式选择持久化;不能读取商城行上一次保存的选择来决定本次包内容。
|
|
290
|
-
- 发布完成后同时回读商城版本行、包正文和构建资产,逐项核对版本、数量与 SHA-256;任一处漂移即发布失败。
|
|
291
|
-
- 官方内置前端应用只能有一个发布源码根。默认租户工作副本与受审计的独立 Git 源码仓库不能同时成为事实源;若使用独立仓库,必须提交一个发布契约并让构建、跨工程测试、所有程序集内置包共同读取它,正式发布还要证明源码根来自无未提交修改的 Git 提交。前端主包只提供通用宿主、诊断和恢复入口,不复制完整业务源码。HDFS/CDN 运行镜像必须回读到同一 `RuntimeManifestHash` 后才可启用,不能用较新的镜像静默覆盖较旧数据库包,也不能用较新的数据库包静默覆盖未验签镜像。
|
|
292
|
-
- `ScheduleJobs` 是一等包资源,必须在 `PostSchema` 之后独立安装、持久化 checkpoint 并回读运行状态;任务失败时不得写入成功版本。
|
|
293
|
-
|
|
294
|
-
## MCP 工作流
|
|
295
|
-
|
|
296
|
-
1. 安装/更新现成商城应用时,先调用 `microi_install_store_application` / `microi_update_store_application` 且不传 `confirmExecution`,核对目标租户、商城源、StoreId 和幂等请求 Id 的预检结果。恢复被商城升版打断的旧任务时,额外传入已回读且仍含完整包正文的 `storeVersionId`;不同快照必须使用新的 `requestId`。
|
|
297
|
-
2. 用户明确确认后,把 `confirmExecution` 精确设为 `StoreId`,提交真实持久化后台任务;只传 StoreId、可选不可变 StoreVersionId、版本和商城源定位信息,不通过 MCP/HTTP 传完整 `AppPakcet`。
|
|
298
|
-
3. 自建应用或低代码系统先用 `microi_list_applications` / `microi_get_application_context` 盘点源码,再用 `microi_get_manifest_schema`、`microi_plan_system` 与 `microi_generate_system(dryRun:true)` 干跑。
|
|
299
|
-
4. 安装任务必须回读至 `Succeeded`,再执行 `microi_validate_system`、远端资源回读和真实 UI 验收;仅返回 TaskId 不代表安装成功。
|
|
300
|
-
|
|
301
|
-
已有 MicroService 优先新增页面/路由;没有时才创建、同步源码、发布构建。复杂安装交互使用 `V8.OpenAppDialog`,后台任务上报进度。
|
|
302
|
-
|
|
303
|
-
## VS Code 本地应用与发布边界
|
|
304
|
-
|
|
305
|
-
- `AI应用` 本地树按每个一级目录的 `.microi-micro-app.json` 发现项目;只要 `osClient/apiBaseUrl` 与当前连接一致,就必须显示 `Web / UniApp / MicroService`,不得用 `runtime === "micro-app"` 过滤掉其它应用类型。无效清单应记录诊断,不能静默吞掉整个目录。
|
|
306
|
-
- “安装到当前租户”和“发布到应用商城(不安装)”是两个独立动作。商城发布只能同步 `sys_microistore`、应用源码/构建/版本元数据及安装包,不得新增或修改当前租户的 `sys_microiservice / sys_microiservice_page`;操作前后必须回读运行态确认未变化。
|
|
307
|
-
- 应用项目行必须直接显示商城发布入口,不能只藏在右键菜单;同时保留构建安装和源码同步状态入口。
|
|
308
|
-
|
|
309
|
-
## 版本与回滚
|
|
310
|
-
|
|
311
|
-
- 版本号单调递增,保存变更清单和前后哈希。
|
|
312
|
-
- 官方 Web、UniApp、MicroService 体验路径统一为公有桶对象键 `/{OsClient小写}/micro-app/{AppKey}/index.html`,通过 `https://static.itdos.com` 访问;`/{OsClient小写}/micro-app/{AppKey}/{Version}/index.html` 及同目录资源是不可变历史版本。私有桶按同样相对目录保存最新版与各历史版本的源码;编译包没有源码时明确记为 `NotIncluded`。v3 的 `microi/application-assets/v3/...` 仍可作为内部校验源,但 `/micro-app/v3/tenants/...` API resolver 和旧 `ai-app-publish` 不再作为官方商城体验链接。
|
|
313
|
-
- 发布顺序为完整上传并验证版本目录、复制私有源码快照、提升固定根的非入口资源、最后提升固定 `index.html`。CDN 对所有被覆写的固定路径做精确刷新并回读任务 `Complete`,再从 `static.itdos.com` 回读入口及引用资源,最后更新 `sys_microistore.PreviewUrl/PublicPublishPath`;任一步失败保留旧商城入口并进入可恢复状态。跨版本重发不得覆写历史目录的不同内容。官网列表、详情、二维码和“立即体验”只能展示固定根的 CDN URL,不带版本、请求指纹或缓存绕过参数。
|
|
314
|
-
- v3 数据库中的 `PreviewUrl/PublicPublishPath` 可以保存以 `/` 开头的对象路径,完成态检查依赖此相对值;官网接口和商城工作台使用租户 `FileServer` 生成完整 CDN 体验 URL。展示层修复不得直接改写 v3 记录为绝对 URL。
|
|
315
|
-
- 官方 CDN 凭据按当前租户系统设置 `Integration.Cdn.Aliyun.*`、`Integration.Dns.Aliyun.*`、历史 SaaS `AlidnsKeyId/AlidnsKeySecret` 顺序读取;半配置失败关闭,不静默跳过刷新。阿里云可能把并发 URL 合并为同一任务号,需等待该任务返回的全部 URL 完成并按原始字节哈希回读。批量迁移应按每日刷新配额限速或分日执行。
|
|
316
|
-
- 旧版对象若已丢失,只能从商城编译包、仍可访问的当前体验路由或本地归档取得逐文件匹配冻结清单的原始字节后补齐;哈希或长度不符时拒绝写入。历史版本无法恢复时保留原版本记录和链接并列出待补清单,可独立迁移已完整校验的当前版本,但不得把未恢复的历史目录标为已归档。
|
|
317
|
-
- stage 前回读并冻结应用的 `CurrentVersion + AppVersion`;finalize 必须同时传 `ExpectedCurrentVersion + ExpectedAppVersion`,在以不可变 AppId 加锁后再次 compare-and-set。缺失前置条件、AppId/AppKey 漂移或旧请求晚到一律失败关闭;重新发布必须重新盘点,不能静默回退。
|
|
318
|
-
- 新清单发布成功时,同应用 `dist/` 下不再出现的 active 文件元数据只能条件式改为可逆归档 scope,条件必须包含 AppId、路径、旧 scope 与版本;禁止删除 HDFS/数据库记录,也不得触碰 Private、非 `dist/` 或另一应用的行。
|
|
319
|
-
- 官网、二维码和用户分享只使用无版本号根入口,不追加 `v/apiBase/OsClient`。目标租户的 `ApiBase/OsClient` 在发布或安装时写入入口 HTML 的 `window.__MICROI_APP_CONTEXT__ / MICROI_API_BASE / MICROI_OS_CLIENT`;安装包不得沿用发布端运行上下文。
|
|
320
|
-
- 数据迁移通常只向前;回滚应用版本不能假设自动回滚业务数据。
|
|
321
|
-
- 更新失败保留原版本可运行资源,记录失败阶段;不要清空客户 V8 后再尝试恢复。
|
|
322
|
-
- 私有源码仓库、`Microi.net/License/keys` 和部署密钥不进入公开应用包。
|
|
323
|
-
|
|
324
|
-
## 验收清单
|
|
325
|
-
|
|
326
|
-
- [ ] 同一包重复安装无重复表/字段/菜单/任务
|
|
327
|
-
- [ ] 客户自定义 V8 与非包拥有配置保持不变
|
|
328
|
-
- [ ] 源码包、构建包、Manifest 和数据库版本一致且哈希可核
|
|
329
|
-
- [ ] 无版本号根入口与当前商城版本一致,历史版本 URL 仍可独立访问
|
|
330
|
-
- [ ] 安装到不同 ApiBase/OsClient 后,入口 HTML 使用目标租户上下文且分享 URL 无运行参数
|
|
331
|
-
- [ ] Web/UniApp 安装后的 `PreviewUrl` 使用目标租户 `FileServer + 真实对象 Key`,不含 OSS/S3 内网域名或临时签名;即使发布包漏选菜单,也会幂等生成可直接在线使用的 Iframe 入口,已有入口则重绑到目标租户地址
|
|
332
|
-
- [ ] 只更新菜单/说明/声明式资源且复用旧运行时的版本,`sys_microistore.AppVersion` 跟随安装包版本,运行版本表保留真实构建版本;商城安装状态不能因两种版本合同合法分离而显示异常
|
|
333
|
-
- [ ] 中断/重启后可恢复,两个节点不会重复副作用
|
|
334
|
-
- [ ] 普通角色不能安装、升级、卸载或读取私有源码
|
|
335
|
-
- [ ] 缓存刷新后远端 API 与真实 UI 通过
|
|
336
|
-
- [ ] 卸载范围明确、可审计、可恢复或已提示不可恢复
|
|
337
|
-
|
|
338
|
-
## 复盘:商城按钮已到达但依赖接口引擎缺失
|
|
339
|
-
|
|
340
|
-
- 触发场景:子租户更新应用商城后能够看到“全部安装/更新”,点击却提示 `sys_apiengine` 中不存在按钮调用的接口;继续临时补引擎后,还可能因目标租户缺少批量计划表再次失败。
|
|
341
|
-
- 根因:商城元数据版本、`AppPakcet.PackageInfo.Version` 与真实包正文发生分叉,页面按钮被单独更新;同时应用导入器把接口引擎新增/更新失败只写进 Debug 后继续返回成功,没有做写后回读,批量引擎又依赖未随同一应用包交付的表。
|
|
342
|
-
- 通用规则:按钮及其调用的接口引擎、表和权限必须属于同一个单调版本应用包;任何依赖写入失败或回读内容不一致都要让安装事务失败。可复用的批量状态优先写入平台后台任务 `CheckpointJson`,避免仅为批量编排增加未交付的租户表。商城行版本、包内版本和包内容哈希必须同时回读一致,禁止单独提升商城行版本或只更新菜单。
|
|
343
|
-
- 自动化检查:应用包契约测试必须从按钮代码提取接口 Key,断言包内存在启用且配置正确的引擎并与独立源码逐字一致;导入器测试覆盖新增失败、更新失败、缓存清理后回读缺失和源码不一致均返回 `Code=0`;真实子租户更新后回读 `sys_menu + sys_apiengine + 后台任务`,再实际执行一次“无需更新”和至少一个安装/更新计划。
|
|
344
|
-
|
|
345
|
-
## 复盘:新版前端先启动、基础包却遗漏登录菜单依赖
|
|
346
|
-
|
|
347
|
-
- 触发场景:租户先升级新版前后端,登录后路由初始化固定调用 `/apiengine/platform-sys-menu`;目标库此前没有该接口。应用商城包只补了 `platform-background-task`,而菜单接口仍由安装顺序靠后的 SaaS 包顺带携带;启动完整性检查也只验证后台任务接口,于是数据库版本和商城版本都显示最新,但用户在进入应用商城之前已经因 `NoExistData sys_apiengine` 全站不可用。
|
|
348
|
-
- 根因:把单个已修复依赖误当成完整的启动依赖集合,包资源闭包、`NeedRefresh` 完成判定和安装后强回读没有使用同一清单;发布验收只覆盖已有目标租户,未覆盖“新版二进制 + 历史库恰好缺少某一启动接口”的升级排列。
|
|
349
|
-
- 通用规则:凡是登录、菜单构建、恢复入口或应用商城打开之前必调的表、接口引擎和微服务路由,都属于启动依赖闭包。每项资源必须只有一个官方 Platform/Application 包作为唯一所有者。API 进程接收流量前的门禁不得维护“登录页七接口”之类手写清单;必须从九个随服务端自动安装的内置官方基础应用包读取全部 `SysApiEngines`。同 Key `Managed` 记录原位覆盖包内源码、版本、主路由、多路由和开关,软删除必须恢复;包内 Id 被其它 Key 占用时生成新 Id,包内主地址被其它接口占用时收回地址。`Tenant/CreateIfMissing` 仅在数据库中完全不存在时创建,既有大小写变体、禁用记录或墓碑都归租户维护,不得恢复或覆盖。
|
|
350
|
-
- 竞态与验收:前端可对明确的“启动 Managed 资源尚未落库”做不超过一分钟的有界退避,并在耗尽后显示精确包名和最低版本;它不能吞掉鉴权错误、普通网络错误,也不能代替服务端修复。跨大量历史租户的 `StartupDependencyBootstrapOnly` 是独立事故工具,可从应用商城与 SaaS 两个不可变包覆盖式恢复七项最小可登录 Managed 接口并做物理强回读;它不是 API 进程的完整运行时就绪定义,成功后仍须执行普通完整应用覆盖更新。契约测试须枚举九个包的全部接口资源,覆盖 Managed 本地漂移/软删除、Id/地址自动重映射、CreateIfMissing 墓碑保护、登录后实际路由、商城批量安装和已健康零操作。
|
|
351
|
-
|
|
352
|
-
### 2026-08-26:登录成功后仍成片 `sys_apiengine NoExistData` 与 Upgrade25 历史文件阻断
|
|
353
|
-
|
|
354
|
-
- 触发:新版前后端部署到历史租户后,登录页依赖已被补齐,但 `platform-service-health`、`platform-sys-dept`、`mci-module-presentation-stats`、`platform-runtime-custom-hook`、商城批量工作器等登录后接口继续缺失;与此同时 `mci_ai_app_file.VersionId` 的历史空值使 Upgrade25 在创建唯一索引前失败,后续后台升级链无法收敛。
|
|
355
|
-
- 根因:把“能登录”误当成“平台运行时已就绪”,启动门禁和事故工作器长期依赖固定七项清单;历史应用文件在 V3 引入版本外键前已经存在,升级只做审计并直接失败,没有安全、确定且可重放的归档策略。旧商城工作器还可能访问已经改名的 `/apiengine/get-microi-store` 地址。
|
|
356
|
-
- 通用修复:API 进程启动门禁以上述九包全部接口为事实源,Managed 资源无论缺失、漂移、软删除或同版本都从程序集内置官方包覆盖恢复,CreateIfMissing 只补完全不存在的记录;应用商城保留独立 Managed 旧地址接口并转发到 `get-microi-store` Key 的正式 `/apiengine/get-microi-store-list` 实现。Upgrade25 必须先按 `OsClient + AppId + legacy-unversioned-v3` 生成确定性历史版本 Id,把每个应用的空 `VersionId` 文件原样归档并强回读为零,再计算路径 Hash 和创建唯一索引;文件同时缺少 `AppId`、确定性 Id 被占用或同名版本身份不一致时失败关闭,不猜测、不合并、不删除。
|
|
357
|
-
- 验收:应用包测试必须证明九包接口 Key/稳定 Id 全局唯一、每项政策与醒目提示完整、旧商城地址和正式地址均存在;升级测试覆盖 MySQL/SQL Server/Oracle 的历史分组、参数化更新和样本诊断 SQL。真实启动日志必须分别显示物理字段、完整平台运行时闭包、Upgrade25 历史归档计数和每个升级步骤终态;登录后逐一调用当前用户、健康、部门、私有文件、菜单角标与商城批量计划,不能只验证匿名系统设置。
|
|
358
|
-
|
|
359
|
-
## 复盘:应用包切换 HDFS 后旧导入器无法更新自己
|
|
360
|
-
|
|
361
|
-
- 触发场景:商城行与不可变版本快照已经只保存 HDFS 路径、大小和 SHA-256;历史租户仍运行只读取 `AppPakcet` 的导入器。用户尝试先更新“应用商城”以获得新版导入器时,旧导入器从商城源取得空 `AppPakcet`,在 3% 直接报“Package不能为空”,形成更新器无法更新自己的引导死锁。
|
|
362
|
-
- 通用协议:新版导入器请求商城模型时必须显式声明 `PackagePointerMode=HdfsV1`,自行下载一次并校验 UTF-8 字节数与 SHA-256。商城模型面对未声明该能力的旧调用端,允许从同一个受信 HDFS 指针读取并严格校验正文,只在本次响应的 `AppPakcet` 中临时回填;绝对禁止写回 `sys_microistore`、`mic_data_version`、任务参数或检查点。私有包仍必须使用短期授权地址,大小上限、HTTP 状态和摘要任一异常都失败关闭。
|
|
363
|
-
- 发布顺序与验收:先把兼容桥更新到官方商城源的 `get-microi-store-model`,再发布包含新版模型接口、导入器和启动依赖的精确应用商城版本。自动化同时覆盖新版请求零回填、旧请求可安装、摘要/大小不符拒绝、数据库无包正文字段更新;真实历史租户必须保留旧导入器启动第一次正式更新,等待终态成功并回读新版导入器,然后立即同版本覆盖式复跑,确认资源仍精确等于包正文且不产生重复记录。直接通过 MCP 替换目标导入器只能作为已故障租户的最后恢复手段,不能代替协议兼容性验收。
|
|
364
|
-
|
|
365
|
-
## 复盘:可信后台任务被 StopHttp 提前拦截
|
|
366
|
-
|
|
367
|
-
- 触发场景:`V8.ApiEngine.RunBackground` 已成功创建任务,但 Worker 执行 `StopHttp=1` 的批量引擎时立即失败并提示“此接口已禁止http调用”。
|
|
368
|
-
- 根因:Worker 为保留按钮调用、权限和审计语义继续使用 `_InvokeType=Client`,旧版 ApiEngine 只按该字段判断 `StopHttp`,没有识别服务端恢复的持久化任务来源。
|
|
369
|
-
- 通用规则:核心 ApiEngine 仅在“服务端可信用户作用域 + `_TrustedServerInvocation=true` + 非空任务 Id + 匹配任务信封 + 正数 fencing token”全部成立时豁免 `StopHttp`;少一项都按普通 HTTP 拒绝。不得把所有后台调用粗暴改成 `Server`,也不得只凭客户端可伪造的任务 Id 或信封放行。
|
|
370
|
-
- 旧节点兼容:应用资源尚需覆盖未部署核心修复的服务,可暂将批量引擎设为 `StopHttp=0`,但 V8 首行安全门必须执行同样的全条件校验;HTTP 控制器必须剥离 `_TrustedServerInvocation`。契约测试同时断言严格 `AND` 校验、独立源码与包内副本一致、普通调用失败关闭。
|
|
371
|
-
|
|
372
|
-
## 复盘:后台任务基础包的自举与索引幂等
|
|
373
|
-
|
|
374
|
-
- `app.microi.background-task` 自身负责创建/修复后台任务表,首次安装和离线安装必须以前台接口完成;不能先调用 `RunBackground`,否则旧库缺少 `OsClient` 等字段时会在导入开始前失败。
|
|
375
|
-
- 后台任务可用性不能只检查表存在,还要检查运行时必需列;部分升级的旧表必须返回“能力尚未就绪”,不能继续拼接包含缺失列的 SQL。
|
|
376
|
-
- 应用包中的独立 `CREATE INDEX` 必须按表名和索引名做执行前回读;并发创建失败后再次回读,已存在则按幂等成功处理。索引 DDL 不能重复触发整张表的字段同步。
|
|
377
|
-
- 基础包必须同时携带 `OsClient` 的 `PhysicalColumns` 定义、建表内联索引与 4 条独立索引 DDL;新表靠建表一次成型,旧表靠物理列同步和独立 DDL 修复。安装前先把“应用商城”更新到包含 `BACKGROUND_TASK_BOOTSTRAP_READINESS_V1`、`APPLICATION_ASSET_BACKGROUND_CHUNKS_V1` 的 v1.8.0+ 导入器;安装成功前必须回读全部运行字段及索引,验收覆盖首次安装、部分旧表修复、重复安装和两节点竞态。
|
|
378
|
-
- 其它用户更新吾码 VS Code 插件并执行“初始化 AI 配置/拉取 Skills”后,AI 应自动识别本规范:大任务优先提交真实后台任务;若基础能力未就绪,先指导用户更新应用商城并以前台方式安装 `app.microi.background-task`,不得伪造进度或让基础包自举入队。
|
|
379
|
-
- 重复安装先比较应用包拥有的字段定义,完全一致就跳过 `UptFormData`。Jint 的 `LimitMemory` 统计累计托管分配而非当前存活堆;大量无效字段更新即使被 GC 回收也会耗尽预算。v1.8.0 导入器每个后台片最多实际上传 8 个文件,并以约 32 MB Base64 为分片目标;为避免单个大文件无限空转,每片至少允许处理一个文件。片末返回 `HasMore + Checkpoint`,下一片按 `AppId + FilePath + Hash` 复用已提交资产,并禁止为统计再次解码整文件 Base64。
|
|
380
|
-
- 只有固定 Key `import-microi-store-package`、服务端可信身份、`Level >= 9999`、当前进程主租户、持久化后台 TaskId 五项同时成立时,后端才使用 `ResidentMemoryGuardOnly`,跳过会永久累计已回收分配的 Jint 内存约束。该特例仍受容器优先的进程 RSS 防线保护:95% 停止接收新工作,98% 有界停机并由持久任务恢复。普通/前台/子租户/其它 V8 不得借用此特例。
|
|
381
|
-
|
|
382
|
-
## 复盘:官网升级资源同步的三道门
|
|
383
|
-
|
|
384
|
-
- 重型发布门禁之前先运行 `node Microi.Server/OfficialApplications/Resource/refresh-resources.mjs --validate-only`:该入口只校验本地全部候选,不联网、不发布、不推进共同基线,且不能与写入参数组合。正式发布仍须通过完整测试、三方同步、精确哈希回读,不能把本地预检当成发布成功。
|
|
385
|
-
- 控制面版本使用语义版本最低门槛,并同时严格核对鉴权、行锁、资源哈希、写后回读等能力;禁止把某个旧版本字符串写成唯一合法值。可选功能一旦由包内表或任意入口声明,就必须校验其完整接口闭包及资源策略;不能自动放行未知 Key,也不能只升级版本而缺失实际保护。预检自身必须进入 Node 自动回归,覆盖新版通过、旧版及缺保护失败、半套可选功能失败。
|
|
386
|
-
- 官网当前资源只是三方合并的一侧,允许暂时落后于本地发布候选。下载阶段只校验固定白名单、稳定资源身份、JSON 可解析性及服务端返回 SHA-256;不能用“必须已包含本地最新功能标记”的规则提前拒绝旧官网,否则会形成“官网不够新所以永远无法发布新版”的循环依赖。
|
|
387
|
-
- 本地输入和三方合并后的最终候选必须继续执行最低版本、功能标记、内嵌逻辑副本一致性等严格校验;发布成功并按内容哈希回读一致后才能推进 `.resource-sync-base`,不能把放宽读取门误做成放宽发布门。
|
|
388
|
-
- 应用包版本与平台发布版本分别单调递增。包正文需要写回而本地包版本、平台版本均未高于官网时,应基于官网包版本自动递增补丁号;内容无变化时不得递增,必须用连续两次同步验证第二次为零变更。
|
|
389
|
-
- MCP 配置中的官方 API、`OsClient` 与 Token 文件是鉴权事实源,但编辑器可执行文件、插件版本目录和 `cwd` 都是易漂移的启动信息。发布器应保留鉴权配置、固定校验 `https://api.itdos.com + itdos`,并支持插件生成的稳定 `microi-cli-mcp.js` 或标准 `mcp-server.js` 入口;旧扩展配置再从同级最新已安装插件或当前工作区发现可信入口,统一使用正在运行发布脚本的 Node 启动。插件升级、Codex 插件化或旧目录清理不能再次阻塞后端发布。
|
|
390
|
-
- Token 文件的新键固定为 `ApiBase|OsClient|OsClientType|OsClientNetwork` 四段身份;Type/Network 为空时仍保留空段。读取和回写必须先用四段精确键,再兼容旧版紧凑键;旧键在多环境配置下可能被有意保留且已经失效,禁止优先读取。自动化测试要覆盖“精确键已刷新、旧键仍过期”以及 type-only/network-only 不碰撞。
|
|
391
|
-
- VS Code 的 SecretStorage 恢复 broker 必须使用确定性激活事件启动;不得只依赖大型工作区可能超时的递归 `workspaceContains`。签名密钥变化时旧 Token 本身不能以旧换新,必须由已激活 broker 使用本机 SecretStorage 静默重登并回写精确身份键。
|
|
392
|
-
- 本地资源同步的官网读取、发布和发布后回读应使用同一个已校验的 `microi_itdos` MCP 链路;CI 无 MCP 时才允许凭显式 Token 使用 HTTP。V8 独立文件与应用包内嵌副本合并时,先把文件头说明和 `Version` 与可执行正文分离:两端独立升版不能算代码冲突,不同正文安全合成后应基于两端最高版本再升一版;只有同一段可执行逻辑出现不同实现才失败关闭。
|
|
393
|
-
- 新增平台共享物理列时,除一次性版本门升级外,还要同步所有会快照该共享表的官方包 `PhysicalColumns`,让新安装和旧租户升级两条路径一致。`.resource-sync-base` 是上次官网回读的共同基线,不能与本地候选一起手工修改;基线可疑时先从官网只读修复,再执行三方合并、自动升包版本、正式发布和 SHA 回读。
|
|
394
|
-
- 发布验收至少包含:定向合并测试、真实 `PublishBatch`、六项资源逐项 SHA-256 回读,以及立即执行第二次幂等重跑。任何一步失败都不得宣称官网已同步,也不得推进共同基线。
|
|
395
|
-
|
|
396
|
-
## 复盘:官网模板库误报平台应用可更新
|
|
397
|
-
|
|
398
|
-
- 触发场景:官网 `sys_microistore` 的平台应用版本持续发布,但 `sys_microistoreversion` 仍保留旧安装版本;官网自身会显示“可更新”,从官网数据库复制出来的新租户也继承同一误报,尽管这些平台能力实际已经随官网主库维护完成。
|
|
399
|
-
- 身份边界:只能在服务端同时满足 `OsClient=iTdos` 且当前节点私钥公钥部分与内嵌官方 License 公钥完全一致时执行。只使用同名租户、域名、配置开关或任意自建私钥都不得触发;客户租户的安装版本仍是其独立事实源。
|
|
400
|
-
- 对齐规则:每次后端启动都在现有租户升级分布式租约内盘点 `ApplicationType=Platform + IsApprove=1` 的商城行,只处理 `Installed/Success/Succeeded/已安装` 的既有安装记录,按 `StoreId -> AppId -> 唯一 AppName` 匹配。只条件更新 `AppVersion/AppVersionInstall/PackageVersion`;稳定键仅在目标键未被其它安装记录占用时补齐。不得新增“已安装”记录、覆盖失败/异常状态、修改安装时间或删除重复历史行。
|
|
401
|
-
- 分布式与验收:更新是确定值条件写入,节点中途退出后下次启动继续,第二次执行必须零更新;验收同时回读版本表三个字段,并执行官网商城列表接口,确认 `Outdated=0`、`Abnormal=0`。真实未安装应用仍应保留 `Uninstalled`,不能为了清空通知伪造成已安装。
|
|
402
|
-
|
|
403
|
-
## 复盘:共同基线已有引擎但官网内嵌副本缺失
|
|
404
|
-
|
|
405
|
-
- 触发场景:本地 `app.microi.store.json`、独立接口脚本和 `.resource-sync-base` 都已有新引擎,但官网商城包尚未收录或被单侧删除;同步器在三方合并前强制读取官网内嵌代码,直接报“缺少接口引擎”,导致新版永远无法通过一键发布补到官网。
|
|
406
|
-
- 根因:旧状态机只区分“共同基线不存在的首次新增”和“三端都存在的正常合并”,漏掉“共同基线已登记、官网副本缺失”的历史基线漂移;严格 getter 在合并前抛错,使已有的首次发布与逻辑副本修复规则没有机会运行。
|
|
407
|
-
- 通用规则:只要副本映射仍属于当前发布契约,本地独立源码和内嵌副本能从共同基线安全合并,官网单独缺少内嵌引擎应视为不完整副本。JSON 合并前只从共同基线恢复该引擎的结构骨架;有官网独立文件时继续把它作为官网代码侧,无独立文件时把共同基线代码视为官网未修改,再执行正文三方合并并将结果写回内嵌副本。写回后必须按 `SysApiEngines.length` 重算 `PackageInfo.ApiEngineCount`。若共同基线引擎 Id 已被其它 Key 占用,或任意两侧同一代码位置实现冲突,仍必须失败关闭;不得通过覆盖/重建整个共同基线来掩盖问题。
|
|
408
|
-
- 自动化检查:同时覆盖共同基线不存在的首次新增、共同基线存在但官网缺失且本地升级、官网内嵌缺失但官网独立源码升级、共同基线 Id 被其它 Key 占用四种状态;断言声明引擎数等于实际数组长度;再用真实 `microi_itdos` 只读资源重放,确认候选含目标引擎且独立源码与内嵌代码相同,正式发布后执行 SHA 回读和零变更幂等重跑。
|
|
409
|
-
|
|
410
|
-
## 复盘:旧包非空约束阻止租户升级与启动
|
|
411
|
-
|
|
412
|
-
- 触发场景:商城应用包把既有字段从可空升级为 `NOT NULL DEFAULT ...`,老租户的物理列已经存在,但历史记录仍为 `NULL`;导入器直接执行 `ALTER TABLE ... MODIFY COLUMN ... NOT NULL` 时,MySQL 报 `Invalid use of NULL value`,整个安装分片失败。
|
|
413
|
-
- 根因:物理列同步只比较类型、可空性、默认值和注释,没有在收紧可空性前迁移存量数据。列默认值只影响后续写入,不会自动修复既有 `NULL`。
|
|
414
|
-
- 通用规则:除所有主键(不限于 `Id`,包括复合主键的每一列)及自增/identity 列外,平台普通物理列一律允许 `NULL`。导入器必须将历史 `PhysicalColumns.IS_NULLABLE=NO` 归一为允许为空,不收紧已有列,不为迁就非空约束而回填零/空串/租户值;业务必填由表单与后端事件校验。默认值独立保留。启动前必需的核心表必须在共享租约内完成可空兼容,再插入运行时接口;不能等商城运行后才修复商城自身的启动前置结构。
|
|
415
|
-
- 自动化检查:构造 `V8Limit NOT NULL` 无默认值的旧表、含 `NULL` 的历史记录及带默认值/注释/排序规则/索引的列;同时覆盖普通列已允许 NULL 但被 DROP DEFAULT 的情况,使用 `SELECT DEFAULT(列) FROM 表 LIMIT 0` 识别元数据无法区分的缺失默认标志。断言 Id 仍为主键、旧数据和列属性保留,随后省略可选字段的 INSERT 成功;同版本重启和二次安装不重复 DDL 或回填业务值。
|
|
416
|
-
|
|
417
|
-
- 历史数据库的可选菜单关联字段可能仍为整数类型。引用该表的应用包只能按实际物理类型把空字符串归一为 `NULL`,不能将无关联猜成 `0`,也不能越过表所有权修改既有类型;非空值及文本列保持原样。验收同时覆盖旧整数列、新文本列、重复安装和无效非空值继续报错。
|
|
418
|
-
|
|
419
|
-
## 复盘:应用新增菜单未自动授予系统管理员完整权限
|
|
420
|
-
|
|
421
|
-
- 触发场景:应用首次安装或版本更新新增了 `sys_menu`,菜单数据已经存在,但系统管理员看不到入口或只能执行部分按钮;再次人工到角色管理中勾选后才恢复。
|
|
422
|
-
- 根因:安装器只导入菜单,没有在同一事务内写入 `sys_rolelimit`;历史补丁又把单个管理员角色 Id 和五项旧权限硬编码,只能修复某个菜单,遗漏 `Read`、自定义按钮及其它 `Level >= 9999` 管理员角色。
|
|
423
|
-
- 通用规则:安装器只对本次真正新增或从删除状态重新引入的菜单自动授权,不扩大既有菜单的客户权限策略。目标角色必须从当前租户实时读取全部有效 `sys_role.Level >= 9999` 记录;基础权限固定为 `Read/Add/Edit/Del/Export/Import`,并合并菜单 `MoreBtns/ExportMoreBtns/BatchSelectMoreBtns/PageBtns/PageTabs/FormBtns` 中每个按钮的 `Id + Name`,不得加入 `NoDetail/NoSearch` 这类限制权限。
|
|
424
|
-
- 旧账号等级兼容仅限已校验官方平台包:没有上述角色时,可检查固定旧内置角色 `5db47859-35a3-411a-a1f7-99482e057d24` 的 `998/9998` 级记录。仅当至少一个活动账号的数据库 `Level >= 9999` 且该角色所有未删除持有者均为系统管理员时,才为该角色补充本次新增菜单权限;保持角色等级和用户绑定,禁止推广到普通自定义角色。角色引用同时识别字符串数组和 `[{Id:...}]`,不相信引用对象中的缓存 Level。
|
|
425
|
-
- 幂等与失败边界:已有 `sys_rolelimit` 只能合并、不得删除历史自定义权限;新增行使用“租户 + 角色 + 菜单”的确定性 Id,并在并发主键冲突后重新回读合并。找不到系统管理员、查询失败或任一权限写入失败必须让整个安装事务回滚,不能出现“菜单成功但管理员无权”的半成品。通过 FormEngine 写入以触发共享授权缓存失效。
|
|
426
|
-
- 自动化检查:覆盖多个系统管理员、已有部分权限、自定义按钮既有 JSON 字符串也有数组、删除菜单恢复、重复安装零新增、两个节点同时插入后合并,以及既有菜单更新不自动扩权;发布门同时校验独立导入器与商城包内嵌副本都包含该能力。
|
|
427
|
-
|
|
428
|
-
## 复盘:商城发布升版打断所有后台分片安装
|
|
429
|
-
|
|
430
|
-
- 触发场景:主租户为大量子租户执行“安装/更新全部平台应用”时,某个平台包从 v7.5.17 发布到 v7.5.18;正在执行的任务在下一分片报“检查点版本与当前版本发生变化”,大量子租户同时失败。
|
|
431
|
-
- 根因:版本保护正确阻止两个包混装,但批量计划只持久化 `StoreId + AppVersion`,每个分片仍从 `sys_microistore` 易变当前行重新取包,没有使用已经存在的 `mic_data_version` 完整快照,也没有把 `StoreVersionId` 写进 checkpoint。
|
|
432
|
-
- 通用规则:后台安装首次取包必须按计划 `AppVersion` 锁定匹配的完整历史快照,并在每个分片复用同一 `StoreVersionId`;应用商城自身必须排在平台批量计划首位,先自举最新版导入器。发布中途升版不能改变既有任务的包体,也不能让既有任务自动追新;下一次批量盘点再安装新版本。
|
|
433
|
-
- 自动化检查:构造计划版本 v1.0.0、商城当前版本在分片间升到 v1.0.1,断言首次选择 v1.0.0 快照 Id,恢复分片仍请求同一 Id且成功;覆盖快照尚未生成、显式 Id 与期望版本不符、身份不符均失败关闭,并断言批量计划第一项为 `app.microi.store`。
|
|
434
|
-
|
|
435
|
-
## 复盘:父任务 Monitor 重复自举误判同版本工作器
|
|
436
|
-
|
|
437
|
-
- 触发场景:全部子租户安装任务已经创建并持续执行,父任务在 Monitor 分片中再次调用租户发现/工作器自举;子租户刚从应用包写入的商城工作器与主租户版本相同,仅 BOM 或 CRLF/LF 不同,却被判为“同版本源码不同、疑似租户定制”,父任务失败,而子任务仍在后台运行。
|
|
438
|
-
- 根因:父编排器在解析 checkpoint 阶段前无条件读取租户目录,导致 Monitor 也重复执行只应发生在 Queue 的有副作用自举;服务端源码比较又直接使用 Ordinal 原文比较,没有先消除跨平台文本格式差异。
|
|
439
|
-
- 通用规则:租户发现与商城工作器自举只允许在 Queue 阶段执行;Monitor 必须只汇总 checkpoint 中已经持久化的 `ChildTasks`。同版本源码比较只可规范化 UTF-8 BOM、CRLF/LF 和文件末尾空白;任何其它字符差异仍按租户定制失败关闭,禁止用去注释、压缩空白或模糊标记绕过保护。
|
|
440
|
-
- 自动化检查:覆盖同版本 LF/CRLF/BOM 等价且不刷新、同版本真实代码差异继续拒绝、旧版官方谱系允许升级、新版目标保留;接口引擎资源断言 Monitor 检查点标记存在且 `GetChildTenantPlatformAppMaintenanceTargets` 只位于 Queue 分支。
|
|
441
|
-
|
|
442
|
-
## 复盘:资源数量小但工作量重的应用被合并为单事务
|
|
443
|
-
|
|
444
|
-
- 触发场景:子租户批量安装进度停在“系统设置”或“系统帐号”十多分钟,心跳和 CPU 仍活跃但没有新检查点;重启后同一现象只会转移到下一个租户。
|
|
445
|
-
- 根因:批量工作器请求 `BulkAdaptiveSingleSlice`,导入器仅按表、字段、菜单和数据行数量判断“小包”,没有计入 DDL、实体生成、权限回填和历史数据迁移的真实成本,因而关闭了内部后台分片。
|
|
446
|
-
- 通用规则:后台商城安装必须始终保留有界分片和持久化检查点;旧工作器仍传单片参数时,新导入器必须安全忽略。已排队的跨租户任务在真正运行目标 V8 前,应按进程缓存执行一次官方安装器自愈,使平台修复能从原检查点接管。
|
|
447
|
-
- 自动化检查:断言批量工作器显式关闭单片参数、导入器不存在 `backgroundChunkingEnabled=false` 路径、旧单片参数只记录忽略诊断;后台执行器在子租户工作器运行前调用受信自举,并继续保留同版本真实源码差异的失败关闭保护。
|
|
448
|
-
|
|
449
|
-
## 复盘:旧租户前置物理列逐列重建耗尽首片超时
|
|
450
|
-
|
|
451
|
-
- 触发场景:已启用后台分片后,旧租户首次更新“系统设置”仍长时间没有 `ChildCheckpoint`;心跳与 CPU 正常,接近单片超时后才推进。实时 Schema 回读显示 `sys_apiengine` 与 `diy_table` 同时缺少多项生成实体固定列。
|
|
452
|
-
- 根因:导入器为兼容历史空库,在第一次 FormEngine 调用前逐列执行 `ALTER TABLE ADD`。MySQL 每个语句都可能重新准备或重建同一张元数据表,多个固定列的累计耗时发生在首个可持久化检查点之前。
|
|
453
|
-
- 通用规则:MySQL 同一张表缺少多个受信固定前置列时,必须先完整盘点,再用单条 `ALTER TABLE ... ADD ..., ADD ...` 原子补齐并回读;可信后台任务每个分片最多修改一张前置元数据表,提交 `Prerequisites` 检查点后再继续下一张。没有缺列的现代租户直接进入原 DDL 阶段,不制造空分片。并发节点已完整补齐时按幂等成功,否则保留真实表名、未补齐列和数据库错误并失败关闭。SQL Server 与 Oracle 使用各自已验证语法,不得直接套用 MySQL 批量语句。
|
|
454
|
-
- 自动化检查:独立导入器和商城包内嵌副本都必须携带批量前置列及检查点标记;断言 MySQL 路径先收集 `pendingDefinitions`、每表只拼接一次批量 ALTER、后台每片写表上限为一,且失败后逐项回读所有待补列。真实旧租户验收需证明前置列分片已提交、随后不可变 `StoreVersionId` 与字段阶段检查点继续推进。
|
|
455
|
-
|
|
456
|
-
## 复盘:父级监控遇到数据库死锁被误判为业务失败
|
|
457
|
-
|
|
458
|
-
- 触发场景:父级 Monitor 已持久化全部子任务 Id,子任务仍在正常执行且 checkpoint 中没有业务失败;父任务汇总进度时偶发数据库死锁,却因调用方配置 `MaxAttempts=1` 立即进入 `Failed`,通知中心因此把仍可成功收敛的整批任务标红。
|
|
459
|
-
- 根因:后台任务把数据库死锁、锁等待超时等基础设施瞬态竞争与接口返回失败共用同一业务重试预算。低业务重试次数无法覆盖工作器自身的领取、心跳、检查点或结果持久化竞争,也没有保留父子任务的真实运行语义。
|
|
460
|
-
- 通用规则:后台任务存储层只对已知数据库死锁、锁等待超时、序列化竞争等稳定特征启用独立的有界基础设施重试;即使业务 `MaxAttempts=1`,也允许最多三次基础设施执行机会。重试必须保留原 TaskId、父子关系、checkpoint 和已产生的副作用,不得重新创建子任务;成功后清除瞬态错误,第三次仍竞争才按原业务规则终止。普通业务错误、数据冲突和 `Value cannot be null` 等非竞争错误不得借用该预算。
|
|
461
|
-
- 自动化检查:覆盖嵌套 ProviderException 与外层包装异常、MySQL/SQL Server/PostgreSQL/Oracle 的稳定错误码或消息;断言第一次和第二次竞争回到可领取状态且不消耗业务 AttemptCount,第三次进入原终态,非竞争异常仍按 `MaxAttempts` 立即失败。真实验收必须在每个活跃运行分区等待该分区全部子任务收敛,再以 `MaxAttempts=1` 连续执行一轮完整汇总和一轮立即无操作重跑;两轮父任务都必须得到 `SucceededCount=ExpectedCount、FailedCount=0`,且无操作轮为零安装/零更新。
|
|
462
|
-
|
|
463
|
-
## 复盘:字段分片完成后后台安装卡在缓存失效广播
|
|
464
|
-
|
|
465
|
-
- 触发场景:字段分片的数据库写入和 Schema 回读已经精确完成,但 `ChildCheckpoint` 长时间停在同一字段索引;任务取消也无法及时结束,进程内存、线程数和 CPU 持续增长。
|
|
466
|
-
- 根因证据:两次托管转储的调用链都停在 `V8.ApiEngine.Run -> GetApiEngineModelInternal -> MicroiTwoLevelCache.SetAsync -> PublishInvalidateAsync -> PublishWithRetryAsync`。权威 Redis 写入已经成功,随后用于通知其它节点清理一级缓存的 Pub/Sub 广播没有完成时限,因而把业务调用永久挂住;与此同时,单字段元数据更新即使只变更 Label、Remark、布局或 V8,也会重复执行物理列 DDL,放大旧租户升级成本。
|
|
467
|
-
- 通用规则:Redis 权威值写入成功后,跨节点一级缓存失效广播只能是有界、尽力而为的附属动作。队列等待和实际发布都必须有独立短超时,超时后观察迟到异常并开启短暂熔断冷却,防止悬挂发布任务无界堆积;不得因此回滚已经成功的权威写入。`UptDiyField` 只有列名或物理类型变化时才允许调用 `ChangeColumn`,显示名称、说明、布局和事件代码等纯元数据变化禁止触发 DDL。
|
|
468
|
-
- 自动化与真实验收:缓存测试必须覆盖发布永久不返回时的有界退出、迟到异常观察和冷却期抑制;字段测试必须断言只有 Name/Type 变化才进入物理 DDL。应用商城资源契约测试、后台任务与 SaaS 回归测试通过后,还必须在每个活跃运行分区完成 `ExpectedCount/ExpectedCount` 子租户收敛,并立即执行一轮相同数量的无操作重跑。验收期间若官方应用发布了新版本,应以新的不可变 `StoreVersionId` 启动独立追赶批次,禁止混入已经开始的旧版本分片。
|
|
469
|
-
|
|
470
|
-
## 复盘:最新版后端仍放行未锁快照的旧商城工作器
|
|
471
|
-
|
|
472
|
-
- 触发场景:目标租户已经部署最新版前后端,但数据库中的 `import-microi-store-package v2.2.9` 与 `bulk-import-microi-store-packages v1.2.4` 被启动完整性检查判为合格;平台应用批量任务开始后,官方商城恰好升版,首个应用在下一分片仍从易变当前行取包并失败。
|
|
473
|
-
- 根因:后端自举门槛只校验早期版本和历史标记,没有把不可变快照、禁止自适应单片、前置物理列分片检查点及商城自举优先级纳入能力契约;MCP 单应用恢复工具也只能传 `StoreId`,无法显式锁定已经回读的 `mic_data_version` 快照。
|
|
474
|
-
- 通用规则:后端启动必须同时校验导入器最低版本与固定快照/有界分片/前置列检查点标记、批量工作器最低版本与 `StoreVersionId + BulkAdaptiveSingleSlice:false`、商城列表的自举优先级;任一缺失都必须从受信升级资源刷新,不能仅看后端二进制版本。MCP 安装/更新允许传受校验的可选 `storeVersionId`,审计同样记录该 Id;不同快照使用不同幂等请求 Id,禁止把旧任务静默改指新包。
|
|
475
|
-
- 自动化与真实验收:单元测试同时拒绝旧版本和缺标记的伪新版工作器;在真实旧租户先用固定快照完成应用商城自举,再执行全部平台应用更新并立即做零更新复跑。验收期间出现的新官方版本只进入下一独立批次,历史失败任务保留作审计,不删除或篡改。
|
|
476
|
-
|
|
477
|
-
## 复盘:本租户自助批量被误判为主租户跨租户任务
|
|
478
|
-
|
|
479
|
-
- 触发场景:普通租户在自己的应用商城点击“全部安装/更新”,后台执行器仅按固定批量工作器 Key 触发跨租户自愈,把 `owner=当前租户、target=当前租户` 当成主→子任务;旧导入器只能从自己复制自己,随后被新能力门禁拒绝,并错误提示“先更新主租户应用商城”。
|
|
480
|
-
- 根因:跨租户自愈没有校验由服务端控制面持久化的目标租户保留标记,也没有要求任务拥有者与执行租户不同;把同租户自助批量和主租户代子租户执行混成了同一作用域。
|
|
481
|
-
- 通用规则:运行前强制自愈只允许用于固定批量工作器、非空服务端目标标记、`owner != execution` 且标记精确等于执行租户的主→子任务。普通租户自助批量必须跳过跨租户复制,让持久计划按官方列表顺序优先安装/更新应用商城自身,再由新版导入器继续后续应用;不能要求官方发布源安装自己。
|
|
482
|
-
- 自动化与真实验收:单元测试覆盖同租户无标记、同租户伪标记、跨租户正确标记、标记漂移和错误工作器 Key;真实旧租户先保留旧导入器发起自助批量,断言不再出现“子租户商城工作器执行前自愈失败”,计划第一项为应用商城,全部任务成功后立即执行零更新复跑。
|
|
483
|
-
|
|
484
|
-
## 复盘:平台包跨旧租户安装时同时暴露结构闭包、元数据回读与目录脆弱性
|
|
485
|
-
|
|
486
|
-
- 触发场景:同一轮主租户批量任务在不同子租户分别报“数据集目标表尚未创建”“接口引擎写入后 HTTP 状态不一致”“既有菜单 Url 唯一冲突”或“未找到 OsClient”;父任务若在目录阶段对全部目标做有副作用自举,还会让一个坏租户阻断其余已可执行租户。
|
|
487
|
-
- 包结构闭包:任何 `DataSets.TableName` 都必须由同一包的 `DiyTables + DiyFields + DDLStatements + PhysicalColumns` 完整创建或由显式依赖声明保证先安装,不能只因为官方母库已有该表就省略。契约测试要逐个数据集反向验证目标表、主键、字段和物理 DDL,并在真实缺表旧租户执行首次安装与重复安装。
|
|
488
|
-
- 无 `Type` 的 `TableChild` 是布局入口,通过真实子表和外键展示记录;不得凭控件名推断 `varchar` 物理列。以实时物理目录核对 DDL/PhysicalColumns,历史包虚构布局列只纠正声明,不远端 DROP、不删除控件/子表/数据,实际存在的同名定制物理列保持。官方资源生成器的精确接口列表必须与完整正式母版及当前包闭包一致,重复生成不得静默删除新增接口、正文、鉴权或 Managed/CreateIfMissing 策略;新增字段及索引也须进入真实计数和幂等深比较回归。
|
|
489
|
-
- 随包固定自动编号:导入器 `v2.9.8` 根据目标 `diy_field.Component=AutoNumber`,仅恢复本次允许写入的显式非空编号,并使用共享事务的最小 `_ForceUpt` 更新和严格回读。`UpsertById` 重装修复旧流水号;`InsertIfMissing` 已有配置保持原编号和值。禁止把包内 `_ForceUpt` 当作可信控制参数,也不能只验证模板存在而不检查其业务检索编号。旧安装器先通过应用商城更新,再重装原不可变应用包;冲突、字段元数据读取失败或回读不一致必须失败回滚。
|
|
490
|
-
- 配置子表种子不能硬编码官方父记录 Id。`InsertIfMissing` 数据集可声明 `ParentBinding:{Field:'SysConfigId',TableName:'sys_config',MatchField:'IsEnable',MatchValue:1}`,仅在目标端查询恰好一条父记录 Id,先绑定外键再检查冲突。0 条、多条、查询失败或不安全标识立即失败;不能覆盖父配置值。导出器须保留该声明,旧导入器必须先升级,不能忽略绑定后按官方 Id 写入。
|
|
491
|
-
- 大表物理兼容必须覆盖全部 DDL 路径:`BIT` 不能落入 `varchar` 默认映射,整数显示宽度与纯标签/注释差异不能触发改列;同一个包的字段元数据变化交给物理列阶段统一比较,不能先改再改回。普通标量列仅默认值变化时使用 `ALTER COLUMN ... SET DEFAULT`,移除旧值必须设为 `NULL`,禁止 `DROP DEFAULT` 留下省略字段时触发 1364 的标志;强回读并禁止 COPY 回退。TEXT/BLOB 的缺失默认标志只能保留完整定义执行 `MODIFY COLUMN` 修复,不能用不支持的 `ALTER COLUMN SET DEFAULT NULL`。空字符串默认值不等同于 NULL。安装器时间辅助必须自包含,应用文件落库等新增分支也不得直接依赖租户的 DateNow。
|
|
492
|
-
- 受管接口状态:旧库 `diy_field` 元数据可能落后于 `sys_apiengine` 物理列,导致 FormEngine 返回成功却忽略 `IsEnable/StopHttp`。仅对受信官方 `Managed` 接口的固定布尔控制列,允许在 FormEngine 写后不一致时按稳定 Id 参数化校准物理列、清理租户缓存并严格二次回读;源码、匿名权限、ApiAddress 和租户扩展不得借此绕过三方冲突或所有权保护,二次回读仍不一致必须整包失败。
|
|
493
|
-
- 菜单与目录隔离:更新既有菜单发生 Url 唯一冲突时,优先保留目标租户当前唯一路由;确需新路由时使用有界、可回读的稳定后缀,不得字符串拼 SQL。子租户目录发现必须是无副作用读取;运行时缺失在单目标投递前按 `sys_osclients` 受控热加载并只记录该租户失败,已经排队的子任务继续监控到终态,禁止一个 `未找到OsClient` 提前终止整批。
|
|
494
|
-
- 百租户并发边界:父协调任务继续使用集群级防重键;子安装任务必须使用固定商城工作器 `ConcurrencyKey` 在当前运行环境内串行。不能根据 `OsClient` 推断物理库隔离,因为多个子租户可能共享同一数据库;只有未来能由服务端权威连接指纹证明互不共享物理库并建立分组锁时,才允许在不同物理库组间并行。
|
|
495
|
-
- 兼容与验收:V8 协调器需要兼容尚未部署新 C# 原子的节点,在目录或单目标投递返回明确的缺失 OsClient 时最多热加载并重试一次,重复同一缺失或超过安全上限立即失败关闭。验收顺序固定为先更新主租户应用商城导入器,再用不可变 `StoreVersionId` 更新 SaaS 协调器,完成全部子租户父子任务收敛,最后立即执行 `Planned=0` 的无操作重跑;同时保留每个失败租户的独立任务和通知中心证据。
|
|
496
|
-
|
|
497
|
-
## 复盘:旧对象存储节点缺少 MoveObject 导致编译资源无限重传
|
|
498
|
-
|
|
499
|
-
- 触发场景:平台微服务包只有少量 `BuildAssets`,但后台检查点长期停在 `ApplicationAssets / Build / AssetIndex=1`,`ApplicationAssetUploaded` 却持续超过包内资源总数。目标节点能够上传并回读公有对象,但不支持或拒绝 `MoveObject`;导入器每一片都重新上传同一文件,再因移动失败写回临时路径,下一片继续重复。
|
|
500
|
-
- 通用规则:新上传文件移动到租户稳定路径失败时,若上传结果已通过摘要和大小校验,应保留这个真实可读路径并写入显式兼容 scope(当前为 `PrivateSource+PublicBuildMoveFallback`)。后续分片只允许在同时命中 AppId、文件路径、摘要、大小、真实 HDFS 路径和该 scope 时直接复用,禁止再次调用 `MoveObject` 或上传;没有兼容标记的历史坏路径仍只允许一次有界重传修复,不能把任意旧元数据误当成有效对象。
|
|
501
|
-
- 自举与验收:主租户投递每个子任务前必须先复制最新版应用商城导入器和批量工作器,已经排队的任务不得假定会动态取得主租户新代码。回归测试要模拟“上传成功、MoveObject 不可用、下一分片恢复”,断言上传次数保持 1 且资源索引继续前进;真实旧租户验收必须观察 4 个编译资源在有界片数内完成,并在全租户成功后立即做 `Planned=0` 复跑。
|
|
502
|
-
|
|
503
|
-
## 复盘:共享公有编译包安装成功但预览进入发布方租户
|
|
504
|
-
|
|
505
|
-
- 共享不可变资源不能像租户独有 HTML 那样重写字节。包内 `SharedPublicRuntime.EntryUrl` 保持纯 HTTPS 不可变地址和摘要;目标 `PreviewUrl` 必须由导入器按当前 `V8.SysConfig.ApiBase + V8.OsClient` 生成 `apiBase/OsClient` 查询参数,不得直接使用发布端默认值,不得附带 Token、密码或签名。
|
|
506
|
-
- 目标 `ApiBase` 缺失、携带凭证或无效时停止并说明配置位置;不能用 CDN 地址或官方默认地址回退。公有字节共享不代表账号、房间、积分或 SignalR 频道跨租户共享。
|
|
507
|
-
- 自动化需比较不可变路径与摘要未变、普通包分支未变,并从目标安装后的实际入口检查登录请求、房间写入及实时事件;后台 `Succeeded` 不能替代租户启动验收。旧导入器先通过应用商城升级,再以新请求 Id 重装目标应用验证修复,保留旧任务审计。
|
|
508
|
-
|
|
509
|
-
## 复盘:历史开关列的单字节文本阻止数值列升级
|
|
510
|
-
|
|
511
|
-
- 数值类型转换失败时先只读实际 `PhysicalColumns` 和错误样本字节;表单字段声明为整数不代表物理列就是整数。旧 `BIT` 曾误转为文本时,可能留下单字节 `00/01`,不能按普通字符串 `0/1` 判断,也不能把所有非数字清零。
|
|
512
|
-
- 仅当可信包与目标字段均明确声明为开关(Switch),且文本值满足单字节和 `HEX IN ('00','01')`,才允许导入器按精确谓词归一为 `0/1`,然后进行类型升级。真正的 BIT 数值列、NULL、多字节文本、普通字段及其它脏值保持各自路径;未知值继续失败关闭。
|
|
513
|
-
- 修复通过正式应用商城导入器版本交付,先升级安装器再用新幂等请求重试原不可变包;禁止直接 SQL 改客户数据或修改旧失败任务。回归覆盖精确匹配、普通字段拒绝、并发重试和物理类型回读,并保留转换计数与终态证据。
|
|
514
|
-
|
|
515
|
-
## 复盘:只补页面首屏接口导致旧租户持续 `sys_apiengine NoExistData`
|
|
516
|
-
|
|
517
|
-
- 触发场景:新版前端已经切换到 `/apiengine/platform-*`、商城 `get-microi-store` 或模块/消息等官方接口,但客户只更新前后端二进制,没有逐个安装应用;启动门禁只检查少数首屏 Key,于是登录恢复后其它页面仍连续报 `sys_apiengine NoExistData`。
|
|
518
|
-
- 根因:把平台运行依赖维护成手写短清单,并只复制 SaaS 单包;接口之间的 `V8.ApiEngine.Run` 依赖、其它官方平台应用和个性化 Hook 没有进入同一闭包,旧数据库也没有可靠的启动前自愈与逐项回读。
|
|
519
|
-
- 强制规则:启动前接口闭包必须由全部内置官方平台应用包动态计算,并递归解析接口调用;当前官方基线为 9 个包、106 个接口(98 个 `Managed`、8 个 `CreateIfMissing`),数量只是发布快照,运行逻辑不得硬编码。门禁逐项校验 Key、地址、启用状态、匿名/HTTP 状态和源码策略;缺失时从受信内置包按原所有权补齐,所有项严格回读成功后才对外提供流量。`CreateIfMissing` 首次创建后永不覆盖客户代码。
|
|
520
|
-
- 控制面自举:官方资源发布必须先保证 `get-microi-upgrade-resource` 自身达到当前协议,再发布其它包;若控制面旧版本不能校验新包,先只发布并回读这一项,刷新动态路由缓存后再发布剩余资源。发布响应超时或 Redis 广播失败时先按资源 SHA 回读判断提交/回滚,禁止盲目重放。
|
|
521
|
-
- 包内明确声明 `Managed` 的 `get-microi-upgrade-resource` 必须和其他受管接口一同原位覆盖;禁止硬编码跳过该 Key 却记安装成功。无 Managed 声明的历史包保留保护边界,官方发布/投影仍需可信后端鉴权。验收核对完整源码、版本、稳定 Id 和路由,不只读取安装状态。
|
|
522
|
-
- 独立系统日志包的接口投影使用 `ReconcilePublishedApiEngines` 与显式 `ProjectionScope: 'SystemLog'`,仅允许单一 `app.microi.sys-log.json`,且包内 `PackageInfo.AppId` 必须为 `app.microi.sys-log`、`ExpectedSha256` 必须等于已发布完整包摘要。默认九包全量规则保持不变;未知范围、其它文件或部分九包选择都应拒绝。仍须执行官方鉴权、事务行锁、Managed/CreateIfMissing 规则及完整回读,不能将母版投影当作客户已安装。
|
|
523
|
-
- 兼容与验收:历史 Controller 回退不能再转调可能缺失的同一个接口引擎;保留旧路由时必须使用可信 Core 原子或明确返回可诊断兼容结果。自动化测试应扫描 PC、UniApp、内置应用包和接口源码的全部 `/apiengine/` 与 `V8.ApiEngine.Run` 引用,证明每个依赖由官方包声明;真实启动必须对每个启用租户输出开始、缺项、修复、逐项成功及最终汇总日志,并同时验证匿名、登录态、商城批量计划和重复启动幂等。
|
|
524
|
-
|
|
525
|
-
跨租户安装验收必须检查 `sys_microiservice.MsUrl`:受托管文件运行时的入口必须使用目标租户与目标 AppKey;数据库运行时保留 `db`,显式外部运行时保留外部地址。源码摘要与编译资源摘要仍需独立回读。
|
|
1
|
+
---
|
|
2
|
+
name: app-store
|
|
3
|
+
description: Microi 应用商城开发、打包、安装和升级规范。用于官方/社区应用、Manifest、源码与构建产物、依赖、后台安装任务、租户隔离、增量升级、回滚和验收。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **Microi吾码基础规范(强制):** 任何 AI 模型与宿主每次新建或接续吾码任务,先完整读取 `../workspace-conventions/SKILL.md`,必须执行版本播报、`@microi.net/cli` 后台自动升级、Skills/MCP 同步和进度播报。安装与诊断读取 `../microi-codex-installer/SKILL.md`;更新失败延后重试,不阻断当前工作。
|
|
7
|
+
|
|
8
|
+
# Microi 应用商城
|
|
9
|
+
|
|
10
|
+
## 核心原则
|
|
11
|
+
|
|
12
|
+
应用包是可审计、可重复安装、可增量升级的交付单元。运行类型使用 `ApplicationType`:普通平台包的新建默认值是 `Regular`,既有商城平台应用/通知仍使用 `Platform`,另外还有 `MicroService`、`UniApp`、`Web`;读取端必须兼容 `Regular/Platform`,不能在迁移完成前强制改单值。官方/社区来源使用 `PublisherType`。
|
|
13
|
+
|
|
14
|
+
`AppType` 是历史复用字段:旧包/接口曾把它用于官方/社区来源,也曾把它作为运行类型回退。新代码不能把 `AppType` 当事实源;只在读取旧数据时回退,写入新数据使用 `ApplicationType + PublisherType`。
|
|
15
|
+
|
|
16
|
+
应用包是声明式资源的权威交付边界:当前包标记为 `Managed` 的表单元数据、菜单、字段、接口引擎等资源按包覆盖;当前包标记为 `CreateIfMissing` 或 `InsertIfMissing` 的租户扩展/配置只补缺。覆盖安装不等于整表清空,仍禁止把发布方租户业务数据、密钥或连接配置原样复制到目标租户。
|
|
17
|
+
|
|
18
|
+
## 平台升级的应用商城边界(强制)
|
|
19
|
+
|
|
20
|
+
- 表、字段、Tab、菜单、权限、接口引擎、事件、数据源、页面、打印、工作流、任务和可幂等种子数据都应通过应用包升级;不得为这些资源在 `Microi.Server/Microi.Upgrade/` 新增租户定制 .NET 代码。
|
|
21
|
+
- 有官方 MCP 权限时,固定使用 `microi_itdos`(`https://api.itdos.com`、`OsClient=iTdos`)更新官方母版、制作并发布对应应用,按内容哈希/包版本回读后,再由目标租户 MCP 安装或更新。无官方权限时只通过当前用户自己的 MCP/Manifest 更新其数据库并回读,不得假借通用升级器越权发布官方应用。
|
|
22
|
+
- `Microi.Upgrade` 只保留应用商城/安装器启动前必需的核心物理兼容或协议迁移,并要求持久化版本门、共享租约、幂等、失败不推进版本。禁止每次启动对每个租户重跑不断增长的历史迁移清单。
|
|
23
|
+
- 新增升级点前必须完成“商城不可表达性”证明:逐项说明为什么 `DiyTables/DiyFields/DDLStatements/PhysicalColumns/DataSets`、菜单、接口引擎、工作流或 AI 应用包无法交付,以及为什么该结构在登录/商城恢复入口可用前就必须存在。不能证明时一律升级对应官方应用包;客户租户缺少某张业务表不得写成全平台 `.NET` 启动迁移。
|
|
24
|
+
- 历史升级点不能因为今天可由商城表达就直接删除:若后续步骤依赖其物理结果,须保留为冻结兼容链,或把必要前置检查显式并入后续步骤。新增步骤必须使用高于当前目标的唯一四段版本并追加到链末尾,不得抬高旧步骤版本造成非单调执行顺序。
|
|
25
|
+
- 租户协调器必须先只读 `ServerVersion`:已达到当前一次性基线时不得取得升级租约、重放历史不变量或刷新缓存;落后租户取得共享租约后必须再次读取版本,防止多节点重复执行。启动成本应近似“每租户一次版本读取 + 实际待执行迁移”,不得近似“租户数 × 历史升级点总数”。主租户接流量前的最小物理/商城引导门禁可独立保留,但不得扩展成全部子租户的永久全量扫描。
|
|
26
|
+
- 同一批历史漂移确需修复时,用一个新版本的“一次性基线”在租约内幂等封口,并仅在全部步骤强回读成功后前向推进版本;失败不得推进。基线完成后,任何新增核心迁移都必须再升版本,任何业务资源修复都必须再升应用包版本,禁止恢复为每次启动复检。
|
|
27
|
+
- 平台通用缺陷的交付证据必须分开记录:源码修复、官方母版资源、商城包发布后回读、目标租户后台安装任务、目标租户资源回读和真实 UI/接口验收;其中任一步未完成都不能笼统称为“已发布并安装”。
|
|
28
|
+
- 任何计划让全部吾码租户通过“安装/更新官方应用”获得的标准字段、布局、菜单、页面或种子数据,必须先在官方 `microi_itdos` 主租户创建并回读,再从该主租户按精确菜单/表资源导出新版包、单调递增应用版本并发布。包正文以 `PackageHdfsPath + PackageSha256 + PackageSize` 为事实源;`AppPakcet` 只作旧版读取兼容,验证完成后应为空。禁止先只在客户/子租户补字段,再用本地手工 JSON 冒充官方母版;客户验证应发生在官方包发布之后。
|
|
29
|
+
- 同一标准能力若同时属于基础 SaaS 空库包和独立官方应用(例如系统设置、系统账号),两条交付链都要更新:基础包保证新租户初始化完整,独立应用保证存量租户可增量安装。表、字段和初始化模板可按这两个目标分别交付,但同一个 Managed ApiEngineKey 必须只有一个官方包所有者,禁止 SaaS、Store 与独立应用重复携带后互相覆盖。发布后分别核对 `PackageInfo.Version`、物理列、`diy_field` 布局节点、接口引擎单一归属、商城行 `AppVersion` 和 HDFS 包指针/下载哈希,不能用其中一条替代另一条。
|
|
30
|
+
|
|
31
|
+
## 吾码创建人开发时的强制发布闭环
|
|
32
|
+
|
|
33
|
+
- 每项平台功能先执行 [工作区基础规范](../workspace-conventions/SKILL.md) 的“平台功能四项同步检查”,不能把商城包发布当成官方文档、Skills、MCP 同步的替代。本节细化其中需要发布应用包时的流程;没有可打包资源变化时记录依据,不为凑检查项空升版。
|
|
34
|
+
- 每次任务先检查工作区根的 `Microi.Server/Microi.net/`。只有目录存在且 `rg --files Microi.Server/Microi.net` 能找到至少一个真实源码文件时,才确认当前是吾码创建人在官方完整源码工作区开发;空目录不算,且不要求本次修改位于该目录。确认后,对任意目录中的平台基础能力执行修改、构建或交付时,官方应用数据包都不是“以后再补”的附加产物,而是本次实现的组成部分。目录缺失或为空时按普通用户工作区处理;纯审查、解释或诊断仍保持只读。
|
|
35
|
+
- 触发资源包括系统设置、表、字段、Tab、菜单、权限、接口引擎、事件、数据源、页面、打印、工作流、任务、平台内置微服务和可幂等种子数据。开始修改时就确定资源归属:租户开通、启动投影与基础空库归 `app.microi.saas-engine`;用户偏好、个人资料及其租户 Hook 归 `app.microi.sys_user`;租户系统设置编排及其 Hook 归 `app.microi.sys-config`;表单引擎归 `app.microi.form-engine`;模块引擎归 `app.microi.module-engine`;应用商城归 `app.microi.store`。同一能力跨多个包时逐包更新,但同一 Managed ApiEngineKey 仍须单一归属。
|
|
36
|
+
- 强制闭环依次包含:①源码和定向测试;②通过绑定 `https://api.itdos.com + OsClient=iTdos` 的 `microi_itdos` 更新并回读官方母版资源;③从母版导出或按受审计发布契约生成本地应用包,单调提升包版本并核对资源数量、版本和 SHA-256;④发布对应官方 Platform 应用;⑤重新读取商城行的小型 HDFS 指针,用公有下载或受权私有下载取得原始 JSON,核对 `Published/IsApprove`、`AppVersion`、`PackageInfo.Version`、UTF-8 字节数、SHA-256 和资源正文;⑥立即做一次同输入幂等重跑,确认无重复升版或漂移。任务还指定目标租户时,再安装/更新并等待后台任务 `Succeeded` 后回读真实资源。
|
|
37
|
+
- 本地包文件、生成器成功、单元测试通过、返回 TaskId 或 HTTP 200 都不能代替官方主数据库与商城回读。`.resource-sync-base` 只能在官网发布后逐项哈希一致时由同步器推进,不得与本地候选一起手工修改。若官方身份、MCP 登录或发布门禁失效,必须保留准确的未发布边界并修复链路;不得把本地 JSON 宣称为“其它吾码用户已经可以安装”。
|
|
38
|
+
- 应用包不得携带真实地图 Key、Token、连接串或其它租户秘密。浏览器供应商 Key 等配置只交付字段/设置模板和安全读取能力,实际值由每个目标租户在安装后自行填写。
|
|
39
|
+
|
|
40
|
+
### 后台原生规则的两种可信来源证明
|
|
41
|
+
|
|
42
|
+
普通租户的编译证明默认 `TenantInstallation`,保留真实 Installed 回执及旧摘要。官方同租户发布源禁止安装自己,只能由后端发行组合明确固定 `OfficialPublishedSnapshot`:`InstallRecordId` 绑定 `mic_data_version.Id`,原始 `Data` 的UTF-8 SHA-256另固定于编译回执并参与独立审批摘要。该类别与快照摘要不从Param或自由表字段选择、不新增表字段、不伪造Installed。受信官方身份、当前Published/审批有效指针、Verified包hash/size/HDFS、不可变快照、V3 Completed源码hash及实际DLL依赖须全部匹配;当前状态变化、软删或主库不可用下次调用立即拒绝,旧历史存在不足以授权。跨租户仍拒绝,结构发布不等于后端安装或代码审批。审批表纳入通用强制管理员清单,普通用户即使误授表/菜单权限仍不得改授权状态;V8Limit和ReadPrimary不是写权限。
|
|
43
|
+
|
|
44
|
+
## 包内容
|
|
45
|
+
|
|
46
|
+
### 仅共享编译运行产物
|
|
47
|
+
|
|
48
|
+
- 消费者只需运行应用、无需安装业务资源时,显式传 `RuntimeAssetsOnly=true`;只接受 `ProtocolVersion=3 + ApplicationType=Web + 显式 IncludeSource=false` 和通过现有 `CommittedProof`、运行清单校验的 `SharedPublicRuntime`。不能把“不包含源码”自动等同于此模式;省略或 `false` 保持原有打包行为。
|
|
49
|
+
- 请求的菜单、表、接口、移除接口、工作流、任务、数据、路由、页面及资源策略选择均必须为空;既有商城行的 `SelectMenu/SelectTable/SelectApiEngine/SelectData` 和 `PreparedAssets.MenuContract` 非空时拒绝,禁止静默清理历史选择。不能与 `DatabaseOnlyBuild` 混用。
|
|
50
|
+
- 现有 `microi_run_engine` 的 `params` 是动态对象,可传此开关,无需增加工具参数。对 `ai_app_publish_store` 的 `Action=InspectResourceSnapshot` 和 `Action=Publish` 都使用同一组冻结模式、版本、资产及提交证明,后者将前者返回的 `ResourceSnapshotHash` 作为 `ExpectedResourceSnapshotHash` 传入。MCP 的 `confirmExecution` 仍必须匹配引擎 Key。
|
|
51
|
+
- 下载真实发布包后,断言 `DDLStatements/PhysicalColumns/DiyTables/DiyFields/DataSets/SysMenus/WfFlowDesigns/WfNodes/WfLines/SysApiEngines/ScheduleJobs` 十一项数组全部为零,`SourceFiles/BuildAssets` 为零,`SourceZip/BuildZip` 为空,唯一运行交付为 `SharedPublicRuntime`。源码分发、服务端业务迁移和共享运行入口是独立事实,不能将共享公有编译产物当成目标租户已有业务接口或权限。
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
#发布器 `v2.1.2` 修复受管接口更新后的重复发布摘要漂移:源码、`Managed` 策略和所有权均与已发布包相同时,保留该包的有效基线;真正的源码变更仍推进基线并保留历史兼容摘要。缺失或无效基线从实际旧源码重新建立,`CreateIfMissing` 租户 Hook 保持原策略。`Inspect` 与 `Publish` 必须使用相同的冻结 `PreparedAssets` 和资源选择,并在发布后立即重放原请求,独立核对包 SHA-256、字节数和不可变快照 Id;重放被 CAS 拒绝仍算失败,不能仅以首次成功声称幂等。
|
|
55
|
+
|
|
56
|
+
## 共享表的稀疏字段选集
|
|
57
|
+
|
|
58
|
+
应用只扩展已有共享表的少数字段时,标准导出器和 `ai_app_publish_store` 接收
|
|
59
|
+
`SparseTableSelections: [{ TableId, FieldIds }]`。Id 必须来自当前租户权威元数据,
|
|
60
|
+
最多 32 张表、每表 512 个非重复字段;不接受调用方传表正文、DDL 或布局覆盖。
|
|
61
|
+
同一表不能同时进入完整 `TableIds` 与稀疏选集,安装基础设施表不能被裁剪。
|
|
62
|
+
|
|
63
|
+
导出只保留表 `Id/Name`、所选字段和对应物理列;不携带共享 `Tabs/Column`、
|
|
64
|
+
其它字段、建表或索引。数据只允许 `InsertIfMissing`,行与冲突字段必须在选集中。
|
|
65
|
+
没有数据行的共享表自动生成标准零行 `DataSet`,复用安装前置检查:缺物理表或
|
|
66
|
+
共享表元数据时,在资源写入前失败;不是自动安装依赖,也不是空库建表契约。
|
|
67
|
+
|
|
68
|
+
旧导入器会拒绝受保护共享表的零行 DataSet。须先升级包含
|
|
69
|
+
`EMPTY_SHARED_TABLE_PREREQUISITE_V1` 的商城安装器,再安装混合应用。
|
|
70
|
+
新分支仅接受严格零行形状,不给受保护表业务数据增加写权限。
|
|
71
|
+
普通 DataSet 仍要求完整建表资源,不能借稀疏分支绕过结构闭包。
|
|
72
|
+
|
|
73
|
+
导出器 `v1.3.8` 修复稀疏默认数据的序列化形状:未声明实际父绑定时,
|
|
74
|
+
必须完全省略 `ParentBinding` 键,不能用 `undefined` 让宿主转成 `null`;
|
|
75
|
+
普通配置子表的显式绑定保持原契约,稀疏导入安全门不放宽。
|
|
76
|
+
仅保留稀疏选集中字段在源记录上真实存在的空字符串;NULL、缺失字段、
|
|
77
|
+
未选字段不推断默认值,跨租户与隐藏元数据仍排除,普通全表导出保持旧行为。
|
|
78
|
+
数值 `0` 原本就保留;秘密状态必须经已有可信设置入口规范源数据,
|
|
79
|
+
不能由导出参数或包正文合成。升级后重新 Inspect 并冻结新摘要,旧快照不可改写。
|
|
80
|
+
|
|
81
|
+
安装器 `v3.0.5` 同时执行 `SPARSE_TABLE_IMPORT_PREFLIGHT_V2`:直接传包和下载包均在进度持久化、物理兼容自举及资源写入前核验原始稀疏正文和目标。严格零行依赖不能由同包 `CREATE` 自行满足;带默认数据的稀疏表也必须已有实体表及唯一未删除的表单元数据。MySQL/SQL Server 查询要求 `BASE TABLE`,Oracle 使用 `USER_TABLES`。共享表只接受 `Id/Name`、精确字段与物理列及 `InsertIfMissing` 数据,不接受布局、其它字段、字段退役或该表 DDL;非空数据集可保留标准导出的 `TableDescription`,该描述不授权更新共享表布局。
|
|
82
|
+
|
|
83
|
+
`DECLARATIVE_PACKAGE_DDL_PREFLIGHT_V1` 在同一写前门禁逐字符识别引号和注释,按实际 SQL 目标核对声明表名,只接受受支持的 `CREATE TABLE`、`CREATE INDEX` 与列/索引 `ALTER TABLE`。DML、动态执行、多语句、未知声明、MySQL/MariaDB 可执行注释及提示一律拒绝。字符串内部的分号和普通注释可保留;含反斜杠的引号内容因 SQL mode/方言歧义拒绝,改用 SQL 标准重复引号。现有官方包 DDL 已做字节绑定的解析回归;这不等于所有数据库版本上的实际 SQL 执行验收,未支持的方言模板须先补明确语法和回归,不能降级原样执行。
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
Web 应用可用 `RuntimeAssetsOnly=false + IncludeSource=false` 同时携带
|
|
87
|
+
`SharedPublicRuntime` 和声明式资源,六张标准应用基础设施表仍按权威闭包导出。
|
|
88
|
+
Inspect 和 Publish 使用完全相同的选择、`CommittedProof` 及运行清单,Publish
|
|
89
|
+
再传 `ExpectedResourceSnapshotHash`;旧稀疏选集必须显式刷新,不能退化为整表。
|
|
90
|
+
`RuntimeAssetsOnly=true` 继续拒绝任何资源选集。
|
|
91
|
+
|
|
92
|
+
现有 `microi_run_engine.params` 为通用对象,已能原样透传此选集,仍须
|
|
93
|
+
`confirmExecution`。这不代表线上导出器已升级,也不能以私有源码含 Manifest
|
|
94
|
+
代替正式包资源。接口默认禁用须另按实时能力配置并独立回读;当前
|
|
95
|
+
`microi_generate_system` 的引擎 upsert 不会透传 `IsEnable/StopHttp`。
|
|
96
|
+
|
|
97
|
+
后台规则审批表 `mci_runtime_installation` 的结构可由责任包安装,但审批业务行
|
|
98
|
+
禁止经导出/导入 DataSets 种入、覆盖或恢复;只有严格零行依赖允许通过。
|
|
99
|
+
可信程序集注册与管理员审批是独立动作,不能以商城发布或包安装代替。
|
|
100
|
+
|
|
101
|
+
标准官方控制面现将 `export-package.js` 纳入固定单资源白名单,沿用
|
|
102
|
+
`Resources[{Name,Content,ExpectedRemoteSha256}]`、可信官方授权、同事务行锁及回读。
|
|
103
|
+
先 CAS 升级控制面,再 CAS 发布导出/导入/发布器,最后从完整母版发行归属商城包;
|
|
104
|
+
源码、包正文、不可变快照和公开下载都须独立验证,不能只更新本地镜像。
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
### 物理索引闭包
|
|
108
|
+
|
|
109
|
+
标准导出器必须同时导出责任表的真实唯一索引和普通复合索引,按列顺序生成独立
|
|
110
|
+
`CREATE INDEX` DDL。组合 AI 应用包按“表 + 索引名”区分物理对象;不能只按表名
|
|
111
|
+
合并 DDL,否则建表语句会吞掉全部索引。同名索引定义冲突须失败,不能任选一条。
|
|
112
|
+
|
|
113
|
+
当前标准物理结构导出支持 MySQL/MariaDB 的完整列升序 BTREE 与 Id 主键;前缀、
|
|
114
|
+
表达式、全文、降序或其它源数据库需使用已审计的专用包,标准导出须明确拒绝,不能
|
|
115
|
+
静默发布缺约束包。此边界指源库导出,不等同于目标安装器的数据库支持范围。
|
|
116
|
+
|
|
117
|
+
发布前使用 `microi_get_table_indexes` 对照包内独立 DDL;安装完成后再次核对索引名称、
|
|
118
|
+
唯一性和有序列集合,并测试业务重复键拒绝及重复安装不复制索引。母版存在索引、
|
|
119
|
+
应用页面正常、安装任务成功均不能单独证明目标库的索引完整。
|
|
120
|
+
|
|
121
|
+
### 空库清理与开发期应用
|
|
122
|
+
|
|
123
|
+
安装包应显式登记菜单、表、接口、工作流、任务和微服务的完整归属,供导出、升级和空库制作共同使用。开发期只发布运行资产而尚未制包时,不能假定商城选集已经覆盖新建业务表;应通过现有空库规则接口预览,逐项核对实际物理表、DIY元数据、菜单后代与接口Key。缺失时在责任清理器补充有限、明确的业务归属识别,保留平台核心白名单,读取失败停止制作。只生成SQL与在隔离临时库执行清理是不同动作,禁止在源主库执行脱敏SQL。
|
|
124
|
+
|
|
125
|
+
清理业务应用时同时按StoreId移除其HDFS包索引,再删除商城主记录,保留平台包索引;历史库缺少索引表时兼容跳过。数据库清理不等于删除HDFS对象,禁止借制作空库清除正式已发布文件。
|
|
126
|
+
|
|
127
|
+
空库安装历史须能对应保留平台应用的稳定身份,显式 `StoreId` 优先,缺失时才使用非空的旧应用身份;不能按名称或应用前缀猜测归属。角色清理须同时覆盖业务角色、保留账号的角色绑定、角色权限快照及孤立菜单权限,并验证初始模板角色等级与新租户登录。不能把空库清理策略用于卸载应用或清理正在使用的租户。
|
|
128
|
+
|
|
129
|
+
空库还须清理源租户的业务组织和旧版账号关系,按已校验的初始组织模板重建保留账号部门;平台组织和关系表只清理数据,保留结构。新租户组织树与账号部门必须实际回读和浏览器验收,不能因角色、菜单已清理就推定部门也已清理。
|
|
130
|
+
|
|
131
|
+
旧布局字段的退役使用可选 `DiyFieldRetirements` 数组,声明 `TableName / Name / ExpectedComponent`,按需用 `ExpectedConfig` 限定组件路径。安装器只允许退役当前包声明表中的 `DevComponent / Divider / Tabs / CollapseGroup`;核心字段、仍在包内声明的字段或控件配置不匹配必须拒绝。先安装支持此协议的商城,再安装声明退役的业务包。退役只软删字段元数据并回读、刷新缓存,不删除物理列或业务数据;已经退役或尚未安装的字段重复执行不产生副作用。
|
|
132
|
+
|
|
133
|
+
- Manifest:应用 Key、版本、兼容平台版本、依赖和资源清单。
|
|
134
|
+
- 数据模型:表、字段、菜单、角色权限、接口引擎、事件、数据源、页面、打印、工作流、任务。
|
|
135
|
+
- 源码与构建:私有源码包与可部署构建包分离,记录 SHA-256。源码 ZIP 必须按当前应用
|
|
136
|
+
`PrivateSourcePath` 的已提交活动根选择当前私有行(`VersionId` 为空、`StorageScope=Private`、
|
|
137
|
+
非目录且未删除),禁止把历史版本、未提交源、上传会话或 `upload/v*` 编译文件混入。
|
|
138
|
+
已完成原子同步后的活动根可以仍在 staged 目录,不能只按目录名猜测提交状态。
|
|
139
|
+
安装器必须把包内源码复制到当前租户私有桶中的清单摘要根
|
|
140
|
+
`ai-app-source-staged/{AppId}/store-{SourceManifestHash}`,对象地址精确等于该根加原始
|
|
141
|
+
`FilePath`,保留大小写、中文与空格。时间戳上传地址不能作为活动源码;旧对象必须保留。
|
|
142
|
+
使用既有 `CopyObject/ObjectExist/GetObjectSha256` 校验复制目标的原始字节与长度后再更新
|
|
143
|
+
当前元数据。同版本重装也修正旧路径;复制响应未知先回读目标,目标不同或能力缺失失败
|
|
144
|
+
关闭。复制及当前游标的对象验签计入分片预算,持久前缀只复用同一包摘要根的精确元数据。
|
|
145
|
+
安装器从 `Build/BuildRepair` 或后续应用检查点恢复时,已完成的源码前缀仍按同一
|
|
146
|
+
清单摘要根复用,不能重新消耗源码分片预算并退回 `Source`。未知资产类型、当前及
|
|
147
|
+
后续未校验条目、非规范根或元数据差异仍需验证;升级导入器后恢复原任务及原请求键。
|
|
148
|
+
ZIP 导出前后必须以原始 `FilePath/ContentHash/Size` 的完整当前清单重新核对 `store-` 根
|
|
149
|
+
摘要;分片切换后的部分旧根、清单漂移和摘要根格式错误均拒绝。去掉 `source/` 的归档名
|
|
150
|
+
不能代替安装根摘要的原始路径。
|
|
151
|
+
安装成功后仍须下载并核验原生源码 ZIP,不能削弱其权限、租户、路径或字节校验。
|
|
152
|
+
大型 UTF8 源码应复用既有 `GetPrivateFileText/Sha256Hex/StringToBase64` 字符串边界,
|
|
153
|
+
在原字节摘要一致后才采用,避免 CLR byte[] 逐字节复制到 Jint。二进制或有损解码继续
|
|
154
|
+
保留原字节路径;文本读取失败或异常不能退回另一条存储路径。Base64 长度与最终 ZIP
|
|
155
|
+
实际条目仍严格验证,旧宿主缺少文本/编码能力时才直接沿用原兼容路径。
|
|
156
|
+
缺失基线不回退历史;分页不完整、重复路径(含大小写)、对象后缀与归档路径不一致、
|
|
157
|
+
大小或原始字节 SHA 漂移均停止。使用当前租户可信私有字节与已有 ZIP 原子,优先对同一
|
|
158
|
+
返回归档调用可信 `ExtractZip`(兼容 `ReadZip`),完整核对每条路径、大小、原始字节 SHA、
|
|
159
|
+
文件数与总量;原子存在但失败或不完整时不能回退。仅旧节点缺少解压核验原子时,逐文件
|
|
160
|
+
校验真实字节,原生 CLR SHA 不可用则复用既有编译 ZIP 的 ES5 算法,不得跳过验签。
|
|
161
|
+
前后重读权威账号、应用指针及清单;普通非拥有者、访问密钥会话、撤权、跨租户或存储错误
|
|
162
|
+
不输出文件。节点缺少字节摘要能力时失败关闭。清单摘要沿用序数排序后的
|
|
163
|
+
`Path\tSha256\tSize` UTF-8 SHA-256;原始 ZIP 摘要与资产准备器 Base64 文本摘要分别核验。
|
|
164
|
+
传输超时先回读对象和完整条目,已有正确 Build ZIP 可复用,但错误 Source ZIP 必须保留
|
|
165
|
+
拒绝发布证据;新源码合格后通过既有准备器单独上传 Source,禁止盲目重跑未知写操作。
|
|
166
|
+
- 编译 ZIP 优先按 `ApplicationType` 选择运行类型,历史 `AppType` 只作缺少该字段时的兼容。真实文件仅接受 HTTP 200,调用既有 `RequireSsrfProtection:true` 禁止自动重定向;合法 JSON 与业务错误响应按已冻结的实际字节大小和 SHA-256 区分,不能把任何含 `Code` 的 JSON 一律拒绝。每个新 ZIP 的版本元数据必须包含非空 `RuntimeManifestHash`,等于完整已验文件清单的 `Path\tSha256\tSize` UTF-8 摘要;当前 V3 还须与精确所属应用的权威 `Completed` 版本和微服务清单一致,前后复读提交指针、请求指纹和行版本,漂移失败关闭。旧缺失哈希 ZIP 保留失败证据,不用于新正式包。
|
|
167
|
+
- 完整制包的现代 `.mjs/.cjs/.mts/.cts` 模块与既有脚本按 UTF-8 文本读取,优先调用当前租户私有文本原子且必须 `Code=1`。旧节点缺少原子或读取失败时保留既有审计 URL 回退,票据异常仍停止;不得以性能为由绕审计。二进制不转文本,最终模型逐项验证实际字节、大小与冻结 SHA。超时先查原执行链与失败原因,不并发重入。
|
|
168
|
+
- 独立源码 ZIP 必须在全新目录安装依赖并执行应用声明的全部责任测试,再核对类型与生产构建;仅构建通过不能证明测试闭包。默认测试不得依赖发布者临时树、兄弟应用或平台仓库 marker。历史兼容所需纯模块应从已发布真实源码按原字节随 owned fixtures 交付,记录版本、原路径、大小和完整 SHA;保留原业务断言,不构造替代历史行为。中央多应用契约检查继续由中央 Full 入口执行,不能重新成为独立下载源码的外部依赖。
|
|
169
|
+
- 安装/升级脚本:幂等、可恢复、可回读;不包含租户密钥、Token、连接串或 License keys。
|
|
170
|
+
- 历史微服务的版本目录正确而 root/latest 缺失时,使用后端已安装投影恢复能力,不重发原安装或补写 V3 身份。恢复必须从当前租户主库读取已发布应用、唯一同版本 LegacyUnverified 历史行、启用文件服务与全部公开文件,逐项核对规范路径、大小和 SHA-256;存在安装任务在途或 V3 指针即停止。复用应用发布租约,每次副作用前后验租并复读完整权威投影,先验全部不可变源,再复制并完整回读目标;同版本漂移、失租和歧义不能报告完成。无条件对象复制可能迟到,须持续从已提交元数据和真实对象收敛,不能声称永久原子切换。商城无新增声明资源时仍需说明原安装包与新后端能力的关系,并分别保留后端镜像、源码 ZIP、版本/固定/API 字节、真实页面操作和业务保全的验收证据。沿用状态、应用上下文和原生只读表工具核对原任务和完整清单,缺少线上证据仍属未完成。
|
|
171
|
+
- 迁移采用“先扩展、后迁移、再收缩”,支持新旧节点短暂并存。
|
|
172
|
+
|
|
173
|
+
制包读取全局 v3 运行对象时,租户私有 HDFS 代理继续保持租户目录边界。发布器仅从当前
|
|
174
|
+
`sys_microistore.CommittedPublishVersionId` 精确读取一条所属应用的 Completed 版本,核对
|
|
175
|
+
`VersionNo / RuntimeManifestHash / RequestFingerprint`、微服务清单和每个文件的不可变完整路径、
|
|
176
|
+
大小及 SHA-256,再由当前 `V8.SysConfig.ApiBase` 的可信 origin 与当前租户、应用 Key、文件
|
|
177
|
+
相对路径构造 `/micro-app/v3/tenants/.../kinds/runtime/apps/.../assets/...` 读取地址。不能从较新的
|
|
178
|
+
staged 行、请求参数、`StableFilePathName` 或外部 CDN URL 推断版本和域名。HTTP 使用既有
|
|
179
|
+
严格 SSRF 原子禁用自动重定向,只接受 200;提供的 ETag 必须等于文件 SHA-256。文本可使用
|
|
180
|
+
解压后的 Content,二进制使用 RawBytes,两者仍须分别通过实际字节大小和 SHA-256 校验。
|
|
181
|
+
清单、提交身份、HTTP 或字节不一致时停止制包;旧无 v3 提交字段的微服务保留原校验路径。
|
|
182
|
+
|
|
183
|
+
## 接口引擎资源所有权(强制)
|
|
184
|
+
|
|
185
|
+
- 新发布包必须声明 `ResourcePolicies.ApiEngines`。不可随租户修改的核心使用 `{ Ownership:'Platform'|'Application', UpgradePolicy:'Managed' }`;提供给租户改业务的 Hook 使用 `{ Ownership:'Tenant', UpgradePolicy:'CreateIfMissing' }`。策略以本次选定且通过身份、版本、大小和 SHA-256 校验的包正文为准。
|
|
186
|
+
- 发布器仍从上一版安装包计算 `BaseHash`,导入成功后把本版摘要写入 `sys_microistoreversion.InstallResult.ResourceState.ApiEngines`,但 `Base/Local/Incoming` 只用于审计。所有官方、社区和普通应用的 `Managed` 接口均按 Incoming 覆盖;本地源码较新、同版本不同源码、历史所有权不同或安装记录缺失都不得形成安装冲突。
|
|
187
|
+
- 当前包声明为 `CreateIfMissing` 时,只在目标 Key 完全不存在时创建;存在时不得对齐 Id、源码、启用状态或其它字段,软删除也算存在。若未来包明确把同一 Key 声明为 `Managed`,则以当前包策略执行覆盖,不再因历史所有权阻断;发布方应在更新日志中明确这一行为变化。
|
|
188
|
+
- 官方功能仍优先采用“Managed 核心 + CreateIfMissing Hook”。核心提供稳定协议和默认行为并随包覆盖;客户日志、写表、通知和业务动作放 Hook,并以稳定 `EventId`、唯一约束或 outbox 幂等。这样覆盖式升级核心时无需自动合并客户可执行代码。
|
|
189
|
+
- 每个官方包内的接口引擎源码顶部都必须有醒目所有权提示。Managed 提示必须写明所属官方应用、从可信官方源安装/更新/重新安装会恢复官方代码,并指向该应用的 CreateIfMissing Hook;CreateIfMissing 提示必须写明首次创建后归租户维护、官方升级不得覆盖。官方 SSO、登录、通知等核心在安全阶段调用 Hook 时,只传脱敏上下文,禁止传 Token、Secret、密码或原始协议断言。
|
|
190
|
+
- 兼容旧 Controller/移动端地址时,在唯一 Managed 接口的 `ApiRoutes` 中用英文分号声明全部旧路径。主地址被其它接口占用时,安装器清除旧占用者的该地址并让当前包收回;稳定 Id 被其它 Key 占用时为当前包资源生成新 Id。每次都要清理旧缓存别名并强回读 `ApiAddress + ApiRoutes + ApiV8Code + Version`。
|
|
191
|
+
- 历史包未声明策略时按旧 `LegacyOverwrite` 覆盖兼容;重新发布时发布器必须生成策略。验收至少覆盖首次安装、官方/社区/普通 Managed 本地差异覆盖、同版本重装、软删除恢复、Id/地址自动重映射、Hook 被改后保持原样、两节点竞态,以及官方发布数据库连 `ValidateOnly` 也禁止执行安装器。
|
|
192
|
+
|
|
193
|
+
## 工作流定义与目标审批绑定
|
|
194
|
+
|
|
195
|
+
- 安装器 `v2.9.9` 对声明 `Installation.ConfigurationPolicy='PreserveTenantValues'` 的包,
|
|
196
|
+
在共享事务内先读取目标流程配置。相同业务表、节点 Id/用途和连线结构的更新保留 `IsEnable`
|
|
197
|
+
以及节点的 `Users/Roles/Depts`;V8、按钮规则等受管定义继续按当前包更新,不保留租户代码差异。
|
|
198
|
+
- 业务表、节点用途或连线结构变化时,保留仍兼容的节点绑定并停用流程,记录需要重新配置的诊断;
|
|
199
|
+
有真实 `Todo` 待办时拒绝改图,不能自动完成、撤回审批或删除历史。管理员须检查包含历史多余
|
|
200
|
+
节点/连线的完整图形后再启用。未声明该策略的历史包保持原覆盖语义。
|
|
201
|
+
- 节点稳定 Id 跨流程占用、配置读取失败、写入失败或字段/V8回读不一致均失败关闭。
|
|
202
|
+
发布包只交付停用模板,目标用户、岗位、部门及业务配置不能从官方测试环境复制。
|
|
203
|
+
- 空绑定或停用模板仍须真实结构声明。预制包发布前逐项核对流程、节点和连线的全部属性
|
|
204
|
+
与目标支持的物理列及类型;新增列必须由同包声明交付,未知属性即拒绝。`0`、空字符串
|
|
205
|
+
或 `[]` 不能证明未知字段可落库,不得凭相近名称发明控制项或补默认值绕过严格回读。
|
|
206
|
+
- 导出器在原生导出及 `PreparedPersistPackageByteBase64` 持久发布中,从可信当前租户
|
|
207
|
+
数据库读取 `wf_flowdesign/wf_node/wf_line` 的真实物理列,按大小写不敏感的字段名检查
|
|
208
|
+
全部资源属性;包自报 `PhysicalColumns` 不授予字段合法性。实际数据库已有的定制列保持
|
|
209
|
+
合法;新增列先由正规结构交付并回读,再制包。未知字段、大小写重复、列读取失败或数据库
|
|
210
|
+
类型缺失/不支持均在 HDFS 上传、日志、发布 CAS 与指针更新前失败关闭。MySQL/MariaDB、
|
|
211
|
+
SQL Server 当前解析表和 Oracle 当前用户表使用各自目录,无工作流的老包不要求该目录。
|
|
212
|
+
- 生成安装模板时,只从当前母版定义提取业务正文,从历史映射提取稳定资源 Id;构建前逐节点
|
|
213
|
+
核对完整 V8 正文与条件代码。私有源码同步、普通 Manifest 生成或管理员测试通过,不能证明
|
|
214
|
+
实际安装包中的内联正文已更新。发布前核对正式包,升级后再以目标普通岗位核对原业务请求。
|
|
215
|
+
- 验收必须包含已绑定审批人的真实租户升级与同版本重装,核对启用状态、目标绑定、受管代码
|
|
216
|
+
更新、在途待办保护及业务配置未变;空模板安装成功不能替代该验收。
|
|
217
|
+
- 安装器 `v3.0.0` 起,流程、节点、连线的新增、更新与配置/结果回读均显式传入同一个
|
|
218
|
+
`V8.DbTrans`,由外层接口决定提交或回滚。不能把共享事务内的读取与独立提交的写入混用:
|
|
219
|
+
可重复读快照可能看不到刚写入的数据,并导致失败后残留部分流程。遇到“工作流写入后回读不存在”
|
|
220
|
+
先升级应用商城安装器,再按原已校验包和任务状态恢复;保留失败审计,不删业务数据或审批历史。
|
|
221
|
+
回归须模拟事务快照,覆盖首次安装、更新后可见性及节点/连线失败时整个流程回滚。
|
|
222
|
+
|
|
223
|
+
## 安装流程
|
|
224
|
+
|
|
225
|
+
1. 校验签名/哈希、包版本、平台兼容性、依赖和磁盘/配额。
|
|
226
|
+
2. 创建全局唯一 `InstallationId` 和稳定幂等键。
|
|
227
|
+
3. 使用后台任务执行,阶段性持久化进度与 checkpoint。
|
|
228
|
+
4. 按 Manifest 创建缺失资源;已有 `Managed` 资源覆盖为包声明值,`CreateIfMissing`/`InsertIfMissing` 既有值保持原样。
|
|
229
|
+
5. `PostSchema` 完成后,在独立 `ScheduleJobs` checkpoint 中幂等安装定时任务并回读 Quartz 运行元数据。
|
|
230
|
+
6. 写入成功后刷新共享缓存版本。
|
|
231
|
+
7. 回读表、字段、引擎、菜单、权限、页面、定时任务等关键资源。
|
|
232
|
+
8. 做 HTTP、UI 和权限冒烟;全部成功后才标记安装版本。
|
|
233
|
+
|
|
234
|
+
安装中断后从 checkpoint 幂等恢复;不能依赖当前 API 节点内存。
|
|
235
|
+
|
|
236
|
+
后台任务中心的 `POST /api/BackgroundTask/List` 只返回有界分页的状态、进度、时间和 `HasLog/HasResult` 摘要;日志、结果、参数、可信用户快照与 checkpoint 必须按任务所有权在详情接口按需读取,不能为列表轮询重复返回大字段。
|
|
237
|
+
|
|
238
|
+
## 权限与租户
|
|
239
|
+
|
|
240
|
+
- 商城定义、安装、升级、卸载和应用源码只允许 `Level >= 9999`。
|
|
241
|
+
- “吾码官方平台”不能只按 `OsClient`、域名或前端变量判断:服务端必须同时校验官方 `OsClient`,并确认当前节点固定只读挂载 `/app/microi_private.pem` 的公钥部分与内嵌官方 License 信任根匹配;本地源码开发可从私有子仓库兼容查找。任意自建私钥不能建立官方身份。官方平台前端隐藏安装、更新、重新安装、离线安装和批量安装入口,后端仍必须拒绝这些写操作。
|
|
242
|
+
- 官方平台是应用发布源,连安装器的 `ValidateOnly` 也必须拒绝,避免通过“只验证”绕过发布源隔离。发布源只做包正文、版本和资产 Hash 回读;真实安装、更新及预检必须切换到非官方目标租户或本地非发布源环境。
|
|
243
|
+
- 所有资源按目标 `OsClient` 写入;包内不能携带源租户 `OsClient`、数据库、Redis、对象存储、MQ/MQTT、AI 或第三方密钥。
|
|
244
|
+
- 按钮调用后台安装接口时,前端只传应用/版本/安装 Id;目标租户和管理员身份由 Token 确定。
|
|
245
|
+
- 每次安装、更新、重新安装生成稳定 `OperationId`。官方计数服务用共享数据库事件表唯一约束去重,并在同一事务内登记事件和递增 `InstallCount`;重试、跨节点和响应丢失不得重复计数。
|
|
246
|
+
- 安装次数回传属于非阻塞幂等遥测,不是应用导入事务的成功条件。来源节点返回旧格式 `True`、空响应、非 JSON、业务失败或请求异常时,只能写入带 `OperationId`/`InstallationKey` 的 warning 诊断,不得用 `_error_` 标记或回滚已经成功导入的应用;重试仍须复用同一幂等键。
|
|
247
|
+
- “全部安装/更新”固定只处理 `ApplicationType=Platform` 的官方平台应用中未安装与存在新版本的项目,不得把 UniApp、Web、MicroService 或其它社区/AI 应用整库安装;已是最新版的应用不重新安装。批量计划、子项状态、checkpoint 和进度必须持久化到共享数据库/后台任务,支持多节点抢占、失败重试和重启恢复,不能依赖进程内集合或浏览器状态。
|
|
248
|
+
- 主租户批量维护全部子租户时,前端入口和接口引擎都必须校验主租户上下文及 `Level >= 9999`,再由可信控制面为每个启用子租户创建独立持久后台任务;父任务必须按子任务真实百分比聚合进度,等全部子任务终态后才成功或失败,并在通知中心保留每个租户、阶段和原始失败原因。所有子任务可立即创建,但固定商城工作器必须通过配置租户 Redis 的集群并发租约跨租户串行执行,避免共享物理库并发 DDL/元数据写入死锁;分片幂等任务使用足以覆盖短时死锁和滚动重启的有界重试预算,禁止无限重试。`MaxAttempts` 表示连续失败预算:任一分片成功写入 checkpoint 后必须把 `AttemptCount` 与陈旧 `LastError` 清零,不能让数百个成功分片之间偶发的网络错误按任务生命周期累计并误终结。分片重新入队后必须按 `COALESCE(NextRunTime, CreateTime)` 选取最早就绪任务,禁止只按 `CreateTime` 让最早长任务重复抢占全部分片。商城包属于只读权威数据,可对空响应做有界退避重试,并优先用完整响应的 `Content`、`RawBytes`、HTTP 状态和传输错误诊断;不得把该规则扩展到安装写入请求。目标租户固定商城工作器必须锁定并校验精确包快照;同版本重装、显式选择历史版本或目标端存在更新源码时,仍以所选包的 `Managed` 资源覆盖,不得用版本/源码差异制造冲突。历史空库缺少生成实体所需物理列时,导入器须在首次 FormEngine 调用前幂等补齐并回读,不能再把真实表结构错误包装成 `Value cannot be null (source)`。
|
|
249
|
+
- 批量维护的权威目录按当前节点 `OsClientType + OsClientNetwork` 隔离;同一主租户同时存在 Internal、Internet 或其它活动分区时,必须在每个分区对应的主租户节点独立发起并验收,不能用一个分区的成功任务推断全平台成功。每个分区先回读精确预期租户数与名单,等待父子任务全部终态且 `SucceededCount=ExpectedCount、FailedCount=0`,再用新幂等键立即执行一次无操作复跑并确认零安装/零更新。禁止修改 `sys_osclients` 的网络字段来把租户临时塞进另一分区,也禁止让两个分区同时维护可能指向同一物理库的重复租户记录。
|
|
250
|
+
- 启动自动恢复的范围严格限制为正常启动、普通登录、菜单导航和商城安装/更新。完整官方应用源码、包、生成器和同步器位于 `Microi.Server/OfficialApplications/Resource/`;`build-bootstrap-package.mjs` 按显式清单生成 `Microi.Upgrade/Resource/app.microi.bootstrap.json` 与 `import-package.js`,升级程序集只嵌入这两项。SSO、AI、通知、备份、OCR、翻译等可选应用只由用户在商城手动安装更新,不能作为启动就绪或版本推进条件。必要共享物理列与安装元数据可恢复,但不导入业务种子、可选菜单、任务或租户配置值。
|
|
251
|
+
- 启动恢复使用共享租约、持久版本门、幂等和强回读;只有登录接口、商城菜单/服务/页面绑定及真实内联资产就绪后才前向推进版本。满足必要路由和安全标志的更高版本 Managed 接口及完整商城资产保留,不能降级用户的手动更新;这项规则仅适用于启动恢复,用户显式选择商城历史版本仍以所选包为准。生成资源变动后必须重新生成并用 `--check` 和完整门禁验证,不能在 Full 后悄悄改包。
|
|
252
|
+
- 完整 SaaS、系统账号、系统设置等官方包继续按其独立归属发布;商城页面之外的平台设置和个人中心由对应包交付。`Source=NotIncluded + Build=DatabaseOnly + StorageMode=db` 的小型恢复资产接受 256 文件/5MB 和逐文件哈希门禁。客户明确要求手动更新时,官方发布不得扩张为客户自动安装或服务器部署。
|
|
253
|
+
- 批量任务已经以“一个应用”为外层持久化恢复单元。规模可控的小型官方包应在一个事务中完成,避免对同一包体按 8 个字段反复下载、解析和重新排队;超过字段、表、DDL、流程、随包数据或资产安全阈值的大包继续使用内部 checkpoint 分片。热更新发现旧版批量计划不含 `ApplicationType` 时,必须丢弃旧计划并重新盘点,不能继续安装历史计划中的社区应用。
|
|
254
|
+
- MySQL 宽表触发 65,535 字节行内上限时,只允许把不参与索引的 `varchar` 配置列无损提升为 `mediumtext`,并把类型覆盖持久化到后台任务 checkpoint;索引列和非行宽错误必须失败关闭。发布包对长连接串、密钥、回调地址、域名/白名单等字段应直接使用 `mediumtext`,同时更新 `DiyFields` 与建表 DDL,不能长期依赖安装时猜测。
|
|
255
|
+
- 历史表连新增 TEXT 行内指针都无法容纳时,仅修改新增字段不够。导入器需支持本次长列行外化后,对本包明确拥有的表内、包声明的既有可空且无默认值/生成属性的长 VARCHAR 有界扩宽。先查询目标 `INFORMATION_SCHEMA.STATISTICS` 保护全部真实索引列(含复合索引非首列),再按长度降序最多调整八次;保留内容、字符集、排序规则、可空性和注释,逐条 DDL 强回读。引用表、未声明列、非文本声明、索引读取失败和其它 DDL 错误禁止自动扩宽;全量验证声明后才修改包对象,不得部分修改或缩窄 LONGTEXT。
|
|
256
|
+
- 行宽修复回归必须先复现旧表中 VARCHAR 与 TEXT 新增都失败,再证明新导入器保留短列类型、长列行外存储、旧数据和列属性不变、检查点恢复以及立即重装零 DDL。MySQL DDL 不随事务回滚,回读不一致必须失败且不得推进安装版本;后续安装依据真实物理容量与检查点覆盖保持兼容。真实租户先更新商城导入器,再验收全部平台应用成功和立即零安装/零更新重跑。
|
|
257
|
+
- 卸载是破坏性操作,必须明确列出将删除/保留的资源、二次确认并优先软删除/归档业务数据。
|
|
258
|
+
|
|
259
|
+
## 联邦商城源、公开范围与历史版本(强制)
|
|
260
|
+
|
|
261
|
+
- 每个主租户和子租户都可以发布自己的应用;应用行用 `IsPublic` 表达公开范围,缺省/历史空值按公开兼容。公开应用允许未登录来源读取和安装,私有应用只允许来源登录成功后的授权身份读取,列表、详情、版本接口都必须重复执行这一权限判断。
|
|
262
|
+
- 组合包的 `ApplicationBundles[].Application` 必须由发布器从源应用实际记录携带 `IsPublic/IsApprove`,不接受请求参数替代。安装器只接受 `0/1`、`"0"/"1"` 和布尔值,显式源标记优先;未审批的源不能因 Build 成功变成已审批。历史包无公开标记时,已有目标保持原值(含历史空值),首次新增运行应用显式 `IsPublic=0`,不能继承目标 Switch 默认1。无效声明在直接包入口任何 I/O 前失败;下载包在读取正文后、该包资源/文件写入前失败,旧库既有物理前置兼容检查不因此重排。父商品 AppId/公开范围、目标拥有者和源码下载独立鉴权不得随运行标记改变;验收必须覆盖新私有、已有私有/公开、显式公开、旧包新建/重装、非法类型零包写入和即时撤权。
|
|
263
|
+
- 新版安装包正文不得长期内联在 `sys_microistore.AppPakcet`,也不得随 `mic_data_version.Data` 重复复制。公开应用写入 HDFS 公有桶并记录 `HdfsPublic`,私有应用写入私有桶并记录 `HdfsPrivate`;数据库只保存 `PackageId/PackageHdfsPath/PackageSha256/PackageSize/PackageContentType/PackageFormatVersion/PackageUploadedAt`。`IsPublic` 历史空值按公开兼容,但所有新建应用必须显式落为 `1/0`。
|
|
264
|
+
- 发布顺序必须是“UTF-8 JSON 上传 → HDFS 回读 → 字节数和 SHA-256 一致 → 写入不可变包索引及商城指针 → 以原值 CAS 清空 `AppPakcet`”。普通发布不得仅凭 Redis 命中跳过 HDFS 回读;只有受控历史压缩可复用内容寻址缓存,安装端仍必须独立下载并校验。公开包可通过 FileServer/CDN 公有地址读取;私有包只能由来源后端在当前授权身份下签发短期下载地址,Token、签名 URL 和包正文不得进入浏览器配置、日志或后台任务参数。
|
|
265
|
+
- `mic_data_version` 历史快照保留不可变 `StoreVersionId` 和同一组包指针,因此旧版本仍可精确安装,不再要求 `Data` 内含完整 JSON。导入器先校验快照版本/应用身份,再按指针下载并在解析前核对大小与哈希;指针缺失时才回退旧版内联字段,禁止快照不匹配时退回当前版本。
|
|
266
|
+
- 旧库容量治理使用 `compact-microi-store-packages` 超级管理员持久后台任务:先幂等补齐物理列,再用有界 `Id` 游标逐批处理;每个包都先上传回读,随后 CAS 清理当前行或历史快照。禁止对数 GB `mic_data_version.Data` 执行全表 `LIKE`/包正文计数。逻辑大字段清空后,MySQL 表空间文件是否立即缩小取决于存储引擎;`OPTIMIZE TABLE` 只能在备份完成的维护窗口由管理员另行执行,不能由应用安装或压缩任务自动触发。
|
|
267
|
+
- 商城来源以 `ApiBase + OsClient` 唯一定位。添加来源先只读发现系统标题、验证码策略和公开应用数;需要私有应用时再登录。帐号、密码、Token 不能写浏览器配置或商城来源 JSON;密码只用于本次登录,长会话 Token 以 `MCP/Mobile` 非 PC 客户端签发,并由当前租户后端加密保存到 `mci_system_setting`,浏览器只持有不具备取密能力的凭据 Key。
|
|
268
|
+
- 后端来源代理必须固定已保存的 `ApiBase + OsClient`,拒绝过期 Token、访问密钥会话、非超级管理员、非 HTTPS 外网地址、重定向漂移和超限响应;Token 不得返回浏览器、日志、审计或应用包。退出登录同步删除服务端密文。
|
|
269
|
+
- 商城源业务由 `app.microi.store` 单一拥有的 `platform-marketplace-source`(`Managed`)编排,租户扩展只写 `platform-marketplace-source-hook`(`CreateIfMissing`,默认可执行正文精确为 `return { Code : 1 };`)。登录必须在远端配置读取、密码发送和凭据保存之前执行 `BeforeMarketplaceSourceLogin`;断开必须在删除服务端凭据之前执行 `BeforeMarketplaceSourceDisconnect`。Hook 失败直接阻断操作。Before Hook 仅允许 `Stage / SourceApiEngineKey / Action / SourceId`,不得传 `ApiBase`、远端 `OsClient`、账号、密码、Token、签名地址或凭据密文;协议、加密和密钥隔离继续由可信网关负责。
|
|
270
|
+
- 商城主页面统一承载应用市场、已安装、我发布的应用、安装离线包和来源管理,不能再通过独立菜单或路由割裂上下文。来源增删改启停逐项自动保存;来源管理、详情和复杂配置使用平台统一 `80%` 可拖动大圆角 Dialog,遮罩服从正向开关 `sys_config.FormMaskBlur`,缺失或 `0/false` 默认关闭毛玻璃。
|
|
271
|
+
- 每张应用卡必须显示预览图、公开范围、分类、最新版本、当前租户已安装版本及状态色。来源卡必须显示其公开数和当前授权可访问总数;平台官方发布节点只显示“平台官方应用源”身份标记,不显示安装、更新或重新安装操作。
|
|
272
|
+
- 安装可明确选择 `sys_microistore` 当前版本或 `mic_data_version` 中仍含完整包正文或已验证包指针的历史快照;后台任务在首次取包时必须把计划中的 `AppVersion` 解析为匹配且可安装的不可变 `StoreVersionId`,写入 checkpoint,并在全部后续分片一直传到详情取包。发布方中途升版时继续完成已锁定快照,新版留给下一轮盘点;快照缺失、版本不匹配、身份变化或快照 Id 漂移必须失败关闭,禁止退回易变当前行。实际安装版本写回 `sys_microistoreversion`。回退旧版属于重新安装,不得静默换成最新版。
|
|
273
|
+
- 应用详情的版本选择必须服务端分页和搜索,默认每页不超过 20 条;当前版本固定置顶,历史版本只返回含完整旧包或有效 HDFS 指针的可安装状态。禁止用 `_PageSize:500` 或一次加载全部版本后在浏览器过滤。翻页、搜索与页大小切换都必须保持已选版本语义并显示总数。
|
|
274
|
+
- 商城详情、来源管理等 Teleport 弹层必须使用宿主级固定遮罩,毛玻璃覆盖完整可视区域;标题栏拖动按弹层真实尺寸限制四边,窗口缩放后重新限制,不能依赖固定像素最大位移或允许内容越出视口。
|
|
275
|
+
- “我发布的应用”只读取当前登录用户拥有的记录,可以包含草稿和构建失败项;普通商城列表只读取已发布项。两者必须在服务端按 Owner 和发布状态过滤,不能依赖浏览器过滤后再分页。
|
|
276
|
+
|
|
277
|
+
## 发布版本与资源选择
|
|
278
|
+
|
|
279
|
+
### 每个应用版本必须有更新日志(强制)
|
|
280
|
+
|
|
281
|
+
- 本规则覆盖 `Platform / Regular / Web / UniApp / MicroService` 以及所有 AI 应用。任何创建、修改、升级、重新构建或重新发布,只要产生新的应用版本,就必须先在 `sys_microistore_changelog` 写入一条更新日志;不允许先发布后补写,也不允许因为只改了元数据、V8、路由、提示文案或内置运行产物而省略。
|
|
282
|
+
- 更新日志通过 `StoreId` 关联 `sys_microistore.Id`,`Version` 必须是规范化后的精确 `AppVersion`,且同一应用同一版本只能有一条。`Title`、`ChangeType`、`Content`、`ReleaseTime` 都是必填项;`Content` 要写清用户可感知的新增、优化、修复、兼容或安全影响,禁止只写“优化体验”“修复问题”等无法审计的空泛文字。
|
|
283
|
+
- 正确顺序固定为:确定目标版本 → 保存商城应用 → 写入或审阅该精确版本日志 → 同步源码与构建 → 制包/发布 → 回读商城行、安装包和日志。发布器发现日志缺失、软删除、版本不一致或任一必填项为空时必须失败关闭。
|
|
284
|
+
- `microi_publish_application_directory_stream`、V3 发布或其它支持变更摘要的工具必须显式传 `changeSummary`,且其含义与更新日志一致;`mci_ai_app_version.ChangeSummary`、`AppPakcet.PackageInfo.ChangeLog` 和商城子表不得互相矛盾。
|
|
285
|
+
- 应用商城包升级必须同时交付子表、真实 `StoreId` 外键字段、唯一约束/索引、隐藏子菜单、主表 `TableChild` 字段、详情时间线和发布门禁。历史商城源没有该能力时前端应明确显示“当前来源暂未提供更新日志”,不得伪造空日志为“暂无更新”。
|
|
286
|
+
- 验收至少回读“商城当前版本 + 对应日志 + 包内版本/ChangeLog”,再在真实商城详情弹层检查版本、类型、标题、时间和正文;重复执行相同版本写入应命中唯一记录而不产生重复行。
|
|
287
|
+
|
|
288
|
+
- 发布器必须把用户请求的精确版本传给资产准备器,并断言 `RequestedVersion == Prepared.PackageVersion == AppPakcet.PackageInfo.Version`;版本不存在就失败,禁止静默改用最新版本。
|
|
289
|
+
- `SelectMenu`、`SelectTable`、`SelectApiEngine` 必须从当前发布包的显式选择持久化;不能读取商城行上一次保存的选择来决定本次包内容。
|
|
290
|
+
- 发布完成后同时回读商城版本行、包正文和构建资产,逐项核对版本、数量与 SHA-256;任一处漂移即发布失败。
|
|
291
|
+
- 官方内置前端应用只能有一个发布源码根。默认租户工作副本与受审计的独立 Git 源码仓库不能同时成为事实源;若使用独立仓库,必须提交一个发布契约并让构建、跨工程测试、所有程序集内置包共同读取它,正式发布还要证明源码根来自无未提交修改的 Git 提交。前端主包只提供通用宿主、诊断和恢复入口,不复制完整业务源码。HDFS/CDN 运行镜像必须回读到同一 `RuntimeManifestHash` 后才可启用,不能用较新的镜像静默覆盖较旧数据库包,也不能用较新的数据库包静默覆盖未验签镜像。
|
|
292
|
+
- `ScheduleJobs` 是一等包资源,必须在 `PostSchema` 之后独立安装、持久化 checkpoint 并回读运行状态;任务失败时不得写入成功版本。
|
|
293
|
+
|
|
294
|
+
## MCP 工作流
|
|
295
|
+
|
|
296
|
+
1. 安装/更新现成商城应用时,先调用 `microi_install_store_application` / `microi_update_store_application` 且不传 `confirmExecution`,核对目标租户、商城源、StoreId 和幂等请求 Id 的预检结果。恢复被商城升版打断的旧任务时,额外传入已回读且仍含完整包正文的 `storeVersionId`;不同快照必须使用新的 `requestId`。
|
|
297
|
+
2. 用户明确确认后,把 `confirmExecution` 精确设为 `StoreId`,提交真实持久化后台任务;只传 StoreId、可选不可变 StoreVersionId、版本和商城源定位信息,不通过 MCP/HTTP 传完整 `AppPakcet`。
|
|
298
|
+
3. 自建应用或低代码系统先用 `microi_list_applications` / `microi_get_application_context` 盘点源码,再用 `microi_get_manifest_schema`、`microi_plan_system` 与 `microi_generate_system(dryRun:true)` 干跑。
|
|
299
|
+
4. 安装任务必须回读至 `Succeeded`,再执行 `microi_validate_system`、远端资源回读和真实 UI 验收;仅返回 TaskId 不代表安装成功。
|
|
300
|
+
|
|
301
|
+
已有 MicroService 优先新增页面/路由;没有时才创建、同步源码、发布构建。复杂安装交互使用 `V8.OpenAppDialog`,后台任务上报进度。
|
|
302
|
+
|
|
303
|
+
## VS Code 本地应用与发布边界
|
|
304
|
+
|
|
305
|
+
- `AI应用` 本地树按每个一级目录的 `.microi-micro-app.json` 发现项目;只要 `osClient/apiBaseUrl` 与当前连接一致,就必须显示 `Web / UniApp / MicroService`,不得用 `runtime === "micro-app"` 过滤掉其它应用类型。无效清单应记录诊断,不能静默吞掉整个目录。
|
|
306
|
+
- “安装到当前租户”和“发布到应用商城(不安装)”是两个独立动作。商城发布只能同步 `sys_microistore`、应用源码/构建/版本元数据及安装包,不得新增或修改当前租户的 `sys_microiservice / sys_microiservice_page`;操作前后必须回读运行态确认未变化。
|
|
307
|
+
- 应用项目行必须直接显示商城发布入口,不能只藏在右键菜单;同时保留构建安装和源码同步状态入口。
|
|
308
|
+
|
|
309
|
+
## 版本与回滚
|
|
310
|
+
|
|
311
|
+
- 版本号单调递增,保存变更清单和前后哈希。
|
|
312
|
+
- 官方 Web、UniApp、MicroService 体验路径统一为公有桶对象键 `/{OsClient小写}/micro-app/{AppKey}/index.html`,通过 `https://static.itdos.com` 访问;`/{OsClient小写}/micro-app/{AppKey}/{Version}/index.html` 及同目录资源是不可变历史版本。私有桶按同样相对目录保存最新版与各历史版本的源码;编译包没有源码时明确记为 `NotIncluded`。v3 的 `microi/application-assets/v3/...` 仍可作为内部校验源,但 `/micro-app/v3/tenants/...` API resolver 和旧 `ai-app-publish` 不再作为官方商城体验链接。
|
|
313
|
+
- 发布顺序为完整上传并验证版本目录、复制私有源码快照、提升固定根的非入口资源、最后提升固定 `index.html`。CDN 对所有被覆写的固定路径做精确刷新并回读任务 `Complete`,再从 `static.itdos.com` 回读入口及引用资源,最后更新 `sys_microistore.PreviewUrl/PublicPublishPath`;任一步失败保留旧商城入口并进入可恢复状态。跨版本重发不得覆写历史目录的不同内容。官网列表、详情、二维码和“立即体验”只能展示固定根的 CDN URL,不带版本、请求指纹或缓存绕过参数。
|
|
314
|
+
- v3 数据库中的 `PreviewUrl/PublicPublishPath` 可以保存以 `/` 开头的对象路径,完成态检查依赖此相对值;官网接口和商城工作台使用租户 `FileServer` 生成完整 CDN 体验 URL。展示层修复不得直接改写 v3 记录为绝对 URL。
|
|
315
|
+
- 官方 CDN 凭据按当前租户系统设置 `Integration.Cdn.Aliyun.*`、`Integration.Dns.Aliyun.*`、历史 SaaS `AlidnsKeyId/AlidnsKeySecret` 顺序读取;半配置失败关闭,不静默跳过刷新。阿里云可能把并发 URL 合并为同一任务号,需等待该任务返回的全部 URL 完成并按原始字节哈希回读。批量迁移应按每日刷新配额限速或分日执行。
|
|
316
|
+
- 旧版对象若已丢失,只能从商城编译包、仍可访问的当前体验路由或本地归档取得逐文件匹配冻结清单的原始字节后补齐;哈希或长度不符时拒绝写入。历史版本无法恢复时保留原版本记录和链接并列出待补清单,可独立迁移已完整校验的当前版本,但不得把未恢复的历史目录标为已归档。
|
|
317
|
+
- stage 前回读并冻结应用的 `CurrentVersion + AppVersion`;finalize 必须同时传 `ExpectedCurrentVersion + ExpectedAppVersion`,在以不可变 AppId 加锁后再次 compare-and-set。缺失前置条件、AppId/AppKey 漂移或旧请求晚到一律失败关闭;重新发布必须重新盘点,不能静默回退。
|
|
318
|
+
- 新清单发布成功时,同应用 `dist/` 下不再出现的 active 文件元数据只能条件式改为可逆归档 scope,条件必须包含 AppId、路径、旧 scope 与版本;禁止删除 HDFS/数据库记录,也不得触碰 Private、非 `dist/` 或另一应用的行。
|
|
319
|
+
- 官网、二维码和用户分享只使用无版本号根入口,不追加 `v/apiBase/OsClient`。目标租户的 `ApiBase/OsClient` 在发布或安装时写入入口 HTML 的 `window.__MICROI_APP_CONTEXT__ / MICROI_API_BASE / MICROI_OS_CLIENT`;安装包不得沿用发布端运行上下文。
|
|
320
|
+
- 数据迁移通常只向前;回滚应用版本不能假设自动回滚业务数据。
|
|
321
|
+
- 更新失败保留原版本可运行资源,记录失败阶段;不要清空客户 V8 后再尝试恢复。
|
|
322
|
+
- 私有源码仓库、`Microi.net/License/keys` 和部署密钥不进入公开应用包。
|
|
323
|
+
|
|
324
|
+
## 验收清单
|
|
325
|
+
|
|
326
|
+
- [ ] 同一包重复安装无重复表/字段/菜单/任务
|
|
327
|
+
- [ ] 客户自定义 V8 与非包拥有配置保持不变
|
|
328
|
+
- [ ] 源码包、构建包、Manifest 和数据库版本一致且哈希可核
|
|
329
|
+
- [ ] 无版本号根入口与当前商城版本一致,历史版本 URL 仍可独立访问
|
|
330
|
+
- [ ] 安装到不同 ApiBase/OsClient 后,入口 HTML 使用目标租户上下文且分享 URL 无运行参数
|
|
331
|
+
- [ ] Web/UniApp 安装后的 `PreviewUrl` 使用目标租户 `FileServer + 真实对象 Key`,不含 OSS/S3 内网域名或临时签名;即使发布包漏选菜单,也会幂等生成可直接在线使用的 Iframe 入口,已有入口则重绑到目标租户地址
|
|
332
|
+
- [ ] 只更新菜单/说明/声明式资源且复用旧运行时的版本,`sys_microistore.AppVersion` 跟随安装包版本,运行版本表保留真实构建版本;商城安装状态不能因两种版本合同合法分离而显示异常
|
|
333
|
+
- [ ] 中断/重启后可恢复,两个节点不会重复副作用
|
|
334
|
+
- [ ] 普通角色不能安装、升级、卸载或读取私有源码
|
|
335
|
+
- [ ] 缓存刷新后远端 API 与真实 UI 通过
|
|
336
|
+
- [ ] 卸载范围明确、可审计、可恢复或已提示不可恢复
|
|
337
|
+
|
|
338
|
+
## 复盘:商城按钮已到达但依赖接口引擎缺失
|
|
339
|
+
|
|
340
|
+
- 触发场景:子租户更新应用商城后能够看到“全部安装/更新”,点击却提示 `sys_apiengine` 中不存在按钮调用的接口;继续临时补引擎后,还可能因目标租户缺少批量计划表再次失败。
|
|
341
|
+
- 根因:商城元数据版本、`AppPakcet.PackageInfo.Version` 与真实包正文发生分叉,页面按钮被单独更新;同时应用导入器把接口引擎新增/更新失败只写进 Debug 后继续返回成功,没有做写后回读,批量引擎又依赖未随同一应用包交付的表。
|
|
342
|
+
- 通用规则:按钮及其调用的接口引擎、表和权限必须属于同一个单调版本应用包;任何依赖写入失败或回读内容不一致都要让安装事务失败。可复用的批量状态优先写入平台后台任务 `CheckpointJson`,避免仅为批量编排增加未交付的租户表。商城行版本、包内版本和包内容哈希必须同时回读一致,禁止单独提升商城行版本或只更新菜单。
|
|
343
|
+
- 自动化检查:应用包契约测试必须从按钮代码提取接口 Key,断言包内存在启用且配置正确的引擎并与独立源码逐字一致;导入器测试覆盖新增失败、更新失败、缓存清理后回读缺失和源码不一致均返回 `Code=0`;真实子租户更新后回读 `sys_menu + sys_apiengine + 后台任务`,再实际执行一次“无需更新”和至少一个安装/更新计划。
|
|
344
|
+
|
|
345
|
+
## 复盘:新版前端先启动、基础包却遗漏登录菜单依赖
|
|
346
|
+
|
|
347
|
+
- 触发场景:租户先升级新版前后端,登录后路由初始化固定调用 `/apiengine/platform-sys-menu`;目标库此前没有该接口。应用商城包只补了 `platform-background-task`,而菜单接口仍由安装顺序靠后的 SaaS 包顺带携带;启动完整性检查也只验证后台任务接口,于是数据库版本和商城版本都显示最新,但用户在进入应用商城之前已经因 `NoExistData sys_apiengine` 全站不可用。
|
|
348
|
+
- 根因:把单个已修复依赖误当成完整的启动依赖集合,包资源闭包、`NeedRefresh` 完成判定和安装后强回读没有使用同一清单;发布验收只覆盖已有目标租户,未覆盖“新版二进制 + 历史库恰好缺少某一启动接口”的升级排列。
|
|
349
|
+
- 通用规则:凡是登录、菜单构建、恢复入口或应用商城打开之前必调的表、接口引擎和微服务路由,都属于启动依赖闭包。每项资源必须只有一个官方 Platform/Application 包作为唯一所有者。API 进程接收流量前的门禁不得维护“登录页七接口”之类手写清单;必须从九个随服务端自动安装的内置官方基础应用包读取全部 `SysApiEngines`。同 Key `Managed` 记录原位覆盖包内源码、版本、主路由、多路由和开关,软删除必须恢复;包内 Id 被其它 Key 占用时生成新 Id,包内主地址被其它接口占用时收回地址。`Tenant/CreateIfMissing` 仅在数据库中完全不存在时创建,既有大小写变体、禁用记录或墓碑都归租户维护,不得恢复或覆盖。
|
|
350
|
+
- 竞态与验收:前端可对明确的“启动 Managed 资源尚未落库”做不超过一分钟的有界退避,并在耗尽后显示精确包名和最低版本;它不能吞掉鉴权错误、普通网络错误,也不能代替服务端修复。跨大量历史租户的 `StartupDependencyBootstrapOnly` 是独立事故工具,可从应用商城与 SaaS 两个不可变包覆盖式恢复七项最小可登录 Managed 接口并做物理强回读;它不是 API 进程的完整运行时就绪定义,成功后仍须执行普通完整应用覆盖更新。契约测试须枚举九个包的全部接口资源,覆盖 Managed 本地漂移/软删除、Id/地址自动重映射、CreateIfMissing 墓碑保护、登录后实际路由、商城批量安装和已健康零操作。
|
|
351
|
+
|
|
352
|
+
### 2026-08-26:登录成功后仍成片 `sys_apiengine NoExistData` 与 Upgrade25 历史文件阻断
|
|
353
|
+
|
|
354
|
+
- 触发:新版前后端部署到历史租户后,登录页依赖已被补齐,但 `platform-service-health`、`platform-sys-dept`、`mci-module-presentation-stats`、`platform-runtime-custom-hook`、商城批量工作器等登录后接口继续缺失;与此同时 `mci_ai_app_file.VersionId` 的历史空值使 Upgrade25 在创建唯一索引前失败,后续后台升级链无法收敛。
|
|
355
|
+
- 根因:把“能登录”误当成“平台运行时已就绪”,启动门禁和事故工作器长期依赖固定七项清单;历史应用文件在 V3 引入版本外键前已经存在,升级只做审计并直接失败,没有安全、确定且可重放的归档策略。旧商城工作器还可能访问已经改名的 `/apiengine/get-microi-store` 地址。
|
|
356
|
+
- 通用修复:API 进程启动门禁以上述九包全部接口为事实源,Managed 资源无论缺失、漂移、软删除或同版本都从程序集内置官方包覆盖恢复,CreateIfMissing 只补完全不存在的记录;应用商城保留独立 Managed 旧地址接口并转发到 `get-microi-store` Key 的正式 `/apiengine/get-microi-store-list` 实现。Upgrade25 必须先按 `OsClient + AppId + legacy-unversioned-v3` 生成确定性历史版本 Id,把每个应用的空 `VersionId` 文件原样归档并强回读为零,再计算路径 Hash 和创建唯一索引;文件同时缺少 `AppId`、确定性 Id 被占用或同名版本身份不一致时失败关闭,不猜测、不合并、不删除。
|
|
357
|
+
- 验收:应用包测试必须证明九包接口 Key/稳定 Id 全局唯一、每项政策与醒目提示完整、旧商城地址和正式地址均存在;升级测试覆盖 MySQL/SQL Server/Oracle 的历史分组、参数化更新和样本诊断 SQL。真实启动日志必须分别显示物理字段、完整平台运行时闭包、Upgrade25 历史归档计数和每个升级步骤终态;登录后逐一调用当前用户、健康、部门、私有文件、菜单角标与商城批量计划,不能只验证匿名系统设置。
|
|
358
|
+
|
|
359
|
+
## 复盘:应用包切换 HDFS 后旧导入器无法更新自己
|
|
360
|
+
|
|
361
|
+
- 触发场景:商城行与不可变版本快照已经只保存 HDFS 路径、大小和 SHA-256;历史租户仍运行只读取 `AppPakcet` 的导入器。用户尝试先更新“应用商城”以获得新版导入器时,旧导入器从商城源取得空 `AppPakcet`,在 3% 直接报“Package不能为空”,形成更新器无法更新自己的引导死锁。
|
|
362
|
+
- 通用协议:新版导入器请求商城模型时必须显式声明 `PackagePointerMode=HdfsV1`,自行下载一次并校验 UTF-8 字节数与 SHA-256。商城模型面对未声明该能力的旧调用端,允许从同一个受信 HDFS 指针读取并严格校验正文,只在本次响应的 `AppPakcet` 中临时回填;绝对禁止写回 `sys_microistore`、`mic_data_version`、任务参数或检查点。私有包仍必须使用短期授权地址,大小上限、HTTP 状态和摘要任一异常都失败关闭。
|
|
363
|
+
- 发布顺序与验收:先把兼容桥更新到官方商城源的 `get-microi-store-model`,再发布包含新版模型接口、导入器和启动依赖的精确应用商城版本。自动化同时覆盖新版请求零回填、旧请求可安装、摘要/大小不符拒绝、数据库无包正文字段更新;真实历史租户必须保留旧导入器启动第一次正式更新,等待终态成功并回读新版导入器,然后立即同版本覆盖式复跑,确认资源仍精确等于包正文且不产生重复记录。直接通过 MCP 替换目标导入器只能作为已故障租户的最后恢复手段,不能代替协议兼容性验收。
|
|
364
|
+
|
|
365
|
+
## 复盘:可信后台任务被 StopHttp 提前拦截
|
|
366
|
+
|
|
367
|
+
- 触发场景:`V8.ApiEngine.RunBackground` 已成功创建任务,但 Worker 执行 `StopHttp=1` 的批量引擎时立即失败并提示“此接口已禁止http调用”。
|
|
368
|
+
- 根因:Worker 为保留按钮调用、权限和审计语义继续使用 `_InvokeType=Client`,旧版 ApiEngine 只按该字段判断 `StopHttp`,没有识别服务端恢复的持久化任务来源。
|
|
369
|
+
- 通用规则:核心 ApiEngine 仅在“服务端可信用户作用域 + `_TrustedServerInvocation=true` + 非空任务 Id + 匹配任务信封 + 正数 fencing token”全部成立时豁免 `StopHttp`;少一项都按普通 HTTP 拒绝。不得把所有后台调用粗暴改成 `Server`,也不得只凭客户端可伪造的任务 Id 或信封放行。
|
|
370
|
+
- 旧节点兼容:应用资源尚需覆盖未部署核心修复的服务,可暂将批量引擎设为 `StopHttp=0`,但 V8 首行安全门必须执行同样的全条件校验;HTTP 控制器必须剥离 `_TrustedServerInvocation`。契约测试同时断言严格 `AND` 校验、独立源码与包内副本一致、普通调用失败关闭。
|
|
371
|
+
|
|
372
|
+
## 复盘:后台任务基础包的自举与索引幂等
|
|
373
|
+
|
|
374
|
+
- `app.microi.background-task` 自身负责创建/修复后台任务表,首次安装和离线安装必须以前台接口完成;不能先调用 `RunBackground`,否则旧库缺少 `OsClient` 等字段时会在导入开始前失败。
|
|
375
|
+
- 后台任务可用性不能只检查表存在,还要检查运行时必需列;部分升级的旧表必须返回“能力尚未就绪”,不能继续拼接包含缺失列的 SQL。
|
|
376
|
+
- 应用包中的独立 `CREATE INDEX` 必须按表名和索引名做执行前回读;并发创建失败后再次回读,已存在则按幂等成功处理。索引 DDL 不能重复触发整张表的字段同步。
|
|
377
|
+
- 基础包必须同时携带 `OsClient` 的 `PhysicalColumns` 定义、建表内联索引与 4 条独立索引 DDL;新表靠建表一次成型,旧表靠物理列同步和独立 DDL 修复。安装前先把“应用商城”更新到包含 `BACKGROUND_TASK_BOOTSTRAP_READINESS_V1`、`APPLICATION_ASSET_BACKGROUND_CHUNKS_V1` 的 v1.8.0+ 导入器;安装成功前必须回读全部运行字段及索引,验收覆盖首次安装、部分旧表修复、重复安装和两节点竞态。
|
|
378
|
+
- 其它用户更新吾码 VS Code 插件并执行“初始化 AI 配置/拉取 Skills”后,AI 应自动识别本规范:大任务优先提交真实后台任务;若基础能力未就绪,先指导用户更新应用商城并以前台方式安装 `app.microi.background-task`,不得伪造进度或让基础包自举入队。
|
|
379
|
+
- 重复安装先比较应用包拥有的字段定义,完全一致就跳过 `UptFormData`。Jint 的 `LimitMemory` 统计累计托管分配而非当前存活堆;大量无效字段更新即使被 GC 回收也会耗尽预算。v1.8.0 导入器每个后台片最多实际上传 8 个文件,并以约 32 MB Base64 为分片目标;为避免单个大文件无限空转,每片至少允许处理一个文件。片末返回 `HasMore + Checkpoint`,下一片按 `AppId + FilePath + Hash` 复用已提交资产,并禁止为统计再次解码整文件 Base64。
|
|
380
|
+
- 只有固定 Key `import-microi-store-package`、服务端可信身份、`Level >= 9999`、当前进程主租户、持久化后台 TaskId 五项同时成立时,后端才使用 `ResidentMemoryGuardOnly`,跳过会永久累计已回收分配的 Jint 内存约束。该特例仍受容器优先的进程 RSS 防线保护:95% 停止接收新工作,98% 有界停机并由持久任务恢复。普通/前台/子租户/其它 V8 不得借用此特例。
|
|
381
|
+
|
|
382
|
+
## 复盘:官网升级资源同步的三道门
|
|
383
|
+
|
|
384
|
+
- 重型发布门禁之前先运行 `node Microi.Server/OfficialApplications/Resource/refresh-resources.mjs --validate-only`:该入口只校验本地全部候选,不联网、不发布、不推进共同基线,且不能与写入参数组合。正式发布仍须通过完整测试、三方同步、精确哈希回读,不能把本地预检当成发布成功。
|
|
385
|
+
- 控制面版本使用语义版本最低门槛,并同时严格核对鉴权、行锁、资源哈希、写后回读等能力;禁止把某个旧版本字符串写成唯一合法值。可选功能一旦由包内表或任意入口声明,就必须校验其完整接口闭包及资源策略;不能自动放行未知 Key,也不能只升级版本而缺失实际保护。预检自身必须进入 Node 自动回归,覆盖新版通过、旧版及缺保护失败、半套可选功能失败。
|
|
386
|
+
- 官网当前资源只是三方合并的一侧,允许暂时落后于本地发布候选。下载阶段只校验固定白名单、稳定资源身份、JSON 可解析性及服务端返回 SHA-256;不能用“必须已包含本地最新功能标记”的规则提前拒绝旧官网,否则会形成“官网不够新所以永远无法发布新版”的循环依赖。
|
|
387
|
+
- 本地输入和三方合并后的最终候选必须继续执行最低版本、功能标记、内嵌逻辑副本一致性等严格校验;发布成功并按内容哈希回读一致后才能推进 `.resource-sync-base`,不能把放宽读取门误做成放宽发布门。
|
|
388
|
+
- 应用包版本与平台发布版本分别单调递增。包正文需要写回而本地包版本、平台版本均未高于官网时,应基于官网包版本自动递增补丁号;内容无变化时不得递增,必须用连续两次同步验证第二次为零变更。
|
|
389
|
+
- MCP 配置中的官方 API、`OsClient` 与 Token 文件是鉴权事实源,但编辑器可执行文件、插件版本目录和 `cwd` 都是易漂移的启动信息。发布器应保留鉴权配置、固定校验 `https://api.itdos.com + itdos`,并支持插件生成的稳定 `microi-cli-mcp.js` 或标准 `mcp-server.js` 入口;旧扩展配置再从同级最新已安装插件或当前工作区发现可信入口,统一使用正在运行发布脚本的 Node 启动。插件升级、Codex 插件化或旧目录清理不能再次阻塞后端发布。
|
|
390
|
+
- Token 文件的新键固定为 `ApiBase|OsClient|OsClientType|OsClientNetwork` 四段身份;Type/Network 为空时仍保留空段。读取和回写必须先用四段精确键,再兼容旧版紧凑键;旧键在多环境配置下可能被有意保留且已经失效,禁止优先读取。自动化测试要覆盖“精确键已刷新、旧键仍过期”以及 type-only/network-only 不碰撞。
|
|
391
|
+
- VS Code 的 SecretStorage 恢复 broker 必须使用确定性激活事件启动;不得只依赖大型工作区可能超时的递归 `workspaceContains`。签名密钥变化时旧 Token 本身不能以旧换新,必须由已激活 broker 使用本机 SecretStorage 静默重登并回写精确身份键。
|
|
392
|
+
- 本地资源同步的官网读取、发布和发布后回读应使用同一个已校验的 `microi_itdos` MCP 链路;CI 无 MCP 时才允许凭显式 Token 使用 HTTP。V8 独立文件与应用包内嵌副本合并时,先把文件头说明和 `Version` 与可执行正文分离:两端独立升版不能算代码冲突,不同正文安全合成后应基于两端最高版本再升一版;只有同一段可执行逻辑出现不同实现才失败关闭。
|
|
393
|
+
- 新增平台共享物理列时,除一次性版本门升级外,还要同步所有会快照该共享表的官方包 `PhysicalColumns`,让新安装和旧租户升级两条路径一致。`.resource-sync-base` 是上次官网回读的共同基线,不能与本地候选一起手工修改;基线可疑时先从官网只读修复,再执行三方合并、自动升包版本、正式发布和 SHA 回读。
|
|
394
|
+
- 发布验收至少包含:定向合并测试、真实 `PublishBatch`、六项资源逐项 SHA-256 回读,以及立即执行第二次幂等重跑。任何一步失败都不得宣称官网已同步,也不得推进共同基线。
|
|
395
|
+
|
|
396
|
+
## 复盘:官网模板库误报平台应用可更新
|
|
397
|
+
|
|
398
|
+
- 触发场景:官网 `sys_microistore` 的平台应用版本持续发布,但 `sys_microistoreversion` 仍保留旧安装版本;官网自身会显示“可更新”,从官网数据库复制出来的新租户也继承同一误报,尽管这些平台能力实际已经随官网主库维护完成。
|
|
399
|
+
- 身份边界:只能在服务端同时满足 `OsClient=iTdos` 且当前节点私钥公钥部分与内嵌官方 License 公钥完全一致时执行。只使用同名租户、域名、配置开关或任意自建私钥都不得触发;客户租户的安装版本仍是其独立事实源。
|
|
400
|
+
- 对齐规则:每次后端启动都在现有租户升级分布式租约内盘点 `ApplicationType=Platform + IsApprove=1` 的商城行,只处理 `Installed/Success/Succeeded/已安装` 的既有安装记录,按 `StoreId -> AppId -> 唯一 AppName` 匹配。只条件更新 `AppVersion/AppVersionInstall/PackageVersion`;稳定键仅在目标键未被其它安装记录占用时补齐。不得新增“已安装”记录、覆盖失败/异常状态、修改安装时间或删除重复历史行。
|
|
401
|
+
- 分布式与验收:更新是确定值条件写入,节点中途退出后下次启动继续,第二次执行必须零更新;验收同时回读版本表三个字段,并执行官网商城列表接口,确认 `Outdated=0`、`Abnormal=0`。真实未安装应用仍应保留 `Uninstalled`,不能为了清空通知伪造成已安装。
|
|
402
|
+
|
|
403
|
+
## 复盘:共同基线已有引擎但官网内嵌副本缺失
|
|
404
|
+
|
|
405
|
+
- 触发场景:本地 `app.microi.store.json`、独立接口脚本和 `.resource-sync-base` 都已有新引擎,但官网商城包尚未收录或被单侧删除;同步器在三方合并前强制读取官网内嵌代码,直接报“缺少接口引擎”,导致新版永远无法通过一键发布补到官网。
|
|
406
|
+
- 根因:旧状态机只区分“共同基线不存在的首次新增”和“三端都存在的正常合并”,漏掉“共同基线已登记、官网副本缺失”的历史基线漂移;严格 getter 在合并前抛错,使已有的首次发布与逻辑副本修复规则没有机会运行。
|
|
407
|
+
- 通用规则:只要副本映射仍属于当前发布契约,本地独立源码和内嵌副本能从共同基线安全合并,官网单独缺少内嵌引擎应视为不完整副本。JSON 合并前只从共同基线恢复该引擎的结构骨架;有官网独立文件时继续把它作为官网代码侧,无独立文件时把共同基线代码视为官网未修改,再执行正文三方合并并将结果写回内嵌副本。写回后必须按 `SysApiEngines.length` 重算 `PackageInfo.ApiEngineCount`。若共同基线引擎 Id 已被其它 Key 占用,或任意两侧同一代码位置实现冲突,仍必须失败关闭;不得通过覆盖/重建整个共同基线来掩盖问题。
|
|
408
|
+
- 自动化检查:同时覆盖共同基线不存在的首次新增、共同基线存在但官网缺失且本地升级、官网内嵌缺失但官网独立源码升级、共同基线 Id 被其它 Key 占用四种状态;断言声明引擎数等于实际数组长度;再用真实 `microi_itdos` 只读资源重放,确认候选含目标引擎且独立源码与内嵌代码相同,正式发布后执行 SHA 回读和零变更幂等重跑。
|
|
409
|
+
|
|
410
|
+
## 复盘:旧包非空约束阻止租户升级与启动
|
|
411
|
+
|
|
412
|
+
- 触发场景:商城应用包把既有字段从可空升级为 `NOT NULL DEFAULT ...`,老租户的物理列已经存在,但历史记录仍为 `NULL`;导入器直接执行 `ALTER TABLE ... MODIFY COLUMN ... NOT NULL` 时,MySQL 报 `Invalid use of NULL value`,整个安装分片失败。
|
|
413
|
+
- 根因:物理列同步只比较类型、可空性、默认值和注释,没有在收紧可空性前迁移存量数据。列默认值只影响后续写入,不会自动修复既有 `NULL`。
|
|
414
|
+
- 通用规则:除所有主键(不限于 `Id`,包括复合主键的每一列)及自增/identity 列外,平台普通物理列一律允许 `NULL`。导入器必须将历史 `PhysicalColumns.IS_NULLABLE=NO` 归一为允许为空,不收紧已有列,不为迁就非空约束而回填零/空串/租户值;业务必填由表单与后端事件校验。默认值独立保留。启动前必需的核心表必须在共享租约内完成可空兼容,再插入运行时接口;不能等商城运行后才修复商城自身的启动前置结构。
|
|
415
|
+
- 自动化检查:构造 `V8Limit NOT NULL` 无默认值的旧表、含 `NULL` 的历史记录及带默认值/注释/排序规则/索引的列;同时覆盖普通列已允许 NULL 但被 DROP DEFAULT 的情况,使用 `SELECT DEFAULT(列) FROM 表 LIMIT 0` 识别元数据无法区分的缺失默认标志。断言 Id 仍为主键、旧数据和列属性保留,随后省略可选字段的 INSERT 成功;同版本重启和二次安装不重复 DDL 或回填业务值。
|
|
416
|
+
|
|
417
|
+
- 历史数据库的可选菜单关联字段可能仍为整数类型。引用该表的应用包只能按实际物理类型把空字符串归一为 `NULL`,不能将无关联猜成 `0`,也不能越过表所有权修改既有类型;非空值及文本列保持原样。验收同时覆盖旧整数列、新文本列、重复安装和无效非空值继续报错。
|
|
418
|
+
|
|
419
|
+
## 复盘:应用新增菜单未自动授予系统管理员完整权限
|
|
420
|
+
|
|
421
|
+
- 触发场景:应用首次安装或版本更新新增了 `sys_menu`,菜单数据已经存在,但系统管理员看不到入口或只能执行部分按钮;再次人工到角色管理中勾选后才恢复。
|
|
422
|
+
- 根因:安装器只导入菜单,没有在同一事务内写入 `sys_rolelimit`;历史补丁又把单个管理员角色 Id 和五项旧权限硬编码,只能修复某个菜单,遗漏 `Read`、自定义按钮及其它 `Level >= 9999` 管理员角色。
|
|
423
|
+
- 通用规则:安装器只对本次真正新增或从删除状态重新引入的菜单自动授权,不扩大既有菜单的客户权限策略。目标角色必须从当前租户实时读取全部有效 `sys_role.Level >= 9999` 记录;基础权限固定为 `Read/Add/Edit/Del/Export/Import`,并合并菜单 `MoreBtns/ExportMoreBtns/BatchSelectMoreBtns/PageBtns/PageTabs/FormBtns` 中每个按钮的 `Id + Name`,不得加入 `NoDetail/NoSearch` 这类限制权限。
|
|
424
|
+
- 旧账号等级兼容仅限已校验官方平台包:没有上述角色时,可检查固定旧内置角色 `5db47859-35a3-411a-a1f7-99482e057d24` 的 `998/9998` 级记录。仅当至少一个活动账号的数据库 `Level >= 9999` 且该角色所有未删除持有者均为系统管理员时,才为该角色补充本次新增菜单权限;保持角色等级和用户绑定,禁止推广到普通自定义角色。角色引用同时识别字符串数组和 `[{Id:...}]`,不相信引用对象中的缓存 Level。
|
|
425
|
+
- 幂等与失败边界:已有 `sys_rolelimit` 只能合并、不得删除历史自定义权限;新增行使用“租户 + 角色 + 菜单”的确定性 Id,并在并发主键冲突后重新回读合并。找不到系统管理员、查询失败或任一权限写入失败必须让整个安装事务回滚,不能出现“菜单成功但管理员无权”的半成品。通过 FormEngine 写入以触发共享授权缓存失效。
|
|
426
|
+
- 自动化检查:覆盖多个系统管理员、已有部分权限、自定义按钮既有 JSON 字符串也有数组、删除菜单恢复、重复安装零新增、两个节点同时插入后合并,以及既有菜单更新不自动扩权;发布门同时校验独立导入器与商城包内嵌副本都包含该能力。
|
|
427
|
+
|
|
428
|
+
## 复盘:商城发布升版打断所有后台分片安装
|
|
429
|
+
|
|
430
|
+
- 触发场景:主租户为大量子租户执行“安装/更新全部平台应用”时,某个平台包从 v7.5.17 发布到 v7.5.18;正在执行的任务在下一分片报“检查点版本与当前版本发生变化”,大量子租户同时失败。
|
|
431
|
+
- 根因:版本保护正确阻止两个包混装,但批量计划只持久化 `StoreId + AppVersion`,每个分片仍从 `sys_microistore` 易变当前行重新取包,没有使用已经存在的 `mic_data_version` 完整快照,也没有把 `StoreVersionId` 写进 checkpoint。
|
|
432
|
+
- 通用规则:后台安装首次取包必须按计划 `AppVersion` 锁定匹配的完整历史快照,并在每个分片复用同一 `StoreVersionId`;应用商城自身必须排在平台批量计划首位,先自举最新版导入器。发布中途升版不能改变既有任务的包体,也不能让既有任务自动追新;下一次批量盘点再安装新版本。
|
|
433
|
+
- 自动化检查:构造计划版本 v1.0.0、商城当前版本在分片间升到 v1.0.1,断言首次选择 v1.0.0 快照 Id,恢复分片仍请求同一 Id且成功;覆盖快照尚未生成、显式 Id 与期望版本不符、身份不符均失败关闭,并断言批量计划第一项为 `app.microi.store`。
|
|
434
|
+
|
|
435
|
+
## 复盘:父任务 Monitor 重复自举误判同版本工作器
|
|
436
|
+
|
|
437
|
+
- 触发场景:全部子租户安装任务已经创建并持续执行,父任务在 Monitor 分片中再次调用租户发现/工作器自举;子租户刚从应用包写入的商城工作器与主租户版本相同,仅 BOM 或 CRLF/LF 不同,却被判为“同版本源码不同、疑似租户定制”,父任务失败,而子任务仍在后台运行。
|
|
438
|
+
- 根因:父编排器在解析 checkpoint 阶段前无条件读取租户目录,导致 Monitor 也重复执行只应发生在 Queue 的有副作用自举;服务端源码比较又直接使用 Ordinal 原文比较,没有先消除跨平台文本格式差异。
|
|
439
|
+
- 通用规则:租户发现与商城工作器自举只允许在 Queue 阶段执行;Monitor 必须只汇总 checkpoint 中已经持久化的 `ChildTasks`。同版本源码比较只可规范化 UTF-8 BOM、CRLF/LF 和文件末尾空白;任何其它字符差异仍按租户定制失败关闭,禁止用去注释、压缩空白或模糊标记绕过保护。
|
|
440
|
+
- 自动化检查:覆盖同版本 LF/CRLF/BOM 等价且不刷新、同版本真实代码差异继续拒绝、旧版官方谱系允许升级、新版目标保留;接口引擎资源断言 Monitor 检查点标记存在且 `GetChildTenantPlatformAppMaintenanceTargets` 只位于 Queue 分支。
|
|
441
|
+
|
|
442
|
+
## 复盘:资源数量小但工作量重的应用被合并为单事务
|
|
443
|
+
|
|
444
|
+
- 触发场景:子租户批量安装进度停在“系统设置”或“系统帐号”十多分钟,心跳和 CPU 仍活跃但没有新检查点;重启后同一现象只会转移到下一个租户。
|
|
445
|
+
- 根因:批量工作器请求 `BulkAdaptiveSingleSlice`,导入器仅按表、字段、菜单和数据行数量判断“小包”,没有计入 DDL、实体生成、权限回填和历史数据迁移的真实成本,因而关闭了内部后台分片。
|
|
446
|
+
- 通用规则:后台商城安装必须始终保留有界分片和持久化检查点;旧工作器仍传单片参数时,新导入器必须安全忽略。已排队的跨租户任务在真正运行目标 V8 前,应按进程缓存执行一次官方安装器自愈,使平台修复能从原检查点接管。
|
|
447
|
+
- 自动化检查:断言批量工作器显式关闭单片参数、导入器不存在 `backgroundChunkingEnabled=false` 路径、旧单片参数只记录忽略诊断;后台执行器在子租户工作器运行前调用受信自举,并继续保留同版本真实源码差异的失败关闭保护。
|
|
448
|
+
|
|
449
|
+
## 复盘:旧租户前置物理列逐列重建耗尽首片超时
|
|
450
|
+
|
|
451
|
+
- 触发场景:已启用后台分片后,旧租户首次更新“系统设置”仍长时间没有 `ChildCheckpoint`;心跳与 CPU 正常,接近单片超时后才推进。实时 Schema 回读显示 `sys_apiengine` 与 `diy_table` 同时缺少多项生成实体固定列。
|
|
452
|
+
- 根因:导入器为兼容历史空库,在第一次 FormEngine 调用前逐列执行 `ALTER TABLE ADD`。MySQL 每个语句都可能重新准备或重建同一张元数据表,多个固定列的累计耗时发生在首个可持久化检查点之前。
|
|
453
|
+
- 通用规则:MySQL 同一张表缺少多个受信固定前置列时,必须先完整盘点,再用单条 `ALTER TABLE ... ADD ..., ADD ...` 原子补齐并回读;可信后台任务每个分片最多修改一张前置元数据表,提交 `Prerequisites` 检查点后再继续下一张。没有缺列的现代租户直接进入原 DDL 阶段,不制造空分片。并发节点已完整补齐时按幂等成功,否则保留真实表名、未补齐列和数据库错误并失败关闭。SQL Server 与 Oracle 使用各自已验证语法,不得直接套用 MySQL 批量语句。
|
|
454
|
+
- 自动化检查:独立导入器和商城包内嵌副本都必须携带批量前置列及检查点标记;断言 MySQL 路径先收集 `pendingDefinitions`、每表只拼接一次批量 ALTER、后台每片写表上限为一,且失败后逐项回读所有待补列。真实旧租户验收需证明前置列分片已提交、随后不可变 `StoreVersionId` 与字段阶段检查点继续推进。
|
|
455
|
+
|
|
456
|
+
## 复盘:父级监控遇到数据库死锁被误判为业务失败
|
|
457
|
+
|
|
458
|
+
- 触发场景:父级 Monitor 已持久化全部子任务 Id,子任务仍在正常执行且 checkpoint 中没有业务失败;父任务汇总进度时偶发数据库死锁,却因调用方配置 `MaxAttempts=1` 立即进入 `Failed`,通知中心因此把仍可成功收敛的整批任务标红。
|
|
459
|
+
- 根因:后台任务把数据库死锁、锁等待超时等基础设施瞬态竞争与接口返回失败共用同一业务重试预算。低业务重试次数无法覆盖工作器自身的领取、心跳、检查点或结果持久化竞争,也没有保留父子任务的真实运行语义。
|
|
460
|
+
- 通用规则:后台任务存储层只对已知数据库死锁、锁等待超时、序列化竞争等稳定特征启用独立的有界基础设施重试;即使业务 `MaxAttempts=1`,也允许最多三次基础设施执行机会。重试必须保留原 TaskId、父子关系、checkpoint 和已产生的副作用,不得重新创建子任务;成功后清除瞬态错误,第三次仍竞争才按原业务规则终止。普通业务错误、数据冲突和 `Value cannot be null` 等非竞争错误不得借用该预算。
|
|
461
|
+
- 自动化检查:覆盖嵌套 ProviderException 与外层包装异常、MySQL/SQL Server/PostgreSQL/Oracle 的稳定错误码或消息;断言第一次和第二次竞争回到可领取状态且不消耗业务 AttemptCount,第三次进入原终态,非竞争异常仍按 `MaxAttempts` 立即失败。真实验收必须在每个活跃运行分区等待该分区全部子任务收敛,再以 `MaxAttempts=1` 连续执行一轮完整汇总和一轮立即无操作重跑;两轮父任务都必须得到 `SucceededCount=ExpectedCount、FailedCount=0`,且无操作轮为零安装/零更新。
|
|
462
|
+
|
|
463
|
+
## 复盘:字段分片完成后后台安装卡在缓存失效广播
|
|
464
|
+
|
|
465
|
+
- 触发场景:字段分片的数据库写入和 Schema 回读已经精确完成,但 `ChildCheckpoint` 长时间停在同一字段索引;任务取消也无法及时结束,进程内存、线程数和 CPU 持续增长。
|
|
466
|
+
- 根因证据:两次托管转储的调用链都停在 `V8.ApiEngine.Run -> GetApiEngineModelInternal -> MicroiTwoLevelCache.SetAsync -> PublishInvalidateAsync -> PublishWithRetryAsync`。权威 Redis 写入已经成功,随后用于通知其它节点清理一级缓存的 Pub/Sub 广播没有完成时限,因而把业务调用永久挂住;与此同时,单字段元数据更新即使只变更 Label、Remark、布局或 V8,也会重复执行物理列 DDL,放大旧租户升级成本。
|
|
467
|
+
- 通用规则:Redis 权威值写入成功后,跨节点一级缓存失效广播只能是有界、尽力而为的附属动作。队列等待和实际发布都必须有独立短超时,超时后观察迟到异常并开启短暂熔断冷却,防止悬挂发布任务无界堆积;不得因此回滚已经成功的权威写入。`UptDiyField` 只有列名或物理类型变化时才允许调用 `ChangeColumn`,显示名称、说明、布局和事件代码等纯元数据变化禁止触发 DDL。
|
|
468
|
+
- 自动化与真实验收:缓存测试必须覆盖发布永久不返回时的有界退出、迟到异常观察和冷却期抑制;字段测试必须断言只有 Name/Type 变化才进入物理 DDL。应用商城资源契约测试、后台任务与 SaaS 回归测试通过后,还必须在每个活跃运行分区完成 `ExpectedCount/ExpectedCount` 子租户收敛,并立即执行一轮相同数量的无操作重跑。验收期间若官方应用发布了新版本,应以新的不可变 `StoreVersionId` 启动独立追赶批次,禁止混入已经开始的旧版本分片。
|
|
469
|
+
|
|
470
|
+
## 复盘:最新版后端仍放行未锁快照的旧商城工作器
|
|
471
|
+
|
|
472
|
+
- 触发场景:目标租户已经部署最新版前后端,但数据库中的 `import-microi-store-package v2.2.9` 与 `bulk-import-microi-store-packages v1.2.4` 被启动完整性检查判为合格;平台应用批量任务开始后,官方商城恰好升版,首个应用在下一分片仍从易变当前行取包并失败。
|
|
473
|
+
- 根因:后端自举门槛只校验早期版本和历史标记,没有把不可变快照、禁止自适应单片、前置物理列分片检查点及商城自举优先级纳入能力契约;MCP 单应用恢复工具也只能传 `StoreId`,无法显式锁定已经回读的 `mic_data_version` 快照。
|
|
474
|
+
- 通用规则:后端启动必须同时校验导入器最低版本与固定快照/有界分片/前置列检查点标记、批量工作器最低版本与 `StoreVersionId + BulkAdaptiveSingleSlice:false`、商城列表的自举优先级;任一缺失都必须从受信升级资源刷新,不能仅看后端二进制版本。MCP 安装/更新允许传受校验的可选 `storeVersionId`,审计同样记录该 Id;不同快照使用不同幂等请求 Id,禁止把旧任务静默改指新包。
|
|
475
|
+
- 自动化与真实验收:单元测试同时拒绝旧版本和缺标记的伪新版工作器;在真实旧租户先用固定快照完成应用商城自举,再执行全部平台应用更新并立即做零更新复跑。验收期间出现的新官方版本只进入下一独立批次,历史失败任务保留作审计,不删除或篡改。
|
|
476
|
+
|
|
477
|
+
## 复盘:本租户自助批量被误判为主租户跨租户任务
|
|
478
|
+
|
|
479
|
+
- 触发场景:普通租户在自己的应用商城点击“全部安装/更新”,后台执行器仅按固定批量工作器 Key 触发跨租户自愈,把 `owner=当前租户、target=当前租户` 当成主→子任务;旧导入器只能从自己复制自己,随后被新能力门禁拒绝,并错误提示“先更新主租户应用商城”。
|
|
480
|
+
- 根因:跨租户自愈没有校验由服务端控制面持久化的目标租户保留标记,也没有要求任务拥有者与执行租户不同;把同租户自助批量和主租户代子租户执行混成了同一作用域。
|
|
481
|
+
- 通用规则:运行前强制自愈只允许用于固定批量工作器、非空服务端目标标记、`owner != execution` 且标记精确等于执行租户的主→子任务。普通租户自助批量必须跳过跨租户复制,让持久计划按官方列表顺序优先安装/更新应用商城自身,再由新版导入器继续后续应用;不能要求官方发布源安装自己。
|
|
482
|
+
- 自动化与真实验收:单元测试覆盖同租户无标记、同租户伪标记、跨租户正确标记、标记漂移和错误工作器 Key;真实旧租户先保留旧导入器发起自助批量,断言不再出现“子租户商城工作器执行前自愈失败”,计划第一项为应用商城,全部任务成功后立即执行零更新复跑。
|
|
483
|
+
|
|
484
|
+
## 复盘:平台包跨旧租户安装时同时暴露结构闭包、元数据回读与目录脆弱性
|
|
485
|
+
|
|
486
|
+
- 触发场景:同一轮主租户批量任务在不同子租户分别报“数据集目标表尚未创建”“接口引擎写入后 HTTP 状态不一致”“既有菜单 Url 唯一冲突”或“未找到 OsClient”;父任务若在目录阶段对全部目标做有副作用自举,还会让一个坏租户阻断其余已可执行租户。
|
|
487
|
+
- 包结构闭包:任何 `DataSets.TableName` 都必须由同一包的 `DiyTables + DiyFields + DDLStatements + PhysicalColumns` 完整创建或由显式依赖声明保证先安装,不能只因为官方母库已有该表就省略。契约测试要逐个数据集反向验证目标表、主键、字段和物理 DDL,并在真实缺表旧租户执行首次安装与重复安装。
|
|
488
|
+
- 无 `Type` 的 `TableChild` 是布局入口,通过真实子表和外键展示记录;不得凭控件名推断 `varchar` 物理列。以实时物理目录核对 DDL/PhysicalColumns,历史包虚构布局列只纠正声明,不远端 DROP、不删除控件/子表/数据,实际存在的同名定制物理列保持。官方资源生成器的精确接口列表必须与完整正式母版及当前包闭包一致,重复生成不得静默删除新增接口、正文、鉴权或 Managed/CreateIfMissing 策略;新增字段及索引也须进入真实计数和幂等深比较回归。
|
|
489
|
+
- 随包固定自动编号:导入器 `v2.9.8` 根据目标 `diy_field.Component=AutoNumber`,仅恢复本次允许写入的显式非空编号,并使用共享事务的最小 `_ForceUpt` 更新和严格回读。`UpsertById` 重装修复旧流水号;`InsertIfMissing` 已有配置保持原编号和值。禁止把包内 `_ForceUpt` 当作可信控制参数,也不能只验证模板存在而不检查其业务检索编号。旧安装器先通过应用商城更新,再重装原不可变应用包;冲突、字段元数据读取失败或回读不一致必须失败回滚。
|
|
490
|
+
- 配置子表种子不能硬编码官方父记录 Id。`InsertIfMissing` 数据集可声明 `ParentBinding:{Field:'SysConfigId',TableName:'sys_config',MatchField:'IsEnable',MatchValue:1}`,仅在目标端查询恰好一条父记录 Id,先绑定外键再检查冲突。0 条、多条、查询失败或不安全标识立即失败;不能覆盖父配置值。导出器须保留该声明,旧导入器必须先升级,不能忽略绑定后按官方 Id 写入。
|
|
491
|
+
- 大表物理兼容必须覆盖全部 DDL 路径:`BIT` 不能落入 `varchar` 默认映射,整数显示宽度与纯标签/注释差异不能触发改列;同一个包的字段元数据变化交给物理列阶段统一比较,不能先改再改回。普通标量列仅默认值变化时使用 `ALTER COLUMN ... SET DEFAULT`,移除旧值必须设为 `NULL`,禁止 `DROP DEFAULT` 留下省略字段时触发 1364 的标志;强回读并禁止 COPY 回退。TEXT/BLOB 的缺失默认标志只能保留完整定义执行 `MODIFY COLUMN` 修复,不能用不支持的 `ALTER COLUMN SET DEFAULT NULL`。空字符串默认值不等同于 NULL。安装器时间辅助必须自包含,应用文件落库等新增分支也不得直接依赖租户的 DateNow。
|
|
492
|
+
- 受管接口状态:旧库 `diy_field` 元数据可能落后于 `sys_apiengine` 物理列,导致 FormEngine 返回成功却忽略 `IsEnable/StopHttp`。仅对受信官方 `Managed` 接口的固定布尔控制列,允许在 FormEngine 写后不一致时按稳定 Id 参数化校准物理列、清理租户缓存并严格二次回读;源码、匿名权限、ApiAddress 和租户扩展不得借此绕过三方冲突或所有权保护,二次回读仍不一致必须整包失败。
|
|
493
|
+
- 菜单与目录隔离:更新既有菜单发生 Url 唯一冲突时,优先保留目标租户当前唯一路由;确需新路由时使用有界、可回读的稳定后缀,不得字符串拼 SQL。子租户目录发现必须是无副作用读取;运行时缺失在单目标投递前按 `sys_osclients` 受控热加载并只记录该租户失败,已经排队的子任务继续监控到终态,禁止一个 `未找到OsClient` 提前终止整批。
|
|
494
|
+
- 百租户并发边界:父协调任务继续使用集群级防重键;子安装任务必须使用固定商城工作器 `ConcurrencyKey` 在当前运行环境内串行。不能根据 `OsClient` 推断物理库隔离,因为多个子租户可能共享同一数据库;只有未来能由服务端权威连接指纹证明互不共享物理库并建立分组锁时,才允许在不同物理库组间并行。
|
|
495
|
+
- 兼容与验收:V8 协调器需要兼容尚未部署新 C# 原子的节点,在目录或单目标投递返回明确的缺失 OsClient 时最多热加载并重试一次,重复同一缺失或超过安全上限立即失败关闭。验收顺序固定为先更新主租户应用商城导入器,再用不可变 `StoreVersionId` 更新 SaaS 协调器,完成全部子租户父子任务收敛,最后立即执行 `Planned=0` 的无操作重跑;同时保留每个失败租户的独立任务和通知中心证据。
|
|
496
|
+
|
|
497
|
+
## 复盘:旧对象存储节点缺少 MoveObject 导致编译资源无限重传
|
|
498
|
+
|
|
499
|
+
- 触发场景:平台微服务包只有少量 `BuildAssets`,但后台检查点长期停在 `ApplicationAssets / Build / AssetIndex=1`,`ApplicationAssetUploaded` 却持续超过包内资源总数。目标节点能够上传并回读公有对象,但不支持或拒绝 `MoveObject`;导入器每一片都重新上传同一文件,再因移动失败写回临时路径,下一片继续重复。
|
|
500
|
+
- 通用规则:新上传文件移动到租户稳定路径失败时,若上传结果已通过摘要和大小校验,应保留这个真实可读路径并写入显式兼容 scope(当前为 `PrivateSource+PublicBuildMoveFallback`)。后续分片只允许在同时命中 AppId、文件路径、摘要、大小、真实 HDFS 路径和该 scope 时直接复用,禁止再次调用 `MoveObject` 或上传;没有兼容标记的历史坏路径仍只允许一次有界重传修复,不能把任意旧元数据误当成有效对象。
|
|
501
|
+
- 自举与验收:主租户投递每个子任务前必须先复制最新版应用商城导入器和批量工作器,已经排队的任务不得假定会动态取得主租户新代码。回归测试要模拟“上传成功、MoveObject 不可用、下一分片恢复”,断言上传次数保持 1 且资源索引继续前进;真实旧租户验收必须观察 4 个编译资源在有界片数内完成,并在全租户成功后立即做 `Planned=0` 复跑。
|
|
502
|
+
|
|
503
|
+
## 复盘:共享公有编译包安装成功但预览进入发布方租户
|
|
504
|
+
|
|
505
|
+
- 共享不可变资源不能像租户独有 HTML 那样重写字节。包内 `SharedPublicRuntime.EntryUrl` 保持纯 HTTPS 不可变地址和摘要;目标 `PreviewUrl` 必须由导入器按当前 `V8.SysConfig.ApiBase + V8.OsClient` 生成 `apiBase/OsClient` 查询参数,不得直接使用发布端默认值,不得附带 Token、密码或签名。
|
|
506
|
+
- 目标 `ApiBase` 缺失、携带凭证或无效时停止并说明配置位置;不能用 CDN 地址或官方默认地址回退。公有字节共享不代表账号、房间、积分或 SignalR 频道跨租户共享。
|
|
507
|
+
- 自动化需比较不可变路径与摘要未变、普通包分支未变,并从目标安装后的实际入口检查登录请求、房间写入及实时事件;后台 `Succeeded` 不能替代租户启动验收。旧导入器先通过应用商城升级,再以新请求 Id 重装目标应用验证修复,保留旧任务审计。
|
|
508
|
+
|
|
509
|
+
## 复盘:历史开关列的单字节文本阻止数值列升级
|
|
510
|
+
|
|
511
|
+
- 数值类型转换失败时先只读实际 `PhysicalColumns` 和错误样本字节;表单字段声明为整数不代表物理列就是整数。旧 `BIT` 曾误转为文本时,可能留下单字节 `00/01`,不能按普通字符串 `0/1` 判断,也不能把所有非数字清零。
|
|
512
|
+
- 仅当可信包与目标字段均明确声明为开关(Switch),且文本值满足单字节和 `HEX IN ('00','01')`,才允许导入器按精确谓词归一为 `0/1`,然后进行类型升级。真正的 BIT 数值列、NULL、多字节文本、普通字段及其它脏值保持各自路径;未知值继续失败关闭。
|
|
513
|
+
- 修复通过正式应用商城导入器版本交付,先升级安装器再用新幂等请求重试原不可变包;禁止直接 SQL 改客户数据或修改旧失败任务。回归覆盖精确匹配、普通字段拒绝、并发重试和物理类型回读,并保留转换计数与终态证据。
|
|
514
|
+
|
|
515
|
+
## 复盘:只补页面首屏接口导致旧租户持续 `sys_apiengine NoExistData`
|
|
516
|
+
|
|
517
|
+
- 触发场景:新版前端已经切换到 `/apiengine/platform-*`、商城 `get-microi-store` 或模块/消息等官方接口,但客户只更新前后端二进制,没有逐个安装应用;启动门禁只检查少数首屏 Key,于是登录恢复后其它页面仍连续报 `sys_apiengine NoExistData`。
|
|
518
|
+
- 根因:把平台运行依赖维护成手写短清单,并只复制 SaaS 单包;接口之间的 `V8.ApiEngine.Run` 依赖、其它官方平台应用和个性化 Hook 没有进入同一闭包,旧数据库也没有可靠的启动前自愈与逐项回读。
|
|
519
|
+
- 强制规则:启动前接口闭包必须由全部内置官方平台应用包动态计算,并递归解析接口调用;当前官方基线为 9 个包、106 个接口(98 个 `Managed`、8 个 `CreateIfMissing`),数量只是发布快照,运行逻辑不得硬编码。门禁逐项校验 Key、地址、启用状态、匿名/HTTP 状态和源码策略;缺失时从受信内置包按原所有权补齐,所有项严格回读成功后才对外提供流量。`CreateIfMissing` 首次创建后永不覆盖客户代码。
|
|
520
|
+
- 控制面自举:官方资源发布必须先保证 `get-microi-upgrade-resource` 自身达到当前协议,再发布其它包;若控制面旧版本不能校验新包,先只发布并回读这一项,刷新动态路由缓存后再发布剩余资源。发布响应超时或 Redis 广播失败时先按资源 SHA 回读判断提交/回滚,禁止盲目重放。
|
|
521
|
+
- 包内明确声明 `Managed` 的 `get-microi-upgrade-resource` 必须和其他受管接口一同原位覆盖;禁止硬编码跳过该 Key 却记安装成功。无 Managed 声明的历史包保留保护边界,官方发布/投影仍需可信后端鉴权。验收核对完整源码、版本、稳定 Id 和路由,不只读取安装状态。
|
|
522
|
+
- 独立系统日志包的接口投影使用 `ReconcilePublishedApiEngines` 与显式 `ProjectionScope: 'SystemLog'`,仅允许单一 `app.microi.sys-log.json`,且包内 `PackageInfo.AppId` 必须为 `app.microi.sys-log`、`ExpectedSha256` 必须等于已发布完整包摘要。默认九包全量规则保持不变;未知范围、其它文件或部分九包选择都应拒绝。仍须执行官方鉴权、事务行锁、Managed/CreateIfMissing 规则及完整回读,不能将母版投影当作客户已安装。
|
|
523
|
+
- 兼容与验收:历史 Controller 回退不能再转调可能缺失的同一个接口引擎;保留旧路由时必须使用可信 Core 原子或明确返回可诊断兼容结果。自动化测试应扫描 PC、UniApp、内置应用包和接口源码的全部 `/apiengine/` 与 `V8.ApiEngine.Run` 引用,证明每个依赖由官方包声明;真实启动必须对每个启用租户输出开始、缺项、修复、逐项成功及最终汇总日志,并同时验证匿名、登录态、商城批量计划和重复启动幂等。
|
|
524
|
+
|
|
525
|
+
跨租户安装验收必须检查 `sys_microiservice.MsUrl`:受托管文件运行时的入口必须使用目标租户与目标 AppKey;数据库运行时保留 `db`,显式外部运行时保留外部地址。源码摘要与编译资源摘要仍需独立回读。
|