Files
workspace/code/fms/模块管理简化与架构收敛方案.md
T
2026-10-09 17:32:14 +08:00

16 KiB
Raw Blame History

FMS 模块管理简化与架构收敛方案

文档状态:方案评审稿
目标:降低新增业务模块的配置成本,明确元数据配置与业务代码的边界
约束:不迁移旧模块配置或旧业务数据;不提供旧表、旧接口、旧配置格式的兼容层

1. 结论摘要

当前模块管理的主要问题不是能力不足,而是把“登记业务对象”“定义字段”“设计页面”“配置查询”“配置权限”“定义删除规则”等不同职责,集中成了一个通用模块配置器。简单模块因此也要理解和维护一套近似低代码平台的概念。

建议将系统收敛为以下模式:

业务域代码包(表、SQL、服务、API、页面)
                 │
                 ├── 代码清单登记业务对象、页面和权限点
                 └── 数据库维护模块启停、菜单结构和角色授权

核心决策:

  1. **业务域代码包成为业务实现的唯一中心。**业务表、查询、保存、校验、业务动作和页面由业务域负责。
  2. **模块管理不再设计业务页面。**它只管理代码中已经存在的业务对象及其启停、名称和顺序。
  3. **菜单和权限分别管理。**菜单只能指向代码清单中已登记的页面;权限由代码声明,数据库维护用户或角色授权。
  4. **保留共享组件,不保留通用业务解释器作为核心路径。**简单资料可复用列表、表单、查询组件;复杂行为进入明确的业务服务。
  5. **从全新数据库和新接口开始。**旧 s_module 配置、旧 schema JSON、旧通用模块运行时和旧接口不迁移、不兼容、不双写。

2. 当前设计的主要负担

当前配置模型大致是:

s_module
  ├── s_field
  ├── s_module_schema(view / edit / query JSON)
  ├── s_autocode
  ├── s_power
  ├── s_relation
  ├── s_delete_rule
  └── s_i18n

这套设计能让通用列表和表单快速出现,但也产生了几类持续成本:

  • **配置入口太多。**新增模块要在多个面板间切换;字段定义与列表、表单、查询布局分别维护,用户需要理解内部元数据结构。
  • **模块概念混杂。**导航树节点、数据对象、虚拟查询对象和页面入口都被叫作“模块”,导致一个模块既像目录又像数据模型和页面定义。
  • **运行时过度依赖配置解释。**配置错误会在运行时才表现为页面空白、字段不可写或保存失败,而不是在编译、启动或发布阶段尽早暴露。
  • **业务规则被推向通用化。**关系、级联删除、公式、权限和 SQL 配置逐渐形成跨业务解释规则;规则越多,编辑器、校验器和运行时之间的耦合越高。
  • **安全边界需要后端兜底。**模块中心在前端限制管理员访问,但元数据和业务写入权限不能依赖路由隐藏或前端角色判断。

问题的根因是:把少数简单 CRUD 的便利,扩展成所有业务都必须经过的运行时模型。

3. 目标与非目标

3.1 目标

  • 新增业务对象时,业务规则和数据访问可以在代码中搜索、评审、测试和发布。
  • 管理员只做运行配置:菜单组织、对象启停、角色授权和少量展示偏好。
  • 简单资料复用统一组件;单据、库存、财务、审批等复杂业务使用专用 API 和服务。
  • 页面引用的数据字段、权限点和业务动作可由代码清单静态登记并校验。
  • 配置改动有明确的操作权限、审计信息和发布责任。

3.2 非目标

  • 不建设新的通用低代码平台或通用 JSON 规则引擎。
  • 不让数据库配置动态创建业务表、推断保存逻辑或执行任意业务 SQL。
  • 不要求每个业务页面都可由管理员拖拽生成。
  • 不迁移旧模块配置、旧业务数据或旧接口调用方。
  • 不为兼容旧版而保留双运行时、双字段定义或旧配置转换器。
  • 第一阶段不做通用代码生成平台;先用一个真实业务域验证代码模板。

4. 目标概念模型

必须把四个概念分开:

概念 含义 权威来源
业务域 一组共同业务职责,如 customer、sales、inventory 后端和前端代码目录
业务对象 可被查询或操作的对象,如 customer、sales_order 业务域代码清单
页面 列表、详情、工作台等用户界面 前端代码路由/页面清单
菜单 用户进入页面的导航结构 数据库菜单配置

菜单不再承担业务对象树的职责;业务对象不再通过树节点推断页面行为;页面也不能靠数据库中任意组件名动态加载。

4.1 业务域代码包

建议沿用新架构草案中的业务域组织方式:

domains/
  customer/
    migration/
    sql/
    repository/
    service/
    api/
    page/
    i18n/
  sales/
  inventory/

每个业务域明确拥有自己的数据库变更、查询 SQL、保存方式、业务动作、API、页面和多语言资源。跨域调用通过接口或明确的业务关系完成,不通过任意 JSON 规则互相解释。

4.2 代码清单

