# 杜康好客 · V2 编码手册(完整规格 · 唯一事实源) > **V3 交付提示**:当前交付验收以 [`杜康好客-v3编码手册.md`](./杜康好客-v3编码手册.md) 为准。本手册中「核销单次上限 ¥500」等规则已被 V3 替代(直接核销可达总余额 / 单据 cap)。 > **版本**:**V2**(完整四端 + 微信生态 + 真实第三方) > **联调裁剪版**:见 [`杜康好客-preV1编码手册.md`](./杜康好客-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.1(28 表,见 §五) > **API**:v3.1(见 §六) > **协作**:见根目录 `conventions.md`、`agent.md`、`skills.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-首页.png`、`3-商品详情页.png` #### 3.2.1 首页 | 元素 | 说明 | | ------ | --------------------------------- | | 品牌区 | 杜康好客 + 当前城市 | | 香型 Tab | 清香型 / 酱香型 / 浓香型(**当前仅清香型上线**) | | 商品卡片 | 大图 + 标题 + 规格 + 价格 + 好客权益标签 + 立即购买 | | 商品数量 | **V1 固定 4 款**清香型,大图列表布局 | #### 3.2.2 商品详情 | 元素 | 说明 | | -------- | ---------------------------------------- | | 主图轮播 | 商品主图 | | 价格/名称/规格 | 固定展示 | | 好客权益说明 | 标准文案:「买杜康美酒·享全城好客礼遇」,展示金额取 `权益金额`(默认同售价) | | 图文详情 | 后台商品管理维护,支持图片+文字 | | 操作 | 返回首页 / 立即购买 | **业务规则** - 权益展示/发放金额 = 商品配置的 `benefit_amount`;**未配置时默认 = 商品售价** - 首页卡片「享 ¥X 好客权益」同步读取该字段 --- ### 3.3 模块三:下单与微信支付 **原型**:`4-立即购买确认订单.png`、`5-订单确认-跨城配送.png`、`6~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-地址列表.png`、`7-新增收货地址.png` | 功能 | 说明 | | ---- | ---------------------- | | 地址列表 | 历史地址,可选择 | | 新增地址 | 收货人、手机号、地区选择、详细地址、是否默认 | | 默认地址 | 下单时优先选中 | --- ### 3.5 模块五:订单管理 **原型**:`9-我的订单列表.png`、`10~12`、`11-我的订单详情.png` #### 3.5.1 订单列表 Tab **原型**:`9-我的订单列表.png`(**5 Tab:全部/待付款/待发货/待收货/已完成**) | Tab | 包含状态 | | ------- | ---------------- | | 全部 | 所有(含退款中、已退款、补发单) | | 待付款 | 待支付 | | **待发货** | 已支付,待出库/待推配送 | | 待收货 | 配送中 + 待签收 | | 已完成 | 已完成 | **完整状态机**:`待付款 → 待发货 → 配送中 → 待签收 → 已完成` **异常分支**:`退款中 → 已退款`;`补发中`(关联原单,价格 ¥0) > **原型改稿**:`pages/user/9` 需增补「待发货」Tab,详见 `doc/原型说明.md`。 #### 3.5.2 列表卡片字段 - 订单号、状态 - 商品图、名称、规格、数量、金额 - 好客权益使用情况 + 「去使用」按钮(未用完时) - 补发单:标记「补发单」,价格 ¥0,提示破损免费补发 #### 3.5.3 订单详情 | 区块 | 内容 | | ---- | --------------------------- | | 进度条 | 下单成功 → 出库中 → 配送中 → 待签收 → 完成 | | 商品信息 | 含好客权益引导入口 | | 收货信息 | 姓名、地址、配送方式;**待发货/配送中可修改** | | 订单信息 | 订单号、创建时间、支付方式 | | 结算 | 商品总额、运费、实付 | | 操作 | 联系客服、确认收货 | #### 3.5.4 修改收货地址 **原型**:`12-修改地址弹窗.png` - 弹窗提示:系统将尝试拦截配送;拦截失败需联系配送员 - 若已按原地址签收,不再二次派送 - **拦截成功**(物流返回「商品已退回」)→ 推送新订单到城市合伙人 → 二次配送 --- ### 3.6 模块六:售后与客服 **原型**:`13-联系客服弹窗.png`、`14-联系在线客服.png` | 渠道 | 说明 | | ------ | ------ | | 电话客服 | 调起拨号 | | 微信图文客服 | 在线实时沟通 | **补发流程**(破损等): 1. 用户联系总部客服,提供订单号 2. 总部客服发起补发 3. 通知用户;推送城市合伙人确认 4. 合伙人确认后进入配送;系统记录补发关联原订单 #### 3.6.2 退款流程(V1) **原型**:`pages/hq/26-补发与退款处理.png` | 环节 | 说明 | | ---- | -------------------------------------------------------- | | 发起 | 用户通过客服(电话/在线)申请退款,提供订单号与原因 | | 受理 | 总部客服在「客服中心」创建退款工单,关联原订单 | | 审核 | 总部客服/财务审核;可部分退款或全额退款 | | 执行 | 调用微信退款 API;订单状态 → `退款中` → `已退款` | | 权益回退 | 若对应好客权益**未使用**:全额退款时作废权益;**已部分核销**:按未使用余额比例退款或人工核算(客服备注) | | 通知 | 退款结果推送用户(小程序订阅消息/客服会话) | **可退款状态** | 订单状态 | 是否可退 | 说明 | | ------- | ---- | ------------------------ | | 待付款 | 否 | 用户直接取消/超时关单 | | 待发货 | 是 | 全额退款优先 | | 配送中 | 是 | 需拦截配送成功后退款 | | 待签收/已完成 | 条件可退 | 签收 7 天内且未开瓶/未核销权益,客服人工判定 | | 补发单 | 否 | — | --- ### 3.7 模块七:门店 **原型**:`15-门店页面-门店列表.png`、`16-门店详情页.png` #### 3.7.1 门店列表 | 元素 | 说明 | | --- | ----------------------------------- | | 定位 | 按用户城市/区域筛选 | | 分类 | 火锅、地方菜、高端餐饮、烧烤烤肉等 | | 卡片 | 招牌图、名称、评分、人均、支持核销标签、营业状态 | | 搜索 | 店名、地址 | | 过滤 | **永久闭店、临时闭店均不在 C 端展示**;仅「营业中」门店可见可选 | #### 3.7.2 门店详情 - 大图、名称、状态、评分、标签 - 环境图(3 张) - 地址、距用户距离 - 电话、导航(调起地图) - 图文介绍(后台维护) - 「去核销」→ 跳转核销页 --- ### 3.8 模块八:好客权益 **原型**:`17-好客权益页.png`、`18-好客权益明细.png`、`20~22` #### 3.8.1 权益首页 - 当前余额(汇总) - 「去使用」→ 核销流程 - Tab:待使用 | 已用完/已过期(当前无过期,仅已用完) - 券卡片:金额、来源订单、永久有效、已用/未用进度、券编号、立即核销 #### 3.8.2 权益明细 - 获取记录 + 消费记录 #### 3.8.3 核销流程 1. 选择门店(或从订单/权益页直接进入) 2. **核销页**:展示可用余额,输入本次核销金额,支持「全部核销」 - 校验:`0 < 金额 ≤ min(可用余额, ¥500)` - 超出 ¥500 提示「单次最高可核销 ¥500.00」 3. 点击「生成核销码」→ 展示二维码 4. 核销码 **5 分钟有效**,一次性使用,可刷新 5. 门店扫码确认 → **核销成功页** 6. 快速评价:服务态度、用餐环境(五星,点击即保存) **入口汇总** - 底部 Tab「好客权益」 - 订单列表/详情「去使用」 - 门店详情「去核销」 - 个人中心「去使用」 --- ### 3.9 模块九:个人中心 **原型**:`19-个人中心页.png` | 区块 | 说明 | | ---------- | -------------------------------------------- | | 用户信息 | 全局默认头像、微信昵称、平台 ID(**V1 无会员等级**,不展示「至尊会员」等标签) | | 我的资产 | 好客权益余额 → 明细 | | 我的订单 | 待付款/待发货/配送中/已完成 快捷入口 | | 地址管理 | 跳转地址列表 | | 可用门店 | 跳转门店 Tab | | 联系客服 | 同订单页 | | 关于我们 / 版本号 | 展示系统版本 | | 退出登录 | — | --- ### 3.10 模块十:推广码与埋点(V1) **原型**:`pages/hq/16-推广码管理.png`、`17-推广码生成.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-登录页.png`、`2-一键登录.png` - 门店手机号 + 验证码 - 微信授权登录 - 记住登录态,二次进入快捷登录 - 展示门店名称、绑定手机号 ### 4.2 首页 · 扫码核销 **原型**:`3-门店管理首页-核销页.png` | 元素 | 说明 | | --------------- | ------------------------ | | 门店名称 | 当前登录门店 | | 今日核销笔数 / 今日到账金额 | 实时统计 | | 扫码核销 | 主操作按钮;亦支持微信扫一扫 | | 营业状态 | 开店 / 临时闭店切换,**实时同步 C 端** | | 最近核销 | 时间 + 金额,倒序 | **营业规则** - 门店端:开店 / 临时闭店 - 临时闭店 → **C 端列表隐藏**,不可核销 - 永久闭店:仅城市合伙人可操作,C 端不可见 ### 4.3 核销确认 **原型**:`4-核销确认.png`、`5-核销成功.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-登录页.png`、`2-快捷登录.png` - 账号由**总部创建**城市合伙人入驻 - 手机验证码 / 微信授权 / 快捷登录 - 微信授权有效期 **30 天** - 展示:企业名称、地址、入驻城市、手机号 ### 5.2 工作台首页 **原型**:`3-首页.png` | 指标 | 说明 | | ----- | ------------------- | | 实时营业额 | 所辖城市酒品订单 GMV | | 预计利润 | 营业额 × 35%(30% + 5%) | | 门店总数 | 正常运营 / 异常·闭店 | | 今日订单量 | 待发货 / 配送中 / 已完成 | | 拓店情况 | 下级合伙人拓店统计 | | 贡献榜 | 按拓店数排行 | **快捷入口**:录入新店 | 补发处理 | 财务对账 | 数据周报 | 拦截配送 > 脚本明确「今日活跃度」等字段暂不使用。 ### 5.3 门店管理 **原型**:`5-门店管理.png`、`6~8` #### 5.3.1 门店列表 - 状态:营业中 / 暂时闭店 / 已关闭(永久闭店) - 搜索:名称、地址 #### 5.3.2 录入新门店(三步) | 步骤 | 内容 | | ------ | ----------------------------- | | 1 基本信息 | 名称*、电话*、地图选址*、门牌号、简介(10~500字) | | 2 照片上传 | 门头照、环境照(≥3 张)、签约合同副本 | | 3 结算资质 | 银行卡姓名、卡号、开户支行 | - 提交 → 推送**总部审核** - 审核通过 → 门店生效,获得核销权限 - 合伙人可编辑门店;**永久闭店**仅合伙人可操作 #### 5.3.3 审核记录 - 待审核 / 已通过 / 已驳回 - 驳回可修改重新提交 ### 5.4 订单管理 **原型**:`12-订单列表.png`、`13-订单详情.png` - 仅查看**所辖城市**订单 - 时间:今天 / 近 7 天 / 近 30 天 - 状态:全部 / 待发货 / 运输中 / 已完成 / 异常(退货补发)/ 拦截 - 列表:订单号、商品、规格、赠券金额、收货地址 - 详情:物流状态、佣金(下单 + 核销两笔)、推广渠道来源 ### 5.5 补发处理 **原型**:`9-补发处理.png` - 总部下达补发工单:原订单号、状态 - 合伙人点击「开始配送」→ 推送城市配送 - 物流签收回调 或 合伙人手动确认送达 ### 5.6 拦截配送 **原型**:`4-拦截配送.png` - 用户改地址触发拦截通知 - 合伙人查看详情,发起拦截 - **拦截成功** → 新地址二次配送(等同正常订单流转) - 待配送状态:直接撤回原单 ### 5.7 财务对账与结算 **原型**:`10-财务对账.png`、`22-确认账单.png`、`23-申请打款.png` | 概念 | 规则 | | ---- | --------------------- | | 账期 | T+30 天 | | 流程 | 总部发起账单 → 合伙人确认 → 总部打款 | | 账单状态 | 待结算 / 审核中 / 已结算 | | 佣金构成 | 酒品下单佣金 + 权益核销佣金 | | 佣金比例 | 总部在开城/合伙人配置处设置 | **确认账单页** - 展示账期、应结总金额 - 拆分:订单分佣 + 核销分佣 - 勾选确认 → 申请打款 - 仅**主账号**(签约账号)可收账单确认通知;子账号不可 ### 5.8 经营周报 **原型**:`11-周报.png` - 默认近 7 天,可回溯 - GMV、活跃门店数(有核销即活跃)、购酒订单量 - 本周新签门店、每日 GMV 趋势、门店核销排行 ### 5.9 子账号管理 **原型**:`15~16`、`18` | 角色 | 说明 | | ----- | ----- | | 城市合伙人 | 子级合伙人 | | 内部员工 | 拓店人员 | | 推广员 | 线下推广 | - 创建:姓名、手机号(验证码校验)、角色 - 默认**禁用**,需手动启用 - 可编辑、禁用、删除 - 贡献榜按拓店数排名 ### 5.10 合伙人中心 **原型**:`17`、`20-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-开城管理.png`、`7-新增城市.png`、`8`、`9-配置佣金比例.png` | 功能 | 说明 | | ---- | --------------- | | 城市列表 | 运营中 / 暂停 / 待开城 | | 城市卡片 | 合伙人、门店数、累计 GMV | | 操作 | 编辑、暂停/恢复、配置 | | 新增城市 | 基本信息 + 开户行 + 附件 | | 佣金配置 | 下单佣金比例、核销佣金比例 | ### 6.3 商品管理 **原型**:`12-商品列表.png`、`14-商品添加.png` - 杜康系列酒品 CRUD - 字段:名称、规格、价格、香型、主图、图文详情、**权益金额(可选)** - **权益金额规则**:留空 = 默认等于售价;填写 = 按配置值发放与展示 - V1 上架 **4 款清香型**;上下架控制 ### 6.4 订单中心 **原型**:`10-11`、`13-1~4`、`24-跨城订单处理.png`、`25-发货处理.png` - 全链路订单监控 - 搜索:订单号、手机号、城市;时间筛选 - 状态筛选:待发货 / 配送中 / 已完成 / 异常 - 跨城订单:总部物流发货处理 - 订单详情:完整履约信息、佣金拆分、推广来源 ### 6.5 门店审核 **原型**:`19-门店审核管理.png`、`20-门店详情页面.png` | Tab | 说明 | | -------------------- | --- | | 全部 / 待审核 / 已通过 / 已驳回 | — | - 审核类型:首次入驻 / 信息修改 - 操作:查看详情、修改、通过、驳回 - 总部也可编辑门店信息 ### 6.6 推广码管理 **原型**:`16-推广码管理.png`、`17-推广码生成.png` - 创建推广码(品鉴会等场景) - 关联渠道名称 - 订单归因统计 ### 6.7 结算中心 **原型**:`21-结算中心.png`、`22-23` **Tab**:城市合伙人结算 | 门店结算 | 功能 | 说明 | | ----- | --------------------------- | | 待结算总额 | 汇总 | | 待处理记录 | 发送账单 / 确认打款 | | 门店结算 | 核销打款给门店(60%),周期 **T+1 工作日** | **结算周期对比** | 对象 | 周期 | 流程 | | ----- | -------- | --------------------- | | 门店 | **T+1** | 总部按日/批打款,门店核销记录标记已打款 | | 城市合伙人 | **T+30** | 账期 → 发账单 → 合伙人确认 → 打款 | ### 6.8 客服中心 · 补发与退款 **原型**:`26-补发与退款处理.png`、`27-补发详情页面.png` | 功能 | 说明 | | ---- | --------------------------------- | | 补发 | 输入订单号 → 创建补发单 → 推送合伙人 → 跟踪配送 | | 退款 | 输入订单号 → 创建退款工单 → 审核 → 微信退款 → 权益回退 | | 工单列表 | 待处理 / 已完成;类型:补发 / 退款 | | 关联查询 | 原订单、补发单、退款单互相关联 | ### 6.9 数据报表 **原型**:`15-数据报表中心.png` - 全链路经营数据看板 ### 6.10 预警 **原型**:`4-预警详情.png`、`5-超时订单详情.png` - 超时未处理订单预警 - 跳转订单处理 --- ## 7. 关键业务流程 ### 7.1 购酒履约 ```mermaid 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 好客权益核销 ```mermaid 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 门店入驻 ```mermaid flowchart LR A[合伙人录入门店] --> B[总部审核] B -->|通过| C[门店生效可核销] B -->|驳回| D[合伙人修改重提] C --> E[C端可见可选] ``` ### 7.4 合伙人结算 ```mermaid flowchart LR A[T+30 账期到期] --> B[总部发起账单] B --> C[合伙人确认] C --> D[总部打款] D --> E[已结算] ``` ### 7.5 门店核销打款(T+1) ```mermaid flowchart LR A[门店确认核销] --> B[记录待打款] B --> C[T+1 工作日] C --> D[总部批量打款] D --> E[门店记录已打款] ``` ### 7.6 退款流程 ```mermaid 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 | 订单列表 | 订单 | **5 Tab(含待发货)** | | 10-我的订单-补发状态.png | 补发订单 | 售后 | | 11-我的订单详情.png | 订单详情 | 订单履约 | | 12-修改地址弹窗.png | 修改地址 | 订单 | | 13-联系客服弹窗.png | 联系客服 | 客服 | | 14-联系在线客服.png | 在线客服 | 客服 | | 15-门店页面-门店列表.png | 门店列表 | 门店 | | 16-门店详情页.png | 门店详情 | 门店 | | 17-好客权益页.png | 好客权益 | 权益 | | 18-好客权益明细.png | 权益明细 | 权益 | | 19-个人中心页.png | 个人中心 | 我的 | V1 移除「至尊会员」标签 | | 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 共用 TypeScript,DTO/枚举可抽到 `packages/shared-types`,减少联调成本 - **NestJS 模块化**:Module/Controller/Service 分层清晰,接近 Spring 结构,适合订单/结算等复杂域 - **微信生态**:`wechatpay-node-v3`、小程序 code2session 等 Node SDK 成熟,满足 V1 支付/退款 - **异步友好**:支付回调、埋点、短信等 I/O 密集场景 Node 表现良好 - V1 仍为**模块化单体**,无需微服务 --- ## 2. 系统架构 ### 2.1 逻辑架构 ```mermaid 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 + 请求 traceId(nestjs-pino) - **进程**:PM2 cluster 或 Docker 单副本;V1 单实例即可 ### 2.3 仓库结构(Monorepo 建议) ``` dukang/ ├── apps/ │ ├── mini-user/ # C端 Taro 小程序 │ ├── mini-partner/ # 合伙人 Taro 小程序 │ ├── mini-hq/ # 总部 Taro 小程序 │ └── h5-shop/ # 门店 H5(Taro 或独立) ├── 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 API(`doc/API列表-杜康好客.md`)+ `shared-types` + Prisma schema(OWNER 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.ts` 的 `exports: [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」。 ```mermaid 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 | `store` → `trade` / `benefit` | 门店域不处理交易 | 由 redeem/trade 回调 | | F3 | `benefit` → `trade` / `redeem` | 防止循环依赖 | trade 调 `BenefitService.grant(dto)`,benefit 不反向查 trade | | F4 | `trade` → `redeem` | 交易不感知核销细节 | 仅通过 benefit 关联 | | F5 | `benefit` → `redeem` | 权益不依赖核销 | redeem 调 benefit 扣券 | | F6 | `catalog` → `trade` / `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` 示例: ```typescript @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) ```mermaid 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 好客权益规则(实现要点) ```typescript // 发放金额 const benefitAmount = product.benefitAmount ?? product.price; // 核销校验 if (amount <= 0 || amount > coupon.balance || amount > 500) { throw new BusinessException('INVALID_REDEEM_AMOUNT'); } ``` - 核销 Token:Redis `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 | Redis(session) | | `TradeModule` | OrderService, WechatPayService | BenefitModule, CatalogModule | | `RedeemModule` | RedeemService | BenefitModule, SettlementModule, Redis | | `SettlementModule` | PayoutService, BillService | BullMQ(T+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` | 全局;操作审计日志 | **Token**:JWT(access 2h)+ Redis refresh;小程序登录走 `wx.login` → code2session。 --- ## 4. 接口设计规范 ### 4.1 约定 - Base URL:`https://api.example.com/api/v1` - 认证:`Authorization: Bearer ` - 响应:`{ "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_resource`、`common_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` | 访问 URL(CDN) | | `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_id` → `common_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` 表,**仅存 Redis**(5 分钟);`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_id;remark=驳回原因;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_id;ref_type=关联类型 | **amount1=变动额, amount2=balance_after** | | `HQ_OPERATION` | 总部操作审计 | operation_logs | 总部后台写操作(非查询) | p1=action, p2=ref_type, p3=ref_id;extra=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=severity;extra=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` param1(ledger_type) | 枚举值 | 中文释义 | |--------|----------| | `GRANT` | 发放 | | `REDEEM` | 核销扣减 | | `VOID` | 退款作废 | | `ADJUST` | 人工调整 | #### 工单 `common_ticket.status`(通用) | 枚举值 | 中文释义 | |--------|----------| | `PENDING` | 待处理 | | `PROCESSING` | 处理中 | | `COMPLETED` | 已完成 | | `REJECTED` | 已驳回 | | `CANCELLED` | 已取消 | --- ## 6. ER 图(核心) ```mermaid 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. 公共 API(common 模块) > 详见本手册 §六;以下为 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` ```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 `(除公开接口与回调) | | `X-Client-App` | `USER_MINI` / `PARTNER_MINI` / `HQ_MINI` / `SHOP_H5` | | `X-Request-Id` | 可选,链路追踪 | ### 1.2 响应格式 ```json { "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_account`(`is_primary=1`) | | `AdminAuth` | 总部 | `hq_account` | | `Public` | 无需登录 | — | | `WxCallback` | 微信/配送回调验签 | — | ### 1.5 JWT Payload(四端统一) ```json { "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` | > 鉴权时须同时校验 `clientApp` 与 `actorType` 一致,禁止仅用数字 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_MINI` → `user_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` 响应要点** ```json { "accessToken": "", "refreshToken": "", "actorType": "USER", "actorId": "10001", "user": { "id": "10001", "userNo": "DK88293401", "phone": "138****8888", "nickname": "", "hasWechat": true } } ``` ### 2.3 门店端(`clientApp: SHOP_H5` → `store_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 | **响应 `actorType`**:`STORE`;附带 `storeId`、`storeName`。 ### 2.4 合伙人端(`clientApp: PARTNER_MINI` → `partner_account`) | 方法 | 路径 | 鉴权 | 说明 | PRD | |------|------|------|------|-----| | POST | `/partner/auth/login/sms` | Public | `{ phone, code }` → 查 `partner_account` | §5.1 | | POST | `/partner/auth/login/wechat` | Public | 微信登录(30 天免登) | §5.1 | **响应 `actorType`**:`PARTNER`;附带 `partnerId`、`isPrimary`、`staffRole`。 ### 2.5 总部端(`clientApp: HQ_MINI` → `hq_account`) | 方法 | 路径 | 鉴权 | 说明 | PRD | |------|------|------|------|-----| | POST | `/admin/auth/login/sms` | Public | `{ phone, code }` → 查 `hq_account` | §6 | | POST | `/admin/auth/login/wechat` | Public | 微信登录 | §6 | **响应 `actorType`**:`HQ`;附带 `adminRole`(`SUPER_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端用户 API(UserAuth) ### 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` 请求** ```json { "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. 门店端 API(StoreAuth) > 登录见 §2.3。Token 中 `actorType=STORE`,`actorId` 为 `store_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` 响应(确认页)** ```json { "storeName": "", "userPhoneMasked": "138****9021", "amount": 100.00, "couponNo": "DK202310248892", "couponValidity": "永久", "tokenExpireAt": "" } ``` --- ## 5. 城市合伙人 API(PartnerAuth) > 登录见 §2.4。Token 中 `actorType=PARTNER`,`actorId` 为 `partner_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 | > `:id` 为 `partner_account.id`。主账号 `is_primary=1`,子账号须设 `staffRole`(`PARTNER` / `INTERNAL` / `PROMOTER`)。 --- ## 6. 总部管理 API(AdminAuth) > 登录见 §2.5。Token 中 `actorType=HQ`,`actorId` 为 `hq_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/sms` → `user_user` | | C端微信首登绑手机 | `POST /auth/login/wechat` → `POST /auth/wechat/bind-phone` | | 门店 H5 登录 | `POST /shop/auth/login/sms` → `store_account` | | 合伙人/子账号登录 | `POST /partner/auth/login/sms` → `partner_account` | | 总部登录 | `POST /admin/auth/login/sms` → `hq_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/address` → `common_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 Commits,scope = 端或模块(`feat(trade)`) ### 0.3 技术栈(锁定) | 层 | 选型 | |----|------| | 前端 | Taro 3 + React + TypeScript,Monorepo 四 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、提审、试运行 | 郑州试运行 | ```mermaid 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.yaml`、`package.json`、ESLint/Prettier、`.env.example` | | packages | `shared-types`(ActorType、OrderStatus、错误码)、`domain`(起购/权益/核销纯函数) | | server | NestJS 启动、`PrismaModule`、`GlobalExceptionFilter`、统一 `{code,message,data}` | | apps | 四端 Taro 脚手架、`request.ts`(带 `X-Client-App`)、登录态存储 | | deploy | `docker-compose.yml`(MySQL + Redis)、`prisma migrate` 或执行 `数据库设计2` §5 SQL | | CI | lint + `prisma validate` + `domain` 单元测试 | **M0 出口**:`GET /api/v1/health` 200;`npx prisma validate` 通过;四端空白页 + 登录页壳可编译。 --- ## 4. 分里程碑交付说明 ### M1 基础(IAM + 开城 + 商品) **PRD**:§3.1 登录、§6.2 开城、§6.3 商品 **DB**:`users`、`store_accounts`、`partner_accounts`、`hq_accounts`、`cities`、`products`、`wx_app_configs` **API**:§2 四端认证、`/catalog/*`、`/admin/cities`、`/admin/products`、`/admin/hq-accounts` | 端 | 页面(原型) | 关键能力 | |----|--------------|----------| | mini-hq | hq/1~2, 6~9, 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 **DB**:`orders`、`order_items`、`payments`、`user_addresses`、`benefit_coupons`、`benefit_ledgers` **API**:`/trade/orders/*`、`/user/addresses`、`callbacks/wechat/pay` | 端 | 页面 | 关键能力 | |----|------|----------| | mini-user | user/3~12, **9 含待发货 Tab** | 详情、下单、支付、5 Tab 订单、改址 | **业务验收**:同城 1 瓶拒单、2 瓶成功;跨城 5 瓶拒单、6 瓶成功;支付成功发券。 ### M3 权益与核销 **PRD**:§3.7~§3.8、§4 **DB**:`redeem_tokens`、`redeem_records`、`store_ratings`、`store_payouts`(创建待打款) **API**:`/benefit/*`、`/redeem/*`、`/stores`、`/shop/redeem/*` | 端 | 页面 | 关键能力 | |----|------|----------| | mini-user | user/15~22, 17~18 | 门店列表、权益、核销码、评价 | | h5-shop | shop/3~7 | 扫码、确认核销、记录 | **业务验收**:核销 ¥501 拒单;码 5 分钟失效;暂停门店 C 端不可见。 ### M4 运营(拓店 + 售后) **PRD**:§5.3~§5.6、§6.5、§6.8 **DB**:`stores`、`store_media`、`store_audits`、`after_sale_tickets`、`refunds`、`delivery_intercepts` **API**:`/partner/stores/*`、`/admin/store-audits/*`、`/admin/after-sales/*`、`/partner/intercepts/*` ### M5 结算 **PRD**:§4.4、§5.7、§6.7 **DB**:`store_payouts`、`partner_bills`、`order_commissions`、`partner_withdrawals` **API**:`/admin/settlement/*`、`/partner/settlement/*`、`/shop/redeem/records` ### M6 增长 **PRD**:§3.10 **DB**:`promo_codes`、`user_promo_attributions`、`event_logs` **API**:`/promo/touch`、`/analytics/events`、`/admin/promo-codes`、`/admin/reports/*` --- ## 5. 编码规范速链 - 模块禁止跨表:见 `conventions.md` §2、`技术方案` §2.5 - JWT:`actorType` + `actorId`,见 `API列表` §1.5 - C 端用户:`users.phone` 唯一必填;B 端三表分离 - 金额:`Decimal(10,2)`;权益发放 `benefitAmount ?? price` - 核销:Redis Token 5min + `benefit_coupons.version` 乐观锁 - 订单 Tab:`all|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/4~9,12~13 | partner API | 闭环 | | M4-FE-HQ-002 | C | 总部审核+客服 | `apps/mini-hq/` | hq/19~20,26~27 | 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/3~5,15~17 | `/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。*