affaan-m/ECC

quarkus-patterns

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.

85Collecting
See how to use itView GitHub source
npx skills add https://github.com/affaan-m/ECC --skill "docs/tr/skills/quarkus-patterns"
Automated source guide

Source checked Jul 28, 2026·Refresh due Oct 26, 2026

Reorganized from the pinned upstream SKILL.md

Turn quarkus-patterns's source instructions into a guide you can follow

According to the pinned SKILL.md from affaan-m/ECC: Apache Camel ile bulut-native, event-driven servisler için Quarkus 3.x mimari ve API desenleri.

npx skills add https://github.com/affaan-m/ECC --skill "docs/tr/skills/quarkus-patterns"
Check the pinned source

Best fit

  • JAX-RS veya RESTEasy Reactive ile REST API'leri oluşturma
  • Resource → service → repository katmanlarını yapılandırma
  • Apache Camel ve RabbitMQ ile event-driven desenler uygulama

Bring this context

  • A concrete task that matches the documented purpose of quarkus-patterns.
  • The files, examples, or context the task depends on.
  • Your constraints, target environment, and definition of done.

Expected outputs

  • Constructor injection için Lombok üzerinden @RequiredArgsConstructor
  • Logback loglama için @Slf4j
  • try-with-resources ile kapsamlı LogContext

Key source sections

Read quarkus-patterns through these 5 source sections

Sections are extracted automatically from the pinned SKILL.md and link back to the source.

01

When to Use

JAX-RS veya RESTEasy Reactive ile REST API'leri oluşturma

SKILL.md · When to Use
JAX-RS veya RESTEasy Reactive ile REST API'leri oluşturmaResource → service → repository katmanlarını yapılandırmaApache Camel ve RabbitMQ ile event-driven desenler uygulama
02

How It Works

Quarkus servislerinde Resource - service - repository akışını CDI scope'ları, @Transactional sınırları, Panache/Hibernate veri erişimi ve Camel/RabbitMQ entegrasyonlarıyla birlikte uygulayın. Aşağıdaki örnekler event üretimi, dosya işleme, özel logging context ve async yayınlama…

SKILL.md · How It Works
Quarkus servislerinde Resource - service - repository akışını CDI scope'ları, @Transactional sınırları, Panache/Hibernate veri erişimi ve Camel/RabbitMQ entegrasyonlarıyla birlikte uygulayın. Aşağıdaki örnekler event ür…
03

Examples

Temel Desenler: - Constructor injection için Lombok üzerinden @RequiredArgsConstructor - Logback loglama için @Slf4j - try-with-resources ile kapsamlı LogContext - Runtime parametrelerine dayalı koşullu akış mantığı - Async işlemler için .join() ile CompletableFuture - Başarı/ha…

SKILL.md · Examples
Constructor injection için Lombok üzerinden @RequiredArgsConstructorLogback loglama için @Slf4jtry-with-resources ile kapsamlı LogContext
04

Birden Fazla Bağımlılıklı Service Katmanı (Lombok)

Temel Desenler: - Constructor injection için Lombok üzerinden @RequiredArgsConstructor - Logback loglama için @Slf4j - try-with-resources ile kapsamlı LogContext - Runtime parametrelerine dayalı koşullu akış mantığı - Async işlemler için .join() ile CompletableFuture - Başarı/ha…

SKILL.md · Birden Fazla Bağımlılıklı Service Katmanı (Lombok)
Constructor injection için Lombok üzerinden @RequiredArgsConstructorLogback loglama için @Slf4jtry-with-resources ile kapsamlı LogContext

SkillSignal prompt templates

Provide the task, context, and acceptance criteria

These prompts were written by SkillSignal from the source structure; they are not upstream text.

Task-start prompt

Confirm source fit, inputs, and outputs before acting.

Use quarkus-patterns to help me with: [specific task]. Context: [files, data, or background]. Constraints: [environment, scope, and prohibited actions]. Before acting, check the pinned SKILL.md and explain which sections apply, what inputs are still missing, and what you will deliver.

Source-guided execution

Make the Agent explicitly follow the key extracted sections.

Apply the pinned quarkus-patterns source to [task]. Pay particular attention to these source sections: “When to Use”, “How It Works”, “Examples”, “Birden Fazla Bağımlılıklı Service Katmanı (Lombok)”, “Özel Loglama Bağlamı Deseni (Logback)”. Preserve the important decision at each step. Mark facts not covered by the source as “needs confirmation” instead of inventing them. Then verify the result against my acceptance criteria: [criteria].

