Files
geMoldInsight/docs/BACKEND_MODULARIZATION_BLUEPRINT.md
T
2026-08-27 14:53:22 +08:00

24 KiB
Raw Blame History

geMoldInsight 后端模块化重构蓝图

目标:在同一 Git 仓库、同一数据库前提下,将当前代码结构整理为可独立部署的多模块架构,明确 gemold、inventory、frontend 的边界与演进路径。本文档是后续实施的权威蓝图,不是历史记录。


1. 背景与目标

当前项目已经从早期单体演进为“双应用 + 共享层”的形态:

  • 业务模块:src/moldinsight/、src/inventory/
  • 共享层:src/shared/
  • 部署入口:src/entrypoints/moldinsight.py、src/entrypoints/inventory.py
  • 前端工程:frontend/

从代码现状看,moldinsight 与 inventory 已基本无直接互引,说明模块边界已经初步形成;但同时,数据库模型、认证、配置、应用工厂等仍集中在 shared/,导致当前更接近“模块化中的单体”,而不是“可独立部署的模块化单体”。

本次蓝图的目标不是拆库、拆仓、微服务化,而是:

  1. 保持单仓库(monorepo)
  2. 保持单数据库
  3. 将后端正式整理为多个模块:
    • gemold(模具分析 / moldinsight)
    • inventory(进销存)
    • identity / platform(共享基础设施与认证)
  4. 保持前端为独立模块工程,并增强其对多部署模式的兼容
  5. 支持三种部署模式:
    • 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/... 与 raw fetch() 的同源假设

3.3 现状判断

当前架构可概括为:

HTTP 入口已分离,业务代码已分组,但平台层与数据层仍共享。

因此,它适合继续朝“可独立部署的模块化单体”演进,而不适合直接跳到微服务。


4. 目标架构:可独立部署的模块化单体

4.1 架构原则

目标态采用以下原则:

  1. 组合优先于复制:不同部署模式通过组合不同模块得到,而不是复制多套代码。
  2. 平台与业务分离:platform 只承载技术性共享能力,不继续承载业务逻辑。
  3. 模块所有权清晰:每张表、每条 API、每个服务类都应有明确归属。
  4. 单数据库但显式边界:允许共享 DB,但不允许“共享数据库 = 没有边界”。
  5. 统一前端,兼容多后端部署形态:前端继续是一套工程,通过 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 + moldinsight
  • inventory_app.py:平台 + identity + inventory
  • unified_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 异步处理链路

可复用现有实现


6.3 inventory

inventory 模块负责 ERP / 进销存类业务流程。

归属范围

  • 产品、物料、供应商、客户、仓库
  • 库存、库存流水
  • 销售订单、采购订单、财务、采购建议
  • BOM / 采购需求推导

可复用现有实现


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 不能直接 import moldinsight.api / moldinsight.services
  • moldinsight 不能直接 import inventory.api / inventory.services
  • platform 不得依赖任一业务模块
  • 跨模块协作只能通过:
    • 显式 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 业务模型

这会带来两个问题:

  1. 代码层看不出模型所有权
  2. 开发者更容易跨模块直接访问整套 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,但应遵守:

  1. 跨模块 FK 是业务桥,不是“任意跨模块查询”的许可
  2. 模块之间应逐步通过 query service / repository contract 暴露需要的读取能力
  3. 避免一个模块直接依赖另一个模块的整套 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 当前可复用基础

当前前端已经具备良好基础:

因此,后续策略应是“边界强化”,不是“前端重写”。

10.3 建议的客户端边界

应继续收敛为:

  • authApi
  • moldinsightApi
  • inventoryApi

并要求:

  • 页面/组件尽量不直接写裸 /api/... 字符串
  • multipart upload / download / export 也尽量通过域客户端封装
  • 统一利用 OpenAPI 生成类型,而不是额外维护平行手写类型

10.4 支持两类部署配置

unified 模式

  • VITE_API_BASE_URL

split 模式

  • VITE_AUTH_API_BASE_URL
  • VITE_MOLDINSIGHT_API_BASE_URL
  • VITE_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 图谱的做法

重点桥接场景:


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. 文档联动更新计划

本蓝图批准后,以下文档应逐步对齐:

其中需要特别注意:

  • README.md 当前仍主要描述旧单体结构,与当前实际代码已有明显漂移。
  • 本文档应作为“当前目标架构”的权威蓝图,路线图与部署文档随后对齐。

15. 附录:实施热点文件

以下文件是后续实际重构时最关键的热点:

平台与组合层

模型与边界

gemold 模块

inventory 模块

前端边界

演进与部署参考


16. 最终结论

本项目当前最适合的演进路径不是微服务,而是:

单仓库 + 单数据库 + 多模块 + 可独立部署的 modular monolith

它既能保留当前业务闭环(模具分析 → 成品 → BOM → 销售/采购/库存),又能逐步降低共享层和模型层的结构耦合。

后续实施时,应优先按以下顺序推进:

  1. 固化组合层(deployment composition)
  2. 纯化 platform/shared 边界
  3. 拆分共享 ORM 文件
  4. 再继续模块内部细分层次
  5. 最后收口前端 API 与部署文档

这条路径风险最低、收益最大,也最符合当前代码现状与团队演进成本。