# 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 文件保留，降级时使用
