project-structure-optimization-plan.md 22.3 KB

BettaFish 项目结构分析与优化方案

版本:v1.0
状态:Draft
更新时间:2026-04-01

1. 结论摘要

当前仓库的核心问题不是单一的“目录命名不统一”,而是以下几类问题同时存在:

  • 根目录承担了过多职责,源码、启动入口、脚本、运行时数据、构建产物和临时文件混在一起。
  • 新架构和旧架构并存,app.py + templatesbackend/frontend/SingleEngineApp/、各 *Engine/ 目录同时存在,但边界没有完全收口。
  • 一级目录没有按职责分层,而是按历史演进结果堆叠,导致前端、后端、爬虫、引擎、模型、脚本、输出物难以快速区分。
  • 配置、依赖、构建和运行入口分散,给后续维护、迁移和自动化带来了明显成本。

这意味着优化方案不能只做“改文件夹名字”,而需要同时完成以下四件事:

  • 重建一级目录边界。
  • 收敛启动装配层。
  • 统一配置与工具入口。
  • 将运行时数据和构建产物从源码区彻底隔离。

建议的总方向是:保持“单仓库、单部署单元、模块化单体”的架构,不急于拆成微服务,但要把仓库从“历史堆叠型目录”重构成“按职责分层的工程化目录”。

2. 当前仓库现状

2.1 顶层目录的真实职责

当前顶层目录大致可以分成六类,但它们没有被清晰区分:

