[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M72XXQXM5WNMP0SW0CWHM5PY":3,"skill-same:01M72XXQXM5WNMP0SW0CWHM5PY":48},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":25,"commitSha":26,"skillDirectory":27,"forksCount":28,"repositoryHtmlUrl":29,"repositoryHomepageUrl":6,"ownerHtmlUrl":30,"ownerBlogUrl":31,"ownerDescription":32,"updatedAt":33,"install":34,"resources":47},"01M72XXQXM5WNMP0SW0CWHM5PY","quarkus-patterns",null,"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.","SriramGandhiS\u002FSkills","SriramGandhiS","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F211849986?v=4","01M72WQCW12BYX71C6WN584TTA","Sriram S","01M72WQCWTJ2RD0ET1X31AF1RC",1,"MIT","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Feverything-claude-code\u002Fdocs\u002Ftr\u002Fskills\u002Fquarkus-patterns\u002FSKILL.md",[],[],"2026-11-10 22:39:42",false,"---\nname: quarkus-patterns\ndescription: 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.\norigin: ECC\n---\n\n# Quarkus Geliştirme Desenleri\n\nApache Camel ile bulut-native, event-driven servisler için Quarkus 3.x mimari ve API desenleri.\n\n## When to Use\n\n- JAX-RS veya RESTEasy Reactive ile REST API'leri oluşturma\n- Resource → service → repository katmanlarını yapılandırma\n- Apache Camel ve RabbitMQ ile event-driven desenler uygulama\n- Hibernate Panache, caching veya reaktif akışları yapılandırma\n- Validation, exception mapping veya sayfalama ekleme\n- Dev\u002Fstaging\u002Fproduction ortamları için profiller kurma (YAML yapılandırma)\n- LogContext ve Logback\u002FLogstash encoder ile özel loglama\n- Async işlemler için CompletableFuture ile çalışma\n- Koşullu akış işleme uygulama\n- GraalVM native derleme ile çalışma\n\n## How It Works\n\nQuarkus servislerinde Resource -> service -> repository akışını CDI scope'ları,\n`@Transactional` sınırları, Panache\u002FHibernate veri erişimi ve Camel\u002FRabbitMQ\nentegrasyonlarıyla birlikte uygulayın. Aşağıdaki örnekler event üretimi,\ndosya işleme, özel logging context ve async yayınlama için kopyalanabilir\nbaşlangıç noktaları sağlar.\n\n## Examples\n\n### Birden Fazla Bağımlılıklı Service Katmanı (Lombok)\n\n```java\n@Slf4j\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class As2ProcessingService {\n\n    private final InvoiceFlowValidator invoiceFlowValidator;\n    private final EventService eventService;\n    private final DocumentJobService documentJobService;\n    private final BusinessRulesPublisher businessRulesPublisher;\n    private final FileStorageService fileStorageService;\n\n    public void processFile(Path filePath) throws Exception {\n        LogContext logContext = CustomLog.getCurrentContext();\n        try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {\n\n            String structureIdPartner = logContext.get(As2Constants.STRUCTURE_ID);\n\n            \u002F\u002F Koşullu akış mantığı\n            boolean isChorusFlow = Boolean.parseBoolean(logContext.get(As2Constants.CHORUS_FLOW));\n            log.info(\"Is CHORUS_FLOW message: {}\", isChorusFlow);\n\n            ValidationFlowConfig validationFlowConfig = isChorusFlow\n                    ? ValidationFlowConfig.xsdOnly()\n                    : ValidationFlowConfig.allValidations();\n\n            InvoiceValidationResult invoiceValidationResult = this.invoiceFlowValidator\n                    .validateFlowWithConfig(filePath, validationFlowConfig,\n                        EInvoiceSyntaxFormat.UBL, logContext);\n\n            FlowProfile flowProfile = isChorusFlow ?\n                    FlowProfile.EXTENDED_CTC_FR :\n                    this.invoiceFlowValidator.computeFlowProfile(invoiceValidationResult,\n                        invoiceValidationResult.getInvoiceDetails().invoiceFormat().getProfile());\n\n            log.info(\"Invoice validation completed. Message is valid\");\n\n            \u002F\u002F CompletableFuture async işlemi\n            try(InputStream inputStream = Files.newInputStream(filePath)) {\n                CompletableFuture\u003CStoredDocumentInfo> documentInfoCompletableFuture =\n                    fileStorageService.uploadOriginalFile(inputStream,\n                        invoiceValidationResult.getSize(), logContext,\n                        invoiceValidationResult.getInvoiceFormat());\n\n                StoredDocumentInfo documentInfo = documentInfoCompletableFuture.join();\n                log.info(\"File uploaded successfully: {}\", documentInfo.getPath());\n\n                if (StringUtils.isBlank(documentInfo.getPath())) {\n                    String errorMsg = \"File path is empty after upload\";\n                    log.error(errorMsg);\n                    this.eventService.createErrorEvent(documentInfo, \"FILE_UPLOAD_FAILED\", errorMsg);\n                    throw new As2ServerProcessingException(errorMsg);\n                }\n\n                this.eventService.createSuccessEvent(documentInfo, \"PERSISTENCE_BLOB_EVENT_TYPE\");\n\n                String originalFileName = documentInfo.getOriginalFileName();\n                BusinessRulesPayload payload = this.documentJobService.createDocumentAndJobEntities(\n                    documentInfo, originalFileName, structureIdPartner,\n                    flowProfile, invoiceValidationResult.getDocumentHash());\n\n                \u002F\u002F Async Camel yayınlama\n                businessRulesPublisher.publishAsync(payload);\n                this.eventService.createSuccessEvent(payload, \"BUSINESS_RULES_MESSAGE_SENT\");\n            }\n        }\n    }\n}\n```\n\n**Temel Desenler:**\n- Constructor injection için Lombok üzerinden `@RequiredArgsConstructor`\n- Logback loglama için `@Slf4j`\n- try-with-resources ile kapsamlı LogContext\n- Runtime parametrelerine dayalı koşullu akış mantığı\n- Async işlemler için `.join()` ile CompletableFuture\n- Başarı\u002Fhata senaryoları için event takibi\n- Async Camel mesaj yayınlama\n\n## Özel Loglama Bağlamı Deseni (Logback)\n\n```java\n@ApplicationScoped\npublic class ProcessingService {\n\n    public void processDocument(Document doc) {\n        LogContext logContext = CustomLog.getCurrentContext();\n        try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {\n            \u002F\u002F Tüm log ifadelerine bağlam ekle\n            logContext.put(\"documentId\", doc.getId().toString());\n            logContext.put(\"documentType\", doc.getType());\n            logContext.put(\"userId\", SecurityContext.getUserId());\n\n            log.info(\"Starting document processing\");\n\n            \u002F\u002F Bu kapsam içindeki tüm loglar bağlamı devralır\n            processInternal(doc);\n\n            log.info(\"Document processing completed\");\n        } catch (Exception e) {\n            log.error(\"Document processing failed\", e);\n            throw e;\n        }\n    }\n}\n```\n\n**Logback Yapılandırması (logback.xml):**\n\n```xml\n\u003Cconfiguration>\n    \u003Cappender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        \u003Cencoder class=\"net.logstash.logback.encoder.LogstashEncoder\">\n            \u003CincludeContext>true\u003C\u002FincludeContext>\n            \u003CincludeMdc>true\u003C\u002FincludeMdc>\n        \u003C\u002Fencoder>\n    \u003C\u002Fappender>\n\n    \u003Clogger name=\"com.example\" level=\"INFO\"\u002F>\n    \u003Croot level=\"WARN\">\n        \u003Cappender-ref ref=\"CONSOLE\"\u002F>\n    \u003C\u002Froot>\n\u003C\u002Fconfiguration>\n```\n\n### Event Service Deseni\n\n```java\n@Slf4j\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class EventService {\n    private final EventRepository eventRepository;\n    private final ObjectMapper objectMapper;\n\n    public void createSuccessEvent(Object payload, String eventType) {\n        Objects.requireNonNull(payload, \"Payload cannot be null\");\n        Event event = new Event();\n        event.setType(eventType);\n        event.setStatus(EventStatus.SUCCESS);\n        event.setPayload(serializePayload(payload));\n        event.setTimestamp(Instant.now());\n\n        eventRepository.persist(event);\n        log.info(\"Success event created: {}\", eventType);\n    }\n\n    public void createErrorEvent(Object payload, String eventType, String errorMessage) {\n        Objects.requireNonNull(payload, \"Payload cannot be null\");\n        if (errorMessage == null || errorMessage.isBlank()) {\n            throw new IllegalArgumentException(\"Error message cannot be blank\");\n        }\n        Event event = new Event();\n        event.setType(eventType);\n        event.setStatus(EventStatus.ERROR);\n        event.setErrorMessage(errorMessage);\n        event.setPayload(serializePayload(payload));\n        event.setTimestamp(Instant.now());\n\n        eventRepository.persist(event);\n        log.error(\"Error event created: {} - {}\", eventType, errorMessage);\n    }\n\n    private String serializePayload(Object payload) {\n        try {\n            return objectMapper.writeValueAsString(payload);\n        } catch (JsonProcessingException e) {\n            throw new IllegalStateException(\"Failed to serialize event payload\", e);\n        }\n    }\n}\n```\n\n## Camel Mesaj Yayınlama (RabbitMQ)\n\n```java\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class BusinessRulesPublisher {\n    private final ProducerTemplate producerTemplate;\n\n    @ConfigProperty(name = \"camel.rabbitmq.queue.business-rules\")\n    String businessRulesQueue;\n\n    public void publishAsync(BusinessRulesPayload payload) {\n        producerTemplate.asyncSendBody(\n            \"direct:business-rules-publisher\",\n            payload\n        );\n        log.info(\"Message published to business rules queue: {}\", payload.getDocumentId());\n    }\n\n    public void publishSync(BusinessRulesPayload payload) {\n        producerTemplate.sendBody(\n            \"direct:business-rules-publisher\",\n            payload\n        );\n    }\n}\n```\n\n**Camel Route Yapılandırması:**\n\n```java\n@ApplicationScoped\npublic class BusinessRulesRoute extends RouteBuilder {\n\n    @ConfigProperty(name = \"camel.rabbitmq.queue.business-rules\")\n    String businessRulesQueue;\n\n    @ConfigProperty(name = \"rabbitmq.host\")\n    String rabbitHost;\n\n    @ConfigProperty(name = \"rabbitmq.port\")\n    Integer rabbitPort;\n\n    @Override\n    public void configure() {\n        from(\"direct:business-rules-publisher\")\n            .routeId(\"business-rules-publisher\")\n            .log(\"Publishing message to RabbitMQ: ${body}\")\n            .marshal().json(JsonLibrary.Jackson)\n            .toF(\"spring-rabbitmq:%s?hostname=%s&portNumber=%d\",\n                businessRulesQueue, rabbitHost, rabbitPort);\n    }\n}\n```\n\n## Camel Direct Route'ları (Bellek İçi)\n\n```java\n@ApplicationScoped\npublic class DocumentProcessingRoute extends RouteBuilder {\n\n    @Override\n    public void configure() {\n        \u002F\u002F Hata yönetimi\n        onException(ValidationException.class)\n            .handled(true)\n            .to(\"direct:validation-error-handler\")\n            .log(\"Validation error: ${exception.message}\");\n\n        \u002F\u002F Ana işleme route'u\n        from(\"direct:process-document\")\n            .routeId(\"document-processing\")\n            .log(\"Processing document: ${header.documentId}\")\n            .bean(DocumentValidator.class, \"validate\")\n            .bean(DocumentTransformer.class, \"transform\")\n            .choice()\n                .when(header(\"documentType\").isEqualTo(\"INVOICE\"))\n                    .to(\"direct:process-invoice\")\n                .when(header(\"documentType\").isEqualTo(\"CREDIT_NOTE\"))\n                    .to(\"direct:process-credit-note\")\n                .otherwise()\n                    .to(\"direct:process-generic\")\n            .end();\n\n        from(\"direct:validation-error-handler\")\n            .bean(EventService.class, \"createErrorEvent\")\n            .log(\"Validation error handled\");\n    }\n}\n```\n\n## Camel Dosya İşleme\n\n```java\n@ApplicationScoped\npublic class FileMonitoringRoute extends RouteBuilder {\n\n    @ConfigProperty(name = \"file.input.directory\")\n    String inputDirectory;\n\n    @ConfigProperty(name = \"file.processed.directory\")\n    String processedDirectory;\n\n    @ConfigProperty(name = \"file.error.directory\")\n    String errorDirectory;\n\n    @Override\n    public void configure() {\n        from(\"file:\" + inputDirectory + \"?move=\" + processedDirectory +\n             \"&moveFailed=\" + errorDirectory + \"&delay=5000\")\n            .routeId(\"file-monitor\")\n            .log(\"Processing file: ${header.CamelFileName}\")\n            .to(\"direct:process-file\");\n\n        from(\"direct:process-file\")\n            .bean(As2ProcessingService.class, \"processFile\")\n            .log(\"File processing completed\");\n    }\n}\n```\n\n## Camel Bean Çağrısı\n\n```java\n@ApplicationScoped\npublic class InvoiceRoute extends RouteBuilder {\n\n    @Override\n    public void configure() {\n        from(\"direct:invoice-validation\")\n            .bean(InvoiceFlowValidator.class, \"validateFlowWithConfig\")\n            .log(\"Validation result: ${body}\");\n\n        from(\"direct:persist-and-publish\")\n            .bean(DocumentJobService.class, \"createDocumentAndJobEntities\")\n            .bean(BusinessRulesPublisher.class, \"publishAsync\")\n            .bean(EventService.class, \"createSuccessEvent(${body}, 'PUBLISHED')\");\n    }\n}\n```\n\n## REST API Yapısı\n\n```java\n@Path(\"\u002Fapi\u002Fdocuments\")\n@Produces(MediaType.APPLICATION_JSON)\n@Consumes(MediaType.APPLICATION_JSON)\n@RequiredArgsConstructor\npublic class DocumentResource {\n  private final DocumentService documentService;\n\n  @GET\n  public Response list(\n      @QueryParam(\"page\") @DefaultValue(\"0\") int page,\n      @QueryParam(\"size\") @DefaultValue(\"20\") int size) {\n    List\u003CDocument> documents = documentService.list(page, size);\n    return Response.ok(documents).build();\n  }\n\n  @POST\n  public Response create(@Valid CreateDocumentRequest request, @Context UriInfo uriInfo) {\n    Document document = documentService.create(request);\n    URI location = uriInfo.getAbsolutePathBuilder()\n        .path(String.valueOf(document.id))\n        .build();\n    return Response.created(location).entity(DocumentResponse.from(document)).build();\n  }\n\n  @GET\n  @Path(\"\u002F{id}\")\n  public Response getById(@PathParam(\"id\") Long id) {\n    return documentService.findById(id)\n        .map(DocumentResponse::from)\n        .map(Response::ok)\n        .orElse(Response.status(Response.Status.NOT_FOUND))\n        .build();\n  }\n}\n```\n\n## Repository Deseni (Panache Repository)\n\n```java\n@ApplicationScoped\npublic class DocumentRepository implements PanacheRepository\u003CDocument> {\n\n  public List\u003CDocument> findByStatus(DocumentStatus status, int page, int size) {\n    return find(\"status = ?1 order by createdAt desc\", status)\n        .page(page, size)\n        .list();\n  }\n\n  public Optional\u003CDocument> findByReferenceNumber(String referenceNumber) {\n    return find(\"referenceNumber\", referenceNumber).firstResultOptional();\n  }\n\n  public long countByStatusAndDate(DocumentStatus status, LocalDate date) {\n    return count(\"status = ?1 and createdAt >= ?2\", status, date.atStartOfDay());\n  }\n}\n```\n\n## Transaction'lı Service Katmanı\n\n```java\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class DocumentService {\n  private final DocumentRepository repo;\n  private final EventService eventService;\n\n  @Transactional\n  public Document create(CreateDocumentRequest request) {\n    Document document = new Document();\n    document.setReferenceNumber(request.referenceNumber());\n    document.setDescription(request.description());\n    document.setStatus(DocumentStatus.PENDING);\n    document.setCreatedAt(Instant.now());\n\n    repo.persist(document);\n\n    eventService.createSuccessEvent(document, \"DOCUMENT_CREATED\");\n\n    return document;\n  }\n\n  public Optional\u003CDocument> findById(Long id) {\n    return repo.findByIdOptional(id);\n  }\n\n  public List\u003CDocument> list(int page, int size) {\n    return repo.findAll()\n        .page(page, size)\n        .list();\n  }\n}\n```\n\n## DTO'lar ve Validation\n\n```java\npublic record CreateDocumentRequest(\n    @NotBlank @Size(max = 200) String referenceNumber,\n    @NotBlank @Size(max = 2000) String description,\n    @NotNull @FutureOrPresent Instant validUntil,\n    @NotEmpty List\u003C@NotBlank String> categories) {}\n\npublic record DocumentResponse(Long id, String referenceNumber, DocumentStatus status) {\n  public static DocumentResponse from(Document document) {\n    return new DocumentResponse(document.getId(), document.getReferenceNumber(),\n        document.getStatus());\n  }\n}\n```\n\n## Exception Eşleme\n\n```java\n@Provider\npublic class ValidationExceptionMapper implements ExceptionMapper\u003CConstraintViolationException> {\n  @Override\n  public Response toResponse(ConstraintViolationException exception) {\n    String message = exception.getConstraintViolations().stream()\n        .map(cv -> cv.getPropertyPath() + \": \" + cv.getMessage())\n        .collect(Collectors.joining(\", \"));\n\n    return Response.status(Response.Status.BAD_REQUEST)\n        .entity(Map.of(\"error\", \"validation_error\", \"message\", message))\n        .build();\n  }\n}\n\n@Provider\n@Slf4j\npublic class GenericExceptionMapper implements ExceptionMapper\u003CException> {\n\n  @Override\n  public Response toResponse(Exception exception) {\n    log.error(\"Unhandled exception\", exception);\n    return Response.status(Response.Status.INTERNAL_SERVER_ERROR)\n        .entity(Map.of(\"error\", \"internal_error\", \"message\", \"An unexpected error occurred\"))\n        .build();\n  }\n}\n```\n\n## CompletableFuture Async İşlemleri\n\n```java\n@Slf4j\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class FileStorageService {\n    private final S3Client s3Client;\n    private final ExecutorService executorService;\n\n    @ConfigProperty(name = \"storage.bucket-name\") String bucketName;\n\n    public CompletableFuture\u003CStoredDocumentInfo> uploadOriginalFile(\n            InputStream inputStream,\n            long size,\n            LogContext logContext,\n            InvoiceFormat format) {\n\n        return CompletableFuture.supplyAsync(() -> {\n            try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {\n                String path = generateStoragePath(format);\n\n                PutObjectRequest request = PutObjectRequest.builder()\n                    .bucket(bucketName)\n                    .key(path)\n                    .contentLength(size)\n                    .build();\n\n                s3Client.putObject(request, RequestBody.fromInputStream(inputStream, size));\n\n                log.info(\"File uploaded to S3: {}\", path);\n\n                return new StoredDocumentInfo(path, size, Instant.now());\n            } catch (Exception e) {\n                log.error(\"Failed to upload file to S3\", e);\n                throw new StorageException(\"Upload failed\", e);\n            }\n        }, executorService);\n    }\n}\n```\n\n## Caching\n\n```java\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class DocumentCacheService {\n  private final DocumentRepository repo;\n\n  @CacheResult(cacheName = \"document-cache\")\n  public Optional\u003CDocument> getById(@CacheKey Long id) {\n    return repo.findByIdOptional(id);\n  }\n\n  @CacheInvalidate(cacheName = \"document-cache\")\n  public void evict(@CacheKey Long id) {}\n\n  @CacheInvalidateAll(cacheName = \"document-cache\")\n  public void evictAll() {}\n}\n```\n\n## YAML Yapılandırması\n\n```yaml\n# application.yml (uygulama yapılandırması)\n\"%dev\":\n  quarkus:\n    datasource:\n      jdbc:\n        url: jdbc:postgresql:\u002F\u002Flocalhost:5432\u002Fdev_db\n      username: dev_user\n      password: dev_pass\n    hibernate-orm:\n      database:\n        generation: drop-and-create\n\n  rabbitmq:\n    host: localhost\n    port: 5672\n    username: guest\n    password: guest\n\n\"%test\":\n  quarkus:\n    datasource:\n      jdbc:\n        url: jdbc:h2:mem:test\n    hibernate-orm:\n      database:\n        generation: drop-and-create\n\n\"%prod\":\n  quarkus:\n    datasource:\n      jdbc:\n        url: ${DATABASE_URL}\n      username: ${DB_USER}\n      password: ${DB_PASSWORD}\n    hibernate-orm:\n      database:\n        generation: validate\n\n  rabbitmq:\n    host: ${RABBITMQ_HOST}\n    port: ${RABBITMQ_PORT}\n    username: ${RABBITMQ_USER}\n    password: ${RABBITMQ_PASSWORD}\n\n# Camel yapılandırması\ncamel:\n  rabbitmq:\n    queue:\n      business-rules: business-rules-queue\n      invoice-processing: invoice-processing-queue\n```\n\n## Sağlık Kontrolleri\n\n```java\n@Readiness\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class DatabaseHealthCheck implements HealthCheck {\n  private final AgroalDataSource dataSource;\n\n  @Override\n  public HealthCheckResponse call() {\n    try (Connection conn = dataSource.getConnection()) {\n      boolean valid = conn.isValid(2);\n      return HealthCheckResponse.named(\"Database connection\")\n          .status(valid)\n          .build();\n    } catch (SQLException e) {\n      return HealthCheckResponse.down(\"Database connection\");\n    }\n  }\n}\n\n@Liveness\n@ApplicationScoped\npublic class CamelHealthCheck implements HealthCheck {\n  @Inject\n  CamelContext camelContext;\n\n  @Override\n  public HealthCheckResponse call() {\n    boolean isStarted = camelContext.getStatus().isStarted();\n    return HealthCheckResponse.named(\"Camel Context\")\n        .status(isStarted)\n        .build();\n  }\n}\n```\n\n## Bağımlılıklar (Maven)\n\n```xml\n\u003Cproperties>\n    \u003Cquarkus.platform.version>3.27.0\u003C\u002Fquarkus.platform.version>\n    \u003Clombok.version>1.18.42\u003C\u002Flombok.version>\n    \u003Cassertj-core.version>3.24.2\u003C\u002Fassertj-core.version>\n    \u003Cjacoco-maven-plugin.version>0.8.13\u003C\u002Fjacoco-maven-plugin.version>\n    \u003Cmaven.compiler.release>17\u003C\u002Fmaven.compiler.release>\n\u003C\u002Fproperties>\n\n\u003CdependencyManagement>\n    \u003Cdependencies>\n        \u003Cdependency>\n            \u003CgroupId>io.quarkus.platform\u003C\u002FgroupId>\n            \u003CartifactId>quarkus-bom\u003C\u002FartifactId>\n            \u003Cversion>${quarkus.platform.version}\u003C\u002Fversion>\n            \u003Ctype>pom\u003C\u002Ftype>\n            \u003Cscope>import\u003C\u002Fscope>\n        \u003C\u002Fdependency>\n        \u003Cdependency>\n            \u003CgroupId>io.quarkus.platform\u003C\u002FgroupId>\n            \u003CartifactId>quarkus-camel-bom\u003C\u002FartifactId>\n            \u003Cversion>${quarkus.platform.version}\u003C\u002Fversion>\n            \u003Ctype>pom\u003C\u002Ftype>\n            \u003Cscope>import\u003C\u002Fscope>\n        \u003C\u002Fdependency>\n    \u003C\u002Fdependencies>\n\u003C\u002FdependencyManagement>\n\n\u003Cdependencies>\n    \u003C!-- Quarkus Çekirdek -->\n    \u003Cdependency>\n        \u003CgroupId>io.quarkus\u003C\u002FgroupId>\n        \u003CartifactId>quarkus-arc\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n    \u003Cdependency>\n        \u003CgroupId>io.quarkus\u003C\u002FgroupId>\n        \u003CartifactId>quarkus-config-yaml\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n\n    \u003C!-- Camel Uzantıları -->\n    \u003Cdependency>\n        \u003CgroupId>org.apache.camel.quarkus\u003C\u002FgroupId>\n        \u003CartifactId>camel-quarkus-spring-rabbitmq\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n    \u003Cdependency>\n        \u003CgroupId>org.apache.camel.quarkus\u003C\u002FgroupId>\n        \u003CartifactId>camel-quarkus-direct\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n    \u003Cdependency>\n        \u003CgroupId>org.apache.camel.quarkus\u003C\u002FgroupId>\n        \u003CartifactId>camel-quarkus-bean\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n\n    \u003C!-- Lombok -->\n    \u003Cdependency>\n        \u003CgroupId>org.projectlombok\u003C\u002FgroupId>\n        \u003CartifactId>lombok\u003C\u002FartifactId>\n        \u003Cversion>${lombok.version}\u003C\u002Fversion>\n        \u003Cscope>provided\u003C\u002Fscope>\n    \u003C\u002Fdependency>\n\n    \u003C!-- Loglama -->\n    \u003Cdependency>\n        \u003CgroupId>io.quarkiverse.logging.logback\u003C\u002FgroupId>\n        \u003CartifactId>quarkus-logging-logback\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n    \u003Cdependency>\n        \u003CgroupId>net.logstash.logback\u003C\u002FgroupId>\n        \u003CartifactId>logstash-logback-encoder\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n\u003C\u002Fdependencies>\n```\n\n## En İyi Uygulamalar\n\n### Mimari\n- Constructor injection için Lombok üzerinden `@RequiredArgsConstructor` kullanın\n- Service katmanını ince tutun; karmaşık mantığı uzmanlaşmış sınıflara devredin\n- Mesaj yönlendirme ve entegrasyon desenleri için Camel route'larını kullanın\n- Veri erişimi için Panache Repository desenini tercih edin\n\n### Event-Driven\n- EventService ile işlemleri her zaman takip edin (başarı\u002Fhata eventleri)\n- Bellek içi yönlendirme için Camel `direct:` endpoint'leri kullanın\n- RabbitMQ entegrasyonu için `spring-rabbitmq` bileşenini kullanın\n- `ProducerTemplate.asyncSendBody()` ile async yayınlama uygulayın\n\n### Loglama\n- Yapılandırılmış loglama için Logstash encoder ile Logback kullanın\n- LogContext'i `SafeAutoCloseable` ile servis çağrıları boyunca yayın\n- İstek takibi için LogContext'e bağlamsal bilgi ekleyin\n- Manuel logger oluşturma yerine `@Slf4j` kullanın\n\n### Async İşlemler\n- Bloklamayan I\u002FO işlemleri için CompletableFuture kullanın\n- Tamamlanmayı beklemek gerektiğinde `.join()` çağırın\n- CompletableFuture'dan gelen exception'ları düzgün şekilde ele alın\n- Takip için async işlemlere LogContext geçirin\n\n### Yapılandırma\n- YAML yapılandırmasını kullanın (`quarkus-config-yaml`)\n- Dev\u002Ftest\u002Fprod ortamları için profil-duyarlı yapılandırma\n- Hassas yapılandırmayı ortam değişkenlerine dışsallaştırın\n- Tip-güvenli yapılandırma injection için `@ConfigProperty` kullanın\n\n### Validation\n- Resource katmanında `@Valid` ile doğrulayın\n- DTO'larda Bean Validation annotasyonları kullanın\n- Exception'ları `@Provider` ile uygun HTTP yanıtlarına eşleyin\n\n### Transaction'lar\n- Veri değiştiren service metodlarında `@Transactional` kullanın\n- Transaction'ları kısa ve odaklı tutun\n- Transaction'lar içinden async işlem çağırmaktan kaçının\n\n### Test\n- Route testi için `camel-quarkus-junit5` kullanın\n- Assertion'lar için AssertJ kullanın\n- Tüm harici bağımlılıkları mock'layın\n- Koşullu akış mantığını kapsamlı biçimde test edin\n\n### Quarkus'a Özgü\n- En son LTS sürümünde kalın (3.x)\n- Hot reload için Quarkus dev modunu kullanın\n- Production hazırlığı için sağlık kontrolleri ekleyin\n- Native derleme uyumluluğunu periyodik olarak test edin\n","# Quarkus Geliştirme Desenleri\n\nApache Camel ile bulut-native, event-driven servisler için Quarkus 3.x mimari ve API desenleri.\n\n## When to Use\n\n- JAX-RS veya RESTEasy Reactive ile REST API'leri oluşturma\n- Resource → service → repository katmanlarını yapılandırma\n- Apache Camel ve RabbitMQ ile event-driven desenler uygulama\n- Hibernate Panache, caching veya reaktif akışları yapılandırma\n- Validation, exception mapping veya sayfalama ekleme\n- Dev\u002Fstaging\u002Fproduction ortamları için profiller kurma (YAML yapılandırma)\n- LogContext ve Logback\u002FLogstash encoder ile özel loglama\n- Async işlemler için CompletableFuture ile çalışma\n- Koşullu akış işleme uygulama\n- GraalVM native derleme ile çalışma\n\n## How It Works\n\nQuarkus servislerinde Resource -> service -> repository akışını CDI scope'ları,\n`@Transactional` sınırları, Panache\u002FHibernate veri erişimi ve Camel\u002FRabbitMQ\nentegrasyonlarıyla birlikte uygulayın. Aşağıdaki örnekler event üretimi,\ndosya işleme, özel logging context ve async yayınlama için kopyalanabilir\nbaşlangıç noktaları sağlar.\n\n## Examples\n\n### Birden Fazla Bağımlılıklı Service Katmanı (Lombok)\n\n```java\n@Slf4j\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class As2ProcessingService {\n\n    private final InvoiceFlowValidator invoiceFlowValidator;\n    private final EventService eventService;\n    private final DocumentJobService documentJobService;\n    private final BusinessRulesPublisher businessRulesPublisher;\n    private final FileStorageService fileStorageService;\n\n    public void processFile(Path filePath) throws Exception {\n        LogContext logContext = CustomLog.getCurrentContext();\n        try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {\n\n            String structureIdPartner = logContext.get(As2Constants.STRUCTURE_ID);\n\n            \u002F\u002F Koşullu akış mantığı\n            boolean isChorusFlow = Boolean.parseBoolean(logContext.get(As2Constants.CHORUS_FLOW));\n            log.info(\"Is CHORUS_FLOW message: {}\", isChorusFlow);\n\n            ValidationFlowConfig validationFlowConfig = isChorusFlow\n                    ? ValidationFlowConfig.xsdOnly()\n                    : ValidationFlowConfig.allValidations();\n\n            InvoiceValidationResult invoiceValidationResult = this.invoiceFlowValidator\n                    .validateFlowWithConfig(filePath, validationFlowConfig,\n                        EInvoiceSyntaxFormat.UBL, logContext);\n\n            FlowProfile flowProfile = isChorusFlow ?\n                    FlowProfile.EXTENDED_CTC_FR :\n                    this.invoiceFlowValidator.computeFlowProfile(invoiceValidationResult,\n                        invoiceValidationResult.getInvoiceDetails().invoiceFormat().getProfile());\n\n            log.info(\"Invoice validation completed. Message is valid\");\n\n            \u002F\u002F CompletableFuture async işlemi\n            try(InputStream inputStream = Files.newInputStream(filePath)) {\n                CompletableFuture\u003CStoredDocumentInfo> documentInfoCompletableFuture =\n                    fileStorageService.uploadOriginalFile(inputStream,\n                        invoiceValidationResult.getSize(), logContext,\n                        invoiceValidationResult.getInvoiceFormat());\n\n                StoredDocumentInfo documentInfo = documentInfoCompletableFuture.join();\n                log.info(\"File uploaded successfully: {}\", documentInfo.getPath());\n\n                if (StringUtils.isBlank(documentInfo.getPath())) {\n                    String errorMsg = \"File path is empty after upload\";\n                    log.error(errorMsg);\n                    this.eventService.createErrorEvent(documentInfo, \"FILE_UPLOAD_FAILED\", errorMsg);\n                    throw new As2ServerProcessingException(errorMsg);\n                }\n\n                this.eventService.createSuccessEvent(documentInfo, \"PERSISTENCE_BLOB_EVENT_TYPE\");\n\n                String originalFileName = documentInfo.getOriginalFileName();\n                BusinessRulesPayload payload = this.documentJobService.createDocumentAndJobEntities(\n                    documentInfo, originalFileName, structureIdPartner,\n                    flowProfile, invoiceValidationResult.getDocumentHash());\n\n                \u002F\u002F Async Camel yayınlama\n                businessRulesPublisher.publishAsync(payload);\n                this.eventService.createSuccessEvent(payload, \"BUSINESS_RULES_MESSAGE_SENT\");\n            }\n        }\n    }\n}\n```\n\n**Temel Desenler:**\n- Constructor injection için Lombok üzerinden `@RequiredArgsConstructor`\n- Logback loglama için `@Slf4j`\n- try-with-resources ile kapsamlı LogContext\n- Runtime parametrelerine dayalı koşullu akış mantığı\n- Async işlemler için `.join()` ile CompletableFuture\n- Başarı\u002Fhata senaryoları için event takibi\n- Async Camel mesaj yayınlama\n\n## Özel Loglama Bağlamı Deseni (Logback)\n\n```java\n@ApplicationScoped\npublic class ProcessingService {\n\n    public void processDocument(Document doc) {\n        LogContext logContext = CustomLog.getCurrentContext();\n        try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {\n            \u002F\u002F Tüm log ifadelerine bağlam ekle\n            logContext.put(\"documentId\", doc.getId().toString());\n            logContext.put(\"documentType\", doc.getType());\n            logContext.put(\"userId\", SecurityContext.getUserId());\n\n            log.info(\"Starting document processing\");\n\n            \u002F\u002F Bu kapsam içindeki tüm loglar bağlamı devralır\n            processInternal(doc);\n\n            log.info(\"Document processing completed\");\n        } catch (Exception e) {\n            log.error(\"Document processing failed\", e);\n            throw e;\n        }\n    }\n}\n```\n\n**Logback Yapılandırması (logback.xml):**\n\n```xml\n\u003Cconfiguration>\n    \u003Cappender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        \u003Cencoder class=\"net.logstash.logback.encoder.LogstashEncoder\">\n            \u003CincludeContext>true\u003C\u002FincludeContext>\n            \u003CincludeMdc>true\u003C\u002FincludeMdc>\n        \u003C\u002Fencoder>\n    \u003C\u002Fappender>\n\n    \u003Clogger name=\"com.example\" level=\"INFO\"\u002F>\n    \u003Croot level=\"WARN\">\n        \u003Cappender-ref ref=\"CONSOLE\"\u002F>\n    \u003C\u002Froot>\n\u003C\u002Fconfiguration>\n```\n\n### Event Service Deseni\n\n```java\n@Slf4j\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class EventService {\n    private final EventRepository eventRepository;\n    private final ObjectMapper objectMapper;\n\n    public void createSuccessEvent(Object payload, String eventType) {\n        Objects.requireNonNull(payload, \"Payload cannot be null\");\n        Event event = new Event();\n        event.setType(eventType);\n        event.setStatus(EventStatus.SUCCESS);\n        event.setPayload(serializePayload(payload));\n        event.setTimestamp(Instant.now());\n\n        eventRepository.persist(event);\n        log.info(\"Success event created: {}\", eventType);\n    }\n\n    public void createErrorEvent(Object payload, String eventType, String errorMessage) {\n        Objects.requireNonNull(payload, \"Payload cannot be null\");\n        if (errorMessage == null || errorMessage.isBlank()) {\n            throw new IllegalArgumentException(\"Error message cannot be blank\");\n        }\n        Event event = new Event();\n        event.setType(eventType);\n        event.setStatus(EventStatus.ERROR);\n        event.setErrorMessage(errorMessage);\n        event.setPayload(serializePayload(payload));\n        event.setTimestamp(Instant.now());\n\n        eventRepository.persist(event);\n        log.error(\"Error event created: {} - {}\", eventType, errorMessage);\n    }\n\n    private String serializePayload(Object payload) {\n        try {\n            return objectMapper.writeValueAsString(payload);\n        } catch (JsonProcessingException e) {\n            throw new IllegalStateException(\"Failed to serialize event payload\", e);\n        }\n    }\n}\n```\n\n## Camel Mesaj Yayınlama (RabbitMQ)\n\n```java\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class BusinessRulesPublisher {\n    private final ProducerTemplate producerTemplate;\n\n    @ConfigProperty(name = \"camel.rabbitmq.queue.business-rules\")\n    String businessRulesQueue;\n\n    public void publishAsync(BusinessRulesPayload payload) {\n        producerTemplate.asyncSendBody(\n            \"direct:business-rules-publisher\",\n            payload\n        );\n        log.info(\"Message published to business rules queue: {}\", payload.getDocumentId());\n    }\n\n    public void publishSync(BusinessRulesPayload payload) {\n        producerTemplate.sendBody(\n            \"direct:business-rules-publisher\",\n            payload\n        );\n    }\n}\n```\n\n**Camel Route Yapılandırması:**\n\n```java\n@ApplicationScoped\npublic class BusinessRulesRoute extends RouteBuilder {\n\n    @ConfigProperty(name = \"camel.rabbitmq.queue.business-rules\")\n    String businessRulesQueue;\n\n    @ConfigProperty(name = \"rabbitmq.host\")\n    String rabbitHost;\n\n    @ConfigProperty(name = \"rabbitmq.port\")\n    Integer rabbitPort;\n\n    @Override\n    public void configure() {\n        from(\"direct:business-rules-publisher\")\n            .routeId(\"business-rules-publisher\")\n            .log(\"Publishing message to RabbitMQ: ${body}\")\n            .marshal().json(JsonLibrary.Jackson)\n            .toF(\"spring-rabbitmq:%s?hostname=%s&portNumber=%d\",\n                businessRulesQueue, rabbitHost, rabbitPort);\n    }\n}\n```\n\n## Camel Direct Route'ları (Bellek İçi)\n\n```java\n@ApplicationScoped\npublic class DocumentProcessingRoute extends RouteBuilder {\n\n    @Override\n    public void configure() {\n        \u002F\u002F Hata yönetimi\n        onException(ValidationException.class)\n            .handled(true)\n            .to(\"direct:validation-error-handler\")\n            .log(\"Validation error: ${exception.message}\");\n\n        \u002F\u002F Ana işleme route'u\n        from(\"direct:process-document\")\n            .routeId(\"document-processing\")\n            .log(\"Processing document: ${header.documentId}\")\n            .bean(DocumentValidator.class, \"validate\")\n            .bean(DocumentTransformer.class, \"transform\")\n            .choice()\n                .when(header(\"documentType\").isEqualTo(\"INVOICE\"))\n                    .to(\"direct:process-invoice\")\n                .when(header(\"documentType\").isEqualTo(\"CREDIT_NOTE\"))\n                    .to(\"direct:process-credit-note\")\n                .otherwise()\n                    .to(\"direct:process-generic\")\n            .end();\n\n        from(\"direct:validation-error-handler\")\n            .bean(EventService.class, \"createErrorEvent\")\n            .log(\"Validation error handled\");\n    }\n}\n```\n\n## Camel Dosya İşleme\n\n```java\n@ApplicationScoped\npublic class FileMonitoringRoute extends RouteBuilder {\n\n    @ConfigProperty(name = \"file.input.directory\")\n    String inputDirectory;\n\n    @ConfigProperty(name = \"file.processed.directory\")\n    String processedDirectory;\n\n    @ConfigProperty(name = \"file.error.directory\")\n    String errorDirectory;\n\n    @Override\n    public void configure() {\n        from(\"file:\" + inputDirectory + \"?move=\" + processedDirectory +\n             \"&moveFailed=\" + errorDirectory + \"&delay=5000\")\n            .routeId(\"file-monitor\")\n            .log(\"Processing file: ${header.CamelFileName}\")\n            .to(\"direct:process-file\");\n\n        from(\"direct:process-file\")\n            .bean(As2ProcessingService.class, \"processFile\")\n            .log(\"File processing completed\");\n    }\n}\n```\n\n## Camel Bean Çağrısı\n\n```java\n@ApplicationScoped\npublic class InvoiceRoute extends RouteBuilder {\n\n    @Override\n    public void configure() {\n        from(\"direct:invoice-validation\")\n            .bean(InvoiceFlowValidator.class, \"validateFlowWithConfig\")\n            .log(\"Validation result: ${body}\");\n\n        from(\"direct:persist-and-publish\")\n            .bean(DocumentJobService.class, \"createDocumentAndJobEntities\")\n            .bean(BusinessRulesPublisher.class, \"publishAsync\")\n            .bean(EventService.class, \"createSuccessEvent(${body}, 'PUBLISHED')\");\n    }\n}\n```\n\n## REST API Yapısı\n\n```java\n@Path(\"\u002Fapi\u002Fdocuments\")\n@Produces(MediaType.APPLICATION_JSON)\n@Consumes(MediaType.APPLICATION_JSON)\n@RequiredArgsConstructor\npublic class DocumentResource {\n  private final DocumentService documentService;\n\n  @GET\n  public Response list(\n      @QueryParam(\"page\") @DefaultValue(\"0\") int page,\n      @QueryParam(\"size\") @DefaultValue(\"20\") int size) {\n    List\u003CDocument> documents = documentService.list(page, size);\n    return Response.ok(documents).build();\n  }\n\n  @POST\n  public Response create(@Valid CreateDocumentRequest request, @Context UriInfo uriInfo) {\n    Document document = documentService.create(request);\n    URI location = uriInfo.getAbsolutePathBuilder()\n        .path(String.valueOf(document.id))\n        .build();\n    return Response.created(location).entity(DocumentResponse.from(document)).build();\n  }\n\n  @GET\n  @Path(\"\u002F{id}\")\n  public Response getById(@PathParam(\"id\") Long id) {\n    return documentService.findById(id)\n        .map(DocumentResponse::from)\n        .map(Response::ok)\n        .orElse(Response.status(Response.Status.NOT_FOUND))\n        .build();\n  }\n}\n```\n\n## Repository Deseni (Panache Repository)\n\n```java\n@ApplicationScoped\npublic class DocumentRepository implements PanacheRepository\u003CDocument> {\n\n  public List\u003CDocument> findByStatus(DocumentStatus status, int page, int size) {\n    return find(\"status = ?1 order by createdAt desc\", status)\n        .page(page, size)\n        .list();\n  }\n\n  public Optional\u003CDocument> findByReferenceNumber(String referenceNumber) {\n    return find(\"referenceNumber\", referenceNumber).firstResultOptional();\n  }\n\n  public long countByStatusAndDate(DocumentStatus status, LocalDate date) {\n    return count(\"status = ?1 and createdAt >= ?2\", status, date.atStartOfDay());\n  }\n}\n```\n\n## Transaction'lı Service Katmanı\n\n```java\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class DocumentService {\n  private final DocumentRepository repo;\n  private final EventService eventService;\n\n  @Transactional\n  public Document create(CreateDocumentRequest request) {\n    Document document = new Document();\n    document.setReferenceNumber(request.referenceNumber());\n    document.setDescription(request.description());\n    document.setStatus(DocumentStatus.PENDING);\n    document.setCreatedAt(Instant.now());\n\n    repo.persist(document);\n\n    eventService.createSuccessEvent(document, \"DOCUMENT_CREATED\");\n\n    return document;\n  }\n\n  public Optional\u003CDocument> findById(Long id) {\n    return repo.findByIdOptional(id);\n  }\n\n  public List\u003CDocument> list(int page, int size) {\n    return repo.findAll()\n        .page(page, size)\n        .list();\n  }\n}\n```\n\n## DTO'lar ve Validation\n\n```java\npublic record CreateDocumentRequest(\n    @NotBlank @Size(max = 200) String referenceNumber,\n    @NotBlank @Size(max = 2000) String description,\n    @NotNull @FutureOrPresent Instant validUntil,\n    @NotEmpty List\u003C@NotBlank String> categories) {}\n\npublic record DocumentResponse(Long id, String referenceNumber, DocumentStatus status) {\n  public static DocumentResponse from(Document document) {\n    return new DocumentResponse(document.getId(), document.getReferenceNumber(),\n        document.getStatus());\n  }\n}\n```\n\n## Exception Eşleme\n\n```java\n@Provider\npublic class ValidationExceptionMapper implements ExceptionMapper\u003CConstraintViolationException> {\n  @Override\n  public Response toResponse(ConstraintViolationException exception) {\n    String message = exception.getConstraintViolations().stream()\n        .map(cv -> cv.getPropertyPath() + \": \" + cv.getMessage())\n        .collect(Collectors.joining(\", \"));\n\n    return Response.status(Response.Status.BAD_REQUEST)\n        .entity(Map.of(\"error\", \"validation_error\", \"message\", message))\n        .build();\n  }\n}\n\n@Provider\n@Slf4j\npublic class GenericExceptionMapper implements ExceptionMapper\u003CException> {\n\n  @Override\n  public Response toResponse(Exception exception) {\n    log.error(\"Unhandled exception\", exception);\n    return Response.status(Response.Status.INTERNAL_SERVER_ERROR)\n        .entity(Map.of(\"error\", \"internal_error\", \"message\", \"An unexpected error occurred\"))\n        .build();\n  }\n}\n```\n\n## CompletableFuture Async İşlemleri\n\n```java\n@Slf4j\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class FileStorageService {\n    private final S3Client s3Client;\n    private final ExecutorService executorService;\n\n    @ConfigProperty(name = \"storage.bucket-name\") String bucketName;\n\n    public CompletableFuture\u003CStoredDocumentInfo> uploadOriginalFile(\n            InputStream inputStream,\n            long size,\n            LogContext logContext,\n            InvoiceFormat format) {\n\n        return CompletableFuture.supplyAsync(() -> {\n            try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {\n                String path = generateStoragePath(format);\n\n                PutObjectRequest request = PutObjectRequest.builder()\n                    .bucket(bucketName)\n                    .key(path)\n                    .contentLength(size)\n                    .build();\n\n                s3Client.putObject(request, RequestBody.fromInputStream(inputStream, size));\n\n                log.info(\"File uploaded to S3: {}\", path);\n\n                return new StoredDocumentInfo(path, size, Instant.now());\n            } catch (Exception e) {\n                log.error(\"Failed to upload file to S3\", e);\n                throw new StorageException(\"Upload failed\", e);\n            }\n        }, executorService);\n    }\n}\n```\n\n## Caching\n\n```java\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class DocumentCacheService {\n  private final DocumentRepository repo;\n\n  @CacheResult(cacheName = \"document-cache\")\n  public Optional\u003CDocument> getById(@CacheKey Long id) {\n    return repo.findByIdOptional(id);\n  }\n\n  @CacheInvalidate(cacheName = \"document-cache\")\n  public void evict(@CacheKey Long id) {}\n\n  @CacheInvalidateAll(cacheName = \"document-cache\")\n  public void evictAll() {}\n}\n```\n\n## YAML Yapılandırması\n\n```yaml\n# application.yml (uygulama yapılandırması)\n\"%dev\":\n  quarkus:\n    datasource:\n      jdbc:\n        url: jdbc:postgresql:\u002F\u002Flocalhost:5432\u002Fdev_db\n      username: dev_user\n      password: dev_pass\n    hibernate-orm:\n      database:\n        generation: drop-and-create\n\n  rabbitmq:\n    host: localhost\n    port: 5672\n    username: guest\n    password: guest\n\n\"%test\":\n  quarkus:\n    datasource:\n      jdbc:\n        url: jdbc:h2:mem:test\n    hibernate-orm:\n      database:\n        generation: drop-and-create\n\n\"%prod\":\n  quarkus:\n    datasource:\n      jdbc:\n        url: ${DATABASE_URL}\n      username: ${DB_USER}\n      password: ${DB_PASSWORD}\n    hibernate-orm:\n      database:\n        generation: validate\n\n  rabbitmq:\n    host: ${RABBITMQ_HOST}\n    port: ${RABBITMQ_PORT}\n    username: ${RABBITMQ_USER}\n    password: ${RABBITMQ_PASSWORD}\n\n# Camel yapılandırması\ncamel:\n  rabbitmq:\n    queue:\n      business-rules: business-rules-queue\n      invoice-processing: invoice-processing-queue\n```\n\n## Sağlık Kontrolleri\n\n```java\n@Readiness\n@ApplicationScoped\n@RequiredArgsConstructor\npublic class DatabaseHealthCheck implements HealthCheck {\n  private final AgroalDataSource dataSource;\n\n  @Override\n  public HealthCheckResponse call() {\n    try (Connection conn = dataSource.getConnection()) {\n      boolean valid = conn.isValid(2);\n      return HealthCheckResponse.named(\"Database connection\")\n          .status(valid)\n          .build();\n    } catch (SQLException e) {\n      return HealthCheckResponse.down(\"Database connection\");\n    }\n  }\n}\n\n@Liveness\n@ApplicationScoped\npublic class CamelHealthCheck implements HealthCheck {\n  @Inject\n  CamelContext camelContext;\n\n  @Override\n  public HealthCheckResponse call() {\n    boolean isStarted = camelContext.getStatus().isStarted();\n    return HealthCheckResponse.named(\"Camel Context\")\n        .status(isStarted)\n        .build();\n  }\n}\n```\n\n## Bağımlılıklar (Maven)\n\n```xml\n\u003Cproperties>\n    \u003Cquarkus.platform.version>3.27.0\u003C\u002Fquarkus.platform.version>\n    \u003Clombok.version>1.18.42\u003C\u002Flombok.version>\n    \u003Cassertj-core.version>3.24.2\u003C\u002Fassertj-core.version>\n    \u003Cjacoco-maven-plugin.version>0.8.13\u003C\u002Fjacoco-maven-plugin.version>\n    \u003Cmaven.compiler.release>17\u003C\u002Fmaven.compiler.release>\n\u003C\u002Fproperties>\n\n\u003CdependencyManagement>\n    \u003Cdependencies>\n        \u003Cdependency>\n            \u003CgroupId>io.quarkus.platform\u003C\u002FgroupId>\n            \u003CartifactId>quarkus-bom\u003C\u002FartifactId>\n            \u003Cversion>${quarkus.platform.version}\u003C\u002Fversion>\n            \u003Ctype>pom\u003C\u002Ftype>\n            \u003Cscope>import\u003C\u002Fscope>\n        \u003C\u002Fdependency>\n        \u003Cdependency>\n            \u003CgroupId>io.quarkus.platform\u003C\u002FgroupId>\n            \u003CartifactId>quarkus-camel-bom\u003C\u002FartifactId>\n            \u003Cversion>${quarkus.platform.version}\u003C\u002Fversion>\n            \u003Ctype>pom\u003C\u002Ftype>\n            \u003Cscope>import\u003C\u002Fscope>\n        \u003C\u002Fdependency>\n    \u003C\u002Fdependencies>\n\u003C\u002FdependencyManagement>\n\n\u003Cdependencies>\n    \u003C!-- Quarkus Çekirdek -->\n    \u003Cdependency>\n        \u003CgroupId>io.quarkus\u003C\u002FgroupId>\n        \u003CartifactId>quarkus-arc\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n    \u003Cdependency>\n        \u003CgroupId>io.quarkus\u003C\u002FgroupId>\n        \u003CartifactId>quarkus-config-yaml\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n\n    \u003C!-- Camel Uzantıları -->\n    \u003Cdependency>\n        \u003CgroupId>org.apache.camel.quarkus\u003C\u002FgroupId>\n        \u003CartifactId>camel-quarkus-spring-rabbitmq\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n    \u003Cdependency>\n        \u003CgroupId>org.apache.camel.quarkus\u003C\u002FgroupId>\n        \u003CartifactId>camel-quarkus-direct\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n    \u003Cdependency>\n        \u003CgroupId>org.apache.camel.quarkus\u003C\u002FgroupId>\n        \u003CartifactId>camel-quarkus-bean\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n\n    \u003C!-- Lombok -->\n    \u003Cdependency>\n        \u003CgroupId>org.projectlombok\u003C\u002FgroupId>\n        \u003CartifactId>lombok\u003C\u002FartifactId>\n        \u003Cversion>${lombok.version}\u003C\u002Fversion>\n        \u003Cscope>provided\u003C\u002Fscope>\n    \u003C\u002Fdependency>\n\n    \u003C!-- Loglama -->\n    \u003Cdependency>\n        \u003CgroupId>io.quarkiverse.logging.logback\u003C\u002FgroupId>\n        \u003CartifactId>quarkus-logging-logback\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n    \u003Cdependency>\n        \u003CgroupId>net.logstash.logback\u003C\u002FgroupId>\n        \u003CartifactId>logstash-logback-encoder\u003C\u002FartifactId>\n    \u003C\u002Fdependency>\n\u003C\u002Fdependencies>\n```\n\n## En İyi Uygulamalar\n\n### Mimari\n- Constructor injection için Lombok üzerinden `@RequiredArgsConstructor` kullanın\n- Service katmanını ince tutun; karmaşık mantığı uzmanlaşmış sınıflara devredin\n- Mesaj yönlendirme ve entegrasyon desenleri için Camel route'larını kullanın\n- Veri erişimi için Panache Repository desenini tercih edin\n\n### Event-Driven\n- EventService ile işlemleri her zaman takip edin (başarı\u002Fhata eventleri)\n- Bellek içi yönlendirme için Camel `direct:` endpoint'leri kullanın\n- RabbitMQ entegrasyonu için `spring-rabbitmq` bileşenini kullanın\n- `ProducerTemplate.asyncSendBody()` ile async yayınlama uygulayın\n\n### Loglama\n- Yapılandırılmış loglama için Logstash encoder ile Logback kullanın\n- LogContext'i `SafeAutoCloseable` ile servis çağrıları boyunca yayın\n- İstek takibi için LogContext'e bağlamsal bilgi ekleyin\n- Manuel logger oluşturma yerine `@Slf4j` kullanın\n\n### Async İşlemler\n- Bloklamayan I\u002FO işlemleri için CompletableFuture kullanın\n- Tamamlanmayı beklemek gerektiğinde `.join()` çağırın\n- CompletableFuture'dan gelen exception'ları düzgün şekilde ele alın\n- Takip için async işlemlere LogContext geçirin\n\n### Yapılandırma\n- YAML yapılandırmasını kullanın (`quarkus-config-yaml`)\n- Dev\u002Ftest\u002Fprod ortamları için profil-duyarlı yapılandırma\n- Hassas yapılandırmayı ortam değişkenlerine dışsallaştırın\n- Tip-güvenli yapılandırma injection için `@ConfigProperty` kullanın\n\n### Validation\n- Resource katmanında `@Valid` ile doğrulayın\n- DTO'larda Bean Validation annotasyonları kullanın\n- Exception'ları `@Provider` ile uygun HTTP yanıtlarına eşleyin\n\n### Transaction'lar\n- Veri değiştiren service metodlarında `@Transactional` kullanın\n- Transaction'ları kısa ve odaklı tutun\n- Transaction'lar içinden async işlem çağırmaktan kaçının\n\n### Test\n- Route testi için `camel-quarkus-junit5` kullanın\n- Assertion'lar için AssertJ kullanın\n- Tüm harici bağımlılıkları mock'layın\n- Koşullu akış mantığını kapsamlı biçimde test edin\n\n### Quarkus'a Özgü\n- En son LTS sürümünde kalın (3.x)\n- Hot reload için Quarkus dev modunu kullanın\n- Production hazırlığı için sağlık kontrolleri ekleyin\n- Native derleme uyumluluğunu periyodik olarak test edin\n",{"name":5,"origin":24,"description":7},"ECC","master","d6ca01da0f24a3b0e26e4a8b7b66cbd25d429f5d","everything-claude-code\u002Fdocs\u002Ftr\u002Fskills\u002Fquarkus-patterns",0,"https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills","https:\u002F\u002Fgithub.com\u002FSriramGandhiS","https:\u002F\u002Fsriram.website\u002F","Curious guy who keeps tinkering until something works","2026-05-20 16:21:34",{"source":8,"skillName":5,"commands":35,"prompt":45,"zipAvailable":46},[36,39,42],{"tool":37,"command":38},"npx","npx skills add SriramGandhiS\u002FSkills --skill quarkus-patterns",{"tool":40,"command":41},"bunx","bunx skills add SriramGandhiS\u002FSkills --skill quarkus-patterns",{"tool":43,"command":44},"pnpm","pnpm dlx skills add SriramGandhiS\u002FSkills --skill quarkus-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Feverything-claude-code\u002Fdocs\u002Ftr\u002Fskills\u002Fquarkus-patterns\u002FSKILL.md",true,[],[49,57,62,68,75,82],{"skillNo":50,"name":51,"nameZh":6,"description":52,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":53,"categories":54,"keywords":55,"publishedAt":56},"01M732609EPJWV13PVTX3GT4TM","webgpu-threejs-tsl","Comprehensive guide for developing WebGPU-enabled Three.js applications using TSL (Three.js Shading Language). Covers WebGPU renderer setup, TSL syntax and node materials, compute shaders, post-processing effects, and WGSL integration. Use this skill when working with Three.js WebGPU, TSL shaders, node materials, or GPU compute in Three.js.","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fwebgpu-threejs-tsl\u002Fskills\u002Fwebgpu-threejs-tsl\u002FSKILL.md",[],[],"2026-11-11 15:11:14",{"skillNo":58,"name":51,"nameZh":6,"description":52,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":59,"categories":60,"keywords":61,"publishedAt":56},"01M7325XM47AGWB6K6C4VXKE6B","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fwebgpu-threejs-tsl\u002FSKILL.md",[],[],{"skillNo":63,"name":64,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":65,"categories":66,"keywords":67,"publishedAt":56},"01M7325WP6DES69JKC840VMFEP","verification-loop","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fweb-assets\u002Fdocs\u002Fzh-TW\u002Fskills\u002Fverification-loop\u002FSKILL.md",[],[],{"skillNo":69,"name":70,"nameZh":6,"description":71,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":72,"categories":73,"keywords":74,"publishedAt":56},"01M7325TFQF1DZTQ6J3WGQQ1VR","tdd-workflow","Use this skill when writing new features, fixing bugs, or refactoring code. Enforces test-driven development with 80%+ coverage including unit, integration, and E2E tests.","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fweb-assets\u002Fdocs\u002Fzh-TW\u002Fskills\u002Ftdd-workflow\u002FSKILL.md",[],[],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":81,"publishedAt":56},"01M7325RGV9AY9PK92D2V8KKPW","strategic-compact","Suggests manual context compaction at logical intervals to preserve context through task phases rather than arbitrary auto-compaction.","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fweb-assets\u002Fdocs\u002Fzh-TW\u002Fskills\u002Fstrategic-compact\u002FSKILL.md",[],[],{"skillNo":83,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":88,"publishedAt":56},"01M7325MZC28SE86E7NMCNEFS4","security-review","Use this skill when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment\u002Fsensitive features. Provides comprehensive security checklist and patterns.","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fweb-assets\u002Fdocs\u002Fzh-TW\u002Fskills\u002Fsecurity-review\u002FSKILL.md",[],[]]