Fundamental_Analysis/docs/rust_data_service_design.md
Lv, Qi 21155bc4f8 feat(realtime): 接入前端实时报价并完善后端缓存
前端: 新增 RealTimeQuoteResponse 类型;新增 useRealtimeQuote Hook 并在报告页图表旁展示价格与时间戳(严格 TTL,无兜底)

FastAPI: 新增 GET /financials/{market}/{symbol}/realtime?max_age_seconds=.. 只读端点;通过 DataPersistenceClient 读取 Rust 缓存

Rust: 新增 realtime_quotes hypertable 迁移;新增 POST /api/v1/market-data/quotes 与 GET /api/v1/market-data/quotes/{symbol}?market=..;新增 DTO/Model/DB 函数;修正 #[api] 宏与路径参数;生成 SQLx 离线缓存 (.sqlx) 以支持离线构建

Python: DataPersistenceClient 新增 upsert/get 实时报价,并调整 GET 路径与参数

说明: TradingView 图表是第三方 websocket,不受我们缓存控制;页面数值展示走自有缓存通路,统一且可控。
2025-11-09 05:12:14 +08:00

199 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Rust 数据持久化服务设计 (`rust_data_service_design.md`)
## 1. 服务定位与核心职责
- **服务名称**: `data-persistence-service`
- **核心定位**: 本服务是整个微服务架构中**唯一的数据持久化层**。它是数据库的**独占所有者 (Sole Owner)**,负责管理所有与数据库的交互。
### 1.1. 职责边界:核心实体服务
本服务被设计为**核心实体数据服务**,而非一个包罗万象的、管理所有数据的“上帝服务”。它的职责被严格限定在管理那些**跨多个业务领域共享的核心数据实体**上。
这种设计遵循了一种务实的**混合微服务数据模式**
- **核心数据集中管理**: 保证了通用数据的唯一性和一致性。我们定义的核心实体包括:
- 公司基本信息 (`company_profiles`)
- 标准化财务数据 (`time_series_financials`)
- 标准化市场数据 (`daily_market_data`)
- AI分析结果 (`analysis_results`) - 作为一种可被多方消费的核心产出物。
- **业务数据独立持久化**: 未来新增的、具有独立业务领域的微服务(例如“量化回测服务”)将被**允许并鼓励拥有和管理自己的数据库 Schema 或表**。这些新服务在需要核心实体数据时,应通过调用本服务提供的 API 来获取,而不是直接连接数据库。
这一策略确保了核心数据的一致性,同时为新服务的独立开发和快速迭代提供了最大的灵活性。
## 2. 技术选型与开发范式
### 2.1. 核心技术栈
- **语言**: **Rust**
- **开发套件**: **`service_kit`** (项目内置的一站式微服务开发套件)
- **Web 框架**: **`axum`**
- **数据库交互**: **`sqlx`**
- **序列化/反序列化**: **`serde`** (由 `service_kit` 自动集成)
### 2.2. 开发范式API 规范驱动
我们将采纳 `service_kit` 提供的、以 **OpenAPI** 规范为核心的开发范式。
- **数据契约**: 所有的数据传输对象 (DTOs) 都将使用 `service_kit` 提供的 `#[api_dto]` 宏进行标注。此宏会自动派生 `serde``utoipa::ToSchema`,确保我们的 Rust 代码即是 API 规范的“唯一事实源”。
- **前后端协同**: 我们将使用 `cargo forge generate-types` 命令,从服务自动生成的 OpenAPI 规范中,为前端项目生成 TypeScript 类型定义,实现端到端的类型安全。
- **数据交换格式**: 服务间的数据交换格式依然是 **JSON**
## 3. API 端点设计 (API Endpoint Design)
API 的设计严格服务于对核心实体的通用读写操作。
---
### 3.1. 公司信息 (`/companies`)
- **对应表**: `company_profiles`
| Method | Endpoint | 描述 |
| :--- | :--- | :--- |
| `PUT` | `/api/v1/companies` | 创建或更新Upsert一个公司的基本信息 |
| `GET` | `/api/v1/companies/{symbol}` | 获取指定公司的基本信息 |
---
### 3.2. 市场与财务数据 (`/market-data`)
- **对应表**: `time_series_financials`, `daily_market_data`
| Method | Endpoint | 描述 |
| :--- | :--- | :--- |
| `POST` | `/api/v1/market-data/financials/batch` | 批量写入多条时间序列财务指标 |
| `GET` | `/api/v1/market-data/financials/{symbol}` | 查询某公司的财务指标 (支持按 `metrics`, `start_date`, `end_date` 过滤) |
| `POST` | `/api/v1/market-data/daily/batch` | 批量写入多条每日市场行情数据 |
| `GET` | `/api/v1/market-data/daily/{symbol}` | 查询某公司的每日行情 (支持按 `start_date`, `end_date` 过滤) |
---
### 3.3. AI 分析结果 (`/analysis-results`)
- **对应表**: `analysis_results`
| Method | Endpoint | 描述 |
| :--- | :--- | :--- |
| `POST` | `/api/v1/analysis-results` | 保存一条新的 AI 分析结果 |
| `GET` | `/api/v1/analysis-results` | 查询分析结果列表 (支持按 `symbol`, `module_id` 过滤) |
| `GET` | `/api/v1/analysis-results/{id}` | 获取单条分析结果的详情 |
---
### 3.4. 系统配置 (`/system-config`)
- **对应表**: `system_config`
| Method | Endpoint | 描述 |
| :--- | :--- | :--- |
| `PUT` | `/api/v1/system-config/{key}` | 创建或更新一条键值对配置 |
| `GET` | `/api/v1/system-config/{key}` | 获取一条键值对配置 |
## 4. 数据传输对象 (DTOs)
所有 API 的请求体和响应体都将使用 `service_kit``#[api_dto]` 宏进行定义以自动获得序列化、API Schema 生成和调试能力。
```rust
use service_kit::macros::api_dto;
// 示例:用于批量写入财务数据的 DTO
#[api_dto]
pub struct TimeSeriesFinancialDto {
pub symbol: String,
pub metric_name: String,
pub period_date: chrono::NaiveDate,
pub value: f64,
pub source: Option<String>,
}
// 示例:用于创建 AI 分析结果的 DTO
#[api_dto]
pub struct NewAnalysisResultDto {
pub symbol: String,
pub module_id: String,
pub model_name: Option<String>,
pub content: String,
pub meta_data: Option<serde_json::Value>,
}
```
## 5. 开发流程与工具链
本服务将完全遵循 `service_kit` 提供的标准化开发流程。
- **项目初始化**: 使用 `cargo generate --git <repo_url> service-template` 创建服务骨架。
- **质量保障**:
- 代码风格检查: `cargo forge lint`
- 单元与集成测试: `cargo forge test`
- **API 调试与交互**: 使用 `forge-cli` 工具,通过 `cargo forge <command>` 与正在运行的服务进行交互式 API 调用和调试。
- **前端协同**: 在 CI/CD 流程或本地开发中,通过 `cargo forge generate-types` 命令,自动将本服务的 API 类型同步到前端项目。
## 6. 项目结构(建议)
```
/data-persistence-service
├── Cargo.toml
└── src/
├── main.rs # 应用入口, 初始化数据库连接池, 定义路由
├── error.rs # 统一的错误处理类型
├── db.rs # 数据库交互逻辑 (使用 sqlx)
├── models.rs # 数据库表对应的结构体
├── dtos.rs # API 请求/响应对应的结构体
└── api/
├── mod.rs
├── companies.rs
├── market_data.rs
└── analysis.rs
```
## 7. 实施计划 (Implementation Plan & To-Do List)
本部分将开发 `data-persistence-service` 的过程分解为一系列可执行、可追踪的任务。
### Phase 1: 项目初始化与基础设置
- [x] **T1.1**: 使用 `cargo generate``service-template``services/data-persistence-service` 目录下初始化新项目。
- [x] **T1.2**: 清理模板中的示例代码(如 `hello` 模块)。
- [x] **T1.3**: 配置 `Cargo.toml`,添加 `sqlx` (with `postgres`, `runtime-tokio-rustls`, `chrono`, `uuid`, `json`), `axum`, `tokio`, `serde` 等核心依赖。
- [x] **T1.4**: 设置 `.env` 文件,用于管理 `DATABASE_URL` 等环境变量。
- [x] **T1.5**: 在 `main.rs` 中建立与 PostgreSQL 的数据库连接池 (`sqlx::PgPool`)。
### Phase 2: 数据库集成与迁移
- [x] **T2.1**: 安装 `sqlx-cli` (`cargo install sqlx-cli`)。
- [x] **T2.2**: 使用 `sqlx-cli` 初始化迁移目录 (`sqlx migrate add create_initial_tables`)。
- [x] **T2.3**: 在生成的迁移 SQL 文件中,编写 `CREATE TABLE` 语句,创建 `docs/database_schema_design.md` 中定义的所有表 (`company_profiles`, `time_series_financials` 等)。
- [x] **T2.4**: 在迁移 SQL 文件中,为时序表 (`time_series_financials`, `daily_market_data`) 添加 `create_hypertable` 命令。
- [x] **T2.5**: 运行 `sqlx migrate run` 应用迁移,并在数据库中验证表结构是否正确创建。
- [x] **T2.6**: 在 `src/models.rs` 中,根据数据库表结构,编写对应的 Rust 结构体。
### Phase 3: 核心 API 实现
- [x] **T3.1**: **Companies API**:
- [x]`src/dtos.rs` 中创建 `CompanyProfileDto`
- [x]`src/db.rs` 中实现 `upsert_company``get_company_by_symbol` 数据库操作函数。
- [x]`src/api/companies.rs` 中创建 `PUT /api/v1/companies``GET /api/v1/companies/{symbol}``axum` handler并连接到 `db` 函数。
- [x] **T3.2**: **Market Data API**:
- [x]`src/dtos.rs` 中创建 `TimeSeriesFinancialDto``DailyMarketDataDto`
- [x]`src/db.rs` 中实现 `batch_insert_financials``get_financials_by_symbol` 函数。
- [x]`src/db.rs` 中实现 `batch_insert_daily_data``get_daily_data_by_symbol` 函数。
- [x]`src/api/market_data.rs` 中创建对应的 `axum` handlers 和路由。
- [x] **T3.3**: **Analysis Results API**:
- [x]`src/dtos.rs` 中创建 `NewAnalysisResultDto``AnalysisResultDto`
- [x]`src/db.rs` 中实现 `create_analysis_result``get_analysis_results` 函数。
- [x]`src/api/analysis.rs` 中创建对应的 `axum` handlers 和路由。
- [x] **T3.4**: 在 `main.rs` 中,将所有 API 路由组合起来。
### Phase 4: 容器化与集成
- [x] **T4.1**: 编写多阶段 `Dockerfile`,优化镜像大小和构建速度。
- [x] **T4.2**: 在根目录的 `docker-compose.yml` 中,添加 `data-persistence-service` 的定义,并配置其依赖 `postgres-db`
- [x] **T4.3**: 修改 `Tiltfile` 以包含新的 Rust 服务,确保 `tilt up` 可以成功构建并运行该服务。
- [x] **T4.4**: **(集成点)** 修改现有的 Python `backend` 服务,使其不再直接连接数据库,而是通过 HTTP 请求调用 `data-persistence-service` 的 API 来读写数据。
### Phase 5: 测试与文档
- [x] **T5.1**: 为 `db.rs` 中的每个数据库操作函数编写单元测试(需要 `sqlx` 的 test-macros 特性)。
- [x] **T5.2**: 为每个 API 端点编写集成测试。
- [ ] **T5.3**: 使用 `#[api_dto]` 宏确保所有 DTO 都已正确集成到 OpenAPI 规范中。
- [ ] **T5.4**: 运行 `cargo forge generate-types`,验证能否成功生成 TypeScript 类型文件。
- [ ] **T5.5**: 编写 `README.md`,说明如何本地启动、配置和测试该服务。