Result-review prompt

Check omissions, permissions, and source drift before delivery.

Review the current quarkus-patterns result: (1) does it satisfy the original task; (2) were any applicable steps or limits in the pinned SKILL.md missed; (3) did it perform any unauthorized file, command, network, or data action; and (4) which conclusions remain unverified? List issues first, then fix only what the source or user authorization supports.

Output checklist

Verify each item before delivery

The task matches the purpose documented in the SKILL.md.

The source section “When to Use” has been checked.

The source section “How It Works” has been checked.

The source section “Examples” has been checked.

The source section “Birden Fazla Bağımlılıklı Service Katmanı (Lombok)” has been checked.

Inputs, constraints, and acceptance criteria are explicit.

Unverified facts, compatibility, and outcome claims are clearly marked.

Any file, command, network, or data action has been reviewed.

Choose a different workflow

When another Skill is the better fit

FAQ

What does quarkus-patterns do?

Apache Camel ile bulut-native, event-driven servisler için Quarkus 3.x mimari ve API desenleri.

How do I start using quarkus-patterns?

The catalog detected this source-specific install command: npx skills add https://github.com/affaan-m/ECC --skill "docs/tr/skills/quarkus-patterns". Inspect the command and pinned source before running it.

Which Agent platforms does it declare?

No dedicated Agent platform is declared in the pinned source record.

Repository stars
234,327
Repository forks
35,711
Quality
85/100
Source repository last pushed

Quality breakdown

Based on traceable docs and repository signals; stars are not treated as quality.

85/100
Documentation30/30
Specificity18/25
Maintenance20/20
Trust signals17/25

Compare before choosing

Related Agent Skills and source variants

These links are selected from shared tasks, functions, stacks, platforms, and same-name variants. Compare the source owner, documentation, permissions, and maintenance signals.

View original Skill.mdThis page is parsed directly from the repository SKILL.md without editorial rewriting. Collected: Jul 28, 2026 · about 3 min

Quarkus Geliştirme Desenleri

Apache Camel ile bulut-native, event-driven servisler için Quarkus 3.x mimari ve API desenleri.

When to Use

  • JAX-RS veya RESTEasy Reactive ile REST API'leri oluşturma
  • Resource → service → repository katmanlarını yapılandırma
  • Apache Camel ve RabbitMQ ile event-driven desenler uygulama
  • Hibernate Panache, caching veya reaktif akışları yapılandırma
  • Validation, exception mapping veya sayfalama ekleme
  • Dev/staging/production ortamları için profiller kurma (YAML yapılandırma)
  • LogContext ve Logback/Logstash encoder ile özel loglama
  • Async işlemler için CompletableFuture ile çalışma
  • Koşullu akış işleme uygulama
  • GraalVM native derleme ile çalışma

How It Works

Quarkus servislerinde Resource -> service -> repository akışını CDI scope'ları, @Transactional sınırları, Panache/Hibernate veri erişimi ve Camel/RabbitMQ entegrasyonlarıyla birlikte uygulayın. Aşağıdaki örnekler event üretimi, dosya işleme, özel logging context ve async yayınlama için kopyalanabilir başlangıç noktaları sağlar.

Examples

Birden Fazla Bağımlılıklı Service Katmanı (Lombok)

@Slf4j
@ApplicationScoped
@RequiredArgsConstructor
public class As2ProcessingService {

    private final InvoiceFlowValidator invoiceFlowValidator;
    private final EventService eventService;
    private final DocumentJobService documentJobService;
    private final BusinessRulesPublisher businessRulesPublisher;
    private final FileStorageService fileStorageService;

