- **Common Contracts**: Updated DTOs and models to support workflow history; removed legacy analysis result DTOs.
- **Data Persistence Service**:
- Removed `analysis_results` table logic and API endpoints.
- Implemented `workflow_history` API and DB access (`history.rs`).
- Fixed compilation errors and updated tests.
- Exposed Postgres port in `docker-compose.yml` for easier debugging/offline checks.
- **API Gateway**:
- Implemented `history` endpoints (get history list, get by ID).
- Removed legacy `analysis-results` endpoints.
- Fixed routing and handler logic in `api.rs`.
- **Report Generator Service**:
- Removed dependency on legacy `analysis-results` persistence calls.
- Fixed compilation errors.
- **Workflow Orchestrator**: Fixed warnings and minor logic issues.
- **Providers**: Updated provider services (alphavantage, tushare, finnhub, yfinance, mock) to align with contract changes.
- **Frontend**:
- Updated `ReportPage` and stores to use new workflow history.
- Added `RecentReportsDropdown` component.
- Cleaned up `RealtimeLogs` component.
- **Documentation**: Moved completed design tasks to `completed/` and added refactoring context docs.
Confirmed all services pass `cargo check`.
88 lines
3.0 KiB
Rust
88 lines
3.0 KiB
Rust
use std::sync::Arc;
|
|
use async_trait::async_trait;
|
|
use anyhow::{Result, anyhow, Context};
|
|
use serde_json::{json, Value};
|
|
use std::collections::HashMap;
|
|
|
|
use common_contracts::workflow_node::{WorkflowNode, NodeContext, NodeExecutionResult, ArtifactContent};
|
|
use common_contracts::data_formatting;
|
|
use common_contracts::persistence_client::PersistenceClient;
|
|
use crate::state::AppState;
|
|
|
|
pub struct YFinanceNode {
|
|
state: AppState,
|
|
}
|
|
|
|
impl YFinanceNode {
|
|
pub fn new(state: AppState) -> Self {
|
|
Self { state }
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl WorkflowNode for YFinanceNode {
|
|
fn node_type(&self) -> &str {
|
|
"yfinance"
|
|
}
|
|
|
|
async fn execute(&self, _ctx: &NodeContext, config: &Value) -> Result<NodeExecutionResult> {
|
|
let symbol = config.get("symbol").and_then(|s| s.as_str()).unwrap_or("").to_string();
|
|
let _market = config.get("market").and_then(|s| s.as_str()).unwrap_or("US").to_string();
|
|
|
|
if symbol.is_empty() {
|
|
return Err(anyhow!("Missing symbol in config"));
|
|
}
|
|
|
|
// 1. Fetch Data
|
|
let provider = self.state.yfinance_provider.clone();
|
|
let (profile, financials) = provider.fetch_all_data(&symbol).await
|
|
.context("Failed to fetch data from YFinance")?;
|
|
|
|
// 2. Cache to DB (Side effect)
|
|
let persistence_url = self.state.config.data_persistence_service_url.clone();
|
|
let p_client = PersistenceClient::new(persistence_url);
|
|
if let Err(e) = p_client.upsert_company_profile(profile.clone()).await {
|
|
tracing::warn!("Failed to cache company profile: {}", e);
|
|
}
|
|
|
|
// 3. Prepare Artifacts
|
|
let mut artifacts = HashMap::new();
|
|
artifacts.insert("profile.json".to_string(), json!(profile).into());
|
|
artifacts.insert("financials.json".to_string(), json!(financials).into());
|
|
|
|
Ok(NodeExecutionResult {
|
|
artifacts,
|
|
meta_summary: Some(json!({
|
|
"symbol": symbol,
|
|
"records": financials.len()
|
|
})),
|
|
})
|
|
}
|
|
|
|
fn render_report(&self, result: &NodeExecutionResult) -> Result<String> {
|
|
let profile_json = match result.artifacts.get("profile.json") {
|
|
Some(ArtifactContent::Json(v)) => v,
|
|
_ => return Err(anyhow!("Missing profile.json")),
|
|
};
|
|
let financials_json = match result.artifacts.get("financials.json") {
|
|
Some(ArtifactContent::Json(v)) => v,
|
|
_ => return Err(anyhow!("Missing financials.json")),
|
|
};
|
|
|
|
let symbol = profile_json["symbol"].as_str().unwrap_or("Unknown");
|
|
|
|
let mut report_md = String::new();
|
|
report_md.push_str(&format!("# YFinance Data Report: {}\n\n", symbol));
|
|
|
|
report_md.push_str("## Company Profile\n\n");
|
|
report_md.push_str(&data_formatting::format_data(profile_json));
|
|
report_md.push_str("\n\n");
|
|
|
|
report_md.push_str("## Financial Statements\n\n");
|
|
report_md.push_str(&data_formatting::format_data(financials_json));
|
|
|
|
Ok(report_md)
|
|
}
|
|
}
|
|
|