# Platform Master — API 参考

> **module**: platform-master
> **doc_type**: API
> **status**: Active (v3 PR2-4)
> **last_verified**: 2026-05-17

## 1. 路径前缀 + 鉴权

- 所有端点以 `/api/v1/platform-master/...` 开头
- 全局 `JwtAuthGuard`：必须 `Authorization: Bearer <accessToken>`
- 响应统一被 `TransformInterceptor` 包装为 `{ code, data, message }`

## 2. L1b 字典 / 参考数据（已上线）

### 货币 / 国家 / 区域 / 计量单位

| Method | Path | 说明 |
|---|---|---|
| GET | `/currencies` | 全部货币 |
| GET | `/currencies/:code` | 单个（如 USD）|
| POST | `/currencies` | 新建货币（admin） |
| PUT | `/currencies/:code` | 更新货币（admin） |
| DELETE | `/currencies/:code` | 软删除 / 禁用（admin） |
| POST | `/currencies/:code/enable` | 启用（admin） |
| GET | `/countries` | 全部 |
| GET | `/countries?region=APAC` | 按 region 过滤 |
| GET | `/countries/:code` | 单个 |
| GET | `/geo-regions` | 全部 |
| GET | `/geo-regions/:code` | 单个 |
| GET | `/units-of-measure` | 全部 |
| GET | `/units-of-measure?category=weight` | 按 category 过滤 |
| GET | `/units-of-measure/:code` | 单个 |

**Currency 写端点 DTO**（POST / PUT）：

```ts
{
  code: string;       // e.g. "USD"（POST 必填，PUT 不变）
  name: string;       // POST 必填
  symbol?: string;    // e.g. "$"
  decimals?: number;  // 默认 2
  enabled?: boolean;  // 默认 true
}
```

权限：`robot-manager:manage:customers`（v3 临时复用，待 followup PR 改为 `platform-master:manage:reference-data` + seed 权限点）
错误码：`INVALID_CURRENCY_CODE`（code 格式非法）/ `CURRENCY_EXISTS`（POST 重复 code）

### 通用字典 (`/dictionaries`)

| Method | Path | 说明 |
|---|---|---|
| GET | `/dictionaries/categories` | 返回所有 category 列表（5 个）|
| GET | `/dictionaries?category=label_type` | 按 category 列出。**`category` 必填**，否则 400 |
| GET | `/dictionaries/:category/:code` | 单个字典项（如 `/dictionaries/label_type/BODY_FCC`）|

返回字段：`{ id, category, code, labelEn, labelZh, sortOrder, enabled, metadata }`

## 3. L1a 主数据（v3 已上线）

### Customer / Supplier / Partner / Location

4 类主数据均提供标准 REST CRUD + soft-delete + restore。统一前缀 `/api/v1/platform-master/`。

| 实体 | List | Get | Create | Update | Soft-delete | Restore |
|---|---|---|---|---|---|---|
| Customer | `GET /customers` | `GET /customers/:id` | `POST /customers` | `PUT /customers/:id` | `DELETE /customers/:id` | `POST /customers/:id/restore` |
| Supplier | `GET /suppliers` | `GET /suppliers/:id` | `POST /suppliers` | `PUT /suppliers/:id` | `DELETE /suppliers/:id` | `POST /suppliers/:id/restore` |
| Partner | `GET /partners` | `GET /partners/:id` | `POST /partners` | `PUT /partners/:id` | `DELETE /partners/:id` | `POST /partners/:id/restore` |
| Location | `GET /locations` | `GET /locations/:id` | `POST /locations` | `PUT /locations/:id` | `DELETE /locations/:id` | `POST /locations/:id/restore` |

**List Query**（4 种共通）：
- `search` — 模糊匹配 code / name
- `enabledOnly` — `true` 仅返启用项
- `type` — `Customer`: B2B/B2C/INTERNAL；`Supplier`: MANUFACTURER/PARTS/LOGISTICS/SERVICE；`Partner`/`Location`: 各自 typeCode 字典
- `regionCode` — `Customer`/`Location` 按 region 过滤

**写端点共通行为**：
- POST 创建：失败抛 `MASTER_CODE_EXISTS`（code unique 冲突）
- PUT 更新：未找到抛 404
- DELETE 软删除（`deletedAt` 标记，列表默认不含；`?includeDeleted=true` 含软删项）
- POST `:id/restore` 把 `deletedAt` 清空恢复

**权限**：
- Read（List/Get）：`robot-manager:read`
- Write（Create/Update/Delete/Restore）：`robot-manager:manage:{customers|suppliers|partners|locations}`（v3 临时复用 robot-manager 权限点，待 followup epic 改为 `platform-master:manage:*`）

**DTO 共通字段**：
- `code`（unique，create 必填）
- `name`（必填）
- `enabled`（默认 true）
- `description`（可选）
- 实体特定字段见 [06-data-model.md](06-data-model.md)

**未实现的子资源**（M2/M3 补）：
- `/customers/:id/contacts` + `/customers/:id/addresses`
- `/suppliers/:id/contacts` / `/partners/:id/contacts`
- `/locations` 层级查询 / 客户站点过滤

## 4. L1c Attachment（多态）

```
GET    /attachments?ownerType=robot_unit&ownerId=:uuid
POST   /attachments (multipart/form-data + ownerType + ownerId + category?)
DELETE /attachments/:id
```

## 5. 错误码

跟 standard `08-error-codes` 一致：
- `PLATFORM_MASTER_DUPLICATE_CODE` — 业务码重复
- `PLATFORM_MASTER_FK_VIOLATION` — 外键引用错（如 customerCode 在被引用时不能删）

## 6. 关联

- [01-prd.md](./01-prd.md) — 模块定位 + 范围
- [06-data-model.md](./06-data-model.md) — 完整 schema
