Files
prompt-optimizer/docs/architecture/storage-refactoring-summary.md
linshen 71600b5081 feat: 重构导入导出架构
## 核心架构重构
- 创建IImportExportable接口,定义统一的导入导出规范
- 新增ImportExportError错误类,提供专门的错误处理
- 将导入导出逻辑从集中式DataManager分散到各个服务
- DataManager职责精简:从375行减至67行(-308行),仅负责协调

## 存储键架构优化
- 移动storage-keys.ts从ui包到core包,实现统一管理
- 修复存储键双重用途问题:物理存储键vs逻辑JSON导出键
- PreferenceService添加'pref:'前缀处理物理存储
- 解决数据导出不完整的关键架构缺陷

## 服务层改造
### ModelManager
- 实现IImportExportable接口(+209行,-153行)
- 添加exportData/importData/validateData方法
- 保持向后兼容的数据格式

### TemplateManager
- 实现分布式导入导出逻辑
- 移除过度设计的configurable storageKey
- 统一使用PreferenceService管理用户偏好

### HistoryManager
- 添加完整的导入导出实现
- 支持数据验证和错误处理

### PreferenceService
- 实现统一的用户设置导入导出
- 处理存储键前缀转换逻辑
- 支持builtin-template-language等核心设置

## Electron桌面端更新
- main.js: 新增148行IPC处理逻辑
- preload.js: 新增177行API暴露
- 更新所有service proxy类支持新接口
- 保持IPC通信的类型安全

## 测试体系完善
- 新增各服务专门的import-export.test.ts文件
- 创建data/import-export-integration.test.ts集成测试
- 建立AI自动化测试框架验证存储键一致性
- 更新现有测试适配新架构

## 文档与架构说明
- 创建import-export-interface-design.md设计文档
- 添加storage-key-architecture.md架构说明
- 建立AI自动化测试文档体系
- 更新workspace文档记录重构过程

BREAKING CHANGE: 导入导出接口从集中式DataManager重构为分布式服务实现,
各服务现在必须实现IImportExportable接口,存储键架构发生变化
2025-07-12 11:56:14 +08:00

7.0 KiB
Raw Permalink Blame History

存储架构重构总结

📋 重构概述

基于用户反馈,我们对存储架构进行了两项重要改进:

  1. 移除TemplateManager的过度设计 - 删除不必要的storageKey配置
  2. 统一使用PreferenceService - 将所有用户偏好设置统一管理

🎯 改进1移除TemplateManager的过度设计

问题分析

TemplateManager的config?.storageKey是过度设计的产物:

  • 理论上提供灵活性,但实际从未被使用
  • 增加了不必要的复杂性
  • 所有地方都使用默认值没有传入自定义storageKey

修改内容

1. 简化TemplateManagerConfig接口

// ❌ 修改前
export interface TemplateManagerConfig {
  storageKey?: string;     // localStorage存储键名
  cacheTimeout?: number;   // 缓存超时时间
}

// ✅ 修改后
export interface TemplateManagerConfig {
  cacheTimeout?: number;   // 缓存超时时间
}

2. 直接使用常量

// ❌ 修改前
this.config = {
  storageKey: config?.storageKey || CORE_SERVICE_KEYS.USER_TEMPLATES,
  cacheTimeout: config?.cacheTimeout || 5 * 60 * 1000,
};

// ✅ 修改后
this.config = {
  cacheTimeout: config?.cacheTimeout || 5 * 60 * 1000,
};

// 直接使用常量
await this.storageProvider.setItem(CORE_SERVICE_KEYS.USER_TEMPLATES, data);

优势

  • 简化代码 - 减少不必要的配置选项
  • 提高可读性 - 直接使用常量,意图更明确
  • 减少维护成本 - 少一个配置点,少一个出错的可能

🎯 改进2统一使用PreferenceService

问题分析

内置模板语言设置与其他UI设置使用不同的存储方式

  • 其他UI设置通过PreferenceService存储pref:前缀)
  • 内置模板语言直接存储(无前缀)
  • 导致存储方式不一致增加了DataManager的复杂性

架构原则重新审视

用户的观点是正确的:

  • PreferenceService不仅仅是UI设置 - 它是用户偏好设置的统一管理
  • 内置模板语言也是用户偏好 - 用户选择使用中文还是英文模板
  • 统一存储方式更简洁 - 减少特殊情况处理

修改内容

1. TemplateLanguageService使用PreferenceService

// ❌ 修改前
export class TemplateLanguageService {
  private readonly STORAGE_KEY = 'app:settings:ui:builtin-template-language';
  private storage: IStorageProvider;

  constructor(storage: IStorageProvider) {
    this.storage = storage;
  }

  async setLanguage(language: BuiltinTemplateLanguage): Promise<void> {
    await this.storage.setItem(this.STORAGE_KEY, language);
  }
}

