# 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 `` 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.