    public void processFile(Path filePath) throws Exception {
        LogContext logContext = CustomLog.getCurrentContext();
        try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {

            String structureIdPartner = logContext.get(As2Constants.STRUCTURE_ID);

            // Koşullu akış mantığı
            boolean isChorusFlow = Boolean.parseBoolean(logContext.get(As2Constants.CHORUS_FLOW));
            log.info("Is CHORUS_FLOW message: {}", isChorusFlow);

            ValidationFlowConfig validationFlowConfig = isChorusFlow
                    ? ValidationFlowConfig.xsdOnly()
                    : ValidationFlowConfig.allValidations();

            InvoiceValidationResult invoiceValidationResult = this.invoiceFlowValidator
                    .validateFlowWithConfig(filePath, validationFlowConfig,
                        EInvoiceSyntaxFormat.UBL, logContext);

            FlowProfile flowProfile = isChorusFlow ?
                    FlowProfile.EXTENDED_CTC_FR :
                    this.invoiceFlowValidator.computeFlowProfile(invoiceValidationResult,
                        invoiceValidationResult.getInvoiceDetails().invoiceFormat().getProfile());

            log.info("Invoice validation completed. Message is valid");

            // CompletableFuture async işlemi
            try(InputStream inputStream = Files.newInputStream(filePath)) {
                CompletableFuture<StoredDocumentInfo> documentInfoCompletableFuture =
                    fileStorageService.uploadOriginalFile(inputStream,
                        invoiceValidationResult.getSize(), logContext,
                        invoiceValidationResult.getInvoiceFormat());

                StoredDocumentInfo documentInfo = documentInfoCompletableFuture.join();
                log.info("File uploaded successfully: {}", documentInfo.getPath());

                if (StringUtils.isBlank(documentInfo.getPath())) {
                    String errorMsg = "File path is empty after upload";
                    log.error(errorMsg);
                    this.eventService.createErrorEvent(documentInfo, "FILE_UPLOAD_FAILED", errorMsg);
                    throw new As2ServerProcessingException(errorMsg);
                }

                this.eventService.createSuccessEvent(documentInfo, "PERSISTENCE_BLOB_EVENT_TYPE");

                String originalFileName = documentInfo.getOriginalFileName();
                BusinessRulesPayload payload = this.documentJobService.createDocumentAndJobEntities(
                    documentInfo, originalFileName, structureIdPartner,
                    flowProfile, invoiceValidationResult.getDocumentHash());

                // Async Camel yayınlama
                businessRulesPublisher.publishAsync(payload);
                this.eventService.createSuccessEvent(payload, "BUSINESS_RULES_MESSAGE_SENT");
            }
        }
    }
}

Temel Desenler:

  • Constructor injection için Lombok üzerinden @RequiredArgsConstructor
  • Logback loglama için @Slf4j
  • try-with-resources ile kapsamlı LogContext
  • Runtime parametrelerine dayalı koşullu akış mantığı
  • Async işlemler için .join() ile CompletableFuture
  • Başarı/hata senaryoları için event takibi
  • Async Camel mesaj yayınlama

Özel Loglama Bağlamı Deseni (Logback)

@ApplicationScoped
public class ProcessingService {

    public void processDocument(Document doc) {
        LogContext logContext = CustomLog.getCurrentContext();
        try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {
            // Tüm log ifadelerine bağlam ekle
            logContext.put("documentId", doc.getId().toString());
            logContext.put("documentType", doc.getType());
            logContext.put("userId", SecurityContext.getUserId());

            log.info("Starting document processing");

            // Bu kapsam içindeki tüm loglar bağlamı devralır
            processInternal(doc);

            log.info("Document processing completed");
        } catch (Exception e) {
            log.error("Document processing failed", e);
            throw e;
        }
    }
}

Logback Yapılandırması (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>

Event Service Deseni

@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);
        }
    }
}

Camel Mesaj Yayınlama (RabbitMQ)

@ApplicationScoped
@RequiredArgsConstructor
public class BusinessRulesPublisher {
    private final ProducerTemplate producerTemplate;

    @ConfigProperty(name = "camel.rabbitmq.queue.business-rules")
    String businessRulesQueue;

    public void publishAsync(BusinessRulesPayload payload) {
        producerTemplate.asyncSendBody(
            "direct:business-rules-publisher",
            payload
        );
        log.info("Message published to business rules queue: {}", payload.getDocumentId());
    }

    public void publishSync(BusinessRulesPayload payload) {
        producerTemplate.sendBody(
            "direct:business-rules-publisher",
            payload
        );
    }
}

Camel Route Yapılandırması:

@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);
    }
}

Camel Direct Route'ları (Bellek İçi)

@ApplicationScoped
public class DocumentProcessingRoute extends RouteBuilder {

