다크 모드
Hexagonal Architecture
truloop-core는 Hexagonal Architecture (Ports & Adapters) 패턴을 적용합니다. 비즈니스 로직을 외부 기술 의존성으로부터 완전히 격리하여, 테스트 용이성과 유지보수성을 극대화합니다.
아키텍처 다이어그램
모듈 의존성 그래프
계층 책임
Layer 0: Common (:common)
순수 유틸리티 모듈입니다. 프레임워크 의존성이 없는 leaf 모듈로, 모든 레이어에서 사용할 수 있습니다. kotlinx-datetime, kotlinx-serialization-json, tsid-creator, libphonenumber 등 경량 라이브러리만 사용합니다.
| 패키지 | 책임 |
|---|---|
config | 공통 설정 인터페이스 |
eid | TSID 기반 외부 공개 ID 생성 |
datetime | 날짜/시간 유틸리티 (TimeProvider 포함) |
phone | 전화번호 파싱/검증 |
validation | 공통 검증 로직 |
hashing | 해시 유틸리티 |
exception | InfrastructureException 정의 |
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:persistence | DB 접근 | Exposed Tables, 29개 Adapter (@Single) |
:adapter:external | 외부 서비스 | S3, FCM, Sendbird, Redis 등 18개 패키지 |
:adapter:web | HTTP 인터페이스 | 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에 의존하며, 그 반대는 절대 허용되지 않습니다.
- Domain 모듈은 프레임워크 독립적: Ktor, Exposed, AWS SDK import 금지
- Application 모듈 규칙:
org.koin.core.annotation.*마커 외 프레임워크 의존 금지 - 의존성 안쪽 방향: Adapter → Port (인터페이스), Port → Domain
- Port는 Application의 인터페이스: Adapter가 이를 구현
검증 명령어:
bash
./gradlew :domain:dependencies
./gradlew :application:dependencies요청 처리 흐름
Bootstrap 초기화 순서
AppConfig 로딩
application.yaml에서 21개 설정 섹션 로드. Review mode 초기화.
Ktor 플러그인 설치
- Sentry (에러 추적 — StatusPages보다 먼저 설치)
- ContentNegotiation (JSON 직렬화)
- StatusPages (에러 핸들링)
- CORS
- CallLogging + CallId (요청 로깅)
- RequestValidation
- Security (JWT + Internal API Key + Admin Google OIDC)
- BasePath (API 경로 접두사)
- 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-12 | OpenApi 플러그인 추가 반영 (Ktor 플러그인 13→14개) |
| 2026-03-10 | Common 패키지 목록 보강 (config, locale, util 추가), Domain에 shortform 추가, 외부 시스템 다이어그램에 SNS/Rekognition 추가, AppConfig 21개 섹션/Ktor 13개 플러그인으로 수치 교정, Bootstrap 초기화 순서 상세화 |