# 前端报告页面重构设计文档 (Frontend Refactoring Design Doc)

**日期**: 2025-11-19
**状态**: 待评审 (Draft)
**目标**: 重构 `app/report/[symbol]` 页面，消除历史技术债务，严格对齐 V2 后端微服务架构。

## 1. 核心原则

1.  **单一数据源 (SSOT)**: 前端不再维护任务进度、依赖关系或倒计时。所有状态严格来自后端 API (`/api/tasks/{id}`, `/api/analysis-results`).
2.  **无隐式逻辑 (No Implicit Logic)**: 严格按照用户选择的 Template ID 渲染，后端未返回的数据即视为不存在，不进行客户端推断或 Fallback。
3.  **真·流式传输 (True Streaming)**: 废弃数据库轮询方案。采用 **Server-Sent Events (SSE)** 技术。
    *   后端在内存中维护 `tokio::sync::broadcast` 通道。
    *   LLM 生成的 Token 实时推送到通道，直达前端。
    *   数据库只负责存储**最终完成**的分析结果 (Persistence)，不参与流式传输过程。

## 2. 页面布局设计

页面采用“固定框架 + 动态内容”的布局模式。

```text
+-----------------------------------------------------------------------+
|  [Header Area]                                                        |
|  Symbol: AAPL | Market: US | Price: $230.5 (Snapshot) | [Status Badge]|
|  Control: [ Template Select Dropdown [v] ]  [ Trigger Analysis Button ]|
+-----------------------------------------------------------------------+
|                                                                       |
|  [ Tab Navigation Bar ]                                               |
|  +-----------+ +--------------+ +------------+ +------------+ +-----+ |
|  | 股价图表  | | 基本面数据 | | 分析模块A | | 分析模块B | | ... | |
|  +-----------+ +--------------+ +------------+ +------------+ +-----+ |
|  |                                                                       |
+-----------------------------------------------------------------------+
|  [ Main Content Area ]                                                |
|                                                                       |
|  (Content changes based on selected Tab)                              |
|                                                                       |
|  SCENARIO 1: Stock Chart Tab                                          |
|  +-------------------------------------------------+                  |
|  |  [ PLACEHOLDER: TradingView / K-Line Chart ]    |                  |
|  |  (Future: Connect to Time-Series DB)            |                  |
|  +-------------------------------------------------+                  |
|                                                                       |
|  SCENARIO 2: Fundamental Data Tab                                     |
|  +-------------------------------------------------+                  |
|  |  Status: Waiting for Providers (2/3)...         |                  |
|  |  ---------------------------------------------  |                  |
|  |  [Tushare]: OK (JSON/Table Dump)                |                  |
|  |  [Finnhub]: OK (JSON/Table Dump)                |                  |
|  |  [AlphaV ]: Pending...                          |                  |
|  +-------------------------------------------------+                  |
|                                                                       |
|  SCENARIO 3: Analysis Module Tab (e.g., Valuation)                    |
|  +-------------------------------------------------+                  |
|  |  [Markdown Renderer]                            |                  |
|  |  ## Valuation Analysis                          |                  |
|  |  Based on the PE ratio of 30...                 |                  |
|  |  (Streaming Cursor) _                           |                  |
|  +-------------------------------------------------+                  |
|                                                                       |
+-----------------------------------------------------------------------+
|  [ Execution Details Footer / Tab ]                                   |
|  Total Time: 12s | Tokens: 4050 | Cost: $0.02                       |
+-----------------------------------------------------------------------+
```

## 3. 数据流与状态机

### 3.1 固定 Tab 定义
无论选择何种模板，以下 Tab 始终存在（Fixed Tabs）：

1.  **股价图表 (Stock Chart)**
    *   **数据源**: 独立的实时行情 API / 时间序列数据库。
    *   **当前实现**: 占位符 (Placeholder)。
2.  **基本面数据 (Fundamental Data)**
    *   **定义**: 所有已启用的 Data Providers 返回的原始数据聚合。
    *   **状态逻辑**:
        *   此 Tab 代表“数据准备阶段”。
        *   必须等待后端 `FetchCompanyDataCommand` 对应的 Task 状态为 Completed/Partial/Failed。
        *   UI 展示所有 Provider 的回执。只有当所有 Provider 都有定论（成功或失败），此阶段才算结束。
        *   **作为后续分析的“门控”**: 此阶段未完成前，后续分析 Tab 处于“等待中”状态。
3.  **执行详情 (Execution Details)**
    *   **定义**: 工作流的元数据汇总。
    *   **内容**: 耗时统计、Token 消耗、API 调用清单。

### 3.2 动态 Tab 定义 (Analysis Modules)
*   **来源**: 根据当前选中的 `Template ID` 从后端获取 `AnalysisTemplateConfig`。
*   **生成逻辑**:
    *   Template 中定义了 Modules: `[Module A, Module B, Module C]`.
    *   前端直接映射为 Tab A, Tab B, Tab C。
*   **渲染**:
    *   **Loading**: 后端 `AnalysisResult` 状态为 `processing`。
    *   **Streaming**: 通过 SSE (`/api/analysis-results/stream`) 接收增量内容。
    *   **Done**: 后端流结束，或直接从 DB 读取完整内容。

### 3.3 状态机 (useReportEngine Hook)

