返回 Skill 列表
extension
分类: 开发与工程无需 API Key

adapter-expert

Adapter Layer 专家。CommandAdapter(仅persist,JpaRepository 1:1),QueryAdapter(4个方法,QueryDslRepository 1:1),AdminQueryAdapter(允许Join,DTO Projection),LockQueryAdapter(6个Lock方法)。仅包含2个字段(Repository + Mapper)。必须使用@Component。绝对禁止使用@Transactional。

person作者: jakexiaohubgithub

Adapter Expert (Adapter 전문가)

목적 (Purpose)

Persistence Layer에서 Port-Out 인터페이스를 구현하는 Adapter를 규칙에 맞게 생성합니다. CQRS 원칙에 따라 Command/Query를 완전 분리하고, Repository ↔ Adapter 1:1 매핑 원칙을 준수합니다.

활성화 조건

  • /impl persistence {feature} 명령 실행 시
  • /plan 실행 후 Persistence Layer 작업 시
  • adapter, port-out, command adapter, query adapter 키워드 언급 시

산출물 (Output)

| 컴포넌트 | 파일명 패턴 | 위치 | Repository | |----------|-------------|------|------------| | CommandAdapter | {Bc}CommandAdapter.java | .../adapter/ | JpaRepository | | QueryAdapter | {Bc}QueryAdapter.java | .../adapter/ | QueryDslRepository | | AdminQueryAdapter | {Bc}AdminQueryAdapter.java | .../adapter/ | AdminQueryDslRepository | | LockQueryAdapter | {Bc}LockQueryAdapter.java | .../adapter/ | LockRepository |

완료 기준 (Acceptance Criteria)

  • [ ] CQRS 분리: Command/Query Adapter 완전 분리
  • [ ] 1:1 매핑: 각 Adapter는 하나의 Repository만 의존
  • [ ] 필드 2개만: Repository + Mapper (AdminQueryAdapter는 Mapper 선택적)
  • [ ] @Component 어노테이션 사용 (@Repository 아님!)
  • [ ] @Transactional 절대 금지 (Application Layer 책임)
  • [ ] 비즈니스 로직 없음 (단순 위임 + 변환만)
  • [ ] Lombok 금지
  • [ ] ArchUnit 테스트 통과

Adapter 선택 기준

┌─────────────────────────────────────────────────────────────────┐
│                    CQRS 기반 Adapter 분리                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐ │
│  │                    Command Adapter                         │ │
│  ├───────────────────────────────────────────────────────────┤ │
│  │  CommandAdapter                                           │ │
│  │  └─ JpaRepository (1:1) + Mapper                         │ │
│  │  └─ persist() 메서드만 (1개)                              │ │
│  └───────────────────────────────────────────────────────────┘ │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐ │
│  │                     Query Adapters                         │ │
│  ├───────────────────────────────────────────────────────────┤ │
│  │                                                           │ │
│  │  ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │ │
│  │  │  QueryAdapter   │ │AdminQueryAdapter│ │LockQueryAdp │ │ │
│  │  │   (일반 조회)   │ │   (관리자)      │ │   (Lock)    │ │ │
│  │  ├─────────────────┤ ├─────────────────┤ ├─────────────┤ │ │
│  │  │• QueryDslRepo   │ │• AdminQueryDsl  │ │• LockRepo   │ │ │
│  │  │• 4개 메서드     │ │• Join 허용      │ │• 6개 메서드 │ │ │
│  │  │• Domain 반환    │ │• DTO Projection │ │• Domain 반환│ │ │
│  │  └─────────────────┘ └─────────────────┘ └─────────────┘ │ │
│  │                                                           │ │
│  └───────────────────────────────────────────────────────────┘ │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

언제 무엇을 사용?

| 상황 | Adapter | Repository | 반환 타입 | |------|---------|------------|----------| | 저장/삭제 | CommandAdapter | JpaRepository | *Id | | 단순 조회 (ID, 목록) | QueryAdapter | QueryDslRepository | Domain | | 관리자 복잡 조회 (Join) | AdminQueryAdapter | AdminQueryDslRepository | DTO | | 동시성 제어 (재고, 좌석) | LockQueryAdapter | LockRepository | Domain |

Adapter 선택 플로우

