설계

목적

  • Clean Architecture + DDD 패턴

핵심 원칙

  1. 의존성 방향: 항상 외부(infrastructure) → 내부(domain) 방향
  2. 단일 책임: 각 컴포넌트는 하나의 명확한 책임만
  3. 레이어 분리: 각 레이어는 자신보다 안쪽 레이어만 의존

최종 설계 구조

1. 레이어 구조

┌─────────────────────────────────────┐
│  Presentation Layer (Controller)    │  ← 사용자 인터페이스
├─────────────────────────────────────┤
│  Application Layer (Service)        │  ← 유스케이스 조율
├─────────────────────────────────────┤
│  Domain Layer (Entity, Service)     │  ← 비즈니스 로직 핵심
├─────────────────────────────────────┤
│  Infrastructure Layer (Repo, API)   │  ← 기술적 세부사항
└─────────────────────────────────────┘

의존성 방향:

Controller → Application Service → Domain Service → Entity
                ↓                      ↓
          Infrastructure ←──────────────┘
          (Repository, Sender)

서비스 기능 추가 시 설계 고민

예약 시간 이후에 추가된 유저도 전송 대상으로 포함 되도록 수정

🏗️ 아키텍처 레이어 구조

graph TD
    subgraph Presentation["🎯 Presentation Layer (Scheduling Trigger)"]
        A[MessageUtils.registerTaskSchedule<br/>- 예약 시간 30분 전에 TaskScheduler 등록]
    end
    
    subgraph Application1["📤 Application Layer (Sender)"]
        B[KakaoAlimtalkSenderImpl<br/>sendKakaoMessageByReservationByMessageIds]
    end
    
    subgraph Application2["📋 Application Layer (Use Case)"]
        C[MessageLogDetailServiceImpl<br/>addMissingDetailsBeforeSend]
        C1["1 - MessageLog 조회 (그룹 정보 포함)"]
        C2["2 - 타겟 그룹 조합 (selectGroup + includeGroups)"]
        C3["3 - 현재 시점 유저 조회"]
        C4["4 - 제외 유저 필터링"]
        C5["5 - 누락 유저 추출"]
        C6["6 - Domain Service 호출"]
        
        C --> C1 --> C2 --> C3 --> C4 --> C5 --> C6
    end
    
    subgraph Domain["🏛️ Domain Layer"]
        D[MessageLogDetailDomainService<br/>createDetailsForUsers]
        D1["1 - 도메인 검증 (canAddNewDetails)"]
        D2["2 - MessageContent 레벨별 조회"]
        D3["3 - User 레벨 매칭"]
        D4["4 - MessageLogDetail 생성"]
        
        D --> D1 --> D2 --> D3 --> D4
    end
    
    A -->|schedules<br/>30min before| B
    B -->|calls| C
    C6 -->|calls| D
    D -->|추가 된 유저 반환| B

    style Presentation fill:#e1f5ff
    style Application1 fill:#fff4e1
    style Application2 fill:#fff4e1
    style Domain fill:#f0e1ff

계층별로 역할

Presentation

  • 역할
    • 스케줄링 트리거
  • 장점
    • 실행 시점만 관리
    • 비즈니스 로직과 무관

Application Sender

  • 역할
    • 메시지 전송 서비스 레이어
  • 장점
    • 플랫폼별 전송 로직 캡슐화
    • 여러 API 통신 관리

Application Service

  • 역할
    • 누락 유저 추가 Detail 서비스 레이어
  • 장점
    • 여러 Repository 조합
    • 다른 UseCase에서 사용할 수 있음

Domain

  • 역할
    • 순수 비즈니스 로직
  • 장점
    • DB와 같은 외부 의존성이 없음
    • 단위 유닛 테스트 가능