@rashidee/co2 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/dist/index.js +25449 -0
  2. package/drizzle/0000_remarkable_charles_xavier.sql +210 -0
  3. package/drizzle/0001_wise_wolf_cub.sql +13 -0
  4. package/drizzle/0002_secret_spyke.sql +16 -0
  5. package/drizzle/0003_workspace_config_singleton.sql +16 -0
  6. package/drizzle/0004_terminal_claim_v120.sql +11 -0
  7. package/drizzle/0005_brainstorm_v124.sql +10 -0
  8. package/drizzle/0006_project_v140.sql +6 -0
  9. package/drizzle/0007_prd_wizard_v124.sql +14 -0
  10. package/drizzle/0008_workflow_artifact_v126.sql +24 -0
  11. package/drizzle/0009_project_import_v150.sql +7 -0
  12. package/drizzle/0010_quality_v151.sql +3 -0
  13. package/drizzle/meta/0000_snapshot.json +1335 -0
  14. package/drizzle/meta/0001_snapshot.json +1416 -0
  15. package/drizzle/meta/0002_snapshot.json +1510 -0
  16. package/drizzle/meta/_journal.json +83 -0
  17. package/package.json +41 -0
  18. package/plugin/.claude-plugin/marketplace.json +36 -0
  19. package/plugin/.claude-plugin/plugin.json +22 -0
  20. package/plugin/README.md +625 -0
  21. package/plugin/SKILLS.md +350 -0
  22. package/plugin/co2.svg +5 -0
  23. package/plugin/commands/brainstorm-loop.md +129 -0
  24. package/plugin/skills/conductor-defect/SKILL.md +898 -0
  25. package/plugin/skills/conductor-feature-develop/SKILL.md +1383 -0
  26. package/plugin/skills/conductor-feature-develop/references/implementation-domain-template.md +131 -0
  27. package/plugin/skills/conductor-feature-develop/references/implementation-master-template.md +89 -0
  28. package/plugin/skills/conductor-feature-develop/references/playwright-setup.md +224 -0
  29. package/plugin/skills/conductor-feature-prepare/SKILL.md +604 -0
  30. package/plugin/skills/depgen-k8s/SKILL.md +468 -0
  31. package/plugin/skills/depgen-k8s/references/dockerfile-laravel.md +197 -0
  32. package/plugin/skills/depgen-k8s/references/dockerfile-nodejs.md +163 -0
  33. package/plugin/skills/depgen-k8s/references/dockerfile-spring-boot.md +174 -0
  34. package/plugin/skills/depgen-k8s/references/k8s-patterns.md +869 -0
  35. package/plugin/skills/mockgen-shadcn/SKILL.md +1067 -0
  36. package/plugin/skills/mockgen-shadcn/references/admin-layout-template.md +1467 -0
  37. package/plugin/skills/mockgen-shadcn/references/mockup-hub-template.md +498 -0
  38. package/plugin/skills/mockgen-shadcn/references/mockup-index-template.md +216 -0
  39. package/plugin/skills/mockgen-tailwind/SKILL.md +904 -0
  40. package/plugin/skills/mockgen-tailwind/references/admin-layout-template.md +720 -0
  41. package/plugin/skills/mockgen-tailwind/references/mockup-hub-template.md +498 -0
  42. package/plugin/skills/mockgen-tailwind/references/mockup-index-template.md +190 -0
  43. package/plugin/skills/modelgen-nosql/SKILL.md +617 -0
  44. package/plugin/skills/modelgen-nosql/references/model-extraction-methodology.md +497 -0
  45. package/plugin/skills/modelgen-nosql/references/nosql-design-guide.md +258 -0
  46. package/plugin/skills/modelgen-relational/SKILL.md +707 -0
  47. package/plugin/skills/modelgen-relational/references/model-extraction-methodology.md +499 -0
  48. package/plugin/skills/specgen-flutter-riverpod/SKILL.md +898 -0
  49. package/plugin/skills/specgen-flutter-riverpod/references/component-patterns.md +971 -0
  50. package/plugin/skills/specgen-flutter-riverpod/references/notification-patterns.md +457 -0
  51. package/plugin/skills/specgen-flutter-riverpod/references/routing-patterns.md +362 -0
  52. package/plugin/skills/specgen-flutter-riverpod/references/security-patterns.md +709 -0
  53. package/plugin/skills/specgen-flutter-riverpod/references/spec-template.md +1566 -0
  54. package/plugin/skills/specgen-flutter-riverpod/references/state-patterns.md +518 -0
  55. package/plugin/skills/specgen-flutter-riverpod/references/storage-patterns.md +370 -0
  56. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/SKILL.md +984 -0
  57. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/batch-patterns.md +359 -0
  58. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/messaging-patterns.md +468 -0
  59. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/modulith-patterns.md +461 -0
  60. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/reporting-patterns.md +803 -0
  61. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/security-patterns.md +501 -0
  62. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/spec-template.md +1268 -0
  63. package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/web-patterns.md +301 -0
  64. package/plugin/skills/specgen-node-cli-web/SKILL.md +561 -0
  65. package/plugin/skills/specgen-node-cli-web/references/auth-patterns.md +293 -0
  66. package/plugin/skills/specgen-node-cli-web/references/cli-packaging-patterns.md +250 -0
  67. package/plugin/skills/specgen-node-cli-web/references/server-patterns.md +247 -0
  68. package/plugin/skills/specgen-node-cli-web/references/spec-template.md +401 -0
  69. package/plugin/skills/specgen-node-cli-web/references/testing-patterns.md +174 -0
  70. package/plugin/skills/specgen-react-mui/SKILL.md +789 -0
  71. package/plugin/skills/specgen-react-mui/references/component-patterns.md +1077 -0
  72. package/plugin/skills/specgen-react-mui/references/reporting-patterns.md +1998 -0
  73. package/plugin/skills/specgen-react-mui/references/routing-patterns.md +461 -0
  74. package/plugin/skills/specgen-react-mui/references/security-patterns.md +599 -0
  75. package/plugin/skills/specgen-react-mui/references/spec-template.md +1030 -0
  76. package/plugin/skills/specgen-react-mui/references/state-patterns.md +327 -0
  77. package/plugin/skills/specgen-react-tailwind/SKILL.md +859 -0
  78. package/plugin/skills/specgen-react-tailwind/references/component-patterns.md +1212 -0
  79. package/plugin/skills/specgen-react-tailwind/references/reporting-patterns.md +1529 -0
  80. package/plugin/skills/specgen-react-tailwind/references/routing-patterns.md +669 -0
  81. package/plugin/skills/specgen-react-tailwind/references/security-patterns.md +656 -0
  82. package/plugin/skills/specgen-react-tailwind/references/spec-template.md +1237 -0
  83. package/plugin/skills/specgen-react-tailwind/references/state-patterns.md +327 -0
  84. package/plugin/skills/specgen-sdk-java/SKILL.md +933 -0
  85. package/plugin/skills/specgen-sdk-java/references/api-extraction-patterns.md +247 -0
  86. package/plugin/skills/specgen-sdk-java/references/http-client-patterns.md +495 -0
  87. package/plugin/skills/specgen-sdk-java/references/packaging-patterns.md +366 -0
  88. package/plugin/skills/specgen-sdk-java/references/spec-template.md +956 -0
  89. package/plugin/skills/specgen-spring-jpa-jtehtmx/SKILL.md +1284 -0
  90. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/batch-patterns.md +1224 -0
  91. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/jasper-patterns.md +1638 -0
  92. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/messaging-patterns.md +512 -0
  93. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/modulith-patterns.md +354 -0
  94. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/security-patterns.md +551 -0
  95. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/spec-template.md +2502 -0
  96. package/plugin/skills/specgen-spring-jpa-jtehtmx/references/web-patterns.md +503 -0
  97. package/plugin/skills/specgen-spring-jpa-restapi/SKILL.md +990 -0
  98. package/plugin/skills/specgen-spring-jpa-restapi/references/batch-patterns.md +1224 -0
  99. package/plugin/skills/specgen-spring-jpa-restapi/references/messaging-patterns.md +512 -0
  100. package/plugin/skills/specgen-spring-jpa-restapi/references/modulith-patterns.md +279 -0
  101. package/plugin/skills/specgen-spring-jpa-restapi/references/reporting-patterns.md +1536 -0
  102. package/plugin/skills/specgen-spring-jpa-restapi/references/restapi-patterns.md +722 -0
  103. package/plugin/skills/specgen-spring-jpa-restapi/references/security-patterns.md +351 -0
  104. package/plugin/skills/specgen-spring-jpa-restapi/references/spec-template.md +553 -0
  105. package/plugin/skills/specgen-ts-cli/SKILL.md +861 -0
  106. package/plugin/skills/specgen-ts-cli/references/async-patterns.md +1101 -0
  107. package/plugin/skills/specgen-ts-cli/references/command-patterns.md +383 -0
  108. package/plugin/skills/specgen-ts-cli/references/config-patterns.md +430 -0
  109. package/plugin/skills/specgen-ts-cli/references/database-patterns.md +750 -0
  110. package/plugin/skills/specgen-ts-cli/references/packaging-patterns.md +426 -0
  111. package/plugin/skills/specgen-ts-cli/references/spec-template.md +1391 -0
  112. package/plugin/skills/specgen-ts-cli/references/testing-patterns.md +909 -0
  113. package/plugin/skills/testgen-functional/SKILL.md +1381 -0
  114. package/plugin/skills/tracegen-matrix/SKILL.md +243 -0
  115. package/plugin/skills/util-preparek8senv/SKILL.md +422 -0
  116. package/plugin/skills/util-projectinit/SKILL.md +307 -0
  117. package/plugin/skills/util-projectinit/reference/brainstorm-loop.md +129 -0
  118. package/plugin/skills/util-projectinit/reference/brainstorm-protocol.md +144 -0
  119. package/plugin/skills/util-projectinit/reference/brainstorm-setup-guide.md +153 -0
  120. package/plugin/skills/util-projectinit/reference/brainstorm-template-appdev.md +87 -0
  121. package/plugin/skills/util-projectinit/reference/co2-context-generation-guide.md +761 -0
  122. package/plugin/skills/util-projectsync/SKILL.md +501 -0
  123. package/plugin/skills/util-updprd/SKILL.md +324 -0
  124. package/plugin/skills/util-usanalyzer/SKILL.md +307 -0
  125. package/plugin/skills/util-ustagger/SKILL.md +154 -0
  126. package/static/assets/abnfDiagram-VRR7QNED-DvPuwyCV.js +1 -0
  127. package/static/assets/arc-DRKw7sjs.js +1 -0
  128. package/static/assets/architectureDiagram-ZJ3FMSHR-CaNcxUbC.js +36 -0
  129. package/static/assets/blockDiagram-677ZJIJ3-Demd4AOK.js +132 -0
  130. package/static/assets/c4Diagram-LMCZKHZV-PVKUfc2x.js +10 -0
  131. package/static/assets/channel-C2nVbuwv.js +1 -0
  132. package/static/assets/chunk-2Q5K7J3B-CExf8ww_.js +1 -0
  133. package/static/assets/chunk-32BRIVSS-CFPaoONF.js +1 -0
  134. package/static/assets/chunk-5VM5RSS4-DE2esM67.js +15 -0
  135. package/static/assets/chunk-EX3LRPZG-SON_YdDG.js +231 -0
  136. package/static/assets/chunk-JWPE2WC7-Qxah8LNr.js +1 -0
  137. package/static/assets/chunk-MOJQB5TN-BcWGQV3j.js +88 -0
  138. package/static/assets/chunk-RYQCIY6F-DkDj-OR5.js +1 -0
  139. package/static/assets/chunk-V7JOEXUC-BlI1Mrah.js +206 -0
  140. package/static/assets/chunk-VR4S4FIN-Agf__duj.js +1 -0
  141. package/static/assets/chunk-XXDRQBXY-B5CfAh85.js +1 -0
  142. package/static/assets/classDiagram-OUVF2IWQ-DXJIljsR.js +1 -0
  143. package/static/assets/classDiagram-v2-EOCWNBFH-DXJIljsR.js +1 -0
  144. package/static/assets/cose-bilkent-JH36ORCC-DO0cQkcy.js +1 -0
  145. package/static/assets/cynefin-VYW2F7L2-CfOnsnXc.js +178 -0
  146. package/static/assets/cynefinDiagram-TSTJHNR4-BJ8tULAv.js +62 -0
  147. package/static/assets/cytoscape.esm-DTSO7Bv0.js +331 -0
  148. package/static/assets/dagre-VKFMJZFB-DfjwzHqP.js +4 -0
  149. package/static/assets/defaultLocale-DX6XiGOO.js +1 -0
  150. package/static/assets/diagram-FQU43EPY-CndSOIIM.js +3 -0
  151. package/static/assets/diagram-G47NLZAW-Czf5hN0Z.js +24 -0
  152. package/static/assets/diagram-NH7WQ7WH-COAyojGh.js +24 -0
  153. package/static/assets/diagram-OA4YK3LP-H8PoiN2m.js +30 -0
  154. package/static/assets/diagram-WEI45ONY-DzcaVzjp.js +41 -0
  155. package/static/assets/ebnfDiagram-CCIWWBDH-DPazGYLJ.js +1 -0
  156. package/static/assets/erDiagram-Q63AITRT-Bo-fubgF.js +85 -0
  157. package/static/assets/flowDiagram-23GEKE2U-CSvxUDwh.js +156 -0
  158. package/static/assets/ganttDiagram-NO4QXBWP-DnBveWX6.js +292 -0
  159. package/static/assets/gitGraphDiagram-IHSO6WYX-B3rVL8c-.js +106 -0
  160. package/static/assets/graph-C9eacEi8.js +1 -0
  161. package/static/assets/index-LZSQkLE2.css +41 -0
  162. package/static/assets/index-y7XDSgMG.js +495 -0
  163. package/static/assets/infoDiagram-FWYZ7A6U-CvWV9yy2.js +2 -0
  164. package/static/assets/init-Gi6I4Gst.js +1 -0
  165. package/static/assets/ishikawaDiagram-FXEZZL3T-DF28a1N6.js +70 -0
  166. package/static/assets/journeyDiagram-5HDEW3XC-CB6CugYk.js +139 -0
  167. package/static/assets/kanban-definition-HUTT4EX6-ResSLF6d.js +89 -0
  168. package/static/assets/katex-C5jXJg4s.js +257 -0
  169. package/static/assets/layout-DEXfKzaS.js +1 -0
  170. package/static/assets/linear-CLO--ryk.js +1 -0
  171. package/static/assets/map-Czzmt4hB.js +1 -0
  172. package/static/assets/mindmap-definition-LN4V7U3C-BvW3EbxX.js +96 -0
  173. package/static/assets/ordinal-Cboi1Yqb.js +1 -0
  174. package/static/assets/pegDiagram-2B236MQR-BHCgqrrM.js +1 -0
  175. package/static/assets/pieDiagram-ENE6RG2P-DVmCQ5FA.js +39 -0
  176. package/static/assets/quadrantDiagram-ABIIQ3AL-B3e5KR52.js +7 -0
  177. package/static/assets/railroadDiagram-RFXS5EU6-Csv5ysLc.js +1 -0
  178. package/static/assets/requirementDiagram-TGXJPOKE-DOMVzvnB.js +84 -0
  179. package/static/assets/sankeyDiagram-HTMAVEWB-B1dcTOvy.js +40 -0
  180. package/static/assets/sequenceDiagram-DBY2YBRQ-BY414yeO.js +162 -0
  181. package/static/assets/sizeCapture-X5ZJPWSS-CuJfrfBN.js +1 -0
  182. package/static/assets/stateDiagram-2N3HPSRC-FX4rJkzV.js +1 -0
  183. package/static/assets/stateDiagram-v2-6OUMAXLB-BVufbO_H.js +1 -0
  184. package/static/assets/swimlanes-5IMT3BWC-Sfy58mmv.js +2 -0
  185. package/static/assets/swimlanesDiagram-G3AALYLV-wDCDw08H.js +8 -0
  186. package/static/assets/timeline-definition-FHXFAJF6-CmV7by8p.js +120 -0
  187. package/static/assets/vennDiagram-L72KCM5P-FqIyFZFt.js +34 -0
  188. package/static/assets/wardleyDiagram-EHGQE667-BZ06O45i.js +78 -0
  189. package/static/assets/xychartDiagram-FW5EYKEG-BOkffR06.js +7 -0
  190. package/static/index.html +24 -0
