# 设计文档 - 基本面选股系统 MVP

## 1. 引言

### 1.1. 文档目的

本文档旨在根据《需求文档 - MVP版本》的要求，提供一个全面的系统设计方案。它将详细阐述系统架构、模块划分、技术选型、数据库设计和API接口，作为开发团队进行系统实现的核心技术指导文件。

### 1.2. 项目概述

基本面选股系统是一个Web应用，旨在为投资者提供自动化、多维度的股票基本面分析报告。用户通过输入股票代码和市场，可以获取或生成一份包含财务数据、AI业务分析、市场情绪、风险评估等多个模块的综合报告，以辅助投资决策。

### 1.3. 范围

本设计涵盖了从用户界面到后端服务、再到数据库的全栈技术方案。主要包括：

- **前端**：用户交互界面，包括报告查询、展示、进度追踪和系统配置。
- **后端**：核心业务逻辑，包括报告生成、数据获取、AI分析、任务管理和配置服务。
- **数据库**：报告数据、分析模块内容、进度信息和系统配置的持久化存储。

## 2. 系统架构

### 2.1. 架构概述

系统采用前后端分离的现代化Web架构，并通过前端API代理到后端：

- **前端 (Frontend)**：基于 React (Next.js App Router) 的应用，负责用户界面与交互。前端通过 Next.js 内置的 API 路由作为代理，转发请求到后端（`NEXT_PUBLIC_BACKEND_URL` 可配置，默认 `http://127.0.0.1:8000/api`）。
- **前端 API 代理**：`/frontend/src/app/api/**` 下的路由将前端请求转发至后端对应路径，统一处理`Content-Type`与状态码。
- **后端 (Backend)**：基于 Python FastAPI 的异步 API 服务，负责财务数据聚合、AI生成、配置管理与分析配置管理。
- **数据库 (Database)**：使用 PostgreSQL（已具备模型与迁移脚手架）。当前 MVP 未落地“报告持久化”，主要以即时查询/生成返回为主；后续迭代将启用。
- **异步任务**：当前 MVP 版本以“同步请求-响应”为主，不使用流式SSE或队列；后续可评估以 SSE/队列增强体验。

