Skip to content

客户功能与模块配置

最终口径

Beta 客户配置只有两个来源:

  1. 模块代码中的 Schema 默认值。
  2. config/sites/{active} 中由可视化页面维护的客户差异 JSON。

运行时始终用“代码默认值 + 客户差异”得到有效值。数据库、n_set、根 .env 和遗留 temp/diff_files 不再作为 Feature/模块配置的现场覆盖层;n_set 只继续承载主题等原有系统数据。

config/site-schema-lock.json 是第三类文件,但它不提供运行时配置值。它只锁定当前 Schema 的默认值、类型、改名信息和遗留来源映射,用来阻止代码默认值或导入关系被无意修改。

身份字段只有一个主键口径:active 是部署配置的唯一标识,同时也是目录名和运行时选择键;dw_biaozhi 只是老系统业务标识,允许多个 active 重复使用,不能拿它定位配置。

文件结构

text
config/sites/
└── shanghaipudong/
    ├── site.json
    ├── features.json                  # 可选,仅保存 Feature 差异
    └── modules/
        └── filemanagement.json        # 可选,仅保存该模块差异

site.json 只包含站点身份:

json
{
    "schema_version": 1,
    "active": "shanghaipudong",
    "dw_biaozhi": "lims3.0",
    "customer_name": "实验室信息管理系统"
}

文件管理客户差异示例:

json
{
    "category.export_subclass.enabled": true
}

配置值等于代码默认值时不会写入 JSON;一个模块没有任何差异时,对应文件会被删除。因此不再保存 generated_at、源路径、哈希、告警或 value_sources 等同步过程信息。

开发新增配置

Feature 与模块设置定义都跟随业务模块,例如:

text
app/Modules/FileManagement/config/
├── features.php
└── settings.php

features.php 声明模块 key 和可独立启停的业务能力,settings.php 声明展示、规则和兼容配置。 FeatureRegistryModuleSettingsRegistry 会自动发现这些文件;不要把业务 Schema 重新添加到 config/features.phpconfig/module-settings.php

模块文件中的 Feature 使用短 key,注册中心自动组合成全系统唯一的 模块 key.Feature key。例如 FileManagement 模块声明 module => filemanagementkey => controlled-file,运行时完整 key 为 filemanagement.controlled-file。同模块依赖可以 使用短 key,跨模块依赖必须写完整 key;运行时不得根据调用位置猜测当前模块。

功能开启状态统一通过以下入口判断:

  • Blade:@feature('filemanagement.controlled-file') ... @endfeature
  • PHP:app('feature')->isEnabled('filemanagement.controlled-file')
  • 路由:feature.enabled:filemanagement.controlled-file

featureFeatureStateService 的容器别名,跨模块调用和构造函数注入读取的是同一个单例。

新增一个字段只需在模块 settings 数组中注册:

php
[
    'key' => 'category.download_by_type.enabled',
    'name' => '按类型下载',
    'type' => 'boolean',
    'default' => false,
    'default_policy' => 'stable',
    'description' => '是否显示按文件类型打包下载入口。',
    'group' => '分类与下载',
    'feature' => 'filemanagement.core',
],

页面会根据 type 自动生成控件。当前支持:

  • boolean:开关。
  • enum:下拉选项,必须声明 options
  • string:文本输入,可用 rules 声明 Laravel 校验规则。
  • string_list:逐行输入,页面不要求管理员手写 JSON。

业务代码通过 ModuleSettingsService 读取有效值,不直接解析客户 JSON。

如果新字段对应老系统已有配置,应在同一个 Feature 或模块 Schema 中声明 legacy_source,不要再把一对一关系写进同步命令:

php
'legacy_source' => [
    'source' => 'global',
    'path' => 'filemanagement.enable_controlled_file',
    'cast' => 'boolean',
],

支持的来源为 envglobalvarstrade_global。每个新配置最多声明一个真实存在的老来源, 不提供来源优先级或多来源覆盖。Feature 必须转换成 boolean,模块设置只支持与字段类型相符的 booleanstringarray 转换。

一个老字段对应多个新字段、按客户标识推导值等复杂转换继续放在 app/Foundation/Deployment/Mappers 的专用 Mapper 中。一对一关系禁止在那里重复维护, 同步器会报告重复绑定和类型转换失败。遗留来源只用于初始化导入, 可视化保存不会反向修改老 PHP 配置。

