Skip to content

配置 JSON 更新与用户偏好保留改善计划 #1517

Description

@cyfung1031

以下是一个概念性想法
ScriptCat 的各种设置现在当 用户改动过后,就会被写入,无视 "defaultValue"
ScriptCat无法控制任何升级所带来的改动,例如更多用户设定等

Image

配置 JSON 更新与用户偏好保留改善计划

一、背景问题

目前系统中存在一份预定义的配置 JSON,用户可以根据自己的需求进行修改。但当系统后续更新这份预定义配置时,容易出现以下问题:

  1. 用户原本修改过的偏好设置可能被覆盖。
  2. 新版本默认配置中的新增字段无法自动同步给用户。
  3. 已废弃或重命名的字段可能导致配置异常。
  4. 系统难以判断某个配置值到底是用户主动修改的,还是旧默认值遗留下来的。
  5. 后续版本升级和配置迁移成本较高。

因此,需要设计一套更稳定、可扩展、可维护的配置更新机制。


二、改善目标

本次改善的核心目标是:

系统可以持续更新默认配置,同时保留用户的个性化设置。

具体目标包括:

  1. 默认配置由系统维护,用户不直接修改默认配置。
  2. 用户只保存自己改动过的配置项。
  3. 当默认配置升级时,用户可以自动获得新的默认配置。
  4. 用户已有偏好不会被系统更新覆盖。
  5. 对配置字段的新增、删除、重命名提供迁移机制。
  6. 在发生冲突时,可以提示用户确认,而不是静默覆盖。

三、推荐方案:默认配置 + 用户覆盖配置

将配置拆分为两层:

最终配置 = 最新默认配置 + 用户覆盖配置

也就是说:

默认配置:由系统维护
用户覆盖配置:只保存用户修改过的部分
最终配置:运行时合并生成

用户不再保存完整 JSON,而是只保存与默认配置不同的部分。


四、配置结构设计

1. 默认配置

默认配置由系统维护,并加入版本号。

{
  "version": "3.0.0",
  "features": {
    "darkMode": true,
    "autoSave": true,
    "exportFormat": "pdf",
    "aiAssist": true
  },
  "limits": {
    "maxItems": 100
  }
}

2. 用户覆盖配置

用户配置只保存用户主动修改过的内容。

{
  "baseVersion": "2.0.0",
  "overrides": {
    "features.exportFormat": "docx",
    "limits.maxItems": 250
  }
}

当系统默认配置升级后,系统会用最新默认配置与用户覆盖配置合并,生成最终配置。


五、合并规则设计

合并时建议采用“三方合并”机制:

旧默认配置
新默认配置
用户覆盖配置

具体规则如下:

场景 处理方式
系统新增字段 使用新默认值
系统修改默认值,用户未修改该字段 使用新的默认值
用户修改过字段,系统未修改默认值 保留用户值
用户修改过字段,系统也修改了默认值 优先保留用户值,并标记为可能冲突
系统删除字段,用户曾修改该字段 尝试迁移,无法迁移则提示用户
系统重命名字段 通过迁移脚本转换到新字段

六、版本迁移机制

每次默认配置发生较大变化时,需要提供迁移逻辑。

例如:

v1 -> v2
v2 -> v3
v3 -> v4

迁移逻辑可以处理:

  1. 字段重命名
  2. 字段删除
  3. 字段结构调整
  4. 默认值策略变化
  5. 用户旧配置兼容

示例:

function migrateV2ToV3(userOverrides) {
  rename(userOverrides, "features.exportType", "features.exportFormat");
  removeIfObsolete(userOverrides, "legacyMode");
  return userOverrides;
}

这样可以保证旧用户在升级系统后,配置仍然可用。


七、避免数组索引作为配置路径

如果配置中存在数组,不建议用数组下标作为用户配置路径。

不推荐:

{
  "menus[2].enabled": false
}

因为菜单顺序变化后,menus[2] 可能已经不是原来的菜单项。

推荐做法是为每个配置对象提供稳定 ID。

{
  "menus": {
    "dashboard": {
      "label": "Dashboard",
      "enabled": true
    },
    "reports": {
      "label": "Reports",
      "enabled": true
    }
  }
}

用户覆盖配置可以写成:

{
  "overrides": {
    "menus.reports.enabled": false
  }
}

这样即使菜单顺序发生变化,用户设置也不会失效。


八、配置校验机制

需要为配置建立 JSON Schema 或类似校验规则。

校验内容包括:

  1. 字段是否存在
  2. 类型是否正确
  3. 枚举值是否合法
  4. 数值范围是否合法
  5. 废弃字段是否仍被使用
  6. 用户自定义字段是否允许存在

在系统加载配置时,应先执行校验,再生成最终配置。


九、用户体验优化

当系统更新默认配置后,可以增加一个“配置更新预览”界面,让用户清楚知道发生了什么。

示例:

本次配置更新内容:

新增默认配置:
- aiAssist: true
- darkMode: true

已保留你的偏好:
- exportFormat: docx
- maxItems: 250

需要确认的项目:
- legacyMode 已被移除
- oldTheme 已替换为 theme.mode

这样可以避免用户感觉系统偷偷修改了自己的设置。


十、建议的目录结构

/config
  default.v1.json
  default.v2.json
  default.v3.json

/user
  user-overrides.json

/schema
  config.schema.json

/migrations
  v1-to-v2.ts
  v2-to-v3.ts

十一、运行流程

系统启动或用户登录时,执行以下流程:

1. 加载最新默认配置
2. 加载用户覆盖配置
3. 检查用户配置的 baseVersion
4. 如果版本过旧,执行迁移脚本
5. 使用 Schema 校验用户覆盖配置
6. 将最新默认配置与用户覆盖配置合并
7. 生成最终配置
8. 应用到系统运行环境
9. 保存迁移后的用户覆盖配置

十二、最终推荐方案

最终建议采用以下设计:

版本化默认配置
+ 稀疏用户覆盖配置
+ 三方合并机制
+ 配置迁移脚本
+ Schema 校验
+ 配置更新预览界面

这套方案的核心原则是:

默认配置由系统持续演进,用户配置只记录用户与默认配置之间的差异。

通过这种方式,系统既可以持续发布新的默认配置,又不会破坏用户已有的个性化设置,从而提升配置系统的稳定性、可维护性和用户信任度。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions