diff --git a/openspec/changes/analysis-storage-refactor/.comet.yaml b/openspec/changes/analysis-storage-refactor/.comet.yaml new file mode 100644 index 0000000..a5e78da --- /dev/null +++ b/openspec/changes/analysis-storage-refactor/.comet.yaml @@ -0,0 +1,24 @@ +workflow: full +phase: design +context_compression: off +build_mode: null +build_pause: null +subagent_dispatch: null +tdd_mode: null +review_mode: thorough +isolation: null +verify_mode: null +auto_transition: true +base_ref: 62a95ca +design_doc: null +plan: null +verify_result: null +verification_report: null +branch_status: null +created_at: 2026-07-04 +verified_at: null +archived: false +handoff_context: null +handoff_hash: null +build_command: python -m pytest tests/ -v +verify_command: python -m pytest tests/ -v diff --git a/openspec/changes/analysis-storage-refactor/.openspec.yaml b/openspec/changes/analysis-storage-refactor/.openspec.yaml new file mode 100644 index 0000000..aa68b22 --- /dev/null +++ b/openspec/changes/analysis-storage-refactor/.openspec.yaml @@ -0,0 +1,3 @@ +name: analysis-storage-refactor +created: 2026-07-04 +status: active diff --git a/openspec/changes/analysis-storage-refactor/design.md b/openspec/changes/analysis-storage-refactor/design.md new file mode 100644 index 0000000..2fbfa53 --- /dev/null +++ b/openspec/changes/analysis-storage-refactor/design.md @@ -0,0 +1,88 @@ +# Design: Analysis Storage Refactor + +## 架构决策 + +### 决策 1:复用现有连接 + +**决策**:复用 `storage_manager.py` 中的 `mysql_engine` 和 `redis_client`,不创建新的连接。 + +**理由**: +- 避免重复创建连接池 +- 保持配置一致性 +- 简化降级逻辑 + +### 决策 2:扩展 StorageManager + +**决策**:在 `StorageManager` 中新增 analysis 表读写方法,与行情数据共用同一套降级逻辑。 + +**理由**: +- 统一降级策略 +- 减少代码重复 +- 便于维护 + +### 决策 3:表名前缀 + +**决策**:analysis 表在 MySQL 中保持原名,不添加前缀。 + +**理由**: +- 表名已通过 ORM 模型定义 +- 避免与行情数据表冲突(行情表:`market_data`, `symbol_timestamps`, `scheduled_tasks`) + +## 数据流 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 应用层 │ +│ app/api/futures_analysis.py ←→ app/services/cache.py │ +│ ↓ │ +│ StorageManager │ +│ (storage_manager.py) │ +└─────────────────────────────────────────────────────────────┘ + ↓ + ┌─────────────────────┼─────────────────────┐ + ↓ ↓ ↓ + ┌─────────┐ ┌─────────┐ ┌─────────┐ + │ Redis │ │ MySQL │ │ SQLite │ + │ (缓存) │ │(持久化) │ │ (兜底) │ + └─────────┘ └─────────┘ └─────────┘ +``` + +## 降级策略 + +### 读取流程 + +1. 检查 Redis 缓存,命中则返回 +2. Redis 未命中,检查 MySQL 可用性 +3. MySQL 可用则查询,结果回填 Redis +4. MySQL 不可用,降级到 SQLite + +### 写入流程 + +1. 删除 Redis 缓存 +2. 写入 MySQL(事务) +3. MySQL 成功后回填 Redis +4. MySQL 失败则写入 SQLite + +## 数据迁移 + +启动时执行一次性迁移: + +1. 检测 MySQL analysis 表是否为空 +2. 为空则从 SQLite 读取全部数据 +3. 批量写入 MySQL +4. 迁移完成后记录日志 + +## 缓存策略 + +| 表类型 | 缓存 TTL | 说明 | +|--------|----------|------| +| AI 分析结果 | 5 分钟 | 频繁读取,短期缓存 | +| 复盘计划 | 1 小时 | 每日更新,中期缓存 | +| 交易记录 | 不缓存 | 写入后不再修改 | +| 配置表 | 10 分钟 | 低频读取 | + +## 兼容性 + +- ORM 模型定义不变 +- API 接口签名不变 +- SQLite 文件保留,降级时使用 diff --git a/openspec/changes/analysis-storage-refactor/proposal.md b/openspec/changes/analysis-storage-refactor/proposal.md new file mode 100644 index 0000000..5c97ab2 --- /dev/null +++ b/openspec/changes/analysis-storage-refactor/proposal.md @@ -0,0 +1,51 @@ +# Proposal: Analysis Storage Refactor + +## 问题背景 + +当前 `futures_analysis.db` 是独立的 SQLite 数据库,存储 14 张表(AI 分析、复盘计划、交易记录等)。与行情数据(已迁移到 MySQL/Redis)分离存储,存在以下问题: + +1. **数据孤岛**:分析数据与行情数据分离,无法统一管理和备份 +2. **扩展性差**:SQLite 不适合高并发读写场景 +3. **架构不一致**:行情数据已采用 Redis→MySQL→SQLite 三级降级策略,分析数据仍使用单一 SQLite + +## 目标 + +将 `futures_analysis.db` 的 14 张表迁移到 MySQL `buffer_platform` 数据库,并引入 Redis 缓存层,与行情数据存储策略保持一致。 + +## 范围 + +### 包含 + +- 复用现有 MySQL 连接(`mysql_engine`)和 Redis 连接(`redis_client`) +- 实现三级降级:Redis 缓存 → MySQL 持久化 → SQLite 兜底 +- 启动时自动迁移现有 SQLite 数据到 MySQL +- 保持 ORM 模型定义不变 +- 保持 API 接口不变 + +### 不包含 + +- 行情数据存储(已完成) +- 前端代码修改 +- 新增业务功能 + +## 非目标 + +- 不改变现有 ORM 模型定义 +- 不改变 API 接口签名 +- 不引入新的业务逻辑 + +## 验收标准 + +1. 启动时检测 MySQL/Redis 可用,自动创建 analysis 表并迁移数据 +2. API 读写 analysis 表时优先使用 Redis 缓存,未命中回源 MySQL +3. MySQL 不可用时降级到 SQLite +4. 现有功能(AI 分析、复盘计划、交易记录)正常工作 +5. 单元测试覆盖三级降级场景 + +## 风险 + +| 风险 | 缓解措施 | +|------|----------| +| 数据迁移失败 | 保留 SQLite 作为降级方案,迁移失败时自动降级 | +| Redis 缓存一致性 | 写入时先删缓存,再写 MySQL,最后回填缓存 | +| 表结构不兼容 | 复用现有 ORM 模型,MySQL 自动创建表结构 | diff --git a/openspec/changes/analysis-storage-refactor/tasks.md b/openspec/changes/analysis-storage-refactor/tasks.md new file mode 100644 index 0000000..9764468 --- /dev/null +++ b/openspec/changes/analysis-storage-refactor/tasks.md @@ -0,0 +1,32 @@ +# Tasks: Analysis Storage Refactor + +## 1. StorageManager 扩展 + +- [ ] 1.1 在 `StorageManager` 中新增 `get_analysis_data()` 方法,支持 analysis 表读取 +- [ ] 1.2 在 `StorageManager` 中新增 `save_analysis_data()` 方法,支持 analysis 表写入 +- [ ] 1.3 在 `StorageManager` 中新增 `save_analysis_with_timestamp()` 方法,支持原子写入 + +## 2. 数据迁移 + +- [ ] 2.1 创建 `app/analysis_migration.py`,实现 SQLite → MySQL 迁移逻辑 +- [ ] 2.2 在 `app/main.py` 的 `lifespan` 中调用迁移函数,启动时自动迁移 +- [ ] 2.3 迁移幂等性:检测 MySQL 表是否已有数据,有则跳过 + +## 3. 降级逻辑集成 + +- [ ] 3.1 修改 `app/analysis_db.py`,使用 `StorageManager` 进行读写 +- [ ] 3.2 实现 MySQL 不可用时降级到 SQLite 的逻辑 +- [ ] 3.3 实现 Redis 缓存命中/未命中的逻辑 + +## 4. 表结构初始化 + +- [ ] 4.1 在 `app/main.py` 的 `lifespan` 中创建 analysis 表(MySQL) +- [ ] 4.2 验证 14 张表在 MySQL 中正确创建 + +## 5. 测试与验证 + +- [ ] 5.1 验证 Redis 缓存命中场景 +- [ ] 5.2 验证 Redis 缓存未命中回源 MySQL 场景 +- [ ] 5.3 验证 MySQL 不可用降级到 SQLite 场景 +- [ ] 5.4 验证数据迁移完整性 +- [ ] 5.5 验证现有功能(AI 分析、复盘计划、交易记录)正常工作