零售电商不是网上商城:人、货、场与全渠道版图
全渠道零售不是多做几个客户端,而是让顾客、商品、库存和服务承诺跨渠道连续流动。本文从渠道、库存节点和履约方式三个维度建立系统边界。
01. 零售电商不是网上商城:人、货、场与全渠道版图
本篇目标:建立全渠道零售系统边界,区分顾客旅程、销售渠道、库存节点和履约方式。读完后,你应该能够解释:为什么“增加一个小程序”不是简单增加一个前端,为什么“门店”也不能只建模成一个渠道。
很多电商架构图的起点都是商城首页、购物车和订单。它们很容易让人产生一个错觉:零售电商就是把线下商品搬到线上,再用微服务把模块拆开。
真正的全渠道零售并不是多做几个客户端,而是让顾客、商品、库存和服务承诺可以跨渠道连续流动。顾客在 App 领取优惠券,在门店试用商品,通过小程序下单,由前置仓发货,最后又到门店退货。这个过程只发生了一次消费决策,却经过多个数字入口、物理节点和履约方式。
1. 业务场景与真实矛盾
先看一个普通的购买过程:顾客在通勤时通过 App 看到商品,到附近门店查看实物,晚上通过小程序下单,选择第二天到店自提。取货时发现规格不合适,又在门店完成退货。
对顾客来说,这是一次连续旅程;对系统来说,至少涉及会员、商品、渠道展示、价格、营销、门店、库存、订单、支付、履约和售后。

这里存在三组不能被“一套逻辑统一掉”的矛盾:
- 统一体验与渠道经营差异。 顾客希望会员、订单和售后连续;运营又希望 App、门店和小程序拥有不同商品、价格与活动。
- 统一库存视图与物理库存分散。 前台希望回答“现在能不能买”,但库存实际分布在中心仓、前置仓和门店,且不断被线上订单、POS 销售和调拨改变。
- 统一订单视图与多种履约过程。 顾客只想查看一个订单,后台却可能拆成快递、即时配送和到店自提等多个履约任务。
架构设计的关键不是消灭这些差异,而是明确哪些事实应该统一、哪些策略允许变化。
2. 错误或初始方案
最常见的第一种方案是“一个渠道一套商城”。App、小程序和 POS 分别拥有商品、价格、购物车和订单逻辑。它上线快,但很快会出现三份会员、三份促销判断和三套售后状态。一次业务调整需要多个团队同步发布,任何遗漏都会形成渠道差异。
第二种方案走向另一个极端:所有客户端共用一个万能接口,所有差异通过 if channel == ... 实现。渠道增加后,商品、订单和营销服务里到处都是条件分支。一个只影响门店的规则,也可能迫使整个交易核心重新发布。
第三种误区是把门店只当作渠道。门店实际上可能同时扮演三种角色:
- 顾客完成购买的销售渠道;
- 保存实物商品的库存节点;
- 执行拣货、自提或退货的履约节点。
如果系统里只有一个 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 是否仍能销售?如果不能,说明哪些能力被错误共享了故障边界?
- 商品、库存或订单核心能力故障时,三个渠道分别应该拒绝、降级还是只读?
- 门店网络中断时,是否允许离线成交?允许的话,库存风险由谁承担、何时对账?
验收题
- 为什么门店不能只建模为销售渠道?请给出同一家门店同时承担三种角色的例子。
- 哪些渠道差异应该停留在 BFF,哪些必须进入核心域?判断依据是什么?
- “统一库存”是否意味着所有仓店共用一张库存表?为什么?
架构产物
绘制自己的全渠道零售版图,至少包含顾客、会员、三个销售渠道、三类库存节点和三种履约方式。每条连线标注它传递的是命令、查询还是业务事件,并写出一份 ADR:为什么选择“共享能力 + 渠道体验层”。
下一篇将沿着这张版图追踪一笔订单,找出哪些步骤必须同步完成,哪些步骤应该通过事件异步推进。