feat(catalog): add product catalog APIs
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
# R1 商品目录接口对接说明
|
||||
|
||||
**提供方:成员 1(R1 商品目录)**
|
||||
|
||||
**消费者:成员 2(设计清单)、成员 3(订单)、成员 4(设计/生产数据)**
|
||||
|
||||
**分支:`feat/r1-catalog`**
|
||||
|
||||
本文档是 R1 向其他路线交付商品数据的简明使用说明。字段、路径与
|
||||
[`api-contract-v1.md`](./api-contract-v1.md) 第 3 节一致;发生冲突时以 API 契约为准。
|
||||
|
||||
## 1. 使用边界
|
||||
|
||||
- 商品与分类查询都是公开接口,调用时必须传 `auth: false`,不依赖登录态。
|
||||
- 消费方只能读取在售商品;下架或不存在的商品详情返回 `404`。
|
||||
- `productId` 是跨路线的稳定业务 ID,不能用数据库生成顺序、数组下标或展示名称替代。
|
||||
- `price` 是服务端权威价格。前端可展示,**不能**作为下单金额依据。
|
||||
|
||||
## 2. 稳定商品 ID
|
||||
|
||||
| productId | 商品 |
|
||||
|---|---|
|
||||
| `notebook-small` | 微雕笔记本(小) |
|
||||
| `notebook-large` | 微雕笔记本(大) |
|
||||
| `coaster` | 铜质杯垫 |
|
||||
| `penbox` | 竹制笔盒 |
|
||||
| `booklamp` | 书本型灯 |
|
||||
|
||||
每个商品都对应一个稳定分类 ID:`cat-<productId>`,例如 `cat-penbox`。
|
||||
|
||||
## 3. 查询接口
|
||||
|
||||
### `GET /api/categories`
|
||||
|
||||
返回扁平分类数组,已按 `sort` 升序排列。
|
||||
|
||||
```ts
|
||||
type CategoryDTO = {
|
||||
id: string
|
||||
name: string
|
||||
parentId?: string | null
|
||||
sort: number
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/products`
|
||||
|
||||
查询参数均可选:
|
||||
|
||||
```ts
|
||||
{
|
||||
page?: number // 默认 1
|
||||
pageSize?: number // 默认 20,最大 100
|
||||
categoryId?: string
|
||||
keyword?: string // 匹配名称、副标题、描述
|
||||
}
|
||||
```
|
||||
|
||||
响应 `data`:
|
||||
|
||||
```ts
|
||||
{
|
||||
list: ProductDTO[]
|
||||
total: number
|
||||
page: number
|
||||
pageSize: number
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/products/:id`
|
||||
|
||||
返回一个在售商品;商品不存在或不是 `ON_SALE` 时返回 `404`。
|
||||
|
||||
```ts
|
||||
type ProductDTO = {
|
||||
id: string
|
||||
name: string
|
||||
categoryId?: string
|
||||
price: number // 元,服务端已转为 number
|
||||
originalPrice?: number
|
||||
leadTime: string
|
||||
subtitle?: string
|
||||
description?: string
|
||||
story?: string
|
||||
scene?: string
|
||||
tags: string[]
|
||||
specs: [string, string][]
|
||||
tone: [number, number, number]
|
||||
mask: {
|
||||
shape: 'rect' | 'circle'
|
||||
width: number
|
||||
height: number
|
||||
borderRadius?: number
|
||||
}
|
||||
images: string[]
|
||||
iconImg?: string
|
||||
status: 'ON_SALE'
|
||||
sort: number
|
||||
}
|
||||
```
|
||||
|
||||
所有接口沿用统一响应包裹:`{ code: 0, message: 'ok', data }`。
|
||||
|
||||
## 4. 前端调用方式
|
||||
|
||||
前端消费者统一从 R1 API 层调用,不能在页面直接拼 HTTP 请求:
|
||||
|
||||
```ts
|
||||
import { fetchCategories, fetchProduct, fetchProducts } from '../../utils/api/product'
|
||||
|
||||
const { list } = await fetchProducts({ keyword: '笔记本', page: 1, pageSize: 20 })
|
||||
const product = await fetchProduct('penbox')
|
||||
const categories = await fetchCategories()
|
||||
```
|
||||
|
||||
## 5. 给成员 2:设计清单
|
||||
|
||||
设计清单保存商品相关数据时使用:
|
||||
|
||||
```ts
|
||||
{
|
||||
productId: product.id,
|
||||
productName: product.name,
|
||||
unitPrice: product.price, // 仅展示/设计清单快照;不是订单结算依据
|
||||
count: quantity,
|
||||
designData: {
|
||||
category: { id: product.id, mask: product.mask, tone: product.tone },
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
`mask` 与 `tone` 必须原样保留,供 R4 构造生产画布;不要把 `productName` 当作关联键。
|
||||
|
||||
## 6. 给成员 3:订单
|
||||
|
||||
R3 创建订单时,客户端请求只传:
|
||||
|
||||
```ts
|
||||
{
|
||||
items: [{ productId: 'penbox', quantity: 1 }]
|
||||
}
|
||||
```
|
||||
|
||||
R3 服务端必须:
|
||||
|
||||
1. 按 `productId` 查询商品并确认 `status === ON_SALE`;
|
||||
2. 以服务端 `price` 重算订单总价;
|
||||
3. 将 `productId`、`name`、`price`、`quantity` 写进 `OrderItem` 快照;
|
||||
4. 忽略客户端传入的单价、商品名和总金额。
|
||||
|
||||
## 7. 给成员 4:设计与生产
|
||||
|
||||
R4 若需要从商品恢复画布尺寸或主题色,使用 `ProductDTO.mask` 和 `ProductDTO.tone`。
|
||||
生产任务内保存的是设计快照;不要仅凭商品名称重新定位商品。
|
||||
|
||||
## 8. 联调前置条件
|
||||
|
||||
R1 合入或本地联调前,后端需要先执行数据库迁移与种子数据:
|
||||
|
||||
```bash
|
||||
npm run prisma:migrate
|
||||
npm run prisma:seed
|
||||
```
|
||||
|
||||
最小 smoke 验收:
|
||||
|
||||
```text
|
||||
GET /api/categories
|
||||
GET /api/products?page=1&pageSize=20
|
||||
GET /api/products/penbox
|
||||
GET /api/products/not-on-sale-or-missing -> 404
|
||||
```
|
||||
Reference in New Issue
Block a user