# Research: 商品规格移植 **Feature**: 013-food-spec | **Date**: 2026-07-15 本研究基于对源项目 `cte_server` 规格功能与目标项目 `foodie_server` 商品体系的代码勘察,记录关键技术决策。无 NEEDS CLARIFICATION(移植任务,源代码即参考答案)。 ## 决策 1:数据模型 — 规格加价模型(非笛卡尔积 SKU) - **Decision**: 采用"规格组 + 规格值 + 商品-规格关联"三表模型;规格值带"加价",顾客选规格后加价累加到商品基础价。 - **Rationale**: 源项目 cte_server 即此模型,需求是"移植";满足餐饮/夜市"甜度/加料/辣度"场景;实现简单,无需笛卡尔积组合管理。 - **Alternatives**: 电商式 SKU(每规格组合独立价格/库存/编码)——拒绝:当前无独立库存/编码需求,且与现有 specPrice/otherPrice 加价口径冲突,复杂度不划算。 ## 决策 2:规格归属 — 门店级共享 - **Decision**: 规格组按门店(`md_id`) + 语言(`language`)维度管理,本门店多商品复用。 - **Rationale**: 与源项目一致;餐饮场景同一门店的"甜度"规格被多杯饮品复用,避免每商品重复录入。 - **Alternatives**: 商品级独立规格——拒绝:录入成本高、无复用价值。 ## 决策 3:food_sku JSON 与结构化关联双写 - **Decision**: 保留 `pos_food.food_sku` JSON 字段,与 `food_spec_relation` 结构化关联双写;查询时以结构化关联为权威,`food_sku` 作兼容冗余。 - **Rationale**: foodie 现有前端与订单链路(`PromotionCalc.specPrice`、`PosOrder.food` 快照 `otherPrice`)读取 `food_sku` JSON;直接废弃会破坏存量链路。双写保证渐进兼容。 - **Alternatives**: 仅结构化关联、废弃 JSON——拒绝:需同步改前端 + 订单读取,范围过大。 ## 决策 4:命名统一 - **Decision**: 消除源项目命名不一致(其 `foodSku` JSON 内规格值明细叫 `objects`,`foodSpecs` 内叫 `foodSpecsItems`)。foodie 移植版统一:结构化规格 `FoodSpecs.foodSpecsItems` 用 `foodSpecsItems`;`food_sku` JSON 内明细若 foodie 前端已有约定则从之,否则统一为 `foodSpecsItems`。最终命名在 [contracts/api.md](contracts/api.md) 明确,前后端对齐。 - **Rationale**: 源项目命名不一致是已知坑,移植时必须消除,否则前后端字段对不上。 - **Alternatives**: 照搬两套命名——拒绝:维护负担大。 ## 决策 5:价格类型与口径统一 - **Decision**: 规格值加价 `price` 与商品 `price` 同口径。foodie `PosFood.price` 为 BigDecimal(DB decimal),故规格加价列也用 decimal/BigDecimal,**不照搬源项目的 Long(分)**。下单实付单价 = 商品基础价 + 所选规格值加价之和;该和即写入订单快照 `otherPrice` 与促销 `specPrice`。 - **Rationale**: 保持与 foodie 现有价格体系一致,避免单位换算 bug;统一 otherPrice/specPrice/规格加价三国口径。 - **Alternatives**: 用整数分——拒绝:与商品价类型不一致,引入换算风险。 ## 决策 6:后台通道统一收口(FR-011) - **Decision**: 一并修复后台 `add`/`edit`(PosFoodController 后台段)不写规格的问题,使两条保存通道行为一致;抽取公共的"保存规格关联 + 写 food_sku"逻辑供 `setposfood` 与 `add`/`edit` 复用。 - **Rationale**: spec FR-011 要求;否则后台编辑商品会丢规格,造成数据不一致。 - **Alternatives**: 仅改商家端 setposfood——拒绝:留隐患。 ## 决策 7:查询性能 — 批量注入避免 N+1 - **Decision**: 商品列表注入规格采用"一次查该批商品所有关联 → 一次查相关规格组 → 一次查相关规格值 → 内存分组",不逐商品查库(沿用源项目模式)。 - **Rationale**: 列表接口商品数多,逐条查会 N+1。 - **Alternatives**: 逐商品查——拒绝:性能差。 ## 依赖与集成 - 技术栈均为 foodie 既有,无需引入新依赖。 - 唯一需对齐的集成点:订单快照 `otherPrice`、促销 `specPrice` 的取值来源(决策 5 已统一为"所选规格值加价之和")。