# 两条定制通道 xly 客户通过**两条不同路径**定制系统。理解区别很关键:它们能力不同、成本不同、运维后果也不同。 ## 通道 1 — 通过**后台**编辑元数据 这是受支持、由 PM 驱动的路径。客户实施人员(或客户自己)打开**后台**构建器,进入某个模块,然后在元数据表中插入 / 更新 / 删除行: - `gdsmodule`:注册新模块。 - `gdsconfigformmaster` + `gdsconfigformslave`:定义表单。 - `gdsconfigformcustomslave`:添加每租户字段覆盖([切片 4](../slices/04-custom-field.md))。 - `gdsconfigformpersonalize`:按租户覆盖表单 SQL / where / order。 - `gdsjurisdiction`:授予或限制权限。 - `gdsroute`、`gdsformconst`、`sysbillnosettings` 等:按需配置。 这些修改是**数据**。它们跟随客户数据库。它们在**后台**界面中可见,PM 可以审计。框架运行时在每次请求中读取它们(带缓存)。Java 代码不变;应用行为由这些行决定。 这是默认路径。**90% 以上客户定制都应该放在这里。** ## 通道 2 — 每客户 SQL 覆盖 这是逃生口。当元数据无法表达客户需求时使用,通常是因为客户需要不同的*过程逻辑*,而不仅是不同字段或标签。工程师会把手写 SQL 文件提交到代码库中的 `script/客户//.sql`。文件通常包含一对 `DROP PROCEDURE ... CREATE PROCEDURE`,视图替换则是 `DROP VIEW ... CREATE VIEW`。 然后 DBA 或工程师把该文件**手工应用**到目标客户的 MySQL schema。从那一刻起,该客户数据库中就有一个与标准同名但主体不同的存储过程。 细节见[切片 5](../slices/05-customer-sql-override.md)。 这个通道**真实存在且用于生产**:当前代码库中有 18 个客户覆盖目录。它也比通道 1 显著更贵。 ## 如何选择 使用**通道 1**的情况: - 定制是结构性的(新字段、新模块、不同标签)。 - 行为可通过修改 SQL 片段表达(`sSqlStr` / `sWhere` / `sOrder`)。 - 定制应在**后台**中可见,并可由 PM 编辑。 - 希望它跟随数据库备份。 使用**通道 2**的情况: - 客户需要框架 Add/Update/Calc 过程无法表达的过程逻辑。 - 需要替换存储过程主体,而不是只在周围注入 SQL 片段。 - 维护人员审查客户运行时时,需要能在源码控制的 SQL 文件中看到差异。 通道 2 *几乎总是最后手段*。只有确认通道 1 做不到时才使用。 ## 成本对比 | 属性 | 通道 1(元数据) | 通道 2(SQL 覆盖) | |---|---|---| | 跟随 DB 备份 | 是 | 只有目标客户 schema 被备份时才是 | | **后台**中可见 | 是 | 否 | | PM 可编辑 | 是 | 否,仅工程师 | | 跨租户影响 | 无,行按 `sBrandsId` 作用域隔离 | 无,按客户 schema 应用 | | schema 重建后自动恢复 | 是,行在 DB 中 | 否,必须手工重新执行 | | 单一来源可审计 | 是,DB 行 + `sMakePerson` | 部分,文件在 repo 中,但应用步骤没有日志 | | 读代码库能否发现 | 需要连接 DB | 是,文件位于 `script/客户/` | ## 对切片读者意味着什么 当某个切片描述“标准行为”时,指的是定制完全位于通道 1 中的租户所看到的行为。带有通道 2 覆盖的客户,在被替换的存储过程上可能会看到不同运行时行为;**框架控制器代码无法分辨差异**。分析这类客户的运行时行为必须查看已部署 schema,而不能只看代码库。