挑战需求A 澄清问答记录 - xiaochu-dev/online-shopping-group5 GitHub Wiki

挑战需求 A · 澄清问答记录

  • 项目:在线购物系统(第 5 组 · 胡成溯组)
  • 记录人:周到(PM)
  • 记录日期:2026-10-20
  • 范围:挑战需求 A.1(商品管理升级 6 条)+ A.2(客户升级 6 条),共 12 条;另含补充问答 4 条
  • 回答来源:产品经理与助教访谈
  • 效力:本记录为组内唯一权威口径,与基线需求冲突处一律以本记录为准
  • 版本说明:2026-10-21 并入原《挑战需求A-产品口径-1020》中仍然有效的部分(决策原则、表结构改动总表、两处认知更正、6 条实现默认),中间稿已删除

〇、决策原则(所有冲突的裁决依据)

  1. A 与基线需求冲突 → 以 A 为准(例:基线"仅一件在售"作废;基线"客户无需注册"改为下单必须登录)。
  2. A 未提及、基线已有的功能 → 继续有效,不因 A 而删除(例:口令码撤销接口保留为存量兜底)。
  3. A 内部措辞优先于实现便利(例:A 原文写"库存数量",故库存必须支持 N > 1)。

一、A.1 商品管理升级

Q1|多商品发布后,基线"同一时间在售仅一件"是否作废?口令码还留吗?

A:作废。可以同时挂多个商品,"只能卖一件"那套不成立。 口令码用不上了——客户能自己注册登录后,下单身份就是登录账号,不需要再靠口令码认领意向。

Q2|库存与冻结的颗粒度?

A:没有 SKU 的概念,一个商品对应一个库存数(非负整数),商品就是最小单位。 冻结是针对「商品」的状态——一件商品进入交易就整件冻住,不碰库存、不减库存;库存要等交易真正成交后才动。

说明:整件冻结 = 同一件商品在同一时刻只允许存在一笔进行中的交易(线下交易,卖家一次只能见一个人);成交并解冻后,剩余库存继续接受下一位买家的意向。因此「整件冻结」与「库存 N 件、可分 N 次交易」并不冲突。

Q3|库存扣减发生在哪一步?取消/失败是否回补?

A:扣减在最后一步——线下交易完成后,卖家在后台标「交易成功」那一刻才减 1。 标「失败」的话库存从头到尾没动过,商品恢复在售即可,谈不上回补。 没有单独的"取消"这档:取消就是「交易失败」。

Q4|库存归零自动下架是哪种"下架"?补货后能否重新上架?已有队列怎么办?

A:归零是状态直接变成「已下架」,不只是前台藏起来——买家端不展示,也不接新意向。 卖家手动改库存补货后,商品可以重新上架。 已经排着的队列:库存都没了,排着的人自然买不到;归零时把该商品所有排队中的意向批量置为失败(原因:库存不足),买家在历史下单里能看到失败结果,不做主动通知。

Q5|二级类别由谁维护、商品挂到哪一级?

A:类别由卖家(本人)在后台维护,增删改都行,层级固定两级。 商品必须挂到二级(叶子级)类别下,挂类别是必填的。 旧分类迁移不用操心——旧的没有分类,分类是本次新增。

Q6|多图与富媒体的边界?

A:图片最多 9 张,JPG/PNG,单张不超过 5MB;商品图不支持视频,想放视频就放进描述里嵌。 上传方式为网页上选文件上传。 富媒体 = 富文本,描述里可以图文混排,嵌图片或视频。


二、A.2 客户升级

Q7|注册是否强制?客户注册后还需要口令码吗?

A:浏览商品不用登录;但要下单(提交购买意向)必须先注册并登录。 登录后身份就是账号,口令码自然用不上。

Q8|注册字段与密码要求?要不要找回密码、改资料?

A:注册字段就四个——用户名、密码、电话(必填)、默认交易地点(选填)。 密码要加密存、不能明文,强度要求跟卖家账号一样。 找回密码、修改资料暂时没有要求,不做。

Q9|历史下单要看到什么程度?

A:每条至少能看到:商品名、下单时间、交易结果(成功/失败)、交易时间;按时间倒序,能翻页就行。

Q10|排队顺序、位次展示、客户自己取消?

A:排队按先到先得,各商品的队列各排各的。 不向买家展示"你排第几";客户不能自己取消意向;取消/重排由卖家在后台确认。

Q11|商家能看客户的哪些字段?要不要脱敏?

A:能看到用户名、电话、默认交易地点、注册时间。不做脱敏,电话本来就是拿来联系的。 "购买历史" = 该客户的下单记录带交易结果,成功的、失败的都在里面。

Q12|存量匿名订单怎么并入账号?同一客户能重复提交吗?

A(PM 裁定):

  1. 存量匿名单不并入任何客户账号,直接清库重建;如需保留旧商品则保留 product、清空 intent。理由:注册不验证手机号,按电话"认领"会把别人的单挂到错误账号下。
  2. 重复提交限制:同一客户 + 同一商品,同时最多 1 条未结束(排队中/交易中)的意向;已成功/已失败的允许再次提交(支持复购)。

三、补充问答:需求文本未覆盖的行为空白

S1|交易失败或取消后,原来排队的人还算数吗?

A:还算数。队列按商品独立存,交易失败后商品恢复「在售」,后面排着的人接着按先到先得往下走。 受影响的只是这次交易里的那个买家——他的意向是作废、还是塞回队列重新排,由卖家在后台确认。 (补充:本体系里"取消"就是「交易失败」这一档,没有独立的"取消"状态。)

S2|客户的历史下单里,未完成的单(排队中、交易中)显不显示?

