spec.md 9.5 KB

Feature Specification: 商品规格(SKU 规格)管理

Feature Branch: 在 test 分支直接开发(按用户要求不创建特性分支)

Created: 2026-07-15

Status: Draft

Input: User description: "将 cte_server 的商品规格功能移植到 foodie_server,包括商品规格的管理、商品使用规格、商品列表返回规格信息"

User Scenarios & Testing (mandatory)

User Story 1 - 商家管理门店规格模板 (Priority: P1)

商家在商家端维护本门店可复用的"规格"(如甜度、加料、辣度)。每个规格是一个规格组,组下有若干规格值(如"无糖/半糖/全糖"、"珍珠/椰果"),每个规格值可设定加价金额。规格组支持单选/多选、必选/可选、排序、启用/停用、软删除。

Why this priority: 规格模板是商品使用规格的前提;没有它,商品无处挂规格,是整个功能的基础。

Independent Test: 商家新增一个"甜度"规格(单选/必选),下设"无糖(加价0)/半糖(0)/全糖(0)"三个规格值,保存后在规格列表可见、可编辑、可停用。

Acceptance Scenarios:

  1. Given 商家已登录其门店,When 商家新增规格组并填入名称、选择类型(单选/多选)、必选/可选、若干规格值及加价,Then 保存成功且列表可见。
  2. Given 规格组已存在,When 商家编辑修改名称或增删规格值,Then 保存后详情反映最新内容。
  3. Given 规格组/规格值已存在,When 商家停用某规格组或某规格值,Then 该规格组/值在"商品可用规格"中不再出现。
  4. Given 规格组已存在,When 商家删除规格组,Then 执行软删除,商品可用规格列表不再显示,但已生成订单与历史快照不受影响。

User Story 2 - 商品使用规格 (Priority: P1)

商家在新增/编辑商品时,可从本门店"可用规格"中勾选若干规格组挂到该商品上。保存商品时,商品与所选规格组建立关联;重新勾选时,旧的关联被清除、新的关联被建立。

Why this priority: 这是规格功能的落地环节,没有它规格模板毫无意义,与 Story 1 同属 MVP。

Independent Test: 商家编辑"珍珠奶茶",勾选"甜度""加料"两个规格组,保存后商品详情能返回这两个规格。

Acceptance Scenarios:

  1. Given 门店已有可用规格,When 商家编辑商品并勾选规格组,Then 保存后商品与规格建立关联。
  2. Given 商品已挂规格,When 商家编辑时重新勾选(增减规格组),Then 保存后关联更新(旧关联清除、新关联建立)。
  3. Given 商品未挂任何规格,When 商家不勾选,Then 商品按无规格售卖(兼容现有行为)。

User Story 3 - 商品列表与详情返回规格 (Priority: P1)

商品列表(按分类、按门店、搜索分页)和商品详情接口返回该商品的规格结构(规格组 + 规格值 + 加价),前端据此渲染规格选择。顾客选定规格值后,所选规格值的加价累加到商品基础价。

Why this priority: 规格必须能被下单链路消费,否则规格只是摆设,属于核心价值闭环。

Independent Test: 顾客打开一个挂了规格的商品详情,能看到规格选项及对应加价。

Acceptance Scenarios:

  1. Given 商品挂了规格,When 查询商品列表/详情,Then 返回完整规格结构(仅含启用的规格组与规格值)。
  2. Given 商品未挂规格,When 查询,Then 返回空规格(与现有无规格行为兼容)。
  3. Given 顾客选了若干规格值,When 计算价格,Then 实付单价 = 商品基础价 + 所选规格值加价之和。

User Story 4 - 规格与订单/促销价格口径统一 (Priority: P2)

顾客选规格下单时,订单商品快照保存所选规格及加价;促销算价将规格加价计入。与现有 specPrice/otherPrice 加价口径对齐,保证下单、促销、订单各环节金额一致。

Why this priority: 保证规格价格在跨环节一致、避免算错钱;属正确性保障,依赖前三条已具备能力,故 P2。

Independent Test: 顾客选加价规格下单,订单快照含规格与加价,且金额与所选规格加价完全一致。

Acceptance Scenarios:

  1. Given 顾客选规格下单,When 生成订单,Then 订单商品快照记录所选规格及加价。
  2. Given 订单含规格加价,When 参与促销算价,Then 规格加价正确叠加到单价。