    @Override
    public void configure() {
        // Hata yönetimi
        onException(ValidationException.class)
            .handled(true)
            .to("direct:validation-error-handler")
            .log("Validation error: ${exception.message}");

        // Ana işleme route'u
        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");
    }
}

Camel Dosya İşleme

@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(As2ProcessingService.class, "processFile")
            .log("File processing completed");
    }
}

Camel Bean Çağrısı

@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')");
    }
}

REST API Yapısı

@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();
  }
}

Repository Deseni (Panache Repository)

@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());
  }
}

Transaction'lı Service Katmanı

@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();
  }
}

DTO'lar ve Validation

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());
  }
}

Exception Eşleme

@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();
  }
}

CompletableFuture Async İşlemleri

@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);
    }
}

Caching

@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() {}
}

YAML Yapılandırması

# application.yml (uygulama yapılandırması)
"%dev":
  quarkus:
    datasource:
      jdbc:
        url: jdbc:postgresql://localhost:5432/dev_db
      username: dev_user
      password: dev_pass
    hibernate-orm:
      database:
        generation: drop-and-create

  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

"%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 yapılandırması
camel:
  rabbitmq:
    queue:
      business-rules: business-rules-queue
      invoice-processing: invoice-processing-queue

Sağlık Kontrolleri

@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();
  }
}

Bağımlılıklar (Maven)

<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 Çekirdek -->
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-arc</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-config-yaml</artifactId>
    </dependency>

    <!-- Camel Uzantıları -->
    <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>

    <!-- Loglama -->
    <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>

En İyi Uygulamalar

Mimari

  • Constructor injection için Lombok üzerinden @RequiredArgsConstructor kullanın
  • Service katmanını ince tutun; karmaşık mantığı uzmanlaşmış sınıflara devredin
  • Mesaj yönlendirme ve entegrasyon desenleri için Camel route'larını kullanın
  • Veri erişimi için Panache Repository desenini tercih edin

Event-Driven

  • EventService ile işlemleri her zaman takip edin (başarı/hata eventleri)
  • Bellek içi yönlendirme için Camel direct: endpoint'leri kullanın
  • RabbitMQ entegrasyonu için spring-rabbitmq bileşenini kullanın
  • ProducerTemplate.asyncSendBody() ile async yayınlama uygulayın

Loglama

  • Yapılandırılmış loglama için Logstash encoder ile Logback kullanın
  • LogContext'i SafeAutoCloseable ile servis çağrıları boyunca yayın
  • İstek takibi için LogContext'e bağlamsal bilgi ekleyin
  • Manuel logger oluşturma yerine @Slf4j kullanın

Async İşlemler

  • Bloklamayan I/O işlemleri için CompletableFuture kullanın
  • Tamamlanmayı beklemek gerektiğinde .join() çağırın
  • CompletableFuture'dan gelen exception'ları düzgün şekilde ele alın
  • Takip için async işlemlere LogContext geçirin

Yapılandırma

  • YAML yapılandırmasını kullanın (quarkus-config-yaml)
  • Dev/test/prod ortamları için profil-duyarlı yapılandırma
  • Hassas yapılandırmayı ortam değişkenlerine dışsallaştırın
  • Tip-güvenli yapılandırma injection için @ConfigProperty kullanın

Validation

  • Resource katmanında @Valid ile doğrulayın
  • DTO'larda Bean Validation annotasyonları kullanın
  • Exception'ları @Provider ile uygun HTTP yanıtlarına eşleyin

Transaction'lar

  • Veri değiştiren service metodlarında @Transactional kullanın
  • Transaction'ları kısa ve odaklı tutun
  • Transaction'lar içinden async işlem çağırmaktan kaçının

Test

  • Route testi için camel-quarkus-junit5 kullanın
  • Assertion'lar için AssertJ kullanın
  • Tüm harici bağımlılıkları mock'layın
  • Koşullu akış mantığını kapsamlı biçimde test edin

Quarkus'a Özgü

  • En son LTS sürümünde kalın (3.x)
  • Hot reload için Quarkus dev modunu kullanın
  • Production hazırlığı için sağlık kontrolleri ekleyin
  • Native derleme uyumluluğunu periyodik olarak test edin
Source repo
affaan-m/ECC
Skill path
docs/tr/skills/quarkus-patterns/SKILL.md
Commit SHA
4e973d3eaf92
Repository license
MIT
Data collected