Install
$ agentstack add skill-iambrzdev-enterprise-agent-skills-java-spring-enterprise ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
When to activate
- Scaffolding a new Spring Boot enterprise project
- "How do I structure this feature?" in a Java/Spring context
- Designing a service layer, use case, or domain model
- Configuring
@Transactional— any question about transactions, isolation, or rollback - Setting up HikariCP connection pool tuning
- Implementing Virtual Threads (Java 21+) for I/O-heavy operations
- Adding observability: Micrometer, Prometheus, Grafana, OpenTelemetry tracing
- Refactoring a fat controller or a service with too many responsibilities
- Any mention of Hexagonal Architecture, ports/adapters, DDD, or use cases in Java
Rules — Non-negotiable
- No business logic in controllers. Controllers receive HTTP input,
delegate to a use case or service, and return a response. Nothing else.
- Domain layer has zero Spring dependencies. Entities and domain services
must not import Spring annotations. Domain is framework-agnostic.
@Transactionalis not a default annotation. Apply it deliberately,
with the correct isolation level. Add readOnly = true for all read operations.
- Never expose domain entities in API responses. Always map to DTOs or
response records before returning from the controller.
- HikariCP pool size must be tuned explicitly. The default pool size (10)
is wrong for most enterprise workloads. Always configure based on load profile.
Project Structure — Clean / Hexagonal Architecture
src/main/java/com/company/app/
├── domain/
│ ├── model/ # Entities, Value Objects, Aggregates — NO Spring here
│ ├── port/
│ │ ├── in/ # Use case interfaces (driving ports)
│ │ └── out/ # Repository + external service interfaces (driven ports)
│ └── service/ # Domain services — pure business logic
│
├── application/
│ └── usecase/ # Use case implementations — orchestrate domain + ports
│ ├── CreateOrderUseCase.java
│ └── GetOrderByIdUseCase.java
│
├── adapter/
│ ├── in/
│ │ └── web/ # Controllers, request/response DTOs, mappers
│ └── out/
│ ├── persistence/ # JPA entities, repositories (Spring Data)
│ └── external/ # HTTP clients, message producers
│
└── config/ # Spring configuration, beans, security
Dependency direction
adapter/in → application → domain ← application ← adapter/out
Domain knows nothing about adapters. Application knows nothing about HTTP or JPA.
Use Case Pattern
Every feature is a use case. Controllers call use cases, not services directly.
// domain/port/in/CreateOrderUseCase.java
public interface CreateOrderUseCase {
OrderResponse execute(CreateOrderCommand command);
}
// application/usecase/CreateOrderUseCaseImpl.java
@Service
@RequiredArgsConstructor
public class CreateOrderUseCaseImpl implements CreateOrderUseCase {
private final OrderRepository orderRepository; // port/out — interface
private final InventoryPort inventoryPort; // port/out — interface
@Override
@Transactional
public OrderResponse execute(CreateOrderCommand command) {
// 1. Validate domain rules
// 2. Call domain service if needed
// 3. Persist via output port
// 4. Return mapped response
}
}
// adapter/in/web/OrderController.java
@RestController
@RequestMapping("/api/v1/orders")
@RequiredArgsConstructor
public class OrderController {
private final CreateOrderUseCase createOrderUseCase;
@PostMapping
public ResponseEntity create(@Valid @RequestBody CreateOrderRequest request) {
CreateOrderCommand command = OrderMapper.toCommand(request);
return ResponseEntity.status(HttpStatus.CREATED)
.body(createOrderUseCase.execute(command));
}
}
@Transactional — Correct Usage
// ✅ Write operation — transactional with default isolation
@Transactional
public OrderResponse createOrder(CreateOrderCommand command) { ... }
// ✅ Read operation — always readOnly = true (avoids dirty checks, improves performance)
@Transactional(readOnly = true)
public OrderResponse getOrderById(Long id) { ... }
// ✅ Explicit isolation for financial operations
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void processPayment(PaymentCommand command) { ... }
// ❌ Never annotate entire class as @Transactional without understanding the blast radius
@Transactional // BAD — every method gets a transaction, including reads
public class OrderService { ... }
// ❌ Never catch and swallow exceptions inside a @Transactional method
@Transactional
public void createOrder(CreateOrderCommand command) {
try { ... }
catch (Exception e) { log.error("failed"); } // BAD — transaction won't roll back
}
Virtual Threads (Java 21+)
For I/O-intensive applications, replace platform thread pools with Virtual Threads:
// config/ThreadConfig.java
@Configuration
public class ThreadConfig {
@Bean
public TomcatProtocolHandlerCustomizer virtualThreadsProtocolHandler() {
return protocolHandler ->
protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
}
}
// Or via application.yml (Spring Boot 3.2+)
// spring:
// threads:
// virtual:
// enabled: true
When to use Virtual Threads:
- ✅ REST APIs with high concurrency and blocking I/O (DB calls, HTTP clients)
- ✅ Applications doing many simultaneous external service calls
- ❌ CPU-bound workloads (image processing, heavy computation) — no benefit
HikariCP — Connection Pool Tuning
# application.yml
spring:
datasource:
hikari:
maximum-pool-size: 20 # Start here; tune based on DB capacity
minimum-idle: 5
connection-timeout: 3000 # 3s — fail fast, don't queue forever
idle-timeout: 600000 # 10 min
max-lifetime: 1800000 # 30 min — less than DB's wait_timeout
pool-name: HikariPool-Enterprise
# With Virtual Threads: keep pool-size conservative
# DB connections saturate before virtual threads do
// Always validate pool configuration on startup
@Component
@Slf4j
public class DataSourceHealthCheck {
@EventListener(ApplicationReadyEvent.class)
public void logPoolConfig(ApplicationReadyEvent event) {
// Log effective pool size to verify configuration was applied
}
}
Observability — Micrometer + OpenTelemetry
io.micrometer
micrometer-registry-prometheus
io.micrometer
micrometer-tracing-bridge-otel
io.opentelemetry
opentelemetry-exporter-otlp
# application.yml
management:
endpoints:
web:
exposure:
include: health, info, prometheus, metrics
metrics:
distribution:
percentiles-histogram:
http.server.requests: true # Enables P50/P95/P99 latency histograms
tracing:
sampling:
probability: 1.0 # 100% in dev; reduce to 0.1 in prod
// Custom business metric example
@Service
@RequiredArgsConstructor
public class OrderMetrics {
private final MeterRegistry meterRegistry;
public void recordOrderCreated(String channel) {
meterRegistry.counter("orders.created", "channel", channel).increment();
}
}
Common mistakes
- ❌ Calling repositories directly from controllers
- ✅ Controllers → Use Cases → Repositories (always through the port interface)
- ❌
@Transactionalon aprivatemethod (Spring proxy won't intercept it) - ✅
@Transactionalonly onpublicmethods of Spring-managed beans
- ❌ Setting
maximum-pool-size: 100without checking DB max connections - ✅ Pool size = (DB max connections / number of app instances) × 0.8
- ❌ Returning
Optionalfrom controllers - ✅ Map to response DTO inside the use case; throw domain exception if not found
- ❌ Placing
@EntityJPA classes inside thedomain/model/package - ✅ JPA entities live in
adapter/out/persistence/; domain model is pure Java
Definition of Done
A feature built with this skill is complete only when:
- [ ] Business logic lives exclusively in domain services or use cases
- [ ] Controller delegates to a use case interface — not a concrete service
- [ ] All write operations have
@Transactional; all reads havereadOnly = true - [ ] API response uses a DTO/record — no domain entity leaking through HTTP
- [ ] HikariCP pool size is explicitly configured (not default)
- [ ] At least one custom Micrometer metric or trace exists for the new feature
- [ ] Domain model has no Spring imports
Reference files
Load on demand:
references/hexagonal-architecture-full.md— full project scaffold with all layersreferences/transaction-patterns.md— saga pattern, compensation, outbox for distributed transactionsreferences/observability-grafana.md— Grafana dashboard setup for Spring Boot metrics
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: iamBrzDev
- Source: iamBrzDev/enterprise-agent-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.