Files
geMoldInsight/docs/TECH_DEBT.md
T
2026-09-16 17:55:04 +08:00

281 lines
14 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 技术债与治理计划(TECH_DEBT)
> 文档定位:**当前活跃技术债与治理计划的权威文档**。
> 本文回答“现在还有哪些重要债务、优先级如何、下一步怎么处理”;不负责维护当前实现状态,当前状态见 [STATUS.md](STATUS.md)。架构边界见 [ARCHITECTURE.md](ARCHITECTURE.md),未来路线见 [ROADMAP.md](ROADMAP.md)。
> 本文由归档文档 [archive/MOLDINSIGHT_TECH_DEBT_PLAN.md](archive/MOLDINSIGHT_TECH_DEBT_PLAN.md) 收敛整理而来,保留活跃债务与治理结论,弱化详细实施流水账。
---
## 1. 当前技术债概览
当前最主要的技术债集中在两个区域:
- **moldinsight API 与处理链路的结构收口**
- **文档 / 部署 / 历史语义与当前代码现状未完全一致**
已经完成的高优先级治理不再作为持续待办反复展开,当前重点聚焦在“还没完成、且值得继续推进”的部分。
---
## 2. 已完成的重要治理(摘要)
以下高价值治理已完成:
### 2.1 安全与权限
- debug/history 路由补鉴权
- 任务访问控制收紧
- 无主数据不再默认放行
- `/api/status/{task_id}` 补 JWT 鉴权与归属校验(原 D5,2026-09-16 清偿,见 D5 条目)
- bcrypt 创建口令超 72 字节显式拒绝、验证侧截断比较;`SECRET_KEY` / `RUSTFS_*` 缺失时明确报错,代码侧弱默认移除(D14 部分,2026-09-16)
### 2.2 静默失败与可用性
- `detect-undercuts` 改为基于真实 shape 分析
- OCC 超时后重建 executor,避免全队列永久堵死
- 后台任务统一分派,补强引用与并发控制
### 2.3 状态存储与缓存
- Redis 任务状态改为 Hash 字段级更新,兼容旧格式
- 完成态任务视图增加缓存
- 导出缓存与持久化链路收口,支持重启后再导出
### 2.4 架构与代码清理
- 删除旧单体入口与死代码
- 设置惰性配置校验,提升可测试性
- Generator 公共接口提取完成,补充契约测试
### 2.5 部署正确性(2026-09-16,批次 0/1)
- `/api/status/{task_id}` 补鉴权与归属校验(原 D5)
- 主处理链路改走 RustFS:分派入参 `stp_file_id` 化,源文件按 object_key 下载;compose 共享卷过渡兜底(原 D6)
- `AUTO_MIGRATE` 开关 + 迁移脚本随镜像分发 + `alembic/`→`migrations/` 改名修复包遮蔽(原 D12)
- OCC 镜像改 conda 运行时原生执行、基础镜像 tag 锁定(D13 主体);compose 关键项去弱默认(D14 部分)
### 2.6 任务一致性模型(2026-09-16,批次 2)
- Redis 内存回退彻底删除,PG 为任务状态单一事实源(原 D7);批量元数据入库(`processing_tasks.batch_id`,迁移 `a3f8c2d91e47`)
- 型腔生成失败任务标 failed,不再静默 completed(原 D8)
- 持久化事务边界收口:数据本体分阶段原子提交、失败先回滚再置 failed(原 D9)
- D11(HTML 双写双读)本批未动:正确性已由共享卷兜底,RustFS 单一来源留待后续批次
详细历史过程保留在原始技术债文档中,后续将转入归档。
---
## 3. 当前活跃技术债
### D1. `advanced_router` 过大,职责混杂
现状:
- 导出、估算、设计/分析相关接口仍混在同一个 router 中
- 请求体仍有较多手动解析逻辑
影响:
- 路由边界不清晰
- OpenAPI 可读性差
- 接口参数校验不统一
- 后续继续扩展时维护成本高
建议:
- 拆分为 export / design / cost 等子路由
- 高优先级请求体改为 Pydantic 模型
优先级:**P1**
### D2. 铝价模拟数据未显式标注来源
现状:
- 铝价服务返回的是模拟/参考数据,但接口层未明确表达
影响:
- 容易误导前端与业务使用者,把模拟数据理解为实时行情
建议:
- 响应增加 `source: "simulated"`
- 前端界面同步标注“模拟/参考数据”
优先级:**P2**
### D3. shared/platform 边界仍需继续收敛
现状:
- `shared` 同时承担平台基础能力与部分历史耦合职责
- 共享 ORM 与 app factory 仍是主要耦合点
影响:
- 模块边界认知成本较高
- 新增逻辑容易继续堆入 shared
建议:
- 继续从文档、目录语义、职责边界上推进收敛
- 在后续实际重构中优先避免把业务逻辑继续沉入 shared
优先级:**P2**
### D4. 文档现状 / 规划 / 历史混放
现状:
- 文档存在部署说明重叠、计划/总结/权威文档混放
- README 承担过多职责
影响:
- 新成员难以判断“哪篇才是当前有效说法”
- 状态、部署、规划容易发生漂移
建议:
- 建立 `STATUS / ARCHITECTURE / ROADMAP / DEPLOYMENT` 主骨架
- 历史材料迁入 `docs/archive/`
优先级:**P1**
### D5. `/api/status/{task_id}` 未鉴权(安全缺口)—— 已清偿(2026-09-16,批次 0)
修复内容(保留编号以维持 D6–D14 引用稳定):
- 端点补 `Depends(get_current_active_user)`;归属校验收敛为 `TaskQueryService.ensure_task_access`,task_router 与 advanced_router 共用(advanced_router 原私有 `_ensure_task_access` 改为委托)
- 语义:无 token 401、他人/无主任务 403(无主不等于公共)、任务不存在 404
- 回归测试:[tests/test_status_endpoint_auth.py](../tests/test_status_endpoint_auth.py)
- 接口行为变化已同步 [API_CONTRACT.md](API_CONTRACT.md) §3.2
~~原现状 / 影响~~:端点未挂鉴权,匿名可枚举任务号拉取完整分析视图。
### D6. 主处理链路依赖节点本地文件路径 —— 已清偿(2026-09-16,批次 1)
修复内容(保留编号以维持引用稳定):
- 分派入参收敛为 `stp_file_id`(`dispatch_processing` 与 Celery 任务签名同步变更):处理方按 PG 元数据从 RustFS 下载源文件到任务专属临时目录(保留原始文件名,下游产物命名不变),任务结束即清理([processing_service.py](../src/moldinsight/services/processing_service.py) `_materialize_source_file`)
- RustFS 不可用时回退 `STPFile.file_path` 节点本地路径;compose 为 backend / celery 增加共享卷 `uploads_data` / `html_data` 作过渡兜底(HTML 产物跨容器写读同源问题一并兜住,正式修复在 D11)
~~原现状 / 影响~~:worker 直读 API 节点本地路径,双容器部署必然 `FileNotFoundError`。
### D7. Redis 降级为进程内 dict,多副本状态不一致 —— 已清偿(2026-09-16,批次 2)
修复内容(比原建议更彻底:完全删除内存回退,而非仅限 DEBUG):
- [redis_task_manager.py](../src/shared/services/redis_task_manager.py) 删除全部 `_fallback_*` 进程内存存储:Redis 不可用时写 no-op、读返回 None(Redis 仅热缓存,任务状态事实源在 PG,缓存缺失不影响正确性)
- 批量元数据入库:`processing_tasks` 新增 `batch_id` 列(迁移 `a3f8c2d91e47`),`GET /api/batch/{batch_id}` 改为按列聚合查询 + `STPFile.user_id` 归属校验,删除 Redis batch key 与进程内 dict 双通道
- `TaskQueryService` 的 PG 组装视图补 `progress` / `current_step`(Redis 不可用时前端轮询仍能看到进度);batch 聚合响应同步补 `current_step`
~~原现状 / 影响~~:Redis 故障时状态静默降级各进程内存,多副本互不可见、同任务不同副本读到不同状态。
### D8. 型腔生成失败被静默标记为 completed —— 已清偿(2026-09-16,批次 2)
修复内容:
- [processing_service.py](../src/moldinsight/services/processing_service.py) `_step_generate_cavity` 不再吞异常:分模失败直接向编排层传播 → 任务 failed(error_message 说明型腔阶段失败);已提交的几何/网格数据保留,用户可凭失败原因重新分析
- 未采用 `completed_with_fallback`:多一个状态值会扩散到前端所有状态分支,failed + 明确错误更诚实且成本低
~~原现状 / 影响~~:型腔失败被吞掉继续主流程,最终 completed,"完成"状态不可信。
### D9. 持久化事务边界破碎 —— 已清偿(2026-09-16,批次 2)
修复内容(进度可见性与原子性折中设计):
- **数据本体写方法只 flush 不 commit**:`save_stp_file` / `save_geometry_data` / `save_mesh_data` / `save_mold_cavity_data` / `save_html_file` / `save_features_and_recommendations` / `update_task_parameters` / `update_stp_file_analysis_summary` / `_save_analysis_metrics` / `_save_verification_metrics`
- **编排层分阶段收口**([processing_service.py](../src/moldinsight/services/processing_service.py)):阶段 A = 几何+网格(解析后确定成果,原子提交);阶段 B = 型腔+HTML+特征+指标+摘要+验证(结果包原子提交);完成时先 flush 任务参数、完成状态提交时一并落库(completed 即完整)
- **失败路径先 rollback 再置 failed**:未提交半成品回滚,失败状态单独提交,不出现"completed 但数据残缺"
- **保留即时 commit**:`update_task_status` / `update_stp_file_status`(处理中进度需跨事务对外可见,分钟级长任务不能憋在一个大事务里)
- 调用方补显式 commit:upload_router / batch_router(分派前置事务,STPFile + ProcessingTask 原子,消除孤儿文件记录)、advanced_router 导出两处
~~原现状 / 影响~~:各存储方法内部自行 commit,型腔保存失败留半成品数据且任务仍 completed。
### D10. OCC 全局单线程串行 + 超时重建泄漏线程
现状:
- 所有 OCC 操作经 `max_workers=1` executor 串行([processing_service.py](../src/moldinsight/services/processing_service.py)),celery 并发无法扩展 OCC 吞吐
- 超时重建 executor 每次泄漏 1 个线程,长期运行只涨不降
影响:
- 一个长耗时型腔生成阻塞全部几何处理;线程随故障累积
建议:
- 记录吞吐上限为已知约束;线程泄漏治理方案设计先行(见 [ROADMAP.md](ROADMAP.md) §3.1 批次 4)
优先级:**P2**
### D11. HTML 报告本地磁盘与 RustFS 双写双读
现状:
- 可视化 HTML/摘要同时写本地 `html_output/`(/html 静态挂载)与 RustFS
影响:
- 多副本下 /html 命中结果取决于负载均衡,跨副本文件不共享;同一份报告两套来源
建议:
- 统一 RustFS 为唯一来源,本地仅作按需缓存
优先级:**P2**
### D12. 应用启动时自动执行 alembic 迁移
### D12. 应用启动时自动执行 alembic 迁移 —— 已清偿(2026-09-16,批次 1)
修复内容:
- 新增 `AUTO_MIGRATE` 开关(settings / .env.example / compose 透传):默认 `true` 保持单机开发行为;多副本部署设 `false`,由部署流程单点执行 alembic CLI 或 `python -m shared.database.init_db`
- **连带发现并修复两个使自动迁移从未真正生效的缺陷**:
1. 迁移目录 `alembic/` 与 alembic 包重名——应用内 `import alembic` 命中本地目录(namespace package)遮蔽真实包,启动期迁移异常被 `init_database` 吞掉只打日志;已改名 `migrations/`(alembic.ini `script_location` 与 4 处文档引用同步)
2. 镜像未打包迁移脚本与 alembic.ini,容器内迁移必然失败——Dockerfile.base / Dockerfile.moldinsight 已补 `COPY migrations/` + `COPY alembic.ini`
### D13. PythonOCC 镜像引入方式脆弱 + 依赖无版本锁(主体已清偿,锁文件遗留)
现状:
- ~~从 conda env 拷贝 site-packages 进 python:3.12-slim~~(2026-09-16 已修正:[Dockerfile.moldinsight](../deploy/Dockerfile.moldinsight) 改为 conda 运行时原生执行,不再跨镜像拷贝;基础镜像 tag 锁定 `continuumio/miniconda3:24.7.1-0`、`python:3.12-slim-bookworm`;tag 可用性随下次镜像构建验证)
- [requirements.txt](../requirements.txt) 全部为 `>=` 下限,无锁文件(**遗留**:首次镜像构建成功后 `pip freeze` 生成锁文件,命令已注释在 Dockerfile 内)
优先级:**P2**(剩余锁文件部分)
### D14. 配置漂移:弱默认 / 死配置 / 重复解析
现状:
- ~~RUSTFS_* 弱默认~~(2026-09-16 代码侧已去除);~~compose 侧 SECRET_KEY / ADMIN_PASSWORD 弱默认~~(2026-09-16 已去除:改用 `${VAR:?}` 强制显式配置,`create_admin_user` 对空 ADMIN_PASSWORD 显式报错)
- MAX_FILE_SIZE 配置项未被使用([file_handler.py](../src/shared/utils/file_handler.py) 硬编码 50MB)
- [celery_app.py](../src/celery_app.py) 重新 load_dotenv 并手拼 REDIS URL,与 settings 两份实现
影响:
- 违背"关键项不兜底"硬约束;配置行为与文档不一致
建议:
- 去掉弱默认、对齐或删除死配置、celery_app 复用 settings
优先级:**P2**
---
## 4. 当前推荐治理顺序
> 注:2026-09-15 后端设计审查后,治理**执行顺序**以 [ROADMAP.md](ROADMAP.md) §3.1 批次计划为准(批次 0–4);D5–D14 的批次归属见该表。本节保留原有优先项作为补充说明。
### 第一优先级
1. `advanced_router` 拆分
2. 高优先级接口补 Pydantic 请求模型
3. 文档主骨架收口并减少重复说明
### 第二优先级
4. 铝价模拟数据来源显式化
5. 部署历史文档归档
6. shared/platform 语义继续收敛
---
## 5. 治理原则
### 5.1 先收口接口与边界,再做更大结构调整
当前最值得继续投入的,不是大规模目录重写,而是:
- 先把接口边界、文档边界、部署边界收清楚
- 再逐步推进 shared/platform 的后续调整
### 5.2 优先做“降低长期维护成本”的改动
优先处理:
- 重复逻辑
- 模糊边界
- 静态契约缺失
- 文档漂移风险
### 5.3 已解决问题不再长期占据主文档中心
已经完成且稳定的问题,只在本文保留摘要结论;详细实施流水账后续归档,不继续作为主文档主体。
---
## 6. 与相关文档的边界
- 当前项目状态:看 [STATUS.md](STATUS.md)
- 当前架构与模块边界:看 [ARCHITECTURE.md](ARCHITECTURE.md)
- 后续演进路线:看 [ROADMAP.md](ROADMAP.md)
- 部署主题入口:看 [DEPLOYMENT.md](DEPLOYMENT.md)
- 原始 moldinsight 细粒度债务记录:看 [archive/MOLDINSIGHT_TECH_DEBT_PLAN.md](archive/MOLDINSIGHT_TECH_DEBT_PLAN.md)