每个业务域提供静态清单,列出可供系统登记的对象、页面和权限点。清单是可执行代码的一部分,不能由数据库传入任意类名或组件名覆盖。

示意:

customer 域
  对象:customer
  页面:customer-list、customer-detail
  权限:customer.read、customer.create、customer.update、customer.disable

启动或发布校验至少检查:

  • 菜单引用的页面 key 必须存在于代码清单;
  • 模块登记的业务对象必须存在于代码清单;
  • 授权引用的权限 key 必须已声明;
  • 一个页面声明使用的对象必须在清单中登记;
  • 数据库表、视图和必要字段必须通过业务域校验。

5. 新的模块管理体验

将“模块管理”改名为 业务对象与模块登记,不再展示字段设计器、列表设计器、表单设计器、查询设计器、自动编码、模块关系和删除 SQL 规则等运行时配置面板。

5.1 业务对象登记

业务对象由代码包提供,管理页面只允许维护少量运行属性:

  • 显示名称或启用的多语言资源;
  • 是否启用;
  • 管理列表中的排序;
  • 必要的说明信息。

不允许在这里填写保存表、查询 SQL、字段列表或业务规则。对象登记不是“凭空创建一个业务模块”:新增对象先有代码,再由清单登记。

5.2 菜单管理

菜单继续负责导航树和页面入口:

  • 只能从代码清单选择页面 key;
  • 菜单层级、排序、名称和启停保存在数据库;
  • 菜单到业务对象的绑定明确记录,不从父子树或模块类型推断;
  • 不允许数据库配置任意前端路由组件。

5.3 权限管理

  • 权限点由业务域清单声明,代码决定具体操作含义。
  • 管理界面只分配已声明的权限给角色或用户。
  • 页面入口权限、对象读写权限、业务动作权限分别判定。
  • 后端 API 对每次请求重新校验登录身份、对象/动作权限和业务数据范围;前端隐藏按钮只作为体验优化。

6. 页面和数据配置边界

6.1 业务页面

页面默认由代码实现,并复用现有通用列表、表单、查询、选择器和附件等 UI 组件。业务页面的字段、校验、动作和调用哪个 API 由页面和业务域代码明确声明。

建议的简单资料实现链路:

Migration
→ 业务表 / 查询视图
→ list/detail/save SQL
→ repository / service
→ API
→ 共享列表与表单组件
→ 页面

复杂单据的提交、撤回、审批、过账、库存变更等动作必须由业务服务实现,不由表单 JSON、通用保存接口或可编辑 SQL 字段推断。

6.2 允许的展示偏好

只在多个业务域确实重复需要时,才保留受限展示配置,例如:

  • 用户个人列表列顺序、列宽;
  • 少量查询默认值;
  • 只影响展示的格式偏好。

这些配置不得改变字段真实类型、保存映射、数据权限、业务校验或事务行为。默认布局优先由代码提供;个人偏好是覆盖,不是创建业务页面的必要步骤。

6.3 数据库是事实来源

  • Migration 定义真实表结构;
  • SQL 文件或受控 repository 实现查询和保存;
  • 代码模型定义 API 输入输出和字段语义;
  • 代码或受控资源维护系统文案;
  • 数据库运行配置只登记启停、菜单和授权。

可以保留 describe 能力用于开发期校验或脚手架辅助,但不把数据库实时反射变成生产运行时的字段定义器。

7. 数据表与接口调整方向

以下是职责方向,不要求为每个旧表设计转换路径:

当前职责 目标处理方式
s_module 中的模块树、视图表、保存表、通用 SQL 模块登记表只保留稳定对象编码、业务域/对象 key、名称、启停和排序;业务 SQL 移入域代码
s_field 运行时字段定义 不作为业务页面运行时字段事实来源;字段由业务 API 和页面代码定义
s_module_schema 的 view/edit/query JSON 移除通用解释器依赖;页面结构由代码定义,只可选保留受限展示偏好
s_autocode 编号规则归业务域所有,由业务服务原子获取和验证
s_relation 真实数据关系由 SQL 约束、查询和业务服务表达;不由全局模块关系解释器驱动
s_delete_rule 删除保护和级联行为由业务域服务及数据库约束明确实现
s_power 权限点定义 权限 key 由代码清单声明,数据库维护角色授权;禁止客户端任意造权限 key
s_menu / 菜单绑定 保留导航职责,但页面目标必须指向代码清单中的安全 page key
s_user_module_pref 如有真实用户偏好需求,可保留为展示偏好;不可承载权限或业务规则

模块登记表的候选字段:

b_id             业务对象编码
b_domain_code    业务域编码
b_object_code    域内对象编码
b_name           显示名称
b_i18n           多语言资源 key
b_canuse         是否启用
b_xh             管理列表排序
b_bz             说明

(b_domain_code, b_object_code) 应有唯一约束。最终字段名和表结构在确认代码清单、权限模型和菜单模型后再定;不要把 view_table、save_table、任意 SQL 或业务配置 JSON 原样搬进新表。

