前端: 新增 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,不受我们缓存控制;页面数值展示走自有缓存通路,统一且可控。
9.8 KiB
9.8 KiB
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 生成和调试能力。
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: 项目初始化与基础设置
- T1.1: 使用
cargo generate和service-template在services/data-persistence-service目录下初始化新项目。 - T1.2: 清理模板中的示例代码(如
hello模块)。 - T1.3: 配置
Cargo.toml,添加sqlx(withpostgres,runtime-tokio-rustls,chrono,uuid,json),axum,tokio,serde等核心依赖。 - T1.4: 设置
.env文件,用于管理DATABASE_URL等环境变量。 - T1.5: 在
main.rs中建立与 PostgreSQL 的数据库连接池 (sqlx::PgPool)。
Phase 2: 数据库集成与迁移
- T2.1: 安装
sqlx-cli(cargo install sqlx-cli)。 - T2.2: 使用
sqlx-cli初始化迁移目录 (sqlx migrate add create_initial_tables)。 - T2.3: 在生成的迁移 SQL 文件中,编写
CREATE TABLE语句,创建docs/database_schema_design.md中定义的所有表 (company_profiles,time_series_financials等)。 - T2.4: 在迁移 SQL 文件中,为时序表 (
time_series_financials,daily_market_data) 添加create_hypertable命令。 - T2.5: 运行
sqlx migrate run应用迁移,并在数据库中验证表结构是否正确创建。 - T2.6: 在
src/models.rs中,根据数据库表结构,编写对应的 Rust 结构体。
Phase 3: 核心 API 实现
- T3.1: Companies API:
- 在
src/dtos.rs中创建CompanyProfileDto。 - 在
src/db.rs中实现upsert_company和get_company_by_symbol数据库操作函数。 - 在
src/api/companies.rs中创建PUT /api/v1/companies和GET /api/v1/companies/{symbol}的axumhandler,并连接到db函数。
- 在
- T3.2: Market Data API:
- 在
src/dtos.rs中创建TimeSeriesFinancialDto和DailyMarketDataDto。 - 在
src/db.rs中实现batch_insert_financials和get_financials_by_symbol函数。 - 在
src/db.rs中实现batch_insert_daily_data和get_daily_data_by_symbol函数。 - 在
src/api/market_data.rs中创建对应的axumhandlers 和路由。
- 在
- T3.3: Analysis Results API:
- 在
src/dtos.rs中创建NewAnalysisResultDto和AnalysisResultDto。 - 在
src/db.rs中实现create_analysis_result和get_analysis_results函数。 - 在
src/api/analysis.rs中创建对应的axumhandlers 和路由。
- 在
- T3.4: 在
main.rs中,将所有 API 路由组合起来。
Phase 4: 容器化与集成
- T4.1: 编写多阶段
Dockerfile,优化镜像大小和构建速度。 - T4.2: 在根目录的
docker-compose.yml中,添加data-persistence-service的定义,并配置其依赖postgres-db。 - T4.3: 修改
Tiltfile以包含新的 Rust 服务,确保tilt up可以成功构建并运行该服务。 - T4.4: (集成点) 修改现有的 Python
backend服务,使其不再直接连接数据库,而是通过 HTTP 请求调用data-persistence-service的 API 来读写数据。
Phase 5: 测试与文档
- T5.1: 为
db.rs中的每个数据库操作函数编写单元测试(需要sqlx的 test-macros 特性)。 - T5.2: 为每个 API 端点编写集成测试。
- T5.3: 使用
#[api_dto]宏确保所有 DTO 都已正确集成到 OpenAPI 规范中。 - T5.4: 运行
cargo forge generate-types,验证能否成功生成 TypeScript 类型文件。 - T5.5: 编写
README.md,说明如何本地启动、配置和测试该服务。