저장/삭제 필요?
├─ Yes → CommandAdapter (persist만)
│
조회 필요?
├─ 단순 조회 (ID, 목록) → QueryAdapter (4개 메서드)
├─ 관리자 복잡 조회 (Join) → AdminQueryAdapter (DTO Projection)
│
동시성 제어 필요?
└─ 재고, 포인트, 좌석 예약 → LockQueryAdapter (6개 Lock 메서드)

코드 템플릿

1. CommandAdapter (JpaRepository 1:1)

package com.ryuqq.adapter.out.persistence.order.adapter;

import org.springframework.stereotype.Component;

import com.ryuqq.application.common.port.out.OrderPersistencePort;
import com.ryuqq.adapter.out.persistence.order.repository.OrderJpaRepository;
import com.ryuqq.adapter.out.persistence.order.mapper.OrderJpaEntityMapper;
import com.ryuqq.adapter.out.persistence.order.entity.OrderJpaEntity;
import com.ryuqq.domain.order.aggregate.Order;
import com.ryuqq.domain.order.vo.OrderId;

@Component
public class OrderCommandAdapter implements OrderPersistencePort {

    private final OrderJpaRepository orderJpaRepository;
    private final OrderJpaEntityMapper orderJpaEntityMapper;

    public OrderCommandAdapter(
        OrderJpaRepository orderJpaRepository,
        OrderJpaEntityMapper orderJpaEntityMapper
    ) {
        this.orderJpaRepository = orderJpaRepository;
        this.orderJpaEntityMapper = orderJpaEntityMapper;
    }

    /**
     * Order 저장 (신규 생성 또는 수정)
     *
     * <p>신규 생성 (ID 없음) → JPA가 ID 자동 할당 (INSERT)</p>
     * <p>기존 수정 (ID 있음) → 더티체킹으로 자동 UPDATE</p>
     *
     * @param order 저장할 Order (Domain)
     * @return 저장된 Order의 ID
     */
    @Override
    public OrderId persist(Order order) {
        // 1. Domain → Entity 변환
        OrderJpaEntity entity = orderJpaEntityMapper.toEntity(order);

        // 2. JPA 저장 (신규/수정 JPA가 자동 판단)
        OrderJpaEntity savedEntity = orderJpaRepository.save(entity);

        // 3. ID 반환
        return OrderId.of(savedEntity.getId());
    }
}

핵심 규칙:

  • 메서드 1개: persist() 만 제공 (update, delete 메서드 금지)
  • JpaRepository 1:1 매핑: 정확히 하나의 JpaRepository만 의존
  • 필드 2개만: Repository + Mapper
  • 반환 타입: *Id (OrderId, ProductId 등)
  • @Transactional 금지: Application Layer에서 관리

2. QueryAdapter (QueryDslRepository 1:1)

package com.ryuqq.adapter.out.persistence.order.adapter;

import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Component;

import com.ryuqq.application.common.port.out.OrderQueryPort;
import com.ryuqq.adapter.out.persistence.order.repository.OrderQueryDslRepository;
import com.ryuqq.adapter.out.persistence.order.mapper.OrderJpaEntityMapper;
import com.ryuqq.adapter.out.persistence.order.entity.OrderJpaEntity;
import com.ryuqq.domain.order.aggregate.Order;
import com.ryuqq.domain.order.vo.OrderId;
import com.ryuqq.domain.order.vo.OrderSearchCriteria;

@Component
public class OrderQueryAdapter implements OrderQueryPort {

    private final OrderQueryDslRepository queryDslRepository;
    private final OrderJpaEntityMapper orderJpaEntityMapper;

    public OrderQueryAdapter(
        OrderQueryDslRepository queryDslRepository,
        OrderJpaEntityMapper orderJpaEntityMapper
    ) {
        this.queryDslRepository = queryDslRepository;
        this.orderJpaEntityMapper = orderJpaEntityMapper;
    }

    /**
     * ID로 Order 단건 조회
     *
     * @param id Order ID
     * @return Order Domain (Optional)
     */
    @Override
    public Optional<Order> findById(OrderId id) {
        return queryDslRepository.findById(id.value())
            .map(orderJpaEntityMapper::toDomain);
    }

    /**
     * ID로 Order 존재 여부 확인
     *
     * @param id Order ID
     * @return 존재 여부
     */
    @Override
    public boolean existsById(OrderId id) {
        return queryDslRepository.existsById(id.value());
    }