类别 当前目录/文件 现状说明
Web 装配层 app.pybackend/templates/static/frontend/frontend/ 既有旧 Flask 模板入口,也有新的 Vue 前端和新的后端 API 模块
分析引擎 InsightEngine/MediaEngine/QueryEngine/ReportEngine/ForumEngine/ 这些才是核心业务能力,但仍直接暴露在仓库根目录
爬虫体系 MindSpider/MindSpider/DeepSentimentCrawling/MediaCrawler/crawler_web.pycrawler_browser_data/ 本体、适配层、浏览器数据和兼容入口混在一起
模型与研究资产 SentimentAnalysisModel/ 更像研究资产或训练资产,而不是当前主应用的一层
工具与脚本 report_engine_only.pyregenerate_latest_*export_pdf.pyscripts/ 一部分脚本仍在根目录,一部分已经进入 scripts/
运行时产物 logs/final_reports/*_streamlit_reports/output/db_data/.codex-tmp-* 与源码处于同一级目录,持续污染仓库根目录

2.2 体量分布暴露出的结构问题

按当前工作区统计,几个最显著的目录如下:

  • crawler_browser_data/:约 337 MB
  • SentimentAnalysisModel/:约 177 MB
  • frontend/:约 116 MB
  • db_data/:约 48 MB
  • static/:约 35 MB
  • ReportEngine/:约 32 MB
  • MindSpider/:约 28 MB
  • output/:约 19 MB

其中尤其值得注意的是:

  • frontend/ 的体量几乎全部来自本地 node_modules/,约 116 MB
  • static/frontend/ 是构建产物,当前约 24 MB
  • crawler_browser_data/db_data/output/ 都属于运行时数据,不应该继续与源码同级放置。

这说明当前仓库的“视觉复杂度”有很大一部分不是业务源码造成的,而是运行时目录、构建产物和本地依赖目录没有被隔离。

3. 主要结构性问题

3.1 一级目录不是按职责划分,而是按历史演进堆叠

当前一级目录同时存在:

  • 业务引擎目录:QueryEngine/MediaEngine/InsightEngine/ReportEngine/ForumEngine/
  • 新增平台目录:backend/frontend/docs/scripts/
  • 旧单页/单引擎入口:SingleEngineApp/
  • 爬虫侧目录:MindSpider/
  • 模型目录:SentimentAnalysisModel/
  • 运行目录:logs/output/final_reports/db_data/

这会带来两个直接问题:

  • 新人无法在 30 秒内判断“主应用代码到底在哪里”。
  • 任何新功能都很容易继续往根目录堆。

3.2 命名规范混用,降低可读性和迁移一致性

当前顶层目录命名风格同时包含:

  • PascalCase:QueryEngineMediaEngineMindSpiderSingleEngineApp
  • lowercase:backendfrontendscriptstests
  • snake_case:crawler_browser_dataquery_engine_streamlit_reports

这会导致:

  • 路径扫描时很难快速形成稳定心智模型。
  • 跨平台时更容易出现大小写、导入和路径映射问题。
  • 未来继续迁移时,目录命名没有统一规则可依。

3.3 根目录承担了超级入口角色

app.py 当前不只是 Web 入口,它同时承担:

  • Flask 应用创建
  • Blueprint 注册
  • Streamlit 子进程生命周期管理
  • ForumEngine 生命周期管理
  • 系统启动/关闭装配
  • 健康检查
  • 路由定义
  • 前端静态入口兜底

这意味着当前根目录其实在扮演“平台装配层”,但它没有被明确建模为一个独立应用层。

3.4 新旧前端/后端结构并存,但边界未完全闭合

当前平台已经明显在向“Vue 前端 + Flask API + 引擎装配层”演进:

  • frontend/ 已经是完整的 Vue 3 + Vite + TypeScript 工程。
  • backend/ 已经开始承接配置、研究任务、爬虫 API。
  • templates/index.html 仍保留旧兜底页面。
  • static/frontend/ 仍作为前端构建产物目录。
  • crawler_web.py 已退化为兼容层。

这说明项目方向是对的,但收口还没做完:

  • 旧入口仍在根目录。
  • 新应用层还没有成为唯一事实来源。
  • 构建产物目录仍暴露在源码树中。

3.5 配置层分裂

当前配置体系至少有四层:

  • 根配置:config.py
  • 引擎内配置:InsightEngine/utils/config.pyMediaEngine/utils/config.pyQueryEngine/utils/config.pyReportEngine/utils/config.py
  • 爬虫配置:MindSpider/config.py
  • 外部子项目配置:MindSpider/DeepSentimentCrawling/MediaCrawler/config/*

更复杂的是,代码对这些配置的使用并不统一:

  • 有的模块直接依赖根 config.py
  • 有的模块依赖本引擎的 utils/config.py
  • 新增 backend/config_admin.py 又直接负责 .env 写入

最终问题是:

  • 配置来源不单一。
  • 配置责任边界不清晰。
  • 修改配置时,开发者无法立即判断影响范围。

3.6 依赖管理分裂

当前依赖管理至少存在以下几套:

  • requirements.txt
  • MindSpider/requirements.txt
  • MindSpider/DeepSentimentCrawling/MediaCrawler/requirements.txt
  • MindSpider/DeepSentimentCrawling/MediaCrawler/pyproject.toml
  • frontend/package.json

其中根 requirements.txt 还同时混入了:

  • Web 服务依赖
  • 爬虫依赖
  • ML 推理依赖
  • PDF 依赖
  • 开发依赖

这会带来:

  • 安装链路重。
  • Docker 镜像构建时间长。
  • 很难区分生产依赖和开发依赖。
  • 很难判断某个子模块是否真的属于主运行链路。

3.7 外部子项目与主仓库耦合过深

MindSpider/DeepSentimentCrawling/MediaCrawler/ 目前是一个 Git 子模块,并且它自己就是一个完整项目,拥有:

  • 自己的 .git
  • 自己的配置
  • 自己的测试
  • 自己的依赖
  • 自己的运行入口

但当前主仓库又直接依赖它的 web_runtime.py 和目录结构。
这会让主仓库结构长期处于一种“外部项目已被内嵌使用,但又没有被真正封装”的状态。

3.8 脚本入口散落,缺少统一工具层

当前脚本入口散落在两层:

  • 根目录脚本:report_engine_only.pyregenerate_latest_html.pyregenerate_latest_md.pyregenerate_latest_pdf.pyexport_pdf.py
  • scripts/reports/export_pdf.py

其中 export_pdf.py 已经只是一个 thin wrapper,这说明项目实际上已经开始往 scripts/ 迁移,但没有彻底完成。

3.9 运行时目录与源码混放

当前仓库根目录直接暴露了大量运行期目录:

  • logs/
  • final_reports/
  • insight_engine_streamlit_reports/
  • media_engine_streamlit_reports/
  • query_engine_streamlit_reports/
  • output/
  • crawler_browser_data/
  • db_data/
  • .codex-tmp-mediacrawler*

这些目录会持续造成:

  • 根目录噪音极大
  • Docker volume 与源码路径纠缠
  • Git ignore、docker ignore、备份和清理策略难统一

3.10 自动化和测试边界偏弱

当前自动化现状更偏“镜像发布”,而不是“代码质量守门”:

  • .github/workflows/docker_ci.yml 主要负责打镜像
  • 测试主要集中在 tests/ 下的 ForumEngine 日志解析与部分 ReportEngine 结构校验
  • 缺少统一 lint、type-check、前端测试、后端 API 测试、端到端测试流程

这会直接提高后续大规模目录调整的风险。

4. 优化目标

本次结构优化建议遵循以下目标:

4.1 保持单仓库、单部署单元

当前项目虽然模块多,但仍更适合“模块化单体”而不是微服务。

原因:

  • 引擎之间耦合非常紧。
  • Docker 部署链路已经围绕单应用构建。
  • 配置、任务、日志、报告都集中在一个平台里。

因此不建议在本轮优化中拆成多个服务仓库。

4.2 一级目录必须只表达职责,不表达历史来源

一级目录应只回答一个问题:
“这块内容属于哪一类职责?”

建议只保留少数顶层职责:

  • apps/
  • services/
  • tools/
  • infra/
  • docs/
  • tests/
  • var/.local/
  • vendor/research/

4.3 源码、构建产物、运行时数据彻底分离

这是本次优化最重要的约束之一。

必须做到:

  • frontend/node_modules/ 不进入源码结构讨论。
  • static/frontend/ 视为构建产物,而不是应用源码目录。
  • crawler_browser_data/db_data/logs/ 等统一下沉到运行目录。

4.4 新 Web 平台成为主装配层,旧入口逐步兼容退出

当前方向已经很明确,应将:

  • frontend/
  • backend/
  • app.py

收敛成“平台应用层”。
旧的 templates/index.htmlcrawler_web.py、根目录 wrapper 脚本应改为兼容层或迁移后删除。

4.5 配置必须单一事实来源

目标不是删除所有局部配置,而是建立清晰规则:

  • 全局环境配置:一处统一定义
  • 引擎局部配置:仅保留运行参数,不重复环境变量模型
  • 外部子项目配置:通过适配层注入,不直接向上扩散

5. 建议的目标目录结构

建议按“应用层 / 业务服务层 / 工具层 / 基础设施 / 运行数据”重组:

BettaFish/
├── apps/
│   ├── web_api/
│   │   ├── app/
│   │   │   ├── api/
│   │   │   ├── orchestration/
│   │   │   ├── sockets/
│   │   │   └── templates/
│   │   └── main.py
│   ├── web_ui/
│   │   ├── src/
│   │   ├── package.json
│   │   └── vite.config.ts
│   └── engine_console/
│       ├── insight_streamlit_app.py
│       ├── media_streamlit_app.py
│       └── query_streamlit_app.py
├── services/
│   ├── engines/
│   │   ├── insight_engine/
│   │   ├── media_engine/
│   │   ├── query_engine/
│   │   ├── report_engine/
│   │   └── forum_engine/
│   ├── crawler/
│   │   ├── mindspider/
│   │   └── mediacrawler_adapter/
│   └── shared/
│       ├── config/
│       ├── llm/
│       ├── logging/
│       ├── storage/
│       └── utils/
├── tools/
│   ├── reports/
│   ├── dev/
│   └── migrations/
├── infra/
│   └── docker/
│       ├── Dockerfile
│       ├── Dockerfile.runtime-hotfix
│       ├── docker-compose.yml
│       └── docker-compose.override.yml
├── docs/
├── tests/
│   ├── unit/
│   ├── integration/
│   └── e2e/
├── vendor/
│   └── mediacrawler/
├── research/
│   └── sentiment_models/
└── var/
    ├── logs/
    ├── reports/
    ├── crawler/
    ├── db/
    └── output/

6. 当前目录到目标目录的映射建议

6.1 应用层

当前路径 建议目标 说明
app.py apps/web_api/main.py 保留为平台主入口,但职责缩减为装配和启动
backend/ apps/web_api/app/api/ 现有 Blueprint 直接归入 Web API 应用层
templates/index.html apps/web_api/app/templates/frontend_fallback.html 只保留兜底,不再放根模板目录
frontend/ apps/web_ui/ 成为正式前端应用目录
SingleEngineApp/ apps/engine_console/ 标注为 legacy/辅助入口,而非主产品层

6.2 业务服务层

当前路径 建议目标 说明
InsightEngine/ services/engines/insight_engine/ 统一转为 snake_case
MediaEngine/ services/engines/media_engine/ 同上
QueryEngine/ services/engines/query_engine/ 同上
ReportEngine/ services/engines/report_engine/ 同上
ForumEngine/ services/engines/forum_engine/ 同上
utils/ services/shared/utils/ 公共工具不再悬挂根目录
config.py services/shared/config/settings.py 作为全局配置唯一事实来源

6.3 爬虫层

当前路径 建议目标 说明
MindSpider/ services/crawler/mindspider/ 主仓库维护的爬虫服务代码
MindSpider/DeepSentimentCrawling/MediaCrawler/ vendor/mediacrawler/services/crawler/vendor/mediacrawler/ 明确它是外部依赖,不与主仓库内部层级混淆
crawler_web.py 删除或并入 apps/web_api/app/api/crawler.py 当前已是兼容层,应尽快收口

6.4 工具与脚本层

当前路径 建议目标 说明
report_engine_only.py tools/reports/report_engine_only.py 明确为运维/调试工具
regenerate_latest_html.py tools/reports/regenerate_latest_html.py 同上
regenerate_latest_md.py tools/reports/regenerate_latest_md.py 同上
regenerate_latest_pdf.py tools/reports/regenerate_latest_pdf.py 同上
export_pdf.py 保留 wrapper 或删除 如果保留,只做过渡兼容
scripts/ tools/ 正式成为工具层,而非零散脚本层

6.5 基础设施与运行数据

当前路径 建议目标 说明
Dockerfile*docker-compose*.yml infra/docker/ 所有部署文件集中
logs/ var/logs/ 运行日志目录
final_reports/ var/reports/final/ 报告产物目录
*_streamlit_reports/ var/reports/engines/* 引擎中间产物目录
crawler_browser_data/ var/crawler/browser_data/ 浏览器会话和缓存目录
db_data/ var/db/postgres/ 数据卷目录
output/ var/output/ 临时输出目录
static/frontend/ 前端构建目录,不入库 由构建流程生成并复制到镜像中
frontend/node_modules/ 本地依赖,不入库 不应成为结构讨论的一部分

6.6 研究资产

当前路径 建议目标 说明
SentimentAnalysisModel/ research/sentiment_models/ 如果长期保留,建议视作研究资产而不是主应用目录

7. 配置与依赖的重构建议

7.1 配置重构

建议分三层:

  1. 全局环境配置
    统一放在 services/shared/config/settings.py

  2. 模块运行参数
    各引擎只保留本模块运行参数,如超时、默认 limit、输出目录等,不再重复声明所有环境变量

  3. 外部子项目配置适配
    MediaCrawler 等外部项目的配置由适配层注入,主仓库不直接依赖其内部配置结构

建议规则:

  • .env 的读写只允许经过统一配置层。
  • backend/config_admin.py 后续改为调用共享配置服务,而不是直接写散落的环境模型。
  • 引擎内 utils/config.py 最终只保留兼容 wrapper,逐步废弃。

7.2 依赖重构

建议中期统一为:

  • Python 主依赖:根 pyproject.toml 或分层 requirements/
  • 前端依赖:apps/web_ui/package.json
  • 外部子模块依赖:保持独立,但通过 adapter 隔离

如果不希望一次性切到 pyproject.toml,也至少应拆分:

  • requirements/base.txt
  • requirements/web.txt
  • requirements/crawler.txt
  • requirements/ml.txt
  • requirements/dev.txt

这样可以减少:

  • 本地安装成本
  • Docker 层缓存失效率
  • 不必要的生产镜像体积

8. 命名规范建议

建议统一为以下规则:

8.1 一级目录

  • 使用 lowercase_snake_caselowercase-kebab-case
  • 本项目更推荐 lowercase_snake_case,因为与 Python 包命名更一致

8.2 Python 包目录

  • 全部使用 snake_case
  • 避免 PascalCase 目录名

8.3 前端目录

  • 应用级目录使用 snake_case
  • Vue 组件文件继续保持 PascalCase.vue 可以接受

8.4 运行时目录

  • 统一放在 var/
  • 不再出现 *_reportsdb_datacrawler_browser_data 这种散落根目录的命名

9. 分阶段实施方案

Phase 0:先清场,不改业务逻辑

目标:先让仓库根目录恢复可控状态。

建议动作:

  • 扩充 .gitignore.dockerignore
  • 明确 var/ 目录方案
  • 停止将 frontend/node_modules/static/frontend/.codex-tmp-* 视为源码内容
  • 新增一份目录规范文档

交付结果:

  • 根目录只保留真正的源码和工程文件
  • 运行数据和构建产物开始分流

优先级:P0

Phase 1:建立新的一级目录骨架

目标:把“前端、后端、引擎、工具、基础设施”先分层放好。

建议动作:

  • 建立 apps/services/tools/infra/var/
  • frontend/ 迁移到 apps/web_ui/
  • backend/ 和根 app.py 装配层迁移到 apps/web_api/
  • SingleEngineApp/ 迁移到 apps/engine_console/
  • 将根目录脚本统一迁移到 tools/reports/

交付结果:

  • 一级目录职责变清晰
  • 根目录不再是“超级杂物层”

优先级:P0

Phase 2:收敛核心服务层

目标:把引擎、共享能力和配置层放进统一服务结构。

建议动作:

  • 将所有 *Engine 迁移到 services/engines/*
  • 抽取 services/shared/config/
  • 抽取 services/shared/llm/
  • 抽取 services/shared/utils/
  • 对旧导入路径增加临时兼容 shim

交付结果:

  • 核心服务目录统一
  • 配置与共享逻辑不再散落

优先级:P0

Phase 3:重构爬虫边界

目标:把主仓库爬虫代码和外部子项目边界拉清。

建议动作:

  • MindSpider/ 迁入 services/crawler/mindspider/
  • MediaCrawler 子模块迁入 vendor/mediacrawler/
  • 新建 services/crawler/mediacrawler_adapter/
  • 平台其余模块只允许通过 adapter 调用爬虫能力

交付结果:

  • 外部项目不再污染主目录结构
  • 后续升级 MediaCrawler 风险更低

优先级:P1

Phase 4:统一工具链和自动化

目标:让仓库具备结构调整后的工程化保障。

建议动作:

  • 建立统一测试入口
  • 增加前端 type-check
  • 增加 Python lint / format / test
  • 增加 API 集成测试
  • 将 GitHub Actions 从“只打镜像”升级为“先校验,再打镜像”

交付结果:

  • 结构迁移可持续推进
  • 重构风险可被自动化守住

优先级:P1

Phase 5:研究资产与主应用解耦

目标:降低主应用维护噪音。

建议动作:

  • 评估 SentimentAnalysisModel/ 是否仍属于主运行链路
  • 如果主要用于研究和训练,迁入 research/
  • 如长期独立演进,可考虑单独仓库或子模块化

交付结果:

  • 主应用和研究资产边界更清晰

优先级:P2

10. 推荐的实施顺序

建议不要一次性“大搬家”,而采用以下顺序:

  1. 先做运行目录隔离和 ignore 规则收口。
  2. 再建立 apps/services/tools/infra/var/ 的新骨架。
  3. 先迁移脚本和前后端目录,再迁移引擎目录。
  4. 配置收敛与 import shim 在同一阶段完成,避免大面积导入失效。
  5. 最后处理爬虫子模块和研究资产。

这样可以把风险控制在“每一步都可运行、可回滚、可验证”的范围内。

11. 本轮优化中不建议做的事

为了降低风险,本轮不建议同时做以下动作:

  • 不建议一边改目录,一边重写全部业务逻辑。
  • 不建议现在就拆成多个部署服务。
  • 不建议现在就把 Flask 完全替换成别的后端框架。
  • 不建议立即把 MediaCrawler 代码完全吸收到主仓库内部。
  • 不建议在没有自动化保护前,直接全量 rename 所有目录和 import。

12. 建议优先落地的 10 个动作

P0

  • 建立 var/ 目录,并把 logs/final_reports/output/crawler_browser_data/db_data/ 的挂载路径统一过去。
  • 扩充 .gitignore.dockerignore,明确忽略 frontend/node_modules/static/frontend/.codex-tmp-* 等目录。
  • 创建 apps/web_api/,把当前 app.py 的装配逻辑迁入。
  • 创建 apps/web_ui/,将 frontend/ 定位为正式前端应用目录。
  • 把根目录脚本迁移到 tools/reports/,根目录只保留过渡 wrapper 或彻底删除。

P1

  • 建立 services/engines/ 并逐步迁移 *Engine/ 目录。
  • 建立 services/shared/config/,统一配置模型与 .env 读写。
  • backend/ 的配置管理只调用共享配置服务,不直接分散控制。
  • SingleEngineApp/ 改名并迁入 apps/engine_console/
  • 将 Docker 相关文件迁入 infra/docker/,统一部署入口。

13. 最终收益

完成本方案后,仓库会获得以下收益:

  • 新人能快速分辨“产品应用、业务服务、爬虫、工具、运行数据”。
  • 目录命名统一后,代码搜索、导航和迁移成本明显下降。
  • 前后端、引擎、脚本和运行产物之间的边界更清晰。
  • Docker、配置、脚本和自动化入口更容易标准化。
  • 后续继续推进“场馆运营研究平台”时,不会再被旧目录结构持续拖累。

14. 推荐决策

如果只做一件事,最值得先做的是:

先完成一级目录重组方案和运行时目录下沉,再开始下一轮业务开发。

原因很简单:

  • 现在业务还在快速演进期。
  • 如果继续在当前结构上叠功能,后续迁移成本只会更高。
  • 当前已经具备足够清晰的新平台方向,正是适合做结构收口的时间点。