Skip to content

feat(example): add the ddk-mall reference application with the order context - #74

Merged
poppycoderr merged 3 commits into
mainfrom
feat/mall-order
Oct 2, 2026
Merged

poppycoderr merged 3 commits into
mainfrom
feat/mall-order

Conversation

@poppycoderr

Copy link
Copy Markdown
Owner

Background

DDK has thirteen starters and one small example with a single-table aggregate. Locks, scheduled jobs, reliable events and the operator context have never been used together in one business flow. ddk-mall is the reference application that does this: place an order, reserve stock, pay, and cancel on timeout, across order, inventory and payment contexts. It is built in six steps; this PR is the first.

Changes

  • New module ddk-examples/ddk-mall: one deployable application, one top-level package per bounded context, four layers inside each.
  • The order context: place an order, read it, list a customer's orders, cancel.
  • platform: the customer identity comes from the X-Customer-Id header through an OperatorResolver; the example has no login.
  • Flyway migrations for the order, order line and product tables, with three seeded products.
  • docker-compose.yml with MySQL and a mysql profile; the default profile runs on in-memory H2.
com.example.mall
├── MallApplication
├── platform                 # customer identity from the request header
└── order
    ├── adapter/controller   # POST /orders, GET /orders/{id}, POST /orders/page, POST /orders/{id}/cancel
    ├── application          # OrderService, commands, query, response, event handler
    ├── domain               # Order (aggregate), OrderLine, Money, events, errors, ports
    └── infrastructure       # repository with a child table, converters, product catalog, id generator

Design decisions:

  • The order is saved and loaded as a whole. OrderRepositoryImpl uses the repository extension points added in the previous PR for the order line table; the application layer never sees it.
  • Prices are not taken from the request. The command carries SKUs and quantities; name and unit price come from the ProductCatalog port and are stored on the order line as a snapshot.
  • Someone else's order is reported as not found, so an order number does not reveal whether it exists.
  • Contexts may not reference each other. ArchitectureTest adds a slices rule over order, inventory and payment next to DDK's layer rules. It has nothing to check yet and starts to matter in step 2.

One test runs against a real MySQL through DdkContainers.mysql(): the migrations apply, an order round-trips with its lines, and a stale order cannot overwrite a newer one.


背景

DDK 有 13 个 starter,却只有一个很小的示例,聚合也只对应一张表。聚合锁、定时任务、可靠事件、操作者上下文从来没有在同一个业务流程里一起用过。ddk-mall 就是做这件事的参考应用:下单、预占库存、支付、超时取消,跨订单、库存、支付三个上下文。它分六步建设,本 PR 是第一步。

改动

  • 新增模块 ddk-examples/ddk-mall:一个可部署应用,每个限界上下文一个顶层包,内部是四层结构。
  • 订单上下文:下单、查询、查询顾客的订单列表、取消。
  • platform:顾客身份通过 OperatorResolver 取自请求头 X-Customer-Id,示例不做登录。
  • Flyway 迁移脚本:订单、订单行、商品三张表,并预置三件商品。
  • docker-compose.yml(MySQL)与 mysql profile;默认 profile 用内存 H2。

包结构见上文。设计取舍:

  • 订单作为一个整体保存和加载。 OrderRepositoryImpl 用上一个 PR 新增的仓储扩展点处理订单行表,应用层看不到它。
  • 价格不取自请求。 命令里只有 SKU 和数量,名称与单价来自 ProductCatalog 端口,并作为快照存在订单行上。
  • 别人的订单按不存在处理,订单号不会泄露它是否存在。
  • 上下文之间不能互相引用。 ArchitectureTest 在 DDK 的分层规则之外,加了一条针对 order、inventory、payment 的切片规则。现在还没有可检查的内容,第 2 步开始起作用。

有一个测试通过 DdkContainers.mysql() 连接真实的 MySQL:迁移脚本可以执行,订单连同订单行完整读写,过期的订单不能覆盖新的。

@poppycoderr
poppycoderr merged commit a9d6b77 into main Oct 2, 2026
4 checks passed
@poppycoderr
poppycoderr deleted the feat/mall-order branch October 2, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant