spring-boot4-skill 1.3.0 → 1.4.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,18 @@ 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.4.0] - 2026-02-21
9
+
10
+ ### Added
11
+
12
+ - **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).
13
+ - **Skill:** spring-boot-4.md: new section 14 (API documentation — OpenAPI/springdoc) and section 15 (Scheduling — @Scheduled, cron, virtual threads).
14
+ - **Skill:** spring-framework-7.md: new section 14 (Bean Validation 3.1 — @Valid, @NotNull, @Size, @Email, Records).
15
+ - **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.
16
+ - **README:** Skill reference table: spring-redis.md, spring-data-mongodb.md, spring-graphql.md; extended descriptions for spring-boot-4 and spring-framework-7.
17
+
18
+ [1.4.0]: https://github.com/AyrtonAldayr/agent-skill-java-spring-framework/compare/v1.3.0...v1.4.0
19
+
8
20
  ## [1.3.0] - 2026-02-21
9
21
 
10
22
  ### 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,10 +133,13 @@ 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 |
142
+ | `skills/java-spring-framework/references/spring-graphql.md` | GraphQL API, Spring for GraphQL |
140
143
  | `skills/java-spring-framework/references/spring-modulith.md` | Module structure, events, integration testing, common pitfalls |
141
144
  | `skills/java-spring-framework/references/build-templates.md` | Complete Gradle KTS + Maven POM templates |
142
145
  | `skills/java-spring-framework/references/troubleshooting-migration.md` | Common errors (javax/jakarta, RestTemplate), Boot 3→4 checklist |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spring-boot4-skill",
3
- "version": "1.3.0",
3
+ "version": "1.4.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": {
@@ -44,6 +44,12 @@ flowchart TD
44
44
  M -->|Yes| N[spring-messaging.md]
45
45
  A --> O{Rate limit / resources / performance?}
46
46
  O -->|Yes| P[spring-boot-4.md]
47
+ A --> Q{Redis / cache distribuido?}
48
+ Q -->|Yes| R[spring-redis.md]
49
+ A --> S{MongoDB / document DB?}
50
+ S -->|Yes| T[spring-data-mongodb.md]
51
+ A --> U{GraphQL API?}
52
+ U -->|Yes| V[spring-graphql.md]
47
53
  ```
48
54
 
49
55
  ## Mandatory Workflow
@@ -80,10 +86,13 @@ Load these as needed — do not load all at once:
80
86
 
81
87
  | Topic | File | Load when |
82
88
  |---|---|---|
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 |
89
+ | Spring Framework 7 APIs | `references/spring-framework-7.md` | Framework-level features: versioning, resilience, JSpecify, SpEL, streaming, Bean Validation, @Valid |
90
+ | 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
91
  | Spring Security 7 | `references/spring-security-7.md` | OAuth2 Resource Server, JWT, method security, CORS, authentication/authorization |
92
+ | Redis | `references/spring-redis.md` | Redis, cache distribuido, session store |
93
+ | MongoDB | `references/spring-data-mongodb.md` | MongoDB, document DB, Spring Data MongoDB |
86
94
  | Messaging (Kafka) | `references/spring-messaging.md` | Kafka, event-driven, messaging, @KafkaListener, producer/consumer |
95
+ | GraphQL | `references/spring-graphql.md` | GraphQL API, Spring for GraphQL |
87
96
  | Spring Modulith | `references/spring-modulith.md` | Domain-driven module design, event-driven architecture |
88
97
  | Build templates | `references/build-templates.md` | Gradle KTS or Maven POM scaffolding with 2026 BOM versions |
89
98
  | Troubleshooting & migration | `references/troubleshooting-migration.md` | Migration from Boot 3, compile/runtime errors (javax/jakarta, RestTemplate, native, null-safety) |
@@ -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.
@@ -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.