skills/quarkus-patterns/SKILL.md
Quarkus 3.x LTS architecture patterns with Camel for messaging, RESTful API design, CDI services, data access with Panache, and async processing. Use for Java Quarkus backend work with event-driven architectures. Use when building or reviewing a Quarkus service, especially with Camel messaging or Panache data access.
npx skillsauth add affaan-m/everything-claude-code quarkus-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Quarkus 3.x architecture and API patterns for cloud-native, event-driven services with Apache Camel.
@Slf4j
@ApplicationScoped
@RequiredArgsConstructor
public class OrderProcessingService {
private final OrderValidator orderValidator;
private final EventService eventService;
private final OrderRepository orderRepository;
private final FulfillmentPublisher fulfillmentPublisher;
private final AuditPublisher auditPublisher;
@Transactional
public OrderReceipt process(CreateOrderCommand command) {
ValidationResult validation = orderValidator.validate(command);
if (!validation.valid()) {
eventService.createErrorEvent(command, "ORDER_REJECTED", validation.message());
throw new WebApplicationException(validation.message(), Response.Status.BAD_REQUEST);
}
Order order = Order.from(command);
orderRepository.persist(order);
OrderReceipt receipt = OrderReceipt.from(order);
fulfillmentPublisher.publishAsync(receipt);
auditPublisher.publish("ORDER_ACCEPTED", receipt);
eventService.createSuccessEvent(receipt, "ORDER_ACCEPTED");
log.info("Processed order {}", order.id);
return receipt;
}
}
Key Patterns:
@RequiredArgsConstructor for constructor injection via Lombok@Slf4j for Logback logging@Transactional on service methods that write through Panache or repositories@ApplicationScoped
public class ProcessingService {
public void processDocument(Document doc) {
LogContext logContext = CustomLog.getCurrentContext();
try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {
// Add context to all log statements
logContext.put("documentId", doc.getId().toString());
logContext.put("documentType", doc.getType());
logContext.put("userId", SecurityContext.getUserId());
log.info("Starting document processing");
// All logs within this scope inherit the context
processInternal(doc);
log.info("Document processing completed");
} catch (Exception e) {
log.error("Document processing failed", e);
throw e;
}
}
}
Logback Configuration (logback.xml):
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeContext>true</includeContext>
<includeMdc>true</includeMdc>
</encoder>
</appender>
<logger name="com.example" level="INFO"/>
<root level="WARN">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
@Slf4j
@ApplicationScoped
@RequiredArgsConstructor
public class EventService {
private final EventRepository eventRepository;
private final ObjectMapper objectMapper;
public void createSuccessEvent(Object payload, String eventType) {
Objects.requireNonNull(payload, "Payload cannot be null");
Event event = new Event();
event.setType(eventType);
event.setStatus(EventStatus.SUCCESS);
event.setPayload(serializePayload(payload));
event.setTimestamp(Instant.now());
eventRepository.persist(event);
log.info("Success event created: {}", eventType);
}
public void createErrorEvent(Object payload, String eventType, String errorMessage) {
Objects.requireNonNull(payload, "Payload cannot be null");
if (errorMessage == null || errorMessage.isBlank()) {
throw new IllegalArgumentException("Error message cannot be blank");
}
Event event = new Event();
event.setType(eventType);
event.setStatus(EventStatus.ERROR);
event.setErrorMessage(errorMessage);
event.setPayload(serializePayload(payload));
event.setTimestamp(Instant.now());
eventRepository.persist(event);
log.error("Error event created: {} - {}", eventType, errorMessage);
}
private String serializePayload(Object payload) {
try {
return objectMapper.writeValueAsString(payload);
} catch (JsonProcessingException e) {
throw new IllegalStateException("Failed to serialize event payload", e);
}
}
}
@Slf4j
@ApplicationScoped
@RequiredArgsConstructor
public class BusinessRulesPublisher {
private final ProducerTemplate producerTemplate;
public void publishSync(BusinessRulesPayload payload) {
producerTemplate.sendBody(
"direct:business-rules-publisher",
payload
);
}
}
Camel Route Configuration:
@ApplicationScoped
public class BusinessRulesRoute extends RouteBuilder {
@ConfigProperty(name = "camel.rabbitmq.queue.business-rules")
String businessRulesQueue;
@ConfigProperty(name = "rabbitmq.host")
String rabbitHost;
@ConfigProperty(name = "rabbitmq.port")
Integer rabbitPort;
@Override
public void configure() {
from("direct:business-rules-publisher")
.routeId("business-rules-publisher")
.log("Publishing message to RabbitMQ: ${body}")
.marshal().json(JsonLibrary.Jackson)
.toF("spring-rabbitmq:%s?hostname=%s&portNumber=%d",
businessRulesQueue, rabbitHost, rabbitPort);
}
}
@ApplicationScoped
public class DocumentProcessingRoute extends RouteBuilder {
@Override
public void configure() {
// Error handling
onException(ValidationException.class)
.handled(true)
.to("direct:validation-error-handler")
.log("Validation error: ${exception.message}");
// Main processing route
from("direct:process-document")
.routeId("document-processing")
.log("Processing document: ${header.documentId}")
.bean(DocumentValidator.class, "validate")
.bean(DocumentTransformer.class, "transform")
.choice()
.when(header("documentType").isEqualTo("INVOICE"))
.to("direct:process-invoice")
.when(header("documentType").isEqualTo("CREDIT_NOTE"))
.to("direct:process-credit-note")
.otherwise()
.to("direct:process-generic")
.end();
from("direct:validation-error-handler")
.bean(EventService.class, "createErrorEvent")
.log("Validation error handled");
}
}
@ApplicationScoped
public class FileMonitoringRoute extends RouteBuilder {
@ConfigProperty(name = "file.input.directory")
String inputDirectory;
@ConfigProperty(name = "file.processed.directory")
String processedDirectory;
@ConfigProperty(name = "file.error.directory")
String errorDirectory;
@Override
public void configure() {
from("file:" + inputDirectory + "?move=" + processedDirectory +
"&moveFailed=" + errorDirectory + "&delay=5000")
.routeId("file-monitor")
.log("Processing file: ${header.CamelFileName}")
.to("direct:process-file");
from("direct:process-file")
.bean(OrderProcessingService.class, "processFile")
.log("File processing completed");
}
}
@ApplicationScoped
public class InvoiceRoute extends RouteBuilder {
@Override
public void configure() {
from("direct:invoice-validation")
.bean(InvoiceFlowValidator.class, "validateFlowWithConfig")
.log("Validation result: ${body}");
from("direct:persist-and-publish")
.bean(DocumentJobService.class, "createDocumentAndJobEntities")
.bean(BusinessRulesPublisher.class, "publishAsync")
.bean(EventService.class, "createSuccessEvent(${body}, 'PUBLISHED')");
}
}
@Path("/api/documents")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RequiredArgsConstructor
public class DocumentResource {
private final DocumentService documentService;
@GET
public Response list(
@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") int size) {
List<Document> documents = documentService.list(page, size);
return Response.ok(documents).build();
}
@POST
public Response create(@Valid CreateDocumentRequest request, @Context UriInfo uriInfo) {
Document document = documentService.create(request);
URI location = uriInfo.getAbsolutePathBuilder()
.path(String.valueOf(document.id))
.build();
return Response.created(location).entity(DocumentResponse.from(document)).build();
}
@GET
@Path("/{id}")
public Response getById(@PathParam("id") Long id) {
return documentService.findById(id)
.map(DocumentResponse::from)
.map(Response::ok)
.orElse(Response.status(Response.Status.NOT_FOUND))
.build();
}
}
@ApplicationScoped
public class DocumentRepository implements PanacheRepository<Document> {
public List<Document> findByStatus(DocumentStatus status, int page, int size) {
return find("status = ?1 order by createdAt desc", status)
.page(page, size)
.list();
}
public Optional<Document> findByReferenceNumber(String referenceNumber) {
return find("referenceNumber", referenceNumber).firstResultOptional();
}
public long countByStatusAndDate(DocumentStatus status, LocalDate date) {
return count("status = ?1 and createdAt >= ?2", status, date.atStartOfDay());
}
}
@ApplicationScoped
@RequiredArgsConstructor
public class DocumentService {
private final DocumentRepository repo;
private final EventService eventService;
@Transactional
public Document create(CreateDocumentRequest request) {
Document document = new Document();
document.setReferenceNumber(request.referenceNumber());
document.setDescription(request.description());
document.setStatus(DocumentStatus.PENDING);
document.setCreatedAt(Instant.now());
repo.persist(document);
eventService.createSuccessEvent(document, "DOCUMENT_CREATED");
return document;
}
public Optional<Document> findById(Long id) {
return repo.findByIdOptional(id);
}
public List<Document> list(int page, int size) {
return repo.findAll()
.page(page, size)
.list();
}
}
public record CreateDocumentRequest(
@NotBlank @Size(max = 200) String referenceNumber,
@NotBlank @Size(max = 2000) String description,
@NotNull @FutureOrPresent Instant validUntil,
@NotEmpty List<@NotBlank String> categories) {}
public record DocumentResponse(Long id, String referenceNumber, DocumentStatus status) {
public static DocumentResponse from(Document document) {
return new DocumentResponse(document.getId(), document.getReferenceNumber(),
document.getStatus());
}
}
@Provider
public class ValidationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
@Override
public Response toResponse(ConstraintViolationException exception) {
String message = exception.getConstraintViolations().stream()
.map(cv -> cv.getPropertyPath() + ": " + cv.getMessage())
.collect(Collectors.joining(", "));
return Response.status(Response.Status.BAD_REQUEST)
.entity(Map.of("error", "validation_error", "message", message))
.build();
}
}
@Provider
@Slf4j
public class GenericExceptionMapper implements ExceptionMapper<Exception> {
@Override
public Response toResponse(Exception exception) {
log.error("Unhandled exception", exception);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(Map.of("error", "internal_error", "message", "An unexpected error occurred"))
.build();
}
}
@Slf4j
@ApplicationScoped
@RequiredArgsConstructor
public class FileStorageService {
private final S3Client s3Client;
private final ExecutorService executorService;
@ConfigProperty(name = "storage.bucket-name")
String bucketName;
public CompletableFuture<StoredDocumentInfo> uploadOriginalFile(
InputStream inputStream,
long size,
LogContext logContext,
InvoiceFormat format) {
return CompletableFuture.supplyAsync(() -> {
try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {
String path = generateStoragePath(format);
PutObjectRequest request = PutObjectRequest.builder()
.bucket(bucketName)
.key(path)
.contentLength(size)
.build();
s3Client.putObject(request, RequestBody.fromInputStream(inputStream, size));
log.info("File uploaded to S3: {}", path);
return new StoredDocumentInfo(path, size, Instant.now());
} catch (Exception e) {
log.error("Failed to upload file to S3", e);
throw new StorageException("Upload failed", e);
}
}, executorService);
}
}
@ApplicationScoped
@RequiredArgsConstructor
public class DocumentCacheService {
private final DocumentRepository repo;
@CacheResult(cacheName = "document-cache")
public Optional<Document> getById(@CacheKey Long id) {
return repo.findByIdOptional(id);
}
@CacheInvalidate(cacheName = "document-cache")
public void evict(@CacheKey Long id) {}
@CacheInvalidateAll(cacheName = "document-cache")
public void evictAll() {}
}
# application.yml
"%dev":
quarkus:
datasource:
jdbc:
url: jdbc:postgresql://localhost:5432/dev_db
username: dev_user
password: ${DB_PASSWORD}
hibernate-orm:
database:
generation: drop-and-create
rabbitmq:
host: localhost
port: 5672
username: ${RABBITMQ_USER}
password: ${RABBITMQ_PASSWORD}
"%test":
quarkus:
datasource:
jdbc:
url: jdbc:h2:mem:test
hibernate-orm:
database:
generation: drop-and-create
"%prod":
quarkus:
datasource:
jdbc:
url: ${DATABASE_URL}
username: ${DB_USER}
password: ${DB_PASSWORD}
hibernate-orm:
database:
generation: validate
rabbitmq:
host: ${RABBITMQ_HOST}
port: ${RABBITMQ_PORT}
username: ${RABBITMQ_USER}
password: ${RABBITMQ_PASSWORD}
# Camel configuration
camel:
rabbitmq:
queue:
business-rules: business-rules-queue
invoice-processing: invoice-processing-queue
@Readiness
@ApplicationScoped
@RequiredArgsConstructor
public class DatabaseHealthCheck implements HealthCheck {
private final AgroalDataSource dataSource;
@Override
public HealthCheckResponse call() {
try (Connection conn = dataSource.getConnection()) {
boolean valid = conn.isValid(2);
return HealthCheckResponse.named("Database connection")
.status(valid)
.build();
} catch (SQLException e) {
return HealthCheckResponse.down("Database connection");
}
}
}
@Liveness
@ApplicationScoped
public class CamelHealthCheck implements HealthCheck {
@Inject
CamelContext camelContext;
@Override
public HealthCheckResponse call() {
boolean isStarted = camelContext.getStatus().isStarted();
return HealthCheckResponse.named("Camel Context")
.status(isStarted)
.build();
}
}
<properties>
<quarkus.platform.version>3.27.0</quarkus.platform.version>
<lombok.version>1.18.42</lombok.version>
<assertj-core.version>3.24.2</assertj-core.version>
<jacoco-maven-plugin.version>0.8.13</jacoco-maven-plugin.version>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-bom</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-camel-bom</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Quarkus Core -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-config-yaml</artifactId>
</dependency>
<!-- Camel Extensions -->
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-spring-rabbitmq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-direct</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-bean</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!-- Logging -->
<dependency>
<groupId>io.quarkiverse.logging.logback</groupId>
<artifactId>quarkus-logging-logback</artifactId>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
</dependency>
</dependencies>
@RequiredArgsConstructor with Lombok for constructor injectiondirect: endpoints for in-memory routingspring-rabbitmq component for RabbitMQ integrationProducerTemplate.asyncSendBody()SafeAutoCloseable@Slf4j instead of manual logger instantiation.join() when you need to wait for completionquarkus-config-yaml)@ConfigProperty for type-safe config injection@Valid@Provider@Transactional on service methods that modify datacamel-quarkus-junit5 for route testingtools
Query live GPU inventory, submit an authenticated Itô fixed-rate RFQ, inspect RFQ or procurement status, revoke device credentials, and run explicitly gated node qualification through the separately installed canonical CLI. Use when a user asks to find H100/H200 capacity, request a fixed compute rate, check Itô compute status, validate GPU nodes, revoke Itô access, or rent or purchase GPU compute and needs the supported boundary explained.
testing
Agent-driven scheduling and publishing of social media posts across 13 platforms via SocialClaw. Use when the user wants to publish to X, LinkedIn, Instagram, Facebook Pages, TikTok, Discord, Telegram, YouTube, Reddit, WordPress, or Pinterest — or when managing campaigns, uploading media, or monitoring post delivery status.
development
LLM APIの使用量のコスト最適化パターン — タスクの複雑さによるモデルルーティング、予算追跡、リトライロジック、プロンプトキャッシング。
tools
Use this skill when retrieving Jira tickets, analyzing requirements, updating ticket status, adding comments, or transitioning issues. Provides Jira API patterns via MCP or direct REST calls.