    /**
     * 검색 조건으로 Order 목록 조회
     *
     * @param criteria 검색 조건
     * @return Order Domain 목록
     */
    @Override
    public List<Order> findByCriteria(OrderSearchCriteria criteria) {
        List<OrderJpaEntity> entities = queryDslRepository.findByCriteria(criteria);
        return entities.stream()
            .map(orderJpaEntityMapper::toDomain)
            .toList();
    }

    /**
     * 검색 조건으로 Order 개수 조회
     *
     * @param criteria 검색 조건
     * @return Order 개수
     */
    @Override
    public long countByCriteria(OrderSearchCriteria criteria) {
        return queryDslRepository.countByCriteria(criteria);
    }
}

핵심 규칙:

  • 메서드 4개 고정: findById, existsById, findByCriteria, countByCriteria
  • QueryDslRepository 1:1 매핑: 정확히 하나의 QueryDslRepository만 의존
  • 필드 2개만: Repository + Mapper
  • Domain 반환: Entity → Domain 변환 (DTO 반환 금지)
  • JPAQueryFactory 직접 사용 금지: QueryDslRepository에 위임

3. AdminQueryAdapter (AdminQueryDslRepository 1:1)

package com.ryuqq.adapter.out.persistence.order.adapter;

import java.util.List;
import java.util.Optional;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import com.ryuqq.application.common.port.out.OrderAdminQueryPort;
import com.ryuqq.adapter.out.persistence.order.repository.OrderAdminQueryDslRepository;
import com.ryuqq.application.order.dto.AdminOrderListResponse;
import com.ryuqq.application.order.dto.AdminOrderDetailResponse;
import com.ryuqq.application.order.dto.AdminOrderSearchCriteria;
import com.ryuqq.domain.order.vo.OrderId;

@Component
public class OrderAdminQueryAdapter implements OrderAdminQueryPort {

    private final OrderAdminQueryDslRepository adminQueryDslRepository;

    public OrderAdminQueryAdapter(OrderAdminQueryDslRepository adminQueryDslRepository) {
        this.adminQueryDslRepository = adminQueryDslRepository;
    }

    /**
     * 관리자 목록 조회 (Join 허용)
     *
     * @param criteria 검색 조건
     * @return 관리자 목록 Response (DTO Projection)
     */
    @Override
    public List<AdminOrderListResponse> findList(AdminOrderSearchCriteria criteria) {
        return adminQueryDslRepository.findList(criteria);
    }

    /**
     * 관리자 상세 조회 (Join 허용)
     *
     * @param id Order ID
     * @return 관리자 상세 Response (DTO Projection)
     */
    @Override
    public Optional<AdminOrderDetailResponse> findDetail(OrderId id) {
        return adminQueryDslRepository.findDetail(id.value());
    }

    /**
     * 관리자 페이징 조회
     *
     * @param criteria 검색 조건
     * @param pageable 페이징 정보
     * @return 페이징된 목록
     */
    @Override
    public Page<AdminOrderListResponse> findPage(
            AdminOrderSearchCriteria criteria,
            Pageable pageable
    ) {
        return adminQueryDslRepository.findPage(criteria, pageable);
    }
}

핵심 규칙:

  • 메서드 자유: 고정된 메서드 개수 없음
  • 필드 1~2개: AdminQueryDslRepository + (선택적) ResponseMapper
  • DTO Projection 직접 반환: Domain이 아닌 DTO 반환
  • Join 허용: AdminQueryDslRepository에서 Long FK 기반 Join

4. LockQueryAdapter (LockRepository 1:1)

package com.ryuqq.adapter.out.persistence.order.adapter;

import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Component;

import com.ryuqq.application.common.port.out.OrderLockQueryPort;
import com.ryuqq.adapter.out.persistence.order.repository.OrderLockRepository;
import com.ryuqq.adapter.out.persistence.order.mapper.OrderJpaEntityMapper;
import com.ryuqq.adapter.out.persistence.order.entity.OrderJpaEntity;
import com.ryuqq.domain.order.aggregate.Order;
import com.ryuqq.domain.order.vo.OrderId;
import com.ryuqq.domain.order.vo.OrderSearchCriteria;

@Component
public class OrderLockQueryAdapter implements OrderLockQueryPort {

    private final OrderLockRepository lockRepository;
    private final OrderJpaEntityMapper orderJpaEntityMapper;

