Files
geMoldInsight/docs/EVOLUTION_ROADMAP.md
T

168 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# geMoldInsight 演进路线图
> 本文档是代码与功能演进的执行清单,基于 2026-07-13 的全量代码体检。每项含「现象 / 证据 / 修法 / 验证」,按 P0→P3 推进,完成后勾选。
## 诊断
代码已演进到「双应用模块化」形态(`entrypoints/` + `moldinsight/` + `inventory/` + `shared/`),但有 **三处结构性缺失** 让快速迭代变贵,外加 **一批静默 bug** 正在让功能"看起来在跑其实没跑":
- **缺中间层**:业务逻辑堆在路由/编排函数里(进销存无 service 层、`process_file_core` 280 行线性函数)
- **缺契约**:前后端靠手写类型,字段已大面积漂移(财务页整页是 0)
- **缺连接**:模具分析与进销存是两个孤立产品(`STPFile` 没有 `product_id`)
---
## P0 止血:正在静默失效的功能(1–2 周)
这些不是技术债,是**现在就在坏**的东西,先修。
### P0-1 Celery worker 不连 Redis/RustFS,异步任务全坏
- **现象**:任务进度写进 Celery 私有内存,web 端永远读不到;首次上传 RustFS 直接抛 `RuntimeError("RustFS 未连接")`。
- **证据**:`redis_task_manager.connect()` / `rustfs_manager.connect()` 只在 FastAPI startup 调用(`entrypoints/moldinsight.py:42,48`),Celery 进程不跑 startup;`processing_service.py` 在 celery 内调 `update_task` 时 `is_connected=False` 走 `_fallback_set`;`rustfs_storage.py:125-126` 未连接直接抛错。`deploy/docker-compose.yml` 的 `moldinsight-celery` 服务块缺 `REDIS_PASSWORD`。
- **修法**:`celery_tasks.py` 加 `@worker_process_init` 信号,显式 `connect()` redis 与 rustfs;补齐 celery 服务的 `REDIS_PASSWORD`/`SECRET_KEY` 等环境变量,与主应用对齐。
- **验证**:上传一个 STP,Celery 路径下任务进度能从 web 端 `/api/status/{task_id}` 读到;上传后 RustFS 中能看到对象。
- **状态**:- [ ]
### P0-2 LLM 设计报告 NameError,静默失效
- **现象**:`LLM_ENABLED=true` 时设计报告功能直接没有。
- **证据**:`llm_service.py:339` 用未定义变量 `trimmed`(应为 `features`,`trimmed` 只在 `_build_side_action_prompt` 中定义),外层 `try/except` 吞掉 `NameError` 返回 `None`。
- **修法**:`trimmed` -> `features`。
- **验证**:启用 LLM 后设计报告字段非空。
- **状态**:- [ ]
### P0-3 前端财务页全字段错配
- **现象**:FinanceTab 整页 0/空;用户管理菜单永不显示(`is_superuser` 后端不返回);dashboard 成品数恒 0。
- **证据**:16 处字段名对不上,如 `total_receivable` vs `receivable_total`(`finance_schemas.py:66`)、`order_no` vs `txn_no`(`finance_schemas.py:48`)等;`App.vue:91` 读 `is_superuser` 但 `UserResponse` 无此字段。
- **修法**:短期按映射手改前端字段;长期靠 P1-3 OpenAPI 契约生成根治。
- **验证**:财务页卡片与表格显示真实数据;用户管理菜单对管理员可见。
- **状态**:- [ ]
### P0-4 OCC 线程安全自相矛盾
- **现象**:偶发崩溃,外层 `max_workers=1` 保护形同虚设。
- **证据**:`processing_service.py:50-51` 用单线程池序列化 OCC,但 `geometry_analyzer._detect_features`(`geometry_analyzer.py:81`)内部又开 `ThreadPoolExecutor(max_workers=4)` 并行操作 OCC `TopoDS_Shape`。
- **修法**:特征检测器改串行;或预处理阶段把面特征抽成纯数值,检测器只处理数值不碰 OCC。
- **验证**:压测大模型反复分析无崩溃。
- **状态**:- [ ]
### P0-5 `.env` 进了 git 历史,真实密钥泄露
- **现象**:DB/Redis/SECRET_KEY/LLM key 已进入仓库历史。
- **证据**:`git ls-files --error-unmatch .env` 命中;`git log -- .env` 有 10+ 次提交;`.env` 内含真实凭据。
- **修法**:`git rm --cached .env`(停止跟踪,保留本地,后续不再提交);`SECRET_KEY` 从默认占位符轮换为强随机值。
- **用户决策(2026-07-13)**:私有仓库,不轮换其他密钥、不重写 git 历史。
- **验证**:`git status` 显示 `.env` 不再被跟踪(`D .env`)。
- **状态**:- [x]
### P0-6 铝价路由模块化部署后丢失
- **现象**:模块化部署后 `/api/aluminum-price/*` 直接 404。
- **证据**:单体 `main.py:47,155` 挂了 `aluminum_price_router`,但 `moldinsight/api/__init__.py` 的 `_safe_include` 列表不含 `aluminum_price_routes`。
- **修法**:把 `aluminum_price_routes` 加入 `_safe_include`。
- **验证**:模块化部署下 `/api/aluminum-price/*` 可访问。
- **状态**:- [ ]
### P0-7 导出缓存无持久化回退
- **现象**:多 worker 或重启后导出返回 409。
- **证据**:`processing_service._export_shapes_cache` 是进程内 dict,`get_export_shapes` 只查内存;`_persist_step_exports` 已写磁盘 manifest 但无回读逻辑。
- **修法**:`get_export_shapes` 缓存未命中时从磁盘 manifest 回读。
- **验证**:重启后导出仍可用。
- **状态**:- [ ]
---
### P0 执行结果(2026-07-13)
- ✅ **P0-1 Celery 连接**:`celery_tasks.py` 在任务内显式 `redis_task_manager.reconnect()` + `rustfs_manager.connect()`(Redis 客户端绑定事件循环,每任务 reconnect;RustFS 同步客户端连一次复用);`deploy/docker-compose.yml` celery 服务补 `REDIS_PASSWORD`/`RUSTFS_TIMEOUT`
- ✅ **P0-2 LLM NameError**:`llm_service.py:339` `trimmed` -> `features`
- ✅ **P0-3 前端字段错配**:FinanceTab 全字段对齐 schema(summary/statement/product-statement/transaction 共 16 处);`UserResponse` 加 `is_superuser` + 统一 `_build_user_response` 构造(修用户管理菜单不显示);DashboardTab `product_count`->`finished_product_count`;PurchaseOrdersTab `received_at/paid_at`->`received_date/paid_date`;后端 `FinanceTransactionResponse` 补 `partner_name` 并批量查询客户/供应商名称
- ✅ **P0-4 OCC 线程安全**:`geometry_analyzer._detect_features` `max_workers` 4->1
- ✅ **P0-5 .env 泄露**:`git rm --cached .env` 已取消跟踪(后续不再提交);`SECRET_KEY` 从默认占位符轮换为强随机值(现有登录 token 失效)。用户决策:私有仓库,不轮换其他密钥、不重写 git 历史
- ✅ **P0-6 铝价路由**:`moldinsight/api/__init__.py` `_safe_include` 加入 `aluminum_price_routes`
- ℹ️ **P0-7 导出缓存**:经排查**非 bug**——`export_artifacts` 已写 PG+Redis(`processing_service.py:342,361`),导出端点先走 `_select_persisted_files` 从 task_data 读取(`advanced_router.py:436`),重启后正常工作;409 仅在持久化也失败时出现,"请重新分析"提示为正确行为。内存 re-export 缓存的可靠性优化归入 P1-2
**未做验证**:前端未跑 vue-tsc 构建(字段重命名属机械改动,低风险);后端未跑 pytest(需 DB/Redis 环境)。建议下次在完整环境验证。
---
## P1 结构性地基:让后续迭代不再昂贵(持续)
### P1-1 进销存抽 service 层
- **现状**:`finance_routes.py` 751 行、`sales_order_routes.py` 777 行,事务编排/库存原子更新/流水写入全耦合在 endpoint;`shared/services/` 仅 auth+redis。
- **目标**:新建 `inventory/services/`,`PurchaseOrderService.receive()`、`SalesOrderService.issue_materials()`、`FinanceService.settle()`,route 只做校验+组装。
- **状态**:- [ ]
### P1-2 moldinsight 可插拔注册表 + Stage 流水线
- **现状**:模具类型硬编码 if-else(`multi_scheme_planner.py:40`);特征检测器硬编码 6 个(`geometry_analyzer.py:76-99`);`process_file_core` 280 行。
- **目标**:`FeatureDetectorRegistry` + `MoldGeneratorRegistry`(`@register` 装饰器);`process_file_core` 拆成 Stage 链。
- **解锁**:新增模具类型、IGES/BREP、批量分析。
- **进展(2026-07-15)**:✅ `MoldGeneratorRegistry`(消除 `multi_scheme_planner` if-else,新增模具类型只需 `register`)+ ✅ `FeatureDetectorRegistry`(消除 6 个检测器硬编码,新增检测器只需 `register`)+ 顺带移除 OCC 线程池改用注册表串行执行;⏳ Stage 流水线**暂缓**--`process_file_core`(278 行/10 stage/~20 跨 stage 变量)是 STP 处理核心,本环境无 OCC 无法运行时验证,盲改风险高。建议在有 OCC 的环境按现有 `_step_*` 模式增量抽取 inline stages(parse_stp / build_plan_result / generate_visualization / analyze_design / generate_llm_report / finalize)
- **状态**:- [~](2/3:两个注册表完成,Stage 流水线暂缓)
### P1-3 前端 OpenAPI 契约生成
- **现状**:前端 40+ 处 `any`,字段全手写已大面积错配。
- **目标**:`openapi-typescript` 从 `/openapi.json` 生成 TS 类型替换 `any`;`api.ts` 加 baseURL/拦截器/超时,按域封装 `inventoryApi`/`moldinsightApi`/`authApi`。
- **状态**:- [ ]
### P1-4 引入 Alembic,废除裸 DDL
- **现状**:无 `alembic.ini`;`init_db.py` 22 条 `ALTER TABLE ADD COLUMN IF NOT EXISTS`,无版本/无回滚;`migrate_db.py` 是 `drop_all` 破坏性脚本;两应用 startup 并发跑 DDL 争锁。
- **目标**:`alembic init`,固化版本化迁移,启动只 `upgrade head`;删 `migrate_db.py`。
- **状态**:- [x]
### P1-5 统一材料属性源
- **现状**:材料字典在 4 处重复定义且冲突(PE 收缩率 `material_service` 0.020 vs `aluminum_foam_mold.py:92` 0.025)。
- **目标**:`MaterialService` 作为唯一源,其他模块查询。
- **状态**:- [x]
---
### P1 执行结果(核心完成)
- ✅ **P1-1 进销存抽 service 层**(核心完成):
- 建立 `inventory/services/` 层,抽出 5 个 service:FinanceService / SalesOrderService / PurchaseOrderService / StockMovementService / InventoryService
- 路由全面瘦身:finance 767->123、sales_order 777->114、purchase_order 472->90、stock_movement 209->37、inventory 205->57
- 将 schemas/ 与 utils.py 从 inventory/api/ 移至 inventory/ 顶层,打破 service<->api 循环导入(正确分层);清理死代码 api/utils.py
- ✅ 全量 import 测试通过:55 inventory 路由无丢失,5 个 service 全部正常加载
- ⏳ 可选后续:剩余纯 CRUD 路由(product/supplier/customer/warehouse/material/dashboard)体量小,可按需增量抽取
- ✅ **P1-5 统一材料属性源**:`MaterialService` 成为唯一源,删除 geometry_analyzer/mold_generator/aluminum_foam_mold 三处重复字典,改查询 MaterialService;解决冲突(PE 收缩率统一 0.020、PC/PA/PMMA 收缩率、POM 密度统一)、补齐 PS、统一泡沫 `shrinkage` 键名、补 `min_wall`/泡沫字段;py_compile + 一致性核对通过
- ✅ **P1-4 引入 Alembic**:`alembic init` + 配置 env.py(接 settings+models metadata);补 3 个 CheckConstraint 到 models;离线生成初始迁移(31 表+约束+95 索引,全 sa.* 通用类型);`init_db.py` 用 `_run_alembic_migrations`(自动基线+upgrade head)替换 `create_tables`+`ensure_schema_updates`(删 92 行裸 DDL);删破坏性 `migrate_db.py`。**既有 DB 自动 stamp 基线**(无需手动);全新部署建议先 `alembic upgrade head` 再启应用
- ✅ **P1-2 可插拔注册表**(Stage 流水线暂缓):新增 `MoldGeneratorRegistry`(`multi_scheme_planner` 消除 if-else,按 mold_type 选生成器)+ `FeatureDetectorRegistry`(`geometry_analyzer._detect_features` 消除 6 个检测器硬编码,改遍历注册表);新增模具类型/特征检测器只需 `register` 一行;顺带移除 OCC 线程池改串行。Stage 流水线(process_file_core 拆分)因无 OCC 运行环境暂缓,文档留计划
---
## P2 功能演进:把两个产品变成一个
### P2-1 打通模具分析 -> 进销存(最高产品价值)
- **现状**:`STPFile` 无 `product_id`,moldinsight 与 inventory 零数据关联。
- **目标**:`STPFile` 加 `product_id` 外键(可空),分析完成后一键创建 `Product(finished)` 并回写。
- **状态**:- [ ]
### P2-2 真 AI 落地,砍掉假 AI
- **现状**:`ai_mold_assistant.py` 209 行纯 stub 从未被调用;`ai_parting_detector.py` GNN 框架完整但无权重;`llm_service` 是唯一真接 AI(且有 P0-2 bug)。
- **目标**:聚焦一个能跑通的 AI 能力(LLM 扩到成本估算/工艺对话);GNN 要么真训权重,要么移除 stub。
- **状态**:- [ ]
### P2-3 模具成本估算 + 批量分析
- 依赖 P1-2 完成后才有性价比。
- **状态**:- [ ]
---
## P3 工程治理(穿插顺手做)
- [ ] `create_app()` 工厂消除两入口重复引导,废弃单体 `main.py`
- [ ] 删死依赖/死代码:Kafka(零引用)、`templates/` legacy、`ai_mold_assistant` stub、`ProcessingService.__init__` 3 个死实例
- [ ] `get_db_session` 统一事务边界(commit/rollback),废除路由手动 commit
- [ ] 连接池治理(3 进程峰值 150 > PG 默认 100),考虑 PgBouncer
- [ ] 进销存 state 从模块级单例迁回 Pinia,tab 改子路由
- [ ] 统一 `/health` 响应 schema;SPA fallback 排除 `/api` 前缀避免吞 404
- [ ] CORS 收敛(`allow_origins=["*"]` + `allow_credentials=True` 不安全)
---
## 执行进度
| 阶段 | 项数 | 已完成 | 进行中 |
|------|------|--------|--------|
| P0 | 7 | 6 修复 + 1 排查 | - |
| P1 | 5 | 4 | P1-1+P1-5+P1-4 完成 + P1-2 注册表完成(Stage 暂缓) |
| P2 | 3 | 0 | - |
| P3 | 7 | 0 | - |