spring-boot4-skill 1.3.0 → 1.5.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.5.0] - 2026-02-21
9
+
10
+ ### Added
11
+
12
+ - **Skill:** New references `architecture-patterns.md` (hexagonal, Vertical Slice, DDD mapping to Modulith, CQRS) and `microservices-architecture.md` (microservices vs Modulith, service boundaries, inter-service communication, API Gateway, distributed observability).
13
+ - **Skill:** spring-modulith.md new section 10 "DDD & Modulith" (aggregate, domain repository, domain vs application events).
14
+ - **Skill:** SKILL.md and README: reference table and Quick decision mermaid updated for architecture and microservices.
15
+
16
+ [1.5.0]: https://github.com/AyrtonAldayr/agent-skill-java-spring-framework/compare/v1.4.0...v1.5.0
17
+
18
+ ## [1.4.0] - 2026-02-21
19
+
20
+ ### Added
21
+
22
+ - **Skill:** New references: `spring-redis.md` (Redis, RedisTemplate, cache backend, session store, pub/sub), `spring-data-mongodb.md` (MongoDB, MongoTemplate, MongoRepository, documents, transactions, indexes), `spring-graphql.md` (Spring for GraphQL, schema, @QueryMapping/@MutationMapping, Records).
23
+ - **Skill:** spring-boot-4.md: new section 14 (API documentation — OpenAPI/springdoc) and section 15 (Scheduling — @Scheduled, cron, virtual threads).
24
+ - **Skill:** spring-framework-7.md: new section 14 (Bean Validation 3.1 — @Valid, @NotNull, @Size, @Email, Records).
25
+ - **Skill:** SKILL.md Reference Files table: Redis, MongoDB, GraphQL rows; extended Load when for spring-boot-4 (OpenAPI/springdoc, scheduling) and spring-framework-7 (Bean Validation, @Valid); Quick decision mermaid nodes for Redis, MongoDB, GraphQL.
26
+ - **README:** Skill reference table: spring-redis.md, spring-data-mongodb.md, spring-graphql.md; extended descriptions for spring-boot-4 and spring-framework-7.
27
+
28
+ [1.4.0]: https://github.com/AyrtonAldayr/agent-skill-java-spring-framework/compare/v1.3.0...v1.4.0
29
+
8
30
  ## [1.3.0] - 2026-02-21
9
31
 
