🏪 应用商城
平台从 v4.7.2 开始自动安装应用商城模块,用户可通过应用商城安装和管理各种应用
📸 预览图

数据来源
AI 应用与应用商城已经统一为一个系统,sys_microistore 是唯一应用主表。商城入口在同一个页面保留四个业务页签:
| 页签 | 数据来源 |
|---|---|
| 应用市场 | 读取当前选中的联邦商城源,包含平台应用、Web、UniApp、微服务以及租户发布的公开/私有应用。 |
| 已经安装应用 | 以当前租户 sys_microistoreversion 为安装事实源,显示安装版本、最新版本和更新状态。 |
| 发布 / 制作离线包 | 只读取当前登录用户在当前租户拥有的应用,草稿和构建失败项也可继续编辑。 |
| 安装离线包 | 在当前页面校验并提交后台安装任务,不跳转到另一个菜单。 |
旧的 /microi-store-installed、/microi-store-published 菜单不再作为独立入口。主页面保留来源、筛选和分页上下文,并通过应用包中的受管接口引擎读取列表、详情与历史版本。列表可按 ApplicationType、Category、PublisherType、公开范围和关键词筛选。
统一字段约定:
| 字段 | 说明 |
|---|---|
ApplicationType | 运行形态:Regular / Platform / Web / UniApp / MicroService。Regular 是普通平台离线包的新建默认值;商城中的既有平台应用、平台应用通知和旧包仍使用 Platform,两者都必须兼容,不能在未迁移数据和调用方前强制改单值。 |
AppType | 历史兼容字段,旧数据/接口曾同时把它用于“官方/社区来源”和运行形态。新代码不得以它作为唯一判断依据;读取旧包时可回退,写入新数据使用 ApplicationType + PublisherType。 |
Category | 游戏、企业应用、办公、教育、行业应用、平台能力等。 |
PublisherType | 发布者身份/展示来源:官方应用、社区应用。新代码的官方/社区筛选以此字段为准。 |
IsPublic | 1 为公开应用,未登录商城源也可读取;0 为私有应用,只在来源登录成功后可见。历史空值按公开兼容。 |
ViewCount | 官网或商城打开应用时累计浏览次数。 |
InstallCount | 每次安装、更新或重新安装成功后累计一次;后台任务重试仍使用同一个 OperationId,不会重复累计。 |
当前租户数据只走当前 ApiBase + OsClient + Token;只有用户主动选择其它商城源时,才由可信后端代理向该来源发起只读查询或取包请求,来源 Token 不经过浏览器。
商城来源与私有应用
商城来源使用 ApiBase + OsClient 唯一定位。添加来源时先识别系统标题、验证码策略以及公开应用数;未登录时只能安装公开应用,登录后才可统计和安装该账号有权访问的私有应用。每个主租户、子租户都可以发布公开或私有应用,也可以添加其它吾码平台作为来源。
来源帐号密码只参与当次登录,不会保存。平台用非 PC 的 MCP/Mobile 客户端类型签发长会话 Token,并在当前租户后端加密保存到 mci_system_setting;浏览器、来源配置 JSON、日志和应用包都拿不到 Token。来源代理固定校验保存时的 ApiBase、OsClient 和有效期,退出来源登录会删除密文。
应用详情显示完整业务信息和可安装版本。当前版本与 mic_data_version 中仍保留旧包正文或已验证 HDFS 包指针的历史快照都可选择安装;后台任务保存实际选择的版本,允许在新版出现问题时明确重新安装旧版。版本区使用服务端搜索与分页,当前版本固定置顶,默认每页不超过 20 条,不能一次加载全部历史版本再由浏览器过滤。详情弹层使用宿主级固定毛玻璃遮罩,默认居中;标题栏拖动和窗口缩放后都会按弹层真实宽高限制四边,内容不能移出视口。平台官方发布节点仅显示“平台官方应用源”标记,不允许对自身执行安装、更新或重新安装。
安装包存储与数据库容量
新版商城不再把数 MB 的 JSON 包长期放在 sys_microistore.AppPakcet,也不会让每次数据版本快照在 mic_data_version.Data 中复制同一份正文:
| 应用范围 | 包存储 | 下载方式 |
|---|---|---|
| 公开应用 | HDFS 公有桶,PackageStorageMode=HdfsPublic | 来源 FileServer/CDN 公有地址;下载后仍校验大小与 SHA-256。 |
| 私有应用 | HDFS 私有桶,PackageStorageMode=HdfsPrivate | 由来源后端验证登录身份后签发短期地址;Token 和签名地址不落浏览器配置或日志。 |
数据库只保留 PackageId、PackageHdfsPath、PackageSha256、PackageSize、内容类型、格式版本和校验时间。发布器先上传 UTF-8 JSON,再从 HDFS 回读并核对字节数和 SHA-256,全部一致后才更新商城指针并清空内联正文;安装器会独立下载和校验,不能只相信数据库或 Redis。历史版本继续以不可变 StoreVersionId 精确安装,快照保存同一组指针,不会静默换成当前版本。
历史数据库若在 V3 发布协议之前已经写入 mci_ai_app_file,这些文件可能没有 VersionId。升级程序会先按租户和 AppId 创建确定性的 legacy-unversioned-v3 只读归档版本,把原文件绑定后强回读空值为零,再创建版本/路径唯一索引;不会合并或删除文件。文件同时缺少 AppId、确定性 Id 冲突或同名版本身份不一致时,升级会输出数量与样本 Id 后停止,避免猜错归属。
应用商城列表的正式公开地址是 /apiengine/get-microi-store-list,接口 Key 仍为 get-microi-store。为兼容尚未完成应用更新的旧批量工作器,官方应用商城包同时提供 /apiengine/get-microi-store Managed 兼容入口,并只转发到正式列表接口;新代码不得继续使用旧地址。
旧库可由超级管理员运行应用商城包提供的容量治理后台任务。任务先自愈缺失字段,再以有界 Id 游标分批外置 sys_microistore 和商城相关 mic_data_version 快照;每行都在 HDFS 校验成功后以原值 CAS 清理,因此节点重启、重试或并发修改不会误删。任务不会对数 GB 的历史 JSON 执行全表 LIKE,也不会自动运行可能长时间锁表的 OPTIMIZE TABLE。逻辑正文清空后,如需让 MySQL 物理文件立即缩小,应在完成备份的维护窗口由数据库管理员另行评估执行。
安装、升级与安全
SharedPublicRuntime复用已经提交的公有编译文件,不上传客户端源码,也不复制大体积素材。 包内EntryUrl保持不可变且不带查询参数;安装器生成的PreviewUrl另带目标租户的apiBase和OsClient,不得直接继承发布方默认租户。目标系统设置的ApiBase必须有效, 启动地址不包含 Token。导入器需达到v2.9.0;旧租户先更新应用商城,再重新安装共享运行应用。 验收须从安装后入口登录,并检查实际 HTTP 和 SignalR 使用目标租户,不能只检查安装任务成功。- 微服务安装兼容没有
ApiBase配置字段的新租户和历史还原库:打开时优先使用同一租户宿主传入的 API 地址,独立打开时使用绑定目标租户的 API 稳定入口,兼容反向代理路径。不会继承发布方租户或把文件 CDN 地址当成 API。 - 独立 Web/UniApp 的公有 HTML 仍需在目标租户系统设置中配置实际
ApiBase;配置缺失时安装器会说明原因和修复位置。个人中心兼容登录接口返回的角色数组、JSON 字符串与空值。 - 应用商城定义、私有源码、安装、升级和卸载属于控制面,只允许
Level >= 9999。 - 官方平台身份不能只看租户名。只有
OsClient=iTdos且当前服务节点持有与平台内嵌官方公钥匹配的 License 私钥时,V8.SysConfig.IsOfficialPlatform才为true。官方环境会隐藏【安装】【更新】【重新安装】【安装离线包】【全部安装/更新】,服务端也会拒绝对应安装接口;普通部署即使把租户命名为iTdos也不会被误判。 - 离线包必须校验 Manifest、平台最低版本、依赖、文件哈希和资源清单;包内不能携带源租户
OsClient、数据库、Redis、对象存储、MQ/MQTT、AI 或第三方密钥。 - 安装使用后台任务和稳定
OperationId,阶段进度/checkpoint 写共享存储。安装成功后先写商城安装事件,再与InstallCount + 1同事务提交;同一操作的重试只回读已有事件。两个节点重复领取时,由幂等键与数据库唯一/条件更新保证副作用一次。 - 非官方环境的页面按钮【全部安装/更新】固定只规划
ApplicationType=Platform的官方平台应用,并只处理Uninstalled和Outdated两类状态;UniApp、Web、MicroService 及其它社区/AI 应用仍由用户逐个选择,已是最新版的Installed不会重新安装。计划、当前应用和子安装 checkpoint 保存在共享数据库的后台任务CheckpointJson,不要求租户额外创建批量计划表;右上角后台任务中心显示总量、当前项和整体进度,节点重启或租约转移后继续执行。 - MySQL 历史宽表接近 65,535 字节行内上限时,导入器只对明确触发行宽错误且不参与索引的
varchar配置列改用mediumtext行外存储,并把类型覆盖写入后台任务 checkpoint,节点切换后继续沿用;索引字段或其它 DDL 错误不会被自动吞掉。应用包中的长连接串、密钥、回调地址、域名清单等配置字段应直接声明为mediumtext,避免依赖运行时回退。 - MySQL 列只有默认值变化时,普通常量使用
ALTER COLUMN。时间列的CURRENT_TIMESTAMP使用兼容 MySQL 5.7 的MODIFY COLUMN,从目标列元数据保留类型、精度、可空性、ON UPDATE与注释,并固定ALGORITHM=INPLACE, LOCK=NONE;数据库不支持时明确失败,不退回整表复制。写后重新读取默认值,等价的大小写、空括号和零精度写法不会造成重复改列;字符列中的同名文本仍作为普通字符串。 - 批量任务以单个应用作为外层事务和恢复边界。规模可控的小型官方包一次完成,避免每 8 个字段反复下载同一包并重新排队;超过字段、表、DDL、流程、随包数据或资产安全阈值的大包仍使用内部安全分片,因此不会为了提速牺牲大包的内存保护和断点恢复。
- 批量引擎只接受平台持久化任务 Worker 注入的可信调用标记,并同时核对任务 Id、任务信封与正数 fencing token。HTTP 控制器会主动剥离该标记,因此即使为兼容旧服务节点将引擎配置为
StopHttp=0,浏览器或外部请求也只能得到“必须通过持久化后台任务执行”,不能绕过后台任务直接安装。 - 商城页面按钮及其调用的接口引擎、权限和数据结构必须由同一版本应用包交付。导入器会在接口引擎新增/更新后清除缓存并回读 Key、启用状态、HTTP 状态和完整源码;任一项失败时整次安装回滚,不会留下“按钮可见但接口不存在”的半安装状态。
- 发布器必须把请求发布的版本精确传给资产准备器,并回读
RequestedVersion == PackageVersion == PackageInfo.Version;禁止资产准备器静默改用“最新版本”。菜单、表和接口引擎的发布选择必须从本次包正文持久化,不能沿用上一版选择状态。 - 接口引擎资源必须在包内声明
ResourcePolicies.ApiEngines。从固定https://api.itdos.com + iTdos实时回读并经权威商城模型确认的官方Platform包,允许把Platform/Managed核心直接覆盖升级到Incoming;Upgrade13 重放程序集固定九个官方基础包时,也必须由后端建立绑定当前租户与固定导入器的一次性宿主可信上下文,导入器消费成功后才取得同等权限。V8 参数本身不能伪造该授权。两条可信路径都不得覆盖Tenant/CreateIfMissing;离线包、自定义商城源、社区/普通应用和无法建立官方信任链的包继续按上一版 SHA-256 执行Base / Local / Incoming三方保护,Local != Base时整包回滚并报告冲突。 CreateIfMissing表示租户拥有的扩展 Hook:首次安装创建,后续更新永远跳过;同一 Key 一旦交给租户,后续版本也禁止改回Managed,确需新官方核心时必须发布新 Key。官方应用必须采用“受管核心接口 + 租户扩展 Hook”,客户定制只写 Hook,扩展 Hook 按稳定EventId幂等。可信官方核心会在升级时被覆盖,因此不能把租户业务修改直接写进核心。- 商城源业务固定由
platform-marketplace-source(Managed)编排,个性化逻辑只写platform-marketplace-source-hook(CreateIfMissing,默认正文精确为return { Code : 1 };)。登录在任何远端配置读取、密码发送和凭据保存之前调用BeforeMarketplaceSourceLogin;断开在删除服务端凭据之前调用BeforeMarketplaceSourceDisconnect。Hook 失败会直接阻断操作,不能静默跳过。 - 商城源 Before Hook 的安全载荷只包含
Stage / SourceApiEngineKey / Action / SourceId。ApiBase、远端OsClient、账号、密码、Token、签名地址和凭据密文不得进入租户 Hook。登录协议、HTTPS/重定向限制、密码加密、Token 保护与密钥隔离继续保留在可信 C# 网关中;成功或失败后的脱敏审计再由 Managed V8 执行。 - 其它已有资源使用存在性检查与差异合并;客户自定义 V8、全局配置和非包拥有字段不得被整表覆盖。
- 更新遵守“先扩展、后迁移、再收缩”,新旧节点滚动期间 API、数据库和缓存合约兼容。
- 定时任务是应用包的一等资源。导入器完成表、字段、数据与其它
PostSchema资源后,必须在独立ScheduleJobscheckpoint 中幂等创建/更新 Quartz 任务并回读运行元数据;任务阶段失败时不能提前写入已安装版本。 - 安装成功后回读表、字段、接口引擎、菜单、权限、页面、工作流、定时任务和版本,并执行真实 HTTP/UI 冒烟。官方发布源只负责制作和发布应用,禁止在自身执行安装、更新、重新安装、批量安装及
ValidateOnly;安装链路必须在非官方目标租户或本地非发布源环境验证,不能削弱发布源隔离规则。
商城入口自愈与通知中心兜底
更新后端源码并重启 API 时,基础应用完整性检查不仅核对应用商城菜单和导入接口,还会核对 microi-platform-service 是否启用、/marketplace 页面是否启用、菜单是否绑定到对应服务/页面,以及数据库内联 index.html 是否存在。任一项缺失、停用或绑定错误都会触发应用商城包的幂等重导入;在线官方资源必须通过相同运行时契约校验,否则整组回退程序集内置资源,不能把不完整资源写入客户库。
API 接收流量前不再维护“登录页七接口”之类手写清单,而是从程序集随附的九个官方基础应用包计算完整接口引擎闭包:校验跨包 Key 与稳定 Id 唯一、ApiAddress、启用/匿名/HTTP 标志及 Managed / CreateIfMissing 所有权,然后按每个运行租户逐项物理强回读。当前官方基线为 106 项(98 个 Managed、8 个租户 Hook);以后包内资源增加时由包声明自动扩展,不能再同步修改另一份数量清单。缺失或失配的 Managed 项从内置官方包恢复,CreateIfMissing 仅在记录完全不存在时创建,既有租户 Hook 永不覆盖。/api/FormEngine/GetSysConfig 仅作为旧 PC/UniApp 的启动兼容回退,并直接调用固定公开投影原子,不再反向依赖 platform-sys-config。
容器日志中所有升级步骤使用 【自动升级状态】 标记并固定保留在 stdout,可直接执行 docker logs microi-api 查看每个租户的启动门禁、运行时不变量、历史版本步骤(待执行/版本已覆盖)、成功或失败原因,以及最终汇总。若某个子租户失败,汇总会列出该租户和失败阶段;不得只根据 ServerVersion 或“进程已启动”判断应用升级成功。
官方应用源升级“发布控制面自身”的校验规则时采用两阶段自举:先只发布并回读 get-microi-upgrade-resource 的完整源码与 SHA-256,确认动态路由已加载新版控制面;再原子发布应用包,最后用独立 RPC 投影全部 live 接口。第二阶段遇到 524/超时只能通过应用包哈希、接口元数据和 Managed 完整源码摘要判断事务是否已经提交;缺失接口、摘要缺失和网络超时必须分别报告,并以有界低并发重试恢复,禁止盲目重复覆盖或把“包已上传”当成 live 接口已经就绪。
源码发布前可在工作区运行 node Microi.Server/Microi.Upgrade/Resource/refresh-resources.mjs --validate-only,提前检查全部本地资源契约。此模式不联网、不写资源或同步基线,也不允许与发布参数组合;它不能代替完整测试和线上发布回读。控制面校验采用最低语义版本加严格安全能力检查,不会因为已升级到更新版本而误拒绝;通知等可选功能一旦在包中声明,必须携带完整接口及资源策略,半套功能和未知接口仍会阻断发布。
这里的数据库内联不是把所有微服务长期塞进数据库,而是平台启动面专用的受信任例外。microi-platform-service 的已校验编译产物同时内置在 SaaS 引擎包和应用商城包中,固定声明 Source=NotIncluded、Build=DatabaseOnly、StorageMode=db,最多 256 个文件、5MB。新环境即使尚未安装 MinIO、OSS 或 S3,仍应能打开应用商城、个人中心和系统设置;前端通过通用微服务宿主先调用 Resolve,旧后端才回退稳定 /micro-app/.../index.html 入口,不携带第二份平台业务源码。
HDFS 故障时按能力降级,不能把“应用商城页面可打开”和“任意应用都可安装”混为一件事:
| 能力 | HDFS 未安装或不可用时 |
|---|---|
| 平台内置微服务、应用商城页面 | 使用程序集内置包导入的数据库运行产物,继续可用 |
| 通知中心的平台应用恢复入口 | 继续可用,不依赖商城微服务页面挂载成功 |
同样满足 DatabaseOnly 严格边界的受信任小型平台包 | 可安装,但仍要校验包、哈希、事务和回读 |
| 普通 MicroService / Web / UniApp 安装、源码在线编辑、上传与文件预览 | 明确显示对象存储不可用并停止相关动作;不得写入半套数据库记录 |
官方发布源维护 microi-platform-service 时,正式源码根由 platform-service-release.json 唯一指定。发布前运行 embed-platform-service-bundle.mjs --verify-only,确认源码版本、源码清单哈希、dist 哈希、路由、SaaS 引擎包和应用商城包完全一致;官网资源发布器还会要求源码根来自无未提交修改的 Git 提交。HDFS/CDN 若作为镜像,必须回读到同一 RuntimeManifestHash 后才可切换。租户同步目录和前端主包都不是该应用的第二事实源。
右上角【通知中心 → 平台应用】为超级管理员提供【安装/更新全部平台应用】。该入口直接提交 bulk-import-microi-store-packages 持久化后台任务,不依赖应用商城微服务页面能否打开;任务固定只处理 ApplicationType=Platform 且状态为 Uninstalled / Outdated 的应用,已是最新版和其它应用类型均跳过。官方应用源节点不会显示该按钮。
遇到 MICRO_APP_NOT_AVAILABLE 或“微服务不存在或已停用”时:
- 同时更新后端和 PC 前端源码,重启 API,确认日志中的“基础应用升级”已完成且没有导入失败。
- 刷新 PC 页面;如仍需补齐平台应用,由超级管理员在通知中心发起全部安装/更新,并在【后台任务】页签查看任务 Id、当前项、进度和失败原因。
- 任务成功后重新进入应用商城,分别核对页面可加载、平台应用版本和安装记录。源码构建成功、升级日志成功、后台任务成功和真实页面可访问是四个独立验收事实,不能互相替代。
AI 平台治理中心
官方应用 ai-platform-studio 通过同一个安装包交付门户、身份与权限、配置、功能开关、发布审批与执行、服务治理、Trace/日志生命周期、可观测告警、组件资产、页面源码桥接、协作和可恢复导入。包内固定包含 40 张治理表和 5 张运行基础表(合计 45 张表、873 个字段)、42 条稳定菜单兼容记录、64 个接口引擎、1 个治理任务、10 条微服务路由和已校验的构建资产;导航仅显示一个 AI平台治理 MicroService 入口,历史工作台和 40 个数据菜单隐藏,能力均在工作台页面中进入。
其中 57 个官方核心接口使用 Managed,7 个租户扩展 Hook 使用 CreateIfMissing。首次安装和后续升级都必须核对两类策略数量;安装后打开 /micro-app/ai-platform-studio/overview 做真实页面冒烟,并逐项验证配置、发布、服务、可观测、资产与协作入口。完整能力与验收见 AI 平台治理中心。
复杂安装交互使用 V8.OpenAppDialog;后台安装调用 V8.ApiEngine.RunBackground。不要在 ConfirmTips 中拼接上传控件和大段内联 HTML/事件。
完整规范见源码 microi.skills/app-store/SKILL.md 与平台安全与兼容基线。
旧开关列的二进制文本兼容
导入器 v2.9.1(应用商城 v8.3.6)补充识别旧 BIT 被历史工具转成文本列后遗留的单字节 00/01。仅当应用包的表/字段元数据明确将该列声明为 Switch 时,程序才规范为数值 0/1 并继续物理列复核。真正的 BIT 列仍按数值类型处理,不扫描或改写为文本;普通字段、多字节二进制与其它非法字符串仍失败关闭。
遇到“元数据 int、物理 varchar”的升级失败,应从正式结构导出检查 PhysicalColumns 与失败样本编码,再通过更新后的导入器重试同一已校验包。不要手工清空业务行、强制把所有非法值转零或关闭物理列检查。
非 Id 主键与检查点恢复
安装器 v2.9.6 从包与目标数据库读取真实主键、自增/identity 信息,保留任意名称及复合主键的非空约束。普通业务字段仍允许 NULL,表单必填规则独立生效。旧包缺少主键信息时也不会把目标主键改为可空或取消自增。
升级失败提示主键不能为 NULL 时,先更新应用商城安装器,再恢复原后台任务的检查点;不要删除主键、清空业务数据或生成不同内容的包来绕过校验。
跨租户安装微服务时,文件、HDFS、OSS 等受托管运行时入口使用目标租户及安装后的 AppKey,不保留来源租户地址;数据库运行时仍使用 db,显式外部运行时保留外部地址。