Edge Cases

  • 商品已挂的规格组随后被门店停用/删除:列表与详情返回时自动剔除该规格组(顾客不可选)。
  • 规格值加价在商品售卖期间发生变更:已生成的订单快照不受影响(快照独立、不可变)。
  • 多语言:规格组/规格值名称需按门店 + 语言维度管理(项目支持 vi/zh/tw/en)。
  • 门店隔离:A 门店的规格对 B 门店完全不可见。
  • 商品保存同时携带结构化规格关联与旧版 food_sku JSON:以结构化规格关联为权威来源,food_sku JSON 作为冗余兼容字段同步更新。
  • 后台管理通道(平台端商品新增/编辑)当前不写规格信息:需统一收口,保证两条保存通道都能持久化规格。

Requirements (mandatory)

Functional Requirements

  • FR-001: 系统 MUST 支持门店级"规格组"的增、删(软删)、改、查;每个规格组包含名称、选择类型(单选/多选)、是否必选、排序、启用状态、所属门店、语言。
  • FR-002: 每个规格组下 MUST 能管理若干"规格值",每个规格值包含名称、加价金额、备注、启用状态。
  • FR-003: 规格组与规格值 MUST 支持启用/停用,停用后在"商品可用规格"中不可见。
  • FR-004: 商家编辑商品时 MUST 能从本门店可用规格中多选规格组挂到商品。
  • FR-005: 保存商品时系统 MUST 维护商品与规格组的关联(重新勾选时清除旧关联、建立新关联)。
  • FR-006: 商品列表(按分类、按门店、搜索分页)与商品详情接口 MUST 返回该商品的规格结构(仅启用的规格组与规格值)。
  • FR-007: 顾客选定规格后,实付单价 MUST 等于商品基础价加上所选规格值加价之和。
  • FR-008: 下单时订单商品快照 MUST 记录所选规格及加价,且促销算价将规格加价计入(与现有 specPrice/otherPrice 口径一致)。
  • FR-009: 规格数据 MUST 按门店隔离,A 门店的规格对 B 门店不可见。
  • FR-010: 规格组与规格值 MUST 支持多语言(vi/zh/tw/en)。
  • FR-011: 后台管理通道(平台端商品新增/编辑)保存商品时也 MUST 能正确持久化规格信息,与商家端通道行为一致。

Key Entities (include if feature involves data)

  • 规格组 (Spec Group): 一个可复用的规格维度,如"甜度""加料"。属于某门店、某种语言。含选择类型(单选/多选)、是否必选、排序、启用状态。下挂多个规格值。
  • 规格值 (Spec Value): 规格组下的一个可选项,如"无糖""珍珠"。含名称、加价金额、备注、启用状态。从属于一个规格组。
  • 商品-规格关联 (Food-Spec Relation): 商品与规格组的多对多关联,表达"该商品使用了哪些规格组"。
  • 商品 (Food): 已有实体,本次扩展其与规格的关联能力;保留既有 food_sku JSON 冗余字段以兼容。
  • 门店 (Store): 规格组的归属维度(规格组门店级共享、商品复用)。

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: 商家能在 1 分钟内为门店新建一个含 3 个规格值的规格组并保存成功。
  • SC-002: 商家编辑商品勾选/取消规格后,保存即时生效,商品详情立即反映正确规格(成功率 100%)。
  • SC-003: 顾客打开任意挂规格的商品详情,规格选项与加价 100% 正确展示。
  • SC-004: 顾客选规格下单,订单金额与所选规格加价完全一致(误差为 0)。
  • SC-005: 规格数据严格按门店隔离,跨门店查询规格返回为空(100%)。

Assumptions

  • 采用源项目 cte_server 的"规格加价"模型(规格组 + 规格值 + 关联表),而非电商式笛卡尔积 SKU(每组合独立价格/库存/编码)。规格值是对商品基础价的加价累加。
  • 规格组为门店级共享(一个门店定义规格,本门店多个商品复用),与源项目一致。
  • 规格组带 language 字段,按门店 + 语言维度管理(参照源项目 FoodSpecs.language)。
  • 保留 foodie 现有 pos_food.food_sku JSON 字段作为冗余兼容,与结构化规格关联双写,避免破坏现有前端/订单读取逻辑。
  • 规格管理入口放在商家端(与现有商品管理入口一致),不在 C 端顾客侧。
  • 价格单位沿用项目现有约定(商品价格 price 为数值,规格加价同口径)。
  • 复用项目既有技术栈与基础设施(Spring Boot + MyBatis-Plus + fastjson + 若依 BaseController/AjaxResult + 自定义 @Auth/JwtUtil)。
  • 规格组/规格值名称的多语言由数据本身的 language 字段承载(商家录入的多语言数据);前端 i18n 框架仅用于固定 UI 文案。
  • 本期聚焦后端能力 + 商家端规格管理/商品编辑交互;具体前端组件与落地范围在 plan 阶段依据现状进一步确定。