Skip to content

ADR-001:NEXA 产品装配与远程 App 架构 ​

状态 ​

已接受(2026-08-22)

背景 ​

NEXA 的产品面向不同客户交付。产品往往复用相同的 GIS、时间轴、实体编辑、底图管理等能力,但布局、视觉形态、数据接口和跨组件业务流程不同。当前产品通过 workspace 依赖和静态 import 集成 apps/*,每次调整组件组合都需要重新修改依赖和产品源码。

目标不是用配置替代复杂产品代码,而是缩短产品交付链路:复用成熟 App,通过配置完成组件选择、版本锁定、展示形态和初始布局,再由少量产品代码实现业务协同。

决策 ​

NEXA 采用以下产品模型:

text
产品 = 产品壳 + 产品业务内核 + 产品装配清单 + 可远程加载 App

职责边界如下:

  1. 远程 App 提供边界清晰的可复用能力,不拥有产品工作流,不直接依赖产品 Store,不直接绑定客户后端 API。
  2. 产品装配清单 固定 App 版本、Renderer、Container、Theme、初始 Props、能力绑定和页面布局,只表达声明式装配信息。
  3. 产品业务内核 通过 TypeScript 代码实现状态机、工作流、跨 App 协同、权限、事务、异常补偿和算法/GIS/仿真编排。
  4. 产品运行时 校验清单、解析远程制品、异步加载 JS/CSS、注册组件、注入能力、渲染布局并提供加载失败降级。
  5. 组件服务平台 管理不可变制品、版本、Manifest、兼容信息、发布、下架与回滚;管理 App 负责选择、预览和导出装配清单,但不承载已发布产品的运行依赖。

核心边界 ​

配置与代码 ​

配置负责“是什么”:组件、精确版本、Renderer、容器、主题、默认参数、初始布局、权限标识和能力绑定。

代码负责“怎么协同”:条件分支、状态机、多步骤操作、数据转换、事务、异步协调、错误补偿、性能策略和安全校验。

禁止把复杂业务逻辑扩展成 JSON 脚本语言。

能力与表现 ​

同一能力的差异按以下规则归属:

差异归属
卡片、列表、树、表格Renderer
卡片、Dock、抽屉、弹窗、无外壳Container(产品运行时)
明暗色、品牌色、圆角、密度Theme / Design Token
字段、操作项、默认值Props / Config Schema
局部产品内容命名扩展点 / Slot
跨组件业务协同产品 Orchestration 代码
业务语义不同新 App / 新 Capability

禁止用大量互斥布尔 Props 构建万能组件。

数据接口 ​

远程 App 只依赖稳定 Capability Port,不直接调用具体客户 API:

text
Remote App → Capability Port → Product Adapter → Customer API
  • 地址、租户、超时等环境差异可以配置;
  • 简单字段和分页结构差异可以声明映射;
  • 聚合调用、权限校验、事务、实时订阅和补偿必须由产品 Adapter/Service 代码实现;
  • 后端 DTO 只存在于适配器边界,跨产品契约进入底层 Contract/Schema;
  • 若领域语义不同,即使 UI 相似也不得强行共用业务 App。

依赖策略 ​

产品不会取消全部 pnpm 依赖。Vue、Pinia、产品运行时、Contract、Cesium/GIS 核心、布局引擎、主题宿主等稳定基础设施仍为构建时依赖;经治理标记为 remote-ready 的可装配 apps/* 才能改为远程加载。

远程制品采用标准 ESM + Manifest。Vue、Cesium、Naive UI 等宿主级依赖必须 external/shared,避免多实例。是否引入 Module Federation 必须另行决策,不能成为 Manifest Contract 的组成部分。

发布与安全 ​

  • Manifest 必须锁定精确 SemVer,禁止 latest、next、^、~ 和范围版本;
  • 已发布制品 URL 必须不可变,生产环境使用 HTTPS;
  • 制品应提供 SRI/hash,运行时实施来源白名单、CSP、超时、失败隔离和回退;
  • 新版本不得覆盖旧版本路径;产品发布必须记录 product/runtime/apps/schemas/environment 版本;
  • 已发布产品应能在管理平台暂时不可用时继续运行;
  • 下架不等于删除,已锁定版本按保留策略继续可取,紧急封禁除外。

运行时交互模型 ​

App 通过事件、命令和 Capability Port 与产品交互。禁止 App 互相直接 import 或访问产品内部 Store。

text
App Event → Product Orchestration → Store/Workflow → Capability Port → Target App/Service

产品可在命名扩展点注册产品专属 Vue 组件,但扩展点必须由 App Manifest 声明,产品不得依赖 App 内部文件。

机器可读契约与门禁 ​

  • Component Manifest Schema:packages/component-contracts/schemas/component-manifest.schema.json(契约单一真相源)
  • Product Manifest Schema:packages/component-contracts/schemas/product-manifest.schema.json(契约单一真相源)
  • 强制规范:docs/specs/product-composition.md
  • 自动门禁:pnpm check:composition

任何真实平台、Runtime、Service 或新 Package 落地时,必须再按真实资产更新 architecture/*.yaml。本 ADR 不预先创建或登记不存在的能力。

后果 ​

正面影响:产品可快速更换组件版本和布局;表现、数据和业务协同边界清晰;相同 App 可跨产品复用;产品仍保留复杂系统所需的编码能力。

代价:必须维护 Manifest/Port 版本、产品 Adapter、远程制品兼容矩阵和运行时故障治理;远程加载不会消除集成测试,只会改变集成边界。

后续阶段 ​

  1. 设计组件服务平台的领域模型、API Contract、存储和发布状态机;
  2. 建立最小 Runtime PoC,仅迁移一个低风险 App;
  3. 建设制品服务与管理 App;
  4. 接入布局编辑、预览、发布、回滚;
  5. 经人工验收后逐个迁移现有 App,禁止一次性切换全部组件。