From 9e571f13cf051f75f0cc6844bcb6ba811994ab4f Mon Sep 17 00:00:00 2001 From: MSuMshk <2039814060@qq.com> Date: Fri, 23 Jan 2026 14:23:50 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E5=95=86=E5=93=81?= =?UTF-8?q?=E6=A8=A1=E5=9D=97API=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 商品模块_API设计_v1.md | 426 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 426 insertions(+) create mode 100644 商品模块_API设计_v1.md diff --git a/商品模块_API设计_v1.md b/商品模块_API设计_v1.md new file mode 100644 index 0000000..d6a1150 --- /dev/null +++ b/商品模块_API设计_v1.md @@ -0,0 +1,426 @@ +# 商品模块 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`,与现有 `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 提供读取能力,写入由套餐/配置管理模块控制。 + +示例结构: +```json +{ + "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-products` +- `GET /api/admin/v1/master-products/{id}` +- `POST /api/admin/v1/master-products` +- `PUT /api/admin/v1/master-products/{id}` +- `PUT /api/admin/v1/master-products/{id}/lock-fields` +- `PUT /api/admin/v1/master-products/{id}/publish` +- `PUT /api/admin/v1/master-products/{id}/unpublish` + +### 10.2 门店私有库与经营商品 +- `GET /api/admin/v1/stores/{storeId}/products` +- `POST /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}/override` +- `PUT /api/admin/v1/stores/{storeId}/products/{id}/publish` +- `PUT /api/admin/v1/stores/{storeId}/products/{id}/unpublish` +- `PUT /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-tasks` +- `POST /api/admin/v1/push-tasks/{taskId}/retry` + +### 10.4 类目 +- `GET /api/admin/v1/categories` +- `POST /api/admin/v1/categories` +- `PUT /api/admin/v1/categories/{id}` +- `DELETE /api/admin/v1/categories/{id}` +- `PUT /api/admin/v1/categories/{id}/enable` +- `PUT /api/admin/v1/categories/{id}/disable` +- `PUT /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-groups` +- `PUT /api/admin/v1/products/{id}/spec-groups` +- `GET /api/admin/v1/products/{id}/skus` +- `POST /api/admin/v1/products/{id}/skus` +- `PUT /api/admin/v1/skus/{id}` +- `PUT /api/admin/v1/skus/{id}/enable` +- `PUT /api/admin/v1/skus/{id}/disable` +- `PUT /api/admin/v1/skus/{id}/price` +- `PUT /api/admin/v1/skus/{id}/stock` +- `PUT /api/admin/v1/skus/{id}/pricing-mode` +- `PUT /api/admin/v1/skus/{id}/packaging-fee` +- `PUT /api/admin/v1/skus/{id}/inventory-policy` + +### 10.6 场景/渠道/时段 +- `PUT /api/admin/v1/products/{id}/scenes` +- `PUT /api/admin/v1/products/{id}/channels` +- `PUT /api/admin/v1/products/{id}/time-slots` +- `PUT /api/admin/v1/products/{id}/channel-mappings` +- `POST /api/admin/v1/products/{id}/channel-sync` + +### 10.7 加料/口味(可选) +- `GET /api/admin/v1/products/{id}/addon-groups` +- `PUT /api/admin/v1/products/{id}/addon-groups` +- `PUT /api/admin/v1/addon-groups/{id}/items` +- `PUT /api/admin/v1/addon-groups/{id}/enable` +- `PUT /api/admin/v1/addon-groups/{id}/disable` + +### 10.8 套餐/组合(可选) +- `GET /api/admin/v1/bundles` +- `POST /api/admin/v1/bundles` +- `PUT /api/admin/v1/bundles/{id}` +- `PUT /api/admin/v1/bundles/{id}/publish` +- `PUT /api/admin/v1/bundles/{id}/unpublish` +- `PUT /api/admin/v1/bundles/{id}/items` +- `PUT /api/admin/v1/bundles/{id}/rules`(N 选 M) + +### 10.9 后厨生产(可选) +- `PUT /api/admin/v1/products/{id}/production-profile` +- `PUT /api/admin/v1/skus/{id}/production-profile` + +### 10.10 导入导出与索引 +- `POST /api/admin/v1/products/import` +- `GET /api/admin/v1/products/import/{taskId}` +- `GET /api/admin/v1/products/export` +- `POST /api/admin/v1/products/reindex` + +### 10.11 审计与日志 +- `GET /api/admin/v1/products/{id}/audit-logs` +- `GET /api/admin/v1/stores/{storeId}/products/{id}/override-logs` +- `GET /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=WeChatMiniProgram` +- `GET /api/mini/v1/menus/{storeId}?scene=Delivery&channel=WeChatMiniProgram` +- `GET /api/mini/v1/products?storeId=...&scene=Delivery&channel=WeChatMiniProgram` +- `GET /api/mini/v1/products/{id}?scene=Delivery&channel=WeChatMiniProgram` +- `GET /api/mini/v1/products/hot?storeId=...` +- `GET /api/mini/v1/products/recommended?storeId=...` +- `POST /api/mini/v1/products/price-estimate` +- `POST /api/mini/v1/products/checkout-validate` +- `POST /api/mini/v1/products/snapshots`(订单服务调用) + +## 12. UserApi(C 端用户)接口清单 +- `GET /api/user/v1/categories?scene=Delivery&channel=H5` +- `GET /api/user/v1/menus/{storeId}?scene=Delivery&channel=H5` +- `GET /api/user/v1/products?storeId=...&scene=Delivery&channel=H5` +- `GET /api/user/v1/products/{id}?scene=Delivery&channel=H5` +- `GET /api/user/v1/products/hot?storeId=...` +- `GET /api/user/v1/products/recommended?storeId=...` +- `POST /api/user/v1/products/price-estimate` +- `POST /api/user/v1/products/checkout-validate` + +## 13. 事件与扩展点 +采用 Outbox 模式输出领域事件,便于搜索索引、缓存失效、推荐计算与三方同步。 +- `MasterProductCreated` +- `MasterProductUpdated` +- `MasterProductPushed` +- `StoreProductPulled` +- `StoreProductOverridden` +- `ProductPriceChanged` +- `ProductAvailabilityChanged` +- `ProductSoldOutChanged` +- `SkuStockChanged` +- `ProductChannelSyncRequested` + +## 14. 示例(关键请求) +### 14.1 商品创建(总部主库) +```json +{ + "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 门店覆盖(价格 + 场景) +```json +{ + "overridePrice": 21.9, + "overrideScenes": ["Delivery", "Pickup"], + "isSoldOut": false, + "overrideReason": "外卖平台佣金调整" +} +``` + +### 14.3 结算校验(Mini/User) +```json +{ + "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 是否强制门店确认。