10
32
  ### Added
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/spring-boot4-skill.svg)](https://www.npmjs.com/package/spring-boot4-skill)
4
4
 
5
5
  > **2026-standard** project scaffolder + Claude Code AI skill for Java / Spring development.
6
- > By [AyrtonAldayr](https://github.com/AyrtonAldayr) · **v1.3.0**
6
+ > By [AyrtonAldayr](https://github.com/AyrtonAldayr) · **v1.4.0**
7
7
 
8
8
  This repository provides two tools in one:
9
9
 
@@ -133,11 +133,16 @@ Once installed, Claude Code acts as a **Senior Spring Boot 4 architect**:
133
133
 
134
134
  | File | Contents |
135
135
  |---|---|
136
- | `skills/java-spring-framework/references/spring-framework-7.md` | All Spring 7 APIs with code examples |
137
- | `skills/java-spring-framework/references/spring-boot-4.md` | Boot 4: native, virtual threads, testing (Testcontainers), reactive stack, rate limiting, connection pools, caching, performance |
136
+ | `skills/java-spring-framework/references/spring-framework-7.md` | All Spring 7 APIs, Bean Validation, @Valid |
137
+ | `skills/java-spring-framework/references/spring-boot-4.md` | Boot 4: native, virtual threads, testing, reactive stack, rate limiting, connection pools, caching, performance, OpenAPI, scheduling |
138
138
  | `skills/java-spring-framework/references/spring-security-7.md` | OAuth2 Resource Server, JWT, method security, CORS |
139
+ | `skills/java-spring-framework/references/spring-redis.md` | Redis, cache distribuido, session store |
140
+ | `skills/java-spring-framework/references/spring-data-mongodb.md` | MongoDB, document DB, Spring Data MongoDB |
139
141
  | `skills/java-spring-framework/references/spring-messaging.md` | Kafka, event-driven, @KafkaListener, producer/consumer |
140
- | `skills/java-spring-framework/references/spring-modulith.md` | Module structure, events, integration testing, common pitfalls |
142
+ | `skills/java-spring-framework/references/spring-graphql.md` | GraphQL API, Spring for GraphQL |
143
+ | `skills/java-spring-framework/references/spring-modulith.md` | Module structure, events, integration testing, common pitfalls, DDD & Modulith |
144
+ | `skills/java-spring-framework/references/architecture-patterns.md` | DDD, hexagonal, Vertical Slice, CQRS, ports & adapters |
145
+ | `skills/java-spring-framework/references/microservices-architecture.md` | Microservices: boundaries, communication, API Gateway, distributed observability |
141
146
  | `skills/java-spring-framework/references/build-templates.md` | Complete Gradle KTS + Maven POM templates |
142
147
  | `skills/java-spring-framework/references/troubleshooting-migration.md` | Common errors (javax/jakarta, RestTemplate), Boot 3→4 checklist |
143
148
 
@@ -159,10 +164,24 @@ Once installed, Claude Code acts as a **Senior Spring Boot 4 architect**:
159
164
 
160
165
  ## Publishing to npm
161
166
 
162
- ```bash
163
- npm login
164
- npm publish --access public
165
- ```
167
+ When releasing a new version:
168
+
169
+ 1. **Bump version** in `package.json` (e.g. `1.5.0` → `1.6.0`).
170
+ 2. **Update CHANGELOG.md** — add an entry under the new version (Added / Changed / Fixed).
171
+ 3. **Commit, tag and push:**
172
+ ```bash
173
+ git add .
174
+ git commit -m "chore: release v1.x.0"
175
+ git tag v1.x.0
176
+ git push origin main
177
+ git push origin v1.x.0
178
+ ```
179
+ (Or push all tags at once: `git push origin main && git push --tags`.)
180
+ 4. **Publish to npm** (requires npm login and 2FA if enabled):
181
+ ```bash
182
+ npm login
183
+ npm publish --access public
184
+ ```
166
185
 
167
186
  After publishing, developers can use:
168
187
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spring-boot4-skill",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Interactive CLI scaffold for Java 25 / Spring Boot 4.x projects — with a bundled Claude Code skill for AI-assisted development.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -29,7 +29,11 @@ idiomatic for **2026 standards**: Spring Boot 4.0.x, Spring Framework 7.0.x, Jav
29
29
 
30
30
  ```mermaid
31
31
  flowchart TD
32
- A[User request] --> B{REST blocking or reactive?}
32
+ A[User request] --> W{Architecture / DDD / hexagonal / VSA?}
33
+ W -->|Yes| X[architecture-patterns.md]
34
+ A --> Y{Microservices design?}
35
+ Y -->|Yes| Z[microservices-architecture.md]
36
+ A --> B{REST blocking or reactive?}
33
37
  B -->|Blocking MVC + JDBC/JPA| C[spring-boot-4.md + spring-framework-7.md]
34
38
  B -->|Reactive WebFlux + R2DBC| D[spring-boot-4.md Reactive section + spring-framework-7.md]
35
39
  A --> E{Modular monolith?}
@@ -44,6 +48,12 @@ flowchart TD
44
48
  M -->|Yes| N[spring-messaging.md]
45
49
  A --> O{Rate limit / resources / performance?}
46
50
  O -->|Yes| P[spring-boot-4.md]
51
+ A --> Q{Redis / cache distribuido?}
52
+ Q -->|Yes| R[spring-redis.md]
53
+ A --> S{MongoDB / document DB?}
54
+ S -->|Yes| T[spring-data-mongodb.md]
55
+ A --> U{GraphQL API?}
56
+ U -->|Yes| V[spring-graphql.md]
47
57
  ```
48
58
 
49
59
  ## Mandatory Workflow
@@ -80,10 +90,15 @@ Load these as needed — do not load all at once:
80
90
 
81
91
  | Topic | File | Load when |
82
92
  |---|---|---|
83
- | Spring Framework 7 APIs | `references/spring-framework-7.md` | Framework-level features: versioning, resilience, JSpecify, SpEL, streaming |
84
- | Spring Boot 4 features | `references/spring-boot-4.md` | Boot auto-config, Actuator, native images, testing, virtual threads, rate limiting, connection pools, resource metrics, caching, performance tuning |
93
+ | Spring Framework 7 APIs | `references/spring-framework-7.md` | Framework-level features: versioning, resilience, JSpecify, SpEL, streaming, Bean Validation, @Valid |
94
+ | Spring Boot 4 features | `references/spring-boot-4.md` | Boot auto-config, Actuator, native images, testing, virtual threads, rate limiting, connection pools, resource metrics, caching, performance tuning, OpenAPI/springdoc, scheduling |
85
95
  | Spring Security 7 | `references/spring-security-7.md` | OAuth2 Resource Server, JWT, method security, CORS, authentication/authorization |
96
+ | Redis | `references/spring-redis.md` | Redis, cache distribuido, session store |
97
+ | MongoDB | `references/spring-data-mongodb.md` | MongoDB, document DB, Spring Data MongoDB |
86
98
  | Messaging (Kafka) | `references/spring-messaging.md` | Kafka, event-driven, messaging, @KafkaListener, producer/consumer |
87
- | Spring Modulith | `references/spring-modulith.md` | Domain-driven module design, event-driven architecture |
99
+ | GraphQL | `references/spring-graphql.md` | GraphQL API, Spring for GraphQL |
100
+ | Spring Modulith | `references/spring-modulith.md` | Domain-driven module design, event-driven architecture, DDD aggregates, domain repository, domain events |
101
+ | Architecture (DDD, hexagonal, VSA, CQRS) | `references/architecture-patterns.md` | DDD, hexagonal, ports & adapters, Vertical Slice, CQRS, bounded context mapping |
102
+ | Microservices architecture | `references/microservices-architecture.md` | Microservices design, service boundaries, inter-service communication, API Gateway, distributed tracing |
88
103
  | Build templates | `references/build-templates.md` | Gradle KTS or Maven POM scaffolding with 2026 BOM versions |
89
104
  | Troubleshooting & migration | `references/troubleshooting-migration.md` | Migration from Boot 3, compile/runtime errors (javax/jakarta, RestTemplate, native, null-safety) |
@@ -0,0 +1,156 @@
1
+ # Application Architecture Patterns — Spring Boot 4
2
+
3
+ **Spring Boot**: 4.0.x | Application architecture | **Jakarta EE**: 11
4
+
5
+ This reference covers hexagonal (ports & adapters), Vertical Slice Architecture, DDD mapping to Modulith, and optional CQRS. For module structure and event-driven communication, see `references/spring-modulith.md`. For Kafka messaging, see `references/spring-messaging.md`.
6
+
7
+ ---
8
+
9
+ ## Table of Contents
10
+
11
+ 1. [Hexagonal (Ports & Adapters) with Spring](#1-hexagonal-ports--adapters-with-spring)
12
+ 2. [Vertical Slice Architecture](#2-vertical-slice-architecture)
13
+ 3. [DDD Mapping to Modulith](#3-ddd-mapping-to-modulith)
14
+ 4. [CQRS (Optional)](#4-cqrs-optional)
15
+
16
+ ---
17
+
18
+ ## 1. Hexagonal (Ports & Adapters) with Spring
19
+
20
+ **Ports** are interfaces that define what the application needs (inbound: use cases; outbound: persistence, messaging, external APIs). **Adapters** are concrete implementations that plug into those ports: REST controllers, JPA/JdbcClient repositories, Kafka listeners.
21
+
22
+ The domain and use cases stay in the center with no framework dependencies; Spring only appears in adapter classes and `@Bean` configuration.
23
+
24
+ **Conceptual layout:**
25
+
26
+ ```mermaid
27
+ flowchart LR
28
+ subgraph adaptersIn [Driving Adapters]
29
+ REST[REST Controller]
30
+ end
31
+ subgraph ports [Ports]
32
+ UseCase[PlaceOrderPort]
33
+ end
34
+ subgraph domain [Domain]
35
+ Order[Order aggregate]
36
+ end
37
+ subgraph adaptersOut [Driven Adapters]
38
+ Repo[OrderRepository impl]
39
+ Events[EventPublisher]
40
+ end
41
+ REST --> UseCase
42
+ UseCase --> Order
43
+ UseCase --> Repo
44
+ UseCase --> Events
45
+ ```
46
+
47
+ **Port (interface):**
48
+
49
+ ```java
50
+ package com.example.shop.orders.application;
51
+
52
+ import com.example.shop.orders.domain.Order;
53
+
54
+ public interface PlaceOrderPort {
55
+ Order placeOrder(PlaceOrderCommand command);
56
+ }
57
+ ```
58
+
59
+ **Use case (implements or uses the port from the “inside”):**
60
+
61
+ ```java
62
+ package com.example.shop.orders.application;
63
+
64
+ import com.example.shop.orders.domain.Order;
65
+ import org.springframework.stereotype.Service;
66
+
67
+ @Service
68
+ public class PlaceOrderUseCase implements PlaceOrderPort {
69
+
70
+ private final OrderRepository orderRepository;
71
+ private final ApplicationEventPublisher events;
72
+
73
+ public PlaceOrderUseCase(OrderRepository orderRepository, ApplicationEventPublisher events) {
74
+ this.orderRepository = orderRepository;
75
+ this.events = events;
76
+ }
77
+
78
+ @Override
79
+ public Order placeOrder(PlaceOrderCommand command) {
80
+ Order order = Order.create(command.sku(), command.quantity());
81
+ orderRepository.save(order);
82
+ events.publishEvent(new OrderPlacedEvent(order.id(), order.sku(), order.quantity()));
83
+ return order;
84
+ }
85
+ }
86
+ ```
87
+
88
+ **Driven port (repository):**
89
+
90
+ ```java
91
+ package com.example.shop.orders.domain;
92
+
93
+ public interface OrderRepository {
94
+ Order save(Order order);
95
+ Order findById(Long id);
96
+ }
97
+ ```
98
+
99
+ **Adapter (REST):** The controller depends on the port (e.g. `PlaceOrderPort`) and delegates; the adapter is registered as a `@Bean` or the port is injected where the controller is defined. **Adapter (persistence):** A class in `internal/` implements `OrderRepository` using JdbcClient or JPA and is registered as a `@Bean`. **Adapter (messaging):** Outbound events can be published via `ApplicationEventPublisher` (in-process) or Kafka (see `references/spring-messaging.md`).
100
+
101
+ Each Modulith module can apply hexagonal internally: public API = driving ports (use cases); `internal/` = driven adapters (repositories, external clients). See `references/spring-modulith.md` for module package structure.
102
+
103
+ ---
104
+
105
+ ## 2. Vertical Slice Architecture
106
+
107
+ Organize by **feature / use case** instead of horizontal layers (controllers/, services/, repositories/). Each **vertical slice** contains everything needed for one capability: HTTP handler, application logic, persistence, and DTOs.
108
+
109
+ **Package layout example (within an `orders` module):**
110
+
111
+ ```
112
+ com.example.shop.orders/
113
+ ├── PlaceOrder/
114
+ │ ├── PlaceOrderController.java # REST endpoint
115
+ │ ├── PlaceOrderCommand.java # request DTO
116
+ │ ├── PlaceOrderHandler.java # use case
117
+ │ └── OrderRepository.java # port; impl in internal or same slice
118
+ ├── GetOrder/
119
+ │ ├── GetOrderController.java
120
+ │ ├── GetOrderHandler.java
121
+ │ └── ...
122
+ └── internal/
123
+ └── JdbcOrderRepository.java # adapter shared by slices if needed
124
+ ```
125
+
126
+ Each slice is a thin vertical: from HTTP (or message) down to persistence. Shared infrastructure (e.g. repository implementation) can live in `internal/` or a shared package. With **Modulith**, the module boundary is the root package (e.g. `orders/`); inside it you can structure by slices (PlaceOrder, GetOrder) or by role (OrderService, OrderController) — both are valid. Use Modulith’s verification and event-driven rules regardless; see `references/spring-modulith.md`.
127
+
128
+ ---
129
+
130
+ ## 3. DDD Mapping to Modulith
131
+
132
+ | DDD concept | Modulith mapping |
133
+ |-------------|------------------|
134
+ | **Bounded context** | One root package = one module (e.g. `orders/`, `inventory/`). |
135
+ | **Use case / application service** | Public service class in the module (e.g. `OrderService`) or a dedicated use-case class that the controller calls. |
136
+ | **Aggregate** | Domain entity (or group of entities) that the module’s service loads and persists as a unit. See section 10 “DDD & Modulith” in `references/spring-modulith.md` for aggregate and domain repository. |
137
+ | **Domain repository** | Interface in the module’s public or domain package; implementation in `internal/` (JdbcClient/JPA). Same as a “port” in hexagonal. |
138
+ | **Domain events** | Often represented as application events published via `ApplicationEventPublisher` and consumed by other modules with `@ApplicationModuleListener`. See “DDD & Modulith” in `references/spring-modulith.md` for domain vs application events. |
139
+
140
+ You do not need a separate “domain” package; the public API of the module can expose use cases and domain types (e.g. Order record). Keep infrastructure (repositories impl, HTTP clients) in `internal/` or in adapters.
141
+
142
+ ---
143
+
144
+ ## 4. CQRS (Optional)
145
+
146
+ **CQRS** separates the **write model** (commands, aggregates, transactional consistency) from the **read model** (projections, queries, possibly different storage).
147
+
148
+ **In a modular monolith (Modulith):** The module that owns the aggregate handles commands and publishes events (see transactional event listeners in `references/spring-modulith.md`). The same or another module can subscribe to those events and update a read model (e.g. a dedicated table or document store). Queries are served from the read model.
149
+
150
+ **Across services:** Use Kafka (or another message broker) to publish domain events; consumer services build and maintain their own read models. See `references/spring-messaging.md` for producers and consumers. Ensure idempotency and ordering guarantees in consumers when building read models.
151
+
152
+ Consider CQRS when read and write workloads or models diverge significantly (e.g. many reads with different shapes, or event-sourced writes with separate projections). For simple CRUD, a single model is often enough.
153
+
154
+ ---
155
+
156
+ **Summary:** Use **ports (interfaces)** for use cases and repositories; implement them with **adapters** (REST, JPA/JdbcClient, Kafka). Structure by **Vertical Slice** per feature if it fits your team. Map **DDD** bounded contexts to **Modulith** modules and use the “DDD & Modulith” section in `references/spring-modulith.md` for aggregates and domain events. Use **CQRS** with event-driven updates when read and write models need to diverge; combine Modulith events and Kafka as needed.
@@ -0,0 +1,77 @@
1
+ # Microservices Architecture — Spring Boot 4
2
+
3
+ **Spring Boot**: 4.0.x | Microservices design | **Jakarta EE**: 11
4
+
5
+ This reference covers when to choose microservices vs a modular monolith, service boundaries, inter-service communication, API Gateway, and distributed observability. For building each service, use `references/spring-boot-4.md`, `references/spring-framework-7.md`, and for event-driven messaging `references/spring-messaging.md`. For a modular monolith alternative, see `references/spring-modulith.md`.
6
+
7
+ ---
8
+
9
+ ## Table of Contents
10
+
11
+ 1. [When to Choose Microservices vs Modular Monolith (Modulith)](#1-when-to-choose-microservices-vs-modular-monolith-modulith)
12
+ 2. [Service Boundaries](#2-service-boundaries)
13
+ 3. [Inter-Service Communication](#3-inter-service-communication)
14
+ 4. [API Gateway](#4-api-gateway)
15
+ 5. [Distributed Observability](#5-distributed-observability)
16
+ 6. [Config and Discovery (Optional)](#6-config-and-discovery-optional)
17
+
18
+ ---
19
+
20
+ ## 1. When to Choose Microservices vs Modular Monolith (Modulith)
21
+
22
+ | Factor | Prefer Modulith (modular monolith) | Prefer Microservices |
23
+ |--------|-------------------------------------|----------------------|
24
+ | **Team structure** | Single team or few teams; shared codebase is manageable | Multiple teams owning different services; need independent delivery |
25
+ | **Scaling** | Scale the whole application (e.g. more replicas of the same process) | Scale individual services (e.g. only the heavy-read service) |
26
+ | **Deployment** | One deployable; simpler pipelines and rollbacks | Independent deploy per service; more operational complexity |
27
+ | **Transactions** | Single database or local transactions across modules | Distributed transactions are hard; prefer eventual consistency and events |
28
+ | **Latency** | In-process calls; low latency between modules | Network calls between services; higher latency and failure modes |
29
+ | **Domain** | Domains are related; modules can communicate via events in one process | Bounded contexts are clearly separate (e.g. different companies or products) |
30
+
31
+ Start with a **modular monolith** (Modulith) when the domain and team do not clearly demand separate deployments and scaling. Extract to microservices when you hit real limits (team boundaries, scaling, technology diversity). See `references/spring-modulith.md` for module structure and event-driven communication inside one application.
32
+
33
+ ---
34
+
35
+ ## 2. Service Boundaries
36
+
37
+ - **One service = one bounded context** (or a cohesive subdomain). Avoid sharing a single database across services; each service typically owns its own data store. This reduces coupling and allows independent schema evolution.
38
+ - **API contracts:** Define clear contracts between services. For REST, use **OpenAPI**; generate client DTOs or use a shared library. Document and version the API (e.g. URL path or header). See the OpenAPI/springdoc section in `references/spring-boot-4.md` for exposing and documenting REST APIs from each service.
39
+ - **Database per service:** Each service uses its own database (or schema). Replicate data across services only via events or explicit sync APIs when necessary; avoid distributed transactions.
40
+
41
+ ---
42
+
43
+ ## 3. Inter-Service Communication
44
+
45
+ **Synchronous (request/response):** Use **RestClient** (see `references/spring-framework-7.md`) to call other services. Share contracts (OpenAPI spec or DTOs). Handle timeouts, retries, and circuit breakers; Spring 7’s resilience annotations (`@Retryable`, `@CircuitBreaker`) can wrap outbound calls. For high-throughput or low-latency sync, consider gRPC in addition to REST.
46
+
47
+ **Asynchronous (events):** Use **Kafka** (or similar) for cross-service events. The producer service publishes domain events; consumer services subscribe and update their own state. Prefer events when you need decoupling, resilience (consumer can process later), or audit. See `references/spring-messaging.md` for producers and `@KafkaListener` consumers. Design for **idempotency** (consumer can process the same message twice safely) and **ordering** (partition by key when order matters).
48
+
49
+ **When to use which:** Use sync when the caller needs an immediate response (e.g. “get order by ID”). Use async when the operation can complete later or when multiple services react to the same event (e.g. “order placed” → inventory, notifications, analytics).
50
+
51
+ ---
52
+
53
+ ## 4. API Gateway
54
+
55
+ An **API Gateway** sits in front of your services and handles routing, authentication/authorization at the edge, rate limiting, and sometimes aggregation. **Spring Cloud Gateway** is the Spring-based option: you configure routes (e.g. by path or host), filters (JWT validation, rate limiting), and point to backend services. Rate limiting at the gateway was mentioned in `references/spring-boot-4.md` (Rate limiting) as an alternative to in-app Bucket4j.
56
+
57
+ Detailed route and filter configuration is outside this skill; see the [Spring Cloud Gateway documentation](https://docs.spring.io/spring-cloud-gateway/reference/) for setup. Each backend service remains a Spring Boot application with its own security (e.g. OAuth2 Resource Server) as in `references/spring-security-7.md`.
58
+
59
+ ---
60
+
61
+ ## 5. Distributed Observability
62
+
63
+ **Distributed tracing:** Propagate a **trace ID** across service boundaries so a single request can be followed through multiple services. **OpenTelemetry** (OTEL) with W3C Trace Context headers is the standard. Each Spring Boot 4 service enables Actuator and OTEL as in `references/spring-boot-4.md` (Actuator & Observability). Ensure the HTTP client (RestClient) and Kafka producers/consumers propagate trace context; Boot’s OTEL integration typically does this when configured. The collector receives spans from all services and correlates them by trace ID.
64
+
65
+ **Metrics and logs:** Each service exposes metrics (e.g. Prometheus) and logs in a consistent format. Aggregate metrics and logs in a central platform (e.g. Grafana, centralized logging). Use the same stack (Micrometer, OTEL) in every service for consistency. See `references/spring-boot-4.md` for Actuator, OTEL export, and health groups.
66
+
67
+ ---
68
+
69
+ ## 6. Config and Discovery (Optional)
70
+
71
+ **Centralized config:** **Spring Cloud Config** can provide configuration (e.g. `application.yaml`) to multiple services from a central server. Use it when you need to change config without redeploying each service. See the [Spring Cloud Config documentation](https://docs.spring.io/spring-cloud-config/reference/) for setup.
72
+
73
+ **Service discovery:** When services need to find each other by name (e.g. “order-service” instead of a fixed URL), use a discovery mechanism (e.g. Consul, Eureka, or Kubernetes services). Spring Cloud supports discovery clients; each service registers itself and resolves others by name. This is optional; you can also use static URLs or a gateway that routes by path.
74
+
75
+ ---
76
+
77
+ **Summary:** Choose **microservices** when team boundaries, independent scaling, or deployment justify the operational cost; otherwise start with a **modular monolith** (Modulith). Define **service boundaries** around bounded contexts and avoid shared databases. Use **RestClient** for sync and **Kafka** for async communication; design for idempotency and ordering. Put an **API Gateway** (e.g. Spring Cloud Gateway) at the edge for routing and auth. Use **OpenTelemetry** and propagate trace context so you get **distributed observability** across all services.
@@ -18,6 +18,8 @@
18
18
  11. [Reactive Stack (R2DBC + WebFlux)](#11-reactive-stack-r2dbc--webflux)
19
19
  12. [Rate Limiting](#12-rate-limiting)
20
20
  13. [Resources & Performance](#13-resources--performance)
21
+ 14. [API Documentation (OpenAPI / springdoc)](#14-api-documentation-openapi--springdoc)
22
+ 15. [Scheduling](#15-scheduling)
21
23
 
22
24
  ---
23
25
 
@@ -598,3 +600,87 @@ Use short TTLs or size limits to avoid stale or unbounded caches.
598
600
  - **Pool sizing:** Set HikariCP (or R2DBC pool) size based on observed metrics (connections in use, pending); avoid over-provisioning.
599
601
  - **N+1:** Avoid N+1 queries in JPA (e.g. `@EntityGraph`, fetch joins, or DTO projections) so a single request does not open many statements.
600
602
  - **Observability:** Use Actuator/Prometheus and traces (section 4) to find bottlenecks (slow endpoints, DB, or external calls) and tune accordingly. No JVM-level tuning (heap, GC) is covered here.
603
+
604
+ ---
605
+
606
+ ## 14. API Documentation (OpenAPI / springdoc)
607
+
608
+ Use **springdoc-openapi** to expose OpenAPI 3 spec and Swagger UI from your REST controllers. The JSON/YAML spec is consumed by clients and code generators; the UI is useful in development.
609
+
610
+ **Dependency:**
611
+
612
+ ```kotlin
613
+ // build.gradle.kts
614
+ dependencies {
615
+ implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0") // align with Boot 4
616
+ }
617
+ ```
618
+
619
+ **application.yaml:**
620
+
621
+ ```yaml
622
+ springdoc:
623
+ api-docs:
624
+ path: /v3/api-docs
625
+ swagger-ui:
626
+ path: /swagger-ui.html
627
+ ```
628
+
629
+ Document controllers with `@Operation` and `@Parameter`:
630
+
631
+ ```java
632
+ import io.swagger.v3.oas.annotations.Operation;
633
+ import io.swagger.v3.oas.annotations.Parameter;
634
+ import io.swagger.v3.oas.annotations.tags.Tag;
635
+
636
+ @RestController
637
+ @RequestMapping("/api/products")
638
+ @Tag(name = "Products", description = "Product API")
639
+ public class ProductController {
640
+
641
+ @GetMapping("/{id}")
642
+ @Operation(summary = "Get product by ID")
643
+ public Product get(@Parameter(description = "Product ID") @PathVariable String id) {
644
+ return productService.findById(id);
645
+ }
646
+ }
647
+ ```
648
+
649
+ The OpenAPI spec is available at `springdoc.api-docs.path` (default `/v3/api-docs`); Swagger UI at `springdoc.swagger-ui.path`. Protect these endpoints in production via Spring Security 7 (e.g. allow only for authenticated users or internal network). See [springdoc documentation](https://springdoc.org/) for grouping, security schemes, and more.
650
+
651
+ ---
652
+
653
+ ## 15. Scheduling
654
+
655
+ Use `@EnableScheduling` and `@Scheduled` for periodic tasks (cron, fixed rate, or fixed delay).
656
+
657
+ **Enable scheduling:**
658
+
659
+ ```java
660
+ @SpringBootApplication
661
+ @EnableScheduling
662
+ public class Application { ... }
663
+ ```
664
+
665
+ **Scheduled component:**
666
+
667
+ ```java
668
+ import org.springframework.scheduling.annotation.Scheduled;
669
+ import org.springframework.stereotype.Component;
670
+
671
+ @Component
672
+ public class SyncJob {
673
+
674
+ @Scheduled(fixedRate = 60000) // every 60 seconds
675
+ public void sync() {
676
+ // run task
677
+ }
678
+
679
+ @Scheduled(cron = "0 0 * * * *") // every hour at minute 0
680
+ public void hourlyReport() {
681
+ // run task
682
+ }
683
+ }
684
+ ```
685
+
686
+ With **virtual threads** enabled (section 6), scheduled tasks run on virtual threads when the default task scheduler is used; blocking work in the task does not block platform threads. For a custom `TaskScheduler` (e.g. thread pool size), define a `TaskScheduler` bean and configure as needed. Spring Batch is not covered here; for batch jobs (chunk-based reading/writing), see Spring Batch documentation.
@@ -0,0 +1,168 @@
1
+ # Spring Data MongoDB — Boot 4
2
+
3
+ **Spring Boot**: 4.0.x | **Spring Data MongoDB**: aligned with Boot BOM | **Jakarta EE**: 11
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Dependencies](#1-dependencies)
10
+ 2. [application.yaml](#2-applicationyaml)
11
+ 3. [Documents and @Document](#3-documents-and-document)
12
+ 4. [MongoRepository](#4-mongorepository)
13
+ 5. [MongoTemplate](#5-mongotemplate)
14
+ 6. [Transactions and indexes](#6-transactions-and-indexes)
15
+
16
+ ---
17
+
18
+ ## 1. Dependencies
19
+
20
+ Spring Boot 4 BOM manages Spring Data MongoDB. Add the starter:
21
+
22
+ ```kotlin
23
+ // build.gradle.kts
24
+ dependencies {
25
+ implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
26
+ }
27
+ ```
28
+
29
+ ---
30
+
31
+ ## 2. application.yaml
32
+
33
+ ```yaml
34
+ spring:
35
+ data:
36
+ mongodb:
37
+ uri: mongodb://localhost:27017/mydb
38
+ # or separately:
39
+ # host: localhost
40
+ # port: 27017
41
+ # database: mydb
42
+ # username: app
43
+ # password: secret
44
+ ```
45
+
46
+ For connection pool tuning (MongoDB driver):
47
+
48
+ ```yaml
49
+ spring:
50
+ data:
51
+ mongodb:
52
+ uri: mongodb://localhost:27017/mydb
53
+ auto-index-creation: true
54
+ ```
55
+
56
+ ---
57
+
58
+ ## 3. Documents and @Document
59
+
60
+ Use a Java record or class with `@Document` and `@Id`. Prefer records for DTOs; for entities that need lazy loading or complex mapping, a class is fine.
61
+
62
+ ```java
63
+ import org.springframework.data.annotation.Id;
64
+ import org.springframework.data.mongodb.core.mapping.Document;
65
+ import org.springframework.data.mongodb.core.index.Indexed;
66
+
67
+ @Document(collection = "products")
68
+ public record Product(
69
+ @Id String id,
70
+ String name,
71
+ @Indexed String sku,
72
+ java.math.BigDecimal price
73
+ ) {}
74
+ ```
75
+
76
+ For mutable entities (e.g. append-only fields), use a class with getters/setters and `@Id` on the identifier field.
77
+
78
+ ---
79
+
80
+ ## 4. MongoRepository
81
+
82
+ Extend `MongoRepository<Entity, IdType>` for CRUD and query methods. Use `String` as ID type for MongoDB ObjectId-backed ids.
83
+
84
+ ```java
85
+ import org.springframework.data.mongodb.repository.MongoRepository;
86
+ import java.util.List;
87
+
88
+ public interface ProductRepository extends MongoRepository<Product, String> {
89
+
90
+ List<Product> findByName(String name);
91
+
92
+ List<Product> findByPriceBetween(java.math.BigDecimal min, java.math.BigDecimal max);
93
+
94
+ boolean existsBySku(String sku);
95
+ }
96
+ ```
97
+
98
+ Custom queries with `@Query`:
99
+
100
+ ```java
101
+ @Query("{ 'name' : { $regex: ?0, $options: 'i' } }")
102
+ List<Product> findByNameRegex(String pattern);
103
+ ```
104
+
105
+ Use `MongoRepository` when you need standard CRUD and derived queries; use `MongoTemplate` for dynamic queries or aggregations (see [Spring Data MongoDB docs](https://docs.spring.io/spring-data/mongodb/reference/) for aggregation pipelines).
106
+
107
+ ---
108
+
109
+ ## 5. MongoTemplate
110
+
111
+ For programmatic or dynamic queries, inject `MongoTemplate`:
112
+
113
+ ```java
114
+ import org.springframework.data.mongodb.core.MongoTemplate;
115
+ import org.springframework.data.mongodb.core.query.Criteria;
116
+ import org.springframework.data.mongodb.core.query.Query;
117
+ import org.springframework.data.mongodb.core.query.Update;
118
+ import org.springframework.stereotype.Service;
119
+
120
+ @Service
121
+ public class ProductService {
122
+
123
+ private final MongoTemplate mongo;
124
+
125
+ public ProductService(MongoTemplate mongo) {
126
+ this.mongo = mongo;
127
+ }
128
+
129
+ public Product findById(String id) {
130
+ return mongo.findById(id, Product.class);
131
+ }
132
+
133
+ public List<Product> findBySku(String sku) {
134
+ return mongo.find(Query.query(Criteria.where("sku").is(sku)), Product.class);
135
+ }
136
+
137
+ public Product insert(Product product) {
138
+ return mongo.insert(product);
139
+ }
140
+
141
+ public void updatePrice(String id, java.math.BigDecimal price) {
142
+ mongo.updateFirst(
143
+ Query.query(Criteria.where("id").is(id)),
144
+ Update.update("price", price),
145
+ Product.class
146
+ );
147
+ }
148
+ }
149
+ ```
150
+
151
+ ---
152
+
153
+ ## 6. Transactions and indexes
154
+
155
+ **Transactions:** Supported when MongoDB is run as a replica set. Enable with `@Transactional` on the method (or class). Spring Data MongoDB uses the same transaction manager as other Spring Data stores when configured.
156
+
157
+ ```java
158
+ @Transactional
159
+ public void transfer(Product from, Product to, int qty) {
160
+ // multiple read/write operations in one transaction
161
+ }
162
+ ```
163
+
164
+ **Indexes:** Use `@Indexed` on fields for single-field indexes. For compound or custom indexes, create them at startup via `MongoTemplate.indexOps(Product.class).ensureIndex(new Index().on("name", Sort.Direction.ASC).on("price", Sort.Direction.DESC))` or with `@CompoundIndex` on the document class. Set `spring.data.mongodb.auto-index-creation: true` in development; in production, manage indexes via migrations or infrastructure as code.
165
+
166
+ ---
167
+
168
+ **Summary:** Use `spring-boot-starter-data-mongodb` with Boot 4 BOM, configure URI (or host/port/database) in `application.yaml`, and model documents with `@Document` and `@Id`. Use `MongoRepository` for CRUD and derived queries; use `MongoTemplate` for dynamic or programmatic access. Use transactions on replica sets and define indexes via `@Indexed` or programmatic API. For aggregation pipelines, see the official Spring Data MongoDB reference.
@@ -20,6 +20,7 @@ For **reactive applications (WebFlux + R2DBC)**, combine this reference with the
20
20
  11. [Enhanced PathPattern](#11-enhanced-pathpattern)
21
21
  12. [RestTestClient (Testing)](#12-resttestclient-testing)
22
22
  13. [Removed APIs Migration](#13-removed-apis-migration)
23
+ 14. [Bean Validation 3.1](#14-bean-validation-31)
23
24
 
24
25
  ---
25
26
 
@@ -316,3 +317,39 @@ class ProductControllerTest {
316
317
  | XML Spring MVC config | `WebMvcConfigurer` (Java) |
317
318
  | `suffixPatternMatch` | Explicit media types |
318
319
  | `trailingSlashMatch` | Explicit URI templates |
320
+
321
+ ---
322
+
323
+ ## 14. Bean Validation 3.1
324
+
325
+ Spring MVC and WebFlux support **Jakarta Bean Validation 3.1** (Boot 4 brings the dependency). Use `@Valid` (or `@Validated`) on `@RequestBody`, and optionally on `@RequestParam` / path variables with group validation or custom validators.
326
+
327
+ **DTO with constraints:**
328
+
329
+ ```java
330
+ import jakarta.validation.constraints.Email;
331
+ import jakarta.validation.constraints.NotBlank;
332
+ import jakarta.validation.constraints.Size;
333
+
334
+ public record CreateUserRequest(
335
+ @NotBlank(message = "Name is required")
336
+ @Size(min = 1, max = 100)
337
+ String name,
338
+
339
+ @NotBlank
340
+ @Email(message = "Must be a valid email")
341
+ String email
342
+ ) {}
343
+ ```
344
+
345
+ **Controller:**
346
+
347
+ ```java
348
+ @PostMapping("/api/users")
349
+ public ResponseEntity<User> create(@Valid @RequestBody CreateUserRequest request) {
350
+ User user = userService.create(request);
351
+ return ResponseEntity.status(HttpStatus.CREATED).body(user);
352
+ }
353
+ ```
354
+
355
+ Validation failures trigger `MethodArgumentNotValidException`; handle them in an `@ExceptionHandler` to return 400 with error details. Standard annotations include `@NotNull`, `@NotBlank`, `@Size`, `@Min`, `@Max`, `@Email`, `@Pattern`. For validation groups or custom validators, use `@Validated` with a group class or implement `ConstraintValidator`; see the Bean Validation spec for details.
@@ -0,0 +1,150 @@
1
+ # Spring for GraphQL — Boot 4
2
+
3
+ **Spring Boot**: 4.0.x | **Spring for GraphQL**: aligned with Boot BOM | **Jakarta EE**: 11
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Dependencies](#1-dependencies)
10
+ 2. [application.yaml](#2-applicationyaml)
11
+ 3. [Schema (SDL)](#3-schema-sdl)
12
+ 4. [Query and mutation controllers](#4-query-and-mutation-controllers)
13
+ 5. [Records for types](#5-records-for-types)
14
+ 6. [Security](#6-security)
15
+
16
+ ---
17
+
18
+ ## 1. Dependencies
19
+
20
+ Spring Boot 4 BOM manages Spring for GraphQL. Add the starter:
21
+
22
+ ```kotlin
23
+ // build.gradle.kts
24
+ dependencies {
25
+ implementation("org.springframework.boot:spring-boot-starter-graphql")
26
+ implementation("org.springframework.boot:spring-boot-starter-web") // or webflux
27
+ }
28
+ ```
29
+
30
+ ---
31
+
32
+ ## 2. application.yaml
33
+
34
+ ```yaml
35
+ spring:
36
+ graphql:
37
+ graphiql:
38
+ enabled: true # dev: UI at /graphiql
39
+ path: /graphql # default
40
+ cors:
41
+ allowed-origins: "https://myapp.example.com"
42
+ ```
43
+
44
+ The GraphQL endpoint is exposed at `spring.graphql.path` (default `/graphql`). Use the same `SecurityFilterChain` as for REST to protect it; see section 6.
45
+
46
+ ---
47
+
48
+ ## 3. Schema (SDL)
49
+
50
+ Place schema files under `src/main/resources/graphql/**/*.graphqls` (or `.graphqls`). Boot auto-picks them.
51
+
52
+ Example `src/main/resources/graphql/schema.graphqls`:
53
+
54
+ ```graphql
55
+ type Query {
56
+ product(id: ID!): Product
57
+ products(first: Int = 10): [Product!]!
58
+ }
59
+
60
+ type Mutation {
61
+ createProduct(input: CreateProductInput!): Product!
62
+ }
63
+
64
+ type Product {
65
+ id: ID!
66
+ name: String!
67
+ sku: String!
68
+ price: Float!
69
+ }
70
+
71
+ input CreateProductInput {
72
+ name: String!
73
+ sku: String!
74
+ price: Float!
75
+ }
76
+ ```
77
+
78
+ ---
79
+
80
+ ## 4. Query and mutation controllers
81
+
82
+ Use `@Controller` and `@QueryMapping` / `@MutationMapping`. Method names match schema field names by default, or specify with the annotation.
83
+
84
+ ```java
85
+ import org.springframework.graphql.data.method.annotation.Argument;
86
+ import org.springframework.graphql.data.method.annotation.MutationMapping;
87
+ import org.springframework.graphql.data.method.annotation.QueryMapping;
88
+ import org.springframework.stereotype.Controller;
89
+
90
+ @Controller
91
+ public class ProductGraphQLController {
92
+
93
+ private final ProductService productService;
94
+
95
+ public ProductGraphQLController(ProductService productService) {
96
+ this.productService = productService;
97
+ }
98
+
99
+ @QueryMapping
100
+ public Product product(@Argument String id) {
101
+ return productService.findById(id);
102
+ }
103
+
104
+ @QueryMapping
105
+ public java.util.List<Product> products(@Argument Integer first) {
106
+ int limit = first != null ? first : 10;
107
+ return productService.findAll(limit);
108
+ }
109
+
110
+ @MutationMapping
111
+ public Product createProduct(@Argument CreateProductInput input) {
112
+ return productService.create(input.name(), input.sku(), input.price());
113
+ }
114
+ }
115
+ ```
116
+
117
+ For nested types (e.g. `Product` has a `category` field), use `@SchemaMapping` on a method that takes the parent object and returns the nested one:
118
+
119
+ ```java
120
+ @SchemaMapping(typeName = "Product", field = "category")
121
+ public Category category(Product product) {
122
+ return categoryService.findById(product.categoryId());
123
+ }
124
+ ```
125
+
126
+ ---
127
+
128
+ ## 5. Records for types
129
+
130
+ Use Java records for DTOs and inputs. Spring for GraphQL maps them to the schema:
131
+
132
+ ```java
133
+ public record CreateProductInput(String name, String sku, double price) {}
134
+
135
+ public record Product(String id, String name, String sku, double price, String categoryId) {}
136
+ ```
137
+
138
+ Ensure record component names align with schema field names (or use `@JsonProperty` if names differ). Use `jakarta.*` and JSpecify where applicable for nullability in the API layer.
139
+
140
+ ---
141
+
142
+ ## 6. Security
143
+
144
+ GraphQL is exposed over HTTP like REST. Protect the GraphQL path in your `SecurityFilterChain` (see `references/spring-security-7.md`): require authentication for `/graphql` and optionally allow anonymous for introspection in dev only. For authenticated GraphQL, clients typically send the same token (e.g. Bearer JWT) in the `Authorization` header; the resolver can access the current user via `SecurityContextHolder` or a custom context in the GraphQL execution.
145
+
146
+ Restrict introspection in production if you do not want to expose the full schema to unauthenticated clients.
147
+
148
+ ---
149
+
150
+ **Summary:** Use `spring-boot-starter-graphql` with Boot 4 BOM, define the schema in `.graphqls` under `resources/graphql`, and implement queries and mutations with `@Controller`, `@QueryMapping`, and `@MutationMapping`. Use records for input and output types. Secure the GraphQL endpoint with the same Spring Security 7 configuration as REST.
@@ -14,6 +14,7 @@
14
14
  7. [Module Integration Testing](#7-module-integration-testing)
15
15
  8. [Generating Documentation](#8-generating-documentation)
16
16
  9. [Common Pitfalls](#9-common-pitfalls)
17
+ 10. [DDD & Modulith](#10-ddd--modulith)
17
18
 
18
19
  ---
19
20
 
@@ -231,3 +232,13 @@ Output lands in `target/spring-modulith-docs/` (Maven) or `build/spring-modulith
231
232
  | **Forgetting the verification test in CI** | Add the module verification test (section 3) to your CI pipeline so boundary violations are caught on every commit. |
232
233
  | **Direct service calls across modules** | One module must not inject another module's service and call it directly. Use `ApplicationEventPublisher` and `@ApplicationModuleListener` (or transactional events) for cross-module communication. |
233
234
  | **Putting shared DTOs in one module's internal** | Types used in events or APIs consumed by several modules belong in a `shared/` (or similar) package, not in one module's `internal/`. |
235
+
236
+ ---
237
+
238
+ ## 10. DDD & Modulith
239
+
240
+ **Aggregate:** An aggregate is a cluster of entities and value objects with a **root entity** that enforces invariants. It is loaded and persisted as a unit. In Modulith, a module usually has one or more aggregates; the module’s public service (e.g. `OrderService`) orchestrates the aggregate: it loads the root via a repository, mutates it, and saves. Example: `Order` as aggregate root; `OrderService.placeOrder(...)` loads or creates an `Order`, applies domain logic, calls `OrderRepository.save(order)`, and publishes events. The repository interface lives in the module API; the implementation (JdbcClient or JPA) lives in `internal/`.
241
+
242
+ **Domain repository:** A **domain repository** is an interface that exposes only domain operations (e.g. `save(Order)`, `findById(OrderId)`), without infrastructure details. In Spring terms, that interface is the **port**; the implementation in `internal/` (using JdbcClient, JPA, etc.) is the **adapter**. The repository you already use for the module (e.g. `OrderRepository`) acts as the domain repository if it only exposes domain-centric methods and returns domain types or optionals.
243
+
244
+ **Domain events vs application events:** A **domain event** is something that happened in the domain (e.g. “OrderPlaced”). An **application event** is the mechanism: you publish with `ApplicationEventPublisher` and other modules listen with `@ApplicationModuleListener`. In practice with Modulith, the events you publish between modules are application events that typically **represent** domain events of the publishing module. The payload (e.g. `OrderPlacedEvent`) carries the domain data. Section 5 (Event-Driven Inter-Module Communication) and section 6 (Transactional Event Listeners) describe how to publish and consume these; here we only distinguish: domain event = meaning; application event = Spring’s delivery mechanism.
@@ -0,0 +1,183 @@
1
+ # Spring Data Redis — Boot 4
2
+
3
+ **Spring Boot**: 4.0.x | **Spring Data Redis**: aligned with Boot BOM | **Jakarta EE**: 11
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Dependencies](#1-dependencies)
10
+ 2. [application.yaml](#2-applicationyaml)
11
+ 3. [RedisTemplate and StringRedisTemplate](#3-redistemplate-and-stringredistemplate)
12
+ 4. [Redis as cache backend](#4-redis-as-cache-backend)
13
+ 5. [Pub/Sub (optional)](#5-pubsub-optional)
14
+ 6. [Session store (optional)](#6-session-store-optional)
15
+
16
+ ---
17
+
18
+ ## 1. Dependencies
19
+
20
+ Spring Boot 4 BOM manages Spring Data Redis. Add the starter:
21
+
22
+ ```kotlin
23
+ // build.gradle.kts
24
+ dependencies {
25
+ implementation("org.springframework.boot:spring-boot-starter-data-redis")
26
+ // Optional: use Redis as distributed cache backend (see section 4)
27
+ // implementation("org.springframework.boot:spring-boot-starter-cache")
28
+ }
29
+ ```
30
+
31
+ For connection pooling (Lettuce is the default client):
32
+
33
+ ```kotlin
34
+ // Lettuce is included transitively; no extra dependency for basic use
35
+ ```
36
+
37
+ ---
38
+
39
+ ## 2. application.yaml
40
+
41
+ ```yaml
42
+ spring:
43
+ data:
44
+ redis:
45
+ host: localhost
46
+ port: 6379
47
+ password: # set in production
48
+ timeout: 2000ms
49
+ lettuce:
50
+ pool:
51
+ max-active: 16
52
+ max-idle: 8
53
+ min-idle: 4
54
+ ```
55
+
56
+ For a single Redis URL:
57
+
58
+ ```yaml
59
+ spring:
60
+ data:
61
+ redis:
62
+ url: redis://user:password@localhost:6379/0
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 3. RedisTemplate and StringRedisTemplate
68
+
69
+ Use `StringRedisTemplate` for string keys/values; use `RedisTemplate<String, Object>` (with a configured serializer) for objects. Prefer strings when possible for simplicity and interoperability.
70
+
71
+ ```java
72
+ import org.springframework.data.redis.core.StringRedisTemplate;
73
+ import org.springframework.stereotype.Service;
74
+
75
+ @Service
76
+ public class TokenStore {
77
+
78
+ private final StringRedisTemplate redis;
79
+
80
+ public TokenStore(StringRedisTemplate redis) {
81
+ this.redis = redis;
82
+ }
83
+
84
+ public void save(String key, String value, java.time.Duration ttl) {
85
+ var ops = redis.opsForValue();
86
+ ops.set(key, value, ttl);
87
+ }
88
+
89
+ public String get(String key) {
90
+ return redis.opsForValue().get(key);
91
+ }
92
+ }
93
+ ```
94
+
95
+ Hashes and lists:
96
+
97
+ ```java
98
+ redis.opsForHash().put("user:1", "name", "Alice");
99
+ redis.opsForHash().put("user:1", "email", "alice@example.com");
100
+ redis.opsForList().rightPush("queue:tasks", taskId);
101
+ ```
102
+
103
+ Use Records or simple DTOs when storing JSON; serialize with Jackson and store as string, or use `RedisTemplate<String, YourRecord>` with `GenericJackson2JsonRedisSerializer` (ensure Jakarta and Boot 4 Jackson versions align).
104
+
105
+ ---
106
+
107
+ ## 4. Redis as cache backend
108
+
109
+ For distributed caching, use Redis instead of Caffeine. Enable caching and set the cache type to Redis:
110
+
111
+ ```yaml
112
+ spring:
113
+ cache:
114
+ type: redis
115
+ cache-names: products,users
116
+ data:
117
+ redis:
118
+ host: localhost
119
+ port: 6379
120
+ ```
121
+
122
+ ```java
123
+ @SpringBootApplication
124
+ @EnableCaching
125
+ public class Application { ... }
126
+ ```
127
+
128
+ Use `@Cacheable`, `@CacheEvict`, `@CachePut` as with any Spring Cache backend. TTL can be configured per cache via `spring.cache.redis.time-to-live` or custom `RedisCacheConfiguration` if needed.
129
+
130
+ Dependencies: `spring-boot-starter-cache` and `spring-boot-starter-data-redis`. No extra starter for Redis cache; Boot auto-configures it when `type: redis` is set.
131
+
132
+ ---
133
+
134
+ ## 5. Pub/Sub (optional)
135
+
136
+ Publish messages with `RedisTemplate`:
137
+
138
+ ```java
139
+ redis.convertAndSend("notifications", "User signed up: " + userId);
140
+ ```
141
+
142
+ Subscribe with a listener:
143
+
144
+ ```java
145
+ import org.springframework.data.redis.connection.Message;
146
+ import org.springframework.data.redis.connection.MessageListener;
147
+ import org.springframework.data.redis.listener.ChannelTopic;
148
+ import org.springframework.data.redis.listener.RedisMessageListenerContainer;
149
+ import org.springframework.context.annotation.Bean;
150
+ import org.springframework.context.annotation.Configuration;
151
+
152
+ @Configuration
153
+ public class RedisPubSubConfig {
154
+
155
+ @Bean
156
+ RedisMessageListenerContainer redisMessageListenerContainer(
157
+ org.springframework.data.redis.connection.RedisConnectionFactory factory,
158
+ NotificationSubscriber subscriber) {
159
+ var container = new RedisMessageListenerContainer();
160
+ container.setConnectionFactory(factory);
161
+ container.addMessageListener(subscriber, new ChannelTopic("notifications"));
162
+ return container;
163
+ }
164
+ }
165
+ ```
166
+
167
+ Implement `MessageListener` and handle `message.getBody()` in `onMessage`.
168
+
169
+ ---
170
+
171
+ ## 6. Session store (optional)
172
+
173
+ To store HTTP sessions in Redis, add Spring Session:
174
+
175
+ ```kotlin
176
+ implementation("org.springframework.session:spring-session-data-redis")
177
+ ```
178
+
179
+ Configure session timeout and optionally namespace in `application.yaml`. Sessions are then stored in Redis instead of in-memory; suitable for multi-instance deployments. Security and session configuration remain in Spring Security 7; see `references/spring-security-7.md` for auth.
180
+
181
+ ---
182
+
183
+ **Summary:** Use `spring-boot-starter-data-redis` with Boot 4 BOM, configure host/port/pool in `application.yaml`, and use `StringRedisTemplate` or `RedisTemplate` for keys/values, hashes, and lists. Use `spring.cache.type=redis` for distributed cache; optionally use pub/sub or Spring Session Data Redis for sessions.