# 2026-02-05 / mall:配送-商家-消费者 数据流统一分析(SQL + 项目规范口径) ## 摘要 本文基于本仓库 **权威 SQL 目录** `docs/sql/`(并参考 `mall_sql/` 中的 `complete_mall_database.sql` 实现细节),结合项目工程与安全规范 `docs/project_spec/AGENT_PROJECT_SPEC.md`、`docs/sql/11_roles_and_permissions_strategy.md`,对 **消费者 / 商家 / 配送员** 三方在电商场景中的数据流运转进行统一分析。 输出内容包括: - 三方域模型与关键表关系(文字版 ER) - 端到端事件链路:下单、支付、履约配送、完成、评价 - 订单与配送状态机(字段口径与关键歧义点) - 读模型(各端典型查询视角) - 权限边界(RLS / RPC / 前端守卫)在本项目中的统一口径 > 本文为分析文档,不包含代码/SQL 变更。 --- ## 动机 - 统一“谁能看/改什么数据”的口径:角色权威字段、RLS 与 RPC 的安全闭环要求必须一致。 - 统一“数据如何落表与流转”的口径:避免前后端/不同模块对订单、配送、商家模型理解不一致。 - 为后续落地(配置页、配送履约闭环、统计看板等)提供可审计的基础说明。 --- ## 影响范围 - **数据库层**:`docs/sql/` 中的表结构、触发器、RLS、RPC 策略口径(本文不修改)。 - **前端工程层**:页面必须通过 `services/` 访问数据;admin/analytics 需通过 RPC 获取全局数据(本文不修改)。 - **业务模块**: - 消费者端(consumer)订单链路 - 商家端(merchant)商品与订单履约 - 配送端(delivery)接单/取货/送达 - 管理端(admin)配置与全局视角 --- ## 变更清单 - **新增文件**: - `docs/ops/2026-02-05__mall__delivery-merchant-customer-dataflow-analysis.md` - **修改文件**:无 - **删除文件**:无 --- ## 权威输入(引用口径) - 数据库与流程说明: - `docs/sql/02_relationships_er.md` - `docs/sql/03_enums_status_dict.md` - `docs/sql/07_business_workflows.md` - `docs/sql/11_roles_and_permissions_strategy.md` - 工程与安全规范: - `docs/project_spec/AGENT_PROJECT_SPEC.md` - 参考实现(非权威口径,但含完整 DDL/触发器/RLS 示例): - `mall_sql/schemas/complete_mall_database.sql` - 管理端设置页现状(占位): - `pages/mall/admin/system-settings.uvue` --- ## 1. 统一域模型:三方是谁(同一身份体系下的三类角色) - **统一用户主表**:`public.ak_users` - **角色唯一权威字段**:`ak_users.role` - **商城用户扩展档案**:`public.ml_user_profiles` - 关系:`ak_users` 1:1 `ml_user_profiles`(`ml_user_profiles.user_id UNIQUE`) 三方角色定义(业务口径): - 消费者:`ak_users.role = 'customer'` - 商家:`ak_users.role = 'merchant'` - 配送员:`ak_users.role = 'delivery'` 结论:三方并非三套用户体系,而是“同一 `ak_users` + 不同域表扩展”。 --- ## 2. 核心表关系(文字版 ER) ### 2.1 消费者(Customer) - `ak_users (customer)` 1:N `ml_user_addresses` - `ak_users (customer)` 1:N `ml_shopping_cart` - `ak_users (customer)` 1:N `ml_orders`(`ml_orders.user_id`) ### 2.2 商家(Merchant) - `ak_users (merchant)` 1:1 `ml_shops`(`ml_shops.merchant_id UNIQUE`) - 当前模型含义:一商家一店铺 - `ak_users (merchant)` 1:N `ml_products`(`ml_products.merchant_id`) - `ak_users (merchant)` 1:N `ml_orders`(`ml_orders.merchant_id`) ### 2.3 商品(Product) - `ml_products` 1:N `ml_product_skus` - `ml_products` 1:N `ml_product_specs` - SKU 变更触发汇总:`ml_product_skus` 变更 -> 触发器刷新 `ml_products.total_stock/available_stock` ### 2.4 订单(Order) - `ml_orders` 1:N `ml_order_items` - `ml_orders` 1:1 `ml_delivery_tasks`(`ml_delivery_tasks.order_id UNIQUE`) - 当前模型含义:一订单最多一个配送任务 ### 2.5 配送(Delivery) - `ak_users (delivery)` 1:1 `ml_delivery_drivers`(`ml_delivery_drivers.user_id UNIQUE`) - `ml_delivery_drivers` 1:N `ml_delivery_tasks`(通过 `ml_delivery_tasks.driver_id` 关联) --- ## 3. 三方端到端数据流(事件 → 落表 → 状态变化) ### 3.1 消费者链路(浏览→加购→下单→支付→收货→评价) #### 事件 A:维护地址 - 写表:`ml_user_addresses` - 约束:同一用户最多一个默认地址 - 由触发器 `ensure_single_default_address()` 保证 #### 事件 B:加购/改购 - 写表:`ml_shopping_cart` - 约束:`UNIQUE(user_id, product_id, sku_id)`(便于 upsert 累加) #### 事件 C:下单(创建订单 + 明细快照) - 写表: - `ml_orders`(订单主表) - `ml_order_items`(订单明细快照) - 关键设计点: - `ml_orders.shipping_address` 为 JSONB 地址快照,避免订单与地址簿耦合 - `ml_order_items` 快照化写入商品名/规格/图/价格,避免商品变更影响历史 > 一致性提示(现状):当前权威文档指出未体现“扣库存/冻结库存”落地,库存一致性需由应用层事务或后续 DB/RPC 补齐。 #### 事件 D:支付成功 - 更新:`ml_orders` - `order_status: 1 -> 2` - `payment_status: 1 -> 2` - `paid_amount = total_amount` - 触发器副作用:`handle_order_status_change()` 在 `1->2` 写 `paid_at` #### 事件 E:收货完成/订单完成 - 更新:`ml_orders` - `order_status: 3 -> 4` - `shipping_status -> 4` - 触发器副作用:写 `delivered_at/completed_at`,并累计更新 `ml_products.sale_count` #### 事件 F:评价 - 写表:`ml_product_reviews` - 强绑定来源:`order_id + order_item_id` --- ### 3.1.1 退款/取消在当前模型中的最小表达(现状与缺口) 当前数据库没有独立的退款申请表或售后流程表,只能通过 `ml_orders` 的状态组合表达: - **退款分支**: - `payment_status: 3(部分退款)` / `4(全额退款)` - `order_status` 通常进入 `6(退款中)` -> `7(已退款)` - **取消分支**: - `order_status: 5`(歧义点,见第 4.2 节) - `cancel_reason`(文本字段)可用于记录取消原因 > **缺口提示**: > - 缺少退款申请流水、审批流、支付对账表,复杂售后需后续扩表或接支付系统。 > - 缺少 `cancelled_at`、`refunded_at` 等审计时间字段。 > - 配送已取货/在途/已送达时的退款/取消口径未在当前模型体现(需业务层定义)。 --- ### 3.2 商家链路(供给→接单→履约) #### 事件 A:创建/编辑商品 - 写表:`ml_products`、`ml_product_skus`、`ml_product_specs` - 库存汇总:SKU 触发器刷新 SPU 汇总库存字段 #### 事件 B:发货/履约推进 - 更新:`ml_orders` - `order_status: 2 -> 3` - `shipping_status: 1 -> 2` - 触发器副作用:`2->3` 时写 `shipped_at` --- ### 3.2.1 单商家订单模型的限制(需求提醒) 当前订单主表 `ml_orders` 直接持有 `merchant_id`,且未见“主单/子单”结构,因此该模型天然对应: - **一笔订单仅归属一个商家/店铺**(单商家订单) > 若产品需求为“一单多商家(多店铺)”,通常需要: > - 引入主/子订单拆分(例如主订单聚合支付与收货信息,子订单按商家拆分履约与结算),或 > - 在下单阶段强制拆单(多个 `ml_orders`)并建立父子关联字段。 --- ### 3.3 配送链路(派单/接单→取货→配送→送达) #### 事件 A:创建配送任务 - 写表:`ml_delivery_tasks` - 关键字段: - `order_id UNIQUE` - `driver_id` 可空(先生成后指派) - `pickup_address`(取货点) - `delivery_address`(配送点,建议源自订单地址快照) #### 事件 B:接单/指派 - 更新:`ml_delivery_tasks` - `status: 1 -> 2` - `assigned_at` 写入 - 绑定 `driver_id` #### 事件 C:取货→配送→送达(或失败) - 更新:`ml_delivery_tasks` - `2 -> 3`(写 `picked_at`) - `3 -> 4` - `4 -> 5`(写 `delivered_at`) - 失败:`status = 6` + `failure_reason` > 一致性提示(现状):未看到 DB 侧“配送送达 → 自动联动订单状态”的权威触发器/RPC 设计,需在 service/RPC 层承担联动更新职责。 --- ### 3.3.1 配送状态 → 订单状态的建议映射(统一口径) 为避免三方对“配送进展如何反映到订单状态”理解不一致,建议采用以下最小映射(可在 service/RPC 事务中实现): | 配送任务 `status` | 建议同步的 `ml_orders.shipping_status` | 建议同步的 `ml_orders.order_status` | 说明 | | ----------------- | -------------------------------------- | ----------------------------------------------------- | ------------------------- | | 1 待接单 | 1 未发货 | 2 待发货(已支付) | 任务生成但未接单 | | 2 已接单 | 2 已发货 | 2 待发货 | 商家/平台已指派,但未取货 | | 3 取货中 | 3 运输中 | 3 待收货 | 骑手已取货,在途 | | 4 配送中 | 3 运输中 | 3 待收货 | 仍在途 | | 5 已送达 | 4 已送达 | 3 待收货(或直接 4 已完成,取决于产品是否需用户确认) | 骑手确认送达 | | 6 配送失败 | 1 未发货(或自定义状态) | 2 待发货(或进入异常分支) | 需人工介入 | > **关键决策点**:`status=5` 时,`order_status` 是“待收货”还是直接“已完成”,取决于产品是否需要用户“确认收货”这一步。若不需要,可直接 `4`。 --- ### 3.3.2 派单依据(任务池可见性)的字段来源 `ml_delivery_drivers` 与 `ml_delivery_tasks` 中的以下字段是“任务池筛选/派单算法”的数据基础: - **服务区域**:`ml_delivery_drivers.service_areas`(JSONB),用于按区域过滤可接单骑手 - **实时位置**:`current_lat/current_lng`,用于距离排序/就近派单 - **工作状态**:`work_status`(在线/忙碌/离线),用于过滤可用骑手 - **任务状态**:`ml_delivery_tasks.status=1`,用于构建“待接单任务池” > 权限提示:若任务池需对骑手可见,需配合 RLS 或 RPC 实现“仅可看同区域且状态=1 的任务”。 --- ## 4. 状态机统一口径(必须统一的单一真相) ### 4.1 订单并行状态字段 `ml_orders` 存在三条并行状态线: - `order_status`:订单流程 - `payment_status`:支付/退款 - `shipping_status`:发货/物流 推荐统一驱动关系: - 支付成功驱动 `order_status` 进入“待发货”阶段 - 发货/配送接管驱动 `order_status` 进入“待收货”阶段 - 签收/确认收货驱动 `order_status` 完成 - 退款以 `payment_status` 为主线,同时影响 `order_status` 分支 ### 4.2 `order_status = 5` 的歧义 文档指出 `5` 在不同脚本存在“已取消/已取货”表述差异。 - 无自提流程:建议统一为“已取消” - 有自提流程:建议拆出独立状态值(避免取消与自提完成混用) --- ## 5. 读模型(各端典型查询视角) > 本节描述“应该怎么查”,不涉及具体实现。 ### 5.1 消费者端 - 商品列表/详情:优先基于商品详情视图(若存在)或 `ml_products`(上架商品) - 我的订单列表:`ml_orders.user_id = 当前用户` + 时间倒序 - 订单详情:`ml_orders` + `ml_order_items` - 配送进度:若需展示,则读取 `ml_delivery_tasks`(需权限策略或 RPC 支持) ### 5.2 商家端 - 我的商品:`ml_products.merchant_id = 当前商家` - 注意:若 `ml_products` 的 RLS select 仅允许 `status=1`,商家后台查看草稿/下架需额外策略或 RPC - 店铺订单:`ml_orders.merchant_id = 当前商家` + `ml_order_items` - 配送任务看板:按订单关联 `ml_delivery_tasks` > **现状风险(RLS)**:`ml_products_select_policy` 仅允许 `status=1`,会导致商家后台直查表时看不到自己的草稿/下架商品。建议扩展 RLS 或为商家后台提供专用 RPC。 ### 5.3 配送端 - 待接单任务池:`ml_delivery_tasks.status = 1`(通常需按服务区域过滤) - 我的任务:`ml_delivery_tasks.driver_id = 当前配送员` - 任务详情:最小化暴露订单/个人敏感信息(原则层面) --- ## 6. 权限边界(RLS / RPC / 前端守卫的闭环) ### 6.1 前端工程约束 - 数据访问唯一入口:必须通过 `services/` - 客户端路由守卫用于快速失败,但最终权限以数据库为准 ### 6.2 admin / analytics 的全局数据访问 按项目规范与策略文档: - 不建议对 admin/analytics 直接开放业务表全局 `SELECT` - 应通过 RPC(`SECURITY DEFINER` + 固定 `search_path` + 入口 `get_current_user_role()` 鉴权)返回最小必要字段/聚合数据 --- ## 7. 金额字段的归因与缺口(运费/优惠/抽佣) | 金额字段 | 数据来源 | 归因说明 | 现状缺口 | | --------------------------- | ----------------------------------------------------- | ------------------------------------------------- | --------------------------------------- | | `ml_orders.shipping_fee` | `ml_system_configs.shipping_fee`(或按距离/重量计算) | 配送费,可配置默认值或按规则计算 | 缺少运费规则表(如按区域/重量/距离) | | `ml_orders.discount_amount` | 优惠券/活动/满减 | 优惠金额,使用券时关联 `ml_user_coupons.order_id` | 缺少活动/满减规则表,复杂优惠需扩表 | | `ml_orders.total_amount` | 商品金额 + 运费 - 优惠 | 订单最终应付 | — | | `platform_commission` | `ml_system_configs.platform_commission`(比例) | 平台抽佣,通常在结算时计算 | 缺少结算单/分账流水表,抽佣未落结算流水 | > **结论**:金额归因在“配置 → 落表”层面基本可表达,但缺少结算/对账/复杂优惠的支撑表。 --- ## 8. 系统配置(system-settings)与“配置驱动流程”的现状说明 - DB 已存在:`ml_system_configs`,并在参考脚本中初始化了配置项(如 `shipping_fee`、`platform_commission`、`order_auto_confirm_days`)。 - 管理端页面现状:`pages/mall/admin/system-settings.uvue` 目前为占位页,仅展示 query 参数,未接入配置读写。 结论:配置承载表存在,但尚未形成“配置 → 业务流程”的实际驱动闭环。 --- ## 兼容性与风险 - **状态机风险**:三条并行状态字段若缺少统一约束,易出现互相矛盾的状态组合。 - **一致性风险**:库存扣减/冻结、配送送达与订单联动等关键一致性未在当前权威 SQL 中体现,需在应用层或后续 RPC/触发器补齐。 - **权限风险**:配送域 RLS/RPC 若未补齐,会导致配送端无法形成可运转的“接单→更新状态”闭环。 --- ## 回滚方案 本文仅新增文档,无业务变更;删除该 markdown 文件即可回滚。 --- ## 验证方式 - 打开本文档,核对引用路径均存在: - `docs/sql/*`、`docs/project_spec/*` - 与现有页面目录结构、角色字段口径(`ak_users.role`)一致。 --- ## 关联文档 - `docs/project_spec/AGENT_PROJECT_SPEC.md` - `docs/sql/02_relationships_er.md` - `docs/sql/03_enums_status_dict.md` - `docs/sql/07_business_workflows.md` - `docs/sql/11_roles_and_permissions_strategy.md`