PanWatch AI 盯盘后端架构边界测试:用 test_architecture_boundaries 守卫模块化单体的完整指南
【免费下载链接】PanWatchPanWatch — AI stock monitoring for A-shares, HK & US markets, powered by TradingAgents. Portfolio insights, real-time alerts & automated reports.|盯盘侠:覆盖 A股/港股/美股的 AI 盯盘、持仓分析、实时提醒与自动报告。项目地址: https://gitcode.com/GitHub_Trending/pa/PanWatch
PanWatch(盯盘侠)是一款覆盖 A股/港股/美股的 AI 盯盘工具,提供持仓分析、实时提醒与自动报告。很多读者只关注它的前端界面,但真正让这个项目长期可维护的,是它后端的模块化单体架构和一套用测试写死的架构边界规则——tests/test_architecture_boundaries.py。本文带你读懂这套守卫机制:为什么需要它、检查了哪些规则、如何运行,让你在任何大型 Python 项目中都能借鉴这一思路。
为什么 PanWatch 选择模块化单体?
PanWatch 后端是典型的模块化单体:只有一个 FastAPI 应用、一个共享数据库,但代码按稳定的业务边界组织,目标是避免重新出现无边界的“大杂烩”core目录。
整体目录结构只有四层,依赖方向自上而下:
| 目录 | 职责 | 关键约束 |
|---|---|---|
src/bootstrap/ | 应用启动与依赖装配 | 唯一创建 FastAPI 应用的地方 |
src/platform/ | 行情、AI、通知、持久化等技术能力 | 不得导入任何业务模块 |
src/modules/ | 市场、持仓、研究、策略等业务能力 | 不得跨模块导入他人models/repository/api |
src/web/ | 跨模块复用的 HTTP 中间件 | 不承载业务 SQL 或 Agent 循环 |
依赖方向的完整说明见 src/ARCHITECTURE.md。核心原则只有一句话:跨模块协作必须经过对方公开的 service,而不是绕过它去摸对方的数据库模型。
test_architecture_boundaries 到底检查什么?
test_architecture_boundaries.py 用 Python 的ast模块静态扫描全部源码的 import 语句,把架构规则变成了机器可执行的断言。它主要守卫三类问题:
1. 依赖方向不反向
- 扫描
src/platform/下所有.py文件,任何一处import src.modules...都会被记录为违规; - 扫描
src/modules/下每个模块,跨模块 import 目标若落在另一模块的models、repository或api(*_api.py)上,直接判定违规。
这意味着“strategy 想偷懒直接读 portfolio 的仓位表”这种代码,在 CI 里就会被红牌罚下。
2. 遗留目录不得复活
迁移期结束后,守卫测试会断言一批旧路径必须不存在:
src/core/、src/agents/、src/web/database.py、src/web/models.py、src/web/migrations.py(见 tests/test_architecture_boundaries.py#L60-L71);- 已收口的根级
collectors/、models/、compat/也不允许重建; - 过渡期的 facade(如
modules/assistant/models.py)禁止重新引入(tests/test_architecture_boundaries.py#L101-L107)。
这类“反向断言”非常巧妙:它防的不是当前错误,而是未来的回退。
3. 装配与边界位置唯一化
src/bootstrap/application.py必须存在且是唯一的应用工厂,旧的src/web/app.py不允许存在;- 业务 router 必须归各模块自己的
api/包,禁止出现第二个业务分层src/web/api/; - 横切能力必须落在对应平台目录:配置在 src/platform/runtime/config.py、日志在 src/platform/observability/log_handler.py、行情缓存表在 src/platform/marketdata/stock_list.py。
配套守卫:模块所有权与 pre-push 钩子
边界测试只解决“谁不能碰谁”,还有两个搭档补齐防线:
- 模块所有权测试:tests/test_module_ownership.py 逐一断言关键实现必须位于指定模块内,例如行情告警引擎必须在 src/modules/market/price_alert_engine.py、TradingAgents 实现必须整体留在 src/modules/automation/tradingagents/。它防止实现文件在重构中“漂走”。
- pre-push 钩子:通过
make install-hooks(脚本见 scripts/pre-push)安装后,每次git push前会自动跑pytest tests/ -x -q,失败即中止推送——架构守卫因此成为开发流的强制卡点,而不是一次性的检查。
如何运行架构边界测试?
在仓库根目录准备虚拟环境后即可运行(详见 CONTRIBUTING.md 的 Validation 章节):
python3 -m venv .venv .venv/bin/pip install -r requirements.txt # 只跑架构守卫(秒级完成) .venv/bin/python -m pytest tests/test_architecture_boundaries.py tests/test_module_ownership.py -v # 或跑全量后端测试 .venv/bin/python -m pytest tests/ -v也可以直接用 Makefile 的make test一键执行。架构守卫测试不依赖数据库、不发起网络请求,纯静态扫描,几秒就能给整个src/目录的依赖健康度“体检”。
对普通开发者的三点启发 🧭
- 把架构规则写成测试,而不是写在文档里:文档会过时,
assert不会。规则变更时同步更新测试与 ARCHITECTURE.md 即可,形成“文档 + 测试”双份契约。 - 用“禁止复活”断言保护重构成果:对已经删除的坏结构做反向存在性检查,比正向检查更能防止腐化回潮。
- 静态扫描足够轻量:基于
ast的 import 扫描无需运行应用、无需外部依赖,非常适合作为 pre-push / CI 的第一道闸门。
PanWatch 用不到 150 行测试代码(tests/test_architecture_boundaries.py + tests/test_module_ownership.py),就为整个 AI 盯盘后端建立了清晰的模块边界与依赖方向。如果你的项目也在单体架构下管理多个业务域,这套“架构即测试”的做法值得直接抄作业。
【免费下载链接】PanWatchPanWatch — AI stock monitoring for A-shares, HK & US markets, powered by TradingAgents. Portfolio insights, real-time alerts & automated reports.|盯盘侠:覆盖 A股/港股/美股的 AI 盯盘、持仓分析、实时提醒与自动报告。项目地址: https://gitcode.com/GitHub_Trending/pa/PanWatch
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考