24 KiB
geMoldInsight 后端模块化重构蓝图
目标:在同一 Git 仓库、同一数据库前提下,将当前代码结构整理为可独立部署的多模块架构,明确 gemold、inventory、frontend 的边界与演进路径。本文档是后续实施的权威蓝图,不是历史记录。
1. 背景与目标
当前项目已经从早期单体演进为“双应用 + 共享层”的形态:
- 业务模块:
src/moldinsight/、src/inventory/ - 共享层:
src/shared/ - 部署入口:
src/entrypoints/moldinsight.py、src/entrypoints/inventory.py - 前端工程:
frontend/
从代码现状看,moldinsight 与 inventory 已基本无直接互引,说明模块边界已经初步形成;但同时,数据库模型、认证、配置、应用工厂等仍集中在 shared/,导致当前更接近“模块化中的单体”,而不是“可独立部署的模块化单体”。
本次蓝图的目标不是拆库、拆仓、微服务化,而是:
- 保持单仓库(monorepo)
- 保持单数据库
- 将后端正式整理为多个模块:
- gemold(模具分析 / moldinsight)
- inventory(进销存)
- identity / platform(共享基础设施与认证)
- 保持前端为独立模块工程,并增强其对多部署模式的兼容
- 支持三种部署模式:
- unified:gemold + inventory 同时部署
- gemold-only:仅部署 gemold
- inventory-only:仅部署 inventory
2. 范围与非目标
2.1 本次蓝图覆盖范围
- 后端模块边界
- 共享层职责重新定义
- 单数据库下的模型归属与表所有权
- 独立部署模式设计
- 前端 API 边界强化策略
- 分阶段迁移路径
- 风险与验证方法
2.2 非目标
本蓝图不包含以下方向:
- 多 Git 仓库拆分
- 多数据库拆分
- 分布式微服务重构
- 全量 DDD 重写
- 全量前端重构
- 事件驱动或消息总线主导的跨服务通信改造
换句话说,目标架构是:
单仓库 + 单数据库 + 多模块 + 可独立部署的 modular monolith
而不是微服务系统。
3. 当前架构快照
3.1 后端现状
当前核心目录结构如下:
src/
entrypoints/
moldinsight.py
inventory.py
shared/
app_factory.py
config/
database/
models/
services/
utils/
moldinsight/
api/
core/
services/
storage/
inventory/
api/
schemas/
services/
其中:
- app_factory.py 已统一 CORS、日志中间件、startup/shutdown、认证路由、健康检查与 SPA fallback。
- moldinsight.py 与 inventory.py 已提供独立入口。
- database.py 同时包含 identity、moldinsight、inventory 三类模型,是当前最强耦合点。
3.2 前端现状
前端已是独立 Vite/Vue 工程:
frontend/
src/
modules/
moldinsight/
inventory/
login/
users/
home/
router/
shared/
stores/
types/
特点:
- 已按页面/业务模块组织
- 已有共享 API 层雏形:api-client.ts
- 已接入 OpenAPI 生成类型:api.ts
- 当前仍有大量相对路径
/api/...与 rawfetch()的同源假设
3.3 现状判断
当前架构可概括为:
HTTP 入口已分离,业务代码已分组,但平台层与数据层仍共享。
因此,它适合继续朝“可独立部署的模块化单体”演进,而不适合直接跳到微服务。
4. 目标架构:可独立部署的模块化单体
4.1 架构原则
目标态采用以下原则:
- 组合优先于复制:不同部署模式通过组合不同模块得到,而不是复制多套代码。
- 平台与业务分离:
platform只承载技术性共享能力,不继续承载业务逻辑。 - 模块所有权清晰:每张表、每条 API、每个服务类都应有明确归属。
- 单数据库但显式边界:允许共享 DB,但不允许“共享数据库 = 没有边界”。
- 统一前端,兼容多后端部署形态:前端继续是一套工程,通过 API client 适配 unified / split deployment。
4.2 架构定位
目标架构不是“多个服务各自拥有数据库”的微服务,而是:
- 同一个仓库
- 同一个数据库
- 多个模块
- 多个部署入口
- 同一套迁移历史
- 同一套共享基础设施能力
这是一种适合当前项目阶段的治理性重构,而不是组织级拆分。
5. 目标目录结构
以下结构是目标态,不要求一次性到位:
src/
platform/
app/
app_factory.py
lifecycle.py
middleware/
config/
auth/
database/
engine.py
session.py
migrations/
observability/
contracts/
api/
events/
shared_kernel/
types/
exceptions/
utils/
modules/
moldinsight/
application/
services/
use_cases/
domain/
models/
policies/
repositories/
infrastructure/
persistence/
storage/
adapters/
interfaces/
api/
schemas/
module.py
inventory/
application/
services/
use_cases/
domain/
models/
policies/
repositories/
infrastructure/
persistence/
adapters/
interfaces/
api/
schemas/
module.py
identity/
application/
domain/
infrastructure/
interfaces/
module.py
compositions/
unified_app.py
gemold_app.py
inventory_app.py
legacy/
main.py
5.1 当前目录到目标目录的映射
| 当前路径 | 目标路径 | 说明 |
|---|---|---|
src/shared/* |
src/platform/* |
共享基础设施重新命名与归位 |
src/moldinsight/* |
src/modules/moldinsight/* |
gemold 业务模块 |
src/inventory/* |
src/modules/inventory/* |
inventory 业务模块 |
src/entrypoints/* |
src/compositions/* |
部署组合层 |
src/main.py |
src/legacy/main.py |
过渡期兼容入口 |
5.2 为什么要引入 compositions/
当前 entrypoints/ 已经承担“部署入口”角色,但语义更偏“启动文件”。
引入 compositions/ 的意义是明确:
- 它不是业务模块
- 它不是平台能力
- 它是“按部署模式装配模块”的组合层
例如:
gemold_app.py:平台 + identity + moldinsightinventory_app.py:平台 + identity + inventoryunified_app.py:平台 + identity + moldinsight + inventory
6. 模块职责边界
6.1 platform
platform 是技术共享层,只承载跨模块公共基础设施能力。
归属范围
- app factory / middleware / 生命周期
- config
- 数据库 engine / session / Alembic 接线
- auth / JWT / 权限
- 日志 / request_id / observability
- 通用 contracts / utilities
可复用现有实现
规则
platform 不得继续吸收业务规则代码,否则新的 platform 会变成旧的 shared。
6.2 moldinsight(gemold)
moldinsight 模块负责模具分析、几何处理和分析结果生命周期。
归属范围
- 上传、任务、历史、批量分析、成本估算、CAM、分析结果
- 几何分析、特征检测、模具方案、报告
- RustFS / 对象存储接入
- Celery 异步处理链路
可复用现有实现
- moldinsight/api/__init__.py
- processing_service.py
- task_query_service.py
- moldinsight/core/
- celery_app.py
- celery_tasks.py
6.3 inventory
inventory 模块负责 ERP / 进销存类业务流程。
归属范围
- 产品、物料、供应商、客户、仓库
- 库存、库存流水
- 销售订单、采购订单、财务、采购建议
- BOM / 采购需求推导
可复用现有实现
- inventory/api/__init__.py
- inventory_service.py
- sales_order_service.py
- purchase_order_service.py
- finance_service.py
6.4 identity
identity 负责用户、角色、权限与认证授权。
归属范围
- User / Role / Permission
- 登录、鉴权、管理员接口
- 统一授权能力
在物理目录上,identity 可以先靠近 platform;但逻辑上应从一开始就被视为独立边界,而不是“moldinsight 的一部分”或“inventory 的一部分”。
7. 允许的依赖方向
这是本蓝图最重要的治理规则之一。
7.1 依赖规则
compositions -> platform
compositions -> modules/*
platform -> 不依赖业务模块
modules/*/interfaces -> modules/*/application
modules/*/application -> modules/*/domain
modules/*/infrastructure -> modules/*/domain
modules/*/interfaces -> platform
modules/*/infrastructure -> platform
7.2 跨模块约束
inventory不能直接 importmoldinsight.api/moldinsight.servicesmoldinsight不能直接 importinventory.api/inventory.servicesplatform不得依赖任一业务模块- 跨模块协作只能通过:
- 显式 contract / query service
- composition wiring
- 受控的共享数据库引用
7.3 当前代码与规则的差距
从代码检查看,当前 moldinsight 与 inventory 基本没有直接互引,这说明上述规则在业务代码层已经接近成立。
当前主要问题集中在:
- database.py 集中承载所有 ORM 模型
- app_factory.py 同时知道通用平台逻辑与 moldinsight 专属 startup 行为
因此,后续实施的重点不是“切断业务模块互引”,而是“把共享层与数据层的边界拉直”。
8. 单数据库下的模型与表归属策略
8.1 核心原则
数据库继续保持为一个 PostgreSQL 数据库,但代码中的模型归属必须显式化。
也就是说:
数据库不拆,模型归属要拆。
8.2 当前最强耦合点
当前 database.py 同时包含:
- identity / 平台相关模型
- moldinsight 业务模型
- inventory 业务模型
这会带来两个问题:
- 代码层看不出模型所有权
- 开发者更容易跨模块直接访问整套 ORM 图谱
因此,后续实施应优先将这个文件按归属拆分。
8.3 推荐表归属矩阵
platform / identity-owned
- users
- roles
- permissions
- user_roles
- role_permissions
- (可选)system_logs
moldinsight-owned
- stp_files
- geometry_data
- mesh_data
- html_files
- processing_tasks
- mold_cavity_data
- feature_detections
- design_recommendations
- analysis_metrics
inventory-owned
- products
- product_materials
- material_price_history
- material_suppliers
- suppliers
- customers
- warehouses
- inventory
- stock_movements
- purchase_orders
- purchase_order_items
- sales_orders
- sales_order_items
- finance_transactions
- finance_allocations
8.4 目标代码形态
推荐逐步演进到:
platform/database/base.py
modules/identity/infrastructure/persistence/models.py
modules/moldinsight/infrastructure/persistence/models.py
modules/inventory/infrastructure/persistence/models.py
同时保持:
- 同一个 SQLAlchemy
Base - 同一个 metadata
- 同一条 Alembic 历史链
- 同一个数据库连接
8.5 跨模块 FK 的处理策略
当前存在真实跨模块业务桥:
STPFile.product_id -> Product.id
这是合理的,因为它反映了真实业务关系:模具分析结果可以创建成品,并与 inventory 中的产品建立连接。
原则上允许保留这类稳定 FK,但应遵守:
- 跨模块 FK 是业务桥,不是“任意跨模块查询”的许可
- 模块之间应逐步通过 query service / repository contract 暴露需要的读取能力
- 避免一个模块直接依赖另一个模块的整套 ORM 图谱
9. 部署模式设计
本项目必须支持三种部署模式。
9.1 unified
组成
- platform + identity + moldinsight + inventory
适用场景
- 本地开发
- 小团队部署
- 集成环境
- 一体化业务场景
说明
新的 unified 组合层应接替旧 main.py 的语义,但应通过 compositions/unified_app.py 的方式实现,而不是继续维持旧单体式入口。
9.2 gemold-only
组成
- platform + identity + moldinsight
适用场景
- 仅开放模具分析能力
- 分析服务独立扩容
- 单独部署算法/文件处理能力
说明
- 只暴露 gemold 路由
- 可保留对共享数据库中
products的受控引用 - RustFS / Celery 等专属基础设施只在该模式启用
当前入口基线:
9.3 inventory-only
组成
- platform + identity + inventory
适用场景
- 仅提供 ERP / 进销存能力
- 不需要模具分析链路的后台场景
说明
- 只暴露 inventory 路由
- 不要求启动 RustFS 等 moldinsight 专属基础设施
当前入口基线:
9.4 当前共享工厂的边界问题
需要特别指出:当前 app_factory.py 通过 mount_html=True 分支初始化 RustFS,这说明共享工厂仍然知道 moldinsight 模块专属基础设施。
这意味着:
shared/platform还不够纯- 模块专属 startup hook 还没有完全从平台层剥离
后续实施时,这应是优先解决的问题之一:
app factory 只负责通用平台装配;模块专属生命周期应由 module hook 或 composition layer 决定。
10. 前端 API 边界策略
10.1 设计原则
前端已经是独立工程,不需要再拆目录或拆仓。后续重点应放在:
- 强化域 API 边界
- 消除对单一同源
/api/...的强依赖 - 兼容 unified / split deployment
10.2 当前可复用基础
当前前端已经具备良好基础:
- 域客户端入口:api-client.ts
- 生成类型:api.ts
- 模块目录:frontend/src/modules/moldinsight/ 与 frontend/src/modules/inventory/
因此,后续策略应是“边界强化”,不是“前端重写”。
10.3 建议的客户端边界
应继续收敛为:
authApimoldinsightApiinventoryApi
并要求:
- 页面/组件尽量不直接写裸
/api/...字符串 - multipart upload / download / export 也尽量通过域客户端封装
- 统一利用 OpenAPI 生成类型,而不是额外维护平行手写类型
10.4 支持两类部署配置
unified 模式
VITE_API_BASE_URL
split 模式
VITE_AUTH_API_BASE_URLVITE_MOLDINSIGHT_API_BASE_URLVITE_INVENTORY_API_BASE_URL
客户端实现上应支持:
- unified 下三个 client 指向同一个 base URL
- split 下各 client 指向不同服务
10.5 capability-aware UI
在 gemold-only 或 inventory-only 部署模式下,前端不应假设所有模块总是存在。
因此建议:
- 后端通过
/health或单独 capability endpoint 暴露已启用模块信息 - 前端根据 capability 隐藏未部署模块入口或禁用对应页面
这样可避免“前端路由还在,但后端根本没部署”的硬失败场景。
11. 分阶段迁移计划
Phase 0:蓝图冻结
目标:冻结目标结构与边界规则,防止迁移过程中继续长出新的耦合。
动作:
- 确认模块边界
- 确认依赖规则
- 确认三种部署模式
- 确认 shared/platform 的使用边界
Phase 1:组合层标准化
目标:将部署模式从“若干入口脚本”升级为“正式的 composition layer”。
动作:
- 将
entrypoints/*升级为compositions/* - 定义
unified_app.py/gemold_app.py/inventory_app.py - 将 module-specific startup hooks 从通用 app factory 中迁出
重点问题:
- 当前
mount_html -> RustFS connect属于模块专属逻辑,必须从 shared factory 中剥离
Phase 2:platform 与业务代码分治
目标:把“共享基础设施”从“共享杂项”中真正分离出来。
动作:
- 从
shared语义切换到更清晰的platform - 归位 config / auth / db / observability / utils
- 禁止新业务逻辑继续沉积到
shared
Phase 3:ORM 按归属拆分
目标:解决当前最大的代码耦合源。
动作:
- 拆分 database.py
- 保持单 Base / 单 Alembic / 单 DB
- 先完成代码层归属拆分,再处理更深层的业务隔离
这是整个重构中最关键的一步。
Phase 4:模块内部继续分层
目标:让每个模块内部的“路由 / 服务 / 领域 / 基础设施”边界更清晰。
动作:
- inventory:从现有 service 层继续向
application / domain / infrastructure / interfaces拉开 - moldinsight:逐步理顺
api / services / core / storage的边界
原则:
- 不要求一步完成 DDD 化
- 先把层次职责清楚,再考虑更纯粹的领域对象抽象
Phase 5:建立跨模块集成规则
目标:把当前 ad hoc 跨表访问逐步收敛成显式桥接能力。
动作:
- 定义跨模块 query services / repository contracts
- 明确“从分析创建成品”等桥接能力的正式入口
- 收敛直接穿透跨模块 ORM 图谱的做法
重点桥接场景:
STPFile.product_id- product_routes.py 中的“按 task 创建产品”逻辑
Phase 6:前端边界加固
目标:让前端真正适配 unified / split deployment。
动作:
- 强制域 API client 收口
- 支持 per-module base URL
- 支持 capability-aware UI
- 减少页面中裸
fetch('/api/...')
Phase 7:部署与文档收尾
目标:使架构蓝图与部署事实一致。
动作:
- 固化 unified / gemold-only / inventory-only 部署说明
- 更新 README / deployment docs / frontend docs
- 明确旧入口、旧 Dockerfile、旧部署说明的地位(兼容 / 历史 / 废弃)
12. 风险与缓解措施
风险 1:共享模型文件继续隐藏领域归属
现象:所有模型集中在 database.py
风险:边界无法落实,任何模块都能自然跨领域访问
缓解:
- 先产出表归属矩阵
- 再拆 ORM 文件
- 拆归属优先于改业务逻辑
风险 2:shared 继续变成杂物间
风险:shared/platform 成为“不知道放哪就放这里”的位置
缓解:
- 以
platform重新定义共享层 - 明确只有技术性共享能力可进入 platform
- 代码 review 中禁止新增业务逻辑进入 platform
风险 3:模块专属启动逻辑继续留在 app factory
现象:当前 mount_html 分支控制 RustFS 连接
风险:平台层继续了解业务模块内部基础设施
缓解:
- module lifecycle hook
- composition 层控制模块 startup/shutdown
- 通用 app factory 保持纯平台化
风险 4:独立部署后,前端仍假设所有模块存在
风险:前端路由可见,但后端未部署,造成运行时错误
缓解:
- capability metadata
- feature gating
- 前端按模块部署形态动态隐藏入口
风险 5:单数据库导致开发者随意跨模块查表
风险:虽然数据库未拆,但代码边界被绕开
缓解:
- 表归属规则文档化
- code review 要求说明跨模块访问理由
- 逐步通过 query services 收口
风险 6:大爆炸式目录迁移导致 import churn
风险:一次性移动所有目录,修改面过大,回归成本高
缓解:
- 分阶段迁移
- 保留兼容 import 过渡层
- 先稳定组合层与模型层,再做深层目录调整
13. 验证清单
13.1 结构验证
platform不 import 业务模块moldinsight/inventory无直接 api/services 互引- ORM 文件已按归属拆分,或至少表归属矩阵已文档化并被遵守
13.2 运行验证
unified
- 两类路由都能正常挂载
- 统一 health / auth / request-id 机制生效
gemold-only
- inventory 路由未挂载
- gemold 路由可用
- RustFS / Celery 等专属依赖正常初始化
inventory-only
- moldinsight 路由未挂载
- inventory 路由可用
- 不依赖 moldinsight 专属基础设施即可启动
13.3 数据验证
- 三种部署模式使用同一 migration head
- 单数据库中的跨模块 FK 保持有效
- Alembic 无分叉历史
13.4 前端验证
- unified 模式下,一个 base URL 即可跑通
- split 模式下,各模块 base URL 可独立配置
- 未部署模块能被隐藏或优雅失败
14. 文档联动更新计划
本蓝图批准后,以下文档应逐步对齐:
- EVOLUTION_ROADMAP.md
- LINUX_SETUP.md
- DEPLOY_PORT.md
- PORT_CONFIG.md
- PORT_REFACTOR_SUMMARY.md
README.mdfrontend/README.md
其中需要特别注意:
README.md当前仍主要描述旧单体结构,与当前实际代码已有明显漂移。- 本文档应作为“当前目标架构”的权威蓝图,路线图与部署文档随后对齐。
15. 附录:实施热点文件
以下文件是后续实际重构时最关键的热点:
平台与组合层
模型与边界
gemold 模块
inventory 模块
- inventory/api/__init__.py
- inventory_service.py
- sales_order_service.py
- purchase_order_service.py
- finance_service.py
前端边界
演进与部署参考
16. 最终结论
本项目当前最适合的演进路径不是微服务,而是:
单仓库 + 单数据库 + 多模块 + 可独立部署的 modular monolith
它既能保留当前业务闭环(模具分析 → 成品 → BOM → 销售/采购/库存),又能逐步降低共享层和模型层的结构耦合。
后续实施时,应优先按以下顺序推进:
- 固化组合层(deployment composition)
- 纯化 platform/shared 边界
- 拆分共享 ORM 文件
- 再继续模块内部细分层次
- 最后收口前端 API 与部署文档
这条路径风险最低、收益最大,也最符合当前代码现状与团队演进成本。