    public OrderLockQueryAdapter(
        OrderLockRepository lockRepository,
        OrderJpaEntityMapper orderJpaEntityMapper
    ) {
        this.lockRepository = lockRepository;
        this.orderJpaEntityMapper = orderJpaEntityMapper;
    }

    // ========================================================================
    // Pessimistic Write Lock (FOR UPDATE)
    // ========================================================================

    /**
     * ID로 Order 단건 조회 (FOR UPDATE)
     *
     * @param id Order ID
     * @return Order Domain (Optional)
     * @throws PessimisticLockException Lock 획득 실패 시
     * @throws LockTimeoutException Lock 타임아웃 시
     */
    @Override
    public Optional<Order> findByIdForUpdate(OrderId id) {
        return lockRepository.findByIdForUpdate(id.value())
            .map(orderJpaEntityMapper::toDomain);
    }

    /**
     * Criteria로 Order 목록 조회 (FOR UPDATE)
     *
     * @param criteria 검색 조건
     * @return Order Domain 목록
     * @throws PessimisticLockException Lock 획득 실패 시
     * @throws LockTimeoutException Lock 타임아웃 시
     */
    @Override
    public List<Order> findByCriteriaForUpdate(OrderSearchCriteria criteria) {
        List<OrderJpaEntity> entities = lockRepository.findByCriteriaForUpdate(criteria);
        return entities.stream()
            .map(orderJpaEntityMapper::toDomain)
            .toList();
    }

    // ========================================================================
    // Pessimistic Read Lock (FOR SHARE)
    // ========================================================================

    /**
     * ID로 Order 단건 조회 (FOR SHARE)
     *
     * @param id Order ID
     * @return Order Domain (Optional)
     * @throws PessimisticLockException Lock 획득 실패 시
     * @throws LockTimeoutException Lock 타임아웃 시
     */
    @Override
    public Optional<Order> findByIdForShare(OrderId id) {
        return lockRepository.findByIdForShare(id.value())
            .map(orderJpaEntityMapper::toDomain);
    }

    /**
     * Criteria로 Order 목록 조회 (FOR SHARE)
     *
     * @param criteria 검색 조건
     * @return Order Domain 목록
     * @throws PessimisticLockException Lock 획득 실패 시
     * @throws LockTimeoutException Lock 타임아웃 시
     */
    @Override
    public List<Order> findByCriteriaForShare(OrderSearchCriteria criteria) {
        List<OrderJpaEntity> entities = lockRepository.findByCriteriaForShare(criteria);
        return entities.stream()
            .map(orderJpaEntityMapper::toDomain)
            .toList();
    }

    // ========================================================================
    // Optimistic Lock (@Version)
    // ========================================================================

    /**
     * ID로 Order 단건 조회 (Optimistic Lock)
     *
     * <p>조회 시 Lock을 걸지 않으며, 업데이트 시 OptimisticLockException 발생 가능</p>
     *
     * @param id Order ID
     * @return Order Domain (Optional)
     */
    @Override
    public Optional<Order> findByIdWithOptimisticLock(OrderId id) {
        return lockRepository.findByIdWithOptimisticLock(id.value())
            .map(orderJpaEntityMapper::toDomain);
    }

    /**
     * Criteria로 Order 목록 조회 (Optimistic Lock)
     *
     * <p>조회 시 Lock을 걸지 않으며, 업데이트 시 OptimisticLockException 발생 가능</p>
     *
     * @param criteria 검색 조건
     * @return Order Domain 목록
     */
    @Override
    public List<Order> findByCriteriaWithOptimisticLock(OrderSearchCriteria criteria) {
        List<OrderJpaEntity> entities = lockRepository.findByCriteriaWithOptimisticLock(criteria);
        return entities.stream()
            .map(orderJpaEntityMapper::toDomain)
            .toList();
    }
}

핵심 규칙:

  • 메서드 6개 고정: ForUpdate(2), ForShare(2), OptimisticLock(2)
  • LockRepository 1:1 매핑: 정확히 하나의 LockRepository만 의존
  • 필드 2개만: Repository + Mapper
  • Domain 반환: Entity → Domain 변환
  • 예외 명시: JavaDoc에 @throws 명시 (catch 하지 않음)
  • 예외 처리는 Application Layer: Adapter는 위임만

