다크 모드
모듈 구조
truloop-core는 Hexagonal Architecture에 따라 7개의 Gradle 모듈로 구성됩니다.
모듈 계층도
settings.gradle.kts
├── :common # Layer 0: 순수 유틸리티
├── :domain # Layer 1: Enterprise Business Rules
├── :application # Layer 2: Application Business Rules
├── :adapter:persistence # Layer 3: DB 어댑터
├── :adapter:external # Layer 3: 외부 서비스 어댑터
├── :adapter:web # Layer 3: HTTP 어댑터
└── :bootstrap # Layer 4: 진입점 & 조립모듈별 상세
:common — 공유 유틸리티
외부 의존성이 없는 leaf 모듈입니다. 다른 모든 모듈에서 사용할 수 있습니다.
co.butbeautiful.truloop.common/
├── config/ # 공통 설정 인터페이스
├── datetime/ # 날짜/시간 유틸리티
├── eid/ # TSID 기반 External ID 생성기
├── exception/ # InfrastructureException 계층
├── hashing/ # 해시 유틸리티
├── locale/ # 로케일 처리
├── phone/ # 전화번호 파싱/검증
├── security/ # 보안 유틸리티
├── util/ # 범용 유틸리티
└── validation/ # 검증 로직허용 의존성: Kotlin 표준 라이브러리 + kotlinx-datetime, kotlinx-serialization-json, tsid-creator, libphonenumber
:domain — 도메인 계층
엔티티, Value Object, 도메인 이벤트를 정의합니다. 프레임워크에 완전히 독립적입니다.
co.butbeautiful.truloop.domain/
├── appversion/ # 앱 버전
├── auth/ # 인증 도메인
├── block/ # 차단
├── chat/ # 채팅
├── contact/ # 연락처
├── contenttemplate/ # 콘텐츠 템플릿
├── coverselection/ # 커버 선택
├── covertemplate/ # 커버 템플릿
├── device/ # 디바이스
├── eta/ # ETA (예상 도착 시간)
├── event/ # 도메인 이벤트 정의
├── health/ # 헬스체크
├── liveactivity/ # Live Activity
├── loop/ # 룹 (핵심 엔티티)
├── loopcomment/ # 룹 댓글
├── loopguestparticipant/ # 비회원 참여자 (내부명: GuestParticipant)
├── loopinvitation/ # 룹 초대
├── loopmedia/ # 룹 미디어
├── mission/ # 미션
├── notificationcenter/ # 알림 센터
├── report/ # 신고
├── sampleloop/ # 샘플 룹
├── secretary/ # AI 비서
├── shared/ # 공유 VO (UserInfo, LoopInfo, Location)
├── shortform/ # 숏폼 (미사용/폐기 예정)
├── story/ # 리캡 (내부명: Story)
├── user/ # 사용자
└── verification/ # 인증(전화번호)허용 의존성: :common만 허용
:application — 애플리케이션 계층
Use Case와 Port 인터페이스를 정의합니다. 비즈니스 로직을 오케스트레이션합니다.
co.butbeautiful.truloop.application/
├── appversion/
├── assistant/
├── auth/
│ ├── port/ # AuthRepository, AuthQueries
│ └── usecase/ # LoginUseCase, RefreshTokenUseCase
├── block/
├── chat/
├── contact/
├── contenttemplate/
├── coverselection/
├── covertemplate/
├── dashboard/ # 관리자 대시보드
│ ├── port/ # DashboardStatsQueries
│ └── usecase/ # GetDashboardSummaryUseCase, GetDashboardTimeSeriesUseCase
├── device/
├── eta/
├── liveactivity/
├── loop/
│ ├── port/ # LoopRepository, LoopQueries
│ └── usecase/ # CreateLoopUseCase, JoinLoopUseCase
├── loopcomment/
├── loopguestparticipant/ # 비회원 참여자 (내부명: GuestParticipant)
├── loopinvitation/
├── loopmedia/ # 이미지 그룹핑 포트/UseCase 포함 (ImageGroupingPort, GroupingJobPublisherPort 등)
├── loopparticipant/
├── mission/
├── notification/
├── notificationcenter/
├── profile/
├── recommendation/
├── report/
├── sampleloop/ # 샘플 룹 (유스케이스 7개, SampleLoopGuard 포함)
│ ├── port/ # SampleLoopRepository, SampleLoopQueries
│ └── usecase/ # RegisterSampleLoopUseCase, GetSampleLoopsForUserUseCase 등
├── secretary/
├── shared/
│ ├── config/ # Policy 설정 (AuthTokenPolicy, WebLinkPolicy 등)
│ ├── dto/ # 공유 DTO
│ ├── error/ # 공통 에러 정의
│ ├── exception/ # 공통 예외 정의
│ └── port/ # 공통 Port 인터페이스 (12개)
├── story/ # 리캡 (내부명: Story)
├── user/
│ ├── port/ # UserRepository, UserQueries
│ └── usecase/
└── verification/허용 의존성: :domain, :common
정보
공통 Port 인터페이스 (shared/port/)에는 UnitOfWork, EventPublisher, CachePort, FileStoragePort, AnalyticsPort, DeepLinkPort, EnvironmentPort, ErrorReportingPort, HttpMetricsPort, MessageSourcePort, RevenueCatPort, SmsMessageSourcePort 등 모든 도메인에서 공유하는 인프라 추상화가 위치합니다.
:adapter:persistence — DB 어댑터
Exposed 기반의 Repository 구현체를 제공합니다. 도메인별로 패키지가 분리되어 있으며, 33개의 Adapter가 등록되어 있습니다.
co.butbeautiful.truloop.adapter.persistence/
├── auth/ # ExposedAuthAdapter, AuthTable
├── block/
├── contact/
├── contenttemplate/
├── coverselection/
├── covertemplate/
├── dashboard/ # ExposedDashboardStatsAdapter
├── device/
├── eta/
├── health/
├── loop/ # ExposedLoopAdapter, LoopsTable
├── loopcomment/
├── loopguestparticipant/ # 비회원 참여자 (내부명: GuestParticipant)
├── loopinvitation/
├── loopmedia/ # ExposedLoopGroupingAdapter, ExposedGroupRepresentativeAdapter 포함
├── mission/
├── notification/
├── report/
├── sampleloop/ # ExposedSampleLoopAdapter, SampleLoopsTable
├── secretary/
├── shared/ # ExposedUnitOfWork
├── story/ # 리캡 (내부명: Story)
├── user/ # ExposedUserAdapter, UsersTable
└── verification/허용 의존성: :application, :domain, :common
:adapter:external — 외부 서비스 어댑터
AWS, Firebase, Sendbird 등 외부 서비스에 대한 19개 패키지로 Port 구현체를 제공합니다.
co.butbeautiful.truloop.adapter.external/
├── ai/ # AI 서비스 연동
├── assistant/ # Assistant 서비스 연동
├── aws/ # S3FileStorageAdapter
├── covertemplate/ # 커버 템플릿 외부 서비스
├── deeplink/ # Branch 딥링크
├── fcm/ # FcmNotificationAdapter
├── imagegrouping/ # HttpImageGroupingAdapter, NoOpImageGroupingAdapter
├── jwt/ # JWT 토큰 발급/검증
├── liveactivity/ # Live Activity 외부 연동
├── loop/ # 룹 관련 외부 서비스
├── message/ # 메시지 서비스
├── poster/ # 포스터 생성 외부 연동
├── redis/ # LettuceRedisAdapter (CachePort 구현)
├── revenuecat/ # RevenueCat 구독 관리
├── segment/ # Segment 분석
├── sendbird/ # SendbirdChatAdapter
├── sms/ # NHN SMS 발송
├── sqs/ # SQS 메시지 발행 (Story큐, Grouping큐 Publisher 포함)
└── story/ # 리캡 외부 연동 (내부명: Story)허용 의존성: :application, :common
:adapter:web — HTTP 어댑터
Ktor 라우트, DTO, Controller/Handler를 정의합니다.
co.butbeautiful.truloop.adapter.web/
├── RouteRegistry.kt # 전체 라우트 등록 (진입점)
├── admin/ # Admin API (Google Workspace OIDC 인증)
├── dashboard/ # 관리자 대시보드 (Admin API)
├── appversion/
├── auth/
├── block/
├── chat/
├── common/ # 공통 웹 유틸리티
├── contact/
├── contenttemplate/
├── coverselection/
├── covertemplate/
├── device/
├── error/ # StatusPages 설정
├── eta/
├── health/
├── liveactivity/
├── loop/
├── loopcomment/
├── loopguestparticipant/ # 비회원 참여자 (내부명: GuestParticipant)
├── loopinvitation/
├── loopmedia/
├── loopparticipant/
├── mission/
├── monitoring/
├── notificationcenter/
├── profile/
├── report/
├── sampleloop/ # 샘플 룹 Admin API (라우트/컨트롤러/DTO)
├── secretary/
├── security/
├── shared/ # 공유 웹 유틸리티 (BasePath 플러그인 포함)
├── shortform/ # 숏폼 (미사용/폐기 예정)
├── story/ # 리캡 (내부명: Story)
├── user/
└── verification/허용 의존성: :application, :domain, :common
:bootstrap — 진입점
애플리케이션의 Composition Root입니다. 모든 모듈을 조합하고 실행합니다.
co.butbeautiful.truloop.bootstrap/
├── Application.kt # main() 진입점
├── appversion/
├── config/ # AppConfig + 19개 설정 로더
├── di/ # Koin 모듈 정의
├── event/ # EventBus, EventHandlerRegistry
│ └── handler/ # 도메인별 이벤트 핸들러
├── external/ # AWS 클라이언트 관리, SQS Consumer
├── health/
├── i18n/
├── logging/
├── monitoring/ # MetricsRegistry
├── plugins/ # 13개 Ktor 플러그인 설정
├── referral/
└── sentry/허용 의존성: 모든 모듈
DI 모듈 구성
Bootstrap에서 Koin에 등록하는 모듈 목록:
| Koin 모듈 | 역할 | 등록 방식 |
|---|---|---|
infrastructureModule | AppConfig, Database, EidGenerator, Json, Policy 등 싱글턴 | DSL |
externalServicesModule | JWT, S3, FCM, Sendbird 등 외부 어댑터 (조건부) | DSL |
persistenceModule | UnitOfWork, Health Check | DSL |
eventModule | EventBus, EventHandlerRegistry, EventPublisher | DSL |
PersistenceScanModule | Persistence Adapter 스캔 (@Single) | Annotation |
ApplicationScanModule | Use Case 스캔 (@Factory) — 27개 도메인별 하위 모듈 포함 | Annotation |
WebScanModule | Controller/Handler 스캔 (@Factory) | Annotation |
BootstrapEventHandlerScanModule | EventHandler 스캔 (@Single) | Annotation |
모듈 간 규칙 요약
위험
절대 위반 금지 규칙
- Domain 모듈에서 프레임워크 import 금지 (Ktor, Exposed, AWS SDK)
- Adapter에서 다른 Adapter 직접 참조 금지
- Route 파일에서
UseCase.execute()직접 호출 금지 (Controller/Handler를 통해야 함) - 순환 의존성 금지
변경 이력
| 날짜 | 내용 |
|---|---|
| 2026-03-16 | SampleLoop 모듈 추가 — domain, application(유스케이스 7개 + SampleLoopGuard), persistence(SampleLoopsTable), web(Admin API 5개 엔드포인트). Persistence Adapter 32→33개 |
| 2026-03-12 | 이미지 그룹핑 모듈 추가 — external에 imagegrouping 패키지, sqs에 GroupingJobPublisher, persistence/loopmedia에 Grouping/Representative Adapter 추가, Persistence Adapter 30→32개, External 패키지 18→19개 |
| 2026-03-11 | Dashboard 모듈 추가 (application, persistence, web), Persistence Adapter 29→30개 |
| 2026-03-10 | Domain에 shortform 추가, Web에 admin/shortform 추가, common에 config 설명 보완, shared/port 전체 목록 반영, application/shared 하위 구조 상세화, 외부 어댑터 18개 패키지로 수정, Bootstrap config loaders 19개/plugins 13개로 교정, DI 모듈에 BootstrapEventHandlerScanModule 추가 |