A:不显示。历史下单记录只放已经有结果的单子——交易成功、交易失败的都在里面。 还在排队、还处于交易中(冻结)的单子,还没出结果,不算"历史",不放进这个列表;它们的状态跟着各自的意向队列走。

S3|卖家能否手动下架"还有库存、正在在售"的商品?

A:能。下架有三种情形:①交易成功(卖完最后一件);②库存归零自动下架;③卖家手动下架。 手动下架跟库存无关——只要想下,正在卖、还有库存的商品照样能手动下架,随时让它退出在售。

S4|已发布商品能否编辑(价格/名称/图片)、能否删除?

A:改和删都没开这个口子。 改:目前只要求能改库存数量(补货、调库存);价格、名称、图片能否改没有要求,暂不做。 删:没有"删除商品"功能。卖完了、库存归零就走下架、进历史记录,用不着单独删——所以也不存在"有订单的商品能不能删"这回事。


四、由以上回答引出的实现裁定(团队内部)

# 事项 裁定
R1 商品「交易中」怎么表示 不复用计数锁,直接 product.status = 'frozen':交易中整件不可下单;成交后 stock - 1 并回 on_sale;失败则回 on_sale 且库存不变
R2 意向状态机 pending → trading → success / failed;卖家侧"取消" = 置 failed,不引入独立 cancelled(cancelled 仅保留给旧口令码撤销的存量数据)
R3 失败买家的两种处置 卖家在后台二选一:作废(置 failed)或 塞回队列(置回 pending 并刷新排队时间为队尾)。需在卖家端提供该分支按钮
R4 归零时队列善后 库存归零那一刻,把该商品所有 pending 批量置 failed,fail_reason = '库存不足'
R5 客户历史列表 只查 status IN ('success','failed') 的意向,按 finished_at 倒序分页;排队中/交易中不进列表
R6 下架原因 delisted 需区分「卖光下架 / 手动下架」,前台/后台文案不同(可用 trade_result 或新增 delist_reason 区分)
R7 商品「我的商品」列表 因无删除功能,已下架商品会长期堆积,列表必须提供状态筛选(在售/已下架/交易中)

五、实现默认(低风险,不认同再改)

# 事项 默认处理
1 S3 的"交易成功"是否等于"卖光最后一件才下架" 按 stock - 1 后归零才下架处理;库存未归零则继续在售(与 S4"卖完了、库存归零就走下架"一致)
2 "塞回队列"是回原位还是排到队尾 用户表述为"重新排",按排到队尾处理(刷新 created_at,并按新时间参与先到先得)
3 客户下单后无任何可见反馈 排队中/交易中不展示;仅在下单成功页给一句「已提交,等待卖家确认」,不展示位次
4 价格/名称写错无法修改 只能手动下架原商品后重新发布;发布页需加二次确认
5 列表页封面用哪张图 sort_no 最小的一张;发布时第一张即封面(product.image_path 降级为封面字段)
6 搜索范围与分页 商品名 + 描述,可叠加分类筛选;每页 10 条
7 用户名 / 电话的唯一性 用户名唯一(注册时提示"已被占用");电话不唯一(不验证手机号,允许多人填同一号码)
8 客户与卖家的登录态 两套独立 cookie(CUSTOMER_SESSION / SELLER_SESSION),同一浏览器可同时登录后台与买家端,互不踢
9 下单时的交易地点 默认带出客户的默认交易地点,允许本单临时改写,落 intent.trade_address 快照
10 富文本描述的安全策略 卖家输入 HTML 原样存、买家端渲染,不做标签白名单(单卖家可信,课程内可接受,但需写入风险说明)

六、表结构改动总表

以 R1「整件冻结」为准,不设 locked 计数列(早期草案里的 locked 已作废)。

表 改动
product + stock INTEGER NOT NULL DEFAULT 1(非负);category_id 由可空改必填;status 增加 frozen(交易中);delisted 需可区分卖光/手动(见 R6);不加 locked
product_image 新建:id / product_id / path / sort_no,一个商品最多 9 行;product.image_path 降级为封面
category + parent_id(自引用,NULL = 一级);业务上限制最多两级;name 的唯一约束由「全表唯一」改为 UNIQUE(parent_id, name)
customer 新建(A.2):username(UNIQUE) / password_hash / salt / phone(必填) / default_address(可空) / created_at;密码复用 seller 的 sha256(salt + 明文) + 8 字节盐,不引入 BCrypt
intent + buyer_id(NOT NULL,关联 customer)/ trade_address / finished_at / trade_result(success·failed) / fail_reason;token_code 改可空(新单不生成,仅存量兜底);buyer_name / phone 保留为下单时快照
seller 不动(仍单卖家;A.2 里的"商家"= 该账号)

两处必须知道的现状更正

① 分类不是"从零做",已有半套。 category 表与 5 条种子数据(数码电子 / 图书教材 / 服饰鞋包 / 生活百货 / 运动户外)已存在,买家列表页也已有单级分类筛选。A1-4 实际要做的是:加 parent_id → 5 条种子改造成两级 → category_id 改必填 → 卖家后台分类增删改页面。

② 9 张 × 5MB 不能进 SQLite。 单商品最多 45MB 图片,塞进库会让打包与复制直接崩溃。必须新建 product_image 表、图片存文件系统 static/uploads/{productId}/、上传时校验扩展名 + MIME + 大小并重命名。

SQLite 迁移注意:SQLite 不支持删除约束,token_code 放开非空、category.name 改唯一约束都只能重建表。课程环境最省事的做法是备份 shop.db → 删库 → 改 schema.sql → 重启(种子数据自动重灌)。