交易系统 2026-07-15 112 次浏览

零售电商不是网上商城:人、货、场与全渠道版图

全渠道零售不是多做几个客户端,而是让顾客、商品、库存和服务承诺跨渠道连续流动。本文从渠道、库存节点和履约方式三个维度建立系统边界。

01. 零售电商不是网上商城:人、货、场与全渠道版图

本篇目标:建立全渠道零售系统边界,区分顾客旅程、销售渠道、库存节点和履约方式。读完后,你应该能够解释:为什么“增加一个小程序”不是简单增加一个前端,为什么“门店”也不能只建模成一个渠道。

很多电商架构图的起点都是商城首页、购物车和订单。它们很容易让人产生一个错觉:零售电商就是把线下商品搬到线上,再用微服务把模块拆开。

真正的全渠道零售并不是多做几个客户端,而是让顾客、商品、库存和服务承诺可以跨渠道连续流动。顾客在 App 领取优惠券,在门店试用商品,通过小程序下单,由前置仓发货,最后又到门店退货。这个过程只发生了一次消费决策,却经过多个数字入口、物理节点和履约方式。

1. 业务场景与真实矛盾

先看一个普通的购买过程:顾客在通勤时通过 App 看到商品,到附近门店查看实物,晚上通过小程序下单,选择第二天到店自提。取货时发现规格不合适,又在门店完成退货。

对顾客来说,这是一次连续旅程;对系统来说,至少涉及会员、商品、渠道展示、价格、营销、门店、库存、订单、支付、履约和售后。

全渠道顾客旅程

这里存在三组不能被“一套逻辑统一掉”的矛盾:

  • 统一体验与渠道经营差异。 顾客希望会员、订单和售后连续;运营又希望 App、门店和小程序拥有不同商品、价格与活动。
  • 统一库存视图与物理库存分散。 前台希望回答“现在能不能买”,但库存实际分布在中心仓、前置仓和门店,且不断被线上订单、POS 销售和调拨改变。
  • 统一订单视图与多种履约过程。 顾客只想查看一个订单,后台却可能拆成快递、即时配送和到店自提等多个履约任务。

架构设计的关键不是消灭这些差异,而是明确哪些事实应该统一、哪些策略允许变化。

2. 错误或初始方案

最常见的第一种方案是“一个渠道一套商城”。App、小程序和 POS 分别拥有商品、价格、购物车和订单逻辑。它上线快,但很快会出现三份会员、三份促销判断和三套售后状态。一次业务调整需要多个团队同步发布,任何遗漏都会形成渠道差异。

第二种方案走向另一个极端:所有客户端共用一个万能接口,所有差异通过 if channel == ... 实现。渠道增加后,商品、订单和营销服务里到处都是条件分支。一个只影响门店的规则,也可能迫使整个交易核心重新发布。

第三种误区是把门店只当作渠道。门店实际上可能同时扮演三种角色:

  1. 顾客完成购买的销售渠道;
  2. 保存实物商品的库存节点;
  3. 执行拣货、自提或退货的履约节点。

如果系统里只有一个 storeId,后续很难判断它究竟表达成交归属、库存位置还是作业责任。

3. 领域模型与关键约束

全渠道架构至少需要分清以下概念:

  • 顾客(Customer):一次访问或交易行为的主体,可以是游客。
  • 会员(Member):顾客在会员体系中的身份、等级与权益。
  • 销售渠道(Sales Channel):商品呈现、交易准入和经营策略发生的入口。
  • 库存节点(Inventory Node):实际核算库存的位置,例如中心仓、前置仓或门店。
  • 履约节点(Fulfillment Node):执行拣货、出库、自提、退货等动作的责任单位。
  • 履约方式(Fulfillment Mode):快递、即时配送、到店自提或门店现货销售。

渠道、库存节点与履约方式

这些概念可以引用同一个门店标识,但必须拥有独立角色。核心约束是:

  • SKU 的物理身份由商品域管理,渠道只能决定如何展示和是否允许销售。
  • 可售量由库存域计算,渠道不能自行维护一个无法核对的库存数字。
  • 履约承诺由履约能力和库存共同决定,不能只看顾客选择的渠道。
  • 下单后需要保存渠道、价格、商品和履约承诺的关键快照,历史订单不能被后续配置修改。

4. 候选架构及取舍

更合适的结构是“共享业务能力 + 渠道体验层”。商品、价格、营销、库存、订单和履约提供稳定业务能力;每个渠道通过 BFF 或体验层组合页面数据、处理客户端协议,并应用少量渠道展示策略。

渠道体验层可以决定首页布局、文案、图片尺寸和交互步骤,但不能绕过核心域创建订单、扣减库存或核销优惠。需要进入业务核心的渠道差异,必须通过明确的上下文传递,而不是隐藏在请求头或散落的条件判断中。

这个选择也有代价:

方案优点主要代价适用情况
渠道独立商城初期交付快、团队自治规则复制、数据漂移渠道业务完全独立
统一万能接口复用率高条件分支膨胀、发布耦合渠道差异极小
共享能力 + BFF核心一致、体验可变需要治理能力边界全渠道零售主线

课程后续采用第三种方案,但不会一开始就把每项能力拆成微服务。边界首先体现在语言、数据所有权和代码模块上,独立部署要由扩缩容、故障隔离或团队自治等证据驱动。

5. Java/Spring 关键实现或伪代码

渠道差异首先通过显式上下文进入应用层:

public record SalesContext(
        ChannelId channel,
        StoreId salesStore,
        CustomerId customer,
        RegionId region,
        FulfillmentMode requestedMode) {
}

public interface ChannelPolicy {
    Eligibility check(SalesContext context, SkuId sku);
}

SalesContext 表示本次销售决策的上下文,不是订单事实。订单受理后,需要把其中真正影响成交的内容转换为不可变快照:

public record SalesSnapshot(
        ChannelId channel,
        StoreId salesStore,
        RegionId region,
        String policyVersion) {
}

注意两个边界:BFF 可以组装商品详情,但不能直接读取商品、价格和库存三套数据库;渠道策略可以拒绝某渠道销售某 SKU,但不能直接修改商品的全局发布状态。

6. 故障推演、验收题和架构产物

故障推演

假设小程序 BFF 完全不可用,回答以下问题:

  • App 和 POS 是否仍能销售?如果不能,说明哪些能力被错误共享了故障边界?
  • 商品、库存或订单核心能力故障时,三个渠道分别应该拒绝、降级还是只读?
  • 门店网络中断时,是否允许离线成交?允许的话,库存风险由谁承担、何时对账?

验收题

  1. 为什么门店不能只建模为销售渠道?请给出同一家门店同时承担三种角色的例子。
  2. 哪些渠道差异应该停留在 BFF,哪些必须进入核心域?判断依据是什么?
  3. “统一库存”是否意味着所有仓店共用一张库存表?为什么?

架构产物

绘制自己的全渠道零售版图,至少包含顾客、会员、三个销售渠道、三类库存节点和三种履约方式。每条连线标注它传递的是命令、查询还是业务事件,并写出一份 ADR:为什么选择“共享能力 + 渠道体验层”。

下一篇将沿着这张版图追踪一笔订单,找出哪些步骤必须同步完成,哪些步骤应该通过事件异步推进。