Add order-fulfillment module: Spring Modulith 2.1 boundary enforcement, events, generated docs
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# order-fulfillment
|
||||
|
||||
Companion code for *[Spring Modulith 2.1: Enforcing Module Boundaries Inside a Spring Boot Monolith](https://ankurm.com)* on [ankurm.com](https://ankurm.com).
|
||||
|
||||
A 4-module Spring Boot monolith — `order`, `inventory`, `shipping`, `notification` — verified
|
||||
with Spring Modulith's `ApplicationModules.verify()`. Everything in the post was produced by
|
||||
actually running this code; see `output/` for every captured transcript, in order.
|
||||
|
||||
## Versions
|
||||
|
||||
| Artifact | Version |
|
||||
|---|---|
|
||||
| Spring Boot | 4.1.1 |
|
||||
| Spring Modulith | 2.1.1 (current GA; 2.2 exists only as milestones as of this writing — verified against Maven Central's `maven-metadata.xml`, not the project's own `<release>` tag, which has pointed at a milestone before) |
|
||||
| JDK | 25 (LTS) |
|
||||
| H2 | 2.4.240 (in-memory, for the demo only) |
|
||||
|
||||
## Quickstart
|
||||
|
||||
```
|
||||
mvn -pl order-fulfillment -am test
|
||||
```
|
||||
|
||||
Runs the module-boundary verification, the documentation generator, and the full
|
||||
`order → inventory → shipping → notification` event-cascade integration test.
|
||||
|
||||
To run the app itself:
|
||||
|
||||
```
|
||||
mvn -pl order-fulfillment -am spring-boot:run
|
||||
```
|
||||
|
||||
```
|
||||
curl -X POST "http://localhost:8080/orders?sku=WIDGET-1&quantity=3"
|
||||
curl "http://localhost:8080/orders/1"
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
| Module | Public API | Internal | Listens for |
|
||||
|---|---|---|---|
|
||||
| `order` | `OrderManagement`, `OrderController` | `internal.Order`, `internal.OrderRepository` | — |
|
||||
| `inventory` | `InventoryManagement` | `internal.Stock`, `internal.StockRepository`, `internal.StockSeeder` | `OrderPlaced` |
|
||||
| `shipping` | `ShippingManagement` | `internal.Shipment`, `internal.ShipmentRepository` | `StockReserved` |
|
||||
| `notification` | `NotificationManagement` | `internal.Notification`, `internal.NotificationRepository` | `OrderPlaced`, `ShipmentScheduled` |
|
||||
|
||||
`order` has zero module dependencies — on purpose. See the Javadoc on `OrderManagement`
|
||||
for why, and `output/03-cycle-via-public-api-still-failed.txt` for what happens the first
|
||||
time that seems like a good idea to "fix" by adding one back.
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Method | Path | Description |
|
||||
|---|---|---|
|
||||
| `POST` | `/orders?sku={sku}&quantity={n}` | Place an order |
|
||||
| `GET` | `/orders/{id}` | Fetch an order |
|
||||
|
||||
## Captured output (`output/`)
|
||||
|
||||
Every number and every stack trace in the post traces to one of these, byte for byte:
|
||||
|
||||
| File | What it captures |
|
||||
|---|---|
|
||||
| `00-table-name-collision.txt` | H2 rejecting `CREATE TABLE order` — `ORDER` is a reserved word |
|
||||
| `01-verify-violation-failed.txt` | `ApplicationModules.verify()` failing on a direct reference to `inventory.internal.StockRepository` — both a cycle and a non-exposed-type violation |
|
||||
| `02-verify-passed.txt` | The same test, green, after removing the dependency on `inventory` entirely |
|
||||
| `03-cycle-via-public-api-still-failed.txt` | Why routing the same call through `InventoryManagement` (the real public API) still fails — a cycle isn't a visibility problem |
|
||||
| `04-event-flow-missing-dependency.txt` | `@ApplicationModuleTest(mode = ALL_DEPENDENCIES)` bootstrapping *zero* other modules for `order`, because `order` has no outgoing dependencies, and the resulting event-cascade test timing out |
|
||||
| `05-redundant-transactional-failure.txt` | Stacking a plain `@Transactional` on top of `@ApplicationModuleListener` failing bean registration outright |
|
||||
| `06-event-flow-passed.txt` | The full `order → inventory → shipping → notification` cascade, fixed, with both notification hops firing |
|
||||
| `07-generated-docs.txt` | The real output of `Documenter.writeModulesAsPlantUml().writeModuleCanvases()...` — the PlantUML component diagram and per-module canvases this repo's own structure produces |
|
||||
| `08-javap-listener-meta-annotations.txt` | `javap -v` on the compiled `@ApplicationModuleListener` class, showing its real meta-annotations (`@Async` + `@Transactional(REQUIRES_NEW)` + `@TransactionalEventListener`) |
|
||||
|
||||
No `docs/` chapter directory in this repository — the intermediate and reference-depth
|
||||
material that would normally live there is in accordion sections inside the WordPress
|
||||
post itself.
|
||||
Reference in New Issue
Block a user