spring-boot4-skill 1.0.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/README.md +144 -0
- package/bin/create-spring-app.js +48 -0
- package/lib/generator.js +188 -0
- package/lib/prompts.js +115 -0
- package/lib/templates.js +45 -0
- package/package.json +44 -0
- package/skills/java-spring-framework/SKILL.md +56 -0
- package/skills/java-spring-framework/references/build-templates.md +304 -0
- package/skills/java-spring-framework/references/spring-boot-4.md +347 -0
- package/skills/java-spring-framework/references/spring-framework-7.md +314 -0
- package/skills/java-spring-framework/references/spring-modulith.md +220 -0
- package/skills-lock.json +20 -0
- package/templates/gradle-kotlin/build.gradle.kts.template +113 -0
- package/templates/gradle-kotlin/compose.yaml.template +40 -0
- package/templates/gradle-kotlin/settings.gradle.kts.template +1 -0
- package/templates/gradle-kotlin/src/main/java/com/example/app/Application.java.template +19 -0
- package/templates/gradle-kotlin/src/main/resources/application.yaml.template +60 -0
- package/templates/gradle-kotlin/src/test/java/com/example/app/ApplicationTests.java.template +17 -0
- package/templates/maven/pom.xml.template +159 -0
package/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Spring Boot 4 · Java 25 · Spring Framework 7
|
|
2
|
+
|
|
3
|
+
> **2026-standard** project scaffolder + Claude Code AI skill for Java / Spring development.
|
|
4
|
+
> By [AyrtonAldayr](https://github.com/AyrtonAldayr)
|
|
5
|
+
|
|
6
|
+
This repository provides two tools in one:
|
|
7
|
+
|
|
8
|
+
| Tool | What it does |
|
|
9
|
+
|---|---|
|
|
10
|
+
| **`npx spring-boot4-skill`** | Interactive CLI that generates a production-ready Spring Boot 4 project |
|
|
11
|
+
| **Claude Code skill** | AI assistant trained on Spring Boot 4 / Framework 7 / Java 25 standards |
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Quick Start — Project Scaffolder
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx spring-boot4-skill
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or providing the project name directly:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx spring-boot4-skill my-service
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Non-interactive (use all defaults):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx spring-boot4-skill my-service --no-interactive
|
|
31
|
+
|
|
32
|
+
# Maven instead of Gradle
|
|
33
|
+
npx spring-boot4-skill my-service --maven
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### What it generates
|
|
37
|
+
|
|
38
|
+
After answering a few prompts, you get a complete project with:
|
|
39
|
+
|
|
40
|
+
- **`build.gradle.kts`** (Gradle Kotlin DSL) or **`pom.xml`** (Maven) — with 2026 BOM versions
|
|
41
|
+
- **`Application.java`** — `@NullMarked`, `proxyBeanMethods = false`, Jakarta EE 11
|
|
42
|
+
- **`application.yaml`** — virtual threads enabled, OTEL endpoints, structured config
|
|
43
|
+
- **`ApplicationTests.java`** — Spring Boot test slice, `WebEnvironment.RANDOM_PORT`
|
|
44
|
+
- **`compose.yaml`** *(optional)* — Docker Compose for PostgreSQL 17, MongoDB 7, OTEL Collector
|
|
45
|
+
- **Spring Modulith module skeleton** *(optional)*
|
|
46
|
+
|
|
47
|
+
### Wizard options
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
? Project name: my-service
|
|
51
|
+
? Base package: com.acme
|
|
52
|
+
? Build tool: Gradle Kotlin DSL ◀ recommended
|
|
53
|
+
? Java version: 25
|
|
54
|
+
? Spring Boot version: 4.0.3
|
|
55
|
+
? Database: PostgreSQL 17
|
|
56
|
+
? Features:
|
|
57
|
+
◉ Actuator + OTEL Observability
|
|
58
|
+
◉ Spring Security 7 (OAuth2 Resource Server)
|
|
59
|
+
◉ Bean Validation 3.1
|
|
60
|
+
◯ Spring Modulith
|
|
61
|
+
◯ GraalVM Native Image
|
|
62
|
+
◯ Spring WebFlux
|
|
63
|
+
◯ Docker Compose support
|
|
64
|
+
? Enable preview features (Structured Concurrency, Scoped Values)? Yes
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Claude Code AI Skill
|
|
70
|
+
|
|
71
|
+
Install the skill to get AI assistance aligned with Spring Boot 4 / Framework 7 standards.
|
|
72
|
+
|
|
73
|
+
### Install from GitHub
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
claude skills install github:AyrtonAldayr/agent-skill-java-spring-framework
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### What the skill does
|
|
80
|
+
|
|
81
|
+
Once installed, Claude Code acts as a **Senior Spring Boot 4 architect**:
|
|
82
|
+
|
|
83
|
+
- Always uses `RestClient`, `JdbcClient`, `HttpServiceProxyFactory` — never `RestTemplate`
|
|
84
|
+
- Uses JSpecify `@NonNull` / `@Nullable` instead of JSR-305
|
|
85
|
+
- Generates `jakarta.*` namespaces (never `javax.*`)
|
|
86
|
+
- Applies Spring Modulith domain-driven patterns
|
|
87
|
+
- Uses Structured Concurrency (`StructuredTaskScope`) and Scoped Values on Java 25
|
|
88
|
+
- Knows native API versioning (`@RequestMapping(version = "...")`)
|
|
89
|
+
- Knows built-in Resilience annotations (`@Retryable`, `@ConcurrencyLimit`)
|
|
90
|
+
|
|
91
|
+
### Skill reference files
|
|
92
|
+
|
|
93
|
+
| File | Contents |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `skills/java-spring-framework/references/spring-framework-7.md` | All Spring 7 APIs with code examples |
|
|
96
|
+
| `skills/java-spring-framework/references/spring-boot-4.md` | Boot 4 features: native, virtual threads, Security 7, testing |
|
|
97
|
+
| `skills/java-spring-framework/references/spring-modulith.md` | Module structure, events, integration testing |
|
|
98
|
+
| `skills/java-spring-framework/references/build-templates.md` | Complete Gradle KTS + Maven POM templates |
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Platform Requirements
|
|
103
|
+
|
|
104
|
+
| Component | Version |
|
|
105
|
+
|---|---|
|
|
106
|
+
| Java | 25 (recommended) · 21 · 17 (minimum) |
|
|
107
|
+
| Spring Boot | 4.0.3 |
|
|
108
|
+
| Spring Framework | 7.0.5 |
|
|
109
|
+
| Spring Modulith | 2.0.3 |
|
|
110
|
+
| Jakarta EE | 11 |
|
|
111
|
+
| GraalVM (optional) | 24+ |
|
|
112
|
+
| Node.js (CLI only) | ≥ 20 |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Publishing to npm
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npm login
|
|
120
|
+
npm publish --access public
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
After publishing, developers can use:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx spring-boot4-skill
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Contributing
|
|
132
|
+
|
|
133
|
+
PRs welcome. Please keep all generated code aligned with:
|
|
134
|
+
|
|
135
|
+
- [Spring Boot 4.x docs](https://docs.spring.io/spring-boot/)
|
|
136
|
+
- [Spring Framework 7.x docs](https://docs.spring.io/spring-framework/reference/)
|
|
137
|
+
- [Spring Modulith docs](https://docs.spring.io/spring-modulith/reference/)
|
|
138
|
+
- [JSpecify](https://jspecify.dev/)
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* spring-boot4-skill — Interactive CLI scaffolder
|
|
4
|
+
* Spring Boot 4.x / Spring Framework 7.x / Java 25 (2026 standards)
|
|
5
|
+
* Author: AyrtonAldayr — https://github.com/AyrtonAldayr/agent-skill-java-spring-framework
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { program } from 'commander';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import { readFileSync } from 'fs';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import { dirname, join } from 'path';
|
|
13
|
+
import { runWizard } from '../lib/prompts.js';
|
|
14
|
+
import { generateProject } from '../lib/generator.js';
|
|
15
|
+
|
|
16
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
|
|
18
|
+
|
|
19
|
+
console.log(
|
|
20
|
+
chalk.bold.green('\n ╔══════════════════════════════════════╗') +
|
|
21
|
+
chalk.bold.green('\n ║ Spring Boot 4 Project Generator ║') +
|
|
22
|
+
chalk.bold.green('\n ║ Java 25 · Spring Framework 7 · 2026 ║') +
|
|
23
|
+
chalk.bold.green('\n ╚══════════════════════════════════════╝\n')
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
program
|
|
27
|
+
.name('spring-boot4-skill')
|
|
28
|
+
.description('Scaffold a Spring Boot 4.x / Java 25 project with 2026 best practices')
|
|
29
|
+
.version(pkg.version)
|
|
30
|
+
.argument('[project-name]', 'Project name (skips the prompt)')
|
|
31
|
+
.option('--gradle', 'Use Gradle Kotlin DSL (default)')
|
|
32
|
+
.option('--maven', 'Use Maven instead of Gradle')
|
|
33
|
+
.option('--no-interactive', 'Use defaults without prompts')
|
|
34
|
+
.action(async (projectName, options) => {
|
|
35
|
+
try {
|
|
36
|
+
const answers = await runWizard(projectName, options);
|
|
37
|
+
await generateProject(answers);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
if (err.name === 'ExitPromptError') {
|
|
40
|
+
console.log(chalk.yellow('\n Cancelled.'));
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
console.error(chalk.red('\n Error: ') + err.message);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
program.parse();
|
package/lib/generator.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project generator — renders templates and writes files to disk
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { mkdirSync, writeFileSync, readFileSync, copyFileSync } from 'fs';
|
|
6
|
+
import { join, dirname, resolve } from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import ora from 'ora';
|
|
10
|
+
import { renderTemplate } from './templates.js';
|
|
11
|
+
|
|
12
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const TEMPLATES_DIR = join(__dirname, '../templates');
|
|
14
|
+
|
|
15
|
+
export async function generateProject(config) {
|
|
16
|
+
const spinner = ora('Generating project…').start();
|
|
17
|
+
const projectDir = resolve(process.cwd(), config.projectName);
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Derive additional config values
|
|
21
|
+
const ctx = buildContext(config);
|
|
22
|
+
|
|
23
|
+
// Create root project directory
|
|
24
|
+
mkdirSync(projectDir, { recursive: true });
|
|
25
|
+
|
|
26
|
+
// Choose template set
|
|
27
|
+
const templateSet = config.buildTool === 'maven' ? 'maven' : 'gradle-kotlin';
|
|
28
|
+
|
|
29
|
+
// Generate files
|
|
30
|
+
generateBuildFile(projectDir, templateSet, ctx);
|
|
31
|
+
generateApplicationClass(projectDir, ctx);
|
|
32
|
+
generateApplicationYaml(projectDir, ctx, templateSet);
|
|
33
|
+
generateApplicationTests(projectDir, ctx);
|
|
34
|
+
|
|
35
|
+
if (ctx.features.includes('docker-compose')) {
|
|
36
|
+
generateDockerCompose(projectDir, ctx);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (ctx.features.includes('modulith')) {
|
|
40
|
+
generateModulithStructure(projectDir, ctx);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
spinner.succeed(chalk.green(`Project created at ${chalk.bold(projectDir)}`));
|
|
44
|
+
printNextSteps(config, projectDir);
|
|
45
|
+
|
|
46
|
+
} catch (err) {
|
|
47
|
+
spinner.fail('Generation failed');
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Context builder
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
function buildContext(config) {
|
|
57
|
+
const appName = toPascalCase(config.projectName);
|
|
58
|
+
const packagePath = config.packageName.replace(/\./g, '/');
|
|
59
|
+
const features = config.features || [];
|
|
60
|
+
|
|
61
|
+
const dbDependency = {
|
|
62
|
+
postgresql: "runtimeOnly(\"org.postgresql:postgresql\")",
|
|
63
|
+
mysql: "runtimeOnly(\"com.mysql:mysql-connector-j\")",
|
|
64
|
+
mongodb: "implementation(\"org.springframework.boot:spring-boot-starter-data-mongodb\")",
|
|
65
|
+
h2: "runtimeOnly(\"com.h2database:h2\")",
|
|
66
|
+
none: '',
|
|
67
|
+
}[config.database] || '';
|
|
68
|
+
|
|
69
|
+
const dbMavenDep = {
|
|
70
|
+
postgresql: '<groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><scope>runtime</scope>',
|
|
71
|
+
mysql: '<groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope>',
|
|
72
|
+
mongodb: '<groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>',
|
|
73
|
+
h2: '<groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope>',
|
|
74
|
+
none: '',
|
|
75
|
+
}[config.database] || '';
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
...config,
|
|
79
|
+
appName,
|
|
80
|
+
packagePath,
|
|
81
|
+
features,
|
|
82
|
+
dbDependency,
|
|
83
|
+
dbMavenDep,
|
|
84
|
+
hasJpa: ['postgresql', 'mysql', 'h2'].includes(config.database),
|
|
85
|
+
hasMongo: config.database === 'mongodb',
|
|
86
|
+
hasActuator: features.includes('actuator'),
|
|
87
|
+
hasSecurity: features.includes('security'),
|
|
88
|
+
hasValidation: features.includes('validation'),
|
|
89
|
+
hasModulith: features.includes('modulith'),
|
|
90
|
+
hasNative: features.includes('native'),
|
|
91
|
+
hasWebFlux: features.includes('webflux'),
|
|
92
|
+
hasDockerCompose: features.includes('docker-compose'),
|
|
93
|
+
enablePreview: config.enablePreview !== false && config.javaVersion === '25',
|
|
94
|
+
year: new Date().getFullYear(),
|
|
95
|
+
modulithDataDep: (() => {
|
|
96
|
+
const f = features;
|
|
97
|
+
const db = config.database;
|
|
98
|
+
if (!f.includes('modulith')) return '';
|
|
99
|
+
if (['postgresql', 'mysql', 'h2'].includes(db)) return 'implementation("org.springframework.modulith:spring-modulith-starter-jpa")';
|
|
100
|
+
if (db === 'mongodb') return 'implementation("org.springframework.modulith:spring-modulith-starter-mongodb")';
|
|
101
|
+
return '';
|
|
102
|
+
})(),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// File generators
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
function generateBuildFile(projectDir, templateSet, ctx) {
|
|
111
|
+
const file = templateSet === 'maven' ? 'pom.xml' : 'build.gradle.kts';
|
|
112
|
+
const content = renderTemplate(join(TEMPLATES_DIR, templateSet, `${file}.template`), ctx);
|
|
113
|
+
writeFileSync(join(projectDir, file), content);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function generateApplicationClass(projectDir, ctx) {
|
|
117
|
+
const srcDir = join(projectDir, 'src/main/java', ctx.packagePath);
|
|
118
|
+
mkdirSync(srcDir, { recursive: true });
|
|
119
|
+
const content = renderTemplate(
|
|
120
|
+
join(TEMPLATES_DIR, 'gradle-kotlin/src/main/java/com/example/app/Application.java.template'),
|
|
121
|
+
ctx
|
|
122
|
+
);
|
|
123
|
+
writeFileSync(join(srcDir, `${ctx.appName}Application.java`), content);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function generateApplicationYaml(projectDir, ctx) {
|
|
127
|
+
const resourcesDir = join(projectDir, 'src/main/resources');
|
|
128
|
+
mkdirSync(resourcesDir, { recursive: true });
|
|
129
|
+
const content = renderTemplate(
|
|
130
|
+
join(TEMPLATES_DIR, 'gradle-kotlin/src/main/resources/application.yaml.template'),
|
|
131
|
+
ctx
|
|
132
|
+
);
|
|
133
|
+
writeFileSync(join(resourcesDir, 'application.yaml'), content);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function generateApplicationTests(projectDir, ctx) {
|
|
137
|
+
const testDir = join(projectDir, 'src/test/java', ctx.packagePath);
|
|
138
|
+
mkdirSync(testDir, { recursive: true });
|
|
139
|
+
const content = renderTemplate(
|
|
140
|
+
join(TEMPLATES_DIR, 'gradle-kotlin/src/test/java/com/example/app/ApplicationTests.java.template'),
|
|
141
|
+
ctx
|
|
142
|
+
);
|
|
143
|
+
writeFileSync(join(testDir, `${ctx.appName}ApplicationTests.java`), content);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function generateDockerCompose(projectDir, ctx) {
|
|
147
|
+
const content = renderTemplate(
|
|
148
|
+
join(TEMPLATES_DIR, 'gradle-kotlin/compose.yaml.template'),
|
|
149
|
+
ctx
|
|
150
|
+
);
|
|
151
|
+
writeFileSync(join(projectDir, 'compose.yaml'), content);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function generateModulithStructure(projectDir, ctx) {
|
|
155
|
+
// Create example module structure
|
|
156
|
+
const modules = ['orders', 'inventory', 'shared'];
|
|
157
|
+
modules.forEach((mod) => {
|
|
158
|
+
mkdirSync(join(projectDir, 'src/main/java', ctx.packagePath, mod, 'internal'), { recursive: true });
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// Helpers
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
function toPascalCase(str) {
|
|
167
|
+
return str.replace(/(^|[-_])([a-z])/g, (_, __, c) => c.toUpperCase());
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function printNextSteps(config, projectDir) {
|
|
171
|
+
const cd = `cd ${config.projectName}`;
|
|
172
|
+
const run = config.buildTool === 'maven'
|
|
173
|
+
? './mvnw spring-boot:run'
|
|
174
|
+
: './gradlew bootRun';
|
|
175
|
+
|
|
176
|
+
console.log(`
|
|
177
|
+
${chalk.bold('Next steps:')}
|
|
178
|
+
|
|
179
|
+
${chalk.cyan(cd)}
|
|
180
|
+
${chalk.cyan(run)}
|
|
181
|
+
|
|
182
|
+
${chalk.bold('Install the AI coding skill:')}
|
|
183
|
+
|
|
184
|
+
${chalk.cyan(`claude skills install github:AyrtonAldayr/agent-skill-java-spring-framework`)}
|
|
185
|
+
|
|
186
|
+
${chalk.dim('Docs: https://github.com/AyrtonAldayr/agent-skill-java-spring-framework')}
|
|
187
|
+
`);
|
|
188
|
+
}
|
package/lib/prompts.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive wizard — collects project configuration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import inquirer from 'inquirer';
|
|
6
|
+
|
|
7
|
+
const DEFAULTS = {
|
|
8
|
+
projectName: 'my-service',
|
|
9
|
+
packageName: 'com.example',
|
|
10
|
+
buildTool: 'gradle',
|
|
11
|
+
javaVersion: '25',
|
|
12
|
+
bootVersion: '4.0.3',
|
|
13
|
+
database: 'postgresql',
|
|
14
|
+
features: ['actuator', 'security', 'validation'],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export async function runWizard(projectNameArg, options = {}) {
|
|
18
|
+
if (options.interactive === false) {
|
|
19
|
+
return {
|
|
20
|
+
...DEFAULTS,
|
|
21
|
+
projectName: projectNameArg || DEFAULTS.projectName,
|
|
22
|
+
buildTool: options.maven ? 'maven' : 'gradle',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const answers = await inquirer.prompt([
|
|
27
|
+
{
|
|
28
|
+
type: 'input',
|
|
29
|
+
name: 'projectName',
|
|
30
|
+
message: 'Project name:',
|
|
31
|
+
default: projectNameArg || DEFAULTS.projectName,
|
|
32
|
+
validate: (v) => /^[a-z][a-z0-9-]*$/.test(v) || 'Use lowercase letters, numbers, and hyphens',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
type: 'input',
|
|
36
|
+
name: 'packageName',
|
|
37
|
+
message: 'Base package (e.g. com.acme):',
|
|
38
|
+
default: DEFAULTS.packageName,
|
|
39
|
+
validate: (v) => /^[a-z][a-z0-9.]*$/.test(v) || 'Use lowercase letters, numbers, and dots',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
type: 'input',
|
|
43
|
+
name: 'description',
|
|
44
|
+
message: 'Project description:',
|
|
45
|
+
default: 'Spring Boot 4 microservice',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: 'list',
|
|
49
|
+
name: 'buildTool',
|
|
50
|
+
message: 'Build tool:',
|
|
51
|
+
choices: [
|
|
52
|
+
{ name: 'Gradle Kotlin DSL (recommended for 2026)', value: 'gradle' },
|
|
53
|
+
{ name: 'Maven POM', value: 'maven' },
|
|
54
|
+
],
|
|
55
|
+
default: options.maven ? 'maven' : 'gradle',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
type: 'list',
|
|
59
|
+
name: 'javaVersion',
|
|
60
|
+
message: 'Java version:',
|
|
61
|
+
choices: [
|
|
62
|
+
{ name: 'Java 25 LTS (recommended)', value: '25' },
|
|
63
|
+
{ name: 'Java 21 LTS', value: '21' },
|
|
64
|
+
{ name: 'Java 17 LTS (minimum)', value: '17' },
|
|
65
|
+
],
|
|
66
|
+
default: '25',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
type: 'list',
|
|
70
|
+
name: 'bootVersion',
|
|
71
|
+
message: 'Spring Boot version:',
|
|
72
|
+
choices: [
|
|
73
|
+
{ name: '4.0.3 (stable)', value: '4.0.3' },
|
|
74
|
+
{ name: '4.1.0-M1 (milestone)', value: '4.1.0-M1' },
|
|
75
|
+
],
|
|
76
|
+
default: '4.0.3',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
type: 'list',
|
|
80
|
+
name: 'database',
|
|
81
|
+
message: 'Database:',
|
|
82
|
+
choices: [
|
|
83
|
+
{ name: 'PostgreSQL 17', value: 'postgresql' },
|
|
84
|
+
{ name: 'MySQL 9', value: 'mysql' },
|
|
85
|
+
{ name: 'MongoDB 7.0', value: 'mongodb' },
|
|
86
|
+
{ name: 'H2 (in-memory / dev only)', value: 'h2' },
|
|
87
|
+
{ name: 'None', value: 'none' },
|
|
88
|
+
],
|
|
89
|
+
default: 'postgresql',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
type: 'checkbox',
|
|
93
|
+
name: 'features',
|
|
94
|
+
message: 'Features (space to toggle, enter to confirm):',
|
|
95
|
+
choices: [
|
|
96
|
+
{ name: 'Spring Actuator + OTEL Observability', value: 'actuator', checked: true },
|
|
97
|
+
{ name: 'Spring Security 7 (OAuth2 Resource Server)', value: 'security', checked: true },
|
|
98
|
+
{ name: 'Bean Validation 3.1', value: 'validation', checked: true },
|
|
99
|
+
{ name: 'Spring Modulith (domain-driven modules)', value: 'modulith', checked: false },
|
|
100
|
+
{ name: 'GraalVM Native Image', value: 'native', checked: false },
|
|
101
|
+
{ name: 'Spring WebFlux (Reactive)', value: 'webflux', checked: false },
|
|
102
|
+
{ name: 'Docker Compose support', value: 'docker-compose', checked: false },
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
type: 'confirm',
|
|
107
|
+
name: 'enablePreview',
|
|
108
|
+
message: 'Enable Java preview features? (Structured Concurrency, Scoped Values)',
|
|
109
|
+
default: true,
|
|
110
|
+
when: (ans) => ans.javaVersion === '25',
|
|
111
|
+
},
|
|
112
|
+
]);
|
|
113
|
+
|
|
114
|
+
return answers;
|
|
115
|
+
}
|
package/lib/templates.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal template engine — replaces {{key}} placeholders using a context object.
|
|
3
|
+
* Supports {{#if key}}...{{/if}} blocks and {{#each array}}...{{/each}}.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFileSync } from 'fs';
|
|
7
|
+
|
|
8
|
+
export function renderTemplate(templatePath, ctx) {
|
|
9
|
+
let source = readFileSync(templatePath, 'utf8');
|
|
10
|
+
source = processIf(source, ctx);
|
|
11
|
+
source = processEach(source, ctx);
|
|
12
|
+
source = interpolate(source, ctx);
|
|
13
|
+
return source;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Replace {{key}} with ctx[key] */
|
|
17
|
+
function interpolate(src, ctx) {
|
|
18
|
+
return src.replace(/\{\{(\w+)\}\}/g, (_, key) => {
|
|
19
|
+
const val = ctx[key];
|
|
20
|
+
return val !== undefined && val !== null ? String(val) : '';
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Process {{#if key}}...{{/if}} — supports negation {{#if !key}} */
|
|
25
|
+
function processIf(src, ctx) {
|
|
26
|
+
return src.replace(
|
|
27
|
+
/\{\{#if (!?)(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g,
|
|
28
|
+
(_, negate, key, body) => {
|
|
29
|
+
const val = Boolean(ctx[key]);
|
|
30
|
+
return (negate ? !val : val) ? body : '';
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Process {{#each arrayKey}}...{{/each}} — exposes item as {{item}} */
|
|
36
|
+
function processEach(src, ctx) {
|
|
37
|
+
return src.replace(
|
|
38
|
+
/\{\{#each (\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g,
|
|
39
|
+
(_, key, body) => {
|
|
40
|
+
const arr = ctx[key];
|
|
41
|
+
if (!Array.isArray(arr)) return '';
|
|
42
|
+
return arr.map((item) => body.replace(/\{\{item\}\}/g, String(item))).join('');
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "spring-boot4-skill",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Interactive CLI scaffold for Java 25 / Spring Boot 4.x projects — with a bundled Claude Code skill for AI-assisted development.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"spring-boot4-skill": "bin/create-spring-app.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node bin/create-spring-app.js",
|
|
11
|
+
"test": "node --experimental-vm-modules node_modules/.bin/jest"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"spring-boot",
|
|
15
|
+
"spring-framework",
|
|
16
|
+
"java",
|
|
17
|
+
"scaffold",
|
|
18
|
+
"cli",
|
|
19
|
+
"generator",
|
|
20
|
+
"spring-modulith",
|
|
21
|
+
"graalvm",
|
|
22
|
+
"jakarta",
|
|
23
|
+
"claude-skill"
|
|
24
|
+
],
|
|
25
|
+
"author": "AyrtonAldayr",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/AyrtonAldayr/agent-skill-java-spring-framework.git"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/AyrtonAldayr/agent-skill-java-spring-framework#readme",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/AyrtonAldayr/agent-skill-java-spring-framework/issues"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20.0.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"chalk": "^5.3.0",
|
|
40
|
+
"commander": "^12.1.0",
|
|
41
|
+
"inquirer": "^10.1.5",
|
|
42
|
+
"ora": "^8.1.0"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: java-spring-framework
|
|
3
|
+
description: >
|
|
4
|
+
Senior Java & Spring Boot 4 / Spring Framework 7 architect skill for 2026-standard development.
|
|
5
|
+
Use when the user asks to build, scaffold, design, review, or explain Java applications using
|
|
6
|
+
Spring Boot 4.x, Spring Framework 7.x, Spring Modulith, or any related Spring ecosystem project.
|
|
7
|
+
Triggers include: creating REST APIs, designing microservices, configuring data access (JdbcClient,
|
|
8
|
+
JPA 3.2, R2DBC), reactive programming (WebFlux), security (Spring Security 7), observability,
|
|
9
|
+
GraalVM native images, Gradle/Maven build configuration, Jakarta EE 11 migration, and any task
|
|
10
|
+
requiring idiomatic modern Java (Java 25: records, sealed classes, structured concurrency,
|
|
11
|
+
scoped values, pattern matching, JSpecify null safety).
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Java & Spring Boot 4 Architect
|
|
15
|
+
|
|
16
|
+
You are a Senior Java & Spring Boot 4 / Spring Framework 7 architect. All code must be
|
|
17
|
+
idiomatic for **2026 standards**: Spring Boot 4.0.x, Spring Framework 7.0.x, Java 25, Jakarta EE 11.
|
|
18
|
+
|
|
19
|
+
## Mandatory Workflow
|
|
20
|
+
|
|
21
|
+
1. **Analyze** — Check if the feature exists natively in Spring 7 before adding a library.
|
|
22
|
+
(e.g., native API versioning, built-in resilience, `RestClient`, `JdbcClient`)
|
|
23
|
+
2. **Implement** — Use `jakarta.*` namespaces. Use Records for DTOs, Pattern Matching for logic.
|
|
24
|
+
3. **Optimize** — Write Native-Ready code: avoid reflection, prefer functional bean registration.
|
|
25
|
+
4. **Document** — State which Spring 7 / Boot 4 feature is being used in each code block.
|
|
26
|
+
|
|
27
|
+
## Core Principles
|
|
28
|
+
|
|
29
|
+
| Concern | Modern Choice | Never Use |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| HTTP client | `RestClient`, `HttpServiceProxyFactory` | `RestTemplate` |
|
|
32
|
+
| JDBC | `JdbcClient` | `JdbcTemplate` (direct) |
|
|
33
|
+
| Null safety | JSpecify `@Nullable` / `@NonNull` | JSR-305 |
|
|
34
|
+
| Concurrency | `StructuredTaskScope` | raw threads |
|
|
35
|
+
| Build | `build.gradle.kts` (default) | XML Spring config |
|
|
36
|
+
| Namespaces | `jakarta.*` | `javax.*` |
|
|
37
|
+
| DI config | `proxyBeanMethods = false` | proxy-heavy `@Configuration` |
|
|
38
|
+
| Testing | JUnit 5 + `RestTestClient` | JUnit 4, `RestTemplate` in tests |
|
|
39
|
+
|
|
40
|
+
## Output Style
|
|
41
|
+
|
|
42
|
+
- Concise, technical, authoritative.
|
|
43
|
+
- Always include full dependency snippet (Gradle KTS preferred).
|
|
44
|
+
- Name the specific Spring Boot / Framework version for each feature used.
|
|
45
|
+
- Use Records for DTOs, `switch` expressions with pattern matching for dispatch logic.
|
|
46
|
+
|
|
47
|
+
## Reference Files
|
|
48
|
+
|
|
49
|
+
Load these as needed — do not load all at once:
|
|
50
|
+
|
|
51
|
+
| Topic | File | Load when |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| Spring Framework 7 APIs | `references/spring-framework-7.md` | Framework-level features: versioning, resilience, JSpecify, SpEL, streaming |
|
|
54
|
+
| Spring Boot 4 features | `references/spring-boot-4.md` | Boot auto-config, Actuator, native images, testing, virtual threads |
|
|
55
|
+
| Spring Modulith | `references/spring-modulith.md` | Domain-driven module design, event-driven architecture |
|
|
56
|
+
| Build templates | `references/build-templates.md` | Gradle KTS or Maven POM scaffolding with 2026 BOM versions |
|