![System Architecture Diagram](https://i.imgur.com/example.png)  <!-- Placeholder for a real diagram -->

### 2.2. 技术选型

| 层次 | 技术 | 理由 |
| :--- | :--- | :--- |
| **前端** | React (Next.js App Router), TypeScript, Shadcn/UI, SWR | App Router 简化路由与服务能力，SWR 负责数据获取与缓存。 |
| **后端** | Python, FastAPI, SQLAlchemy (Async) | 异步框架带来高并发性能，Python拥有强大的数据处理和AI生态，SQLAlchemy提供强大的ORM能力。 |
| **数据库** | PostgreSQL | 功能强大、稳定可靠的开源关系型数据库，支持JSONB等高级数据类型，适合存储结构化报告数据。 |
| **数据源** | Tushare API, Yahoo Finance | Tushare提供全面的中国市场数据，Yahoo Finance作为其他市场的补充，易于集成。 |
| **AI模型** | Google Gemini | 强大的大语言模型，能够根据指令生成高质量的业务分析内容。 |

注：当前实现通过 `config/financial-tushare.json` 配置需要拉取的 Tushare 指标分组，通过 `config/analysis-config.json` 配置各分析模块名称、模型与 Prompt 模板。

## 3. 后端设计 (Backend Design)

### 3.1. 核心服务设计

后端逻辑将围绕以下几个核心服务展开：

- **ReportGenerator (报告生成器)**: 核心服务，负责编排整个报告生成流程。它接收报告请求，并按顺序调用各个分析模块。
- **AnalysisModule (分析模块)**: 定义一个基础接口或抽象类，每个具体的分析（如基本面、看涨/看跌分析等）都将实现此接口。这使得系统易于扩展新的分析维度。
- **DataSourceManager (数据源管理器)**: 封装对Tushare、Yahoo等外部数据API的调用，提供统一的数据获取接口，并处理认证、重试和缓存逻辑。
- **AIService (AI服务)**: 封装对Gemini API的调用，负责发送Prompt、处理响应和管理Token消耗的记录。
- **ConfigManager (配置管理器)**: 负责从`config.json`或数据库中加载、更新和验证系统配置（如API密钥、数据库URL）。
- **ProgressTracker (进度追踪器)**: 负责在报告生成的每个阶段更新状态、耗时和Token使用情况，并提供给前端查询。

### 3.2. 任务执行模型（MVP）

当前 MVP 以“按需生成/查询”的同步调用为主：

- 财务数据：请求到达后端即刻聚合最新数据并返回，包含元信息（耗时、步骤、API 调用统计）。
- 公司简介与各分析模块：到达后端实时调用 Gemini 生成，返回内容与 Token/耗时指标。
- 前端在同一页面内顺序执行“公司简介 → 各分析模块”，并以本地状态记录执行轨迹，不依赖 SSE/队列。

### 3.3. API 端点设计（当前实现）

后端 FastAPI 实现的主要端点（被前端 Next.js API 代理转发）：

| Method | Endpoint | 描述 | 请求体/参数 | 响应体 |
| :--- | :--- | :--- | :--- | :--- |
| `GET` | `/api/financials/config` | 获取财务指标分组配置 | - | `FinancialConfigResponse` |
| `GET` | `/api/financials/china/{ts_code}` | 聚合中国市场财务数据（按年汇总，含元信息与步骤） | `years` | `BatchFinancialDataResponse` |
| `GET` | `/api/financials/china/{ts_code}/company-profile` | 生成公司简介（Gemini，同步） | `company_name?` | `CompanyProfileResponse` |
| `GET` | `/api/financials/analysis-config` | 获取分析模块配置 | - | `AnalysisConfigResponse` |
| `PUT` | `/api/financials/analysis-config` | 更新分析模块配置 | `AnalysisConfigResponse` | `AnalysisConfigResponse` |
| `POST` | `/api/financials/china/{ts_code}/analysis` | 生成完整的分析报告（根据依赖关系编排） | `company_name?` | `List[AnalysisResponse]` |
| `GET` | `/api/config` | 获取系统配置 | - | `ConfigResponse` |
| `PUT` | `/api/config` | 更新系统配置 | `ConfigUpdateRequest` | `ConfigResponse` |
| `POST` | `/api/config/test` | 测试配置有效性（数据库/Gemini/Tushare 等） | `ConfigTestRequest` | `ConfigTestResponse` |

说明：前端对应的代理路径如下（示例）：

- 前端请求 `/api/financials/china/...` → 代理到后端 `${BACKEND_BASE}/financials/china/...`
- 前端请求 `/api/config`、`/api/config/test` → 代理到后端 `${BACKEND_BASE}/config`、`${BACKEND_BASE}/config/test`

## 4. 数据库设计

### 4.1. 数据模型 (Schema)

【规划中】以下表结构为后续“报告持久化与历史管理”功能的设计草案，当前 MVP 未启用：

**1. `reports` (报告表)**

用于存储报告的元数据。

| 字段名 | 类型 | 描述 | 示例 |
| :--- | :--- | :--- | :--- |
| `id` | UUID (Primary Key) | 报告的唯一标识符 | `uuid.uuid4()` |
| `symbol` | VARCHAR | 股票代码 | "600519" |
| `market` | VARCHAR | 交易市场 | "china" |
| `status` | VARCHAR | 生成状态 (generating, completed, failed) | "completed" |
| `created_at` | TIMESTAMPTZ | 创建时间 | `datetime.utcnow()` |
| `updated_at` | TIMESTAMPTZ | 最后更新时间 | `datetime.utcnow()` |

**2. `analysis_modules` (分析模块表)**

存储每个报告的具体分析模块内容。

| 字段名 | 类型 | 描述 | 示例 |
| :--- | :--- | :--- | :--- |
| `id` | UUID (Primary Key) | 模块的唯一标识符 | `uuid.uuid4()` |
| `report_id` | UUID (Foreign Key) | 关联的报告ID | `reports.id` |
| `module_type` | VARCHAR | 模块类型 (e.g., "business_info", "bull_case") | "bull_case" |
| `content` | JSONB | 模块的分析结果，结构化数据 | `{"title": "看涨分析", "data": [...]}` |
| `status` | VARCHAR | 模块生成状态 (pending, running, completed, failed) | "completed" |
| `error_message`| TEXT | 失败时的错误信息 | "API call failed" |

**3. `progress_tracking` (进度追踪表)**

记录报告生成过程中每个步骤的状态和性能指标。

| 字段名 | 类型 | 描述 | 示例 |
| :--- | :--- | :--- | :--- |
| `id` | UUID (Primary Key) | 进度记录的唯一标识符 | `uuid.uuid4()` |
| `report_id` | UUID (Foreign Key) | 关联的报告ID | `reports.id` |
| `step_name` | VARCHAR | 步骤名称 | "获取财务数据" |
| `status` | VARCHAR | 步骤状态 (pending, running, completed, failed) | "completed" |
| `started_at` | TIMESTAMPTZ | 步骤开始时间 | `datetime.utcnow()` |
| `completed_at` | TIMESTAMPTZ | 步骤完成时间 | `datetime.utcnow()` |
| `duration_ms` | INTEGER | 步骤耗时（毫秒） | 1500 |
| `token_usage` | INTEGER | AI步骤的Token消耗量 | 2500 |
| `error_message`| TEXT | 失败时的错误信息 | "Data source timeout" |

**4. `system_config` (系统配置表)**

以键值对形式存储可动态修改的系统配置。

| 字段名 | 类型 | 描述 | 示例 |
| :--- | :--- | :--- | :--- |
| `config_key` | VARCHAR (Primary Key) | 配置项的键 | "gemini_api_key" |
| `config_value`| JSONB | 配置项的值 | `{"api_key": "..."}` |

### 4.2. 关系

- `reports` 与 `analysis_modules` 是一对多关系。
- `reports` 与 `progress_tracking` 是一对多关系。

## 5. 前端设计 (Frontend Design)

### 5.1. 组件设计（当前实现）

- **`ReportPage` (`frontend/src/app/report/[symbol]/page.tsx`)**：报告主页面，基于 Tabs 展示：股价图表、财务数据表格、公司简介、各分析模块、执行详情。
  - 中国市场 `ts_code` 规范化：支持纯6位数字自动推断交易所（0/3→SZ，6→SH）。
  - “公司简介 → 各分析模块”按顺序串行执行，带状态、耗时与 Token 统计，可单项重试。
  - 财务数据表按年列展示，包含主要指标、费用率、资产占比、周转能力、人均效率、市场表现等分组；含多项计算型指标与高亮规则（如 ROE/ROIC>12%）。
- **`TradingViewWidget`**：嵌入式股价图表，展示传入 `symbol` 的行情。
- **`ConfigPage` (`frontend/src/app/config/page.tsx`)**：配置中心，支持数据库/Gemini/Tushare/Finnhub 配置查看、保存与测试；支持分析模块名称、模型、Prompt 模板的在线编辑与保存。
- **前端 API 代理**：`/frontend/src/app/api/**` 路由用于转发到后端，解耦部署与本地开发。

### 5.2. 页面与路由（当前实现）

- `/`: 入口页。
- `/report/[symbol]?market=china|cn|...`: 报告页面（当前主要支持中国市场）。
- `/config`: 配置中心。
- `/docs`, `/logs`, `/reports`, `/query`: 辅助页面（如存在）。

### 5.3. 状态管理（当前实现）

- **数据获取**：使用 SWR（`useSWR`）封装于 `frontend/src/hooks/useApi.ts` 中，提供 `useChinaFinancials`、`useFinancialConfig`、`useAnalysisConfig`、`useConfig` 等。
- **全局配置**：使用 Zustand `useConfigStore` 存放系统配置与加载状态。
- **页面局部状态**：`ReportPage` 使用 `useState/useMemo/useRef` 管理任务队列、当前任务、计时器、执行记录与各模块的内容/错误/耗时/Token。

注：当前无 SSE；进度条和“执行详情”来自本地状态与后端返回的元信息（财务数据接口含步骤与耗时统计）。

### 5.4. 指标与显示规范（要点）

- 百分比字段支持 0–1 与百分数两种输入，自动规范化显示为 `%`。
- 金额类（损益/资产负债/现金流）按“亿元/亿股”等进行缩放显示，市值按“亿元”整数化展示。
- 计算项示例：自由现金流 = 经营现金流 − 资本开支；费用率=费用/收入；其他费用率=毛利率−净利率−销售−管理−研发。
- 高亮规则：例如 ROE/ROIC>12% 标绿色背景，增长率为负标红等。

### 5.5. 分析模块编排

系统的核心能力之一是允许分析模块之间传递信息，即一个模块可以利用前序模块的分析结果作为上下文。这通过模块间的**依赖关系（Dependencies）**实现。

- **编排方式**：
  - 前端不再独立、依次请求每个分析模块，而是通过调用一个统一的编排端点 `POST /api/financials/china/{ts_code}/analysis` 来发起一次完整的报告生成任务。
  - 后端编排器会读取 `config/analysis-config.json` 中定义的模块依赖关系，通过**拓扑排序**算法智能地计算出最优执行顺序，确保被依赖的模块总是先于依赖它的模块执行。

- **依赖配置与上下文注入**：
  - **如何配置**：在前端的“配置中心”页面，可以为每个分析模块通过复选框勾选其需要依赖的其他模块。保存后，这将在 `analysis-config.json` 对应模块下生成一个 `dependencies` 数组，例如：
    ```json
    "bull_case": {
      "name": "看涨分析",
      "dependencies": ["fundamental_analysis"],
      "prompt_template": "基于以下基本面分析：\n{fundamental_analysis}\n\n请生成看涨分析报告。"
    }
    ```
  - **如何工作**：当后端执行时，它会先运行 `fundamental_analysis` 模块，然后将其生成的**全部文本结果**，完整地替换掉 `bull_case` 模块提示词模板中的 `{fundamental_analysis}` 占位符。这样，AI在执行看涨分析时，就已经获得了充分的上下文。

- **重要：未配置依赖但使用占位符的后果**
  - 如果您**没有**在配置中为一个模块（如 `bull_case`）勾选其对另一个模块（如 `fundamental_analysis`）的依赖，但依然在其提示词模板中使用了对应的占位符（`{fundamental_analysis}`），系统**不会报错**，但会发生以下情况：
    1.  **执行顺序不保证**：编排器认为这两个模块独立，`fundamental_analysis` 不一定会在 `bull_case` 之前运行。
    2.  **上下文不会被注入**：即使前序模块先运行完，由于 `dependencies` 列表为空，系统也不会进行占位符替换。
  - **最终结果**：该占位符将作为**纯文本**（例如字符串 `"{fundamental_analysis}"`）被原封不动地包含在提示词中并发送给大语言模型。这通常会导致分析质量下降，因为模型会收到一个它无法理解的指令片段，但得益于后端的安全机制（`SafeFormatter`），整个流程不会因缺少数据而崩溃。
  - **结论**：**必须通过配置页面的复选框明确声明依赖关系**，才能激活模块间的上下文传递。

- **失败处理**：
  - 当前的编排流程中，如果一个模块执行失败，依赖于它的后续模块在生成提示词时，会收到一段表示错误的文本（例如 `"Error: Analysis for a_module_failed."`）作为上下文，而不是空字符串。这可以防止后续模块因缺少信息而生成质量过低的内容，同时也为调试提供了线索。
  - 原有的单项重试功能已由全局的“重新运行完整分析”按钮取代，以适应新的编排模式。

### 5.6. 股票代码规范化（中国市场）

- 输入为 6 位数字时自动添加交易所后缀：首位 `6`→`.SH`，`0/3`→`.SZ`；已有后缀将转为大写保留。
## 6. 与最初规划的差异与后续计划

- **报告持久化/历史列表/再生成功能**：目前未实现，仍按需生成并即时展示；后续将启用数据库表 `reports`、`analysis_modules` 与 `progress_tracking` 完成闭环。
- **SSE/队列化执行**：当前为前端串行请求 + 本地状态记录；后续可引入 SSE 或任务队列以提供更丝滑的进度与并发控制。
- **多市场支持**：当前聚焦中国市场（Tushare）；后续将补充美股等数据源与规则。
- **权限与用户体系**：MVP 暂无；后续纳入登录、权限与审计。

本设计文档已对“当前实现”与“后续规划”进行了清晰标注，便于开发与验收。
