Skip to content

Hexagonal Architecture

truloop-core는 Hexagonal Architecture (Ports & Adapters) 패턴을 적용합니다. 비즈니스 로직을 외부 기술 의존성으로부터 완전히 격리하여, 테스트 용이성과 유지보수성을 극대화합니다.


아키텍처 다이어그램


모듈 의존성 그래프


계층 책임

Layer 0: Common (:common)

순수 유틸리티 모듈입니다. 프레임워크 의존성이 없는 leaf 모듈로, 모든 레이어에서 사용할 수 있습니다. kotlinx-datetime, kotlinx-serialization-json, tsid-creator, libphonenumber 등 경량 라이브러리만 사용합니다.

패키지책임
config공통 설정 인터페이스
eidTSID 기반 외부 공개 ID 생성
datetime날짜/시간 유틸리티 (TimeProvider 포함)
phone전화번호 파싱/검증
validation공통 검증 로직
hashing해시 유틸리티
exceptionInfrastructureException 정의
locale로케일 처리
security보안 관련 유틸리티
util범용 유틸리티 (SecureTokenGenerator 등)

Layer 1: Domain (:domain)

Enterprise Business Rules를 정의합니다. 프레임워크에 완전히 독립적이며, Ktor/Exposed/AWS SDK 등의 import가 허용되지 않습니다.

주요 도메인:

  • user - 사용자, 프로필
  • loop - 룹 (핵심 비즈니스 엔티티)
  • story - 리캡 (내부명: Story)
  • chat - 채팅
  • auth - 인증
  • shortform - 숏폼 (미사용/폐기 예정)
  • event - 도메인 이벤트 정의
  • shared - 공유 Value Objects (UserInfo, LoopInfo, Location)

Layer 2: Application (:application)

Application Business Rules를 정의합니다. Use Case와 Port Interface가 위치합니다.

  • Use Case: 비즈니스 로직 오케스트레이션 (@Factory 어노테이션)
  • Port Interface: 외부 의존성에 대한 추상화
  • Koin @Factory / @Single 마커 외에는 프레임워크 독립적

주의

Application 계층의 Port는 인터페이스만 정의합니다. 구현체는 Adapter 계층에 위치해야 합니다.

Layer 3: Adapters

Interface Adapters로, Port 인터페이스의 구현체를 제공합니다.

모듈책임주요 구현
:adapter:persistenceDB 접근Exposed Tables, 29개 Adapter (@Single)
:adapter:external외부 서비스S3, FCM, Sendbird, Redis 등 18개 패키지
:adapter:webHTTP 인터페이스Ktor Routes, DTOs, Controllers/Handlers

Layer 4: Bootstrap (:bootstrap)

Frameworks & Drivers로, 애플리케이션의 진입점이자 Composition Root입니다.

  • Koin DI 설정 및 모듈 조합
  • Ktor 플러그인 설치 (14개)
  • EventBus 및 EventHandlerRegistry 초기화
  • SQS Consumer 수명주기 관리
  • AppConfig 로딩 (21개 설정 섹션)

의존성 방향 규칙

위험

의존성은 항상 안쪽(Domain)을 향해 흐릅니다. Adapter가 Port에 의존하며, 그 반대는 절대 허용되지 않습니다.

  1. Domain 모듈은 프레임워크 독립적: Ktor, Exposed, AWS SDK import 금지
  2. Application 모듈 규칙: org.koin.core.annotation.* 마커 외 프레임워크 의존 금지
  3. 의존성 안쪽 방향: Adapter → Port (인터페이스), Port → Domain
  4. Port는 Application의 인터페이스: Adapter가 이를 구현

검증 명령어:

bash
./gradlew :domain:dependencies
./gradlew :application:dependencies

요청 처리 흐름


Bootstrap 초기화 순서

AppConfig 로딩

application.yaml에서 21개 설정 섹션 로드. Review mode 초기화.

Ktor 플러그인 설치

  1. Sentry (에러 추적 — StatusPages보다 먼저 설치)
  2. ContentNegotiation (JSON 직렬화)
  3. StatusPages (에러 핸들링)
  4. CORS
  5. CallLogging + CallId (요청 로깅)
  6. RequestValidation
  7. Security (JWT + Internal API Key + Admin Google OIDC)
  8. BasePath (API 경로 접두사)
  9. OpenApi (API 문서 자동 생성 — 보안 스키마 포함)

Koin DI 설정

infrastructureModule, externalServicesModule, persistenceModule, eventModule 및 Annotation Scan 모듈 등록. 추가로 ReferralCodeGeneratorPort 바인딩 모듈도 등록.

라우팅 구성

RouteRegistry.configureAllRoutes()로 전체 API 라우트 등록.

EventBus 초기화

EventBus 생성, EventHandlerRegistry에서 모든 @Single 핸들러 자동 발견 및 등록.

SQS Consumer 시작

SQS 큐 URL이 설정된 경우 Consumer 시작. Shutdown hook 등록.

Health Check 실행

외부 서비스 연결 상태 확인 후 서버 기동 완료.


변경 이력

날짜내용
2026-03-12OpenApi 플러그인 추가 반영 (Ktor 플러그인 13→14개)
2026-03-10Common 패키지 목록 보강 (config, locale, util 추가), Domain에 shortform 추가, 외부 시스템 다이어그램에 SNS/Rekognition 추가, AppConfig 21개 섹션/Ktor 13개 플러그인으로 수치 교정, Bootstrap 초기화 순서 상세화