8. 安全要求

这次收敛必须同时明确服务端边界:

  1. 模块登记、菜单配置、角色授权的写接口必须有服务端系统管理员权限校验。
  2. 通用数据写入不能只按客户端传入的 table 和 key_field 决定是否允许写;应使用受控表清单或专用业务 API。
  3. 业务 API 必须校验用户对对象和动作的权限,以及公司、组织等数据范围。
  4. 权限定义和页面 key 来自代码清单,不接受页面传入任意字符串作为授权依据。
  5. SQL 参数值使用参数绑定;表、列和排序标识符必须来自服务端登记的标识符清单。
  6. 关键管理操作记录操作人、对象、变更前后值和请求追踪信息。

9. 全新替换策略

本方案不提供旧数据或旧接口的兼容路径:

  • 新环境从新的 Migration 基线建库;
  • 不迁移旧 s_module、s_field、s_module_schema 或其他模块配置数据;
  • 不实现旧 JSON 转换器、双读、双写、旧 API 代理或回退到旧页面的逻辑;
  • 新版模块中心不读取旧配置表;
  • 旧模块运行时、旧管理路由和仅服务旧运行时的接口随新实现整体移除;
  • 旧业务数据迁移不属于本方案范围,需另立项目决策,不在新模块管理中隐式处理。

因此部署策略是新系统按新 schema 初始化,而不是在旧数据库上做无损升级。旧环境如需留档,由环境和备份策略处理,不由新版运行时兼容。

10. 实施顺序

阶段 A:锁定边界

  • 定义业务域代码清单格式;
  • 定义对象、页面和权限 key 的命名规则;
  • 明确模块登记、菜单和角色授权三者关系;
  • 明确简单 CRUD 与复杂业务 API 的使用边界;
  • 完成后端管理员授权和通用写接口策略设计。

阶段 B:建立新内核

  • 使用全新 Migration 建立最小模块登记、菜单、权限和审计结构;
  • 实现代码清单校验;
  • 实现服务端菜单/授权管理 API;
  • 新模块中心只提供登记、启停、排序和菜单/授权入口。

阶段 C:验证一个简单业务域

选择客户或产品资料,完整实现:

Migration → SQL → repository/service → API → 页面 → 菜单 → 授权 → 审计

该对象必须不依赖 s_field、s_module_schema 或通用模块解释器才能运行。

阶段 D:验证一个复杂业务动作

选择一个真实动作(例如单据提交或审批绑定),验证业务校验、事务和权限均在明确的业务服务中完成;工作流只调用已登记的业务动作。

阶段 E:移除旧模块中心实现

  • 移除旧模块配置面板和仅供其使用的 JSON 解释逻辑;
  • 移除旧运行时对模块字段/schema 的依赖;
  • 删除旧模块专属接口与无调用点代码;
  • 确认所有菜单页面来自代码清单,所有关键写操作经服务端权限校验。

不为旧数据补转换步骤,也不设置旧新并行期。

11. 验收标准

  • 开发者新增业务对象时,有一致的业务域模板和单一 API/服务入口。
  • 管理员新增菜单时只能选择已编译、已登记的页面和对象。
  • 建立简单资料不需要分别维护字段表、列表 JSON、表单 JSON、查询 JSON 才能运行。
  • 复杂业务动作的校验、事务和 SQL 均可在对应业务域代码中定位。
  • 没有业务页面依赖全局模块 JSON 解释器才能启动。
  • 未授权用户直接调用 API 不能修改模块、菜单、权限或业务数据。
  • 新数据库初始化后,完整业务示例不需要导入任何旧模块配置即可工作。
  • 配置偏好只影响展示,不能放宽数据权限或改变保存行为。

12. 代价与风险

  • **优点:**运行时更容易理解和测试;业务逻辑可代码评审;减少管理员配置步骤;SQL、权限和事务责任明确。
  • **代价:**新增业务对象需要开发和发布,不再承诺管理员零代码创建任意模块。
  • **控制新增代码成本:**先建立简单资料业务域模板并复用共享组件;只有至少两个业务域出现相同重复后,再抽取脚手架或通用能力。
  • **主要风险:**若大多数模块都要求管理员自行创建且业务结构高度同质,完全代码化会降低业务人员自助能力。应先用真实客户/产品模块验证开发成本,再决定是否增加“生成代码”的开发工具;不要因此恢复生产运行时的通用配置解释器。

13. 评审时需要确认

  1. 新模块由开发者通过代码清单登记,管理员只能启停和配置菜单/授权,是否作为默认流程?
  2. 列表列宽和列顺序是否只保留用户个人偏好,系统级默认布局是否完全由代码维护?
  3. 简单 CRUD 的代码模板是否足够,是否先不做自动代码生成器?
  4. 新数据库 schema 是否允许直接移除旧模块配置表和旧通用模块 API?

以上四项确定后,再据此制定数据库表结构、API 清单和分阶段实施任务。本方案本身不改代码、不执行数据库变更,也不包含旧数据兼容或迁移实现。