1通道
10表
D0–D3决策门
全部决策门已布防
--:--:--
English
M3 · 最小闭环已交付

把自营店铺
跑成一条 fail-closed 的电商闭环

商品中心、内容、上架、订单与售后构成一条最小闭环。可插拔 ChannelAdapter 离线回放沙箱通道,live 通道在凭据到位前一律 fail-closed;所有金额与外部动作——上架、退款——都经 HTTP 交给 zeus 决策内核并等待人工审批。订单幂等,关键动作全程留痕,没做的功能绝不假装成功。

1 条完整闭环48 个测试全绿12 个 API 路由
运营控制台1 通道 · 离线沙箱
ZEUS 决策内核 · HTTP上架与退款在这里分级,本仓不本地分级
D3 publish  HELD 423 → APPROVED → channel.upsert
D2 refund   HELD 423 → APPROVED → channel.refund
kernel down  503 DECISION_UNAVAILABLE · fail-closed
通道注册表新增平台 = 加一个适配器
sandbox-douyin  ONLINE · offline replay
douyin live      FAIL-CLOSED · 422 CREDENTIAL_MISSING
审计台账 · commerce_events每个关键动作,可回放
listing.published  decision=D3 sku=SKU-DEMO-001
order.imported    ext=DY-SB-20261022-0001 1299 CNY idempotent=hit
refund.succeeded   decision=D2 ref=DY-SB-REFUND-5001
商品 / 订单流决策门 · zeus通道适配闭环完成熔断控制台为静态示意
完整闭环

一条订单,如何走完整条闭环

从商品建档到退款落账共五个工位。内容与通道都藏在端口后面;上架与退款这两个金额/外部动作,会在 zeus 决策门前挂起,直到人工审批放行。没有任何一步能绕过决策门。

  1. 01
    PRODUCT

    商品建档

    类目与 SPU/SKU 商品中心先校验标题、价格、币种与 skuCode 唯一性,合格后才往下游走。

  2. 02
    CONTENT

    内容产出

    M3 用确定性离线内容桩——禁词拦截、单次审核、永不自动确认;M4 在同一 ContentClient 端口后换成 loom 内容底座,调用方不变。

  3. 03D3 GATE
    LISTING

    上架过门

    内容提交 zeus 做 D3 外部动作决策,先返回 423 DECISION_HELD 挂起;只有人工审批通过后,才调用通道 upsert/publish。

  4. 04
    ORDER

    订单回传

    通道回传订单、订单中心落库,以 (channel, external_order_id) 幂等,回填 SKU 编码,order.imported 写入台账。

  5. 05D2 GATE
    REFUND

    退款过门

    退款金额只按订单行计算;D2 决策挂起,状态机按 requested → awaiting_approval → succeeded/rejected 流转,审批通过后才真正调用通道退款。

领域模块

一套代码,九个专注模块

每个模块只负责闭环上的一段,通过显式端口与其他模块通信。通道、决策与内容三条缝都是契约,接入 live 通道、loom 内容底座或另一家店铺都不用重写领域。

PRODUCT

商品中心

类目、SPU/SKU 与属性校验;skuCode 唯一、价格与币种合法才建档。

CONTENT

内容客户端

ContentClient 端口在 M3 提供确定性离线桩——禁词拦截、单次审核、永不自动确认;M4 换成 loom 内容底座,调用方不变。

CHANNEL

通道适配器

ChannelAdapter 五方法契约 + 注册表,新增平台就是加一个适配器。离线沙箱回放录制,live 通道在凭据到位前一律 fail-closed。

ORDER

订单中心

通道拉单、本地落库;(channel, external_order_id) 幂等,重复回放不会产生重复订单。

DECISION

决策端口

DecisionPort 经 zeus-client 走 HTTP,把金额与外部动作交给 zeus;本仓不做本地分级,zeus 不可达即返回 503。

PUBLISHING

上架编排

内容 → D3 决策 → 人工审批 → 通道 upsert/publish,外部动作的每一步都按顺序显式发生。

AFTERSALE

退款状态机