@@ -0,0 +1,354 @@
1
+ # Spring Modulith Patterns — Module Structure & Event Architecture
2
+
3
+ This reference describes the Spring Modulith conventions used in the spec. Include this
4
+ content in Sections 4 and 8 of the generated specification.
5
+
6
+ ---
7
+
8
+ ## Module Boundary Rules
9
+
10
+ Spring Modulith enforces architectural boundaries by treating each top-level package
11
+ under the base package as an independent application module. This spec uses the strict
12
+ encapsulation model: public API at the module root, all implementation in `internal/`.
13
+
14
+ ### What constitutes a module
15
+
16
+ ```
17
+ com.example.app/
18
+ ├── config/ ← NOT a module (infrastructure config)
19
+ ├── shared/ ← NOT a module (shared kernel, accessible by all)
20
+ ├── order/ ← MODULE: order bounded context
21
+ ├── inventory/ ← MODULE: inventory bounded context
22
+ ├── scheduling/ ← MODULE: scheduling bounded context
23
+ └── Application.java
24
+ ```
25
+
26
+ Spring Modulith scans `Application.java`'s package and treats each direct sub-package
27
+ as a module, EXCEPT for packages explicitly designated as shared infrastructure.
28
+
29
+ ### Visibility rules — Public API vs Internal Implementation
30
+
31
+ Each module has a strict two-layer structure:
32
+
33
+ ```
34
+ com.example.app.order/ ← PUBLIC API (visible to other modules)
35
+ ├── OrderService.java ← Service interface
36
+ ├── OrderDTO.java ← Return type for inter-module communication
37
+ ├── OrderException.java ← Module-specific exception
38
+ ├── OrderCreatedEvent.java ← Domain event (visible to listeners)
39
+
40
+ └── internal/ ← INTERNAL (hidden from other modules)
41
+ ├── OrderServiceImpl.java ← Implements OrderService
42
+ ├── OrderRepository.java ← MongoRepository — data access
43
+ ├── OrderDocument.java ← MongoDB document — data model
44
+ ├── OrderMapper.java ← MapStruct mapper
45
+ └── web/
46
+ └── OrderController.java ← REST controller (inbound adapter)
47
+ ```
48
+
49
+ **Public API (module root)** — only these types are visible to other modules:
50
+ - `OrderService` — Interface. The sole programmatic entry point for other modules.
51
+ Other modules inject this interface; Spring wires the internal `OrderServiceImpl`.
52
+ - `OrderDTO` — The data contract. When `OrderService` returns data, it returns this
53
+ DTO, never the internal `OrderDocument`. This prevents leaking persistence details.
54
+ - `OrderException` — Callers can catch module-specific failures.
55
+ - `OrderCreatedEvent` — Domain events must be in the root package so listeners in
56
+ other modules can reference the event type.
57
+
58
+ **Internal implementation (`internal/`)** — invisible to other modules:
59
+ - `OrderServiceImpl` — Contains all business logic, repository calls, event publishing.
60
+ Spring Modulith treats everything in `internal/` as module-private.
61
+ - `OrderRepository` — Data access is an implementation detail. Other modules never
62
+ query another module's database directly.
63
+ - `OrderDocument` — The MongoDB document model is internal. It may have fields,
64
+ embedded objects, or annotations that are irrelevant to consumers.
65
+ - `OrderMapper` — DTO ↔ Document conversion is an internal concern.
66
+ - `web/OrderController` — The REST controller is an **inbound adapter**. It accepts
67
+ HTTP requests and delegates to the service interface. It is NOT part of the
68
+ inter-module API — other modules never call controllers. Placing it in `internal/web/`
69
+ makes this architectural intent explicit and enforceable.
70
+ - `OrderEventConsumer` *(if Messaging = yes)* — The `@RabbitListener` is also an
71
+ **inbound adapter** (MQ instead of HTTP) and follows the same rule: it lives in
72
+ `internal/`, is package-private, and delegates to the module's service interface.
73
+ It must NEVER be placed under `shared/messaging/` — see `messaging-patterns.md`
74
+ for the full convention.
75
+
76
+ ### Why the controller is internal
77
+
78
+ This is a deliberate architectural choice. In hexagonal / ports-and-adapters terms:
79
+ - The **port** is `OrderService` (the interface) — this is the module's public API
80
+ - The **adapter** is `OrderController` — it adapts HTTP to the service interface
81
+
82
+ Other modules interact through the port (service interface), not the adapter (controller).
83
+ If tomorrow you add a gRPC adapter or a message consumer, they would also be internal
84
+ adapters delegating to the same public service interface. Keeping adapters internal
85
+ enforces this separation.
86
+
87
+ ### Inter-module dependency direction
88
+
89
+ ```
90
+ OrderController (internal) → OrderService (public interface)
91
+
92
+ InventoryService (another module) → OrderService (public interface)
93
+ ```
94
+
95
+ Both the internal controller and external modules depend on the same public interface.
96
+ The `OrderServiceImpl` is wired by Spring but never directly referenced.
97
+
98
+ ### What modules must NOT do
99
+
100
+ - Never inject a ServiceImpl from another module — use the Service interface
101
+ - Never reference another module's `internal` package (enforced by Spring Modulith)
102
+ - Never reference another module's Repository or Document
103
+ - Never create circular dependencies between modules
104
+ - Never bypass the service interface by calling another module's controller
105
+
106
+ ---
107
+
108
+ ## Inter-Module Communication via Events
109
+
110
+ When one module needs to notify others about a domain event (e.g., an order was created
111
+ and inventory needs to adjust), use Spring Modulith application events.
112
+
113
+ ### Event Class Convention
114
+
115
+ Events are Java records, immutable, and carry only the data the listener needs.
116
+
117
+ Naming: `<AggregateRoot><PastTenseVerb>Event`
118
+
119
+ ```java
120
+ // In com.example.app.order (module root — visible to other modules)
121
+ public record OrderCreatedEvent(
122
+ String orderId,
123
+ String customerId,
124
+ Instant occurredAt
125
+ ) {}
126
+ ```
127
+
128
+ Why records: they're immutable, generate equals/hashCode, and make the event's contract
129
+ explicit. Using `Instant occurredAt` establishes when the event happened.
130
+
131
+ ### Publishing Events
132
+
133
+ The service implementation (internal) publishes events using Spring's `ApplicationEventPublisher`:
134
+
135
+ ```java
136
+ // In com.example.app.order.internal (INTERNAL — hidden from other modules)
137
+ @Service
138
+ @RequiredArgsConstructor
139
+ @Slf4j
140
+ class OrderServiceImpl implements OrderService {
141
+ private final OrderRepository repository;
142
+ private final OrderMapper mapper;
143
+ private final ApplicationEventPublisher eventPublisher;
144
+
145
+ @Override
146
+ @Transactional
147
+ public OrderDTO create(CreateOrderRequest request) {
148
+ OrderDocument saved = repository.save(mapper.toDocument(request));
149
+
150
+ eventPublisher.publishEvent(new OrderCreatedEvent(
151
+ saved.getId(),
152
+ saved.getCustomerId(),
153
+ Instant.now()
154
+ ));
155
+
156
+ log.info("Order created: {}", saved.getId());
157
+ return mapper.toDTO(saved);
158
+ }
159
+ }
160
+ ```
161
+
162
+ Note that the class has package-private visibility (no `public` keyword). Spring still
163
+ discovers it via component scanning, but other modules cannot reference it directly.
164
+ They depend on the `OrderService` interface instead.
165
+
166
+ Events are published within the transaction boundary. If the transaction rolls back,
167
+ the event is not delivered.
168
+
169
+ ### Listening to Events
170
+
171
+ Other modules listen using `@ApplicationModuleListener` in their internal implementation:
172
+
173
+ ```java
174
+ // In com.example.app.inventory.internal (INTERNAL)
175
+ @Service
176
+ @RequiredArgsConstructor
177
+ @Slf4j
178
+ class InventoryServiceImpl implements InventoryService {
179
+
180
+ @ApplicationModuleListener
181
+ void on(OrderCreatedEvent event) {
182
+ log.info("Adjusting inventory for order: {}", event.orderId());
183
+ // Business logic to reserve inventory
184
+ }
185
+ }
186
+ ```
187
+
188
+ The listener references `OrderCreatedEvent` which is in the `order` module's root
189
+ package (public API), so this cross-module reference is valid. The implementation
190
+ class itself is internal to the `inventory` module.
191
+
192
+ `@ApplicationModuleListener` is a composed annotation that includes `@Async` and
193
+ `@TransactionalEventListener`. This means:
194
+ - The listener runs in a separate transaction
195
+ - It executes after the publishing transaction commits
196
+ - Failures in the listener do not roll back the publisher
197
+
198
+ ### Event Publication Registry
199
+
200
+ Spring Modulith's event publication registry (backed by MongoDB via
201
+ `spring-modulith-starter-mongodb`) persists events. If a listener fails, the event
202
+ is marked as incomplete and can be retried.
203
+
204
+ Configuration in `application.yml`:
205
+ ```yaml
206
+ spring:
207
+ modulith:
208
+ events:
209
+ republish-outstanding-events-on-restart: true
210
+ ```
211
+
212
+ This ensures at-least-once delivery semantics for application events.
213
+
214
+ ---
215
+
216
+ ## Module Verification
217
+
218
+ Spring Modulith provides a test that verifies all module boundary rules are respected:
219
+
220
+ ```java
221
+ @Test
222
+ void verifyModularity() {
223
+ ApplicationModules.of(Application.class).verify();
224
+ }
225
+ ```
226
+
227
+ This test catches:
228
+ - Direct dependencies between modules that bypass events
229
+ - Circular module dependencies
230
+ - References to another module's internal types
231
+
232
+ Include this test in the Testing Strategy section of the spec. It should run as part
233
+ of the build to enforce architectural integrity continuously.
234
+
235
+ ---
236
+
237
+ ## Module Documentation
238
+
239
+ Spring Modulith can generate architecture documentation from the module structure:
240
+
241
+ ```java
242
+ @Test
243
+ void createModuleDocumentation() {
244
+ ApplicationModules modules = ApplicationModules.of(Application.class);
245
+ new Documenter(modules).writeDocumentation();
246
+ }
247
+ ```
248
+
249
+ This produces PlantUML diagrams and Asciidoc documentation of module interactions.
250
+ Mention this as an optional capability in the spec.
251
+
252
+ ---
253
+
254
+ ## Web Application Module Adaptations
255
+
256
+ For server-rendered web applications, the module structure is adapted to include `page`
257
+ and `fragment` subpackages within `internal/`. The controller is a `@Controller` (not
258
+ `@RestController`) that returns JTE view names.
259
+
260
+ ### Web Module Structure
261
+
262
+ ```
263
+ com.example.app.order/ ← PUBLIC API (visible to other modules)
264
+ ├── OrderService.java ← Service interface
265
+ ├── OrderDTO.java ← Return type for inter-module communication
266
+ ├── OrderException.java ← Module-specific exception
267
+
268
+ └── internal/ ← INTERNAL (hidden from other modules)
269
+ ├── OrderServiceImpl.java ← Implements OrderService
270
+ ├── OrderRepository.java ← MongoRepository — data access
271
+ ├── OrderDocument.java ← MongoDB document — data model
272
+ ├── OrderMapper.java ← MapStruct mapper
273
+ ├── page/ ← Page controllers (full HTML pages)
274
+ │ ├── OrderPageController.java ← @Controller returning JTE view names
275
+ │ ├── OrderListView.java ← View model for list page
276
+ │ └── OrderDetailView.java ← View model for detail page
277
+ └── fragment/ ← Fragment controllers (htmx partials)
278
+ └── OrderFragmentController.java ← Returns HTML fragments for htmx
279
+ ```
280
+
281
+ ### Key Differences from API Modules
282
+
283
+ 1. **No REST controllers**: Web modules use `@Controller` instead of `@RestController`.
284
+ Controllers return JTE template paths, not JSON.
285
+
286
+ 2. **Direct data ownership**: Each module owns its MongoDB documents and repositories.
287
+ The service layer queries MongoDB directly via Spring Data `MongoRepository`.
288
+
289
+ 3. **View models**: Each page has a dedicated view model class that encapsulates all
290
+ data needed by the JTE template. View models are internal to the module.
291
+
292
+ 4. **Page vs Fragment separation**: `page/` subpackage holds controllers for full page
293
+ renders; `fragment/` holds controllers that return partial HTML for htmx requests.
294
+
295
+ 5. **Mixins**: Controllers implement `PaginationAware`, `ThemeAware`, and `AuthAware`
296
+ interfaces to extract pagination, theme, and user info from the request.
297
+
298
+ ### Web Page Controller Pattern
299
+
300
+ ```java
301
+ @Controller
302
+ @RequestMapping("/orders")
303
+ @RequiredArgsConstructor
304
+ class OrderPageController implements PaginationAware, ThemeAware, AuthAware {
305
+
306
+ private final OrderService service;
307
+ private final MainLayout layout;
308
+
309
+ @GetMapping
310
+ String list(Model model, HttpServletRequest req) {
311
+ var pageRequest = pagination(req, 20, 100);
312
+ var result = service.list(pageRequest);
313
+ var paginationVm = result.toPagination("/orders");
314
+ var view = new OrderListView(result.data(), paginationVm, theme(req), currentUser(req));
315
+ model.addAttribute("layout", layout.defaultPage("Orders", req));
316
+ model.addAttribute("view", view);
317
+ return "com/example/app/order/page/OrderListPage";
318
+ }
319
+
320
+ @GetMapping("/{id}")
321
+ String detail(@PathVariable String id, Model model, HttpServletRequest req) {
322
+ var dto = service.get(id);
323
+ var view = new OrderDetailView(dto, theme(req), currentUser(req));
324
+ model.addAttribute("layout", layout.defaultPage(dto.getFieldOne(), req));
325
+ model.addAttribute("view", view);
326
+ return "com/example/app/order/page/OrderDetailPage";
327
+ }
328
+ }
329
+ ```
330
+
331
+ ### Web Fragment Controller Pattern
332
+
333
+ ```java
334
+ @Controller
335
+ @RequestMapping("/orders/fragments")
336
+ @RequiredArgsConstructor
337
+ class OrderFragmentController implements PaginationAware, AuthAware {
338
+
339
+ private final OrderService service;
340
+
341
+ @GetMapping("/row/{id}")
342
+ String row(@PathVariable String id, Model model) {
343
+ var dto = service.get(id);
344
+ model.addAttribute("item", dto);
345
+ return "com/example/app/order/fragment/OrderRowFragment";
346
+ }
347
+
348
+ @DeleteMapping("/{id}")
349
+ ResponseEntity<String> delete(@PathVariable String id) {
350
+ service.delete(id);
351
+ return ResponseEntity.ok("");
352
+ }
353
+ }
354
+ ```