# Design: Config to MySQL ## 架构决策 ### 决策 1:统一配置管理模块 **决策**:创建 `app/config_store.py` 作为所有配置读写的唯一入口。 **理由**: - 消除多处重复的文件读取逻辑 - 集中管理降级策略 - 便于后续扩展(如缓存、审计) ### 决策 2:单表存储键值对 **决策**:使用单表 `app_config` 存储所有配置,以 `config_key` 区分 `symbols` 和 `ai`。 **表结构**: ```sql CREATE TABLE app_config ( id INT PRIMARY KEY AUTO_INCREMENT, config_key VARCHAR(64) UNIQUE NOT NULL, -- 'symbols' 或 'ai' config_value JSON NOT NULL, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) ``` **理由**: - 与现有 JSON schema 兼容 - 减少表数量 - 未来新增配置无需改表结构 ### 决策 3:MySQL + JSON 文件降级 **决策**:MySQL 可用时优先读写数据库;MySQL 不可用时回退到 JSON 文件。 **理由**: - 用户明确要求无需 Redis - JSON 文件作为 fallback 简单可靠 - 与现有配置读取方式兼容 ## 数据流 ``` 业务代码 ↓ app/config_store.py ↓ MySQL 可用? ↓ 是 ↓ 否 读/写 app_config 读/写 JSON 文件 ``` ## 配置键设计 | config_key | 对应文件 | 用途 | |------------|----------|------| | `symbols` | `config/symbols_config.json` | 品种合约映射 | | `ai` | `config/ai_config.json` | AI 模型配置 | ## 降级策略 ### 读取流程 1. 检查 MySQL 可用性 2. MySQL 可用则查询 `app_config` 3. 数据库无数据则读取 JSON 文件并回填数据库 4. MySQL 不可用则直接读取 JSON 文件 ### 写入流程 1. 检查 MySQL 可用性 2. MySQL 可用则写入 `app_config` 3. 无论数据库是否成功,同步写入 JSON 文件(保持一致性) 4. MySQL 不可用则只写入 JSON 文件 ## 兼容性 - 保持 `symbols_config.json` 和 `ai_config.json` 的 schema 不变 - API 接口签名不变 - 文件路径不变,作为 fallback 使用 ## 数据迁移 启动时执行一次性迁移: 1. 检测 `app_config` 表是否已有 `symbols` 和 `ai` 配置 2. 缺失则从 JSON 文件读取并写入数据库 3. 迁移幂等:已存在则跳过 ## 测试策略 1. 单元测试: - `ConfigStore.get_config` 从 MySQL 读取 - `ConfigStore.get_config` 在 MySQL 不可用时读取 JSON - `ConfigStore.set_config` 写入 MySQL 和 JSON - 迁移幂等性 2. 集成测试: - 启动时自动创建表并迁移 - API 接口正常工作