N+1 해결 전략

Application Layer에서 해결 (1:1 매핑 원칙 유지)

❌ Adapter에서 N+1 해결 (금지)
──────────────────────────────
OrderQueryAdapter
├─ orderQueryDslRepository
├─ customerQueryDslRepository  ← 금지! 1:1 위반
└─ mapper


✅ Application Layer에서 해결 (권장)
──────────────────────────────
OrderQueryUseCase (Application Layer)
├─ orderQueryPort.findByCriteria()     → 주문 목록
├─ customerQueryPort.findByIds()       → 고객 목록 (IN 절)
└─ 조합 및 Response 생성               → Application에서 처리

N+1 해결 패턴:

// Application Layer (UseCase)
@Component
public class OrderQueryUseCase {
    private final OrderQueryPort orderQueryPort;
    private final CustomerQueryPort customerQueryPort;

    @Transactional(readOnly = true)
    public List<OrderWithCustomerResponse> findOrdersWithCustomer(
            OrderSearchCriteria criteria) {
        // 1. 주문 조회
        List<Order> orders = orderQueryPort.findByCriteria(criteria);

        // 2. 고객 ID 수집
        Set<Long> customerIds = orders.stream()
            .map(Order::getCustomerId)
            .collect(Collectors.toSet());

        // 3. 고객 일괄 조회 (IN 절로 N+1 해결)
        Map<Long, Customer> customerMap = customerQueryPort.findByIds(customerIds)
            .stream()
            .collect(Collectors.toMap(c -> c.getId().getValue(), c -> c));

        // 4. 조합
        return orders.stream()
            .map(order -> new OrderWithCustomerResponse(
                order,
                customerMap.get(order.getCustomerId())
            ))
            .toList();
    }
}

Zero-Tolerance 규칙

✅ MANDATORY (필수)

| 규칙 | 설명 | |------|------| | @Component | 모든 Adapter에 적용 | | 1:1 매핑 | 각 Adapter는 정확히 하나의 Repository만 의존 | | 필드 2개만 | Repository + Mapper (AdminQueryAdapter는 Mapper 선택적) | | Domain 반환 | QueryAdapter, LockQueryAdapter는 Domain 반환 | | DTO 반환 | AdminQueryAdapter만 DTO Projection 반환 | | persist() | CommandAdapter 유일한 메서드 | | 4개 메서드 | QueryAdapter: findById, existsById, findByCriteria, countByCriteria | | 6개 메서드 | LockQueryAdapter: ForUpdate(2), ForShare(2), OptimisticLock(2) |

❌ PROHIBITED (금지)

| 항목 | 이유 | |------|------| | @Repository | @Component 사용 | | @Transactional | Application Layer에서 관리 | | 비즈니스 로직 | Domain Layer 책임 | | 다른 Repository 주입 | 1:1 매핑 위반 | | JPAQueryFactory 직접 사용 | QueryDslRepository에 위임 | | update(), delete() 메서드 | persist()로 통합 (더티체킹 활용) | | Query 메서드 in CommandAdapter | CQRS 분리 | | Command 메서드 in QueryAdapter | CQRS 분리 | | Lombok | Plain Java 사용 |


Adapter 유형별 비교

| 항목 | CommandAdapter | QueryAdapter | AdminQueryAdapter | LockQueryAdapter | |------|---------------|--------------|-------------------|------------------| | Repository | JpaRepository | QueryDslRepo | AdminQueryDslRepo | LockRepository | | 메서드 수 | 1개 (persist) | 4개 고정 | 자유 | 6개 고정 | | 필드 수 | 2개 | 2개 | 1~2개 | 2개 | | Mapper | 필수 | 필수 | 선택적 | 필수 | | 반환 타입 | *Id | Domain | DTO | Domain | | Join | N/A | ❌ 금지 | ✅ 허용 | N/A |


패키지 구조

