Files
baiyue-firstleg/docs/phase1-local-api.md
T
2026-07-31 16:53:07 +08:00

305 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.
# 一期本地联调 API 文档
## 1. 通用约定
统一基地址:`http://127.0.0.1:9000`;局域网前端使用 `http://192.168.110.149:9000`。除登录、注册、刷新和 Swagger 外,接口均携带:
```http
Authorization: Bearer <accessToken>
Content-Type: application/json
```
创建订单草稿和提交订单还必须携带 `Idempotency-Key`。同一操作者重试同一请求时复用原值;同一键用于不同请求返回 409,键缺失或长度超过 128 返回 400/422。
普通成功响应:
```json
{
"code": "0",
"message": "success",
"data": {},
"requestId": null,
"traceId": null,
"timestamp": "2026-07-30T12:00:00"
}
```
分页数据:
```json
{"records": [], "page": 1, "size": 20, "total": 0, "pages": 0}
```
常用业务错误码:`A0400` 参数错误、`A0401` 未登录、`A0403` 无权限、`A0404` 不存在、`A0409` 冲突、`A0422` 业务校验失败、`A0429` 请求过多、`B0001` 业务失败、`S0500` 服务异常、`S0503` 服务不可用。
## 2. 认证接口
| 方法 | 路径 | 登录要求 | 说明 |
|---|---|---|---|
| POST | `/api/auth/register` | 匿名 | 注册商户及租户 |
| POST | `/api/auth/login` | 匿名 | 平台、商户统一登录 |
| POST | `/api/auth/refresh` | 匿名 | 刷新令牌 |
| POST | `/api/auth/logout` | Access Token | 注销刷新令牌 |
注册请求:
```json
{
"username": "merchant_demo",
"password": "ChangeMe123!",
"displayName": "张三",
"companyName": "深圳示例贸易有限公司",
"legalPerson": "张三",
"legalPhone": "13800138000",
"contactEmail": "demo@example.com",
"countryCode": "CN",
"address": "广东省深圳市南山区测试路1号"
}
```
用户名为 4 至 64 位字母、数字或下划线,密码为 8 至 72 位。注册响应 `data`:`accountId,tenantId,membershipId,tenantStatus,nextStep`。
登录请求:
```json
{"username":"merchant_admin","password":"ChangeMe123!"}
```
登录/刷新响应 `data`:`tokenType,accessToken,expiresIn,refreshToken,refreshExpiresIn`。刷新和退出请求均为:
```json
{"refreshToken":"<refreshToken>"}
```
## 3. IAM 商户端
| 方法 | 路径 | 请求/响应 |
|---|---|---|
| GET | `/api/merchant/v1/iam/tenant/profile` | 返回当前 JWT 租户资料 |
| PUT | `/api/merchant/v1/iam/tenant/profile` | 更新当前租户资料 |
| GET | `/api/merchant/v1/iam/tenant/qualifications` | 返回当前租户资质列表 |
IAM 的商户资质接口只读。旧的 `POST /api/merchant/v1/iam/tenant/qualifications` 已移除,上传必须使用 File 服务的 multipart 接口,避免数据库出现没有真实文件支撑的 URL。
个人资料与修改密码:
| 方法 | 路径 | 说明 |
| --- | --- | --- |
| GET | `/api/merchant/v1/iam/profile` | 查询当前登录成员资料 |
| PUT | `/api/merchant/v1/iam/profile` | 编辑姓名、电话和邮箱 |
| PUT | `/api/auth/password` | 校验旧密码并修改本人密码,成功后撤销全部旧会话 |
成员与角色:
| 方法 | 路径 | 说明 |
| --- | --- | --- |
| GET/POST | `/api/merchant/v1/iam/members` | 成员列表、创建成员和认证账号 |
| GET/PUT | `/api/merchant/v1/iam/members/{membershipId}` | 成员详情、编辑资料和角色 |
| PUT | `/api/merchant/v1/iam/members/{membershipId}/status` | 启用或停用普通成员 |
| PUT | `/api/merchant/v1/iam/members/{membershipId}/password` | 管理员重置成员密码 |
| GET/POST | `/api/merchant/v1/iam/roles` | 角色列表、新建角色 |
| GET/PUT/DELETE | `/api/merchant/v1/iam/roles/{roleId}` | 角色详情、编辑、删除 |
| PUT | `/api/merchant/v1/iam/roles/{roleId}/status` | 启用或停用自定义角色 |
| GET | `/api/merchant/v1/iam/permissions` | 查询去重后的权限资源 |
| PUT | `/api/merchant/v1/iam/roles/permissions` | 全量保存角色权限 |
| GET | `/api/merchant/v1/iam/members/{membershipId}/roles` | 查询成员当前角色 |
| PUT | `/api/merchant/v1/iam/members/roles` | 全量保存或清空成员角色 |
成员列表和详情均返回 `displayName,phone,email,roleIds`;角色列表和详情均返回 `permissionIds`。企业所有者和系统角色受保护,已分配成员的自定义角色不能删除。
资料更新请求:
```json
{
"tenantName": "深圳示例贸易有限公司",
"legalName": "深圳示例贸易有限公司",
"contactName": "李四",
"contactPhone": "13900139000",
"contactEmail": "service@example.com"
}
```
资料响应字段:`id,tenantCode,tenantName,status,legalName,unifiedSocialCreditCode,contactName,contactPhone,contactEmail`。
## 4. IAM 平台审核
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
| GET | `/api/platform/v1/iam/reviews` | 平台身份 | 待审核记录 |
| GET | `/api/platform/v1/iam/tenants/{tenantId}/qualifications` | `platform:customer:review` | 指定租户资质 |
| POST | `/api/platform/v1/iam/reviews/{id}/approve` | `platform:customer:approve` | 审核通过 |
| POST | `/api/platform/v1/iam/reviews/{id}/reject` | `platform:customer:reject` | 审核驳回 |
平台登录初始化与后台管理:
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
| GET | `/api/{platform\|merchant}/v1/iam/authorization/permissions` | 已认证有效成员 | 实时返回当前有效权限,不要求角色管理权限 |
| GET | `/api/platform/v1/iam/tenants?page=1&size=20` | `platform:customer:list` | 仅分页查询商户企业,支持关键字与状态 |
| GET | `/api/platform/v1/iam/internal-users` | `platform:user:list` | 返回 `membershipId`、账号资料和 `roleIds` |
| POST | `/api/platform/v1/iam/internal-users` | `platform:user:create` | 创建或关联平台认证账号 |
| PUT | `/api/platform/v1/iam/internal-users/{membershipId}` | `platform:user:edit` | 编辑资料与角色 |
| PUT | `/api/platform/v1/iam/internal-users/{membershipId}/status` | `platform:user:status` | 启用或停用平台用户 |
| PUT | `/api/platform/v1/iam/internal-users/{membershipId}/password` | `platform:user:reset-password` | 重置密码,密码只转交 Auth |
审核请求:
```json
{"comment":"资料完整,审核通过"}
```
审核通过后租户状态为 `ACTIVE`、资质为 `APPROVED`;驳回后租户和资质为 `REJECTED`。
## 5. 资质文件
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | `/api/merchant/v1/files/qualifications` | 上传当前租户营业执照 |
| GET | `/api/merchant/v1/files/qualifications/{fileName}` | 商户下载自己的资质 |
| GET | `/api/platform/v1/files/qualifications/{tenantId}/{fileName}` | 平台查看指定租户资质 |
历史 `/phase1-seed/...` 路径不符合 File 服务契约,不能直接改成不存在的 UUID。处理步骤见 `docs/企业资质文件迁移说明.md`。
上传采用 `multipart/form-data`:`file` 必填,`certificateNo` 可选。只接受文件内容真实为 JPG/PNG 的图片,最大 5MB。上传成功 `data`:
```json
{
"qualificationId": 1,
"reviewId": 1,
"tenantStatus": "PENDING",
"documentUrl": "/api/merchant/v1/files/qualifications/文件名.png"
}
```
下载接口直接返回图片二进制,不使用统一 JSON 包装。
## 6. 商户头程订单
基路径:`/api/merchant/v1/orders/first-leg`。
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
| POST | `/api/merchant/v1/orders/first-leg` | `merchant:order:create` | 创建草稿,必须携带 `Idempotency-Key`,`data` 为订单 ID |
| PUT | `/api/merchant/v1/orders/first-leg/{id}` | `merchant:order:edit` | 编辑草稿 |
| GET | `/api/merchant/v1/orders/first-leg` | 商户身份 | 分页查询自己的订单 |
| GET | `/api/merchant/v1/orders/first-leg/{id}` | 商户身份 | 查询自己的订单详情 |
| POST | `/api/merchant/v1/orders/first-leg/{id}/submit` | `merchant:order:submit` | 提交订单,必须携带 `Idempotency-Key` |
列表参数:`keyword,status,customerId,destinationWarehouseId,createdFrom,createdTo,page,size`;`page` 从 1 开始,`size` 为 1 至 200。
创建/编辑请求示例:
```json
{
"customerId": 10001,
"customerName": "深圳示例贸易有限公司",
"transportMode": "SEA",
"tradeTerm": "FOB",
"destinationCountryCode": "US",
"destinationWarehouseId": 1001,
"destinationWarehouseName": "ONT8",
"expectedShipDate": "2026-08-15",
"customerRemark": "提货前联系",
"pickupMethod": "PICKUP",
"receivingWarehouseId": 2001,
"receivingWarehouseName": "深圳收货仓",
"channelCode": "SEA-US-FBA",
"channelName": "美国海运渠道",
"taxMode": "BUY_DECLARATION",
"containerMode": "LCL",
"customsInspection": false,
"destinationType": "FBA",
"amazonWarehouseCode": "ONT8",
"shipmentId": "FBA20260730001",
"referenceId": "REF20260730001",
"sender": {
"companyName": "深圳示例贸易有限公司",
"contactName": "张三",
"phone": "13800138000",
"email": "sender@example.com",
"countryCode": "CN",
"province": "广东",
"city": "深圳",
"district": "南山",
"addressLine": "测试路1号",
"postalCode": "518000"
},
"receiver": {
"companyName": "Amazon",
"contactName": "ONT8",
"phone": "1234567890",
"email": "ont8@example.com",
"countryCode": "US",
"province": "CA",
"city": "Moreno Valley",
"district": "Riverside",
"addressLine": "24300 Nandina Ave",
"postalCode": "92551"
},
"cargoes": [{
"cargoName": "蓝牙音箱",
"hsCode": "8518210000",
"packageType": "CARTON",
"packageCount": 2,
"grossWeightKg": 20.5,
"volumeCbm": 0.2,
"declaredValue": 200,
"currency": "USD",
"dangerousGoods": false,
"totalQuantity": 20,
"netWeightKg": 18
}]
}
```
枚举约束:`transportMode=SEA|AIR|RAIL|TRUCK`;`pickupMethod=SELF_EXPRESS|PICKUP|SELF_TRUCK`;`taxMode=BUY_DECLARATION|TAX_REFUND`;`containerMode=FULL_CONTAINER|LCL`;`destinationType=FBA|OVERSEAS|PRIVATE`。
订单详情 `data` 包含 `order,cargoes,parties,internalNotes,statusHistory`。商户详情的 `internalNotes` 固定为空;平台内部备注不得向商户展示。企业必须为 `ACTIVE` 且至少有一项 `APPROVED` 资质,才能创建和提交订单。
## 7. 一期相关查询接口
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | `/api/merchant/v1/warehouses?page=1&size=20` | 商户仓库列表 |
| GET | `/api/merchant/v1/warehouses/{warehouseId}` | 启用仓库详情、地址、能力和收货截单时间 |
| GET | `/api/merchant/v1/partners/candidates` | 当前租户启用往来单位候选 |
| GET | `/api/merchant/v1/partners/{partnerId}` | 当前租户启用往来单位详情 |
| GET | `/api/platform/v1/warehouse-admin?tenantId={tenantId}&page=1&size=20` | 平台仓储列表 |
| GET | `/api/platform/v1/partners?tenantId={tenantId}&page=1&size=20` | 平台往来单位分页,需要 `platform:counterparty:list` |
| GET | `/api/platform/v1/partners/{id}?tenantId={tenantId}` | 平台往来单位详情,需要 `platform:counterparty:list` |
| POST | `/api/platform/v1/partners?tenantId={tenantId}` | 新增往来单位,需要 `platform:counterparty:create` |
| PUT | `/api/platform/v1/partners/{id}?tenantId={tenantId}` | 编辑往来单位,需要 `platform:counterparty:edit` |
| PATCH | `/api/platform/v1/partners/{id}/status?tenantId={tenantId}` | 启用或停用往来单位,需要 `platform:counterparty:status` |
| GET | `/api/platform/v1/express-companies?tenantId={tenantId}&page=1&size=20` | 平台快递公司分页,需要 `platform:express:list` |
| GET | `/api/platform/v1/express-companies/{id}?tenantId={tenantId}` | 平台快递公司详情,需要 `platform:express:list` |
| POST | `/api/platform/v1/express-companies?tenantId={tenantId}` | 新增快递公司,需要 `platform:express:create` |
| PUT | `/api/platform/v1/express-companies/{id}?tenantId={tenantId}` | 编辑快递公司,需要 `platform:express:edit` |
| PATCH | `/api/platform/v1/express-companies/{id}/status?tenantId={tenantId}` | 启用或停用快递公司,需要 `platform:express:status` |
| GET | `/api/platform/v1/first-leg/tasks?tenantId={tenantId}&page=1&size=20` | 履约任务分页,需要 `platform:firstleg:task:list` |
| GET | `/api/platform/v1/first-leg/tasks/{taskId}?tenantId={tenantId}` | 履约任务详情,需要 `platform:firstleg:task:view` |
| GET | `/api/platform/v1/first-leg/tasks/by-order/{orderId}?tenantId={tenantId}` | 按订单查询履约任务,需要 `platform:firstleg:task:view` |
| GET | `/api/platform/v1/first-leg/tasks/{taskId}/assignment-history?tenantId={tenantId}` | 分配历史,需要 `platform:firstleg:assignment:history` |
| POST | `/api/platform/v1/first-leg/tasks/{taskId}/assignment?tenantId={tenantId}` | 分配或改派,需要 `platform:firstleg:assignment:assign` |
| GET | `/api/platform/v1/iam/status` | IAM 网关路由状态 |
| GET | `/api/platform/v1/orders/status` | Order 网关路由状态 |
| GET | `/api/platform/v1/first-leg/status` | Firstleg 网关路由状态 |
| GET | `/api/platform/v1/warehouses/status` | Warehouse 网关路由状态 |
| GET | `/api/platform/v1/files/status` | File 网关路由状态 |
| GET | `/api/platform/v1/print/status` | Print 网关路由状态 |
往来单位由 `warehouse-service` 承载,表为 `baiyue_warehouse.wh_partner`,不是独立服务或独立数据库。仓库和往来单位查询强制执行租户隔离和停用过滤。
平台往来单位和快递公司均为目标商户租户下的主数据,因此所有平台管理接口都必须显式传入 `tenantId`,缺失或小于 1 返回参数错误。`/api/platform/v1/warehouses/status` 会实际探测仓库、地址、服务能力、往来单位和快递公司表的必需字段;缺表或缺列返回 HTTP 503 且状态为 `DEGRADED`。业务查询遇到数据源不可用或结构漂移时统一返回 `S0503`,不再用 `S0500` 隐藏迁移问题。
部署到既有数据库时,除主建表脚本外还要执行 `firstleg/src/main/resources/db/phase1-firstleg-task-list-index.sql`;该脚本可重复执行,用于补齐履约任务租户时间分页索引。
平台履约可通过 `PUT /api/platform/v1/orders/first-leg/{orderId}/express?tenantId={tenantId}` 写入 `expressCompany,expressTrackingNo`;商户端只能在订单详情读取,不能维护快递公司或调用平台写接口。
## 8. Swagger 分组
入口:`http://127.0.0.1:9000/swagger-ui.html`。当前可用分组:Auth 平台、IAM 平台/商户、Order 平台/商户、Firstleg 平台、Warehouse 平台/商户、File 平台/商户、Print 平台。
## 9. 一期明确不纳入
订单平台审核、受理、履约、完成、取消;尾程业务;跨区域事件通知;测试/生产部署,均不属于本地一期前端联调验收范围。