Files
dukang/杜康好客-V2编码手册.md

150 KiB
Raw Permalink Blame History

杜康好客 · V2 编码手册(完整规格 · 唯一事实源)

V3 交付提示:当前交付验收以 杜康好客-v3编码手册.md 为准。本手册中「核销单次上限 ¥500」等规则已被 V3 替代(直接核销可达总余额 / 单据 cap)。

版本V2(完整四端 + 微信生态 + 真实第三方)
联调裁剪版:见 杜康好客-preV1编码手册.md(三端 H5 + Mock,同库同 API 契约)
用途:V2 正式编码与 preV1 预留对齐的完整规格
日期2026-06-27
范围:郑州开城 · 4 款清香型 SKU · 四端(C端小程序/门店H5/合伙人小程序/总部小程序)
技术栈Taro 3 + React + TS · NestJS 10 + Prisma 5 · MySQL 8 · Redis 7 · BullMQ
数据库v3.128 表,见 §五)
APIv3.1(见 §六)
协作:见根目录 conventions.mdagent.mdskills.md


文档索引

章节 内容
§一 项目目标与 V1 范围
§二 产品需求(PRD + 原型对应)
§三 原型全清单与页面流
§四 技术架构与模块边界
§五 数据库设计 v3.1
§六 API 列表 v3.1
§七 开发计划与任务卡
§八 核心业务链路
§九 第三方集成与非功能

§一、项目目标与 V2 范围

杜康好客是杜康酒业 O2O 平台:用户购酒获等额「好客权益」,到合作餐饮门店核销;城市合伙人拓店与履约;总部管开城、商品、结算与客服。

载体 原型目录 后端 Guard
C端 微信小程序 pages/user/ UserAuth → user_user
门店 H5 pages/shop/ StoreAuth → store_account
合伙人 微信小程序 pages/partner/ PartnerAuth → partner_account
总部 微信小程序 pages/hq/ AdminAuth → hq_account

V2 锁定:郑州 · 4 款清香型 · 含退款/推广码/埋点 · 不含会员体系 · 订单 5 Tab(含待发货) · 核销单次上限 ¥500 · 门店 T+1 / 合伙人 T+30 结算。

里程碑M0 骨架 → M1 IAM/开城/商品 → M2 交易 → M3 权益核销 → M4 拓店售后 → M5 结算 → M6 推广埋点 → 上线。


