背景
- HEAD 长期停在 08-03 的安全审计提交,此后六周的工作全部只在工作区。
- 更严重的是部分源码从未进入过版本控制(非"改了没提交"):
· Services/findatahub-core/ 索引 0 条 —— 18 个核心模块(pipeline/gate/cleaner/
db/cross_validator/health/retry…)全新 clone 拿不到
· Services/findatahub-client/ 索引 0 条
· App/Sources 磁盘 74 个 .swift、索引 54 —— 20 个未入库(AutoRecoveryManager、
全套 Settings*Section、PowerSaver、MySQLOnDemandManager、DependencyScanner…)
一次 `git clean -fd`、误删目录或磁盘故障即可不可恢复地丢失这些文件。
本提交内容
1. 补齐上述未跟踪源码、测试、文档与报告(Services/App/Docs/Tests/根报告)。
2. 纳入 .workbuddy/memory(项目知识)与 .github CI 配置。
3. 本次代码与架构复查的修复(详见下一段说明):
- Scripts/bin/common.py PidManager.status 改 split(":", 1),修复时间戳被截断到整点
- Scripts/bin/db_pool.py 取连接加超时、归还前 rollback、失败归还池位、双检锁初始化
- Scripts/bin/newsflash_backend.py _query_all 改 try/finally 无条件归还连接
- Scripts/bin/newsflash_collect.py 新增 _install_crash_handlers(faulthandler + excepthook)
- tushare_fetcher/core/fetcher.py _fetch_static 增量走 upsert,仅全量快照才 replace
- tushare_fetcher/scripts/tushare_sync.sh 银层迁移补 stock_weekly/stock_monthly;
月度增加分红按报告期全量刷新
- kuaixun-service/extend/content_enricher.py 禁用自动重定向 + 逐跳 SSRF 校验
- App/.../AutoRecoveryManager.swift 反复故障改告警不熔断(避免拉长数据空窗)
- 新增 Scripts/bin/repair_dividend_history.py(分红历史修复,按报告期分页幂等 upsert)
- 新增 Docs/repro/*(两个可运行的缺陷复现脚本)
- 补齐 6 个文件共 20 条回归用例(均做过证伪:旧实现下必然失败)
安全
- 已确认未纳入任何凭据:Services/tushare_fetcher/.env 被其 .gitignore 覆盖;
~/.config/findatahub/env(0600)在仓库外。
验证
- Python 测试 1074 passed(Scripts/bin 207 / core 105 / tushare 174 / kuaixun 405 / akshare 183)
- Swift 经 `swift build --disable-sandbox` 编译通过,产物 v1.5.2 已部署
15 KiB
FinDataHub 项目全景分析与优化建议
分析日期:2026-08-09 | 当前版本:v1.4.7 | 分析范围:App / Services / Scripts / Docs 全仓
一、一句话定位
FinDataHub 是一个面向 A 股的本地化金融数据中枢:以「双源采集 → 七步清洗 → 四级质量门控 → SDK/API/MCP 多形态输出」为数据主线,外挂一个 macOS 菜单栏桌面端做可视化管理,以及一个财经快讯子系统做实时资讯采集推送。本质是把散落在 TuShare / AKShare / 各大财经网站的原始数据,治理成一份干净、可信、可被程序与 AI 直接消费的数据资产。
它的差异化定位在于三点:
- 数据质量优先 —— 不是简单"拉数据存库",而是有 Medallion 分层、质量分(0–1 六维加权)、门控 BLOCK/WARN/INFO 的完整治理链路。
- AI 原生 —— SDK → REST → Skills → MCP 四级抽象,让大模型能自然语言直连数据。
- 本地优先 —— MySQL 本地持久化 + macOS 原生 App,无云端依赖,隐私与可控性强。
二、技术栈全景
| 层 | 子系统 | 语言 / 框架 | 构建 | 备注 |
|---|---|---|---|---|
| 桌面端 | App/ | Swift 5.9 · SwiftUI · AppKit · Combine · CryptoKit | SwiftPM(macOS 13+,零第三方依赖) | MenuBarExtra 菜单栏应用 |
| 数据核心 | Services/findatahub-core | Python ≥3.10 · pandas · SQLAlchemy 2 · pymysql · structlog | setuptools | 公共核心库(被两 fetcher editable 依赖) |
| SDK/API | Services/findatahub-client | Python + FastAPI + uvicorn + MCP | setuptools | 11 方法 SDK + 14 端点 REST + 7 MCP 工具 |
| 采集器 A | Services/tushare_fetcher | Python ≥3.12 · Typer · pydantic-settings + Rust(PyO3 cdylib) | hatchling + uv | 39 个数据接口 + Rust 序列化加速 |
| 采集器 B | Services/akshare_fetcher | Python ≥3.10 · akshare · Typer · cryptography | hatchling + uv | 腾讯源优先 + 东财降级 |
| 快讯后端 | Services/kuaixun-service | Python ≥3.10 · FastAPI · jieba · websockets | setuptools | 12 源采集 + AI 增强 + 四层去重 + 多渠道推送 |
| 快讯前端 | Services/kuaixun-frontend | Vue 3(纯 JS,非 TS) · Vite 5 · Pinia · axios | pnpm + Vite | 实时快讯流 / 搜索 / 统计 / 标签云 |
| 胶水层 | Scripts/bin | Python | — | 25 个脚本,App 通过子进程调用 |
| 存储 | — | MySQL(fin_data_clean 等 3 库) | — | Swift 端从不直连,全走环境变量注入 |
⚠️ 注意:仓内统计的 954 个
.ts/ 1020 个.js绝大多数是node_modules与dist构建产物,前端源码实际是 Vue 3 + 纯 JavaScript,并非 TypeScript。
三、架构分层与功能模块
┌─────────────────────────────────────────────────────────┐
│ L4 接入层 SDK(client.py) │ REST(api.py) │ MCP │ Skills │
├─────────────────────────────────────────────────────────┤
│ L3 使用层 findatahub-client 直读 fin_data_clean │
├─────────────────────────────────────────────────────────┤
│ L2 预处理层 findatahub-core:七步 Pipeline + 四级门控 │
│ fetch→G1→clean→G2→impute→G3→store→G4 │
├─────────────────────────────────────────────────────────┤
│ L1 采集层 tushare_fetcher │ akshare_fetcher(双源对照) │
├─────────────────────────────────────────────────────────┤
│ 旁路 kuaixun 快讯子系统(后端 FastAPI + 前端 Vue) │
│ 呈现 macOS App(菜单栏,SwiftUI) │
└─────────────────────────────────────────────────────────┘
七步 Pipeline(findatahub-core):DAG 编排器,无依赖 Step 用 ThreadPoolExecutor 并行,指数退避重试 + 熔断 + 失败队列 + RerouteRequest 反馈回路(单步≤3 次/全局≤10 次),写 _data_lineage 血缘表。
四级门控(gate.py):
gate1_collection:非空 / 行数≥50%(BLOCK)gate2_cleaning:OHLC 关系、负价 BLOCK、|pct_chg|>11% WARNgate3_ingestion:(ts_code,trade_date)唯一键 + 质量分≥0.60 BLOCK,可 reroute 回 G2gate4_post:日期连续性 >7 天 gap(INFO)
macOS App 功能模块:Dashboard 概览 / AkShare·TuShare 同步控制 / 快讯流 / 定时任务 / 日志归档·日历历史 / 环境检查 / 设置(9 分区)。数据通路:App 不连库,通过 Process 拉起 Scripts/bin/*.py 子进程,读 stdout 的 JSON / tqdm 进度,MySQL 配置经环境变量注入。
快讯子系统:12 源抓取(cls/华尔街见闻/新浪/东财/金十/格隆汇/同花顺/腾讯…)→ 翻译/打标/评分(AI 增强,本地 Ollama)→ 四层去重(source_id 精确 + SimHash 汉明≤12 + TF-IDF 余弦≥0.85)→ 多渠道推送(Bark/飞书/企微/钉钉/Telegram)。
四、发展现状评估
文档层面:P1(采集层)/ P2(预处理层)/ P3(使用层)/ P4(AI 接入)全部标记完成,P5(云端扩展:阿里云同步/Redis/数据血缘/版本管理)为远期规划。文档体系按 pipeline / macos / tracking 三目录组织,较完整。
代码实证层面(探索核对结果):
| 维度 | 现状 | 评价 |
|---|---|---|
| 数据治理链路 | 七步+四级门控+双源交叉验证已落地,AKShare 成交额/单位/涨跌幅等多项修复 | ✅ 完成度高 |
| 重构收敛 | db.py 已收敛到 BaseDatabaseManager(280→30 行),bootstrap.py 移除反向依赖 |
✅ 方向正确 |
| 测试覆盖 | tushare ~169 + akshare ~149 + 快讯后端 262 通过;但 core 仅 8 个、client 0 个、Swift 0 个 | 🟡 严重不均 |
| 安全 | 2026-08-03 已做安全审计并修复;API Key、表名白名单、限流、Keychain 存储 | ✅ 意识到位 |
| 工程一致性 | Python 3.10/3.12/3.14 混用;setuptools/hatchling 两套后端;src/ 与 app/ 双轨 | 🔴 待统一 |
总体判断:核心数据链路已"能用且可信",完成了从"脚本集合"到"有架构的数据平台"的关键一跃。当前处于功能完备但工程债开始显现的阶段——重复代码、测试盲区、超大文件、性能隐患是下一步的主要矛盾。
五、优化方向(按四大维度,均可落地)
🚀 A. 性能提升
-
消除行级 pandas 操作(收益最大)
cross_validator.py:186用merged.iterrows()逐行比对 → 改向量化np.isclose/DataFrame列运算,双源比对数据量大时提速 1–2 个数量级。akshare_fetcher/core/fetcher.py至少 8 处df.apply(..., axis=1)计算 pct_chg → 改为(df['close']/df['pre_close']-1)*100向量化。
-
Pipeline 血缘写入连接复用
pipeline.py每个 Step 的血缘记录都新建 pymysql 连接 → 注入共享连接池或批量 flush,减少高并发 Step 下的连接抖动。
-
并行 Step 的可变 context 竞态
- 并行 Step 共享可变
PipelineContext→ 为每个并行分支传快照/副本,或在 DAG 层明确读写隔离,避免隐蔽的数据竞争。
- 并行 Step 共享可变
-
阻塞式限流
- 两 fetcher 共 10 处
time.sleep→ 改令牌桶 /asyncio非阻塞限流,或至少集中到统一RateLimiter,便于调参与观测。
- 两 fetcher 共 10 处
-
快讯搜索 UNION LIKE
- 多张
news_*表 UNION +LIKE %kw%全表扫描 → 建全文索引(MySQL FULLTEXT)或引入 Meilisearch/ES 轻量检索,并对结果集加 LIMIT 与覆盖索引。
- 多张
-
Rust 加速面扩大
- 现有
rust_core只做批量序列化 → 可顺势把去重 SimHash、双源比对这类 CPU 密集且边界清晰的计算下沉到 Rust,与现有 PyO3 基建复用。
- 现有
🧹 B. 代码质量改进
-
修复已定位的真实 Bug(最优先)
findatahub-client/client.py的stats():COUNT(*)结果赋给df却引用未定义变量row_count→ 运行即 NameError,属上线级缺陷。pipeline.py:300血缘写入失败except: pass静默吞错 → 至少记 structlog 警告。- 快讯
extend/dedup用内置hash()做 SimHash 位映射 →hash()跨进程不稳定(PYTHONHASHSEED 随机化),去重结果不可复现,改hashlib.md5/blake2b。
-
治理超大文件与职责混杂(Swift 端最突出)
SettingsView.swift2467 行、NewsFlashService888 行、PythonProcessManager827 行、DatabaseSetupGuideView806 行 → 按"设置分区 / 进程管理·通知·过滤·健康监控"等职责拆分。AppConstants.swift混入完整 Cron 表达式模型、SyncLogEntry.swift混放 DataSource/DBConfig/AppConfig → 各归其位到独立 Model 文件。NewsFlashService集进程管理+通知+过滤+健康监控于一身 → 拆 4 个单一职责服务。
-
消除强制解包与脆弱解析
try!正则×5、.first!、group.next()!、data(using:)!→ 全部改安全可选绑定或预处理常量。- 用"stdout 含 📡/✅/❌ emoji 判定日志级别"的解析与 Python 输出格式强耦合 → 改为结构化 JSON 行协议(Python 端
structlog输出 JSON,Swift 端解码为 enum),一劳永逸解耦。
-
收口重复逻辑
- MySQL 环境变量注入逻辑在
PythonProcessManager.executeSync/ContentView.checkDatabaseReady/NewsFlashService.runDetachedProcess三处重复 → 统一走PythonPathFinder.dbEnv()。 - 两 fetcher 的
cache.py(规范化后 diff 仅 36 行)、report.py、validator.py、config.py高度雷同 → 仿照db.py的收敛路径下沉 findatahub-core。
- MySQL 环境变量注入逻辑在
-
清理"双轨"与坏入口
- 快讯
pyproject.toml入口脚本指向不存在的kuaixun_service.main→ 修复或删除该 entry point。 src/kuaixun_service/与app/+extend/双轨并存、unified_writer.py两处重复 → 二选一,删除空壳迁移残留。app/main.py用sys.path.inserthack → 改为正式打包安装。
- 快讯
✨ C. 功能扩展
-
补齐 SDK/数据覆盖面(承接 TODO P0 系列)
stock_weekly/stock_monthly/fina_indicator的 clean schema + flow + SDK 方法(client.weekly/monthly/fina_indicator已有签名,需打通迁移)。- 全量历史迁移:tushare 788 万行、akshare 1670 万行入
fin_data_clean,跑通双源交叉验证闭环。
-
统计/相关性/PCA 分析能力产品化
stats.py/correlation.py/pca.py已实现但偏"管道内部件" → 暴露为 SDK/REST 端点,并在 App 增加"数据画像"页,把质量分、分布、冗余特征可视化。
-
快讯子系统的 Web 化与推送增强
- 当前 Web 端强依赖打包 dist 易过期(DEVLOG 已踩坑)→ 加构建版本指纹 + 启动校验。
- 推送渠道可加"重要度阈值 + 免打扰时段"的用户级策略(realtime 已分即时/5min 批量,可再上层配置)。
-
数据血缘可视化
_data_lineage已在写入 → 在 App 或 Web 加血缘图谱页,为 P5 数据血缘治理打底。
-
AI 能力深化
- MCP 已有 7 工具 → 补"质量分查询""跨表联查""自然语言取数→图表"工具;快讯的 AI 评分/总结可统一收口到 Ollama 调用的
/api/chat+think:false范式(DEVLOG 已验证)。
- MCP 已有 7 工具 → 补"质量分查询""跨表联查""自然语言取数→图表"工具;快讯的 AI 评分/总结可统一收口到 Ollama 调用的
🛠 D. 可维护性增强
-
统一工程基线
- Python 版本钉死一个(建议 3.12,两 fetcher 取高),消除 3.10/3.12/3.14 混跑;构建后端统一(建议全 hatchling + uv)。
- 根目录加一个统一编排:
Makefile或justfile/taskfile,把 build / test / lint / run 各子系统一条命令串起来。
-
补齐测试盲区(投入产出比最高)
findatahub-core(门控/编排/重试逻辑)从 8 → 覆盖核心路径;findatahub-client从 0 → 至少 SDK 方法与导出路径。- Swift 端建
testTarget,先测PythonProcessManager的 stdout 解析、Cron 模型、Config/Keychain 读写(当前 0 测试是最大单点风险)。 - 修复现存失败用例:快讯后端 3 failed / 前端 3 failed(含过期断言),让 CI 全绿。
-
引入质量门禁工具链
- Python:
ruff+mypy --strict(tushare 已声明,推广到 core/client/akshare/快讯)+pytest-cov覆盖率阈值。 - Swift:
SwiftLint;前端:eslint+vitest纳入 CI。 - 建 GitHub Actions / GitHub-hosted runner:PR 触发 lint+test,阻止回归。
- Python:
-
依赖与产物治理
.gitignore确认排除node_modules/dist/__pycache__/.build(避免仓内混入构建产物,当前统计噪音很大)。- 根目录的
implementation-report/、kuaixun-architecture-spec/为生成的 HTML 报告 → 移入Docs/reports/归档,保持根目录干净。
-
可观测性统一
- structlog 已铺开 → 定义统一字段规范(trace_id / step / duration_ms / rows),血缘表 + 日志 + HealthMonitor 打通,形成"一次同步可全链路追溯"。
六、落地优先级建议(三步走)
| 阶段 | 目标 | 关键动作 | 预期产出 |
|---|---|---|---|
| 第 1 步(1 周内) | 止血 | 修 client.py stats() Bug、SimHash hash()、血缘静默吞错、快讯坏入口;跑全量历史迁移 | 消除上线级缺陷,数据覆盖闭环 |
| 第 2 步(2–3 周) | 提质 | 行级 pandas 向量化、Swift 超大文件拆分、测试盲区补齐、统一 Python 基线 + CI | 性能与可维护性显著改善,回归有网 |
| 第 3 步(1 月起) | 扩展 | SDK 表类型补全、数据画像/血缘可视化、快讯检索升级、AI 工具深化 → 平滑衔接 P5 云端扩展 | 从"本地数据平台"走向"数据产品" |
一句话总结:FinDataHub 已跨過"能不能用"的门槛,现在的核心是还工程债、补测试网、把已实现的治理与分析能力对外产品化。 先修 Bug、再向量化与拆分、最后扩展,是当前性价比最高的路径。