default_policy 支持三种纪律:

  • stable:默认策略。允许客户继承,但默认值受 Schema 锁保护,修改时必须评估受影响客户。
  • customer_required:对应功能启用时,每个客户必须在 JSON 中单独配置该字段。
  • inherited:允许默认值跟随代码演进,仅适合确认可以全局同步变化的低风险展示项。

字段改名时不要直接删旧 key。新定义先声明迁移别名:

php
[
    'key' => 'preview.use_legacy_pdf_viewer',
    'renamed_from' => ['preview.legacy_viewer'],
    // 其余定义……
]

运行时会临时兼容旧 key,校验命令会列出仍需迁移的客户;新旧 key 同时存在会直接报错。客户 JSON 全部迁移后,再在后续版本移除 renamed_from

日常配置流程

  1. 超级管理员打开 /feature-configuration
  2. 选择目标客户和模块。
  3. 修改字段;未定制字段保持“跟随系统默认”。
  4. 保存后页面直接原子写入目标 JSON。
  5. 开发或实施人员检查 git diff,人工提交并随代码发布。

页面保存使用文件哈希做并发保护。如果文件在页面打开后被其他人修改,本次保存返回 409,不会覆盖新内容。 页面默认只读。只有总部维护环境设置 SITE_CONFIG_EDITABLE=true 后才能保存;客户现场保持默认值 false,即使超级管理员构造请求,后端也会拒绝写入。

提交前校验与横向查看

每次修改模块 Schema 或客户 JSON 后执行:

bash
php artisan lims:site-config-validate
php artisan lims:site-config-validate --strict
php artisan lims:site-config-validate --site=nanning_zls

命令会校验全部客户的 JSON 格式、未知/旧 key、字段类型、Feature 依赖、customer_required 字段以及 Schema 锁。--strict 会把待迁移旧 key 等警告也视为失败。

横向回答“哪些客户开了某功能”或“关键字段各客户有什么差异”:

bash
php artisan lims:site-config-status --all --feature=filemanagement.controlled-file
php artisan lims:site-config-status --all \
  --feature=filemanagement.controlled-file \
  --setting=filemanagement:preview.use_legacy_pdf_viewer
php artisan lims:site-config-status --all --json

矩阵同时显示有效值及来源:客户值 表示客户 JSON、继承 表示代码默认、旧 key 表示兼容读取、无效 表示客户值不合法且运行时已回退默认。

修改默认值的安全流程

“只存差异”不等于可以随意改默认值。stable 字段的默认值变更会影响所有未显式覆盖的客户,必须按以下顺序处理:

  1. 修改 Schema 默认值,但先不要刷新锁。
  2. 执行 php artisan lims:site-config-validate,查看 schema_default_changed 列出的继承客户。
  3. 对必须保持旧行为的客户,通过页面写入旧值;必要时用状态矩阵复核。
  4. 再次校验,确认剩余受影响客户确实应随新默认变化。
  5. 执行 php artisan lims:site-config-validate --refresh-schema-lock,把审核过的新基线写入锁文件。
  6. 将 Schema、客户 JSON 和锁文件放在同一次代码评审中提交。

刷新锁前如仍存在非 Schema 类配置错误,命令会拒绝写锁,避免用“更新基线”掩盖客户配置问题。

遗留配置初始化

遗留文件只用于首次/过渡导入:

bash
php artisan lims:sync-site-config
php artisan lims:sync-site-config --only=nanning_zls
php artisan lims:sync-site-config --dry-run
php artisan lims:sync-site-config --strict

不带 --only 会先解析全部站点,全部成功后再切换整个 config/sites 目录,避免只生成一半。该命令以遗留配置重新生成客户 JSON,会覆盖可视化页面已经保存的差异,因此不应作为日常部署时的自动步骤。 只要目标 active(或全量目标目录)已经存在,命令就会拒绝写入;确认需要重新导入时必须加 --force--dry-run--validate-only 永远不要求 --force,也不会写文件。

安全与版本管理

  • 仅超级管理员能查看页面;保存还必须由 SITE_CONFIG_EDITABLE=true 开启。
  • active 和 module key 均经过白名单格式校验,不能构造目录穿越路径。
  • 值必须通过模块 Schema 类型与 rules 校验。
  • JSON 采用稳定字段顺序、Unicode 明文和统一缩进,便于 Git 审核。
  • 写入使用同目录临时文件和 rename,避免进程中断留下半个 JSON。
  • 页面本身不执行 git addcommitpush,仍由人工检查客户差异后提交。
  • config/site-schema-lock.json 必须随代码提交;CI/发布检查应执行 lims:site-config-validate --strict