adapter-out/persistence-mysql/
└─ src/main/java/
   └─ com/company/adapter/out/persistence/
       └─ order/
           ├─ entity/
           │  └─ OrderJpaEntity.java
           │
           ├─ repository/
           │  ├─ OrderJpaRepository.java              (JPA - Command)
           │  ├─ OrderQueryDslRepository.java         (QueryDSL - 일반)
           │  ├─ OrderAdminQueryDslRepository.java    (QueryDSL - 관리자)
           │  └─ OrderLockRepository.java             (Lock)
           │
           ├─ mapper/
           │  └─ OrderJpaEntityMapper.java
           │
           └─ adapter/
              ├─ OrderCommandAdapter.java          (JpaRepository 1:1)
              ├─ OrderQueryAdapter.java            (QueryDslRepository 1:1)
              ├─ OrderAdminQueryAdapter.java       (AdminQueryDslRepository 1:1)
              └─ OrderLockQueryAdapter.java        (LockRepository 1:1)

체크리스트 (Output Checklist)

CommandAdapter

  • [ ] @Component 어노테이션
  • [ ] *PersistencePort 구현
  • [ ] JpaRepository 의존성 주입
  • [ ] Mapper 의존성 주입
  • [ ] 필드 2개만
  • [ ] persist() 메서드만 (1개)
  • [ ] 반환 타입 *Id
  • [ ] @Transactional 금지
  • [ ] Query 메서드 없음
  • [ ] 비즈니스 로직 없음

QueryAdapter

  • [ ] @Component 어노테이션
  • [ ] *QueryPort 구현
  • [ ] QueryDslRepository 의존성 주입
  • [ ] Mapper 의존성 주입
  • [ ] 필드 2개만
  • [ ] findById() 메서드 - Optional<Domain>
  • [ ] existsById() 메서드 - boolean
  • [ ] findByCriteria() 메서드 - List<Domain>
  • [ ] countByCriteria() 메서드 - long
  • [ ] 메서드 4개만
  • [ ] @Transactional 금지
  • [ ] Command 메서드 없음
  • [ ] JPAQueryFactory 직접 사용 금지

AdminQueryAdapter

  • [ ] @Component 어노테이션
  • [ ] *AdminQueryPort 구현
  • [ ] AdminQueryDslRepository 의존성 주입
  • [ ] 필드 1~2개 (Mapper 선택적)
  • [ ] DTO Projection 직접 반환
  • [ ] @Transactional 금지
  • [ ] 비즈니스 로직 없음

LockQueryAdapter

  • [ ] @Component 어노테이션
  • [ ] *LockQueryPort 구현
  • [ ] LockRepository 의존성 주입
  • [ ] Mapper 의존성 주입
  • [ ] 필드 2개만
  • [ ] findByIdForUpdate() - FOR UPDATE 단건
  • [ ] findByCriteriaForUpdate() - FOR UPDATE 목록
  • [ ] findByIdForShare() - FOR SHARE 단건
  • [ ] findByCriteriaForShare() - FOR SHARE 목록
  • [ ] findByIdWithOptimisticLock() - Optimistic 단건
  • [ ] findByCriteriaWithOptimisticLock() - Optimistic 목록
  • [ ] 메서드 6개만
  • [ ] JavaDoc @throws 명시 (예외 catch 금지)
  • [ ] @Transactional 금지
  • [ ] Domain 반환

테스트 체크리스트

Adapter 단위 테스트

  • [ ] Repository 위임 검증
  • [ ] Mapper 변환 검증
  • [ ] 반환 타입 검증

ArchUnit 테스트

  • [ ] @Component 어노테이션 검증
  • [ ] @Transactional 금지 검증
  • [ ] 필드 개수 검증 (2개)
  • [ ] 메서드 개수/이름 검증
  • [ ] 1:1 매핑 검증

참조 문서

  • Adapter Guide: docs/coding_convention/04-persistence-layer/mysql/adapter/adapter-guide.md
  • Command Adapter Guide: docs/coding_convention/04-persistence-layer/mysql/adapter/command/command-adapter-guide.md
  • Query Adapter Guide: docs/coding_convention/04-persistence-layer/mysql/adapter/query/general/query-adapter-guide.md
  • Admin Query Adapter Guide: docs/coding_convention/04-persistence-layer/mysql/adapter/query/admin/admin-query-adapter-guide.md
  • Lock Query Adapter Guide: docs/coding_convention/04-persistence-layer/mysql/adapter/query/lock/lock-query-adapter-guide.md
  • Command Adapter ArchUnit: docs/coding_convention/04-persistence-layer/mysql/adapter/command/command-adapter-archunit.md
  • Query Adapter ArchUnit: docs/coding_convention/04-persistence-layer/mysql/adapter/query/general/query-adapter-archunit.md