// ✅ 修改后
export class TemplateLanguageService {
  private storage: IStorageProvider;
  private preferenceService: IPreferenceService;

  constructor(storage: IStorageProvider, preferenceService: IPreferenceService) {
    this.storage = storage;
    this.preferenceService = preferenceService;
  }

  async setLanguage(language: BuiltinTemplateLanguage): Promise<void> {
    await this.preferenceService.set(UI_SETTINGS_KEYS.BUILTIN_TEMPLATE_LANGUAGE, language);
  }
}

2. 更新工厂函数

// ❌ 修改前
export function createTemplateLanguageService(storageProvider: IStorageProvider): TemplateLanguageService {
  return new TemplateLanguageService(storageProvider);
}

// ✅ 修改后
export function createTemplateLanguageService(
  storageProvider: IStorageProvider, 
  preferenceService: IPreferenceService
): TemplateLanguageService {
  return new TemplateLanguageService(storageProvider, preferenceService);
}

3. 简化DataManager

// ❌ 修改前
const PREFERENCE_BASED_KEYS = [
  'app:settings:ui:theme-id',
  'app:settings:ui:preferred-language',
  // ...
] as const;

const DIRECT_STORAGE_KEYS = [
  'app:settings:ui:builtin-template-language', // 特殊处理
] as const;

// ✅ 修改后
const PREFERENCE_BASED_KEYS = [
  'app:settings:ui:theme-id',
  'app:settings:ui:preferred-language',
  'app:settings:ui:builtin-template-language', // 统一处理
  // ...
] as const;

const DIRECT_STORAGE_KEYS = [
  // 现在所有UI设置都通过PreferenceService存储
] as const;

优势

  • 架构一致性 - 所有用户偏好设置都通过PreferenceService管理
  • 简化DataManager - 不再需要区分两种存储方式
  • 语义清晰 - 内置模板语言确实是用户偏好,应该统一管理
  • 便于扩展 - 未来新增用户偏好设置都遵循同一模式

📊 影响范围

修改的文件

  1. 核心服务

    • packages/core/src/services/template/types.ts - 简化配置接口
    • packages/core/src/services/template/manager.ts - 移除storageKey配置
    • packages/core/src/services/template/languageService.ts - 使用PreferenceService
    • packages/core/src/services/data/manager.ts - 简化存储键分类
  2. 应用初始化

    • packages/ui/src/composables/useAppInitializer.ts - 更新服务创建
    • packages/desktop/main.js - 更新服务创建
  3. 测试文件

    • packages/core/tests/unit/template/languageService.test.ts - 更新测试
    • packages/core/tests/unit/template/manager.test.ts - 更新测试
  4. 文档

    • docs/architecture/storage-key-architecture.md - 更新架构说明

向后兼容性

  • 数据导入 - 旧版本数据仍然可以正常导入
  • 键名转换 - LEGACY_KEY_MAPPING确保兼容性
  • 用户体验 - 用户不会感知到任何变化

🎉 重构效果

代码质量提升

  • 减少复杂性 - 移除不必要的配置选项
  • 提高一致性 - 统一的存储方式
  • 增强可维护性 - 更简洁的架构

架构改进

  • 职责清晰 - PreferenceService专门管理用户偏好
  • 扩展性好 - 新增用户偏好设置有明确的模式
  • 测试友好 - 统一的存储方式便于测试

用户体验

  • 功能不变 - 用户不会感知到任何变化
  • 数据安全 - 完全向后兼容,不会丢失数据
  • 性能提升 - 减少了特殊情况处理的开销

🚀 最佳实践

1. 新增用户偏好设置

// 1. 在常量文件中定义键名
export const UI_SETTINGS_KEYS = {
  NEW_PREFERENCE: 'app:settings:ui:new-preference',
} as const;

// 2. 通过PreferenceService存储
await preferenceService.set(UI_SETTINGS_KEYS.NEW_PREFERENCE, value);

// 3. 在DataManager中添加到PREFERENCE_BASED_KEYS
const PREFERENCE_BASED_KEYS = [
  // ...existing keys
  'app:settings:ui:new-preference',
] as const;

2. 避免过度设计

  • 只在真正需要时才添加配置选项
  • 优先使用常量而不是可配置参数
  • 定期审查和清理不必要的配置

3. 保持架构一致性

  • 同类型的数据使用相同的存储方式
  • 遵循既定的命名规范
  • 保持服务职责的清晰边界

📝 总结

这次重构体现了"简单即美"的设计哲学:

  1. 移除过度设计 - 删除不必要的复杂性
  2. 统一架构模式 - 相同类型的数据使用相同的处理方式
  3. 保持向后兼容 - 在改进架构的同时不影响用户

重构后的架构更加简洁、一致和可维护,为未来的功能扩展奠定了良好的基础。