15 KiB
15 KiB
商品模块 API 设计(v1)
企业级/混合模式版
0. 目标与范围
- 面向商业化外卖 SaaS,覆盖“总部主库 + 门店私库 + 多维度经营 + 可配置开关 + 可扩展集成”。
- 本文仅讨论 API 设计与契约,不涉及实现细节。
- 默认对齐项目现有约束:多租户、CQRS、统一响应、Snowflake ID、JWT/RBAC。
1. 通用规范
1.1 路由与版本
- AdminApi:
/api/admin/v1/... - MiniApi:
/api/mini/v1/... - UserApi:
/api/user/v1/...
1.2 鉴权与租户
- Header:
Authorization: Bearer {token} - 租户:
X-Tenant-Id或X-Tenant-Code(必填,除白名单路径) - 角色权限:AdminApi 必须绑定
PermissionAuthorize权限码
1.3 响应格式
统一使用 ApiResponse<T>,与现有 Shared.Web 约定一致。
1.4 ID 与并发
- 所有
long类型 ID 在 API 中 序列化为 string。 - 更新类接口需携带
rowVersion(Base64)或If-Match以并发控制。
1.5 幂等与限流
- 创建、批量变更、导入等写接口支持
Idempotency-Key。 - 面向公网端启用限流策略,读接口优先缓存。
1.6 分页与排序
统一参数:page、pageSize、sortBy、sortOrder(asc|desc)。
2. 产品原则(10 年外卖 SaaS 视角)
- 品牌一致性优先:总部主库保证品牌统一,门店仅允许“可控范围内的微调”。
- 经营灵活性必备:门店私有商品与局部覆盖是应对“城市、商圈、人力”的关键。
- C 端效率优先:类目不超过 2 级,菜单渲染优先走聚合与缓存。
- 扩展优先:渠道/场景/时段/三方同步都必须可开关,避免“为少数租户拖累成本”。
3. 功能域拆分(可开关)
3.1 核心域
- 公共商品库(Master Library,总部商品)
- 门店私有库(Store Library,本地特色)
- 引用/下发机制(Push & Pull)
- 类目管理(2 级以内 + 时段可见)
- 商品(Product/SPU)与规格 SKU
- 场景/渠道/时段维度可见性
- 计价与打包费策略
- 库存视图与沽清(含每日重置)
3.2 可选域
- 加料/口味(Addon/Modifier)
- 套餐/组合(Bundle/N 选 M)
- 称重计价与时价
- 后厨生产(KDS/打印标签/台位)
- 三方平台同步(美团/饿了么/抖音)
- 审核流与定时上架
- 多语言(I18n)
- 评分/销量统计视图(Stats)
4. 核心架构:公共商品库 + 门店私有库 + Push/Pull
4.1 公共商品库(Tenant/Master Library)
- 定义:总部创建的标准化商品。
- 作用:维护品牌统一形象(名称、图、描述、营养、后厨分类)。
- 管控:总部可锁定核心字段,门店仅可引用,不可篡改。
4.2 门店私有库(Store Private Library)
- 定义:门店为本地市场创建的特色商品。
- 作用:一店一策(开业活动、地域限定等)。
- 权限:仅本门店可见,总部可审计但默认不干预。
4.3 引用与下发(Push & Pull)
- 总部推送(Push):支持“静默上架”或“待门店确认”。
- 门店拉取(Pull):门店经理从公共库勾选引入到本店经营列表。
- 门店引用后允许“局部覆盖”,但不破坏主库锁定字段。
4.4 混合视图标识
- API 输出
libraryType+masterProductId,便于后台列表用标签区分来源。 lockedFields返回总部锁定字段,避免门店误操作。
5. 维度管理:类目、场景、渠道与时段
5.1 类目(2 级以内)
- 类目支持“生效时段”,如早餐类目 10:00 后隐藏。
- 类目可绑定“场景”,如堂食专属类目。
5.2 场景(履约场景)
- 堂食(DineIn)、外卖(Delivery)、自提(Pickup)。
- 外卖场景强制打包费规则;堂食可免打包费。
5.3 渠道(流量入口)
- 微信小程序、POS 点餐、美团、饿了么、抖音等。
- 支持“渠道隔离”:显示顺序、价格、上下架状态可独立配置。
5.4 维度优先级(建议)
门店覆盖 > 渠道配置 > 时段配置 > 商品基础配置。
6. 核心业务规则
6.1 覆盖机制(Override Rule)
- 门店可对价格、场景、上架/沽清做覆盖。
- 被锁定字段不允许覆盖;如需调整须总部解锁或走审核。
6.2 计价与打包费
- 计价模式:固定单价、按克计价(称重菜)、时价(随行就市)。
- 打包费支持按 SKU 设置,且可按场景配置(堂食可为 0)。
- 打包费支持单单封顶(不超过 X 元)。
6.3 库存与自动重置
- 支持门店级“每日自动恢复初始库存”(默认凌晨执行)。
- 沽清为临时状态,不影响主库与其他门店。
6.4 规格、加料与套餐
- SKU 影响价格与库存。
- 加料支持“收费加料 + 免费属性”,可配置选配上限/下限。
- 动态套餐支持“N 选 M”,并要求库存穿透:
- 套餐内关键单品沽清时,套餐自动联动下架。
6.5 生产与后厨(KDS/打印)
- 商品可绑定“打印标签 + 后厨台位”。
- 订单下发需标示场景,以区分堂食/外卖/自提出餐逻辑。
6.6 三方平台同步
- 内置 Mapping 机制,支持“商品—平台商品”映射。
- 价格/沽清变动触发事件总线,异步同步到平台接口。
7. 权限与审计
- 总部运营:管理主库、类目、全局规则、价格上限、审核流。
- 门店经理:门店私有商品、门店覆盖、今日沽清。
- 字段级审计日志:记录“谁在何时修改了哪个门店商品的价格/状态”。
- 推送审计:记录主库变更的下发范围与结果。
8. 功能开关(租户级)
用于“商业化套餐可选启用”。建议 AdminApi 提供读取能力,写入由套餐/配置管理模块控制。
示例结构:
{
"enableMasterLibrary": true,
"enableStoreLibrary": true,
"enablePushPull": true,
"enableVariant": true,
"enableAddon": true,
"enableBundle": true,
"enableSceneFilter": true,
"enableChannelIsolation": true,
"enableChannelPrice": true,
"enableTimePrice": true,
"enableStoreOverride": true,
"enablePricingWeight": true,
"enablePricingMarket": true,
"enablePackagingFee": true,
"enablePackagingFeeCap": true,
"enableDailyStockReset": true,
"enableInventory": true,
"enableApproval": false,
"enableScheduledPublish": true,
"enableKds": true,
"enableThirdPartySync": true,
"enableMultiLanguage": false,
"enableNutritionInfo": false
}
9. 关键 DTO(摘要)
字段命名遵循现有规范,布尔值使用
Is/Has前缀。
9.1 CategoryDto
| 字段 | 说明 |
|---|---|
| id | 类目 ID(string) |
| parentId | 父级类目 ID |
| name | 类目名称 |
| sortOrder | 排序 |
| isEnabled | 是否启用 |
| availableScenes | 生效场景 |
| availableTimeRanges | 生效时段 |
| createdAt | 创建时间 |
9.2 ProductDto(SPU)
| 字段 | 说明 |
|---|---|
| id | 商品 ID(string) |
| libraryType | Master/Store |
| masterProductId | 引用的主库商品 ID |
| storeId | 归属门店 |
| name | 商品名称 |
| categoryId | 类目 ID |
| unit | 单位 |
| tags | 标签 |
| coverImageUrl | 封面图 |
| imageUrls | 轮播图 |
| isEnabled | 是否启用 |
| isPublished | 是否上架 |
| hasSku | 是否包含 SKU |
| hasAddon | 是否包含加料 |
| pricingMode | Fixed/Weight/Market |
| basePrice | 基础价格 |
| packagingFee | 打包费(基础) |
| packagingFeeCap | 打包费封顶 |
| availableScenes | 生效场景 |
| availableChannels | 生效渠道 |
| lockedFields | 被总部锁定字段 |
| rowVersion | 并发字段 |
9.3 SkuDto
| 字段 | 说明 |
|---|---|
| id | SKU ID(string) |
| productId | 商品 ID |
| specValues | 规格值列表 |
| price | 价格 |
| stock | 库存 |
| isEnabled | 是否启用 |
| rowVersion | 并发字段 |
9.4 StoreProductOverrideDto
| 字段 | 说明 |
|---|---|
| storeId | 门店 ID |
| productId | 商品 ID |
| overridePrice | 覆盖价格 |
| overrideScenes | 覆盖场景 |
| isSoldOut | 是否沽清 |
| isApproved | 是否已审核 |
| overrideReason | 覆盖原因 |
9.5 AddonGroupDto(可选)
| 字段 | 说明 |
|---|---|
| id | 组 ID |
| name | 组名 |
| minSelected | 最少选择 |
| maxSelected | 最多选择 |
| isRequired | 是否必选 |
| items | 加料项列表 |
9.6 ChannelSettingDto(可选)
| 字段 | 说明 |
|---|---|
| channelCode | 渠道编码 |
| price | 渠道价格 |
| sortOrder | 渠道排序 |
| isEnabled | 是否启用 |
9.7 ProductionProfileDto(可选)
| 字段 | 说明 |
|---|---|
| kitchenStationId | 后厨台位 |
| printTagId | 打印标签 |
10. AdminApi(管理端)接口清单
10.1 公共商品库(总部)
GET /api/admin/v1/master-productsGET /api/admin/v1/master-products/{id}POST /api/admin/v1/master-productsPUT /api/admin/v1/master-products/{id}PUT /api/admin/v1/master-products/{id}/lock-fieldsPUT /api/admin/v1/master-products/{id}/publishPUT /api/admin/v1/master-products/{id}/unpublish
10.2 门店私有库与经营商品
GET /api/admin/v1/stores/{storeId}/productsPOST /api/admin/v1/stores/{storeId}/products(创建门店私有商品)POST /api/admin/v1/stores/{storeId}/products/pull(从主库拉取)PUT /api/admin/v1/stores/{storeId}/products/{id}PUT /api/admin/v1/stores/{storeId}/products/{id}/overridePUT /api/admin/v1/stores/{storeId}/products/{id}/publishPUT /api/admin/v1/stores/{storeId}/products/{id}/unpublishPUT /api/admin/v1/stores/{storeId}/products/{id}/sold-out
10.3 总部推送(Push)
POST /api/admin/v1/master-products/{id}/push(指定门店)GET /api/admin/v1/master-products/{id}/push-tasksPOST /api/admin/v1/push-tasks/{taskId}/retry
10.4 类目
GET /api/admin/v1/categoriesPOST /api/admin/v1/categoriesPUT /api/admin/v1/categories/{id}DELETE /api/admin/v1/categories/{id}PUT /api/admin/v1/categories/{id}/enablePUT /api/admin/v1/categories/{id}/disablePUT /api/admin/v1/categories/sort(批量排序)PUT /api/admin/v1/categories/{id}/schedule(类目时段)PUT /api/admin/v1/categories/{id}/scenes(类目场景)
10.5 规格与 SKU
GET /api/admin/v1/products/{id}/spec-groupsPUT /api/admin/v1/products/{id}/spec-groupsGET /api/admin/v1/products/{id}/skusPOST /api/admin/v1/products/{id}/skusPUT /api/admin/v1/skus/{id}PUT /api/admin/v1/skus/{id}/enablePUT /api/admin/v1/skus/{id}/disablePUT /api/admin/v1/skus/{id}/pricePUT /api/admin/v1/skus/{id}/stockPUT /api/admin/v1/skus/{id}/pricing-modePUT /api/admin/v1/skus/{id}/packaging-feePUT /api/admin/v1/skus/{id}/inventory-policy
10.6 场景/渠道/时段
PUT /api/admin/v1/products/{id}/scenesPUT /api/admin/v1/products/{id}/channelsPUT /api/admin/v1/products/{id}/time-slotsPUT /api/admin/v1/products/{id}/channel-mappingsPOST /api/admin/v1/products/{id}/channel-sync
10.7 加料/口味(可选)
GET /api/admin/v1/products/{id}/addon-groupsPUT /api/admin/v1/products/{id}/addon-groupsPUT /api/admin/v1/addon-groups/{id}/itemsPUT /api/admin/v1/addon-groups/{id}/enablePUT /api/admin/v1/addon-groups/{id}/disable
10.8 套餐/组合(可选)
GET /api/admin/v1/bundlesPOST /api/admin/v1/bundlesPUT /api/admin/v1/bundles/{id}PUT /api/admin/v1/bundles/{id}/publishPUT /api/admin/v1/bundles/{id}/unpublishPUT /api/admin/v1/bundles/{id}/itemsPUT /api/admin/v1/bundles/{id}/rules(N 选 M)
10.9 后厨生产(可选)
PUT /api/admin/v1/products/{id}/production-profilePUT /api/admin/v1/skus/{id}/production-profile
10.10 导入导出与索引
POST /api/admin/v1/products/importGET /api/admin/v1/products/import/{taskId}GET /api/admin/v1/products/exportPOST /api/admin/v1/products/reindex
10.11 审计与日志
GET /api/admin/v1/products/{id}/audit-logsGET /api/admin/v1/stores/{storeId}/products/{id}/override-logsGET /api/admin/v1/master-products/{id}/push-logs
10.12 功能开关读取
GET /api/admin/v1/products/features
11. MiniApi(小程序端)接口清单
GET /api/mini/v1/categories?scene=Delivery&channel=WeChatMiniProgramGET /api/mini/v1/menus/{storeId}?scene=Delivery&channel=WeChatMiniProgramGET /api/mini/v1/products?storeId=...&scene=Delivery&channel=WeChatMiniProgramGET /api/mini/v1/products/{id}?scene=Delivery&channel=WeChatMiniProgramGET /api/mini/v1/products/hot?storeId=...GET /api/mini/v1/products/recommended?storeId=...POST /api/mini/v1/products/price-estimatePOST /api/mini/v1/products/checkout-validatePOST /api/mini/v1/products/snapshots(订单服务调用)
12. UserApi(C 端用户)接口清单
GET /api/user/v1/categories?scene=Delivery&channel=H5GET /api/user/v1/menus/{storeId}?scene=Delivery&channel=H5GET /api/user/v1/products?storeId=...&scene=Delivery&channel=H5GET /api/user/v1/products/{id}?scene=Delivery&channel=H5GET /api/user/v1/products/hot?storeId=...GET /api/user/v1/products/recommended?storeId=...POST /api/user/v1/products/price-estimatePOST /api/user/v1/products/checkout-validate
13. 事件与扩展点
采用 Outbox 模式输出领域事件,便于搜索索引、缓存失效、推荐计算与三方同步。
MasterProductCreatedMasterProductUpdatedMasterProductPushedStoreProductPulledStoreProductOverriddenProductPriceChangedProductAvailabilityChangedProductSoldOutChangedSkuStockChangedProductChannelSyncRequested
14. 示例(关键请求)
14.1 商品创建(总部主库)
{
"name": "黄金鸡排饭",
"categoryId": "1782328933492367360",
"unit": "份",
"coverImageUrl": "https://cdn/xxx.jpg",
"imageUrls": ["https://cdn/xxx1.jpg", "https://cdn/xxx2.jpg"],
"pricingMode": "Fixed",
"basePrice": 19.9,
"isEnabled": true
}
14.2 门店覆盖(价格 + 场景)
{
"overridePrice": 21.9,
"overrideScenes": ["Delivery", "Pickup"],
"isSoldOut": false,
"overrideReason": "外卖平台佣金调整"
}
14.3 结算校验(Mini/User)
{
"storeId": "1782328933492367000",
"scene": "Delivery",
"channel": "WeChatMiniProgram",
"items": [
{
"productId": "1782328933492367360",
"skuId": "1782328933492367400",
"quantity": 2,
"addonItemIds": ["1782328933492367501", "1782328933492367502"]
}
]
}
15. 依赖说明
- 文件上传:复用 Storage 模块(FilesController)获取 URL。
- 库存:优先对接 Inventory 模块,商品侧仅提供视图与校验。
- 订单:下单时生成商品快照,避免历史价格漂移。
- 后厨:KDS/打印由生产模块承接,商品仅配置绑定信息。
- 三方同步:由集成服务监听事件并进行异步同步与重试。
- 权限码:
product.read、product.write、product.publish、product.import等(待统一权限表配置)。
待确认:渠道编码标准、称重计价精度与四舍五入规则、库存每日重置默认时间、Push 是否强制门店确认。