0e6b3b1811
按 ROADMAP §3.1 治理批次推进的后端设计审查整改:
- 批次 0(安全):/api/status/{task_id} 补 JWT 鉴权与任务归属校验;
pythonocc_available 真实探测;bcrypt 超 72 字节显式拒绝;
SECRET_KEY/RUSTFS_* 惰性校验,代码侧弱默认移除
- 批次 1(部署正确性):主处理链路改走 RustFS(分派入参 stp_file_id 化,
worker 按 object_key 下载);AUTO_MIGRATE 开关 + 迁移目录 alembic/→migrations/
修复包遮蔽(自动迁移此前从未真正生效);OCC 镜像改 conda 原生执行 +
基础镜像 tag 锁定;compose 关键项改 ${VAR:?} 强制显式配置
- 批次 2(任务一致性):删除 Redis 进程内存回退,PG 为任务状态单一事实源;
批量元数据入库(processing_tasks.batch_id,迁移 a3f8c2d91e47);
型腔失败任务标 failed 不再静默 completed;事务边界收口
(数据本体写 flush-only、失败先回滚再置 failed、进度更新保留即时 commit)
- 批次 3(API 与代码结构):592 行 advanced_router 拆为 design/cost/machining/
export 四子路由,请求体全量 Pydantic 化;ROUTE_MODULES + route_registry
(/api/health 呈现 degraded,DEBUG fail fast);纯计算端点统一 to_thread;
StorageIntegrationService 按职责三拆;MAX_FILE_SIZE 接线生效、
celery 复用 Settings.redis_url;管理员重置密码改 JSON body(端到端断裂修复);
openapi.json 重导出(76 paths)+ 前端 gen:api
- 批次 4(架构演进):共享 ORM 按模块拆分(shared/models/base.py + identity.py、
moldinsight/models/、inventory/models/,删除三条无使用方的跨模块
relationship,跨模块桥接收敛为裸 FK 硬规则,无兼容 facade);
OCC executor 重建补 cancel_futures=True(消除旧队列被慢恢复线程
并行消化的数据竞争);OCC 吞吐方案设计先行
(docs/topics/performance/OCC_THROUGHPUT.md);顺手清偿 D15
(vite.config.ts 未用参数致 npm run build 失败)
测试基线:125 passed, 2 skipped(pytest + sqlite+aiosqlite;归属边界、
路由契约、配置治理、鉴权回归等随批新增)
文档同步:STATUS / TECH_DEBT / ROADMAP / ARCHITECTURE / API_CONTRACT /
OPERATIONS / AGENTS
Co-Authored-By: Claude Code <noreply@anthropic.com>
112 lines
8.1 KiB
Markdown
112 lines
8.1 KiB
Markdown
# geMoldInsight 前后端契约(API_CONTRACT)
|
||
|
||
> 文档定位:**前后端契约的唯一归属**——端点总览、统一约定、OpenAPI 类型生成流程。
|
||
> 端点定义、路径、请求/响应 schema 的**最终真相源是根目录 `openapi.json`**(由 FastAPI 自动生成);本文维护人可读的总览与变更规则。当前状态见 [STATUS.md](STATUS.md),架构见 [ARCHITECTURE.md](ARCHITECTURE.md),接口类技术债见 [TECH_DEBT.md](TECH_DEBT.md) D1。
|
||
|
||
---
|
||
|
||
## 1. 总览
|
||
|
||
三种部署形态暴露的 API 面(入口见 [src/entrypoints/](../src/entrypoints/)):
|
||
|
||
| 形态 | API 面 |
|
||
|---|---|
|
||
| unified(推荐) | `/api/*`(moldinsight + inventory)+ `/api/auth/*` + 顶层 `/health` |
|
||
| moldinsight-only | `/api/*`(moldinsight)+ `/api/auth/*` + `/health` |
|
||
| inventory-only | `/api/*`(inventory)+ `/api/auth/*` + `/health` |
|
||
|
||
- moldinsight 路由在 [moldinsight/api/\_\_init\_\_.py](../src/moldinsight/api/__init__.py) 按 `ROUTE_MODULES` 清单经 `_safe_include` 聚合(装载失败登记 [route_registry.py](../src/moldinsight/api/route_registry.py),`/api/health` 呈现 `degraded` 并列出失败模块;`DEBUG=true` 下失败直接抛错;`debug_router` 仅 `DEBUG=true` 注册)。
|
||
- inventory 路由在 [inventory/api/\_\_init\_\_.py](../src/inventory/api/__init__.py) 按域静态聚合。
|
||
- 认证路由来自 [shared/services/auth_routes.py](../src/shared/services/auth_routes.py),由 [app_factory](../src/shared/app_factory.py) 挂载,三种形态共用。
|
||
|
||
## 2. 统一约定
|
||
|
||
- **鉴权**:JWT Bearer(`Authorization: Bearer <token>`)。登录:`POST /api/auth/login`(表单)/ `POST /api/auth/login/json`(JSON);受保护路由通过 FastAPI 依赖 `get_current_active_user` 注入当前用户([shared/services/auth_service.py](../src/shared/services/auth_service.py))。`SECRET_KEY` 跨进程必须一致。
|
||
- **响应形态**:现状**无统一信封包装**——各端点直接返回业务 JSON;schema 以 `openapi.json` 的 components 为准。新增接口不建议另起信封风格,保持与所在模块一致。
|
||
- **错误**:FastAPI 标准 `HTTPException` 状态码语义;业务校验优先 Pydantic 请求模型自动 422。
|
||
- **业务路由前缀**:全部业务端点在 `/api` 下;顶层仅 `/health`(探活)、`/login`、`/users`(历史遗留入口,前端主链路用 `/api/auth/*`)。
|
||
|
||
## 3. 端点总览(按域分组)
|
||
|
||
> 下表为导航用速览;路径参数、请求/响应字段以 `openapi.json` 为准。
|
||
|
||
### 3.1 认证与用户(shared)
|
||
|
||
| 域 | 端点 | 文件 |
|
||
|---|---|---|
|
||
| 登录 | `/api/auth/login`、`/api/auth/login/json`、`/api/auth/logout` | auth_routes.py |
|
||
| 当前用户 | `/api/auth/me` | auth_routes.py |
|
||
| 用户管理 | `/api/auth/users`、`/api/auth/users/{user_id}`、`/api/auth/users/{user_id}/reset-password`(管理员;JSON body `{ new_password }`,最短 6 位) | auth_routes.py |
|
||
| 角色权限 | `/api/auth/roles`、`/api/auth/roles/{role_id}`、`/api/auth/roles/{role_id}/permissions`、`/api/auth/permissions`、`/api/auth/permissions/{permission_id}` | auth_routes.py |
|
||
|
||
### 3.2 moldinsight(模具分析)
|
||
|
||
| 域 | 端点 | 文件 |
|
||
|---|---|---|
|
||
| 上传 | `/api/upload` | upload_router.py |
|
||
| 批量分析 | `/api/batch-upload`、`/api/batch/{batch_id}`(聚合状态以 PG 为准;响应含 `current_step`;他人批次 403、不存在 404) | batch_router.py |
|
||
| 任务状态 | `/api/status/{task_id}`(需登录;仅任务所有者可访问,他人/无主任务 403,不存在 404) | task_router.py |
|
||
| 历史结果 | `/api/history`、`/api/history/{filename}` | history_router.py |
|
||
| CAM | `/api/cam/plan`(Pydantic 请求模型;未提供的偏好回落任务持久化偏好再回落默认) | cam_router.py |
|
||
| 设计 | `/api/optimize-layout`、`/api/design-cooling`、`/api/design-gating`、`/api/design-mold-system`、`/api/detect-undercuts` | design_router.py |
|
||
| 成本估算 | `/api/cost-estimate` | cost_router.py |
|
||
| 加工 | `/api/design-cam`、`/api/check-collision`、`/api/optimize-toolpath`、`/api/design-electrodes`、`/api/simulate-machining` | machining_router.py |
|
||
| 导出 | `/api/export-mold`、`/api/export-download/{filepath}`、`/api/export-recommendations` | export_router.py |
|
||
| 铝价(模拟数据) | `/api/aluminum-price/current`、`/api/aluminum-price/history` | aluminum_price_routes.py |
|
||
| 健康检查 | `/api/health`(有路由装载失败时 `status: degraded` 并列出失败清单;`pythonocc` 为真实探测) | health_router.py |
|
||
| 调试(仅 DEBUG) | `/api/debug/tasks` | debug_router.py |
|
||
|
||
### 3.3 inventory(进销存)
|
||
|
||
| 域 | 端点 | 文件 |
|
||
|---|---|---|
|
||
| 成品 | `/api/products`、`/api/products/{product_id}`、`/api/products/{product_id}/materials`、`/api/products/from-task/{task_id}` | product_routes.py |
|
||
| 物料价格/供应商 | `/api/materials/*` | material_routes.py |
|
||
| 供应商 | `/api/suppliers`、`/api/suppliers/{supplier_id}` | supplier_routes.py |
|
||
| 客户 | `/api/customers`、`/api/customers/{customer_id}` | customer_routes.py |
|
||
| 仓库 | `/api/warehouses` | warehouse_routes.py |
|
||
| 库存 | `/api/inventory`、`/api/inventory/{inventory_id}` | inventory_routes.py |
|
||
| 库存流水 | `/api/stock-movements` | stock_movement_routes.py |
|
||
| 采购订单 | `/api/purchase-orders`、`/api/purchase-orders/{order_id}`、`.../receive`、`.../status` | purchase_order_routes.py |
|
||
| 采购建议 | `/api/purchase-demands/calculate` | purchase_demand_routes.py |
|
||
| 销售订单 | `/api/sales-orders`、`/api/sales-orders/{order_id}`、`.../status`、`.../issue-materials`、`.../consume-materials`、`.../production-plan` | sales_order_routes.py |
|
||
| 财务 | `/api/finance/summary`、`/api/finance/receivables|payables|receipts|payments|transactions`、`/api/finance/partner-statement/{partner_type}` 等 | finance_routes.py |
|
||
| 看板 | `/api/dashboard` | dashboard_routes.py |
|
||
|
||
**moldinsight → inventory 桥接**:`/api/products/from-task/{task_id}` 由分析任务一键创建成品(对应 `STPFile.product_id -> Product.id` 单库桥接,见 [ARCHITECTURE.md](ARCHITECTURE.md) §5.1)。
|
||
|
||
## 4. OpenAPI 与前端类型生成(接口变更三件套)
|
||
|
||
接口变更后**必须依次完成**:
|
||
|
||
1. **改代码**:路由 + Pydantic 请求/响应模型(优先模型,少写 `request.json()` 解析)。
|
||
2. **重导出 `openapi.json`**(在可 import 项目的环境执行,如 conda `gemold`):
|
||
|
||
```bash
|
||
python -c "import sys; sys.path.insert(0, 'src'); from entrypoints.unified import app; import json; print(json.dumps(app.openapi(), ensure_ascii=False, indent=2))" > openapi.json
|
||
```
|
||
|
||
(moldinsight-only 契约视角可把 `entrypoints.unified` 换成 `entrypoints.moldinsight`;对外主契约以 unified 为准。)
|
||
|
||
3. **重新生成前端类型**:
|
||
|
||
```bash
|
||
cd frontend && npm run gen:api # openapi-typescript:../openapi.json -> src/types/api.ts
|
||
```
|
||
|
||
- `frontend/src/types/api.ts` 是**生成物,禁止手改**;前端代码类型引用它。
|
||
- 三步缺一即前后端契约漂移(硬约束,见 [AGENTS.md](../AGENTS.md) §2)。
|
||
- 当前 `openapi.json` 于 2026-09-17 随批次 3 重导出(76 paths),前端 `src/types/api.ts` 同步再生。
|
||
|
||
## 5. 契约变更规则
|
||
|
||
- 新增接口先定模块归属(moldinsight / inventory / shared auth),再写路由;返回结构、路径、鉴权发生变化时,同步更新本文相应表格。
|
||
- 路由文件过大按职责拆分(参照批次 3 的 design / cost / machining / export 拆分先例;新增路由须登记 [moldinsight/api/\_\_init\_\_.py](../src/moldinsight/api/__init__.py) 的 `ROUTE_MODULES`)。
|
||
- 破坏性变更(删字段 / 改语义)需在 [STATUS.md](STATUS.md) 日志条目中记录,并确认前端同仓同步修改。
|
||
|
||
## 6. 前端消费约定
|
||
|
||
- 前端为独立工程 [frontend/](../frontend/)(Vue 3 + Vite + TS + Pinia + TDesign),按域组织在 `src/modules/`(moldinsight / inventory / users / login / home)。
|
||
- API 类型唯一来源 `src/types/api.ts`(生成物);组件不手写与后端重复的响应类型。
|
||
- 跨域:开发期走 Vite;部署期为同域反代(见 [DEPLOYMENT.md](DEPLOYMENT.md)),`CORS_ORIGINS` 仅服务于非同域场景。
|