§二、产品需求(PRD

1. 项目背景与目标

1.1 背景

杜康好客是杜康酒业的 O2O 消费平台:用户在线购买杜康酒品,同时获得等额「好客权益」用于合作餐饮门店消费;城市合伙人负责拓展本地门店网络与订单履约;总部统一管理开城、商品、结算与客服。

1.2 产品目标

  1. 打通「购酒 → 赠权益 → 到店核销」完整闭环
  2. 支持多城市开城,同城/跨城差异化配送
  3. 为城市合伙人、门店、总部提供各自工作台
  4. 可追溯订单来源(推广码)与资金结算

1.3 产品范围(四端)

载体 用户
C端 微信小程序 终端消费者
门店端 H5 合作餐饮门店
城市合伙人端 微信小程序 城市合伙人及子账号
总部管理端 微信小程序 总部运营、财务、客服

1.4 V1 上线范围(已锁定)

维度 V1 范围 说明
开城 郑州 唯一上线城市;其他城市原型仅作扩展参考
商品 4 款清香型 酱香型/浓香型 Tab 展示但不可购(灰态)
会员体系 不实现 个人中心仅默认头像 + 昵称 + 平台 ID
退款 纳入 V1 总部客服中心处理,见 §3.6.2
推广码 + 埋点 纳入 V1 见 §3.10
跨城配送 纳入 V1 逻辑保留,V1 以郑州同城为主

2. 核心概念

2.1 好客权益

  • 用户购酒并支付成功后发放好客权益(餐券)
  • V1 默认规则:权益金额 = 商品售价(等额)
  • 可配置扩展:总部商品管理可单独设置「权益金额」字段;未配置时自动取商品售价,便于后续营销活动灵活调整
  • 系统内统一称为「好客权益」,可在合作门店核销抵扣餐饮消费
  • 永久有效,当前版本不设过期时间
  • 支持部分核销:一张券可多次使用直至余额为 0
  • 单次核销上限:不超过当前券可用余额(系统校验)

2.2 开城与订单路由

  • 总部「开城管理」配置城市及城市合伙人
  • 用户定位/选城决定可见商品与配送方式
  • 订单归属城市 = 收货地址所在城市(用于合伙人业绩与佣金)

2.3 配送模式

模式 条件 配送方 时效 运费 起购量
同城配送 地址在已开城同城范围 小飞侠 24 小时内 ¥0 2 瓶
跨城物流 超出同城范围 总部物流快递 依物流 到付 6 瓶(1 箱)

3. C端用户小程序

原型目录pages/user/
底部导航:首页 | 门店 | 好客权益 | 我的

原型文件 页面 PRD 模块
pages/user/1-登录.png 登录 §3.1
pages/user/2-首页.png 首页 §3.2
pages/user/3-商品详情页.png 商品详情 §3.2
pages/user/4-立即购买确认订单.png 确认订单(同城) §3.3
pages/user/5-订单确认-跨城配送.png 确认订单(跨城) §3.3
pages/user/6-地址列表.png 地址列表 §3.4
pages/user/7-新增收货地址.png 新增地址 §3.4
pages/user/8-微信支付页面.png 微信支付 §3.3
pages/user/9-我的订单列表.png 订单列表(5 Tab §3.5
pages/user/10-我的订单-补发状态.png 补发订单 §3.5
pages/user/11-我的订单详情.png 订单详情 §3.5
pages/user/12-修改地址弹窗.png 修改地址 §3.5
pages/user/13-联系客服弹窗.png 联系客服 §3.6
pages/user/14-联系在线客服.png 在线客服 §3.6
pages/user/15-门店页面-门店列表.png 门店列表 §3.7
pages/user/16-门店详情页.png 门店详情 §3.7
pages/user/17-好客权益页.png 好客权益 §3.8
pages/user/18-好客权益明细.png 权益明细 §3.8
pages/user/19-个人中心页.png 个人中心 §3.9
pages/user/20-好客权益核销.png 核销输入 §3.8
pages/user/21-核销码展示.png 核销码 §3.8
pages/user/22-核销成功及评价.png 核销成功 §3.8

3.1 模块一:登录与城市归属

原型1-登录.png

功能 说明
手机验证码登录 输入手机号 + 验证码
微信授权登录 需勾选用户协议与授权
定位授权 登录后请求定位,获取市+区(最多两级)
手动选城 用户可手动选择城市/区域

业务规则

  • 城市决定后续商品、门店、配送方式
  • V1 仅郑州开城;非郑州用户可浏览,下单按跨城/未开通规则处理

3.2 模块二:首页与商品展示

原型2-首页.png3-商品详情页.png

3.2.1 首页

元素 说明
品牌区 杜康好客 + 当前城市
香型 Tab 清香型 / 酱香型 / 浓香型(当前仅清香型上线
商品卡片 大图 + 标题 + 规格 + 价格 + 好客权益标签 + 立即购买
商品数量 V1 固定 4 款清香型,大图列表布局

3.2.2 商品详情

元素 说明
主图轮播 商品主图
价格/名称/规格 固定展示
好客权益说明 标准文案:「买杜康美酒·享全城好客礼遇」,展示金额取 权益金额(默认同售价)
图文详情 后台商品管理维护,支持图片+文字
操作 返回首页 / 立即购买

业务规则

  • 权益展示/发放金额 = 商品配置的 benefit_amount未配置时默认 = 商品售价
  • 首页卡片「享 ¥X 好客权益」同步读取该字段

3.3 模块三:下单与微信支付

原型4-立即购买确认订单.png5-订单确认-跨城配送.png6~8

3.3.1 确认订单

字段 说明
收货地址 必选;跳转地址列表
商品信息 图、名、规格、单价、数量
好客权益 本单可享权益金额
配送方式 同城:小飞侠(预计 24h);跨城:物流配送
运费 同城 ¥0;跨城显示「到付」
合计/实付 商品总额 + 运费(跨城不含运费)
支付 仅微信支付

3.3.2 跨城提示

地址超出同城范围时:

  • 弹窗/横幅提示:总部物流发货,运费到付,需用户确认继续
  • 配送方式变为「物流配送」,运费标记「到付」

3.3.3 起购校验

配送类型 最低数量 不满足时
同城 2 瓶 拦截下单
跨城 6 瓶 拦截下单

3.3.4 支付流程

  1. 点击「微信支付」→ 锁单
  2. 跳转微信支付确认页
  3. 支付成功 → 微信回调 → 订单生成
  4. 初始状态:待发货
  5. 支付成功同时发放好客权益

3.4 模块四:地址管理

原型6-地址列表.png7-新增收货地址.png

功能 说明
地址列表 历史地址,可选择
新增地址 收货人、手机号、地区选择、详细地址、是否默认
默认地址 下单时优先选中

3.5 模块五:订单管理

原型9-我的订单列表.png10~1211-我的订单详情.png

3.5.1 订单列表 Tab

原型9-我的订单列表.png5 Tab:全部/待付款/待发货/待收货/已完成

Tab 包含状态
全部 所有(含退款中、已退款、补发单)
待付款 待支付
待发货 已支付,待出库/待推配送
待收货 配送中 + 待签收
已完成 已完成

完整状态机待付款 → 待发货 → 配送中 → 待签收 → 已完成
异常分支退款中 → 已退款补发中(关联原单,价格 ¥0

原型改稿pages/user/9 需增补「待发货」Tab,详见 doc/原型说明.md

3.5.2 列表卡片字段

  • 订单号、状态
  • 商品图、名称、规格、数量、金额
  • 好客权益使用情况 + 「去使用」按钮(未用完时)
  • 补发单:标记「补发单」,价格 ¥0,提示破损免费补发

3.5.3 订单详情

区块 内容
进度条 下单成功 → 出库中 → 配送中 → 待签收 → 完成
商品信息 含好客权益引导入口
收货信息 姓名、地址、配送方式;待发货/配送中可修改
订单信息 订单号、创建时间、支付方式
结算 商品总额、运费、实付
操作 联系客服、确认收货

3.5.4 修改收货地址

原型12-修改地址弹窗.png

  • 弹窗提示:系统将尝试拦截配送;拦截失败需联系配送员
  • 若已按原地址签收,不再二次派送
  • 拦截成功(物流返回「商品已退回」)→ 推送新订单到城市合伙人 → 二次配送

3.6 模块六:售后与客服

原型13-联系客服弹窗.png14-联系在线客服.png

渠道 说明
电话客服 调起拨号
微信图文客服 在线实时沟通

补发流程(破损等):

  1. 用户联系总部客服,提供订单号
  2. 总部客服发起补发
  3. 通知用户;推送城市合伙人确认
  4. 合伙人确认后进入配送;系统记录补发关联原订单

3.6.2 退款流程(V1

原型pages/hq/26-补发与退款处理.png

环节 说明
发起 用户通过客服(电话/在线)申请退款,提供订单号与原因
受理 总部客服在「客服中心」创建退款工单,关联原订单
审核 总部客服/财务审核;可部分退款或全额退款
执行 调用微信退款 API;订单状态 → 退款中已退款
权益回退 若对应好客权益未使用:全额退款时作废权益;已部分核销:按未使用余额比例退款或人工核算(客服备注)
通知 退款结果推送用户(小程序订阅消息/客服会话)

可退款状态

订单状态 是否可退 说明
待付款 用户直接取消/超时关单
待发货 全额退款优先
配送中 需拦截配送成功后退款
待签收/已完成 条件可退 签收 7 天内且未开瓶/未核销权益,客服人工判定
补发单

3.7 模块七:门店

原型15-门店页面-门店列表.png16-门店详情页.png

3.7.1 门店列表

元素 说明
定位 按用户城市/区域筛选
分类 火锅、地方菜、高端餐饮、烧烤烤肉等
卡片 招牌图、名称、评分、人均、支持核销标签、营业状态
搜索 店名、地址
过滤 永久闭店、临时闭店均不在 C 端展示;仅「营业中」门店可见可选

3.7.2 门店详情

  • 大图、名称、状态、评分、标签
  • 环境图(3 张)
  • 地址、距用户距离
  • 电话、导航(调起地图)
  • 图文介绍(后台维护)
  • 「去核销」→ 跳转核销页

3.8 模块八:好客权益

原型17-好客权益页.png18-好客权益明细.png20~22

3.8.1 权益首页

  • 当前余额(汇总)
  • 「去使用」→ 核销流程
  • Tab:待使用 | 已用完/已过期(当前无过期,仅已用完)
  • 券卡片:金额、来源订单、永久有效、已用/未用进度、券编号、立即核销

3.8.2 权益明细

  • 获取记录 + 消费记录

3.8.3 核销流程

  1. 选择门店(或从订单/权益页直接进入)
  2. 核销页:展示可用余额,输入本次核销金额,支持「全部核销」
  • 校验:0 < 金额 ≤ min(可用余额, ¥500)
  • 超出 ¥500 提示「单次最高可核销 ¥500.00」
  1. 点击「生成核销码」→ 展示二维码
  2. 核销码 5 分钟有效,一次性使用,可刷新
  3. 门店扫码确认 → 核销成功页
  4. 快速评价:服务态度、用餐环境(五星,点击即保存)

入口汇总

  • 底部 Tab「好客权益」
  • 订单列表/详情「去使用」
  • 门店详情「去核销」
  • 个人中心「去使用」

3.9 模块九:个人中心

原型19-个人中心页.png

区块 说明
用户信息 全局默认头像、微信昵称、平台 IDV1 无会员等级,不展示「至尊会员」等标签)
我的资产 好客权益余额 → 明细
我的订单 待付款/待发货/配送中/已完成 快捷入口
地址管理 跳转地址列表
可用门店 跳转门店 Tab
联系客服 同订单页
关于我们 / 版本号 展示系统版本
退出登录

3.10 模块十:推广码与埋点(V1

原型pages/hq/16-推广码管理.png17-推广码生成.png

3.10.1 推广码

功能 说明
创建 总部创建推广码,绑定渠道名称(如「XX 品鉴会」)
扫码归因 用户扫码进入小程序,首次写入 channel_source 至 session
订单绑定 下单时将 channel_source 写入订单;合伙人/总部订单详情可查看
统计 总部数据报表按渠道汇总 GMV、订单量

3.10.2 用户行为埋点(V1 事件清单)

事件名 触发时机 关键参数
app_launch 小程序启动 city, channel_source
login_success 登录成功 method( sms/wechat )
location_grant 定位授权结果 granted, city, district
home_view 首页曝光 city, aroma_tab
product_click 点击商品卡片 product_id, price
product_detail_view 商品详情曝光 product_id, benefit_amount
order_confirm_view 确认订单页曝光 product_id, qty, delivery_type
order_submit 点击微信支付 order_id, amount, delivery_type
pay_success / pay_fail 支付回调 order_id, amount, fail_reason
order_tab_view 订单列表 Tab 切换 tab_name
store_list_view 门店列表曝光 city, category
store_detail_view 门店详情 store_id
benefit_redeem_start 进入核销页 store_id, available_balance
benefit_qrcode_generate 生成核销码 amount, coupon_id
benefit_redeem_success 核销成功 amount, store_id
cs_contact 联系客服 type( phone/chat )
promo_scan 扫描推广码 promo_code, channel_name

技术要求

  • 统一上报 SDK,支持批量上报与失败重试
  • 埋点数据可在总部「数据报表中心」查询(V1 基础统计即可)

4. 门店端 H5

原型目录pages/shop/
底部导航:首页 | 核销记录 | 我的

原型文件 页面 PRD 模块
pages/shop/1-登录页.png 登录 §4.1
pages/shop/2-一键登录.png 快捷登录 §4.1
pages/shop/3-门店管理首页-核销页.png 首页核销 §4.2
pages/shop/4-核销确认.png 核销确认 §4.3
pages/shop/5-核销成功.png 核销成功 §4.3
pages/shop/6-核销记录.png 核销记录 §4.4
pages/shop/7-门店信息.png 门店信息 §4.5

4.1 登录

原型1-登录页.png2-一键登录.png

  • 门店手机号 + 验证码
  • 微信授权登录
  • 记住登录态,二次进入快捷登录
  • 展示门店名称、绑定手机号

4.2 首页 · 扫码核销

原型3-门店管理首页-核销页.png

元素 说明
门店名称 当前登录门店
今日核销笔数 / 今日到账金额 实时统计
扫码核销 主操作按钮;亦支持微信扫一扫
营业状态 开店 / 临时闭店切换,实时同步 C 端
最近核销 时间 + 金额,倒序

营业规则

  • 门店端:开店 / 临时闭店
  • 临时闭店 → C 端列表隐藏,不可核销
  • 永久闭店:仅城市合伙人可操作,C 端不可见

4.3 核销确认

原型4-核销确认.png5-核销成功.png

确认页字段 说明
当前门店 登录门店信息
用户手机号 脱敏展示
核销金额 用户输入的面额
券编号 券 ID
有效期 永久(码本身 5 分钟有效)
  • 点击「确认核销」→ 服务端执行核销
  • 成功 → 用户端更新;门店端展示成功页
  • 短信通知门店老板:到账金额 + 核销时间
  • 授权且营业中的门店可核销

4.4 核销记录

原型6-核销记录.png

筛选项 选项
时间 今日 / 近 7 日 / 近 30 日
状态 全部 / 待打款 / 已打款
汇总 说明
期间核销总额 面额合计
期间到账总额 面额 × 60%
结算比例 60%6 折)
明细字段 说明
核销单号、时间
核销面额 / 到账金额 60%
打款状态 待打款 / 已打款
打款时间 总部打款时间
打款周期 T+1 工作日(核销日次日起算)
  • 待打款记录展示「预计打款:T+1 工作日」
  • 账单链接亦可通过服务号/短信通知查看

4.5 我的 · 门店信息

原型7-门店信息.png

  • 门店名称、地址、电话:仅查看
  • 修改需联系城市合伙人
  • 营业状态切换
  • 退出登录

5. 城市合伙人端小程序

原型目录pages/partner/
底部导航:首页 | 门店管理 | 合伙人中心

原型文件 页面 PRD 模块
pages/partner/1-登录页.png 登录 §5.1
pages/partner/2-快捷登录.png 快捷登录 §5.1
pages/partner/3-首页.png 工作台 §5.2
pages/partner/4-拦截配送.png 拦截配送 §5.6
pages/partner/5-门店管理.png 门店列表 §5.3
pages/partner/6~8 录入门店三步 §5.3.2
pages/partner/9-补发处理.png 补发 §5.5
pages/partner/10-财务对账.png 财务对账 §5.7
pages/partner/11-周报.png 周报 §5.8
pages/partner/12-13 订单列表/详情 §5.4
pages/partner/15~16,18 子账号/员工 §5.9
pages/partner/17,20-23 合伙人中心/结算 §5.10

5.1 登录与账号

原型1-登录页.png2-快捷登录.png

  • 账号由总部创建城市合伙人入驻
  • 手机验证码 / 微信授权 / 快捷登录
  • 微信授权有效期 30 天
  • 展示:企业名称、地址、入驻城市、手机号

5.2 工作台首页

原型3-首页.png

指标 说明
实时营业额 所辖城市酒品订单 GMV
预计利润 营业额 × 35%30% + 5%
门店总数 正常运营 / 异常·闭店
今日订单量 待发货 / 配送中 / 已完成
拓店情况 下级合伙人拓店统计
贡献榜 按拓店数排行

快捷入口:录入新店 | 补发处理 | 财务对账 | 数据周报 | 拦截配送

脚本明确「今日活跃度」等字段暂不使用。

5.3 门店管理

原型5-门店管理.png6~8

5.3.1 门店列表

  • 状态:营业中 / 暂时闭店 / 已关闭(永久闭店)
  • 搜索:名称、地址

5.3.2 录入新门店(三步)

步骤 内容
1 基本信息 名称*、电话*、地图选址*、门牌号、简介(10~500字)
2 照片上传 门头照、环境照(≥3 张)、签约合同副本
3 结算资质 银行卡姓名、卡号、开户支行
  • 提交 → 推送总部审核
  • 审核通过 → 门店生效,获得核销权限
  • 合伙人可编辑门店;永久闭店仅合伙人可操作

5.3.3 审核记录

  • 待审核 / 已通过 / 已驳回
  • 驳回可修改重新提交

5.4 订单管理

原型12-订单列表.png13-订单详情.png

  • 仅查看所辖城市订单
  • 时间:今天 / 近 7 天 / 近 30 天
  • 状态:全部 / 待发货 / 运输中 / 已完成 / 异常(退货补发)/ 拦截
  • 列表:订单号、商品、规格、赠券金额、收货地址
  • 详情:物流状态、佣金(下单 + 核销两笔)、推广渠道来源

5.5 补发处理

原型9-补发处理.png

  • 总部下达补发工单:原订单号、状态
  • 合伙人点击「开始配送」→ 推送城市配送
  • 物流签收回调 或 合伙人手动确认送达

5.6 拦截配送

原型4-拦截配送.png

  • 用户改地址触发拦截通知
  • 合伙人查看详情,发起拦截
  • 拦截成功 → 新地址二次配送(等同正常订单流转)
  • 待配送状态:直接撤回原单

5.7 财务对账与结算

原型10-财务对账.png22-确认账单.png23-申请打款.png

概念 规则
账期 T+30 天
流程 总部发起账单 → 合伙人确认 → 总部打款
账单状态 待结算 / 审核中 / 已结算
佣金构成 酒品下单佣金 + 权益核销佣金
佣金比例 总部在开城/合伙人配置处设置

确认账单页

  • 展示账期、应结总金额
  • 拆分:订单分佣 + 核销分佣
  • 勾选确认 → 申请打款
  • 主账号(签约账号)可收账单确认通知;子账号不可

5.8 经营周报

原型11-周报.png

  • 默认近 7 天,可回溯
  • GMV、活跃门店数(有核销即活跃)、购酒订单量
  • 本周新签门店、每日 GMV 趋势、门店核销排行

5.9 子账号管理

原型15~1618

角色 说明
城市合伙人 子级合伙人
内部员工 拓店人员
推广员 线下推广
  • 创建:姓名、手机号(验证码校验)、角色
  • 默认禁用,需手动启用
  • 可编辑、禁用、删除
  • 贡献榜按拓店数排名

5.10 合伙人中心

原型1720-21

  • 所在城市、账户余额(待结算 / 已提现)
  • 发起提现 → 总部财务审核
  • 资产明细、合同管理(PDF、编号、签约/到期日期)
  • 门店审核记录、员工管理入口

6. 总部管理端(微信小程序)

原型目录pages/hq/
载体:微信小程序
底部导航:管理中心 | 门店审核 | 结算中心 | 客服中心

原型文件 页面 PRD 模块
pages/hq/1-2 登录 §6
pages/hq/3-5 首页/预警 §6.1, §6.10
pages/hq/6-9 开城管理 §6.2
pages/hq/10-11,13,24-25 订单中心 §6.4
pages/hq/12,14 商品管理 §6.3
pages/hq/15 数据报表 §6.9
pages/hq/16-17 推广码 §6.6
pages/hq/19-20 门店审核 §6.5
pages/hq/21-23 结算中心 §6.7
pages/hq/26-27 补发退款 §6.8

6.1 管理中心首页

原型3-数据聚合与预警.png

今日概况:订单数、新增用户、核销笔数、新增门店、今日 GMV、累计 GMV、核销金额

待办预警:超时订单等异常,可跳转处理

核心管理入口

  • 开城管理
  • 订单中心
  • 商品管理
  • 推广码
  • 数据报表

6.2 开城管理

原型6-开城管理.png7-新增城市.png89-配置佣金比例.png

功能 说明
城市列表 运营中 / 暂停 / 待开城
城市卡片 合伙人、门店数、累计 GMV
操作 编辑、暂停/恢复、配置
新增城市 基本信息 + 开户行 + 附件
佣金配置 下单佣金比例、核销佣金比例

6.3 商品管理

原型12-商品列表.png14-商品添加.png

  • 杜康系列酒品 CRUD
  • 字段:名称、规格、价格、香型、主图、图文详情、权益金额(可选)
  • 权益金额规则:留空 = 默认等于售价;填写 = 按配置值发放与展示
  • V1 上架 4 款清香型;上下架控制

6.4 订单中心

原型10-1113-1~424-跨城订单处理.png25-发货处理.png

  • 全链路订单监控
  • 搜索:订单号、手机号、城市;时间筛选
  • 状态筛选:待发货 / 配送中 / 已完成 / 异常
  • 跨城订单:总部物流发货处理
  • 订单详情:完整履约信息、佣金拆分、推广来源

6.5 门店审核

原型19-门店审核管理.png20-门店详情页面.png

Tab 说明
全部 / 待审核 / 已通过 / 已驳回
  • 审核类型:首次入驻 / 信息修改
  • 操作:查看详情、修改、通过、驳回
  • 总部也可编辑门店信息

6.6 推广码管理

原型16-推广码管理.png17-推广码生成.png

  • 创建推广码(品鉴会等场景)
  • 关联渠道名称
  • 订单归因统计

6.7 结算中心

原型21-结算中心.png22-23

Tab:城市合伙人结算 | 门店结算

功能 说明
待结算总额 汇总
待处理记录 发送账单 / 确认打款
门店结算 核销打款给门店(60%),周期 T+1 工作日

结算周期对比

对象 周期 流程
门店 T+1 总部按日/批打款,门店核销记录标记已打款
城市合伙人 T+30 账期 → 发账单 → 合伙人确认 → 打款

6.8 客服中心 · 补发与退款

原型26-补发与退款处理.png27-补发详情页面.png

功能 说明
补发 输入订单号 → 创建补发单 → 推送合伙人 → 跟踪配送
退款 输入订单号 → 创建退款工单 → 审核 → 微信退款 → 权益回退
工单列表 待处理 / 已完成;类型:补发 / 退款
关联查询 原订单、补发单、退款单互相关联

6.9 数据报表

原型15-数据报表中心.png

  • 全链路经营数据看板

6.10 预警

原型4-预警详情.png5-超时订单详情.png

  • 超时未处理订单预警
  • 跳转订单处理

7. 关键业务流程

7.1 购酒履约

sequenceDiagram
    participant U as C端用户
    participant S as 系统
    participant W as 微信支付
    participant D as 小飞侠/物流
    participant P as 城市合伙人

    U->>S: 选商品、地址、数量
    S->>S: 校验起购量、配送方式
    U->>W: 微信支付
    W->>S: 支付回调
    S->>S: 订单待发货 + 发放好客权益
    S->>D: 推送配送
    D->>S: 状态回调(出库/配送中/签收)
    S->>U: 更新订单进度
    Note over P: 同城由合伙人辖区履约

7.2 好客权益核销

sequenceDiagram
    participant U as C端用户
    participant S as 系统
    participant M as 门店H5

    U->>S: 选门店、输入核销金额
    S->>U: 生成二维码(5min有效)
    M->>S: 扫码
    S->>M: 展示确认页(金额/用户/券)
    M->>S: 确认核销
    S->>U: 核销成功 + 评价
    S->>M: 更新记录 + 短信通知老板

7.3 门店入驻

flowchart LR
    A[合伙人录入门店] --> B[总部审核]
    B -->|通过| C[门店生效可核销]
    B -->|驳回| D[合伙人修改重提]
    C --> E[C端可见可选]

7.4 合伙人结算

flowchart LR
    A[T+30 账期到期] --> B[总部发起账单]
    B --> C[合伙人确认]
    C --> D[总部打款]
    D --> E[已结算]

7.5 门店核销打款(T+1

flowchart LR
    A[门店确认核销] --> B[记录待打款]
    B --> C[T+1 工作日]
    C --> D[总部批量打款]
    D --> E[门店记录已打款]

7.6 退款流程

sequenceDiagram
    participant U as C端用户
    participant CS as 总部客服
    participant S as 系统
    participant W as 微信退款

    U->>CS: 申请退款(订单号)
    CS->>S: 创建退款工单
    CS->>S: 审核通过
    S->>W: 发起退款
    W->>S: 退款回调
    S->>S: 回退未使用权益
    S->>U: 通知退款结果

8. 非功能需求(初稿)

类别 要求
安全 手机号脱敏;核销码一次性+短时效
性能 首页/列表首屏 < 2s(目标,待压测确认)
兼容 微信小程序基础库版本 待确认
通知 短信(核销到账、账单链接);微信服务号 待确认

9. V1 决策记录(已确认)

# 决策项 结论
1 好客权益金额 默认 = 酒价;商品管理支持单独配置
2 暂停营业门店 C 端完全隐藏
3 订单 Tab 增加「待发货」:全部/待付款/待发货/待收货/已完成
4 V1 范围 含退款、推广码、埋点;不含会员体系
5 上线范围 郑州 + 4 款清香型
6 总部端载体 微信小程序
7 核销单次上限 ¥500
8 门店打款 T+1 工作日

10. 待技术对接事项

# 事项 说明
1 小飞侠 API 出库/配送中/签收状态枚举与回调格式
2 跨城物流 API 发货、轨迹、签收回调
3 微信退款 API 退款时效、部分退款能力
4 小程序基础库版本 四端最低兼容版本
5 服务费 V1 结算不扣除服务费;后续版本预留字段
6 总部小程序 appId 独立应用 or 子包方案

11. V1 里程碑

阶段 范围 交付
M1 基础 郑州开城、4 SKU、账号、总部小程序 可配置商品与开城
M2 交易 C端下单支付、待发货 Tab、同城配送 完整购酒履约
M3 权益 权益发放(可配置金额)、门店、核销(¥500 上限) O2O 闭环
M4 运营 合伙人门店录入、补发/拦截、退款工单 城市运营 + 售后
M5 结算 门店 T+1 打款、合伙人 T+30 对账 资金闭环
M6 增长 推广码归因、行为埋点、数据报表 渠道可追溯


§三、原型全清单与页面流

C端用户 pages/user/

文件 页面 关联模块
1-登录.png 登录 账号
2-首页.png 首页 商品展示、城市定位
3-商品详情页.png 商品详情 商品、好客权益说明
4-立即购买确认订单.png 确认订单(同城) 下单
5-订单确认-跨城配送.png 确认订单(跨城到付) 下单、配送规则
6-地址列表.png 地址列表 地址管理
7-新增收货地址.png 新增地址 地址管理
8-微信支付页面.png 微信支付 支付
9-我的订单列表.png 订单列表 订单
10-我的订单-补发状态.png 补发订单 售后
11-我的订单详情.png 订单详情 订单履约
12-修改地址弹窗.png 修改地址 订单
13-联系客服弹窗.png 联系客服 客服
14-联系在线客服.png 在线客服 客服
15-门店页面-门店列表.png 门店列表 门店
16-门店详情页.png 门店详情 门店
17-好客权益页.png 好客权益 权益
18-好客权益明细.png 权益明细 权益
19-个人中心页.png 个人中心 我的
20-好客权益核销.png 核销输入 核销
21-核销码展示.png 核销码 核销
22-核销成功及评价.png 核销成功 核销、评价

底部导航:首页 | 门店 | 好客权益 | 我的

门店端 H5 pages/shop/

文件 页面 关联模块
1-登录页.png 登录 账号
2-一键登录.png 快捷登录 账号
3-门店管理首页-核销页.png 首页 核销、营业状态
4-核销确认.png 核销确认 核销
5-核销成功.png 核销成功 核销
6-核销记录.png 核销记录 账单
7-门店信息.png 门店信息 门店

底部导航:首页 | 核销记录 | 我的

城市合伙人 pages/partner/

文件 页面 关联模块
1-登录页.png 登录 账号
2-快捷登录.png 快捷登录 账号
3-首页.png 工作台首页 概览
4-拦截配送.png 拦截配送 订单拦截
5-门店管理.png 门店管理 门店
6-录入门店.png 录入门店-基本信息 门店入驻
7-录入门店-合同.png 录入门店-照片合同 门店入驻
8-录入门店银行卡号.png 录入门店-结算信息 门店入驻
9-补发处理.png 补发处理 售后
10-财务对账.png 财务对账 结算
11-周报.png 经营周报 数据
12-订单列表.png 订单列表 订单
13-订单详情.png 订单详情 订单
14-贡献榜.png 合伙人贡献榜 拓店
15-子账号管理.png 子账号管理 账号
16-添加子账号.png 添加子账号 账号
17-合伙人中心.png 合伙人中心 我的
18-员工管理.png 员工管理 账号
19-门店核销列表.png 门店核销列表 权益
20-资产列表.png 资产明细 佣金
21-合同管理.png 合同管理 合同
22-确认账单.png 确认账单 结算
23-申请打款.png 申请打款 结算

底部导航:首页 | 门店管理 | 合伙人中心

总部管理 pages/hq/

文件 页面 关联模块
1-登录.png 登录 账号
2-快捷登录.png 快捷登录 账号
3-数据聚合与预警.png 管理中心首页 概览
4-预警详情.png 预警详情 预警
5-超时订单详情.png 超时订单 订单
6-开城管理.png 开城管理 开城
7-新增城市.png 新增城市 开城
8-完善开户行与附件上传.png 开城-银行信息 开城
9-配置佣金比例.png 配置佣金比例 开城/佣金
10-订单中心.png 订单中心搜索 订单
11-订单中心管理页.png 订单中心列表 订单
12-商品列表.png 商品列表 商品
13-订单详情-1~4.png 订单详情 订单
14-商品添加.png 商品添加 商品
15-数据报表中心.png 数据报表 数据
16-推广码管理.png 推广码管理 营销
17-推广码生成.png 推广码生成 营销
18-佣金拆分和订单.png 佣金拆分 佣金
19-门店审核管理.png 门店审核 门店
20-门店详情页面.png 门店详情 门店
21-结算中心.png 结算中心 结算
22-账单明细.png 账单明细 结算
23-门店结算明细.png 门店结算 结算
24-跨城订单处理.png 跨城订单 订单
25-发货处理.png 发货处理 订单
26-补发与退款处理.png 补发退款 售后
27-补发详情页面.png 补发详情 售后

底部导航:管理中心 | 门店审核 | 结算中心 | 客服中心

第三方集成清单

系统 用途 触发场景
微信登录/支付 登录、下单支付 C端、门店、合伙人
微信客服 图文客服 C端联系客服
小飞侠 同城配送状态回调 出库、配送中、签收
物流快递 跨城配送状态 跨城订单
微信地图 选址、导航 地址、门店
短信 核销到账通知、账单链接 门店老板
微信扫一扫 门店核销(H5 外) 门店端

C 端页面流

登录(1) → 首页(2) → 商品详情(3) → 确认订单(4/5) → 支付(8) 订单列表(9) → 订单详情(11) → 修改地址(12) 门店列表(15) → 门店详情(16) → 核销(20) → 核销码(21) → 成功(22) 好客权益(17) → 明细(18) → 个人中心(19) → 地址(6/7)

原型与 PRD 差异(实现以 PRD 为准)

原型 说明
pages/user/9 Tab 必须为 5 个:全部/待付款/待发货/待收货/已完成
pages/user/19 移除「至尊会员」标签
各端城市示例 原型多为洛阳,V1 上线城市为郑州

§四、技术架构

1.1 建设目标

在 V1 范围内(郑州开城、4 SKU、四端协同)交付可运营的生产系统,支撑:

  • 购酒交易与微信支付的可靠闭环
  • 好客权益发放、核销与门店 T+1 结算
  • 城市合伙人拓店、履约、T+30 分佣结算
  • 总部开城/商品/审核/客服/数据运营
  • 推广码归因与用户行为埋点

1.2 架构原则

原则 说明
方案三:统一后端 + 模块归属 一个 NestJS 进程;全栈按「端 + 后端模块」分工,禁止多端各自起服务、仅共库
单体优先、模块化拆分 V1 单进程部署;模块间通过 Exported Service 协作,禁止跨模块直写表
多端复用、统一 API 四端共用 REST API;契约见本手册 §六
事件驱动异步 支付/配送回调、埋点、T+1 结算走 BullMQ,保证幂等
开城可扩展 城市、佣金、配送规则配置化
财务可追溯 订单、权益、核销、打款全链路留痕
共享类型优先 枚举/DTO 放 packages/shared-types,禁止各端复制业务常量

1.3 推荐技术栈(总览)

层次 推荐选型 备选
C端 / 合伙人 / 总部小程序 Taro 3 + React + TypeScript 原生微信小程序 ×3
门店 H5 Taro H5(与小程序同 monorepo Vue3 + Vite 独立 H5
后端 API Node.js 20 LTS + NestJS 10 Express / Koa(需自建分层)
ORM Prisma TypeORM
主库 MySQL 8.0
缓存 / 锁 / 队列 Redis 7 + BullMQ ioredis 直连
对象存储 阿里云 OSS / 腾讯云 COS
定时任务 @nestjs/schedule + BullMQ 延时队列 node-cron
埋点 自建 log_user_analytics + BullMQ 异步入库
部署 Docker + PM2 或 Node 单进程 + Nginx K8s(二期)
CI/CD GitHub Actions / GitLab CI

选型理由(NestJS + Taro 全栈 TypeScript

  • 与前端同语言Taro 与 NestJS 共用 TypeScriptDTO/枚举可抽到 packages/shared-types减少联调成本
  • NestJS 模块化Module/Controller/Service 分层清晰,接近 Spring 结构,适合订单/结算等复杂域
  • 微信生态wechatpay-node-v3、小程序 code2session 等 Node SDK 成熟,满足 V1 支付/退款
  • 异步友好:支付回调、埋点、短信等 I/O 密集场景 Node 表现良好
  • V1 仍为模块化单体,无需微服务

2. 系统架构

2.1 逻辑架构

flowchart TB
    subgraph clients [客户端]
        U[C端小程序]
        P[合伙人小程序]
        H[总部小程序]
        S[门店 H5]
    end

    subgraph gateway [接入层]
        NG[Nginx / HTTPS]
    end

    subgraph app [dukang-api 单体服务]
        direction TB
        M1[iam 身份认证]
        M2[catalog 商品开城]
        M3[trade 交易订单]
        M4[benefit 好客权益]
        M5[store 门店]
        M6[redeem 核销]
        M7[settlement 结算]
        M8[ops 总部运营]
        M9[notify 通知集成]
        M10[analytics 埋点报表]
    end

    subgraph infra [基础设施]
        DB[(MySQL)]
        RD[(Redis)]
        OSS[对象存储]
    end

    subgraph ext [外部系统]
        WX[微信登录/支付/退款/客服]
        XFX[小飞侠配送]
        LOG[物流快递]
        SMS[短信]
    end

    U & P & H & S --> NG --> app
    app --> DB & RD & OSS
    app --> WX & XFX & LOG & SMS

2.2 部署架构(V1

                    ┌──────────────┐
                    │   CDN/OSS    │  静态资源、图片
                    └──────────────┘
┌─────────┐         ┌──────────────┐         ┌─────────┐
│ 微信小程序 │ ──────►│ Nginx + SSL  │────────►│ MySQL   │
│ ×3 + H5 │         │ NestJS :3000 │         │ 主从可选 │
└─────────┘         └──────┬───────┘         └─────────┘
                           │
                           └────────────────► Redis + BullMQ
  • 环境dev / staging / prod 三套
  • 配置:敏感项走环境变量(.env 不入库);生产用 Docker secrets
  • 日志Pino 结构化 JSON + 请求 traceIdnestjs-pino
  • 进程PM2 cluster 或 Docker 单副本;V1 单实例即可

2.3 仓库结构(Monorepo 建议)

dukang/
├── apps/
│   ├── mini-user/          # C端 Taro 小程序
│   ├── mini-partner/       # 合伙人 Taro 小程序
│   ├── mini-hq/            # 总部 Taro 小程序
│   └── h5-shop/            # 门店 H5Taro 或独立)
├── packages/
│   ├── shared-ui/          # 公共组件(前端)
│   ├── shared-utils/       # 工具、常量
│   ├── shared-types/       # API DTO、枚举、错误码(前后端共用)
│   └── domain/             # 纯函数领域规则(起购/核销上限/权益计算,无 IO)
├── server/
│   └── dukang-api/         # 唯一后端进程(NestJS 单体)
│       ├── prisma/         # schema 按模块 OWNER 分区注释,迁移需 OWNER Review
│       └── src/
│           ├── common/     # 全局:Guard、Filter、PrismaModule
│           ├── modules/    # 见 §2.4 模块归属
│           ├── callbacks/  # 微信/配送回调(薄层,转调各 Module Service
│           └── jobs/       # BullMQ 消费者、定时任务
├── doc/
└── deploy/

2.4 多人协作架构(方案三)

2.4.1 方案定义

结论
选定方案 方案三Monorepo + 一个 NestJS 后端 + 模块 OWNER + 全栈负责「端 + 模块」
明确不做 多端各自独立后端、仅数据库对齐;多个微信支付回调入口
协作单元 后端 Module(领域边界)+ 前端 App(交互边界)
集成契约 HTTP APIdoc/API列表-杜康好客.md+ shared-types + Prisma schemaOWNER Review

2.4.2 分工模型

全栈开发者 A  ──► apps/mini-user        + modules/{iam,trade,benefit}  Controller
全栈开发者 B  ──► apps/mini-partner     + modules/{store} + 部分 partner 接口
全栈开发者 C  ──► apps/mini-hq          + modules/{catalog,ops,settlement} 总部侧
全栈开发者 D  ──► apps/h5-shop          + modules/{redeem} + 门店侧接口
公共           ──► packages/* , callbacks/, jobs/ , prisma 迁移(架构师/轮值 Review

OWNER 为主责(改代码、Review PR、负责迁移),非 OWNER 提需求走 Issue + 跨模块 PR。

2.4.3 模块与端归属表

后端模块 职责摘要 主 OWNER 建议 关联前端 App 关联 API 前缀
iam 登录、JWT、四端鉴权、用户身份 U1~U5 全栈 A 四端共用 /auth, /user
catalog 开城、商品、推广码、佣金配置 全栈 C mini-hq /catalog, /admin/cities, /admin/products, /admin/promo-codes
trade 订单、支付、退款、拦截、补发单 全栈 A mini-user, mini-partner, mini-hq /trade, /admin/orders, /partner/orders
benefit 权益券、流水、发放/作废 全栈 A mini-user /benefit
store 门店 CRUD、审核、营业状态 全栈 B mini-partner, mini-user, mini-hq /stores, /partner/stores, /admin/store-audits
redeem 核销码、确认核销、评价 全栈 D h5-shop, mini-user /redeem, /shop/redeem
settlement 门店 T+1、合伙人 T+30、提现 全栈 C mini-partner, h5-shop, mini-hq /settlement, /partner/settlement, /admin/settlement
ops 总部看板、预警、报表聚合 全栈 C mini-hq /admin/dashboard, /admin/reports, /admin/alerts
notify 短信、订阅消息(被各模块调用) 轮值 / 架构 内部 Service
analytics 埋点入库、渠道统计 全栈 A mini-user + 总部报表 /analytics, /promo/touch
callbacks 微信/小飞侠/物流回调入口 架构师 + trade OWNER /callbacks/*
jobs 超时关单、T+1 打款、出账 settlement + trade OWNER 内部

2.4.4 协作规则(强制)

# 规则
R1 禁止 Module A 直接使用 PrismaService 读写 Module B 拥有的表;只调用 B 导出的 XxxService
R2 每个 Module 通过 xxx.module.tsexports: [XxxService] 暴露能力;禁止 export Repository/Prisma 裸访问
R3 schema.prisma 中某表 → 必须对应模块 OWNER Review
R4 新增/变更 API → 同步更新 doc/API列表-杜康好客.md + shared-types
R5 跨模块写操作走 Service 调用Domain Event + BullMQ;禁止分布式「各写各的」
R6 微信支付/退款/配送回调 callbacks/ 入口,内部转调 TradeService
R7 集成测试必须覆盖横切链路:购酒→发券→核销→门店打款(CI 门禁)
R8 前端 App 禁止 import server/ 代码;只通过 HTTP + shared-types

2.4.5 全栈闭环定义

「独立闭环」指 在模块依赖规则内 端到端交付,而非单独部署:

开发者 闭环范围(示例)
A C端下单支付 → 发券 → 权益页(trade + benefit + mini-user
B 合伙人录店 → 总部审核 → C端可见(store + mini-partner + 配合 C 审核 API
D C端出码 → 门店扫码核销 → 短信通知(redeem + h5-shop + notify 调用)
C 总部退款/结算/报表(trade 回调 + settlement + ops + mini-hq

2.5 模块依赖:允许 / 禁止

2.5.1 分层与允许依赖(模块图)

规则:只能 向下同层通过 exported Service 依赖;箭头表示「允许 import / inject」。

flowchart TB
    subgraph L6 [L6 接入与编排]
        CB[callbacks 回调入口]
        JB[jobs 定时与队列]
        OP[ops 运营报表]
    end

    subgraph L5 [L5 结算域]
        ST[settlement 结算]
    end

    subgraph L4 [L4 核销域]
        RD[redeem 核销]
    end

    subgraph L3 [L3 交易域]
        TR[trade 订单支付]
        BF[benefit 好客权益]
    end

    subgraph L2 [L2 主数据]
        CT[catalog 开城商品]
        SO[store 门店]
    end

    subgraph L1 [L1 基础域]
        IM[iam 身份]
        AN[analytics 埋点]
        NT[notify 通知]
    end

    subgraph L0 [L0 基础设施]
        CM[common 公共]
        PR[(prisma)]
        PK[packages/domain]
    end

    CB --> TR
    CB --> ST
    JB --> ST
    JB --> TR

    OP --> TR
    OP --> ST
    OP --> SO
    OP --> AN

    ST --> TR
    ST --> RD
    ST --> SO
    ST --> CT

    RD --> BF
    RD --> SO
    RD --> ST
    RD --> IM
    RD --> NT

    TR --> BF
    TR --> CT
    TR --> IM
    TR --> SO
    TR --> NT

    BF --> IM

    SO --> CT
    SO --> IM

    CT --> IM

    AN --> IM

    IM --> CM
    TR --> CM
    BF --> CM
    RD --> CM
    ST --> CM
    SO --> CM
    CT --> CM
    OP --> CM
    AN --> CM
    NT --> CM
    CB --> CM
    JB --> CM

    TR -.-> PK
    BF -.-> PK
    RD -.-> PK
    ST -.-> PK

图例

  • 实线箭头:允许 NestJS Module imports + Service 注入
  • 虚线:允许引用 packages/domain 纯函数(无 DB/Redis

2.5.2 允许依赖矩阵( = 可调 Service

调用方 ↓ / 被调方 → iam catalog store trade benefit redeem settlement notify analytics domain
catalog
store
trade
benefit
redeem
settlement
ops
callbacks
jobs
analytics

2.5.3 禁止依赖( 违反即 PR 拒绝)

# 禁止项 原因 正确做法
F1 redeem → 直接 prisma.order.update 订单归 trade TradeService
F2 storetrade / benefit 门店域不处理交易 由 redeem/trade 回调
F3 benefittrade / redeem 防止循环依赖 trade 调 BenefitService.grant(dto)benefit 不反向查 trade
F4 traderedeem 交易不感知核销细节 仅通过 benefit 关联
F5 benefitredeem 权益不依赖核销 redeem 调 benefit 扣券
F6 catalogtrade / settlement 主数据不依赖业务 反向调用
F7 任意 Module → 另一 Module 的 *.controller.ts Controller 不可跨模块引 只 inject Service
F8 任意 Module → 另一 Module 未 export 的 Provider 破坏封装 module.ts 显式 exports
F9 apps/*server/* 源码 import 前后端物理隔离 HTTP + shared-types
F10 多个 Module 各自注册 /callbacks/wechat/pay 重复回调 callbacks 模块
F11 复制粘贴起购/核销/权益规则到 Controller 规则漂移 packages/domain

2.5.4 跨模块典型调用链(允许)

支付成功发券

callbacks/wechat/pay → TradeService.handlePaySuccess()
  → BenefitService.grantOnOrderPaid(orderId)
  → NotifyService(可选)

核销确认

ShopRedeemController → RedeemService.confirm()
  → BenefitService.deduct(couponId)
  → SettlementService.createStorePayout(redeemRecordId)
  → NotifyService.sendSms(storeOwner)

退款

AdminRefundController → TradeService.createRefund()
  → BenefitService.voidUnused(orderId)
  → WechatPayService.refund()

2.5.5 Module 文件约定

每个模块目录结构统一,便于 CODEOWNERS:

modules/trade/
├── trade.module.ts      # imports / exports 唯一入口
├── trade.controller.ts  # 仅本域路由
├── trade.service.ts     # 业务 + 本域表 Prisma
├── dto/
├── events/              # 可选:BullMQ producer
└── __tests__/

trade.module.ts 示例:

@Module({
  imports: [CatalogModule, BenefitModule, IamModule, NotifyModule],
  controllers: [TradeController, PartnerOrderController, AdminOrderController],
  providers: [TradeService, WechatPayService],
  exports: [TradeService], // 仅导出 Service
})
export class TradeModule {}

3. 后端模块设计

3.1 模块职责

模块 职责 主要实体
iam 四端登录、Token、角色权限、子账号 User, Account, Role, Session
catalog 商品、开城、推广码、佣金配置 Product, City, PromoCode, CommissionRule
trade 订单、支付、退款、补发、地址改派 Order, OrderItem, Payment, Refund, Reshipment
benefit 权益券发放、余额、明细 BenefitCoupon, BenefitLedger
store 门店 CRUD、审核、营业状态 Store, StoreAudit, StoreMedia
redeem 核销码生成、门店扫码核销、评价 RedeemToken, RedeemRecord, StoreRating
settlement 门店 T+1、合伙人 T+30 账单 StorePayout, PartnerBill, Withdrawal
ops 总部首页统计、预警、报表 Alert, ReportSnapshot
notify 微信/短信/订阅消息封装 NotificationLog
analytics 埋点接收、渠道归因 EventLog, ChannelAttribution

3.2 核心领域模型(简化 ER

erDiagram
    USER ||--o{ ORDER : places
    ORDER ||--|{ ORDER_ITEM : contains
    ORDER ||--o| PAYMENT : has
    ORDER ||--o{ BENEFIT_COUPON : grants
    BENEFIT_COUPON ||--o{ REDEEM_RECORD : redeemed_at
    STORE ||--o{ REDEEM_RECORD : receives
    STORE }o--|| CITY : belongs
    CITY }o--|| PARTNER : managed_by
    ORDER }o--o| PROMO_CODE : attributed
    REDEEM_RECORD ||--o| STORE_PAYOUT : settles
    PARTNER ||--o{ PARTNER_BILL : billed

3.3 订单状态机(后端枚举)

PENDING_PAY      待付款
PENDING_SHIP     待发货
SHIPPING         配送中
PENDING_RECEIVE  待签收
COMPLETED        已完成
REFUNDING        退款中
REFUNDED         已退款

补发单:RESHIPMENT,关联 origin_order_id,金额 0。

3.4 好客权益规则(实现要点)

// 发放金额
const benefitAmount = product.benefitAmount ?? product.price;

// 核销校验
if (amount <= 0 || amount > coupon.balance || amount > 500) {
  throw new BusinessException('INVALID_REDEEM_AMOUNT');
}
  • 核销 TokenRedis SET redeem:token:{id} JSON EX 300
  • 核销事务:Prisma $transaction 内完成「扣券余额 → 写 redeem_record → 写 store_payout 待打款」
  • 并发:券表 version 字段乐观锁,或 UPDATE ... WHERE balance >= amount

3.5 NestJS 模块与依赖

模块边界与允许/禁止依赖见 §2.5。 下表为各 Module 技术要点。

NestJS Module 主要 Providers 外部依赖
IamModule AuthService, JwtStrategy Redissession
TradeModule OrderService, WechatPayService BenefitModule, CatalogModule
RedeemModule RedeemService BenefitModule, SettlementModule, Redis
SettlementModule PayoutService, BillService BullMQT+1 任务)
NotifyModule SmsService, WxSubscribeService 短信 SDK(被各模块 inject

常用 Nest 生态

能力
配置 @nestjs/config
校验 class-validator + class-transformer
JWT @nestjs/jwt + @nestjs/passport
定时 @nestjs/schedule
队列 @nestjs/bullmq
微信支付的 wechatpay-node-v3
API 文档 @nestjs/swagger

3.6 鉴权与多租户

标识 数据隔离
C端 user_id 仅本人订单/权益/地址
门店 store_id 仅本店核销记录
合伙人 partner_id + city_id 仅辖城市订单/门店
总部 admin_role 全局;操作审计日志

TokenJWTaccess 2h+ Redis refresh;小程序登录走 wx.login → code2session。


4. 接口设计规范

4.1 约定

  • Base URLhttps://api.example.com/api/v1
  • 认证:Authorization: Bearer <token>
  • 响应:{ "code": 0, "message": "ok", "data": {} }
  • 分页:page, pageSize;列表统一 { list, total }
  • 幂等:支付回调、核销、退款用 业务幂等键idempotency_key / 微信 transaction_id

4.2 核心 API 分组(V1

认证 /auth

方法 路径 说明
POST /auth/sms/send 发送验证码
POST /auth/login/sms 手机号登录
POST /auth/login/wechat 微信登录(含 appId 区分端)
POST /auth/refresh 刷新 Token

商品与开城 /catalog

| GET | /products | 商品列表(按城市/香型) | | GET | /products/{id} | 商品详情 | | GET | /cities/current | 当前开城信息 |

交易 /trade

| POST | /orders/preview | 下单预览(配送方式、起购校验、运费) | | POST | /orders | 创建订单 | | POST | /orders/{id}/pay | 发起微信支付 | | POST | /callbacks/wechat/pay | 支付回调(内部) | | GET | /orders | 订单列表(tab 参数) | | GET | /orders/{id} | 订单详情 | | PUT | /orders/{id}/address | 修改地址(触发拦截工单) | | POST | /orders/{id}/confirm-receive | 确认收货 |

权益与核销 /benefit, /redeem

| GET | /benefit/summary | 权益余额汇总 | | GET | /benefit/coupons | 券列表 | | POST | /redeem/token | 生成核销码 | | POST | /redeem/confirm | 门店确认核销 | | POST | /redeem/rating | 核销后评价 |

门店 /stores

| GET | /stores | C端门店列表(仅营业中) | | GET | /stores/{id} | 门店详情 | | PUT | /stores/{id}/status | 门店切换营业状态(门店端) | | POST | /stores | 合伙人录入门店 | | POST | /stores/{id}/audit | 总部审核 |

结算 /settlement

| GET | /settlement/store/records | 门店核销记录 | | GET | /settlement/partner/bills | 合伙人账单 | | POST | /settlement/partner/bills/{id}/confirm | 确认账单 |

总部运营 /admin

| GET | /admin/dashboard | 今日概况 | | GET | /admin/alerts | 待办预警 | | POST | /admin/refunds | 创建退款工单 | | POST | /admin/reshipments | 创建补发单 | | POST | /admin/promo-codes | 创建推广码 |

埋点 /analytics

| POST | /analytics/events | 批量上报(可异步队列) |


5. 第三方集成

5.1 微信支付

场景 接口 要点
下单支付 JSAPI 统一下单 wechatpay-node-v3,按 appId 多商户配置
支付回调 notify_url 验签 → BullMQ 异步入队 → 幂等更新订单 → 发券
退款 退款 API RefundService;失败重试队列

5.2 小飞侠(同城配送)

  • 下单成功后推送配送单
  • 回调状态映射:OUT_WAREHOUSE → SHIPPING → DELIVERED
  • 超时未回调 → 总部预警(admin/alerts

5.3 跨城物流

  • 总部手动/半自动发货;对接物流查询 API(V1 可人工录入运单号 + 状态手动更新,API 对接并行)

5.4 短信

  • 核销成功通知门店老板
  • 账单链接(短链跳转 H5/小程序页)

5.5 推广码

  • 小程序码参数:scene=promo_{code}
  • 启动时写入 Redis user:{id}:channel,下单时落库 order.channel_source


§五、数据库设计 v3.1

1. 命名规范

前缀 含义 示例
user_ C 端用户域 user_order
partner_ 城市合伙人域 partner_bill
store_ 门店域 store_store
hq_ 总部域 hq_account
common_ 跨域公共 common_resourcecommon_event
log_ 日志/审计(只追加) log_third_party

2. 公共抽象设计

2.1 common_resource(资源表 · OSS

所有图片、视频、合同文件统一入库,文件实体在阿里云 OSS

字段 说明
owner_type 归属类型:PRODUCT / STORE / PARTNER / USER / ORDER / HQ
owner_id 归属业务 ID
biz_type 业务用途:COVER / ENV / CONTRACT / CAROUSEL / DETAIL / AVATAR / QRCODE / SIGN_PHOTO / VIDEO
media_type IMAGE / VIDEO / FILE
oss_bucket / oss_key OSS 定位
url 访问 URLCDN
sort_order 同 owner 下排序

替代关系

原表/字段 v3 做法
store_media owner_type=STORE, biz_type=COVER/ENV/CONTRACT
partner_contracts.file_url owner_type=PARTNER, biz_type=CONTRACT + partner 表存 contract_no
products.main_image_url / carousel_urls owner_type=PRODUCT, biz_type=COVER/CAROUSEL
stores.cover_url cover_resource_idcommon_resource.id
promo_codes.wx_qrcode_url owner_type=PROMO, biz_type=QRCODE
用户头像 owner_type=USER, biz_type=AVATAR
签收照片 owner_type=ORDER, biz_type=SIGN_PHOTO

2.2 common_event(统一业务事件表)

定位:仅记录有业务语义、需审计/追溯的后端事件(审核、状态流转、权益变动、总部操作、推广触达统计)。用户行为埋点写入 log_user_analytics,不写入本表。

查询:ref_type + ref_id + event_type

字段 说明
event_type 事件类型(见 §5.1
ref_type / ref_id 关联业务实体
actor_type / actor_id 操作人(USER/STORE/PARTNER/HQ/SYSTEM
status 部分事件有状态(如审核 PENDING/APPROVED
param1 ~ param3 参数值(状态码、ID、类型等)
param1_desc ~ param3_desc 参数含义说明(文档化,便于 UI 展示)
amount1 / amount2 BENEFIT_LEDGER 使用(变动额、变动后余额);其余类型为 NULL
remark 备注/驳回原因
extra_json 扩展快照(原 submit_data、操作 detail 等)

2.3 common_ticket(通用工单表)

after_sale_tickets、部分 alerts 等工单类事务统一抽象。

字段 说明
ticket_type REFUND / RESHIPMENT / ALERT
ticket_no 对外工单号
ref_type / ref_id 关联订单/门店等
operator_type / operator_id 处理人
param1 ~ param3 + desc 类型相关参数(金额、关联单号等)
status 工单状态

2.4 log_third_party(第三方交互记录)

payments 及所有外部调用统一记录。

字段 说明
provider WECHAT_PAY / WECHAT_REFUND / WECHAT_AUTH / WECHAT_MAP / XFX / SMS / LOGISTICS
scene 业务场景:ORDER_PAY / ORDER_REFUND / LOGIN / DELIVERY_CALLBACK / SMS_VERIFY
ref_type / ref_id 关联订单/用户等
request_url 请求 URL
request_body 发送参数 JSON
response_body 响应 JSON
external_no 第三方单号(微信 transaction_id 等)
amount 涉及金额
status PENDING / SUCCESS / FAILED

订单支付:不再建 payments 表;user_order 保留 pay_status / paid_at / pay_external_no 冗余字段,明细查 log_third_party

核销码:删除 redeem_tokens 表,仅存 Redis5 分钟);user_redeem_record 不再存 token_id。

2.5 log_user_analytics(用户埋点日志)

C 端行为埋点专用表,与 common_event 分离(见 §4.1 探讨)。

字段 说明
user_id 用户 ID;未登录上报可为 NULL
session_id 会话 ID,用于漏斗串联
event_name 事件名(与 PRD §3.10.2 对齐,见 §4.1
ref_type / ref_id 关联商品/门店/订单等
keyword 搜索类事件关键词
source_type / source_ref_id 注册类事件来源快照
extra_json 其余埋点参数

3. 表清单(28 张)

前缀 表名 说明
common common_wx_app_config 四端微信配置
common common_resource 统一资源(OSS
common common_event 统一业务事件(非埋点)
common common_ticket 通用工单
common common_product_item 商品 SKU(含 69 码)
common common_store_category 门店餐饮分类
common common_city 开城
common common_city_commission_rule 城市佣金规则
common common_promo_code 推广码
user user_user C 端用户(含注册来源)
user user_address 收货地址
user user_city_preference 城市偏好
user user_promo_attribution 推广首次触达(统计用)
user user_order 订单(含商品快照冗余,无明细子表)
user user_order_delivery 配送(含签收照,与订单 1:1
user user_benefit_coupon 权益券
user user_redeem_record 核销记录
user user_store_rating 核销评价
partner partner_partner 合伙人主体
partner partner_account 合伙人账号
partner partner_bill T+30 账单(汇总金额,无 commission 明细表)
store store_store 门店
store store_account 门店登录账号
store store_payout 门店 T+1 打款
hq hq_account 总部账号
log log_third_party 第三方交互日志
log log_user_analytics 用户行为埋点日志

5. 枚举与事件/工单参数映射

5.1 common_event.event_type(写入逻辑)

event_type 中文 原表 触发逻辑 param 约定 amount
STORE_AUDIT 门店审核 store_audits 门店提交入驻/资料变更;总部审核通过或驳回 p1=audit_type(NEW/UPDATE), p2=status, p3=reviewer_idremark=驳回原因;extra=submit_data
ORDER_STATUS 订单状态变更 order_status_logs 状态机每次 transition(含 SYSTEM/回调) p1=from_status, p2=to_status, p3=operator 标识
BENEFIT_LEDGER 权益流水 benefit_ledgers 发券/核销/退款作废/人工调整,与券余额变更同事务 p1=ledger_type(GRANT/REDEEM/VOID/ADJUST), p2=coupon_id, p3=ref_idref_type=关联类型 amount1=变动额, amount2=balance_after
HQ_OPERATION 总部操作审计 operation_logs 总部后台写操作(非查询) p1=action, p2=ref_type, p3=ref_idextra=detail
PROMO_TOUCH 推广触达 用户扫码/带参进入(可选,与 scan_count++ 同事务) p1=promo_code_id, p2=触达类型(SCAN/LINK)

5.2 common_ticket.ticket_type

ticket_type 中文 原场景 param 约定
REFUND 退款工单 客服发起退款 p1=refund_amount, p2=wx_refund_id, p3=benefit_adjust
RESHIPMENT 补发工单 漏发/错发补发 p1=origin_order_id, p2=reshipment_order_id
ALERT 运营预警 超时未发货等 p1=alert_type, p2=severityextra=content

5.3 枚举值(含中文释义)

订单 user_order

字段 枚举值 中文释义
status PENDING_PAY 待付款
PENDING_SHIP 待发货
OUT_WAREHOUSE 已出库
SHIPPING 配送中
PENDING_RECEIVE 待签收
COMPLETED 已完成
CANCELLED 已取消
REFUNDING 退款中
REFUNDED 已退款
pay_status UNPAID 未支付
PAYING 支付中
PAID 已支付
REFUNDING 退款中
REFUNDED 已退款
order_type NORMAL 普通订单
RESHIPMENT 补发订单
delivery_type LOCAL 同城配送
CROSS_CITY 跨城配送
freight_pay_type FREE 包邮
COD 运费到付

权益 user_benefit_coupon

字段 枚举值 中文释义
status ACTIVE 可用
USED_UP 已用完
VOID 已作废

门店 store_store

字段 枚举值 中文释义
status OPEN 营业中
PAUSED 临时闭店
CLOSED 永久关闭

结算

表.字段 枚举值 中文释义
store_payout.status PENDING 待打款
PAID 已打款
partner_bill.status DRAFT 草稿
PENDING_CONFIRM 待合伙人确认
CONFIRMED 已确认
PAID 已打款
REJECTED 已驳回

用户来源 user_user.source_type

枚举值 中文释义
ORGANIC 自然流量(无渠道参数)
PROMO_CODE 推广码/渠道码
SHARE_LINK 分享链接(好友/群分享带参)
FRIEND_REFERRAL 好友推荐(referrer_user_id
OFFLINE_EVENT 线下活动
OTHER 其他

商品 common_product_item

字段 枚举值 中文释义
aroma_type QINGXIANG 清香型
JIANGXIANG 酱香型
NONGXIANG 浓香型
status DRAFT 草稿
ON_SALE 在售
OFF_SALE 下架

开城 common_city.status

枚举值 中文释义
PENDING 待开城
ACTIVE 已开城
PAUSED 暂停

资源 common_resource

字段 枚举值 中文释义
media_type IMAGE 图片
VIDEO 视频
FILE 文件
status ACTIVE 有效
DELETED 已删除

账号状态(store_account / partner_account / hq_account

枚举值 中文释义
ACTIVE 正常
DISABLED 禁用

合伙人子账号 partner_account.staff_role

枚举值 中文释义
PARTNER 合伙人
INTERNAL 内部员工
PROMOTER 推广员

总部职能 hq_account.admin_role

枚举值 中文释义
SUPER_ADMIN 超级管理员
OPS 运营
FINANCE 财务
CUSTOMER_SERVICE 客服

配送 user_order_delivery.provider

枚举值 中文释义
XFX 小飞侠同城
LOGISTICS 传统物流
MANUAL 人工配送

第三方 log_third_party

字段 枚举值 中文释义
provider WECHAT_PAY 微信支付
WECHAT_REFUND 微信退款
WECHAT_AUTH 微信授权
WECHAT_MAP 微信地图
XFX 小飞侠
SMS 短信
LOGISTICS 物流查询
status PENDING 处理中
SUCCESS 成功
FAILED 失败

权益流水 BENEFIT_LEDGER param1ledger_type

枚举值 中文释义
GRANT 发放
REDEEM 核销扣减
VOID 退款作废
ADJUST 人工调整

工单 common_ticket.status(通用)

枚举值 中文释义
PENDING 待处理
PROCESSING 处理中
COMPLETED 已完成
REJECTED 已驳回
CANCELLED 已取消

6. ER 图(核心)

erDiagram
    user_user ||--o{ user_address : has
    user_user ||--o| user_city_preference : has
    user_user ||--o{ user_order : places
    user_user ||--o{ user_benefit_coupon : owns
    user_user ||--o{ user_redeem_record : redeems
    user_user ||--o{ log_user_analytics : tracks

    common_city ||--o{ store_store : contains
    common_city ||--o{ user_order : routes
    partner_partner ||--o{ common_city : manages
    partner_partner ||--o{ store_store : owns
    partner_partner ||--o{ partner_account : has
    partner_partner ||--o{ partner_bill : billed

    common_product_item ||--o{ user_order : sold_in
    common_promo_code ||--o{ user_order : source

    user_order ||--o| user_order_delivery : "1:1 delivered"
    user_order ||--o{ user_benefit_coupon : grants
    user_order ||--o{ common_ticket : tickets
    user_order ||--o{ log_third_party : third_party

    user_benefit_coupon ||--o{ user_redeem_record : redeemed
    store_store ||--o{ user_redeem_record : receives
    store_store ||--|| store_account : login
    store_store ||--o{ store_payout : payout

    common_resource }o--|| store_store : cover
    common_resource }o--|| common_product_item : images
    common_resource }o--|| user_order : product_image
    common_resource }o--|| user_order_delivery : sign_photo

    common_event }o--|| user_order : logs
    common_event }o--|| store_store : audits
    common_event }o--|| user_benefit_coupon : ledger

    common_ticket }o--|| user_order : after_sale
    hq_account ||--o{ common_ticket : handles

7. 公共 APIcommon 模块)

详见本手册 §六;以下为 v3 新增/调整接口。

7.1 资源 common_resource

方法 路径 鉴权 说明
POST /common/resources/upload-token * 获取 OSS 直传凭证 { bizType, mediaType, fileName }
POST /common/resources * 上传确认/登记 { ownerType, ownerId, bizType, ossKey, url, ... }
GET /common/resources * 列表 ?ownerType=&ownerId=&bizType=
GET /common/resources/:id * 详情
PUT /common/resources/:id * 更新排序/状态
DELETE /common/resources/:id * 删除(OSS 异步删)

7.2 事件 common_event

方法 路径 鉴权 说明
POST /common/events Internal/各端 写入事件(业务 Service 调用)
GET /common/events * 查询 ?refType=&refId=&eventType=&page=
GET /common/events/timeline * 聚合时间线(订单/门店详情页)

7.3 工单 common_ticket

方法 路径 鉴权 说明
POST /common/tickets AdminAuth 等 创建工单
GET /common/tickets * 列表 ?ticketType=&status=&refType=&refId=
GET /common/tickets/:id * 详情
PUT /common/tickets/:id/status * 更新状态/处理
PUT /common/tickets/:id/assign AdminAuth 指派处理人

7.4 第三方日志 log_third_party(只读,内部写入)

方法 路径 鉴权 说明
GET /common/third-party-logs AdminAuth 查询 ?provider=&scene=&refType=&refId=
GET /common/third-party-logs/:id AdminAuth 详情(对账/排错)

7.5 用户埋点 log_user_analytics

方法 路径 鉴权 说明
POST /log/analytics/batch UserAuth 可选 客户端批量上报 { events: [...] }
GET /admin/analytics/events AdminAuth 总部报表 ?eventName=&userId=&from=&to=
GET /admin/analytics/funnel AdminAuth 漏斗统计(V1 基础)

8. 核心业务链路(v3

8.1 购酒 → 发券

user_user
  → user_order(含 product 快照 + 价格冗余)
  → log_third_party (WECHAT_PAY, scene=ORDER_PAY) → user_order.pay_status=PAID
  → log_user_analytics (pay_success)
  → common_event (ORDER_STATUS → PENDING_SHIP)
  → user_order_delivery(预创建,待发货)
  → user_benefit_coupon
  → common_event (BENEFIT_LEDGER, GRANT)

8.2 核销 → 门店打款

Redis redeem:token (5min,无 DB 表)
  → user_redeem_record
  → common_event (BENEFIT_LEDGER, REDEEM)
  → store_payout (T+1)
  → user_store_rating
  → log_third_party (SMS, 通知门店)

8.3 门店入驻

partner_partner
  → store_store + common_resource (COVER/ENV/CONTRACT)
  → common_event (STORE_AUDIT, PENDING)
  → hq_account 审核 → common_event (APPROVED)
  → store_account

8.4 退款

common_ticket (REFUND)
  → log_third_party (WECHAT_REFUND)
  → user_benefit_coupon VOID
  → common_event (BENEFIT_LEDGER, VOID)
  → common_event (ORDER_STATUS, REFUNDED)

9. 可执行 SQL(完整建表脚本)

mysql -u root -p dukang_haoke < init_v3.sql

-- ============================================================
-- 杜康好客 V3.1 数据库初始化脚本
-- MySQL 8.0+  utf8mb4_unicode_ci  InnoDB
-- ============================================================

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

CREATE DATABASE IF NOT EXISTS dukang_haoke
  DEFAULT CHARACTER SET utf8mb4
  DEFAULT COLLATE utf8mb4_unicode_ci;

USE dukang_haoke;

-- ===================== COMMON =============================

DROP TABLE IF EXISTS common_wx_app_config;
CREATE TABLE common_wx_app_config (
  id            BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  client_app    VARCHAR(32)  NOT NULL COMMENT 'USER_MINI|PARTNER_MINI|HQ_MINI|SHOP_H5',
  app_id        VARCHAR(64)  NOT NULL,
  app_secret    VARCHAR(128) NOT NULL,
  mch_id        VARCHAR(32)  DEFAULT NULL,
  created_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_common_wx_app_config_client (client_app)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='四端微信配置';

DROP TABLE IF EXISTS common_resource;
CREATE TABLE common_resource (
  id            BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  owner_type    VARCHAR(32)  NOT NULL COMMENT 'PRODUCT|STORE|PARTNER|USER|ORDER|PROMO|HQ',
  owner_id      BIGINT UNSIGNED NOT NULL COMMENT '归属业务ID',
  biz_type      VARCHAR(32)  NOT NULL COMMENT 'COVER|ENV|CONTRACT|CAROUSEL|DETAIL|AVATAR|QRCODE|SIGN_PHOTO|VIDEO',
  media_type    VARCHAR(16)  NOT NULL DEFAULT 'IMAGE' COMMENT 'IMAGE|VIDEO|FILE',
  oss_bucket    VARCHAR(64)  NOT NULL COMMENT 'OSS Bucket',
  oss_key       VARCHAR(256) NOT NULL COMMENT 'OSS Object Key',
  url           VARCHAR(512) NOT NULL COMMENT 'CDN访问URL',
  file_name     VARCHAR(128) DEFAULT NULL,
  file_size     BIGINT UNSIGNED DEFAULT NULL COMMENT '字节',
  mime_type     VARCHAR(64)  DEFAULT NULL,
  sort_order    INT          NOT NULL DEFAULT 0,
  status        VARCHAR(16)  NOT NULL DEFAULT 'ACTIVE' COMMENT 'ACTIVE|DELETED',
  created_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  KEY idx_common_resource_owner (owner_type, owner_id, biz_type),
  KEY idx_common_resource_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='统一资源表(OSS)';

DROP TABLE IF EXISTS common_event;
CREATE TABLE common_event (
  id            BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  event_type    VARCHAR(32)  NOT NULL COMMENT 'STORE_AUDIT|ORDER_STATUS|BENEFIT_LEDGER|HQ_OPERATION|PROMO_TOUCH',
  ref_type      VARCHAR(32)  NOT NULL COMMENT 'ORDER|STORE|BENEFIT_COUPON|USER|PRODUCT|...',
  ref_id        BIGINT UNSIGNED NOT NULL,
  actor_type    VARCHAR(16)  DEFAULT NULL COMMENT 'USER|STORE|PARTNER|HQ|SYSTEM',
  actor_id      BIGINT UNSIGNED DEFAULT NULL,
  status        VARCHAR(32)  DEFAULT NULL COMMENT '事件子状态(如审核PENDING/APPROVED)',
  param1        VARCHAR(128) DEFAULT NULL,
  param1_desc   VARCHAR(64)  DEFAULT NULL,
  param2        VARCHAR(128) DEFAULT NULL,
  param2_desc   VARCHAR(64)  DEFAULT NULL,
  param3        VARCHAR(128) DEFAULT NULL,
  param3_desc   VARCHAR(64)  DEFAULT NULL,
  amount1       DECIMAL(10,2) DEFAULT NULL COMMENT '仅BENEFIT_LEDGER:变动额',
  amount2       DECIMAL(10,2) DEFAULT NULL COMMENT '仅BENEFIT_LEDGER:变动后余额',
  remark        VARCHAR(512) DEFAULT NULL,
  extra_json    JSON         DEFAULT NULL,
  created_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  KEY idx_common_event_ref (ref_type, ref_id, event_type),
  KEY idx_common_event_type_created (event_type, created_at),
  KEY idx_common_event_actor (actor_type, actor_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='统一事件表';

DROP TABLE IF EXISTS common_ticket;
CREATE TABLE common_ticket (
  id              BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  ticket_no       VARCHAR(32)  NOT NULL,
  ticket_type     VARCHAR(32)  NOT NULL COMMENT 'REFUND|RESHIPMENT|ALERT',
  status          VARCHAR(32)  NOT NULL DEFAULT 'PENDING',
  ref_type        VARCHAR(32)  NOT NULL COMMENT 'ORDER|STORE|PARTNER|...',
  ref_id          BIGINT UNSIGNED NOT NULL,
  operator_type   VARCHAR(16)  DEFAULT NULL COMMENT 'HQ|PARTNER|SYSTEM',
  operator_id     BIGINT UNSIGNED DEFAULT NULL,
  param1          VARCHAR(128) DEFAULT NULL,
  param1_desc     VARCHAR(64)  DEFAULT NULL,
  param2          VARCHAR(128) DEFAULT NULL,
  param2_desc     VARCHAR(64)  DEFAULT NULL,
  param3          VARCHAR(128) DEFAULT NULL,
  param3_desc     VARCHAR(64)  DEFAULT NULL,
  remark          VARCHAR(512) DEFAULT NULL,
  extra_json      JSON         DEFAULT NULL,
  created_at      DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  completed_at    DATETIME(3)  DEFAULT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY uk_common_ticket_no (ticket_no),
  KEY idx_common_ticket_ref (ref_type, ref_id),
  KEY idx_common_ticket_type_status (ticket_type, status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='通用工单表';

DROP TABLE IF EXISTS common_product_item;
CREATE TABLE common_product_item (
  id                BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  sku_code          VARCHAR(32)  NOT NULL COMMENT 'SKU编码',
  barcode_69        VARCHAR(32)  NOT NULL COMMENT '69码(商品条码)',
  name              VARCHAR(128) NOT NULL,
  subtitle          VARCHAR(256) DEFAULT NULL,
  aroma_type        VARCHAR(16)  NOT NULL COMMENT 'QINGXIANG|JIANGXIANG|NONGXIANG',
  spec              VARCHAR(128) NOT NULL,
  price             DECIMAL(10,2) NOT NULL,
  benefit_amount    DECIMAL(10,2) DEFAULT NULL COMMENT 'NULL=等同售价',
  status            VARCHAR(16)  NOT NULL DEFAULT 'DRAFT' COMMENT 'DRAFT|ON_SALE|OFF_SALE',
  sort_order        INT          NOT NULL DEFAULT 0,
  cover_resource_id BIGINT UNSIGNED DEFAULT NULL COMMENT '主图 common_resource.id',
  detail_content    JSON         DEFAULT NULL COMMENT '图文详情(纯文本结构)',
  created_at        DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at        DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_common_product_item_sku (sku_code),
  UNIQUE KEY uk_common_product_item_barcode (barcode_69),
  KEY idx_common_product_item_status (status, aroma_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='商品SKU';

DROP TABLE IF EXISTS common_store_category;
CREATE TABLE common_store_category (
  id    BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  code  VARCHAR(32)  NOT NULL,
  name  VARCHAR(64)  NOT NULL,
  sort  INT          NOT NULL DEFAULT 0,
  PRIMARY KEY (id),
  UNIQUE KEY uk_common_store_category_code (code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='门店餐饮分类';

DROP TABLE IF EXISTS common_promo_code;
CREATE TABLE common_promo_code (
  id              BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  code            VARCHAR(32)  NOT NULL,
  name            VARCHAR(128) NOT NULL,
  status          VARCHAR(16)  NOT NULL DEFAULT 'ACTIVE',
  qrcode_resource_id BIGINT UNSIGNED DEFAULT NULL COMMENT '小程序码 common_resource.id',
  scan_count      INT          NOT NULL DEFAULT 0,
  order_count     INT          NOT NULL DEFAULT 0,
  created_at      DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_common_promo_code_code (code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='推广码';

-- ===================== PARTNER(先于 city/store =============================

DROP TABLE IF EXISTS partner_partner;
CREATE TABLE partner_partner (
  id                BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  company_name      VARCHAR(128) NOT NULL,
  address           VARCHAR(256) NOT NULL,
  contact_phone     VARCHAR(20)  NOT NULL,
  contract_no       VARCHAR(64)  DEFAULT NULL COMMENT '合同编号',
  contract_signed_at DATETIME(3) DEFAULT NULL,
  contract_expire_at DATETIME(3) DEFAULT NULL,
  bank_account_name VARCHAR(64)  DEFAULT NULL,
  bank_account_no   VARCHAR(32)  DEFAULT NULL,
  bank_branch       VARCHAR(128) DEFAULT NULL,
  created_at        DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at        DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  KEY idx_partner_partner_phone (contact_phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='城市合伙人主体';

DROP TABLE IF EXISTS common_city;
CREATE TABLE common_city (
  id             BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  code           VARCHAR(16)  NOT NULL,
  name           VARCHAR(64)  NOT NULL,
  province       VARCHAR(32)  NOT NULL,
  status         VARCHAR(16)  NOT NULL DEFAULT 'PENDING',
  partner_id     BIGINT UNSIGNED DEFAULT NULL,
  local_min_qty  INT          NOT NULL DEFAULT 2,
  cross_min_qty  INT          NOT NULL DEFAULT 6,
  created_at     DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at     DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_common_city_code (code),
  KEY idx_common_city_partner (partner_id),
  CONSTRAINT fk_common_city_partner FOREIGN KEY (partner_id) REFERENCES partner_partner(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='开城配置';

DROP TABLE IF EXISTS common_city_commission_rule;
CREATE TABLE common_city_commission_rule (
  id                     BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  city_id                BIGINT UNSIGNED NOT NULL,
  order_commission_rate  DECIMAL(5,4) NOT NULL DEFAULT 0.0000,
  redeem_commission_rate DECIMAL(5,4) NOT NULL DEFAULT 0.0000,
  partner_profit_rate    DECIMAL(5,4) NOT NULL DEFAULT 0.3500,
  store_settlement_rate  DECIMAL(5,4) NOT NULL DEFAULT 0.6000,
  updated_at             DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_common_city_commission_city (city_id),
  CONSTRAINT fk_common_city_commission_city FOREIGN KEY (city_id) REFERENCES common_city(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='城市佣金规则';

DROP TABLE IF EXISTS partner_account;
CREATE TABLE partner_account (
  id                BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  partner_id        BIGINT UNSIGNED NOT NULL,
  phone             VARCHAR(20)  NOT NULL,
  name              VARCHAR(64)  NOT NULL,
  wx_open_id        VARCHAR(64)  DEFAULT NULL,
  wx_union_id       VARCHAR(64)  DEFAULT NULL,
  is_primary        TINYINT      NOT NULL DEFAULT 0,
  parent_account_id BIGINT UNSIGNED DEFAULT NULL,
  staff_role        VARCHAR(16)  DEFAULT NULL COMMENT 'PARTNER|INTERNAL|PROMOTER',
  status            VARCHAR(16)  NOT NULL DEFAULT 'ACTIVE',
  last_login_at     DATETIME(3)  DEFAULT NULL,
  created_at        DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at        DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_partner_account_phone (phone),
  KEY idx_partner_account_partner (partner_id),
  CONSTRAINT fk_partner_account_partner FOREIGN KEY (partner_id) REFERENCES partner_partner(id) ON DELETE RESTRICT,
  CONSTRAINT fk_partner_account_parent FOREIGN KEY (parent_account_id) REFERENCES partner_account(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合伙人账号';

DROP TABLE IF EXISTS partner_bill;
CREATE TABLE partner_bill (
  id                BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  bill_no           VARCHAR(32)  NOT NULL,
  partner_id        BIGINT UNSIGNED NOT NULL,
  period_start      DATETIME(3)  NOT NULL,
  period_end        DATETIME(3)  NOT NULL,
  order_commission  DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '下单佣金汇总',
  redeem_commission DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '核销佣金汇总',
  total_amount      DECIMAL(10,2) NOT NULL,
  status            VARCHAR(16)  NOT NULL DEFAULT 'DRAFT',
  confirmed_at      DATETIME(3)  DEFAULT NULL,
  paid_at           DATETIME(3)  DEFAULT NULL,
  created_at        DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_partner_bill_no (bill_no),
  KEY idx_partner_bill_partner_status (partner_id, status),
  CONSTRAINT fk_partner_bill_partner FOREIGN KEY (partner_id) REFERENCES partner_partner(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合伙人T+30账单';

-- ===================== HQ =============================

DROP TABLE IF EXISTS hq_account;
CREATE TABLE hq_account (
  id            BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  phone         VARCHAR(20)  NOT NULL,
  name          VARCHAR(64)  NOT NULL,
  admin_role    VARCHAR(32)  NOT NULL DEFAULT 'OPS',
  wx_open_id    VARCHAR(64)  DEFAULT NULL,
  wx_union_id   VARCHAR(64)  DEFAULT NULL,
  status        VARCHAR(16)  NOT NULL DEFAULT 'ACTIVE',
  last_login_at DATETIME(3)  DEFAULT NULL,
  created_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_hq_account_phone (phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='总部账号';

-- ===================== USER =============================

DROP TABLE IF EXISTS user_user;
CREATE TABLE user_user (
  id                BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  user_no           VARCHAR(20)  NOT NULL,
  phone             VARCHAR(20)  NOT NULL,
  wx_open_id        VARCHAR(64)  DEFAULT NULL,
  wx_union_id       VARCHAR(64)  DEFAULT NULL,
  nickname          VARCHAR(64)  DEFAULT NULL,
  avatar_resource_id BIGINT UNSIGNED DEFAULT NULL COMMENT '头像 common_resource.id',
  status            TINYINT      NOT NULL DEFAULT 1,
  source_type       VARCHAR(32)  NOT NULL DEFAULT 'ORGANIC' COMMENT 'ORGANIC|PROMO_CODE|SHARE_LINK|FRIEND_REFERRAL|OFFLINE_EVENT|OTHER',
  source_ref_id     BIGINT UNSIGNED DEFAULT NULL COMMENT 'promo_code_id 或 referrer_user_id',
  source_label      VARCHAR(128) DEFAULT NULL COMMENT '渠道名称快照',
  referrer_user_id  BIGINT UNSIGNED DEFAULT NULL COMMENT '好友推荐人 user_user.id',
  created_at        DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at        DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_user_user_phone (phone),
  UNIQUE KEY uk_user_user_no (user_no),
  KEY idx_user_user_source (source_type, source_ref_id),
  KEY idx_user_user_referrer (referrer_user_id),
  KEY idx_user_user_wx_open (wx_open_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='C端用户';

DROP TABLE IF EXISTS user_address;
CREATE TABLE user_address (
  id            BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  user_id       BIGINT UNSIGNED NOT NULL,
  receiver_name VARCHAR(32)  NOT NULL,
  phone         VARCHAR(20)  NOT NULL,
  province      VARCHAR(32)  NOT NULL,
  city          VARCHAR(32)  NOT NULL,
  district      VARCHAR(32)  NOT NULL,
  detail        VARCHAR(256) NOT NULL,
  latitude      DECIMAL(10,7) DEFAULT NULL,
  longitude     DECIMAL(10,7) DEFAULT NULL,
  is_default    TINYINT      NOT NULL DEFAULT 0,
  created_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  KEY idx_user_address_user (user_id),
  CONSTRAINT fk_user_address_user FOREIGN KEY (user_id) REFERENCES user_user(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户收货地址';

DROP TABLE IF EXISTS user_city_preference;
CREATE TABLE user_city_preference (
  id                 BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  user_id            BIGINT UNSIGNED NOT NULL,
  selected_city_code VARCHAR(16)  DEFAULT NULL,
  selected_district  VARCHAR(32)  DEFAULT NULL,
  locate_city_code   VARCHAR(16)  DEFAULT NULL,
  locate_district    VARCHAR(32)  DEFAULT NULL,
  updated_at         DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_user_city_preference_user (user_id),
  CONSTRAINT fk_user_city_preference_user FOREIGN KEY (user_id) REFERENCES user_user(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户城市偏好';

DROP TABLE IF EXISTS user_promo_attribution;
CREATE TABLE user_promo_attribution (
  id             BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  user_id        BIGINT UNSIGNED NOT NULL,
  promo_code_id  BIGINT UNSIGNED NOT NULL,
  channel_name   VARCHAR(128) NOT NULL,
  first_touch_at DATETIME(3)  NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY uk_user_promo_attribution_user (user_id),
  KEY idx_user_promo_attribution_promo (promo_code_id),
  CONSTRAINT fk_user_promo_attribution_user FOREIGN KEY (user_id) REFERENCES user_user(id) ON DELETE CASCADE,
  CONSTRAINT fk_user_promo_attribution_promo FOREIGN KEY (promo_code_id) REFERENCES common_promo_code(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='推广首次触达(统计)';

-- ===================== STORE =============================

DROP TABLE IF EXISTS store_store;
CREATE TABLE store_store (
  id                BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  city_id           BIGINT UNSIGNED NOT NULL,
  partner_id        BIGINT UNSIGNED NOT NULL,
  category_id       BIGINT UNSIGNED DEFAULT NULL,
  name              VARCHAR(128) NOT NULL,
  phone             VARCHAR(20)  NOT NULL,
  province          VARCHAR(32)  NOT NULL,
  city_name         VARCHAR(32)  NOT NULL COMMENT '市(冗余)',
  district          VARCHAR(32)  NOT NULL,
  address           VARCHAR(256) NOT NULL,
  latitude          DECIMAL(10,7) DEFAULT NULL,
  longitude         DECIMAL(10,7) DEFAULT NULL,
  intro             TEXT         DEFAULT NULL,
  cover_resource_id BIGINT UNSIGNED DEFAULT NULL COMMENT '门头图',
  avg_price         DECIMAL(10,2) DEFAULT NULL,
  rating            DECIMAL(3,2) DEFAULT NULL,
  tags              JSON         DEFAULT NULL,
  status            VARCHAR(16)  NOT NULL DEFAULT 'PAUSED',
  open_time         VARCHAR(8)   DEFAULT NULL,
  close_time        VARCHAR(8)   DEFAULT NULL,
  bank_account_name VARCHAR(64)  DEFAULT NULL,
  bank_account_no   VARCHAR(32)  DEFAULT NULL,
  bank_branch       VARCHAR(128) DEFAULT NULL,
  created_at        DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at        DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  KEY idx_store_store_city_status (city_id, status),
  KEY idx_store_store_partner (partner_id),
  CONSTRAINT fk_store_store_city FOREIGN KEY (city_id) REFERENCES common_city(id) ON DELETE RESTRICT,
  CONSTRAINT fk_store_store_partner FOREIGN KEY (partner_id) REFERENCES partner_partner(id) ON DELETE RESTRICT,
  CONSTRAINT fk_store_store_category FOREIGN KEY (category_id) REFERENCES common_store_category(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='餐饮门店';

DROP TABLE IF EXISTS store_account;
CREATE TABLE store_account (
  id            BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  store_id      BIGINT UNSIGNED NOT NULL,
  phone         VARCHAR(20)  NOT NULL,
  name          VARCHAR(64)  NOT NULL,
  wx_open_id    VARCHAR(64)  DEFAULT NULL,
  wx_union_id   VARCHAR(64)  DEFAULT NULL,
  status        VARCHAR(16)  NOT NULL DEFAULT 'ACTIVE',
  last_login_at DATETIME(3)  DEFAULT NULL,
  created_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_store_account_store (store_id),
  UNIQUE KEY uk_store_account_phone (phone),
  CONSTRAINT fk_store_account_store FOREIGN KEY (store_id) REFERENCES store_store(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='门店H5账号';

-- ===================== USER ORDER =============================

DROP TABLE IF EXISTS user_order_item;
DROP TABLE IF EXISTS user_order_delivery;
DROP TABLE IF EXISTS user_order;
CREATE TABLE user_order (
  id                  BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  order_no            VARCHAR(32)  NOT NULL,
  order_type          VARCHAR(16)  NOT NULL DEFAULT 'NORMAL' COMMENT 'NORMAL|RESHIPMENT',
  user_id             BIGINT UNSIGNED NOT NULL,
  city_id             BIGINT UNSIGNED NOT NULL,
  status              VARCHAR(32)  NOT NULL DEFAULT 'PENDING_PAY',
  pay_status          VARCHAR(16)  NOT NULL DEFAULT 'UNPAID' COMMENT 'UNPAID|PAYING|PAID|REFUNDING|REFUNDED',
  delivery_type       VARCHAR(16)  NOT NULL COMMENT 'LOCAL|CROSS_CITY',
  origin_order_id     BIGINT UNSIGNED DEFAULT NULL,
  promo_code_id       BIGINT UNSIGNED DEFAULT NULL,
  channel_source      VARCHAR(128) DEFAULT NULL,
  product_id          BIGINT UNSIGNED NOT NULL COMMENT '商品 common_product_item.id',
  barcode_69          VARCHAR(32)  NOT NULL COMMENT '69码快照',
  product_name        VARCHAR(128) NOT NULL COMMENT '商品名称快照',
  product_spec        VARCHAR(128) NOT NULL COMMENT '规格快照',
  image_resource_id   BIGINT UNSIGNED DEFAULT NULL COMMENT '商品图快照 common_resource.id',
  quantity            INT          NOT NULL COMMENT '购买数量',
  list_unit_price     DECIMAL(10,2) NOT NULL COMMENT '标价单价',
  list_amount         DECIMAL(10,2) NOT NULL COMMENT '标价总额',
  discount_amount     DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '优惠金额',
  product_amount      DECIMAL(10,2) NOT NULL COMMENT '商品应付',
  freight_amount      DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '运费',
  freight_pay_type    VARCHAR(8)   DEFAULT NULL COMMENT 'FREE|COD',
  pay_amount          DECIMAL(10,2) NOT NULL COMMENT '实付总额',
  benefit_amount      DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '本单发放权益',
  receiver_name       VARCHAR(32)  NOT NULL,
  receiver_phone      VARCHAR(20)  NOT NULL,
  receiver_address    TEXT         NOT NULL,
  receiver_province   VARCHAR(32)  NOT NULL,
  receiver_city       VARCHAR(32)  NOT NULL,
  receiver_district   VARCHAR(32)  NOT NULL,
  pay_external_no     VARCHAR(64)  DEFAULT NULL COMMENT '微信交易号(冗余)',
  paid_at             DATETIME(3)  DEFAULT NULL COMMENT '支付时间',
  shipped_at          DATETIME(3)  DEFAULT NULL COMMENT '发货时间(冗余=user_order_delivery.shipping_at)',
  completed_at        DATETIME(3)  DEFAULT NULL COMMENT '完成时间',
  cancelled_at        DATETIME(3)  DEFAULT NULL COMMENT '取消时间',
  pay_expire_at       DATETIME(3)  DEFAULT NULL COMMENT '待付款过期时间',
  remark              VARCHAR(512) DEFAULT NULL,
  created_at          DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at          DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_user_order_no (order_no),
  KEY idx_user_order_user_status (user_id, status),
  KEY idx_user_order_city_created (city_id, created_at),
  KEY idx_user_order_product (product_id),
  KEY idx_user_order_barcode (barcode_69),
  KEY idx_user_order_pay_external (pay_external_no),
  CONSTRAINT fk_user_order_user FOREIGN KEY (user_id) REFERENCES user_user(id) ON DELETE RESTRICT,
  CONSTRAINT fk_user_order_city FOREIGN KEY (city_id) REFERENCES common_city(id) ON DELETE RESTRICT,
  CONSTRAINT fk_user_order_origin FOREIGN KEY (origin_order_id) REFERENCES user_order(id) ON DELETE SET NULL,
  CONSTRAINT fk_user_order_promo FOREIGN KEY (promo_code_id) REFERENCES common_promo_code(id) ON DELETE SET NULL,
  CONSTRAINT fk_user_order_product FOREIGN KEY (product_id) REFERENCES common_product_item(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单(含商品快照,V1单SKU)';

DROP TABLE IF EXISTS user_order_delivery;
CREATE TABLE user_order_delivery (
  id                   BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  order_id             BIGINT UNSIGNED NOT NULL,
  provider             VARCHAR(16)  NOT NULL COMMENT 'XFX|LOGISTICS|MANUAL',
  provider_order_no    VARCHAR(64)  DEFAULT NULL,
  tracking_no          VARCHAR(64)  DEFAULT NULL,
  out_warehouse_at     DATETIME(3)  DEFAULT NULL,
  shipping_at          DATETIME(3)  DEFAULT NULL,
  delivered_at         DATETIME(3)  DEFAULT NULL,
  sign_photo_resource_id BIGINT UNSIGNED DEFAULT NULL COMMENT '签收照片 common_resource.id',
  updated_at           DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_user_order_delivery_order (order_id),
  CONSTRAINT fk_user_order_delivery_order FOREIGN KEY (order_id) REFERENCES user_order(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单配送(与user_order 1:1)';

-- ===================== BENEFIT & REDEEM =============================

DROP TABLE IF EXISTS user_benefit_coupon;
CREATE TABLE user_benefit_coupon (
  id             BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  coupon_no      VARCHAR(32)  NOT NULL,
  user_id        BIGINT UNSIGNED NOT NULL,
  order_id       BIGINT UNSIGNED NOT NULL,
  total_amount   DECIMAL(10,2) NOT NULL,
  used_amount    DECIMAL(10,2) NOT NULL DEFAULT 0.00,
  balance        DECIMAL(10,2) NOT NULL,
  status         VARCHAR(16)  NOT NULL DEFAULT 'ACTIVE',
  source_product VARCHAR(128) NOT NULL,
  version        INT          NOT NULL DEFAULT 0 COMMENT '乐观锁',
  created_at     DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  updated_at     DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_user_benefit_coupon_no (coupon_no),
  KEY idx_user_benefit_coupon_user (user_id, status),
  CONSTRAINT fk_user_benefit_coupon_user FOREIGN KEY (user_id) REFERENCES user_user(id) ON DELETE RESTRICT,
  CONSTRAINT fk_user_benefit_coupon_order FOREIGN KEY (order_id) REFERENCES user_order(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='好客权益券';

DROP TABLE IF EXISTS user_redeem_record;
CREATE TABLE user_redeem_record (
  id            BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  redeem_no     VARCHAR(32)  NOT NULL,
  user_id       BIGINT UNSIGNED NOT NULL,
  coupon_id     BIGINT UNSIGNED NOT NULL,
  store_id      BIGINT UNSIGNED NOT NULL,
  amount        DECIMAL(10,2) NOT NULL,
  settle_amount DECIMAL(10,2) NOT NULL,
  created_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_user_redeem_record_no (redeem_no),
  KEY idx_user_redeem_record_store (store_id, created_at),
  CONSTRAINT fk_user_redeem_record_user FOREIGN KEY (user_id) REFERENCES user_user(id) ON DELETE RESTRICT,
  CONSTRAINT fk_user_redeem_record_coupon FOREIGN KEY (coupon_id) REFERENCES user_benefit_coupon(id) ON DELETE RESTRICT,
  CONSTRAINT fk_user_redeem_record_store FOREIGN KEY (store_id) REFERENCES store_store(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='核销记录';

DROP TABLE IF EXISTS user_store_rating;
CREATE TABLE user_store_rating (
  id               BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  redeem_record_id BIGINT UNSIGNED NOT NULL,
  store_id         BIGINT UNSIGNED NOT NULL,
  service_score    TINYINT      NOT NULL,
  env_score        TINYINT      NOT NULL,
  created_at       DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_user_store_rating_redeem (redeem_record_id),
  CONSTRAINT fk_user_store_rating_redeem FOREIGN KEY (redeem_record_id) REFERENCES user_redeem_record(id) ON DELETE CASCADE,
  CONSTRAINT fk_user_store_rating_store FOREIGN KEY (store_id) REFERENCES store_store(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='核销评价';

DROP TABLE IF EXISTS store_payout;
CREATE TABLE store_payout (
  id               BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  redeem_record_id BIGINT UNSIGNED NOT NULL,
  store_id         BIGINT UNSIGNED NOT NULL,
  redeem_amount    DECIMAL(10,2) NOT NULL,
  payout_amount    DECIMAL(10,2) NOT NULL,
  settlement_rate  DECIMAL(5,4) NOT NULL,
  status           VARCHAR(16)  NOT NULL DEFAULT 'PENDING',
  expected_pay_at  DATETIME(3)  NOT NULL,
  paid_at          DATETIME(3)  DEFAULT NULL,
  batch_no         VARCHAR(32)  DEFAULT NULL,
  created_at       DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  UNIQUE KEY uk_store_payout_redeem (redeem_record_id),
  KEY idx_store_payout_store_status (store_id, status),
  CONSTRAINT fk_store_payout_redeem FOREIGN KEY (redeem_record_id) REFERENCES user_redeem_record(id) ON DELETE RESTRICT,
  CONSTRAINT fk_store_payout_store FOREIGN KEY (store_id) REFERENCES store_store(id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='门店T+1打款';

-- ===================== LOG =============================

DROP TABLE IF EXISTS log_third_party;
CREATE TABLE log_third_party (
  id             BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  provider       VARCHAR(32)  NOT NULL COMMENT 'WECHAT_PAY|WECHAT_REFUND|WECHAT_AUTH|WECHAT_MAP|XFX|SMS|LOGISTICS',
  scene          VARCHAR(64)  NOT NULL COMMENT '业务场景',
  ref_type       VARCHAR(32)  DEFAULT NULL COMMENT 'ORDER|USER|STORE|...',
  ref_id         BIGINT UNSIGNED DEFAULT NULL,
  request_url    VARCHAR(512) DEFAULT NULL,
  request_body   JSON         DEFAULT NULL COMMENT '发送参数',
  response_body  JSON         DEFAULT NULL COMMENT '响应数据',
  external_no    VARCHAR(128) DEFAULT NULL COMMENT '第三方单号',
  amount         DECIMAL(10,2) DEFAULT NULL,
  status         VARCHAR(16)  NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING|SUCCESS|FAILED',
  error_message  VARCHAR(512) DEFAULT NULL,
  created_at     DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  KEY idx_log_third_party_ref (ref_type, ref_id),
  KEY idx_log_third_party_provider_scene (provider, scene, created_at),
  KEY idx_log_third_party_external (external_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='第三方交互记录';

DROP TABLE IF EXISTS log_user_analytics;
CREATE TABLE log_user_analytics (
  id              BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  user_id         BIGINT UNSIGNED DEFAULT NULL COMMENT '未登录可为NULL',
  session_id      VARCHAR(64)  DEFAULT NULL COMMENT '会话ID',
  event_name      VARCHAR(64)  NOT NULL COMMENT '见§4.1 event_name 清单',
  client_app      VARCHAR(32)  DEFAULT NULL COMMENT 'USER_MINI|PARTNER_MINI|HQ_MINI|SHOP_H5',
  page_path       VARCHAR(128) DEFAULT NULL COMMENT '页面路径',
  ref_type        VARCHAR(32)  DEFAULT NULL COMMENT 'PRODUCT|STORE|ORDER|TAB|ADDRESS|PROMO|...',
  ref_id          BIGINT UNSIGNED DEFAULT NULL,
  keyword         VARCHAR(128) DEFAULT NULL COMMENT '搜索关键词',
  source_type     VARCHAR(32)  DEFAULT NULL COMMENT 'register事件:来源类型快照',
  source_ref_id   BIGINT UNSIGNED DEFAULT NULL COMMENT 'register事件:来源ID',
  extra_json      JSON         DEFAULT NULL COMMENT 'PRD埋点参数',
  created_at      DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id),
  KEY idx_log_user_analytics_user_created (user_id, created_at),
  KEY idx_log_user_analytics_event_created (event_name, created_at),
  KEY idx_log_user_analytics_session (session_id),
  KEY idx_log_user_analytics_ref (ref_type, ref_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户行为埋点日志';

SET FOREIGN_KEY_CHECKS = 1;

§六、API 列表 v3.1

1. 通用约定

1.1 请求头

Header 说明
Authorization Bearer <access_token>(除公开接口与回调)
X-Client-App USER_MINI / PARTNER_MINI / HQ_MINI / SHOP_H5
X-Request-Id 可选,链路追踪

1.2 响应格式

{
  "code": 0,
  "message": "ok",
  "data": {}
}

1.3 分页参数

page(从 1)、pageSize(默认 20,最大 100)→ data: { list, total, page, pageSize }

1.4 鉴权角色

Guard 适用端 数据表
UserAuth C端 user_user
StoreAuth 门店 H5 store_account
PartnerAuth 合伙人(含子账号) partner_account
PartnerPrimaryAuth 仅主账号(账单确认、提现) partner_accountis_primary=1
AdminAuth 总部 hq_account
Public 无需登录
WxCallback 微信/配送回调验签

1.5 JWT Payload(四端统一)

{
  "sub": "12345",
  "actorType": "USER",
  "actorId": "12345",
  "clientApp": "USER_MINI"
}
actorType 含义 actorId 指向
USER C端消费者 user_user.id
STORE 门店登录账号 store_account.id
PARTNER 合伙人/子账号 partner_account.id
HQ 总部管理员 hq_account.id

鉴权时须同时校验 clientAppactorType 一致,禁止仅用数字 ID 跨表匹配。


2. 认证 Auth

2.1 通用接口

方法 路径 鉴权 说明 PRD
POST /auth/sms/send Public 发送短信验证码 { phone, scene } §3.1
POST /auth/refresh Public 刷新 Token
POST /auth/logout * 退出,失效 refresh §3.9
GET /auth/me * 当前登录身份摘要(按 actorType 返回不同结构)

scene 枚举USER_LOGIN / STORE_LOGIN / PARTNER_LOGIN / HQ_LOGIN / BIND_PHONE / PARTNER_STAFF_ADD

2.2 C端(clientApp: USER_MINIuser_user

方法 路径 鉴权 说明 PRD
POST /auth/login/sms Public 手机号登录 { phone, code } → 查/建 user_user §3.1
POST /auth/login/wechat Public 微信登录 { code } → 换 openId已绑定 phone 则直接登录,否则返回 needBindPhone: true §3.1
POST /auth/wechat/bind-phone Public 微信首登补绑手机 { wxSessionKey, phone, code } → 写 user_user.phone + wx_open_id U4

POST /auth/login/sms 响应要点

{
  "accessToken": "",
  "refreshToken": "",
  "actorType": "USER",
  "actorId": "10001",
  "user": {
    "id": "10001",
    "userNo": "DK88293401",
    "phone": "138****8888",
    "nickname": "",
    "hasWechat": true
  }
}

2.3 门店端(clientApp: SHOP_H5store_account

方法 路径 鉴权 说明 PRD
POST /shop/auth/login/sms Public { phone, code } → 查 store_account §4.1
POST /shop/auth/login/wechat Public { code } → 写辅助 openId 后仍须匹配 store_accounts.phone §4.1

响应 actorTypeSTORE;附带 storeIdstoreName

2.4 合伙人端(clientApp: PARTNER_MINIpartner_account

方法 路径 鉴权 说明 PRD
POST /partner/auth/login/sms Public { phone, code } → 查 partner_account §5.1
POST /partner/auth/login/wechat Public 微信登录(30 天免登) §5.1

响应 actorTypePARTNER;附带 partnerIdisPrimarystaffRole

2.5 总部端(clientApp: HQ_MINIhq_account

方法 路径 鉴权 说明 PRD
POST /admin/auth/login/sms Public { phone, code } → 查 hq_account §6
POST /admin/auth/login/wechat Public 微信登录 §6

响应 actorTypeHQ;附带 adminRoleSUPER_ADMIN / OPS / FINANCE / CUSTOMER_SERVICE)。

2.6 身份校验错误码

code 说明
PHONE_REQUIRED C 端微信首登未绑定手机
PHONE_ALREADY_USED 手机号已被同端其他账号占用
ACCOUNT_DISABLED B 端账号 status=DISABLED
ACTOR_TYPE_MISMATCH Token actorType 与接口 Guard 不匹配
NOT_PRIMARY_ACCOUNT 非合伙人主账号调用 PartnerPrimaryAuth 接口

3. C端用户 APIUserAuth

3.1 用户与城市

方法 路径 说明 PRD
GET /user/profile 个人中心信息 §3.9
PUT /user/profile 更新昵称/头像 §3.9
GET /user/city 获取选城/定位偏好 §3.1
PUT /user/city 更新选城 { cityCode, district } §3.1
POST /user/location 上报定位 { lat, lng, city, district } §3.1

3.2 地址

方法 路径 说明 PRD
GET /user/addresses 地址列表 §3.4
POST /user/addresses 新增地址 §3.4
PUT /user/addresses/:id 编辑地址 §3.4
DELETE /user/addresses/:id 删除地址 §3.4
PUT /user/addresses/:id/default 设为默认 §3.4

3.3 商品与开城(Public / 部分需登录)

方法 路径 鉴权 说明 PRD
GET /catalog/cities/open Public 已开城列表(V1 郑州) §1.4
GET /catalog/products Public 商品列表 ?aromaType=&cityCode= §3.2
GET /catalog/products/:id Public 商品详情(含 benefitAmount §3.2

3.4 订单交易

方法 路径 说明 PRD
POST /trade/orders/preview 下单预览:配送方式、起购、运费、权益 §3.3
POST /trade/orders 创建订单(锁单) §3.3
POST /trade/orders/:id/pay 发起微信支付,返回 prepay 参数 §3.3.4
GET /trade/orders 订单列表 ?tab=all|pending_pay|pending_ship|pending_receive|completed §3.5.1
GET /trade/orders/:id 订单详情(进度、权益入口) §3.5.3
PUT /trade/orders/:id/address 修改收货地址(触发拦截) §3.5.4
POST /trade/orders/:id/cancel 取消待付款订单 §3.5
POST /trade/orders/:id/confirm-receive 确认收货 §3.5.3
GET /trade/orders/counts 各 Tab 数量(个人中心角标) §3.9

POST /trade/orders/preview 请求

{
  "productId": "",
  "quantity": 2,
  "addressId": ""
}

响应要点deliveryType, freightAmount, freightPayType, benefitAmount, minQty, crossCityWarning

3.5 好客权益

方法 路径 说明 PRD
GET /benefit/summary 权益余额汇总 §3.8.1
GET /benefit/coupons 券列表 ?status=active|used §3.8.1
GET /benefit/coupons/:id 券详情 §3.8
GET /benefit/ledgers 权益明细(获取+消费) §3.8.2

3.6 核销

方法 路径 说明 PRD
POST /redeem/token 生成核销码 { couponId, storeId, amount } §3.8.3
POST /redeem/token/:token/refresh 刷新核销码(作废旧码) §3.8.3
GET /redeem/token/:token 轮询码状态(可选) §3.8.3
POST /redeem/rating 核销评价 { redeemRecordId, serviceScore, envScore } §3.8.3

3.7 门店(C端浏览)

方法 路径 鉴权 说明 PRD
GET /stores Public 门店列表(仅 OPEN?cityCode=&category=&keyword=&lat=&lng= §3.7
GET /stores/:id Public 门店详情 §3.7.2
GET /stores/categories Public 分类列表 §3.7

3.8 推广与埋点

方法 路径 鉴权 说明 PRD
POST /promo/touch UserAuth 扫码归因 { promoCode }(首次写入) §3.10.1
POST /log/analytics/batch UserAuth / Public 批量埋点 { events:[] } §3.10.2

4. 门店端 APIStoreAuth

登录见 §2.3。Token 中 actorType=STOREactorIdstore_account.id

方法 路径 说明 PRD
GET /shop/dashboard 首页:今日笔数/金额、营业状态 §4.2
GET /shop/store 门店信息(只读) §4.5
PUT /shop/store/status 切换营业 { status: OPEN|PAUSED } §4.2
POST /shop/redeem/scan 扫码解析 { token } → 确认页数据 §4.3
POST /shop/redeem/confirm 确认核销 { token } §4.3
GET /shop/redeem/records 核销记录 ?range=today|7d|30d&status= §4.4
GET /shop/redeem/records/summary 期间汇总(核销额/到账额/60% §4.4
GET /shop/redeem/records/:id 单笔详情 §4.4

POST /shop/redeem/scan 响应(确认页)

{
  "storeName": "",
  "userPhoneMasked": "138****9021",
  "amount": 100.00,
  "couponNo": "DK202310248892",
  "couponValidity": "永久",
  "tokenExpireAt": ""
}

5. 城市合伙人 APIPartnerAuth

登录见 §2.4。Token 中 actorType=PARTNERactorIdpartner_account.id

5.1 工作台

方法 路径 说明 PRD
GET /partner/dashboard 营业额、利润、门店数、今日订单 §5.2
GET /partner/dashboard/leaderboard 贡献榜 §5.2, §5.9
GET /partner/reports/weekly 经营周报 ?startDate= §5.8

5.2 门店管理

方法 路径 说明 PRD
GET /partner/stores 门店列表 ?status=&keyword= §5.3
GET /partner/stores/:id 门店详情 §5.3
POST /partner/stores 录入门店(步骤1 基本信息) §5.3.2
PUT /partner/stores/:id/basic 更新基本信息 §5.3
POST /partner/stores/:id/media 上传照片/合同(步骤2 §5.3.2
PUT /partner/stores/:id/settlement 结算银行卡(步骤3 §5.3.2
POST /partner/stores/:id/submit-audit 提交审核 §5.3.2
PUT /partner/stores/:id/status 变更状态 { status: PAUSED|CLOSED|OPEN } §5.3
GET /partner/store-audits 审核记录 §5.3.3

5.3 订单

方法 路径 说明 PRD
GET /partner/orders 订单列表 ?range=&status=&keyword= §5.4
GET /partner/orders/:id 订单详情(佣金、渠道) §5.4
GET /partner/benefit/overview 权益发放/待核销统计 §5.4
GET /partner/benefit/records 已核销权益明细 §5.4

5.4 补发与拦截

方法 路径 说明 PRD
GET /partner/after-sales/reshipments 补发待处理列表 §5.5
POST /partner/after-sales/reshipments/:id/confirm-ship 开始配送 §5.5
POST /partner/after-sales/reshipments/:id/confirm-delivered 手动确认送达 §5.5
GET /partner/intercepts 拦截列表 §5.6
GET /partner/intercepts/:id 拦截详情 §5.6
POST /partner/intercepts/:id/start 发起拦截 §5.6
POST /partner/intercepts/:id/confirm-success 确认拦截成功 §5.6

5.5 财务

方法 路径 鉴权 说明 PRD
GET /partner/settlement/summary 待结算/已结算/本月预估 §5.7
GET /partner/settlement/bills 账单列表 §5.7
GET /partner/settlement/bills/:id 账单详情(拆分佣金) §5.7
POST /partner/settlement/bills/:id/confirm 确认账单 §5.7
PartnerPrimary
GET /partner/assets 资产明细 §5.10
POST /partner/withdrawals 申请提现 §5.10
GET /partner/contracts 合同列表 §5.10

5.6 子账号(partner_account 表)

方法 路径 说明 PRD
GET /partner/staff 员工/子账号列表(parent_account_id 指向主账号) §5.9
POST /partner/staff 添加子账号 { phone, name, staffRole, code } §5.9
PUT /partner/staff/:id 编辑/启用/禁用 §5.9
DELETE /partner/staff/:id 删除子账号 §5.9

:idpartner_account.id。主账号 is_primary=1,子账号须设 staffRolePARTNER / INTERNAL / PROMOTER)。


6. 总部管理 APIAdminAuth

登录见 §2.5。Token 中 actorType=HQactorIdhq_account.id
门店审核、退款审核、售后工单、操作审计均关联 hq_account.id

6.0 总部账号(hq_account 表,SUPER_ADMIN 可管)

方法 路径 鉴权 说明
GET /admin/hq-accounts AdminAuth 总部账号列表
POST /admin/hq-accounts SUPER_ADMIN 创建账号 { phone, name, adminRole }
PUT /admin/hq-accounts/:id SUPER_ADMIN 编辑/启用/禁用
GET /admin/hq-accounts/me AdminAuth 当前总部账号信息

6.1 首页与预警

方法 路径 说明 PRD
GET /admin/dashboard 今日概况 §6.1
GET /admin/alerts 预警列表 §6.1, §6.10
GET /admin/alerts/:id 预警详情 §6.10
PUT /admin/alerts/:id/resolve 标记已处理 §6.10

6.2 开城

方法 路径 说明 PRD
GET /admin/cities 开城列表 §6.2
POST /admin/cities 新增城市 §6.2
GET /admin/cities/:id 城市详情 §6.2
PUT /admin/cities/:id 编辑城市 §6.2
PUT /admin/cities/:id/status 暂停/恢复 §6.2
PUT /admin/cities/:id/commission 配置佣金比例 §6.2
POST /admin/partners 创建合伙人主体 §6.2

6.3 商品

方法 路径 说明 PRD
GET /admin/products 商品列表 §6.3
POST /admin/products 新增商品 §6.3
GET /admin/products/:id 商品详情 §6.3
PUT /admin/products/:id 编辑(含 benefitAmount §6.3
PUT /admin/products/:id/status 上下架 §6.3

6.4 订单中心

方法 路径 说明 PRD
GET /admin/orders 订单列表/搜索 §6.4
GET /admin/orders/search-suggest 搜索建议 §6.4
GET /admin/orders/:id 订单详情 §6.4
PUT /admin/orders/:id/status 手动改状态(异常处理) §6.4
POST /admin/orders/:id/ship 跨城发货/录入运单 §6.4
GET /admin/orders/:id/commissions 佣金拆分 §6.4

6.5 门店审核

方法 路径 说明 PRD
GET /admin/store-audits 审核列表 ?status= §6.5
GET /admin/store-audits/:id 审核详情 §6.5
PUT /admin/store-audits/:id/approve 通过 §6.5
PUT /admin/store-audits/:id/reject 驳回 { reason } §6.5
PUT /admin/stores/:id 总部编辑门店 §6.5

6.6 推广码

方法 路径 说明 PRD
GET /admin/promo-codes 推广码列表 §6.6
POST /admin/promo-codes 创建(生成小程序码) §6.6
PUT /admin/promo-codes/:id/status 启用/禁用 §6.6
GET /admin/promo-codes/:id/stats 扫码/转化统计 §6.6

6.7 结算中心

方法 路径 说明 PRD
GET /admin/settlement/summary 待结算总额等 §6.7
GET /admin/settlement/partner-bills 合伙人待处理账单 §6.7
POST /admin/settlement/partner-bills 发起账期账单 §6.7
POST /admin/settlement/partner-bills/:id/send 发送账单通知 §6.7
POST /admin/settlement/partner-bills/:id/confirm-paid 确认打款 §6.7
GET /admin/settlement/store-payouts 门店待打款列表 §6.7
POST /admin/settlement/store-payouts/batch-pay T+1 批量打款 §6.7
GET /admin/settlement/withdrawals 提现审核列表 §5.10
PUT /admin/settlement/withdrawals/:id/approve 提现审核 §5.10

6.8 客服 · 售后

方法 路径 说明 PRD
GET /admin/after-sales 工单列表 ?type=refund|reshipment&status= §6.8
GET /admin/after-sales/:id 工单详情 §6.8
POST /admin/after-sales/refunds 创建退款 { orderId, amount, reason } §3.6.2
PUT /admin/after-sales/refunds/:id/approve 审核通过并发起微信退款 §3.6.2
PUT /admin/after-sales/refunds/:id/reject 驳回 §3.6.2
POST /admin/after-sales/reshipments 创建补发 { orderId, reason } §3.6
GET /admin/after-sales/reshipments/:id 补发详情/进度 §6.8

6.9 数据报表

方法 路径 说明 PRD
GET /admin/reports/overview 报表中心概览 §6.9
GET /admin/reports/gmv GMV 趋势 §6.9
GET /admin/reports/channels 推广渠道转化 §3.10
GET /admin/reports/events 埋点统计 §3.10.2

6.10 通用

方法 路径 说明
POST /admin/upload 图片/文件上传 OSS
GET /admin/operation-logs 操作审计(common_event(HQ_OPERATION)

7. 回调接口(验签,无 JWT

方法 路径 说明 PRD
POST /callbacks/wechat/pay 支付结果通知 §3.3.4
POST /callbacks/wechat/refund 退款结果通知 §3.6.2
POST /callbacks/xfx/delivery 小飞侠配送状态 §7.1
POST /callbacks/logistics/tracking 跨城物流状态 §2.3

8. API 统计

接口数(约)
认证(四端分拆) 11
C端 28
门店 8
合伙人 32
总部 49
回调 4
合计 ~132

9. 业务场景 → API 快速索引

场景 关键 API
C端手机登录(phone 唯一) POST /auth/login/smsuser_user
C端微信首登绑手机 POST /auth/login/wechatPOST /auth/wechat/bind-phone
门店 H5 登录 POST /shop/auth/login/smsstore_account
合伙人/子账号登录 POST /partner/auth/login/smspartner_account
总部登录 POST /admin/auth/login/smshq_account
JWT 四端隔离 actorType + actorId,见 §1.5
同城2瓶/跨城6瓶 POST /trade/orders/preview
跨城到付 preview 返回 crossCityWarning + create
支付发券 回调 → 内部服务;GET /benefit/coupons
订单5 Tab GET /trade/orders?tab=pending_ship
改址拦截 PUT /trade/orders/:id/addresscommon_ticket+改址流程
核销¥500上限 POST /redeem/token 校验
门店隐藏暂停 GET /stores 过滤
门店T+1 GET /shop/redeem/records + 总部 batch-pay
合伙人T+30 /partner/settlement/bills/*
退款 /admin/after-sales/refunds/*
补发 /admin/after-sales/reshipments + partner confirm
推广归因 POST /promo/touch + 下单写 channel
埋点17事件 POST /analytics/events


§七、开发计划与任务卡

杜康好客 · V1 开发计划(可执行版)

版本v2.0
日期2026-06-27
状态Agent / 人工编码事实源
目标上线:郑州开城、4 SKU、四端闭环(日历 10~12 周,按团队调整)


0. 文档权威与 Agent 使用说明

0.1 阅读优先级(冲突时)

优先级 文档 用途
1 本手册 §二 做什么(业务规则、状态、边界)
2 conventions.md 怎么协作(模块边界、提交、契约)
3 本手册 §四 怎么架构NestJS 模块、依赖规则)
4 本手册 §五 表结构Prisma / SQL 事实源 v2.1
5 本手册 §六 接口契约v1.1,含四端 JWT
6 pages/{user,shop,partner,hq}/ UI 参照(字段、布局、跳转)
7 doc/原型说明.md 原型与 PRD 差异(如 user/9 待发货 Tab

0.2 Cursor Agent 编码流程

  1. 绑定 Skill:实现代码时启用 .cursor/skills/dukang-coding(或用户 @dukang-coding
  2. 领取任务:从本文 附录 A 取任务卡 ID(如 M2-FE-U-003),一次只做一个任务卡
  3. 读文档:按任务卡上的 PRD §、API 路径、DB 表、原型路径逐项对照
  4. 写代码:遵守 conventions.md §2 模块边界;DTO/枚举进 packages/shared-types
  5. 自验:完成任务卡「验收标准」;跨模块改动同步 API 文档
  6. 提交Conventional Commitsscope = 端或模块(feat(trade)

0.3 技术栈(锁定)

选型
前端 Taro 3 + React + TypeScriptMonorepo 四 App
后端 Node 20 + NestJS 10 + Prisma 5 + MySQL 8 + Redis 7 + BullMQ
协作 方案三:一个 dukang-api,模块 OWNER,禁止跨模块直写表

0.4 仓库目标结构(M0 必须落地)

dukang/
├── apps/
│   ├── mini-user/          # C端
│   ├── mini-partner/       # 合伙人
│   ├── mini-hq/            # 总部
│   └── h5-shop/            # 门店 H5
├── packages/
│   ├── shared-types/       # DTO、枚举、错误码、JWT Payload
│   ├── shared-utils/
│   ├── shared-ui/
│   └── domain/             # 纯函数:起购、权益额、核销上限
├── server/
│   └── dukang-api/
│       ├── prisma/schema.prisma   # 已 v2.1
│       └── src/
│           ├── common/
│           ├── modules/{iam,catalog,trade,benefit,store,redeem,settlement,ops,notify,analytics}
│           ├── callbacks/
│           └── jobs/
├── pages/                  # 原型图(只读参照)
├── doc/
└── conventions.md

1. 团队与 OWNER 分工

OWNER 前端 App 后端 Module 主责里程碑
A mini-user iam, trade, benefit, analytics M1~M2, M6
B mini-partner store M1, M4
C mini-hq catalog, settlement, ops M1, M4~M6
D h5-shop redeem M3
Lead packages/* callbacks, jobs, common M0, 横切 CI

跨模块 PR:相关双 OWNER Review(技术方案 §2.4.4 R1~R3)。


2. 里程碑总览

里程碑 周次 核心交付 出口标准
M0 第 0~1 周 Monorepo + 骨架 + 环境 pnpm dev 四端可启,API /health
M1 第 1~2 周 IAM 四端、开城、商品 总部配郑州+4 SKU;四端可登录
M2 第 3~4 周 C端购酒支付履约 同城2瓶/跨城6瓶;支付发券;5 Tab 订单
M3 第 5~6 周 权益+核销+门店 H5 端到端核销;门店短信
M4 第 7~8 周 拓店审核、补发退款拦截 合伙人录店→总部审→C端可见
M5 第 9 周 T+1 门店 / T+30 合伙人 结算状态正确
M6 第 10 周 推广码、埋点、报表 渠道可归因
上线 第 11~12 周 UAT、提审、试运行 郑州试运行
gantt
    title 杜康好客 V1(示意)
    dateFormat YYYY-MM-DD
    section 基础
    M0 仓库骨架           :m0, 2026-07-01, 7d
    M1 IAM开城商品        :m1, after m0, 10d
    section 核心
    M2 交易               :m2, after m1, 14d
    M3 权益核销           :m3, after m2, 14d
    section 运营
    M4 拓店售后           :m4, after m3, 14d
    M5 结算               :m5, after m4, 10d
    M6 增长               :m6, after m5, 7d
    section 上线
    UAT上线               :launch, after m6, 14d

3. M0 仓库初始化(第 0~1 周)

阻塞一切后续任务。任务卡见附录 A M0-*

类别 交付
根目录 pnpm-workspace.yamlpackage.json、ESLint/Prettier、.env.example
packages shared-typesActorType、OrderStatus、错误码)、domain(起购/权益/核销纯函数)
server NestJS 启动、PrismaModuleGlobalExceptionFilter、统一 {code,message,data}
apps 四端 Taro 脚手架、request.ts(带 X-Client-App)、登录态存储
deploy docker-compose.ymlMySQL + Redis)、prisma migrate 或执行 数据库设计2 §5 SQL
CI lint + prisma validate + domain 单元测试

M0 出口GET /api/v1/health 200npx prisma validate 通过;四端空白页 + 登录页壳可编译。


4. 分里程碑交付说明

M1 基础(IAM + 开城 + 商品)

PRD:§3.1 登录、§6.2 开城、§6.3 商品
DBusersstore_accountspartner_accountshq_accountscitiesproductswx_app_configs
API:§2 四端认证、/catalog/*/admin/cities/admin/products/admin/hq-accounts

页面(原型) 关键能力
mini-hq hq/12, 69, 12~14 总部登录、开城、商品 CRUD
mini-user user/1, 2 C端登录、首页骨架
mini-partner partner/1~2 合伙人登录壳
h5-shop shop/1~2 门店登录壳

M2 交易(C端主链路)

PRD:§3.2~§3.6
DBordersorder_itemspaymentsuser_addressesbenefit_couponsbenefit_ledgers
API/trade/orders/*/user/addressescallbacks/wechat/pay

页面 关键能力
mini-user user/3~12, 9 含待发货 Tab 详情、下单、支付、5 Tab 订单、改址

业务验收:同城 1 瓶拒单、2 瓶成功;跨城 5 瓶拒单、6 瓶成功;支付成功发券。

M3 权益与核销

PRD:§3.7~§3.8、§4
DBredeem_tokensredeem_recordsstore_ratingsstore_payouts(创建待打款)
API/benefit/*/redeem/*/stores/shop/redeem/*

页面 关键能力
mini-user user/1522, 1718 门店列表、权益、核销码、评价
h5-shop shop/3~7 扫码、确认核销、记录

业务验收:核销 ¥501 拒单;码 5 分钟失效;暂停门店 C 端不可见。

M4 运营(拓店 + 售后)

PRD:§5.3~§5.6、§6.5、§6.8
DBstoresstore_mediastore_auditsafter_sale_ticketsrefundsdelivery_intercepts
API/partner/stores/*/admin/store-audits/*/admin/after-sales/*/partner/intercepts/*

M5 结算

PRD:§4.4、§5.7、§6.7
DBstore_payoutspartner_billsorder_commissionspartner_withdrawals
API/admin/settlement/*/partner/settlement/*/shop/redeem/records

M6 增长

PRD:§3.10
DBpromo_codesuser_promo_attributionsevent_logs
API/promo/touch/analytics/events/admin/promo-codes/admin/reports/*


5. 编码规范速链

  • 模块禁止跨表:见 conventions.md §2、技术方案 §2.5
  • JWTactorType + actorId,见 API列表 §1.5
  • C 端用户:users.phone 唯一必填;B 端三表分离
  • 金额:Decimal(10,2);权益发放 benefitAmount ?? price
  • 核销:Redis Token 5min + benefit_coupons.version 乐观锁
  • 订单 Taball|pending_pay|pending_ship|pending_receive|completed

6. 测试策略

类型 范围
单元 packages/domain:起购、权益额、核销上限 ¥500
集成 支付回调、核销事务、退款权益 VOID
E2E 购酒→发券→核销→门店 payout PENDING
里程碑末 全量冒烟 + 附录 A 任务卡验收勾选

必测 8 条(与 v1.2 相同):起购、跨城到付、发券金额、核销上限、闭店隐藏、待发货 Tab、退款作废、T+1 状态。


7. 前置依赖

最迟
微信商户号、三小程序 AppId M1
pages/user/9 改稿(待发货 Tab M2
郑州 4 SKU 素材 M1
小飞侠 API(可 Mock M2
短信模板 M3

8. 人天估算(不变)

176 人天8 人团队 10~12 周(见 v1.2 §4)。


附录 A · 编码任务卡

Agent一次只领取一张卡;完成后在 PR 描述写 Closes Mx-XX-XXX

M0 基础设施

ID OWNER 任务 主要路径 PRD API/DB 验收
M0-INFRA-001 Lead pnpm workspace + 根脚本 /package.json, pnpm-workspace.yaml pnpm -r list 四 apps + server
M0-INFRA-002 Lead packages/shared-types 枚举与 JWT packages/shared-types/src/ API §1.5 导出 ActorType、OrderStatus、ApiResponse
M0-INFRA-003 Lead packages/domain 纯函数 + 测试 packages/domain/ PRD §2.1, §2.3 起购/权益/¥500 单测通过
M0-BE-001 Lead NestJS 骨架 + health server/dukang-api/src/main.ts 技术方案 §2.3 GET /health
M0-BE-002 Lead PrismaModule + migrate server/dukang-api/prisma/ 数据库设计2 §5 全表 prisma validate
M0-BE-003 Lead 统一响应/异常 Filter server/dukang-api/src/common/ API §1.2 {code,message,data}
M0-FE-001 A~D 四端 Taro init apps/*/ 各端 dev 编译通过
M0-FE-002 A mini-user request + auth 存储 apps/mini-user/src/services/ API §1.1 可带 X-Client-App
M0-DEV-001 Lead docker-compose MySQL+Redis deploy/docker-compose.yml 本地 DB 可连

M1 IAM + 开城 + 商品

ID OWNER 任务 主要路径 PRD API/DB 验收
M1-BE-IAM-001 A 短信发送 modules/iam/ §3.1 POST /auth/sms/send, sms_logs scene 分端
M1-BE-IAM-002 A C端 sms/wechat 登录 modules/iam/ §3.1, U1~U4 /auth/login/*, users phone 唯一
M1-BE-IAM-003 D 门店登录 modules/iam/ §4.1 /shop/auth/*, store_accounts actorType=STORE
M1-BE-IAM-004 B 合伙人登录 modules/iam/ §5.1 /partner/auth/*, partner_accounts actorType=PARTNER
M1-BE-IAM-005 C 总部登录 + hq 账号 CRUD modules/iam/, modules/catalog/ §6 /admin/auth/*, hq_accounts actorType=HQ
M1-BE-IAM-006 A JWT Guard 四端 common/guards/ API §1.4 actor 校验
M1-BE-CAT-001 C 开城 CRUD + 佣金 modules/catalog/ §6.2 /admin/cities/*, cities, city_commission_rules 郑州 ACTIVE
M1-BE-CAT-002 C 商品 CRUD modules/catalog/ §6.3 /admin/products/*, products benefit_amount 可空
M1-BE-CAT-003 C C端商品列表 Public modules/catalog/ §3.2 GET /catalog/products 仅 ON_SALE
M1-FE-HQ-001 C 总部登录+开城+商品页 apps/mini-hq/ hq/1,6~9,12,14 §6 admin 可配 4 SKU
M1-FE-U-001 A C端登录+首页 apps/mini-user/ user/1,2 §3.1~3.2 清香型 4 款
M1-FE-P-001 B 合伙人登录壳 apps/mini-partner/ partner/1~2 §5.1 可登录
M1-FE-S-001 D 门店登录壳 apps/h5-shop/ shop/1~2 §4.1 可登录

M2 交易

ID OWNER 任务 主要路径 PRD API/DB 验收
M2-BE-TRD-001 A 地址 CRUD modules/trade/ §3.4 /user/addresses, user_addresses 默认地址
M2-BE-TRD-002 A 下单 preview(起购/运费) modules/trade/ + domain §2.3, §3.3 POST /trade/orders/preview 2/6 瓶规则
M2-BE-TRD-003 A 创建订单 + 推广归因 modules/trade/ §3.10 POST /trade/orders, orders.promo_code_id 带 channel_source
M2-BE-TRD-004 A 微信支付 + 回调 modules/trade/, callbacks/ §3.3.4 /trade/orders/:id/pay, payments 幂等 SUCCESS
M2-BE-BEN-001 A 支付成功发券 modules/benefit/ §2.1 benefit_coupons, benefit_ledgers GRANT 流水
M2-BE-TRD-005 A 订单列表 5 Tab modules/trade/ §3.5.1 GET /trade/orders?tab= 含 pending_ship
M2-BE-TRD-006 A 改址 + 拦截工单 modules/trade/ §3.5.4 delivery_intercepts 创建拦截
M2-FE-U-002 A 商品详情+确认订单 apps/mini-user/ user/3~5 preview API 跨城弹窗
M2-FE-U-003 A 地址+支付+订单列表 apps/mini-user/ user/6~12,9 trade API 5 Tab
M2-INT-001 A 小飞侠 Mock/对接 callbacks/xfx §7.1 配送状态 待发货→配送中

M3 权益与核销

ID OWNER 任务 主要路径 PRD API/DB 验收
M3-BE-BEN-002 A 权益汇总/券/明细 modules/benefit/ §3.8 /benefit/* 余额正确
M3-BE-RDM-001 D 核销 Token Redis modules/redeem/ §3.8.3 POST /redeem/token, redeem_tokens 5min/¥500
M3-BE-RDM-002 D 门店扫码确认核销 modules/redeem/ §4.3 /shop/redeem/*, redeem_records 事务+乐观锁
M3-BE-RDM-003 D 核销评价 modules/redeem/ §3.8.3 store_ratings 1~5 分
M3-BE-STR-001 B C端门店列表/详情 modules/store/ §3.7 GET /stores 仅 OPEN
M3-BE-NOT-001 Lead 核销短信 modules/notify/ §4.3 sms_logs 门店收到短信
M3-FE-U-004 A 权益+核销全流程 apps/mini-user/ user/15~22 benefit+redeem 出码成功
M3-FE-S-002 D 门店核销全流程 apps/h5-shop/ shop/3~7 shop/redeem 扫码确认

M4 运营

ID OWNER 任务 主要路径 PRD API/DB 验收
M4-BE-STR-002 B 门店三步录入+审核 modules/store/ §5.3 /partner/stores/*, store_audits 提交 PENDING
M4-BE-STR-003 C 总部审核门店 modules/store/ §6.5 /admin/store-audits/* reviewer=hq_accounts
M4-BE-IAM-007 B 合伙人子账号 modules/iam/ §5.9 /partner/staff, partner_accounts 主/子账号
M4-BE-TRD-007 A 补发单 modules/trade/ §3.6 orders RESHIPMENT 金额 0
M4-BE-TRD-008 A 退款+权益 VOID modules/trade/ §3.6.2 refunds, after_sale_tickets 微信退款
M4-FE-P-002 B 合伙人门店+补发+拦截 apps/mini-partner/ partner/49,1213 partner API 闭环
M4-FE-HQ-002 C 总部审核+客服 apps/mini-hq/ hq/1920,2627 admin after-sales 退款可操作

M5 结算

ID OWNER 任务 主要路径 PRD API/DB 验收
M5-BE-STL-001 C 核销→store_payouts modules/settlement/ §4.4 60%, T+1 PENDING
M5-BE-STL-002 C T+1 打款任务 jobs/ §6.7 batch-pay PAID
M5-BE-STL-003 C 合伙人 T+30 账单 modules/settlement/ §5.7 partner_bills 确认流程
M5-FE-* B,C,D 三端结算页 各 app partner/10,22; shop/6; hq/21~23 settlement API 状态展示

M6 增长

ID OWNER 任务 主要路径 PRD API/DB 验收
M6-BE-ANA-001 A promo touch 归因 modules/analytics/ §3.10.1 user_promo_attributions 首次触达
M6-BE-ANA-002 A 埋点批量入库 modules/analytics/ §3.10.2 event_logs 17 事件
M6-BE-CAT-004 C 推广码+统计 modules/catalog/ §6.6 /admin/promo-codes scan/order_count
M6-FE-HQ-003 C 报表+预警 apps/mini-hq/ hq/35,1517 /admin/reports GMV/渠道

附录 B · 原型 → API → 模块 速查

原型目录 主要 API 前缀 NestJS Module
C端 pages/user/ /auth, /user, /catalog, /trade, /benefit, /redeem, /stores, /promo iam, catalog, trade, benefit, redeem, store, analytics
门店 pages/shop/ /shop/auth, /shop/redeem, /shop/store iam, redeem, store
合伙人 pages/partner/ /partner/* iam, store, trade, settlement
总部 pages/hq/ /admin/* iam, catalog, store, trade, settlement, ops, analytics

附录 C · Skills 绑定说明

Skill 路径 何时启用
dukang-coding .cursor/skills/dukang-coding/ 写代码、实现任务卡、修 Bug
dukang-project .cursor/skills/dukang-project/ 写 PRD、评审需求、对照原型

在 Cursor 项目设置或对话中 @dukang-coding,并指明任务卡 ID,例如:

实现 M2-BE-TRD-002,按开发计划与 PRD 完成下单 preview。


计划随迭代每周更新;任务卡新增请保持 ID 格式 Mx-LAYER-NNN


§八、核心业务链路

购酒 → 发券 → 配送

user_user → user_order(含商品快照) → log_third_party(WECHAT_PAY)
→ user_order_delivery(1:1) → user_benefit_coupon → common_event(BENEFIT_LEDGER,GRANT)

核销 → 门店 T+1

Redis redeem:token(5min) → user_redeem_record → common_event(BENEFIT_LEDGER,REDEEM)
→ store_payout(T+1) → user_store_rating → log_third_party(SMS)

门店入驻

partner_partner → store_store + common_resource → common_event(STORE_AUDIT)
→ hq_account 审核 → store_account

退款

common_ticket(REFUND) → log_third_party(WECHAT_REFUND) → user_benefit_coupon VOID
→ common_event(BENEFIT_LEDGER,VOID) → common_event(ORDER_STATUS,REFUNDED)

改址拦截

用户改址 API 更新 user_order 收货字段 → common_event(ORDER_STATUS) + 可选 common_ticket(ALERT) → 合伙人 pages/partner/4-拦截配送.png 处理 → user_order_delivery 与第三方回调同步状态。


§九、第三方集成与非功能

系统 用途 落库
微信支付/退款 下单、退款 log_third_party + user_order.pay_*
小飞侠 同城配送 log_third_party(XFX) + user_order_delivery
物流 跨城 user_order_delivery + 总部发货
短信 验证码、核销通知 log_third_party(SMS)
OSS 图片/合同 common_resource

非功能:JWT 四端隔离;支付/核销幂等;列表 P95 < 500ms;核销 Redis 5min + 券 version 乐观锁;手机号脱敏。


编码配合根目录 agent.md、skills.md、conventions.md。