@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.
- package/dist/index.js +25449 -0
- package/drizzle/0000_remarkable_charles_xavier.sql +210 -0
- package/drizzle/0001_wise_wolf_cub.sql +13 -0
- package/drizzle/0002_secret_spyke.sql +16 -0
- package/drizzle/0003_workspace_config_singleton.sql +16 -0
- package/drizzle/0004_terminal_claim_v120.sql +11 -0
- package/drizzle/0005_brainstorm_v124.sql +10 -0
- package/drizzle/0006_project_v140.sql +6 -0
- package/drizzle/0007_prd_wizard_v124.sql +14 -0
- package/drizzle/0008_workflow_artifact_v126.sql +24 -0
- package/drizzle/0009_project_import_v150.sql +7 -0
- package/drizzle/0010_quality_v151.sql +3 -0
- package/drizzle/meta/0000_snapshot.json +1335 -0
- package/drizzle/meta/0001_snapshot.json +1416 -0
- package/drizzle/meta/0002_snapshot.json +1510 -0
- package/drizzle/meta/_journal.json +83 -0
- package/package.json +41 -0
- package/plugin/.claude-plugin/marketplace.json +36 -0
- package/plugin/.claude-plugin/plugin.json +22 -0
- package/plugin/README.md +625 -0
- package/plugin/SKILLS.md +350 -0
- package/plugin/co2.svg +5 -0
- package/plugin/commands/brainstorm-loop.md +129 -0
- package/plugin/skills/conductor-defect/SKILL.md +898 -0
- package/plugin/skills/conductor-feature-develop/SKILL.md +1383 -0
- package/plugin/skills/conductor-feature-develop/references/implementation-domain-template.md +131 -0
- package/plugin/skills/conductor-feature-develop/references/implementation-master-template.md +89 -0
- package/plugin/skills/conductor-feature-develop/references/playwright-setup.md +224 -0
- package/plugin/skills/conductor-feature-prepare/SKILL.md +604 -0
- package/plugin/skills/depgen-k8s/SKILL.md +468 -0
- package/plugin/skills/depgen-k8s/references/dockerfile-laravel.md +197 -0
- package/plugin/skills/depgen-k8s/references/dockerfile-nodejs.md +163 -0
- package/plugin/skills/depgen-k8s/references/dockerfile-spring-boot.md +174 -0
- package/plugin/skills/depgen-k8s/references/k8s-patterns.md +869 -0
- package/plugin/skills/mockgen-shadcn/SKILL.md +1067 -0
- package/plugin/skills/mockgen-shadcn/references/admin-layout-template.md +1467 -0
- package/plugin/skills/mockgen-shadcn/references/mockup-hub-template.md +498 -0
- package/plugin/skills/mockgen-shadcn/references/mockup-index-template.md +216 -0
- package/plugin/skills/mockgen-tailwind/SKILL.md +904 -0
- package/plugin/skills/mockgen-tailwind/references/admin-layout-template.md +720 -0
- package/plugin/skills/mockgen-tailwind/references/mockup-hub-template.md +498 -0
- package/plugin/skills/mockgen-tailwind/references/mockup-index-template.md +190 -0
- package/plugin/skills/modelgen-nosql/SKILL.md +617 -0
- package/plugin/skills/modelgen-nosql/references/model-extraction-methodology.md +497 -0
- package/plugin/skills/modelgen-nosql/references/nosql-design-guide.md +258 -0
- package/plugin/skills/modelgen-relational/SKILL.md +707 -0
- package/plugin/skills/modelgen-relational/references/model-extraction-methodology.md +499 -0
- package/plugin/skills/specgen-flutter-riverpod/SKILL.md +898 -0
- package/plugin/skills/specgen-flutter-riverpod/references/component-patterns.md +971 -0
- package/plugin/skills/specgen-flutter-riverpod/references/notification-patterns.md +457 -0
- package/plugin/skills/specgen-flutter-riverpod/references/routing-patterns.md +362 -0
- package/plugin/skills/specgen-flutter-riverpod/references/security-patterns.md +709 -0
- package/plugin/skills/specgen-flutter-riverpod/references/spec-template.md +1566 -0
- package/plugin/skills/specgen-flutter-riverpod/references/state-patterns.md +518 -0
- package/plugin/skills/specgen-flutter-riverpod/references/storage-patterns.md +370 -0
- package/plugin/skills/specgen-laravel-eloquent-bladehtmx/SKILL.md +984 -0
- package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/batch-patterns.md +359 -0
- package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/messaging-patterns.md +468 -0
- package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/modulith-patterns.md +461 -0
- package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/reporting-patterns.md +803 -0
- package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/security-patterns.md +501 -0
- package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/spec-template.md +1268 -0
- package/plugin/skills/specgen-laravel-eloquent-bladehtmx/references/web-patterns.md +301 -0
- package/plugin/skills/specgen-node-cli-web/SKILL.md +561 -0
- package/plugin/skills/specgen-node-cli-web/references/auth-patterns.md +293 -0
- package/plugin/skills/specgen-node-cli-web/references/cli-packaging-patterns.md +250 -0
- package/plugin/skills/specgen-node-cli-web/references/server-patterns.md +247 -0
- package/plugin/skills/specgen-node-cli-web/references/spec-template.md +401 -0
- package/plugin/skills/specgen-node-cli-web/references/testing-patterns.md +174 -0
- package/plugin/skills/specgen-react-mui/SKILL.md +789 -0
- package/plugin/skills/specgen-react-mui/references/component-patterns.md +1077 -0
- package/plugin/skills/specgen-react-mui/references/reporting-patterns.md +1998 -0
- package/plugin/skills/specgen-react-mui/references/routing-patterns.md +461 -0
- package/plugin/skills/specgen-react-mui/references/security-patterns.md +599 -0
- package/plugin/skills/specgen-react-mui/references/spec-template.md +1030 -0
- package/plugin/skills/specgen-react-mui/references/state-patterns.md +327 -0
- package/plugin/skills/specgen-react-tailwind/SKILL.md +859 -0
- package/plugin/skills/specgen-react-tailwind/references/component-patterns.md +1212 -0
- package/plugin/skills/specgen-react-tailwind/references/reporting-patterns.md +1529 -0
- package/plugin/skills/specgen-react-tailwind/references/routing-patterns.md +669 -0
- package/plugin/skills/specgen-react-tailwind/references/security-patterns.md +656 -0
- package/plugin/skills/specgen-react-tailwind/references/spec-template.md +1237 -0
- package/plugin/skills/specgen-react-tailwind/references/state-patterns.md +327 -0
- package/plugin/skills/specgen-sdk-java/SKILL.md +933 -0
- package/plugin/skills/specgen-sdk-java/references/api-extraction-patterns.md +247 -0
- package/plugin/skills/specgen-sdk-java/references/http-client-patterns.md +495 -0
- package/plugin/skills/specgen-sdk-java/references/packaging-patterns.md +366 -0
- package/plugin/skills/specgen-sdk-java/references/spec-template.md +956 -0
- package/plugin/skills/specgen-spring-jpa-jtehtmx/SKILL.md +1284 -0
- package/plugin/skills/specgen-spring-jpa-jtehtmx/references/batch-patterns.md +1224 -0
- package/plugin/skills/specgen-spring-jpa-jtehtmx/references/jasper-patterns.md +1638 -0
- package/plugin/skills/specgen-spring-jpa-jtehtmx/references/messaging-patterns.md +512 -0
- package/plugin/skills/specgen-spring-jpa-jtehtmx/references/modulith-patterns.md +354 -0
- package/plugin/skills/specgen-spring-jpa-jtehtmx/references/security-patterns.md +551 -0
- package/plugin/skills/specgen-spring-jpa-jtehtmx/references/spec-template.md +2502 -0
- package/plugin/skills/specgen-spring-jpa-jtehtmx/references/web-patterns.md +503 -0
- package/plugin/skills/specgen-spring-jpa-restapi/SKILL.md +990 -0
- package/plugin/skills/specgen-spring-jpa-restapi/references/batch-patterns.md +1224 -0
- package/plugin/skills/specgen-spring-jpa-restapi/references/messaging-patterns.md +512 -0
- package/plugin/skills/specgen-spring-jpa-restapi/references/modulith-patterns.md +279 -0
- package/plugin/skills/specgen-spring-jpa-restapi/references/reporting-patterns.md +1536 -0
- package/plugin/skills/specgen-spring-jpa-restapi/references/restapi-patterns.md +722 -0
- package/plugin/skills/specgen-spring-jpa-restapi/references/security-patterns.md +351 -0
- package/plugin/skills/specgen-spring-jpa-restapi/references/spec-template.md +553 -0
- package/plugin/skills/specgen-ts-cli/SKILL.md +861 -0
- package/plugin/skills/specgen-ts-cli/references/async-patterns.md +1101 -0
- package/plugin/skills/specgen-ts-cli/references/command-patterns.md +383 -0
- package/plugin/skills/specgen-ts-cli/references/config-patterns.md +430 -0
- package/plugin/skills/specgen-ts-cli/references/database-patterns.md +750 -0
- package/plugin/skills/specgen-ts-cli/references/packaging-patterns.md +426 -0
- package/plugin/skills/specgen-ts-cli/references/spec-template.md +1391 -0
- package/plugin/skills/specgen-ts-cli/references/testing-patterns.md +909 -0
- package/plugin/skills/testgen-functional/SKILL.md +1381 -0
- package/plugin/skills/tracegen-matrix/SKILL.md +243 -0
- package/plugin/skills/util-preparek8senv/SKILL.md +422 -0
- package/plugin/skills/util-projectinit/SKILL.md +307 -0
- package/plugin/skills/util-projectinit/reference/brainstorm-loop.md +129 -0
- package/plugin/skills/util-projectinit/reference/brainstorm-protocol.md +144 -0
- package/plugin/skills/util-projectinit/reference/brainstorm-setup-guide.md +153 -0
- package/plugin/skills/util-projectinit/reference/brainstorm-template-appdev.md +87 -0
- package/plugin/skills/util-projectinit/reference/co2-context-generation-guide.md +761 -0
- package/plugin/skills/util-projectsync/SKILL.md +501 -0
- package/plugin/skills/util-updprd/SKILL.md +324 -0
- package/plugin/skills/util-usanalyzer/SKILL.md +307 -0
- package/plugin/skills/util-ustagger/SKILL.md +154 -0
- package/static/assets/abnfDiagram-VRR7QNED-DvPuwyCV.js +1 -0
- package/static/assets/arc-DRKw7sjs.js +1 -0
- package/static/assets/architectureDiagram-ZJ3FMSHR-CaNcxUbC.js +36 -0
- package/static/assets/blockDiagram-677ZJIJ3-Demd4AOK.js +132 -0
- package/static/assets/c4Diagram-LMCZKHZV-PVKUfc2x.js +10 -0
- package/static/assets/channel-C2nVbuwv.js +1 -0
- package/static/assets/chunk-2Q5K7J3B-CExf8ww_.js +1 -0
- package/static/assets/chunk-32BRIVSS-CFPaoONF.js +1 -0
- package/static/assets/chunk-5VM5RSS4-DE2esM67.js +15 -0
- package/static/assets/chunk-EX3LRPZG-SON_YdDG.js +231 -0
- package/static/assets/chunk-JWPE2WC7-Qxah8LNr.js +1 -0
- package/static/assets/chunk-MOJQB5TN-BcWGQV3j.js +88 -0
- package/static/assets/chunk-RYQCIY6F-DkDj-OR5.js +1 -0
- package/static/assets/chunk-V7JOEXUC-BlI1Mrah.js +206 -0
- package/static/assets/chunk-VR4S4FIN-Agf__duj.js +1 -0
- package/static/assets/chunk-XXDRQBXY-B5CfAh85.js +1 -0
- package/static/assets/classDiagram-OUVF2IWQ-DXJIljsR.js +1 -0
- package/static/assets/classDiagram-v2-EOCWNBFH-DXJIljsR.js +1 -0
- package/static/assets/cose-bilkent-JH36ORCC-DO0cQkcy.js +1 -0
- package/static/assets/cynefin-VYW2F7L2-CfOnsnXc.js +178 -0
- package/static/assets/cynefinDiagram-TSTJHNR4-BJ8tULAv.js +62 -0
- package/static/assets/cytoscape.esm-DTSO7Bv0.js +331 -0
- package/static/assets/dagre-VKFMJZFB-DfjwzHqP.js +4 -0
- package/static/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/static/assets/diagram-FQU43EPY-CndSOIIM.js +3 -0
- package/static/assets/diagram-G47NLZAW-Czf5hN0Z.js +24 -0
- package/static/assets/diagram-NH7WQ7WH-COAyojGh.js +24 -0
- package/static/assets/diagram-OA4YK3LP-H8PoiN2m.js +30 -0
- package/static/assets/diagram-WEI45ONY-DzcaVzjp.js +41 -0
- package/static/assets/ebnfDiagram-CCIWWBDH-DPazGYLJ.js +1 -0
- package/static/assets/erDiagram-Q63AITRT-Bo-fubgF.js +85 -0
- package/static/assets/flowDiagram-23GEKE2U-CSvxUDwh.js +156 -0
- package/static/assets/ganttDiagram-NO4QXBWP-DnBveWX6.js +292 -0
- package/static/assets/gitGraphDiagram-IHSO6WYX-B3rVL8c-.js +106 -0
- package/static/assets/graph-C9eacEi8.js +1 -0
- package/static/assets/index-LZSQkLE2.css +41 -0
- package/static/assets/index-y7XDSgMG.js +495 -0
- package/static/assets/infoDiagram-FWYZ7A6U-CvWV9yy2.js +2 -0
- package/static/assets/init-Gi6I4Gst.js +1 -0
- package/static/assets/ishikawaDiagram-FXEZZL3T-DF28a1N6.js +70 -0
- package/static/assets/journeyDiagram-5HDEW3XC-CB6CugYk.js +139 -0
- package/static/assets/kanban-definition-HUTT4EX6-ResSLF6d.js +89 -0
- package/static/assets/katex-C5jXJg4s.js +257 -0
- package/static/assets/layout-DEXfKzaS.js +1 -0
- package/static/assets/linear-CLO--ryk.js +1 -0
- package/static/assets/map-Czzmt4hB.js +1 -0
- package/static/assets/mindmap-definition-LN4V7U3C-BvW3EbxX.js +96 -0
- package/static/assets/ordinal-Cboi1Yqb.js +1 -0
- package/static/assets/pegDiagram-2B236MQR-BHCgqrrM.js +1 -0
- package/static/assets/pieDiagram-ENE6RG2P-DVmCQ5FA.js +39 -0
- package/static/assets/quadrantDiagram-ABIIQ3AL-B3e5KR52.js +7 -0
- package/static/assets/railroadDiagram-RFXS5EU6-Csv5ysLc.js +1 -0
- package/static/assets/requirementDiagram-TGXJPOKE-DOMVzvnB.js +84 -0
- package/static/assets/sankeyDiagram-HTMAVEWB-B1dcTOvy.js +40 -0
- package/static/assets/sequenceDiagram-DBY2YBRQ-BY414yeO.js +162 -0
- package/static/assets/sizeCapture-X5ZJPWSS-CuJfrfBN.js +1 -0
- package/static/assets/stateDiagram-2N3HPSRC-FX4rJkzV.js +1 -0
- package/static/assets/stateDiagram-v2-6OUMAXLB-BVufbO_H.js +1 -0
- package/static/assets/swimlanes-5IMT3BWC-Sfy58mmv.js +2 -0
- package/static/assets/swimlanesDiagram-G3AALYLV-wDCDw08H.js +8 -0
- package/static/assets/timeline-definition-FHXFAJF6-CmV7by8p.js +120 -0
- package/static/assets/vennDiagram-L72KCM5P-FqIyFZFt.js +34 -0
- package/static/assets/wardleyDiagram-EHGQE667-BZ06O45i.js +78 -0
- package/static/assets/xychartDiagram-FW5EYKEG-BOkffR06.js +7 -0
- package/static/index.html +24 -0
|
@@ -0,0 +1,279 @@
|
|
|
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 5 and 14 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
|
+
├── CreateOrderRequest.java <- Request DTO (with Bean Validation)
|
|
38
|
+
├── UpdateOrderRequest.java <- Request DTO (with Bean Validation)
|
|
39
|
+
├── OrderException.java <- Module-specific exception
|
|
40
|
+
├── OrderCreatedEvent.java <- Domain event (visible to listeners)
|
|
41
|
+
│
|
|
42
|
+
└── internal/ <- INTERNAL (hidden from other modules)
|
|
43
|
+
├── OrderServiceImpl.java <- Implements OrderService
|
|
44
|
+
├── OrderRepository.java <- Spring Data repository — data access
|
|
45
|
+
├── OrderEntity.java <- JPA entity or MongoDB document
|
|
46
|
+
├── OrderMapper.java <- MapStruct mapper
|
|
47
|
+
└── OrderController.java <- REST controller (inbound adapter)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Public API (module root)** — only these types are visible to other modules:
|
|
51
|
+
- `OrderService` — Interface. The sole programmatic entry point for other modules.
|
|
52
|
+
- `OrderDTO` — The response data contract (Java record).
|
|
53
|
+
- `CreateOrderRequest` / `UpdateOrderRequest` — Request DTOs (Java records with validation).
|
|
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
|
+
- `OrderRepository` — Data access is an implementation detail.
|
|
61
|
+
- `OrderEntity` — The entity/document model is internal.
|
|
62
|
+
- `OrderMapper` — DTO <-> Entity conversion is an internal concern.
|
|
63
|
+
- `OrderController` — The REST controller is an **inbound adapter**. It accepts
|
|
64
|
+
HTTP requests and delegates to the service interface. It is NOT part of the
|
|
65
|
+
inter-module API.
|
|
66
|
+
- `OrderEventConsumer` *(if Messaging = yes)* — The `@RabbitListener` is also an
|
|
67
|
+
**inbound adapter** (MQ instead of HTTP) and follows the same rule: it lives in
|
|
68
|
+
`internal/`, is package-private, and delegates to the module's service interface.
|
|
69
|
+
It must NEVER be placed under `shared/messaging/` — see `messaging-patterns.md`
|
|
70
|
+
for the full convention.
|
|
71
|
+
|
|
72
|
+
### Why the controller is internal
|
|
73
|
+
|
|
74
|
+
This is a deliberate architectural choice. In hexagonal / ports-and-adapters terms:
|
|
75
|
+
- The **port** is `OrderService` (the interface) — this is the module's public API
|
|
76
|
+
- The **adapter** is `OrderController` — it adapts HTTP to the service interface
|
|
77
|
+
|
|
78
|
+
Other modules interact through the port (service interface), not the adapter (controller).
|
|
79
|
+
|
|
80
|
+
### Inter-module dependency direction
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
OrderController (internal) -> OrderService (public interface)
|
|
84
|
+
^
|
|
85
|
+
InventoryService (another module) -> OrderService (public interface)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### What modules must NOT do
|
|
89
|
+
|
|
90
|
+
- Never inject a ServiceImpl from another module — use the Service interface
|
|
91
|
+
- Never reference another module's `internal` package (enforced by Spring Modulith)
|
|
92
|
+
- Never reference another module's Repository or Entity/Document
|
|
93
|
+
- Never create circular dependencies between modules
|
|
94
|
+
- Never bypass the service interface by calling another module's controller
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Inter-Module Communication via Events
|
|
99
|
+
|
|
100
|
+
When one module needs to notify others about a domain event, use Spring Modulith
|
|
101
|
+
application events.
|
|
102
|
+
|
|
103
|
+
### Event Class Convention
|
|
104
|
+
|
|
105
|
+
Events are Java records, immutable, and carry only the data the listener needs.
|
|
106
|
+
|
|
107
|
+
Naming: `<AggregateRoot><PastTenseVerb>Event`
|
|
108
|
+
|
|
109
|
+
```java
|
|
110
|
+
// In com.example.app.order (module root — visible to other modules)
|
|
111
|
+
public record OrderCreatedEvent(
|
|
112
|
+
String orderId,
|
|
113
|
+
String customerId,
|
|
114
|
+
Instant occurredAt
|
|
115
|
+
) {}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Publishing Events
|
|
119
|
+
|
|
120
|
+
```java
|
|
121
|
+
// In com.example.app.order.internal (INTERNAL)
|
|
122
|
+
@Service
|
|
123
|
+
@RequiredArgsConstructor
|
|
124
|
+
@Slf4j
|
|
125
|
+
class OrderServiceImpl implements OrderService {
|
|
126
|
+
private final OrderRepository repository;
|
|
127
|
+
private final OrderMapper mapper;
|
|
128
|
+
private final ApplicationEventPublisher eventPublisher;
|
|
129
|
+
|
|
130
|
+
@Override
|
|
131
|
+
@Transactional
|
|
132
|
+
public OrderDTO create(CreateOrderRequest request) {
|
|
133
|
+
var entity = mapper.toEntity(request);
|
|
134
|
+
var saved = repository.save(entity);
|
|
135
|
+
|
|
136
|
+
eventPublisher.publishEvent(new OrderCreatedEvent(
|
|
137
|
+
saved.getId(),
|
|
138
|
+
saved.getCustomerId(),
|
|
139
|
+
Instant.now()
|
|
140
|
+
));
|
|
141
|
+
|
|
142
|
+
log.info("Order created: {}", saved.getId());
|
|
143
|
+
return mapper.toDTO(saved);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Listening to Events
|
|
149
|
+
|
|
150
|
+
```java
|
|
151
|
+
// In com.example.app.inventory.internal (INTERNAL)
|
|
152
|
+
@Service
|
|
153
|
+
@RequiredArgsConstructor
|
|
154
|
+
@Slf4j
|
|
155
|
+
class InventoryServiceImpl implements InventoryService {
|
|
156
|
+
|
|
157
|
+
@ApplicationModuleListener
|
|
158
|
+
void on(OrderCreatedEvent event) {
|
|
159
|
+
log.info("Adjusting inventory for order: {}", event.orderId());
|
|
160
|
+
// Business logic to reserve inventory
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`@ApplicationModuleListener` includes `@Async` and `@TransactionalEventListener`:
|
|
166
|
+
- The listener runs in a separate transaction
|
|
167
|
+
- It executes after the publishing transaction commits
|
|
168
|
+
- Failures in the listener do not roll back the publisher
|
|
169
|
+
|
|
170
|
+
### Event Publication Registry
|
|
171
|
+
|
|
172
|
+
Spring Modulith's event publication registry persists events. If a listener fails, the
|
|
173
|
+
event is marked as incomplete and can be retried.
|
|
174
|
+
|
|
175
|
+
```yaml
|
|
176
|
+
spring:
|
|
177
|
+
modulith:
|
|
178
|
+
events:
|
|
179
|
+
republish-outstanding-events-on-restart: true
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Module Verification
|
|
185
|
+
|
|
186
|
+
```java
|
|
187
|
+
@Test
|
|
188
|
+
void verifyModularity() {
|
|
189
|
+
ApplicationModules.of(Application.class).verify();
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
This test catches:
|
|
194
|
+
- Direct dependencies between modules that bypass events
|
|
195
|
+
- Circular module dependencies
|
|
196
|
+
- References to another module's internal types
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## REST API Module Structure
|
|
201
|
+
|
|
202
|
+
For REST API applications, the module structure uses a `@RestController` in `internal/`
|
|
203
|
+
instead of `@Controller` with page/fragment subpackages.
|
|
204
|
+
|
|
205
|
+
### REST Module Structure
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
com.example.app.order/ <- PUBLIC API
|
|
209
|
+
├── OrderService.java <- Service interface
|
|
210
|
+
├── OrderDTO.java <- Response DTO (Java record)
|
|
211
|
+
├── CreateOrderRequest.java <- Request DTO (Java record + validation)
|
|
212
|
+
├── UpdateOrderRequest.java <- Request DTO (Java record + validation)
|
|
213
|
+
├── OrderException.java <- Module-specific exception
|
|
214
|
+
│
|
|
215
|
+
└── internal/ <- INTERNAL
|
|
216
|
+
├── OrderServiceImpl.java <- Implements OrderService
|
|
217
|
+
├── OrderRepository.java <- Spring Data repository
|
|
218
|
+
├── OrderEntity.java <- JPA entity / MongoDB document
|
|
219
|
+
├── OrderMapper.java <- MapStruct mapper
|
|
220
|
+
└── OrderController.java <- @RestController (JSON in/out)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### REST Controller Pattern
|
|
224
|
+
|
|
225
|
+
```java
|
|
226
|
+
@RestController
|
|
227
|
+
@RequestMapping("/api/v1/orders")
|
|
228
|
+
@RequiredArgsConstructor
|
|
229
|
+
@Tag(name = "Orders", description = "Order management operations")
|
|
230
|
+
class OrderController {
|
|
231
|
+
|
|
232
|
+
private final OrderService service;
|
|
233
|
+
|
|
234
|
+
@GetMapping
|
|
235
|
+
public ResponseEntity<Page<OrderDTO>> list(
|
|
236
|
+
@PageableDefault(size = 20) Pageable pageable,
|
|
237
|
+
@RequestParam(required = false) String search) {
|
|
238
|
+
return ResponseEntity.ok(service.findAll(search, pageable));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
@GetMapping("/{id}")
|
|
242
|
+
public ResponseEntity<OrderDTO> getById(@PathVariable String id) {
|
|
243
|
+
return ResponseEntity.ok(service.findById(id));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@PostMapping
|
|
247
|
+
public ResponseEntity<OrderDTO> create(
|
|
248
|
+
@Valid @RequestBody CreateOrderRequest request) {
|
|
249
|
+
OrderDTO created = service.create(request);
|
|
250
|
+
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
|
|
251
|
+
.path("/{id}").buildAndExpand(created.id()).toUri();
|
|
252
|
+
return ResponseEntity.created(location).body(created);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
@PutMapping("/{id}")
|
|
256
|
+
public ResponseEntity<OrderDTO> update(
|
|
257
|
+
@PathVariable String id,
|
|
258
|
+
@Valid @RequestBody UpdateOrderRequest request) {
|
|
259
|
+
return ResponseEntity.ok(service.update(id, request));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@DeleteMapping("/{id}")
|
|
263
|
+
public ResponseEntity<Void> delete(@PathVariable String id) {
|
|
264
|
+
service.delete(id);
|
|
265
|
+
return ResponseEntity.noContent().build();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Key Differences from Web (JTE) Modules
|
|
271
|
+
|
|
272
|
+
1. **`@RestController` instead of `@Controller`**: Returns JSON directly, not view names.
|
|
273
|
+
2. **No view models**: Response DTOs serve as the API contract. No JTE templates.
|
|
274
|
+
3. **No page/fragment subpackages**: Single `OrderController` handles all CRUD operations.
|
|
275
|
+
4. **`ResponseEntity` wrapping**: All responses wrapped in `ResponseEntity` for explicit
|
|
276
|
+
status code and header control.
|
|
277
|
+
5. **`@Valid @RequestBody`**: Bean Validation at the controller boundary.
|
|
278
|
+
6. **`Pageable` parameter**: Spring Data `Pageable` injected directly from query params.
|
|
279
|
+
7. **OpenAPI annotations**: `@Tag`, `@Operation`, `@ApiResponse` for API documentation.
|