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

109 lines
7.3 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 前后端契约(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) 经 `_safe_include` 聚合(子 router 加载失败仅 WARNING 跳过;`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` | 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` | cam_router.py |
| 铝价(模拟数据) | `/api/aluminum-price/current`、`/api/aluminum-price/history` | aluminum_price_routes.py |
| 健康检查 | `/api/health` | health_router.py |
| 调试(仅 DEBUG) | `/api/debug/tasks` | debug_router.py |
| 导出/估算/设计等高级接口 | 见 `openapi.json` 对应路径 | advanced_router.py(技术债 D1:待拆分) |
### 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)。
- **当前已知滞后**:checked-in `openapi.json`(2026-07-27)落后当前代码(实际 76 paths vs 文件内 70),下次接口变更时按上述流程重导出。
## 5. 契约变更规则
- 新增接口先定模块归属(moldinsight / inventory / shared auth),再写路由;返回结构、路径、鉴权发生变化时,同步更新本文相应表格。
- 路由文件过大按职责拆分(现状债务:`advanced_router` 待拆分,见 [TECH_DEBT.md](TECH_DEBT.md) D1)。
- 破坏性变更(删字段 / 改语义)需在 [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` 仅服务于非同域场景。