# KT Event Marketing - Clean Architecture Package Structure ## 프로젝트 구조 개요 ``` kt-event-marketing/ ├── common/ # 공통 모듈 ├── user-service/ # 사용자 서비스 ├── event-service/ # 이벤트 서비스 ├── ai-service/ # AI 서비스 ├── content-service/ # 콘텐츠 서비스 ├── distribution-service/ # 배포 서비스 ├── participation-service/ # 참여 서비스 ├── analytics-service/ # 분석 서비스 ├── settings.gradle └── build.gradle ``` --- ## Common 모듈 패키지 구조 ``` common/ └── src/main/java/com/kt/event/common/ ├── dto/ │ ├── ApiResponse.java # 공통 API 응답 래퍼 │ ├── PageResponse.java # 페이지네이션 응답 │ └── ErrorResponse.java # 에러 응답 ├── exception/ │ ├── ErrorCode.java # 에러 코드 enum │ ├── BusinessException.java # 비즈니스 예외 │ ├── InfraException.java # 인프라 예외 │ └── GlobalExceptionHandler.java # 전역 예외 핸들러 ├── util/ │ ├── DateTimeUtil.java # 날짜/시간 유틸 │ ├── StringUtil.java # 문자열 유틸 │ ├── ValidationUtil.java # 유효성 검증 유틸 │ └── EncryptionUtil.java # 암호화 유틸 ├── security/ │ ├── UserPrincipal.java # 인증된 사용자 정보 │ ├── JwtTokenProvider.java # JWT 토큰 제공자 │ └── JwtAuthenticationFilter.java # JWT 인증 필터 └── entity/ └── BaseTimeEntity.java # 생성/수정 시간 base entity ``` --- ## User Service 패키지 구조 (Clean Architecture) ``` user-service/ └── src/main/java/com/kt/event/user/ ├── biz/ # Business Layer │ ├── domain/ # 도메인 모델 │ │ ├── User.java │ │ ├── Store.java │ │ └── BusinessVerification.java │ ├── usecase/ # Use Case 인터페이스 │ │ ├── in/ # Inbound Port (비즈니스 로직 진입점) │ │ │ ├── RegisterUserUseCase.java │ │ │ ├── LoginUserUseCase.java │ │ │ ├── LogoutUserUseCase.java │ │ │ ├── GetUserProfileUseCase.java │ │ │ ├── UpdateUserProfileUseCase.java │ │ │ ├── ChangePasswordUseCase.java │ │ │ └── GetStoreInfoUseCase.java │ │ └── out/ # Outbound Port (외부 의존성 인터페이스) │ │ ├── UserReader.java │ │ ├── UserWriter.java │ │ ├── StoreReader.java │ │ ├── StoreWriter.java │ │ ├── RedisSessionWriter.java │ │ └── BusinessVerifier.java │ ├── service/ # Use Case 구현체 │ │ ├── UserService.java │ │ ├── AuthenticationService.java │ │ └── ProfileService.java │ └── dto/ # 비즈니스 DTO │ ├── UserCommand.java │ ├── UserInfo.java │ └── StoreInfo.java └── infra/ # Infrastructure Layer ├── UserApplication.java # Spring Boot Main ├── controller/ # REST API Controller (Inbound Adapter) │ ├── UserController.java │ └── AuthController.java ├── dto/ # API Request/Response DTO │ ├── request/ │ │ ├── UserRegisterRequest.java │ │ ├── UserLoginRequest.java │ │ ├── UserProfileUpdateRequest.java │ │ └── ChangePasswordRequest.java │ └── response/ │ ├── UserProfileResponse.java │ ├── StoreInfoResponse.java │ └── LoginResponse.java ├── gateway/ # Outbound Adapter │ ├── entity/ # JPA Entity │ │ ├── UserEntity.java │ │ └── StoreEntity.java │ ├── repository/ # JPA Repository │ │ ├── UserJpaRepository.java │ │ └── StoreJpaRepository.java │ ├── UserGateway.java # User Reader/Writer 구현 │ ├── StoreGateway.java # Store Reader/Writer 구현 │ ├── RedisSessionGateway.java # Redis Session 구현 │ └── BusinessVerifierGateway.java # 사업자번호 검증 구현 └── config/ # 설정 ├── SecurityConfig.java ├── RedisConfig.java ├── SwaggerConfig.java └── DataLoader.java ``` --- ## Event Service 패키지 구조 (Clean Architecture) ``` event-service/ └── src/main/java/com/kt/event/event/ ├── biz/ │ ├── domain/ │ │ ├── Event.java │ │ ├── EventObjective.java │ │ ├── EventStatus.java │ │ ├── AIRecommendation.java │ │ ├── Image.java │ │ ├── DistributionChannel.java │ │ └── Job.java │ ├── usecase/ │ │ ├── in/ │ │ │ ├── CreateEventObjectiveUseCase.java │ │ │ ├── RequestAIRecommendationUseCase.java │ │ │ ├── SelectAIRecommendationUseCase.java │ │ │ ├── RequestImageGenerationUseCase.java │ │ │ ├── SelectImageUseCase.java │ │ │ ├── EditImageUseCase.java │ │ │ ├── SelectDistributionChannelsUseCase.java │ │ │ ├── PublishEventUseCase.java │ │ │ ├── GetEventListUseCase.java │ │ │ ├── GetEventDetailUseCase.java │ │ │ ├── UpdateEventUseCase.java │ │ │ ├── DeleteEventUseCase.java │ │ │ ├── EndEventUseCase.java │ │ │ └── GetJobStatusUseCase.java │ │ └── out/ │ │ ├── EventReader.java │ │ ├── EventWriter.java │ │ ├── JobReader.java │ │ ├── JobWriter.java │ │ ├── KafkaJobPublisher.java │ │ ├── KafkaEventPublisher.java │ │ ├── RedisAIDataReader.java │ │ ├── RedisImageDataReader.java │ │ └── DistributionServiceCaller.java │ ├── service/ │ │ ├── EventCreationService.java │ │ ├── EventManagementService.java │ │ ├── AIRecommendationService.java │ │ ├── ImageGenerationService.java │ │ ├── DistributionService.java │ │ └── JobStatusService.java │ └── dto/ │ ├── EventCommand.java │ ├── EventInfo.java │ ├── AIRecommendationInfo.java │ ├── ImageInfo.java │ ├── ChannelInfo.java │ └── JobInfo.java └── infra/ ├── EventApplication.java ├── controller/ │ ├── EventController.java │ ├── EventCreationController.java │ └── JobController.java ├── dto/ │ ├── request/ │ │ ├── EventObjectiveRequest.java │ │ ├── AIRecommendationSelectionRequest.java │ │ ├── ImageSelectionRequest.java │ │ ├── ImageEditRequest.java │ │ ├── ChannelSelectionRequest.java │ │ └── EventUpdateRequest.java │ └── response/ │ ├── EventResponse.java │ ├── EventListResponse.java │ ├── JobStatusResponse.java │ └── PublishResponse.java ├── gateway/ │ ├── entity/ │ │ ├── EventEntity.java │ │ ├── AIRecommendationEntity.java │ │ ├── ImageEntity.java │ │ ├── DistributionChannelEntity.java │ │ └── JobEntity.java │ ├── repository/ │ │ ├── EventJpaRepository.java │ │ ├── AIRecommendationJpaRepository.java │ │ ├── ImageJpaRepository.java │ │ ├── DistributionChannelJpaRepository.java │ │ └── JobJpaRepository.java │ ├── EventGateway.java │ ├── JobGateway.java │ ├── KafkaProducerGateway.java │ ├── RedisGateway.java │ └── DistributionServiceGateway.java └── config/ ├── SecurityConfig.java ├── KafkaProducerConfig.java ├── RedisConfig.java ├── SwaggerConfig.java └── FeignConfig.java ``` --- ## AI Service 패키지 구조 (Clean Architecture) ``` ai-service/ └── src/main/java/com/kt/event/ai/ ├── biz/ │ ├── domain/ │ │ ├── AIRecommendation.java │ │ ├── TrendAnalysis.java │ │ ├── EventRecommendation.java │ │ └── Job.java │ ├── usecase/ │ │ ├── in/ │ │ │ ├── GenerateAIRecommendationUseCase.java │ │ │ ├── GetJobStatusUseCase.java │ │ │ └── GetRecommendationResultUseCase.java │ │ └── out/ │ │ ├── JobReader.java │ │ ├── JobWriter.java │ │ ├── RedisResultWriter.java │ │ ├── RedisResultReader.java │ │ ├── TrendAnalyzer.java │ │ └── AIModelCaller.java │ ├── service/ │ │ ├── AIRecommendationService.java │ │ ├── TrendAnalysisService.java │ │ └── JobManagementService.java │ └── dto/ │ ├── AICommand.java │ ├── AIResult.java │ ├── TrendInfo.java │ └── JobInfo.java └── infra/ ├── AIApplication.java ├── controller/ │ └── InternalAIController.java ├── dto/ │ ├── request/ │ │ └── AIRequestDto.java │ └── response/ │ ├── AIRecommendationResponse.java │ ├── JobStatusResponse.java │ └── TrendAnalysisResponse.java ├── gateway/ │ ├── entity/ │ │ └── JobEntity.java │ ├── repository/ │ │ └── JobJpaRepository.java │ ├── JobGateway.java │ ├── RedisGateway.java │ ├── TrendAnalyzerGateway.java │ └── ClaudeAPIGateway.java ├── consumer/ │ └── AIJobConsumer.java └── config/ ├── SecurityConfig.java ├── KafkaConsumerConfig.java ├── RedisConfig.java ├── SwaggerConfig.java └── ClaudeAPIConfig.java ``` --- ## Content Service 패키지 구조 (Clean Architecture) ``` content-service/ └── src/main/java/com/kt/event/content/ ├── biz/ │ ├── domain/ │ │ ├── Content.java │ │ ├── GeneratedImage.java │ │ ├── ImageStyle.java │ │ ├── Platform.java │ │ └── Job.java │ ├── usecase/ │ │ ├── in/ │ │ │ ├── GenerateImagesUseCase.java │ │ │ ├── GetJobStatusUseCase.java │ │ │ ├── GetEventContentUseCase.java │ │ │ ├── GetImageListUseCase.java │ │ │ ├── GetImageDetailUseCase.java │ │ │ └── RegenerateImageUseCase.java │ │ └── out/ │ │ ├── ContentReader.java │ │ ├── ContentWriter.java │ │ ├── JobReader.java │ │ ├── JobWriter.java │ │ ├── RedisAIDataReader.java │ │ ├── RedisImageWriter.java │ │ ├── ImageGeneratorCaller.java │ │ └── CDNUploader.java │ ├── service/ │ │ ├── ImageGenerationService.java │ │ ├── ContentManagementService.java │ │ └── JobManagementService.java │ └── dto/ │ ├── ContentCommand.java │ ├── ContentInfo.java │ ├── ImageInfo.java │ └── JobInfo.java └── infra/ ├── ContentApplication.java ├── controller/ │ └── ContentController.java ├── dto/ │ ├── request/ │ │ ├── ImageGenerationRequest.java │ │ └── RegenerateRequest.java │ └── response/ │ ├── ContentResponse.java │ ├── ImageResponse.java │ └── JobStatusResponse.java ├── gateway/ │ ├── entity/ │ │ ├── ContentEntity.java │ │ ├── GeneratedImageEntity.java │ │ └── JobEntity.java │ ├── repository/ │ │ ├── ContentJpaRepository.java │ │ ├── GeneratedImageJpaRepository.java │ │ └── JobJpaRepository.java │ ├── ContentGateway.java │ ├── JobGateway.java │ ├── RedisGateway.java │ ├── StableDiffusionGateway.java │ └── AzureBlobStorageGateway.java ├── consumer/ │ └── ImageGenerationJobConsumer.java └── config/ ├── SecurityConfig.java ├── KafkaConsumerConfig.java ├── RedisConfig.java ├── SwaggerConfig.java └── AzureStorageConfig.java ``` --- ## Distribution Service 패키지 구조 (Clean Architecture) ``` distribution-service/ └── src/main/java/com/kt/event/distribution/ ├── biz/ │ ├── domain/ │ │ ├── Distribution.java │ │ ├── DistributionChannel.java │ │ ├── ChannelResult.java │ │ └── DistributionStatus.java │ ├── usecase/ │ │ ├── in/ │ │ │ ├── DistributeToChannelsUseCase.java │ │ │ └── GetDistributionStatusUseCase.java │ │ └── out/ │ │ ├── DistributionReader.java │ │ ├── DistributionWriter.java │ │ ├── ChannelDistributor.java │ │ └── KafkaEventPublisher.java │ ├── service/ │ │ ├── DistributionService.java │ │ └── ChannelService.java │ └── dto/ │ ├── DistributionCommand.java │ ├── DistributionInfo.java │ └── ChannelInfo.java └── infra/ ├── DistributionApplication.java ├── controller/ │ └── DistributionController.java ├── dto/ │ ├── request/ │ │ └── DistributionRequest.java │ └── response/ │ ├── DistributionResponse.java │ └── DistributionStatusResponse.java ├── gateway/ │ ├── entity/ │ │ ├── DistributionEntity.java │ │ └── ChannelResultEntity.java │ ├── repository/ │ │ ├── DistributionJpaRepository.java │ │ └── ChannelResultJpaRepository.java │ ├── DistributionGateway.java │ ├── KafkaProducerGateway.java │ └── channel/ │ ├── UriDongneTVGateway.java │ ├── RingoBizGateway.java │ ├── GenieTVGateway.java │ ├── InstagramGateway.java │ ├── NaverBlogGateway.java │ └── KakaoChannelGateway.java └── config/ ├── SecurityConfig.java ├── KafkaProducerConfig.java ├── SwaggerConfig.java ├── ResilienceConfig.java └── FeignConfig.java ``` --- ## Participation Service 패키지 구조 (Clean Architecture) ``` participation-service/ └── src/main/java/com/kt/event/participation/ ├── biz/ │ ├── domain/ │ │ ├── Participant.java │ │ ├── Winner.java │ │ ├── DrawResult.java │ │ └── Consent.java │ ├── usecase/ │ │ ├── in/ │ │ │ ├── ParticipateEventUseCase.java │ │ │ ├── GetParticipantListUseCase.java │ │ │ ├── GetParticipantDetailUseCase.java │ │ │ ├── DrawWinnersUseCase.java │ │ │ └── GetWinnerListUseCase.java │ │ └── out/ │ │ ├── ParticipantReader.java │ │ ├── ParticipantWriter.java │ │ ├── WinnerReader.java │ │ ├── WinnerWriter.java │ │ ├── DrawExecutor.java │ │ └── KafkaEventPublisher.java │ ├── service/ │ │ ├── ParticipationService.java │ │ └── WinnerDrawService.java │ └── dto/ │ ├── ParticipationCommand.java │ ├── ParticipantInfo.java │ ├── WinnerInfo.java │ └── DrawCommand.java └── infra/ ├── ParticipationApplication.java ├── controller/ │ └── ParticipationController.java ├── dto/ │ ├── request/ │ │ ├── ParticipationRequest.java │ │ └── WinnerDrawRequest.java │ └── response/ │ ├── ParticipationResponse.java │ ├── ParticipantListResponse.java │ └── WinnerResponse.java ├── gateway/ │ ├── entity/ │ │ ├── ParticipantEntity.java │ │ └── WinnerEntity.java │ ├── repository/ │ │ ├── ParticipantJpaRepository.java │ │ └── WinnerJpaRepository.java │ ├── ParticipantGateway.java │ ├── WinnerGateway.java │ ├── DrawExecutorGateway.java │ └── KafkaProducerGateway.java └── config/ ├── SecurityConfig.java ├── KafkaProducerConfig.java └── SwaggerConfig.java ``` --- ## Analytics Service 패키지 구조 (Clean Architecture) ``` analytics-service/ └── src/main/java/com/kt/event/analytics/ ├── biz/ │ ├── domain/ │ │ ├── EventAnalytics.java │ │ ├── ChannelPerformance.java │ │ ├── TimelineData.java │ │ ├── RoiDetail.java │ │ └── ParticipantProfile.java │ ├── usecase/ │ │ ├── in/ │ │ │ ├── GetAnalyticsDashboardUseCase.java │ │ │ ├── GetChannelPerformanceUseCase.java │ │ │ ├── GetTimelineDataUseCase.java │ │ │ └── GetRoiDetailUseCase.java │ │ └── out/ │ │ ├── AnalyticsReader.java │ │ ├── AnalyticsWriter.java │ │ ├── ExternalAPIDataCollector.java │ │ └── RedisAnalyticsCache.java │ ├── service/ │ │ ├── AnalyticsDashboardService.java │ │ ├── PerformanceAnalysisService.java │ │ └── RoiCalculationService.java │ └── dto/ │ ├── AnalyticsCommand.java │ ├── AnalyticsInfo.java │ ├── PerformanceInfo.java │ └── RoiInfo.java └── infra/ ├── AnalyticsApplication.java ├── controller/ │ └── AnalyticsController.java ├── dto/ │ └── response/ │ ├── AnalyticsDashboardResponse.java │ ├── ChannelPerformanceResponse.java │ ├── TimelineDataResponse.java │ └── RoiDetailResponse.java ├── gateway/ │ ├── entity/ │ │ ├── EventAnalyticsEntity.java │ │ ├── ChannelPerformanceEntity.java │ │ └── TimelineDataEntity.java │ ├── repository/ │ │ ├── EventAnalyticsJpaRepository.java │ │ ├── ChannelPerformanceJpaRepository.java │ │ └── TimelineDataJpaRepository.java │ ├── AnalyticsGateway.java │ ├── RedisGateway.java │ └── external/ │ ├── UriDongneTVAPIGateway.java │ ├── GenieTVAPIGateway.java │ ├── InstagramAPIGateway.java │ ├── NaverAPIGateway.java │ └── KakaoAPIGateway.java ├── consumer/ │ └── AnalyticsEventConsumer.java └── config/ ├── SecurityConfig.java ├── KafkaConsumerConfig.java ├── RedisConfig.java ├── SwaggerConfig.java ├── ResilienceConfig.java └── FeignConfig.java ``` --- ## 아키텍처 설명 ### Clean Architecture 레이어 구조 1. **biz (Business Layer)** - 비즈니스 로직 - `domain/`: 핵심 도메인 모델 (순수 Java 객체, 외부 의존성 없음) - `usecase/in/`: Inbound Port (비즈니스 로직 진입점 인터페이스) - `usecase/out/`: Outbound Port (외부 의존성 인터페이스) - `service/`: Use Case 구현체 (비즈니스 로직 실행) - `dto/`: 비즈니스 레이어 내부 DTO 2. **infra (Infrastructure Layer)** - 외부 세계와의 통신 - `controller/`: REST API Controller (Inbound Adapter) - `dto/request/`, `dto/response/`: API 계약 DTO - `gateway/`: Outbound Adapter (DB, 외부 API, Kafka, Redis 등) - `gateway/entity/`: JPA Entity - `gateway/repository/`: JPA Repository - `consumer/`: Kafka Consumer - `config/`: 설정 클래스 ### 의존성 규칙 - **biz → infra**: ❌ 불가능 (비즈니스 로직은 인프라에 의존하지 않음) - **infra → biz**: ✅ 가능 (인프라는 비즈니스 인터페이스를 구현) - **domain → 외부**: ❌ 불가능 (순수 비즈니스 로직만 포함) ### 네이밍 규칙 - **UseCase 인터페이스**: `{동작}{대상}UseCase` (예: `RegisterUserUseCase`) - **Service 구현체**: `{대상}Service` (예: `UserService`) - **Gateway 구현체**: `{대상}Gateway` (예: `UserGateway`) - **Port 인터페이스**: `{대상}{동작}` (예: `UserReader`, `UserWriter`) --- ## 기술 스택 정리 | 레이어 | 기술 | |--------|------| | Framework | Spring Boot 3.3.0, Java 21 | | Database | PostgreSQL (각 서비스별 독립 DB) | | Cache | Redis (공통) | | Message Queue | Kafka (비동기 Job 처리, Event 발행) | | Security | JWT, Spring Security | | API Documentation | Swagger UI (SpringDoc OpenAPI) | | Persistence | Spring Data JPA | | Build Tool | Gradle 8.x | --- **작성일**: 2025-10-23 **작성자**: Backend Developer (리액트킹)