requested → awaiting_approval → succeeded/rejected;驳回留痕,审批通过后才调用通道退款。

FULFILLMENT

履约与支付占位

库存手工维护;发货与支付在 M3 显式返回 501 NOT_IMPLEMENTED_PLACEHOLDER,不伪造成功。

AUDIT

审计台账

commerce_events 记录全部关键动作——决策请求、上架、订单导入、退款流转,可回放、可追溯。

工程承诺

为 fail-closed 而设计,而不是 fail-open

电商要动钱、要触发真实外部动作。Commerce OS 宁可拒绝并返回精确错误,也不执行任何无法授权的事。下面四条承诺由代码和测试强制保证。

FAIL-CLOSED1

默认熔断,而非默认放行

未注册通道拒绝调用;live 通道缺 credentialRef 直接 422 CREDENTIAL_MISSING;zeus 不可达返回 503 DECISION_UNAVAILABLE。任何无法授权的金额或外部动作都不会发生。

DECISION EXTERNALIZED2

分级决策,一律外移给 zeus

本仓不做本地分级。上架(D3)、退款(D2)等所有金额与外部动作都经 HTTP 交给决策内核;D3/D2 先返回 423 DECISION_HELD,等待人工审批。

NO FAKE SUCCESS3

没做的显式 501,不假装成功

支付与履约在 M3 显式占位,返回 501 NOT_IMPLEMENTED_PLACEHOLDER;内容是离线桩而不是模型。占位是明确的产品口径,不是静默 mock。

IDEMPOTENT & AUDITED4

幂等落库,全程留痕

订单按 (channel, external_order_id) 去重,重放安全;决策请求、上架、订单导入、退款流转都写入 commerce_events,与 zeus decision 记录一一对应。

架构

面向端口的分层,方言只在存储层

HTTP v1 路由、组合根、领域模块与三组端口。存储同时支持 SQLite 和 PostgreSQL,方言锁在存储层,迁移文件按编号双方言配对。

L1

运行时与质量门

Node ≥22、TypeScript strict(noUncheckedIndexedAccess、exactOptionalPropertyTypes)、Vitest 48 用例,含经假 zeus HTTP 服务器的真实 zeus-client 链路与 GATE-M3 全链路 e2e。

L2

双方言存储

本地用内置 node:sqlite 零依赖,生产用 PostgreSQL;sqlite/pg 迁移按编号配对,由 check:migrations 强校验。

L3

三组端口

ChannelAdapter(五方法)、DecisionPort(zeus-client)、ContentClient(M3 桩 → M4 loom)。

L4

领域模块

storage · channel · product · order · decision · content · publishing · aftersale · fulfillment。

L5

组合根 · services.ts

在装配处注入 DecisionPort、ContentClient 与通道注册表,领域模块只依赖端口。

L6

HTTP v1 · Hono

12 个路由,统一错误体 { error: { code, message, retryable, details? } },错误码与 HTTP 映射集中管理。

部署
开源 · 自托管

几分钟内,在本机跑通整条闭环

无需任何 live 凭据:沙箱通道回放录制好的 fixtures,假 zeus 决策链路与 GATE-M3 端到端测试证明整条闭环;默认 SQLite,上生产再换 PostgreSQL。

  • 48 个测试全绿:真实 zeus-client 经假 zeus HTTP 服务器走完整决策链路,外加 GATE-M3 全链路 e2e。
  • 默认 SQLite(内置 node:sqlite),生产 PostgreSQL,迁移文件双方言配对。
  • 沙箱通道离线回放,不触网、不要密钥;一条 1299 CNY 演示订单跑完上架、回传与退款。
  • live 通道、模型 key、支付与履约在你接通之前全部 fail-closed / 501,绝不假装成功。
快速开始:8787
# clone + install
$ git clone https://github.com/bayernjf/commerce-os.git commerce-os
$ cd commerce-os && npm install
# migrate the local SQLite store
$ npm run migrate:up
# start — http://127.0.0.1:8787
$ npm start

M3 里程碑产物。live 通道需资质与密钥;M4 内容由 loom 内容底座提供。