我们将废弃旧的 Hook，实现一个纯粹的 `useReportEngine`。

```typescript
interface ReportState {
  // 1. 配置上下文
  symbol: string;
  templateId: string;
  templateConfig: AnalysisTemplateSet | null; // 用于生成动态 Tab

  // 2. 阶段状态
  fetchStatus: 'idle' | 'fetching' | 'complete' | 'error'; // 基本面数据阶段
  analysisStatus: 'idle' | 'running' | 'complete';         // 分析阶段

  // 3. 数据持有
  fundamentalData: any[]; // 来自各个 Provider 的原始数据
  analysisResults: Record<string, AnalysisResultDto>; // Key: ModuleID
  
  // 4. 进度
  executionMeta: {
    startTime: number;
    elapsed: number;
    tokens: number;
  }
}
```

## 4. 交互流程

1.  **初始化**:
    *   用户进入页面 -> 加载 `api/configs/analysis_template_sets` -> 填充下拉框。
    *   如果 URL 或历史数据中有 `template_id`，自动选中。

2.  **触发 (Trigger)**:
    *   用户点击“开始分析”。
    *   前端 POST `/api/data-requests` (payload: `{ symbol, template_id }`)。
    *   **前端重置所有动态 Tab 内容为空**。
    *   进入 `fetchStatus: fetching`。

3.  **阶段一：基本面数据获取**:
    *   前端轮询 `/api/tasks/{request_id}`。
    *   **基本面 Tab** 高亮/显示 Spinner。
    *   展示各个 Provider 的子任务进度。
    *   当 Task 状态 = Completed -> 进入阶段二。

4.  **阶段二：流式分析 (SSE)**:
    *   前端建立 EventSource 连接 `/api/analysis-results/stream?request_id={id}`。
    *   **智能切换 Tab**: (可选) 当某个 Module 开始生成 (收到 SSE 事件 `module_start`) 时，UI 可以自动切换到该 Tab。
    *   **渲染**: 收到 `content` 事件，追加到对应 Module 的内容中。
    *   **持久化**: 只有当 SSE 收到 `DONE` 事件时，后端才保证数据已落库。

5.  **完成**:
    *   SSE 连接关闭。
    *   状态转为 `complete`。

## 5. 架构设计 (Architecture Design)

为了实现真流式传输，后端架构调整如下：

1.  **内存状态管理 (In-Memory State)**:
    *   `AppState` 中增加 `stream_manager: StreamManager`。
    *   `StreamManager` 维护 `HashMap<RequestId, BroadcastSender<StreamEvent>>`。
    *   这消除了对数据库的中间状态写入压力。
2.  **Worker 职责**:
    *   Worker 执行 LLM 请求。
    *   收到 Token -> 写入 `BroadcastSender` (Fire and forget)。
    *   同时将 Token 累积在内存 Buffer 中。
    *   生成结束 -> 将完整 Buffer 写入数据库 (PostgreSQL) -> 广播 `ModuleDone` 事件。
3.  **API 职责**:
    *   `GET /stream`:
        *   检查内存中是否有对应的 `BroadcastSender`?
        *   **有**: 建立 SSE 连接，订阅并转发事件。
        *   **无**: 检查数据库是否已完成?
            *   **已完成**: 一次性返回完整内容 (模拟 SSE 或直接返回 JSON)。
            *   **未开始/不存在**: 返回 404 或等待。

## 6. 迁移计划 (Action Items)

### 6.1 清理与归档 (Cleanup)
- [x] 创建 `frontend/archive/v1_report` 目录。
- [x] 移动 `app/report/[symbol]/components` 下的旧组件（`ExecutionDetails.tsx`, `TaskStatus.tsx`, `ReportHeader.tsx`, `AnalysisContent.tsx`）到 archive。
- [x] 移动 `app/report/[symbol]/hooks` 下的 `useAnalysisRunner.ts` 和 `useReportData.ts` 到 archive。

### 6.2 核心构建 (Core Scaffolding)
- [x] 创建 `hooks/useReportEngine.ts`: 实现上述状态机，严格对接后端 API。
- [x] 创建 `components/ReportLayout.tsx`: 实现新的布局框架（Header + Tabs + Content）。
- [x] 创建 `components/RawDataViewer.tsx`: 用于展示基本面原始数据（JSON View）。
- [x] 创建 `components/AnalysisViewer.tsx`: 用于展示分析结果（Markdown Streaming）。

### 6.3 页面集成 (Integration)
- [x] 重写 `app/report/[symbol]/page.tsx`: 引入 `useReportEngine` 和新组件。
- [ ] 验证全流程：Trigger -> Task Fetching -> Analysis Streaming -> Finish。

### 6.4 后端重构 (Backend Refactoring) - NEW
- [x] **State Upgrade**: 更新 `AppState` 引入 `tokio::sync::broadcast` 用于流式广播。
- [x] **Worker Update**: 修改 `run_report_generation_workflow`，不再生成完才写库，也不中间写库，而是**中间发广播，最后写库**。
- [x] **API Update**: 新增 `GET /api/analysis-results/stream` (SSE Endpoint)，对接广播通道。
- [x] **Frontend Update**: 修改 `useReportEngine.ts`，将轮询 `analysis-results` 改为 `EventSource` 连接。
