From 7813f934b9fb302f75686c6fc8db5c173275c287 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Jun 2025 14:24:26 +0900 Subject: [PATCH] modify: folder - java/python --- .idea/.gitignore | 5 + .idea/gradle.xml | 11 + .idea/misc.xml | 4 + .idea/vcs.xml | 6 + .../content/domain/model/Content.java | 114 ---- .gitignore => smarketing-java/.gitignore | 0 .../ai-recommend}/build.gradle | 0 .../AIRecommendServiceApplication.java | 0 .../service/MarketingTipService.java | 0 .../usecase/MarketingTipUseCase.java | 0 .../recommend/domain/model/MarketingTip.java | 0 .../recommend/domain/model/StoreData.java | 0 .../recommend/domain/model/TipId.java | 0 .../recommend/domain/model/WeatherData.java | 0 .../repository/MarketingTipRepository.java | 0 .../domain/service/AiTipGenerator.java | 0 .../domain/service/StoreDataProvider.java | 0 .../domain/service/WeatherDataProvider.java | 0 .../external/ClaudeAiTipGenerator.java | 0 .../external/StoreApiDataProvider.java | 0 .../external/WeatherApiDataProvider.java | 0 .../controller/RecommendationController.java | 0 .../dto/DetailedMarketingTipResponse.java | 0 .../presentation/dto/ErrorResponseDto.java | 0 .../dto/MarketingTipGenerationRequest.java | 0 .../presentation/dto/MarketingTipRequest.java | 0 .../dto/MarketingTipResponse.java | 0 .../presentation/dto/StoreInfoDto.java | 0 .../presentation/dto/WeatherInfoDto.java | 0 .../src/main/resources/application.yml | 0 build.gradle => smarketing-java/build.gradle | 0 .../common}/build.gradle | 0 .../smarketing/common/config/RedisConfig.java | 0 .../common/config/SecurityConfig.java | 0 .../common/config/SwaggerConfig.java | 0 .../smarketing/common/dto/ApiResponse.java | 0 .../smarketing/common/dto/PageResponse.java | 0 .../common/exception/BusinessException.java | 0 .../common/exception/ErrorCode.java | 0 .../exception/GlobalExceptionHandler.java | 0 .../security/JwtAuthenticationFilter.java | 0 .../common/security/JwtTokenProvider.java | 0 .../gradle}/wrapper/gradle-wrapper.jar | Bin .../gradle}/wrapper/gradle-wrapper.properties | 0 gradlew => smarketing-java/gradlew | 0 gradlew.bat => smarketing-java/gradlew.bat | 0 .../marketing-content}/build.gradle | 0 .../MarketingContentServiceApplication.java | 0 .../service/ContentQueryService.java | 15 +- .../service/PosterContentService.java | 0 .../service/SnsContentService.java | 6 +- .../usecase/ContentQueryUseCase.java | 0 .../usecase/PosterContentUseCase.java | 0 .../usecase/SnsContentUseCase.java | 0 .../content/domain/model/Content.java | 611 ++++++++++++++++++ .../content/domain/model/ContentId.java | 0 .../content/domain/model/ContentStatus.java | 0 .../content/domain/model/ContentType.java | 0 .../domain/model/CreationConditions.java | 0 .../content/domain/model/Platform.java | 0 .../domain/repository/ContentRepository.java | 0 .../domain/service/AiContentGenerator.java | 0 .../domain/service/AiPosterGenerator.java | 0 .../controller/ContentController.java | 0 .../dto/ContentDetailResponse.java | 86 +++ .../presentation/dto/ContentListRequest.java | 37 ++ .../dto/ContentRegenerateRequest.java | 33 + .../presentation/dto/ContentResponse.java | 361 +++++++++++ .../dto/ContentStatisticsResponse.java | 41 ++ .../dto/ContentUpdateRequest.java | 33 + .../dto/ContentUpdateResponse.java | 35 + .../dto/OngoingContentResponse.java | 47 ++ .../dto/PosterContentCreateRequest.java | 51 ++ .../dto/PosterContentCreateResponse.java | 41 ++ .../dto/PosterContentSaveRequest.java | 33 + .../dto/SnsContentCreateResponse.java | 380 +++++++++++ .../dto/SnsContentSaveRequest.java | 35 + .../src/main/resources/application.yml | 0 .../member}/build.gradle | 0 .../member/MemberServiceApplication.java | 0 .../smarketing/member/config/JpaConfig.java | 0 .../member/controller/AuthController.java | 0 .../member/controller/MemberController.java | 0 .../member/dto/DuplicateCheckResponse.java | 0 .../smarketing/member/dto/LoginRequest.java | 0 .../smarketing/member/dto/LoginResponse.java | 0 .../smarketing/member/dto/LogoutRequest.java | 0 .../member/dto/PasswordValidationRequest.java | 0 .../member/dto/RegisterRequest.java | 0 .../member/dto/TokenRefreshRequest.java | 0 .../smarketing/member/dto/TokenResponse.java | 0 .../member/dto/ValidationResponse.java | 0 .../won/smarketing/member/entity/Member.java | 0 .../member/repository/MemberRepository.java | 0 .../member/service/AuthService.java | 0 .../member/service/AuthServiceImpl.java | 0 .../member/service/MemberService.java | 0 .../member/service/MemberServiceImpl.java | 0 .../src/main/resources/application.yml | 0 .../settings.gradle | 0 {store => smarketing-java/store}/build.gradle | 0 .../store/StoreServiceApplication.java | 0 .../smarketing/store/config/JpaConfig.java | 0 .../store/controller/MenuController.java | 0 .../store/controller/SalesController.java | 0 .../store/controller/StoreController.java | 0 .../store/dto/MenuCreateRequest.java | 0 .../smarketing/store/dto/MenuResponse.java | 0 .../store/dto/MenuUpdateRequest.java | 0 .../smarketing/store/dto/SalesResponse.java | 0 .../store/dto/StoreCreateRequest.java | 0 .../smarketing/store/dto/StoreResponse.java | 0 .../store/dto/StoreUpdateRequest.java | 0 .../com/won/smarketing/store/entity/Menu.java | 0 .../won/smarketing/store/entity/Sales.java | 0 .../won/smarketing/store/entity/Store.java | 0 .../store/repository/MenuRepository.java | 0 .../store/repository/SalesRepository.java | 0 .../store/repository/StoreRepository.java | 0 .../smarketing/store/service/MenuService.java | 0 .../store/service/MenuServiceImpl.java | 0 .../store/service/SalesService.java | 0 .../store/service/SalesServiceImpl.java | 0 .../store/service/StoreService.java | 0 .../store/service/StoreServiceImpl.java | 0 .../store}/src/main/resources/application.yml | 0 126 files changed, 1856 insertions(+), 129 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml delete mode 100644 marketing-content/src/main/java/com/won/smarketing/content/domain/model/Content.java rename .gitignore => smarketing-java/.gitignore (100%) rename {ai-recommend => smarketing-java/ai-recommend}/build.gradle (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/AIRecommendServiceApplication.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/application/service/MarketingTipService.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/application/usecase/MarketingTipUseCase.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/domain/model/MarketingTip.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/domain/model/StoreData.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/domain/model/TipId.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/domain/model/WeatherData.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/domain/repository/MarketingTipRepository.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/domain/service/AiTipGenerator.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/domain/service/StoreDataProvider.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/domain/service/WeatherDataProvider.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/infrastructure/external/ClaudeAiTipGenerator.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/infrastructure/external/StoreApiDataProvider.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/infrastructure/external/WeatherApiDataProvider.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/presentation/controller/RecommendationController.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/presentation/dto/DetailedMarketingTipResponse.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/presentation/dto/ErrorResponseDto.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipGenerationRequest.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipRequest.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipResponse.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/presentation/dto/StoreInfoDto.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/java/com/won/smarketing/recommend/presentation/dto/WeatherInfoDto.java (100%) rename {ai-recommend => smarketing-java/ai-recommend}/src/main/resources/application.yml (100%) rename build.gradle => smarketing-java/build.gradle (100%) rename {common => smarketing-java/common}/build.gradle (100%) rename {common => smarketing-java/common}/src/main/java/com/won/smarketing/common/config/RedisConfig.java (100%) rename {common => smarketing-java/common}/src/main/java/com/won/smarketing/common/config/SecurityConfig.java (100%) rename {common => smarketing-java/common}/src/main/java/com/won/smarketing/common/config/SwaggerConfig.java (100%) rename {common => smarketing-java/common}/src/main/java/com/won/smarketing/common/dto/ApiResponse.java (100%) rename {common => smarketing-java/common}/src/main/java/com/won/smarketing/common/dto/PageResponse.java (100%) rename {common => smarketing-java/common}/src/main/java/com/won/smarketing/common/exception/BusinessException.java (100%) rename {common => smarketing-java/common}/src/main/java/com/won/smarketing/common/exception/ErrorCode.java (100%) rename {common => smarketing-java/common}/src/main/java/com/won/smarketing/common/exception/GlobalExceptionHandler.java (100%) rename {common => smarketing-java/common}/src/main/java/com/won/smarketing/common/security/JwtAuthenticationFilter.java (100%) rename {common => smarketing-java/common}/src/main/java/com/won/smarketing/common/security/JwtTokenProvider.java (100%) rename {gradle => smarketing-java/gradle}/wrapper/gradle-wrapper.jar (100%) rename {gradle => smarketing-java/gradle}/wrapper/gradle-wrapper.properties (100%) rename gradlew => smarketing-java/gradlew (100%) rename gradlew.bat => smarketing-java/gradlew.bat (100%) rename {marketing-content => smarketing-java/marketing-content}/build.gradle (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/MarketingContentServiceApplication.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/application/service/ContentQueryService.java (90%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/application/service/PosterContentService.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/application/service/SnsContentService.java (97%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/application/usecase/ContentQueryUseCase.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/application/usecase/PosterContentUseCase.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/application/usecase/SnsContentUseCase.java (100%) create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/Content.java rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/domain/model/ContentId.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/domain/model/ContentStatus.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/domain/model/ContentType.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/domain/model/CreationConditions.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/domain/model/Platform.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/domain/repository/ContentRepository.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/domain/service/AiContentGenerator.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/domain/service/AiPosterGenerator.java (100%) rename {marketing-content => smarketing-java/marketing-content}/src/main/java/com/won/smarketing/content/presentation/controller/ContentController.java (100%) create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentDetailResponse.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentListRequest.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentRegenerateRequest.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentResponse.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentStatisticsResponse.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentUpdateRequest.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentUpdateResponse.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/OngoingContentResponse.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentCreateRequest.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentCreateResponse.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentSaveRequest.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentCreateResponse.java create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentSaveRequest.java rename {marketing-content => smarketing-java/marketing-content}/src/main/resources/application.yml (100%) rename {member => smarketing-java/member}/build.gradle (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/MemberServiceApplication.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/config/JpaConfig.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/controller/AuthController.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/controller/MemberController.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/dto/DuplicateCheckResponse.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/dto/LoginRequest.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/dto/LoginResponse.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/dto/LogoutRequest.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/dto/PasswordValidationRequest.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/dto/RegisterRequest.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/dto/TokenRefreshRequest.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/dto/TokenResponse.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/dto/ValidationResponse.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/entity/Member.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/repository/MemberRepository.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/service/AuthService.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/service/AuthServiceImpl.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/service/MemberService.java (100%) rename {member => smarketing-java/member}/src/main/java/com/won/smarketing/member/service/MemberServiceImpl.java (100%) rename {member => smarketing-java/member}/src/main/resources/application.yml (100%) rename settings.gradle => smarketing-java/settings.gradle (100%) rename {store => smarketing-java/store}/build.gradle (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/StoreServiceApplication.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/config/JpaConfig.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/controller/MenuController.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/controller/SalesController.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/controller/StoreController.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/dto/MenuCreateRequest.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/dto/MenuResponse.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/dto/MenuUpdateRequest.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/dto/SalesResponse.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/dto/StoreCreateRequest.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/dto/StoreResponse.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/dto/StoreUpdateRequest.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/entity/Menu.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/entity/Sales.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/entity/Store.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/repository/MenuRepository.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/repository/SalesRepository.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/repository/StoreRepository.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/service/MenuService.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/service/MenuServiceImpl.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/service/SalesService.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/service/SalesServiceImpl.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/service/StoreService.java (100%) rename {store => smarketing-java/store}/src/main/java/com/won/smarketing/store/service/StoreServiceImpl.java (100%) rename {store => smarketing-java/store}/src/main/resources/application.yml (100%) diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b7b3d1b --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# 디폴트 무시된 파일 +/shelf/ +/workspace.xml +# 환경에 따라 달라지는 Maven 홈 디렉터리 +/mavenHomeManager.xml diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..9018a0d --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..6ed36dd --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/marketing-content/src/main/java/com/won/smarketing/content/domain/model/Content.java b/marketing-content/src/main/java/com/won/smarketing/content/domain/model/Content.java deleted file mode 100644 index 6eee928..0000000 --- a/marketing-content/src/main/java/com/won/smarketing/content/domain/model/Content.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.won.smarketing.content.domain.model; - -import lombok.*; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.List; - -/** - * 마케팅 콘텐츠 도메인 모델 - * 콘텐츠의 핵심 비즈니스 로직과 상태를 관리 - */ -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor -@Builder -public class Content { - - /** - * 콘텐츠 고유 식별자 - */ - private ContentId id; - - /** - * 콘텐츠 타입 (SNS 게시물, 포스터 등) - */ - private ContentType contentType; - - /** - * 플랫폼 (인스타그램, 네이버 블로그 등) - */ - private Platform platform; - - /** - * 콘텐츠 제목 - */ - private String title; - - /** - * 콘텐츠 내용 - */ - private String content; - - /** - * 해시태그 목록 - */ - private List hashtags; - - /** - * 이미지 URL 목록 - */ - private List images; - - /** - * 콘텐츠 상태 - */ - private ContentStatus status; - - /** - * 콘텐츠 생성 조건 - */ - private CreationConditions creationConditions; - - /** - * 매장 ID - */ - private Long storeId; - - /** - * 생성 시각 - */ - private LocalDateTime createdAt; - - /** - * 수정 시각 - */ - private LocalDateTime updatedAt; - - /** - * 콘텐츠 제목 업데이트 - * - * @param title 새로운 제목 - */ - public void updateTitle(String title) { - this.title = title; - this.updatedAt = LocalDateTime.now(); - } - - /** - * 콘텐츠 기간 업데이트 - * - * @param startDate 시작일 - * @param endDate 종료일 - */ - public void updatePeriod(LocalDate startDate, LocalDate endDate) { - if (this.creationConditions != null) { - this.creationConditions = this.creationConditions.toBuilder() - .startDate(startDate) - .endDate(endDate) - .build(); - } - this.updatedAt = LocalDateTime.now(); - } - - /** - * 콘텐츠 상태 변경 - * - * @param status 새로운 상태 - */ - public void changeStatus(ContentStatus status) { - this.status = status; - this.updatedAt = LocalDateTime.now(); - } -} diff --git a/.gitignore b/smarketing-java/.gitignore similarity index 100% rename from .gitignore rename to smarketing-java/.gitignore diff --git a/ai-recommend/build.gradle b/smarketing-java/ai-recommend/build.gradle similarity index 100% rename from ai-recommend/build.gradle rename to smarketing-java/ai-recommend/build.gradle diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/AIRecommendServiceApplication.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/AIRecommendServiceApplication.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/AIRecommendServiceApplication.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/AIRecommendServiceApplication.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/application/service/MarketingTipService.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/application/service/MarketingTipService.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/application/service/MarketingTipService.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/application/service/MarketingTipService.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/application/usecase/MarketingTipUseCase.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/application/usecase/MarketingTipUseCase.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/application/usecase/MarketingTipUseCase.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/application/usecase/MarketingTipUseCase.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/MarketingTip.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/MarketingTip.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/MarketingTip.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/MarketingTip.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/StoreData.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/StoreData.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/StoreData.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/StoreData.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/TipId.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/TipId.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/TipId.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/TipId.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/WeatherData.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/WeatherData.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/WeatherData.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/model/WeatherData.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/repository/MarketingTipRepository.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/repository/MarketingTipRepository.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/domain/repository/MarketingTipRepository.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/repository/MarketingTipRepository.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/AiTipGenerator.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/AiTipGenerator.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/AiTipGenerator.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/AiTipGenerator.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/StoreDataProvider.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/StoreDataProvider.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/StoreDataProvider.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/StoreDataProvider.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/WeatherDataProvider.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/WeatherDataProvider.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/WeatherDataProvider.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/domain/service/WeatherDataProvider.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/ClaudeAiTipGenerator.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/ClaudeAiTipGenerator.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/ClaudeAiTipGenerator.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/ClaudeAiTipGenerator.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/StoreApiDataProvider.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/StoreApiDataProvider.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/StoreApiDataProvider.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/StoreApiDataProvider.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/WeatherApiDataProvider.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/WeatherApiDataProvider.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/WeatherApiDataProvider.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/infrastructure/external/WeatherApiDataProvider.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/controller/RecommendationController.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/controller/RecommendationController.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/controller/RecommendationController.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/controller/RecommendationController.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/DetailedMarketingTipResponse.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/DetailedMarketingTipResponse.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/DetailedMarketingTipResponse.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/DetailedMarketingTipResponse.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/ErrorResponseDto.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/ErrorResponseDto.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/ErrorResponseDto.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/ErrorResponseDto.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipGenerationRequest.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipGenerationRequest.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipGenerationRequest.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipGenerationRequest.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipRequest.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipRequest.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipRequest.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipRequest.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipResponse.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipResponse.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipResponse.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/MarketingTipResponse.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/StoreInfoDto.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/StoreInfoDto.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/StoreInfoDto.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/StoreInfoDto.java diff --git a/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/WeatherInfoDto.java b/smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/WeatherInfoDto.java similarity index 100% rename from ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/WeatherInfoDto.java rename to smarketing-java/ai-recommend/src/main/java/com/won/smarketing/recommend/presentation/dto/WeatherInfoDto.java diff --git a/ai-recommend/src/main/resources/application.yml b/smarketing-java/ai-recommend/src/main/resources/application.yml similarity index 100% rename from ai-recommend/src/main/resources/application.yml rename to smarketing-java/ai-recommend/src/main/resources/application.yml diff --git a/build.gradle b/smarketing-java/build.gradle similarity index 100% rename from build.gradle rename to smarketing-java/build.gradle diff --git a/common/build.gradle b/smarketing-java/common/build.gradle similarity index 100% rename from common/build.gradle rename to smarketing-java/common/build.gradle diff --git a/common/src/main/java/com/won/smarketing/common/config/RedisConfig.java b/smarketing-java/common/src/main/java/com/won/smarketing/common/config/RedisConfig.java similarity index 100% rename from common/src/main/java/com/won/smarketing/common/config/RedisConfig.java rename to smarketing-java/common/src/main/java/com/won/smarketing/common/config/RedisConfig.java diff --git a/common/src/main/java/com/won/smarketing/common/config/SecurityConfig.java b/smarketing-java/common/src/main/java/com/won/smarketing/common/config/SecurityConfig.java similarity index 100% rename from common/src/main/java/com/won/smarketing/common/config/SecurityConfig.java rename to smarketing-java/common/src/main/java/com/won/smarketing/common/config/SecurityConfig.java diff --git a/common/src/main/java/com/won/smarketing/common/config/SwaggerConfig.java b/smarketing-java/common/src/main/java/com/won/smarketing/common/config/SwaggerConfig.java similarity index 100% rename from common/src/main/java/com/won/smarketing/common/config/SwaggerConfig.java rename to smarketing-java/common/src/main/java/com/won/smarketing/common/config/SwaggerConfig.java diff --git a/common/src/main/java/com/won/smarketing/common/dto/ApiResponse.java b/smarketing-java/common/src/main/java/com/won/smarketing/common/dto/ApiResponse.java similarity index 100% rename from common/src/main/java/com/won/smarketing/common/dto/ApiResponse.java rename to smarketing-java/common/src/main/java/com/won/smarketing/common/dto/ApiResponse.java diff --git a/common/src/main/java/com/won/smarketing/common/dto/PageResponse.java b/smarketing-java/common/src/main/java/com/won/smarketing/common/dto/PageResponse.java similarity index 100% rename from common/src/main/java/com/won/smarketing/common/dto/PageResponse.java rename to smarketing-java/common/src/main/java/com/won/smarketing/common/dto/PageResponse.java diff --git a/common/src/main/java/com/won/smarketing/common/exception/BusinessException.java b/smarketing-java/common/src/main/java/com/won/smarketing/common/exception/BusinessException.java similarity index 100% rename from common/src/main/java/com/won/smarketing/common/exception/BusinessException.java rename to smarketing-java/common/src/main/java/com/won/smarketing/common/exception/BusinessException.java diff --git a/common/src/main/java/com/won/smarketing/common/exception/ErrorCode.java b/smarketing-java/common/src/main/java/com/won/smarketing/common/exception/ErrorCode.java similarity index 100% rename from common/src/main/java/com/won/smarketing/common/exception/ErrorCode.java rename to smarketing-java/common/src/main/java/com/won/smarketing/common/exception/ErrorCode.java diff --git a/common/src/main/java/com/won/smarketing/common/exception/GlobalExceptionHandler.java b/smarketing-java/common/src/main/java/com/won/smarketing/common/exception/GlobalExceptionHandler.java similarity index 100% rename from common/src/main/java/com/won/smarketing/common/exception/GlobalExceptionHandler.java rename to smarketing-java/common/src/main/java/com/won/smarketing/common/exception/GlobalExceptionHandler.java diff --git a/common/src/main/java/com/won/smarketing/common/security/JwtAuthenticationFilter.java b/smarketing-java/common/src/main/java/com/won/smarketing/common/security/JwtAuthenticationFilter.java similarity index 100% rename from common/src/main/java/com/won/smarketing/common/security/JwtAuthenticationFilter.java rename to smarketing-java/common/src/main/java/com/won/smarketing/common/security/JwtAuthenticationFilter.java diff --git a/common/src/main/java/com/won/smarketing/common/security/JwtTokenProvider.java b/smarketing-java/common/src/main/java/com/won/smarketing/common/security/JwtTokenProvider.java similarity index 100% rename from common/src/main/java/com/won/smarketing/common/security/JwtTokenProvider.java rename to smarketing-java/common/src/main/java/com/won/smarketing/common/security/JwtTokenProvider.java diff --git a/gradle/wrapper/gradle-wrapper.jar b/smarketing-java/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from gradle/wrapper/gradle-wrapper.jar rename to smarketing-java/gradle/wrapper/gradle-wrapper.jar diff --git a/gradle/wrapper/gradle-wrapper.properties b/smarketing-java/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from gradle/wrapper/gradle-wrapper.properties rename to smarketing-java/gradle/wrapper/gradle-wrapper.properties diff --git a/gradlew b/smarketing-java/gradlew similarity index 100% rename from gradlew rename to smarketing-java/gradlew diff --git a/gradlew.bat b/smarketing-java/gradlew.bat similarity index 100% rename from gradlew.bat rename to smarketing-java/gradlew.bat diff --git a/marketing-content/build.gradle b/smarketing-java/marketing-content/build.gradle similarity index 100% rename from marketing-content/build.gradle rename to smarketing-java/marketing-content/build.gradle diff --git a/marketing-content/src/main/java/com/won/smarketing/content/MarketingContentServiceApplication.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/MarketingContentServiceApplication.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/MarketingContentServiceApplication.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/MarketingContentServiceApplication.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/application/service/ContentQueryService.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/service/ContentQueryService.java similarity index 90% rename from marketing-content/src/main/java/com/won/smarketing/content/application/service/ContentQueryService.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/service/ContentQueryService.java index eb868eb..a84e0a5 100644 --- a/marketing-content/src/main/java/com/won/smarketing/content/application/service/ContentQueryService.java +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/service/ContentQueryService.java @@ -3,11 +3,7 @@ package com.won.smarketing.content.application.service; import com.won.smarketing.common.exception.BusinessException; import com.won.smarketing.common.exception.ErrorCode; import com.won.smarketing.content.application.usecase.ContentQueryUseCase; -import com.won.smarketing.content.domain.model.Content; -import com.won.smarketing.content.domain.model.ContentId; -import com.won.smarketing.content.domain.model.ContentStatus; -import com.won.smarketing.content.domain.model.ContentType; -import com.won.smarketing.content.domain.model.Platform; +import com.won.smarketing.content.domain.model.*; import com.won.smarketing.content.domain.repository.ContentRepository; import com.won.smarketing.content.presentation.dto.*; import lombok.RequiredArgsConstructor; @@ -181,20 +177,15 @@ public class ContentQueryService implements ContentQueryUseCase { * @param conditions CreationConditions 도메인 객체 * @return CreationConditionsDto */ - private CreationConditionsDto toCreationConditionsDto(CreationConditions conditions) { + private ContentDetailResponse.CreationConditionsDto toCreationConditionsDto(CreationConditions conditions) { if (conditions == null) { return null; } - return CreationConditionsDto.builder() - .category(conditions.getCategory()) - .requirement(conditions.getRequirement()) + return ContentDetailResponse.CreationConditionsDto.builder() .toneAndManner(conditions.getToneAndManner()) .emotionIntensity(conditions.getEmotionIntensity()) .eventName(conditions.getEventName()) - .startDate(conditions.getStartDate()) - .endDate(conditions.getEndDate()) - .photoStyle(conditions.getPhotoStyle()) .build(); } } diff --git a/marketing-content/src/main/java/com/won/smarketing/content/application/service/PosterContentService.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/service/PosterContentService.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/application/service/PosterContentService.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/service/PosterContentService.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/application/service/SnsContentService.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/service/SnsContentService.java similarity index 97% rename from marketing-content/src/main/java/com/won/smarketing/content/application/service/SnsContentService.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/service/SnsContentService.java index 508fbe5..444be06 100644 --- a/marketing-content/src/main/java/com/won/smarketing/content/application/service/SnsContentService.java +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/service/SnsContentService.java @@ -33,13 +33,13 @@ public class SnsContentService implements SnsContentUseCase { /** * SNS 콘텐츠 생성 - * + * * @param request SNS 콘텐츠 생성 요청 * @return 생성된 SNS 콘텐츠 정보 */ @Override @Transactional - public SnsContentCreateResponse generateSnsContent(SnsContentCreateRequest request) { +/* public SnsContentCreateResponse generateSnsContent(SnsContentCreateRequest request) { // AI를 사용하여 SNS 콘텐츠 생성 String generatedContent = aiContentGenerator.generateSnsContent(request); @@ -84,7 +84,7 @@ public class SnsContentService implements SnsContentUseCase { .status(content.getStatus().name()) .createdAt(content.getCreatedAt()) .build(); - } + }*/ /** * SNS 콘텐츠 저장 diff --git a/marketing-content/src/main/java/com/won/smarketing/content/application/usecase/ContentQueryUseCase.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/usecase/ContentQueryUseCase.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/application/usecase/ContentQueryUseCase.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/usecase/ContentQueryUseCase.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/application/usecase/PosterContentUseCase.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/usecase/PosterContentUseCase.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/application/usecase/PosterContentUseCase.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/usecase/PosterContentUseCase.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/application/usecase/SnsContentUseCase.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/usecase/SnsContentUseCase.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/application/usecase/SnsContentUseCase.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/application/usecase/SnsContentUseCase.java diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/Content.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/Content.java new file mode 100644 index 0000000..440fd77 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/Content.java @@ -0,0 +1,611 @@ +// marketing-content/src/main/java/com/won/smarketing/content/domain/model/Content.java +package com.won.smarketing.content.domain.model; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + * 콘텐츠 도메인 모델 + * + * 이 클래스는 마케팅 콘텐츠의 핵심 정보와 비즈니스 로직을 포함하는 + * DDD(Domain-Driven Design) 엔티티입니다. + * + * Clean Architecture의 Domain Layer에 위치하며, + * 비즈니스 규칙과 도메인 로직을 캡슐화합니다. + */ +@Entity +@Table( + name = "contents", + indexes = { + @Index(name = "idx_store_id", columnList = "store_id"), + @Index(name = "idx_content_type", columnList = "content_type"), + @Index(name = "idx_platform", columnList = "platform"), + @Index(name = "idx_status", columnList = "status"), + @Index(name = "idx_promotion_dates", columnList = "promotion_start_date, promotion_end_date"), + @Index(name = "idx_created_at", columnList = "created_at") + } +) +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@EntityListeners(AuditingEntityListener.class) +public class Content { + + // ==================== 기본키 및 식별자 ==================== + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "content_id") + private Long id; + + // ==================== 콘텐츠 분류 ==================== + + @Enumerated(EnumType.STRING) + @Column(name = "content_type", nullable = false, length = 20) + private ContentType contentType; + + @Enumerated(EnumType.STRING) + @Column(name = "platform", nullable = false, length = 20) + private Platform platform; + + // ==================== 콘텐츠 내용 ==================== + + @Column(name = "title", nullable = false, length = 200) + private String title; + + @Column(name = "content", nullable = false, columnDefinition = "TEXT") + private String content; + + // ==================== 멀티미디어 및 메타데이터 ==================== + + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable( + name = "content_hashtags", + joinColumns = @JoinColumn(name = "content_id"), + indexes = @Index(name = "idx_content_hashtags", columnList = "content_id") + ) + @Column(name = "hashtag", length = 100) + @Builder.Default + private List hashtags = new ArrayList<>(); + + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable( + name = "content_images", + joinColumns = @JoinColumn(name = "content_id"), + indexes = @Index(name = "idx_content_images", columnList = "content_id") + ) + @Column(name = "image_url", length = 500) + @Builder.Default + private List images = new ArrayList<>(); + + // ==================== 상태 관리 ==================== + + @Enumerated(EnumType.STRING) + @Column(name = "status", nullable = false, length = 20) + @Builder.Default + private ContentStatus status = ContentStatus.DRAFT; + + // ==================== AI 생성 조건 (Embedded) ==================== + + @Embedded + @AttributeOverrides({ + @AttributeOverride(name = "toneAndManner", column = @Column(name = "tone_and_manner", length = 50)), + @AttributeOverride(name = "promotionType", column = @Column(name = "promotion_type", length = 50)), + @AttributeOverride(name = "emotionIntensity", column = @Column(name = "emotion_intensity", length = 50)), + @AttributeOverride(name = "targetAudience", column = @Column(name = "target_audience", length = 50)), + @AttributeOverride(name = "eventName", column = @Column(name = "event_name", length = 100)) + }) + private CreationConditions creationConditions; + + // ==================== 비즈니스 관계 ==================== + + @Column(name = "store_id", nullable = false) + private Long storeId; + + // ==================== 홍보 기간 ==================== + + @Column(name = "promotion_start_date") + private LocalDateTime promotionStartDate; + + @Column(name = "promotion_end_date") + private LocalDateTime promotionEndDate; + + // ==================== 감사(Audit) 정보 ==================== + + @CreatedDate + @Column(name = "created_at", nullable = false, updatable = false) + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + // ==================== 비즈니스 로직 메서드 ==================== + + /** + * 콘텐츠 제목 수정 + * + * 비즈니스 규칙: + * - 제목은 null이거나 빈 값일 수 없음 + * - 200자를 초과할 수 없음 + * - 발행된 콘텐츠는 제목 변경 시 상태가 DRAFT로 변경됨 + * + * @param title 새로운 제목 + * @throws IllegalArgumentException 제목이 유효하지 않은 경우 + */ + public void updateTitle(String title) { + validateTitle(title); + + boolean wasPublished = isPublished(); + this.title = title.trim(); + + // 발행된 콘텐츠의 제목이 변경되면 재검토 필요 + if (wasPublished) { + this.status = ContentStatus.DRAFT; + } + } + + /** + * 콘텐츠 내용 수정 + * + * 비즈니스 규칙: + * - 내용은 null이거나 빈 값일 수 없음 + * - 발행된 콘텐츠는 내용 변경 시 상태가 DRAFT로 변경됨 + * + * @param content 새로운 콘텐츠 내용 + * @throws IllegalArgumentException 내용이 유효하지 않은 경우 + */ + public void updateContent(String content) { + validateContent(content); + + boolean wasPublished = isPublished(); + this.content = content.trim(); + + // 발행된 콘텐츠의 내용이 변경되면 재검토 필요 + if (wasPublished) { + this.status = ContentStatus.DRAFT; + } + } + + /** + * 콘텐츠 상태 변경 + * + * 비즈니스 규칙: + * - PUBLISHED 상태로 변경시 유효성 검증 수행 + * - ARCHIVED 상태에서는 PUBLISHED로만 변경 가능 + * + * @param status 새로운 상태 + * @throws IllegalStateException 잘못된 상태 전환인 경우 + */ + public void changeStatus(ContentStatus status) { + validateStatusTransition(this.status, status); + + if (status == ContentStatus.PUBLISHED) { + validateForPublication(); + } + + this.status = status; + } + + /** + * 홍보 기간 설정 + * + * 비즈니스 규칙: + * - 시작일은 종료일보다 이전이어야 함 + * - 과거 날짜로 설정 불가 (현재 시간 기준) + * + * @param startDate 홍보 시작일 + * @param endDate 홍보 종료일 + * @throws IllegalArgumentException 날짜가 유효하지 않은 경우 + */ + public void setPromotionPeriod(LocalDateTime startDate, LocalDateTime endDate) { + validatePromotionPeriod(startDate, endDate); + + this.promotionStartDate = startDate; + this.promotionEndDate = endDate; + } + + /** + * 해시태그 추가 + * + * @param hashtag 추가할 해시태그 (# 없이) + */ + public void addHashtag(String hashtag) { + if (hashtag != null && !hashtag.trim().isEmpty()) { + String cleanHashtag = hashtag.trim().replace("#", ""); + if (!this.hashtags.contains(cleanHashtag)) { + this.hashtags.add(cleanHashtag); + } + } + } + + /** + * 해시태그 제거 + * + * @param hashtag 제거할 해시태그 + */ + public void removeHashtag(String hashtag) { + if (hashtag != null) { + String cleanHashtag = hashtag.trim().replace("#", ""); + this.hashtags.remove(cleanHashtag); + } + } + + /** + * 이미지 추가 + * + * @param imageUrl 이미지 URL + */ + public void addImage(String imageUrl) { + if (imageUrl != null && !imageUrl.trim().isEmpty()) { + if (!this.images.contains(imageUrl.trim())) { + this.images.add(imageUrl.trim()); + } + } + } + + /** + * 이미지 제거 + * + * @param imageUrl 제거할 이미지 URL + */ + public void removeImage(String imageUrl) { + if (imageUrl != null) { + this.images.remove(imageUrl.trim()); + } + } + + // ==================== 도메인 조회 메서드 ==================== + + /** + * 발행 상태 확인 + * + * @return 발행된 상태이면 true + */ + public boolean isPublished() { + return this.status == ContentStatus.PUBLISHED; + } + + /** + * 수정 가능 상태 확인 + * + * @return 임시저장 또는 예약발행 상태이면 true + */ + public boolean isEditable() { + return this.status == ContentStatus.DRAFT || this.status == ContentStatus.PUBLISHED; + } + + /** + * 현재 홍보 진행 중인지 확인 + * + * @return 홍보 기간 내이고 발행 상태이면 true + */ + public boolean isOngoingPromotion() { + if (!isPublished() || promotionStartDate == null || promotionEndDate == null) { + return false; + } + + LocalDateTime now = LocalDateTime.now(); + return now.isAfter(promotionStartDate) && now.isBefore(promotionEndDate); + } + + /** + * 홍보 예정 상태 확인 + * + * @return 홍보 시작 전이면 true + */ + public boolean isUpcomingPromotion() { + if (promotionStartDate == null) { + return false; + } + + return LocalDateTime.now().isBefore(promotionStartDate); + } + + /** + * 홍보 완료 상태 확인 + * + * @return 홍보 종료 후이면 true + */ + public boolean isCompletedPromotion() { + if (promotionEndDate == null) { + return false; + } + + return LocalDateTime.now().isAfter(promotionEndDate); + } + + /** + * SNS 콘텐츠 여부 확인 + * + * @return SNS 게시물이면 true + */ + public boolean isSnsContent() { + return this.contentType == ContentType.SNS_POST; + } + + /** + * 포스터 콘텐츠 여부 확인 + * + * @return 포스터이면 true + */ + public boolean isPosterContent() { + return this.contentType == ContentType.POSTER; + } + + /** + * 이미지가 있는 콘텐츠인지 확인 + * + * @return 이미지가 1개 이상 있으면 true + */ + public boolean hasImages() { + return this.images != null && !this.images.isEmpty(); + } + + /** + * 해시태그가 있는 콘텐츠인지 확인 + * + * @return 해시태그가 1개 이상 있으면 true + */ + public boolean hasHashtags() { + return this.hashtags != null && !this.hashtags.isEmpty(); + } + + // ==================== 유효성 검증 메서드 ==================== + + /** + * 제목 유효성 검증 + */ + private void validateTitle(String title) { + if (title == null || title.trim().isEmpty()) { + throw new IllegalArgumentException("제목은 필수 입력 사항입니다."); + } + if (title.trim().length() > 200) { + throw new IllegalArgumentException("제목은 200자를 초과할 수 없습니다."); + } + } + + /** + * 내용 유효성 검증 + */ + private void validateContent(String content) { + if (content == null || content.trim().isEmpty()) { + throw new IllegalArgumentException("콘텐츠 내용은 필수 입력 사항입니다."); + } + } + + /** + * 홍보 기간 유효성 검증 + */ + private void validatePromotionPeriod(LocalDateTime startDate, LocalDateTime endDate) { + if (startDate == null || endDate == null) { + throw new IllegalArgumentException("홍보 시작일과 종료일은 필수 입력 사항입니다."); + } + if (startDate.isAfter(endDate)) { + throw new IllegalArgumentException("홍보 시작일은 종료일보다 이전이어야 합니다."); + } + if (endDate.isBefore(LocalDateTime.now())) { + throw new IllegalArgumentException("홍보 종료일은 현재 시간 이후여야 합니다."); + } + } + + /** + * 상태 전환 유효성 검증 + */ + private void validateStatusTransition(ContentStatus from, ContentStatus to) { + if (from == ContentStatus.ARCHIVED && to != ContentStatus.PUBLISHED) { + throw new IllegalStateException("보관된 콘텐츠는 발행 상태로만 변경할 수 있습니다."); + } + } + + /** + * 발행을 위한 유효성 검증 + */ + private void validateForPublication() { + validateTitle(this.title); + validateContent(this.content); + + if (this.promotionStartDate == null || this.promotionEndDate == null) { + throw new IllegalStateException("발행하려면 홍보 기간을 설정해야 합니다."); + } + + if (this.contentType == ContentType.POSTER && !hasImages()) { + throw new IllegalStateException("포스터 콘텐츠는 이미지가 필수입니다."); + } + } + + // ==================== 비즈니스 계산 메서드 ==================== + + /** + * 홍보 진행률 계산 (0-100%) + * + * @return 진행률 + */ + public double calculateProgress() { + if (promotionStartDate == null || promotionEndDate == null) { + return 0.0; + } + + LocalDateTime now = LocalDateTime.now(); + + if (now.isBefore(promotionStartDate)) { + return 0.0; + } else if (now.isAfter(promotionEndDate)) { + return 100.0; + } + + long totalDuration = java.time.Duration.between(promotionStartDate, promotionEndDate).toHours(); + long elapsedDuration = java.time.Duration.between(promotionStartDate, now).toHours(); + + if (totalDuration == 0) { + return 100.0; + } + + return (double) elapsedDuration / totalDuration * 100.0; + } + + /** + * 남은 홍보 일수 계산 + * + * @return 남은 일수 (음수면 0) + */ + public long calculateRemainingDays() { + if (promotionEndDate == null) { + return 0L; + } + + LocalDateTime now = LocalDateTime.now(); + if (now.isAfter(promotionEndDate)) { + return 0L; + } + + return java.time.Duration.between(now, promotionEndDate).toDays(); + } + + // ==================== 팩토리 메서드 ==================== + + /** + * SNS 콘텐츠 생성 팩토리 메서드 + */ + public static Content createSnsContent(String title, String content, Platform platform, + Long storeId, CreationConditions conditions) { + Content snsContent = Content.builder() + .contentType(ContentType.SNS_POST) + .platform(platform) + .title(title) + .content(content) + .storeId(storeId) + .creationConditions(conditions) + .status(ContentStatus.DRAFT) + .hashtags(new ArrayList<>()) + .images(new ArrayList<>()) + .build(); + + // 유효성 검증 + snsContent.validateTitle(title); + snsContent.validateContent(content); + + return snsContent; + } + + /** + * 포스터 콘텐츠 생성 팩토리 메서드 + */ + public static Content createPosterContent(String title, String content, List images, + Long storeId, CreationConditions conditions) { + if (images == null || images.isEmpty()) { + throw new IllegalArgumentException("포스터 콘텐츠는 이미지가 필수입니다."); + } + + Content posterContent = Content.builder() + .contentType(ContentType.POSTER) + .platform(Platform.INSTAGRAM) // 기본값 + .title(title) + .content(content) + .storeId(storeId) + .creationConditions(conditions) + .status(ContentStatus.DRAFT) + .hashtags(new ArrayList<>()) + .images(new ArrayList<>(images)) + .build(); + + // 유효성 검증 + posterContent.validateTitle(title); + posterContent.validateContent(content); + + return posterContent; + } + + // ==================== Object 메서드 오버라이드 ==================== + + /** + * 비즈니스 키 기반 동등성 비교 + * JPA 엔티티에서는 ID가 아닌 비즈니스 키 사용 권장 + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + + Content content = (Content) obj; + return id != null && id.equals(content.id); + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } + + /** + * 디버깅용 toString (민감한 정보 제외) + */ + @Override + public String toString() { + return "Content{" + + "id=" + id + + ", contentType=" + contentType + + ", platform=" + platform + + ", title='" + title + '\'' + + ", status=" + status + + ", storeId=" + storeId + + ", promotionStartDate=" + promotionStartDate + + ", promotionEndDate=" + promotionEndDate + + ", createdAt=" + createdAt + + '}'; + } +} + +/* +==================== 데이터베이스 스키마 (참고용) ==================== + +CREATE TABLE contents ( + content_id BIGINT NOT NULL AUTO_INCREMENT, + content_type VARCHAR(20) NOT NULL, + platform VARCHAR(20) NOT NULL, + title VARCHAR(200) NOT NULL, + content TEXT NOT NULL, + status VARCHAR(20) NOT NULL DEFAULT 'DRAFT', + tone_and_manner VARCHAR(50), + promotion_type VARCHAR(50), + emotion_intensity VARCHAR(50), + target_audience VARCHAR(50), + event_name VARCHAR(100), + store_id BIGINT NOT NULL, + promotion_start_date DATETIME, + promotion_end_date DATETIME, + created_at DATETIME NOT NULL, + updated_at DATETIME, + PRIMARY KEY (content_id), + INDEX idx_store_id (store_id), + INDEX idx_content_type (content_type), + INDEX idx_platform (platform), + INDEX idx_status (status), + INDEX idx_promotion_dates (promotion_start_date, promotion_end_date), + INDEX idx_created_at (created_at) +); + +CREATE TABLE content_hashtags ( + content_id BIGINT NOT NULL, + hashtag VARCHAR(100) NOT NULL, + INDEX idx_content_hashtags (content_id), + FOREIGN KEY (content_id) REFERENCES contents(content_id) ON DELETE CASCADE +); + +CREATE TABLE content_images ( + content_id BIGINT NOT NULL, + image_url VARCHAR(500) NOT NULL, + INDEX idx_content_images (content_id), + FOREIGN KEY (content_id) REFERENCES contents(content_id) ON DELETE CASCADE +); +*/ \ No newline at end of file diff --git a/marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentId.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentId.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentId.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentId.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentStatus.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentStatus.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentStatus.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentStatus.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentType.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentType.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentType.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/ContentType.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/domain/model/CreationConditions.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/CreationConditions.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/domain/model/CreationConditions.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/CreationConditions.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/domain/model/Platform.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/Platform.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/domain/model/Platform.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/model/Platform.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/domain/repository/ContentRepository.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/repository/ContentRepository.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/domain/repository/ContentRepository.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/repository/ContentRepository.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/domain/service/AiContentGenerator.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/service/AiContentGenerator.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/domain/service/AiContentGenerator.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/service/AiContentGenerator.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/domain/service/AiPosterGenerator.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/service/AiPosterGenerator.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/domain/service/AiPosterGenerator.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/domain/service/AiPosterGenerator.java diff --git a/marketing-content/src/main/java/com/won/smarketing/content/presentation/controller/ContentController.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/controller/ContentController.java similarity index 100% rename from marketing-content/src/main/java/com/won/smarketing/content/presentation/controller/ContentController.java rename to smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/controller/ContentController.java diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentDetailResponse.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentDetailResponse.java new file mode 100644 index 0000000..7cc6a52 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentDetailResponse.java @@ -0,0 +1,86 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 콘텐츠 상세 응답 DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Schema(description = "콘텐츠 상세 응답") +public class ContentDetailResponse { + + @Schema(description = "콘텐츠 ID", example = "1") + private Long contentId; + + @Schema(description = "콘텐츠 타입", example = "SNS_POST") + private String contentType; + + @Schema(description = "플랫폼", example = "INSTAGRAM") + private String platform; + + @Schema(description = "제목", example = "맛있는 신메뉴를 소개합니다!") + private String title; + + @Schema(description = "콘텐츠 내용") + private String content; + + @Schema(description = "해시태그 목록") + private List hashtags; + + @Schema(description = "이미지 URL 목록") + private List images; + + @Schema(description = "상태", example = "PUBLISHED") + private String status; + + @Schema(description = "홍보 시작일") + private LocalDateTime promotionStartDate; + + @Schema(description = "홍보 종료일") + private LocalDateTime promotionEndDate; + + @Schema(description = "생성 조건") + private CreationConditionsDto creationConditions; + + @Schema(description = "생성일시") + private LocalDateTime createdAt; + + @Schema(description = "수정일시") + private LocalDateTime updatedAt; + + /** + * 생성 조건 내부 DTO + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + @Schema(description = "콘텐츠 생성 조건") + public static class CreationConditionsDto { + + @Schema(description = "톤앤매너", example = "친근함") + private String toneAndManner; + + @Schema(description = "프로모션 유형", example = "할인 정보") + private String promotionType; + + @Schema(description = "감정 강도", example = "보통") + private String emotionIntensity; + + @Schema(description = "홍보 대상", example = "메뉴") + private String targetAudience; + + @Schema(description = "이벤트명", example = "신메뉴 출시 이벤트") + private String eventName; + } +} \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentListRequest.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentListRequest.java new file mode 100644 index 0000000..8a35e35 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentListRequest.java @@ -0,0 +1,37 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 콘텐츠 목록 조회 요청 DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "콘텐츠 목록 조회 요청") +public class ContentListRequest { + + @Schema(description = "콘텐츠 타입", example = "SNS_POST") + private String contentType; + + @Schema(description = "플랫폼", example = "INSTAGRAM") + private String platform; + + @Schema(description = "조회 기간", example = "7days") + private String period; + + @Schema(description = "정렬 기준", example = "createdAt") + private String sortBy; + + @Schema(description = "정렬 방향", example = "DESC") + private String sortDirection; + + @Schema(description = "페이지 번호", example = "0") + private Integer page; + + @Schema(description = "페이지 크기", example = "20") + private Integer size; +} diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentRegenerateRequest.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentRegenerateRequest.java new file mode 100644 index 0000000..47060a0 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentRegenerateRequest.java @@ -0,0 +1,33 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 콘텐츠 재생성 요청 DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "콘텐츠 재생성 요청") +public class ContentRegenerateRequest { + + @Schema(description = "원본 콘텐츠 ID", example = "1", required = true) + @NotNull(message = "원본 콘텐츠 ID는 필수입니다") + private Long originalContentId; + + @Schema(description = "수정된 톤앤매너", example = "전문적") + private String toneAndManner; + + @Schema(description = "수정된 프로모션 유형", example = "신메뉴 알림") + private String promotionType; + + @Schema(description = "수정된 감정 강도", example = "열정적") + private String emotionIntensity; + + @Schema(description = "추가 요구사항", example = "더 감성적으로 작성해주세요") + private String additionalRequirements; +} diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentResponse.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentResponse.java new file mode 100644 index 0000000..c3ff5c3 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentResponse.java @@ -0,0 +1,361 @@ +// marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentResponse.java +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 콘텐츠 응답 DTO + * 콘텐츠 목록 조회 시 사용되는 기본 응답 DTO + * + * 이 클래스는 콘텐츠의 핵심 정보만을 포함하여 목록 조회 시 성능을 최적화합니다. + * 상세 정보가 필요한 경우 ContentDetailResponse를 사용합니다. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Schema(description = "콘텐츠 응답") +public class ContentResponse { + + // ==================== 기본 식별 정보 ==================== + + @Schema(description = "콘텐츠 ID", example = "1") + private Long contentId; + + @Schema(description = "콘텐츠 타입", example = "SNS_POST", + allowableValues = {"SNS_POST", "POSTER"}) + private String contentType; + + @Schema(description = "플랫폼", example = "INSTAGRAM", + allowableValues = {"INSTAGRAM", "NAVER_BLOG", "FACEBOOK", "KAKAO_STORY"}) + private String platform; + + // ==================== 콘텐츠 정보 ==================== + + @Schema(description = "제목", example = "맛있는 신메뉴를 소개합니다!") + private String title; + + @Schema(description = "콘텐츠 내용", example = "특별한 신메뉴가 출시되었습니다! 🍽️\n지금 바로 맛보세요!") + private String content; + + @Schema(description = "해시태그 목록", example = "[\"#맛집\", \"#신메뉴\", \"#추천\", \"#인스타그램\"]") + private List hashtags; + + @Schema(description = "이미지 URL 목록", + example = "[\"https://example.com/image1.jpg\", \"https://example.com/image2.jpg\"]") + private List images; + + // ==================== 상태 관리 ==================== + + @Schema(description = "상태", example = "PUBLISHED", + allowableValues = {"DRAFT", "PUBLISHED", "SCHEDULED", "ARCHIVED"}) + private String status; + + @Schema(description = "상태 표시명", example = "발행완료") + private String statusDisplay; + + // ==================== 홍보 기간 ==================== + + @Schema(description = "홍보 시작일", example = "2024-01-15T09:00:00") + private LocalDateTime promotionStartDate; + + @Schema(description = "홍보 종료일", example = "2024-01-22T23:59:59") + private LocalDateTime promotionEndDate; + + // ==================== 시간 정보 ==================== + + @Schema(description = "생성일시", example = "2024-01-15T10:30:00") + private LocalDateTime createdAt; + + @Schema(description = "수정일시", example = "2024-01-15T14:20:00") + private LocalDateTime updatedAt; + + // ==================== 계산된 필드들 ==================== + + @Schema(description = "홍보 진행 상태", example = "ONGOING", + allowableValues = {"UPCOMING", "ONGOING", "COMPLETED"}) + private String promotionStatus; + + @Schema(description = "남은 홍보 일수", example = "5") + private Long remainingDays; + + @Schema(description = "홍보 진행률 (%)", example = "60.5") + private Double progressPercentage; + + @Schema(description = "콘텐츠 요약 (첫 50자)", example = "특별한 신메뉴가 출시되었습니다! 지금 바로 맛보세요...") + private String contentSummary; + + @Schema(description = "이미지 개수", example = "3") + private Integer imageCount; + + @Schema(description = "해시태그 개수", example = "8") + private Integer hashtagCount; + + // ==================== 비즈니스 메서드 ==================== + + /** + * 콘텐츠 요약 생성 + * 콘텐츠가 길 경우 첫 50자만 표시하고 "..." 추가 + * + * @param content 원본 콘텐츠 + * @param maxLength 최대 길이 + * @return 요약된 콘텐츠 + */ + public static String createContentSummary(String content, int maxLength) { + if (content == null || content.length() <= maxLength) { + return content; + } + return content.substring(0, maxLength) + "..."; + } + + /** + * 홍보 상태 계산 + * 현재 시간과 홍보 기간을 비교하여 상태 결정 + * + * @param startDate 홍보 시작일 + * @param endDate 홍보 종료일 + * @return 홍보 상태 + */ + public static String calculatePromotionStatus(LocalDateTime startDate, LocalDateTime endDate) { + if (startDate == null || endDate == null) { + return "UNKNOWN"; + } + + LocalDateTime now = LocalDateTime.now(); + + if (now.isBefore(startDate)) { + return "UPCOMING"; // 홍보 예정 + } else if (now.isAfter(endDate)) { + return "COMPLETED"; // 홍보 완료 + } else { + return "ONGOING"; // 홍보 진행중 + } + } + + /** + * 남은 일수 계산 + * 홍보 종료일까지 남은 일수 계산 + * + * @param endDate 홍보 종료일 + * @return 남은 일수 (음수면 0 반환) + */ + public static Long calculateRemainingDays(LocalDateTime endDate) { + if (endDate == null) { + return 0L; + } + + LocalDateTime now = LocalDateTime.now(); + if (now.isAfter(endDate)) { + return 0L; + } + + return java.time.Duration.between(now, endDate).toDays(); + } + + /** + * 진행률 계산 + * 홍보 기간 대비 진행률 계산 (0-100%) + * + * @param startDate 홍보 시작일 + * @param endDate 홍보 종료일 + * @return 진행률 (0-100%) + */ + public static Double calculateProgressPercentage(LocalDateTime startDate, LocalDateTime endDate) { + if (startDate == null || endDate == null) { + return 0.0; + } + + LocalDateTime now = LocalDateTime.now(); + + if (now.isBefore(startDate)) { + return 0.0; // 아직 시작 안함 + } else if (now.isAfter(endDate)) { + return 100.0; // 완료 + } + + long totalDuration = java.time.Duration.between(startDate, endDate).toHours(); + long elapsedDuration = java.time.Duration.between(startDate, now).toHours(); + + if (totalDuration == 0) { + return 100.0; + } + + return (double) elapsedDuration / totalDuration * 100.0; + } + + /** + * 상태 표시명 변환 + * 영문 상태를 한글로 변환 + * + * @param status 영문 상태 + * @return 한글 상태명 + */ + public static String getStatusDisplay(String status) { + if (status == null) { + return "알 수 없음"; + } + + switch (status) { + case "DRAFT": + return "임시저장"; + case "PUBLISHED": + return "발행완료"; + case "SCHEDULED": + return "예약발행"; + case "ARCHIVED": + return "보관됨"; + default: + return status; + } + } + + // ==================== Builder 확장 메서드 ==================== + + /** + * 도메인 엔티티에서 ContentResponse 생성 + * 계산된 필드들을 자동으로 설정 + * + * @param content 콘텐츠 도메인 엔티티 + * @return ContentResponse + */ + public static ContentResponse fromDomain(com.won.smarketing.content.domain.model.Content content) { + ContentResponseBuilder builder = ContentResponse.builder() + .contentId(content.getId().getValue()) + .contentType(content.getContentType().name()) + .platform(content.getPlatform().name()) + .title(content.getTitle()) + .content(content.getContent()) + .hashtags(content.getHashtags()) + .images(content.getImages()) + .status(content.getStatus().name()) + .statusDisplay(getStatusDisplay(content.getStatus().name())) + .promotionStartDate(content.getPromotionStartDate()) + .promotionEndDate(content.getPromotionEndDate()) + .createdAt(content.getCreatedAt()) + .updatedAt(content.getUpdatedAt()); + + // 계산된 필드들 설정 + builder.contentSummary(createContentSummary(content.getContent(), 50)); + builder.imageCount(content.getImages() != null ? content.getImages().size() : 0); + builder.hashtagCount(content.getHashtags() != null ? content.getHashtags().size() : 0); + + // 홍보 관련 계산 필드들 + builder.promotionStatus(calculatePromotionStatus( + content.getPromotionStartDate(), + content.getPromotionEndDate())); + builder.remainingDays(calculateRemainingDays(content.getPromotionEndDate())); + builder.progressPercentage(calculateProgressPercentage( + content.getPromotionStartDate(), + content.getPromotionEndDate())); + + return builder.build(); + } + + // ==================== 유틸리티 메서드 ==================== + + /** + * 콘텐츠가 현재 활성 상태인지 확인 + * + * @return 홍보 기간 내이고 발행 상태면 true + */ + public boolean isActive() { + return "PUBLISHED".equals(status) && "ONGOING".equals(promotionStatus); + } + + /** + * 콘텐츠 수정 가능 여부 확인 + * + * @return 임시저장 상태이거나 예약발행 상태면 true + */ + public boolean isEditable() { + return "DRAFT".equals(status) || "SCHEDULED".equals(status); + } + + /** + * 이미지가 있는 콘텐츠인지 확인 + * + * @return 이미지가 1개 이상 있으면 true + */ + public boolean hasImages() { + return images != null && !images.isEmpty(); + } + + /** + * 해시태그가 있는 콘텐츠인지 확인 + * + * @return 해시태그가 1개 이상 있으면 true + */ + public boolean hasHashtags() { + return hashtags != null && !hashtags.isEmpty(); + } + + /** + * 디버깅용 toString (간소화된 정보만) + */ + @Override + public String toString() { + return "ContentResponse{" + + "contentId=" + contentId + + ", contentType='" + contentType + '\'' + + ", platform='" + platform + '\'' + + ", title='" + title + '\'' + + ", status='" + status + '\'' + + ", promotionStatus='" + promotionStatus + '\'' + + ", createdAt=" + createdAt + + '}'; + } +} + +/* +==================== 사용 예시 ==================== + +// 1. 도메인 엔티티에서 DTO 생성 +Content domainContent = contentRepository.findById(contentId); +ContentResponse response = ContentResponse.fromDomain(domainContent); + +// 2. 수동으로 빌더 사용 +ContentResponse response = ContentResponse.builder() + .contentId(1L) + .contentType("SNS_POST") + .platform("INSTAGRAM") + .title("맛있는 신메뉴") + .content("특별한 신메뉴가 출시되었습니다!") + .status("PUBLISHED") + .build(); + +// 3. 비즈니스 로직 활용 +boolean canEdit = response.isEditable(); +boolean isLive = response.isActive(); +String summary = response.getContentSummary(); + +==================== JSON 응답 예시 ==================== + +{ + "contentId": 1, + "contentType": "SNS_POST", + "platform": "INSTAGRAM", + "title": "맛있는 신메뉴를 소개합니다!", + "content": "특별한 신메뉴가 출시되었습니다! 🍽️\n지금 바로 맛보세요!", + "hashtags": ["#맛집", "#신메뉴", "#추천", "#인스타그램"], + "images": ["https://example.com/image1.jpg"], + "status": "PUBLISHED", + "statusDisplay": "발행완료", + "promotionStartDate": "2024-01-15T09:00:00", + "promotionEndDate": "2024-01-22T23:59:59", + "createdAt": "2024-01-15T10:30:00", + "updatedAt": "2024-01-15T14:20:00", + "promotionStatus": "ONGOING", + "remainingDays": 5, + "progressPercentage": 60.5, + "contentSummary": "특별한 신메뉴가 출시되었습니다! 지금 바로 맛보세요...", + "imageCount": 1, + "hashtagCount": 4 +} +*/ \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentStatisticsResponse.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentStatisticsResponse.java new file mode 100644 index 0000000..fed7dfa --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentStatisticsResponse.java @@ -0,0 +1,41 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +/** + * 콘텐츠 통계 응답 DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Schema(description = "콘텐츠 통계 응답") +public class ContentStatisticsResponse { + + @Schema(description = "총 콘텐츠 수", example = "150") + private Long totalContents; + + @Schema(description = "이번 달 생성된 콘텐츠 수", example = "25") + private Long thisMonthContents; + + @Schema(description = "발행된 콘텐츠 수", example = "120") + private Long publishedContents; + + @Schema(description = "임시저장된 콘텐츠 수", example = "30") + private Long draftContents; + + @Schema(description = "콘텐츠 타입별 통계") + private Map contentTypeStats; + + @Schema(description = "플랫폼별 통계") + private Map platformStats; + + @Schema(description = "월별 생성 통계 (최근 6개월)") + private Map monthlyStats; +} \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentUpdateRequest.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentUpdateRequest.java new file mode 100644 index 0000000..d550f0f --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentUpdateRequest.java @@ -0,0 +1,33 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * 콘텐츠 수정 요청 DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "콘텐츠 수정 요청") +public class ContentUpdateRequest { + + @Schema(description = "제목", example = "수정된 제목") + private String title; + + @Schema(description = "콘텐츠 내용") + private String content; + + @Schema(description = "홍보 시작일") + private LocalDateTime promotionStartDate; + + @Schema(description = "홍보 종료일") + private LocalDateTime promotionEndDate; + + @Schema(description = "상태", example = "PUBLISHED") + private String status; +} \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentUpdateResponse.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentUpdateResponse.java new file mode 100644 index 0000000..3296ee2 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/ContentUpdateResponse.java @@ -0,0 +1,35 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * 콘텐츠 수정 응답 DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Schema(description = "콘텐츠 수정 응답") +public class ContentUpdateResponse { + + @Schema(description = "콘텐츠 ID", example = "1") + private Long contentId; + + @Schema(description = "수정된 제목", example = "수정된 제목") + private String title; + + @Schema(description = "수정된 콘텐츠 내용") + private String content; + + @Schema(description = "상태", example = "PUBLISHED") + private String status; + + @Schema(description = "수정일시") + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/OngoingContentResponse.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/OngoingContentResponse.java new file mode 100644 index 0000000..047cb2d --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/OngoingContentResponse.java @@ -0,0 +1,47 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * 진행 중인 콘텐츠 응답 DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Schema(description = "진행 중인 콘텐츠 응답") +public class OngoingContentResponse { + + @Schema(description = "콘텐츠 ID", example = "1") + private Long contentId; + + @Schema(description = "콘텐츠 타입", example = "SNS_POST") + private String contentType; + + @Schema(description = "플랫폼", example = "INSTAGRAM") + private String platform; + + @Schema(description = "제목", example = "진행 중인 이벤트") + private String title; + + @Schema(description = "상태", example = "PUBLISHED") + private String status; + + @Schema(description = "홍보 시작일") + private LocalDateTime promotionStartDate; + + @Schema(description = "홍보 종료일") + private LocalDateTime promotionEndDate; + + @Schema(description = "남은 일수", example = "5") + private Long remainingDays; + + @Schema(description = "진행률 (%)", example = "60.5") + private Double progressPercentage; +} \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentCreateRequest.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentCreateRequest.java new file mode 100644 index 0000000..1e3a406 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentCreateRequest.java @@ -0,0 +1,51 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 포스터 콘텐츠 생성 요청 DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "포스터 콘텐츠 생성 요청") +public class PosterContentCreateRequest { + + @Schema(description = "홍보 대상", example = "메뉴", required = true) + @NotBlank(message = "홍보 대상은 필수입니다") + private String targetAudience; + + @Schema(description = "홍보 시작일", required = true) + @NotNull(message = "홍보 시작일은 필수입니다") + private LocalDateTime promotionStartDate; + + @Schema(description = "홍보 종료일", required = true) + @NotNull(message = "홍보 종료일은 필수입니다") + private LocalDateTime promotionEndDate; + + @Schema(description = "이벤트명 (이벤트 홍보시)", example = "신메뉴 출시 이벤트") + private String eventName; + + @Schema(description = "이미지 스타일", example = "모던") + private String imageStyle; + + @Schema(description = "프로모션 유형", example = "할인 정보") + private String promotionType; + + @Schema(description = "감정 강도", example = "보통") + private String emotionIntensity; + + @Schema(description = "업로드된 이미지 URL 목록", required = true) + @NotNull(message = "이미지는 1개 이상 필수입니다") + @Size(min = 1, message = "이미지는 1개 이상 업로드해야 합니다") + private List images; +} \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentCreateResponse.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentCreateResponse.java new file mode 100644 index 0000000..04bb601 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentCreateResponse.java @@ -0,0 +1,41 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 포스터 콘텐츠 생성 응답 DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Schema(description = "포스터 콘텐츠 생성 응답") +public class PosterContentCreateResponse { + + @Schema(description = "콘텐츠 ID", example = "1") + private Long contentId; + + @Schema(description = "생성된 포스터 제목", example = "특별 이벤트 안내") + private String title; + + @Schema(description = "생성된 포스터 텍스트 내용") + private String content; + + @Schema(description = "포스터 이미지 URL 목록") + private List posterImages; + + @Schema(description = "원본 이미지 URL 목록") + private List originalImages; + + @Schema(description = "이미지 스타일", example = "모던") + private String imageStyle; + + @Schema(description = "생성 상태", example = "DRAFT") + private String status; +} \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentSaveRequest.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentSaveRequest.java new file mode 100644 index 0000000..a7bd715 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentSaveRequest.java @@ -0,0 +1,33 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 포스터 콘텐츠 저장 요청 DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "포스터 콘텐츠 저장 요청") +public class PosterContentSaveRequest { + + @Schema(description = "콘텐츠 ID", example = "1", required = true) + @NotNull(message = "콘텐츠 ID는 필수입니다") + private Long contentId; + + @Schema(description = "최종 제목", example = "특별 이벤트 안내") + private String finalTitle; + + @Schema(description = "최종 콘텐츠 내용") + private String finalContent; + + @Schema(description = "선택된 포스터 이미지 URL") + private String selectedPosterImage; + + @Schema(description = "발행 상태", example = "PUBLISHED") + private String status; +} \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentCreateResponse.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentCreateResponse.java new file mode 100644 index 0000000..31a8435 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentCreateResponse.java @@ -0,0 +1,380 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * SNS 콘텐츠 생성 응답 DTO + * + * AI를 통해 SNS 콘텐츠를 생성한 후 클라이언트에게 반환되는 응답 정보입니다. + * 생성된 콘텐츠의 기본 정보와 함께 사용자가 추가 편집할 수 있는 정보를 포함합니다. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Schema(description = "SNS 콘텐츠 생성 응답") +public class SnsContentCreateResponse { + + // ==================== 기본 식별 정보 ==================== + + @Schema(description = "생성된 콘텐츠 ID", example = "1") + private Long contentId; + + @Schema(description = "콘텐츠 타입", example = "SNS_POST") + private String contentType; + + @Schema(description = "대상 플랫폼", example = "INSTAGRAM", + allowableValues = {"INSTAGRAM", "NAVER_BLOG", "FACEBOOK", "KAKAO_STORY"}) + private String platform; + + // ==================== AI 생성 콘텐츠 ==================== + + @Schema(description = "AI가 생성한 콘텐츠 제목", + example = "맛있는 신메뉴를 소개합니다! ✨") + private String title; + + @Schema(description = "AI가 생성한 콘텐츠 내용", + example = "안녕하세요! 😊\n\n특별한 신메뉴가 출시되었습니다!\n진짜 맛있어서 꼭 한번 드셔보세요 🍽️\n\n매장에서 기다리고 있을게요! 💫") + private String content; + + @Schema(description = "AI가 생성한 해시태그 목록", + example = "[\"맛집\", \"신메뉴\", \"추천\", \"인스타그램\", \"일상\", \"좋아요\", \"팔로우\", \"맛있어요\"]") + private List hashtags; + + // ==================== 플랫폼별 최적화 정보 ==================== + + @Schema(description = "플랫폼별 최적화된 콘텐츠 길이", example = "280") + private Integer contentLength; + + @Schema(description = "플랫폼별 권장 해시태그 개수", example = "8") + private Integer recommendedHashtagCount; + + @Schema(description = "플랫폼별 최대 해시태그 개수", example = "15") + private Integer maxHashtagCount; + + // ==================== 생성 조건 정보 ==================== + + @Schema(description = "콘텐츠 생성에 사용된 조건들") + private GenerationConditionsDto generationConditions; + + // ==================== 상태 및 메타데이터 ==================== + + @Schema(description = "생성 상태", example = "DRAFT", + allowableValues = {"DRAFT", "PUBLISHED", "SCHEDULED"}) + private String status; + + @Schema(description = "생성 일시", example = "2024-01-15T10:30:00") + private LocalDateTime createdAt; + + @Schema(description = "AI 모델 버전", example = "gpt-4-turbo") + private String aiModelVersion; + + @Schema(description = "생성 시간 (초)", example = "3.5") + private Double generationTimeSeconds; + + // ==================== 추가 정보 ==================== + + @Schema(description = "업로드된 원본 이미지 URL 목록") + private List originalImages; + + @Schema(description = "콘텐츠 품질 점수 (1-100)", example = "85") + private Integer qualityScore; + + @Schema(description = "예상 참여율 (%)", example = "12.5") + private Double expectedEngagementRate; + + @Schema(description = "콘텐츠 카테고리", example = "음식/메뉴소개") + private String category; + + // ==================== 편집 가능 여부 ==================== + + @Schema(description = "제목 편집 가능 여부", example = "true") + @Builder.Default + private Boolean titleEditable = true; + + @Schema(description = "내용 편집 가능 여부", example = "true") + @Builder.Default + private Boolean contentEditable = true; + + @Schema(description = "해시태그 편집 가능 여부", example = "true") + @Builder.Default + private Boolean hashtagsEditable = true; + + // ==================== 대안 콘텐츠 ==================== + + @Schema(description = "대안 제목 목록 (사용자 선택용)") + private List alternativeTitles; + + @Schema(description = "대안 해시태그 세트 목록") + private List> alternativeHashtagSets; + + // ==================== 내부 DTO 클래스 ==================== + + /** + * 콘텐츠 생성 조건 DTO + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + @Schema(description = "콘텐츠 생성 조건") + public static class GenerationConditionsDto { + + @Schema(description = "홍보 대상", example = "메뉴") + private String targetAudience; + + @Schema(description = "이벤트명", example = "신메뉴 출시 이벤트") + private String eventName; + + @Schema(description = "톤앤매너", example = "친근함") + private String toneAndManner; + + @Schema(description = "프로모션 유형", example = "할인 정보") + private String promotionType; + + @Schema(description = "감정 강도", example = "보통") + private String emotionIntensity; + + @Schema(description = "홍보 시작일", example = "2024-01-15T09:00:00") + private LocalDateTime promotionStartDate; + + @Schema(description = "홍보 종료일", example = "2024-01-22T23:59:59") + private LocalDateTime promotionEndDate; + } + + // ==================== 비즈니스 메서드 ==================== + + /** + * 플랫폼별 콘텐츠 최적화 여부 확인 + * + * @return 콘텐츠가 플랫폼 권장 사항을 만족하면 true + */ + public boolean isOptimizedForPlatform() { + if (content == null || hashtags == null) { + return false; + } + + // 플랫폼별 최적화 기준 + switch (platform.toUpperCase()) { + case "INSTAGRAM": + return content.length() <= 2200 && + hashtags.size() <= 15 && + hashtags.size() >= 5; + case "NAVER_BLOG": + return content.length() >= 300 && + hashtags.size() <= 10 && + hashtags.size() >= 3; + case "FACEBOOK": + return content.length() <= 500 && + hashtags.size() <= 5; + default: + return true; + } + } + + /** + * 고품질 콘텐츠 여부 확인 + * + * @return 품질 점수가 80점 이상이면 true + */ + public boolean isHighQuality() { + return qualityScore != null && qualityScore >= 80; + } + + /** + * 참여율 예상 등급 반환 + * + * @return 예상 참여율 등급 (HIGH, MEDIUM, LOW) + */ + public String getExpectedEngagementLevel() { + if (expectedEngagementRate == null) { + return "UNKNOWN"; + } + + if (expectedEngagementRate >= 15.0) { + return "HIGH"; + } else if (expectedEngagementRate >= 8.0) { + return "MEDIUM"; + } else { + return "LOW"; + } + } + + /** + * 해시태그를 문자열로 변환 (# 포함) + * + * @return #으로 시작하는 해시태그 문자열 + */ + public String getHashtagsAsString() { + if (hashtags == null || hashtags.isEmpty()) { + return ""; + } + + return hashtags.stream() + .map(tag -> "#" + tag) + .reduce((a, b) -> a + " " + b) + .orElse(""); + } + + /** + * 콘텐츠 요약 생성 + * + * @param maxLength 최대 길이 + * @return 요약된 콘텐츠 + */ + public String getContentSummary(int maxLength) { + if (content == null || content.length() <= maxLength) { + return content; + } + return content.substring(0, maxLength) + "..."; + } + + /** + * 플랫폼별 최적화 제안사항 반환 + * + * @return 최적화 제안사항 목록 + */ + public List getOptimizationSuggestions() { + List suggestions = new java.util.ArrayList<>(); + + if (!isOptimizedForPlatform()) { + switch (platform.toUpperCase()) { + case "INSTAGRAM": + if (content != null && content.length() > 2200) { + suggestions.add("콘텐츠 길이를 2200자 이하로 줄여주세요."); + } + if (hashtags != null && hashtags.size() > 15) { + suggestions.add("해시태그를 15개 이하로 줄여주세요."); + } + if (hashtags != null && hashtags.size() < 5) { + suggestions.add("해시태그를 5개 이상 추가해주세요."); + } + break; + case "NAVER_BLOG": + if (content != null && content.length() < 300) { + suggestions.add("블로그 포스팅을 위해 내용을 300자 이상으로 늘려주세요."); + } + if (hashtags != null && hashtags.size() > 10) { + suggestions.add("네이버 블로그는 해시태그를 10개 이하로 사용하는 것이 좋습니다."); + } + break; + case "FACEBOOK": + if (content != null && content.length() > 500) { + suggestions.add("페이스북에서는 500자 이하의 짧은 글이 더 효과적입니다."); + } + break; + } + } + + return suggestions; + } + + // ==================== 팩토리 메서드 ==================== + + /** + * 도메인 엔티티에서 SnsContentCreateResponse 생성 + * + * @param content 콘텐츠 도메인 엔티티 + * @param aiMetadata AI 생성 메타데이터 + * @return SnsContentCreateResponse + */ + public static SnsContentCreateResponse fromDomain( + com.won.smarketing.content.domain.model.Content content, + AiGenerationMetadata aiMetadata) { + + SnsContentCreateResponseBuilder builder = SnsContentCreateResponse.builder() + .contentId(content.getId()) + .contentType(content.getContentType().name()) + .platform(content.getPlatform().name()) + .title(content.getTitle()) + .content(content.getContent()) + .hashtags(content.getHashtags()) + .status(content.getStatus().name()) + .createdAt(content.getCreatedAt()) + .originalImages(content.getImages()); + + // 생성 조건 정보 설정 + if (content.getCreationConditions() != null) { + builder.generationConditions(GenerationConditionsDto.builder() + .targetAudience(content.getCreationConditions().getTargetAudience()) + .eventName(content.getCreationConditions().getEventName()) + .toneAndManner(content.getCreationConditions().getToneAndManner()) + .promotionType(content.getCreationConditions().getPromotionType()) + .emotionIntensity(content.getCreationConditions().getEmotionIntensity()) + .promotionStartDate(content.getPromotionStartDate()) + .promotionEndDate(content.getPromotionEndDate()) + .build()); + } + + // AI 메타데이터 설정 + if (aiMetadata != null) { + builder.aiModelVersion(aiMetadata.getModelVersion()) + .generationTimeSeconds(aiMetadata.getGenerationTime()) + .qualityScore(aiMetadata.getQualityScore()) + .expectedEngagementRate(aiMetadata.getExpectedEngagementRate()) + .alternativeTitles(aiMetadata.getAlternativeTitles()) + .alternativeHashtagSets(aiMetadata.getAlternativeHashtagSets()); + } + + // 플랫폼별 최적화 정보 설정 + SnsContentCreateResponse response = builder.build(); + response.setContentLength(response.getContent() != null ? response.getContent().length() : 0); + response.setRecommendedHashtagCount(getRecommendedHashtagCount(content.getPlatform().name())); + response.setMaxHashtagCount(getMaxHashtagCount(content.getPlatform().name())); + + return response; + } + + /** + * 플랫폼별 권장 해시태그 개수 반환 + */ + private static Integer getRecommendedHashtagCount(String platform) { + switch (platform.toUpperCase()) { + case "INSTAGRAM": return 8; + case "NAVER_BLOG": return 5; + case "FACEBOOK": return 3; + case "KAKAO_STORY": return 5; + default: return 5; + } + } + + /** + * 플랫폼별 최대 해시태그 개수 반환 + */ + private static Integer getMaxHashtagCount(String platform) { + switch (platform.toUpperCase()) { + case "INSTAGRAM": return 15; + case "NAVER_BLOG": return 10; + case "FACEBOOK": return 5; + case "KAKAO_STORY": return 8; + default: return 10; + } + } + + // ==================== AI 생성 메타데이터 DTO ==================== + + /** + * AI 생성 메타데이터 + * AI 생성 과정에서 나온 부가 정보들 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class AiGenerationMetadata { + private String modelVersion; + private Double generationTime; + private Integer qualityScore; + private Double expectedEngagementRate; + private List alternativeTitles; + private List> alternativeHashtagSets; + private String category; + } +} \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentSaveRequest.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentSaveRequest.java new file mode 100644 index 0000000..5b4a2c7 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentSaveRequest.java @@ -0,0 +1,35 @@ +package com.won.smarketing.content.presentation.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * SNS 콘텐츠 저장 요청 DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "SNS 콘텐츠 저장 요청") +public class SnsContentSaveRequest { + + @Schema(description = "콘텐츠 ID", example = "1", required = true) + @NotNull(message = "콘텐츠 ID는 필수입니다") + private Long contentId; + + @Schema(description = "최종 제목", example = "맛있는 신메뉴를 소개합니다!") + private String finalTitle; + + @Schema(description = "최종 콘텐츠 내용") + private String finalContent; + + @Schema(description = "발행 상태", example = "PUBLISHED") + private String status; +} \ No newline at end of file diff --git a/marketing-content/src/main/resources/application.yml b/smarketing-java/marketing-content/src/main/resources/application.yml similarity index 100% rename from marketing-content/src/main/resources/application.yml rename to smarketing-java/marketing-content/src/main/resources/application.yml diff --git a/member/build.gradle b/smarketing-java/member/build.gradle similarity index 100% rename from member/build.gradle rename to smarketing-java/member/build.gradle diff --git a/member/src/main/java/com/won/smarketing/member/MemberServiceApplication.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/MemberServiceApplication.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/MemberServiceApplication.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/MemberServiceApplication.java diff --git a/member/src/main/java/com/won/smarketing/member/config/JpaConfig.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/config/JpaConfig.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/config/JpaConfig.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/config/JpaConfig.java diff --git a/member/src/main/java/com/won/smarketing/member/controller/AuthController.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/controller/AuthController.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/controller/AuthController.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/controller/AuthController.java diff --git a/member/src/main/java/com/won/smarketing/member/controller/MemberController.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/controller/MemberController.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/controller/MemberController.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/controller/MemberController.java diff --git a/member/src/main/java/com/won/smarketing/member/dto/DuplicateCheckResponse.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/dto/DuplicateCheckResponse.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/dto/DuplicateCheckResponse.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/dto/DuplicateCheckResponse.java diff --git a/member/src/main/java/com/won/smarketing/member/dto/LoginRequest.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/dto/LoginRequest.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/dto/LoginRequest.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/dto/LoginRequest.java diff --git a/member/src/main/java/com/won/smarketing/member/dto/LoginResponse.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/dto/LoginResponse.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/dto/LoginResponse.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/dto/LoginResponse.java diff --git a/member/src/main/java/com/won/smarketing/member/dto/LogoutRequest.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/dto/LogoutRequest.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/dto/LogoutRequest.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/dto/LogoutRequest.java diff --git a/member/src/main/java/com/won/smarketing/member/dto/PasswordValidationRequest.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/dto/PasswordValidationRequest.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/dto/PasswordValidationRequest.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/dto/PasswordValidationRequest.java diff --git a/member/src/main/java/com/won/smarketing/member/dto/RegisterRequest.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/dto/RegisterRequest.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/dto/RegisterRequest.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/dto/RegisterRequest.java diff --git a/member/src/main/java/com/won/smarketing/member/dto/TokenRefreshRequest.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/dto/TokenRefreshRequest.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/dto/TokenRefreshRequest.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/dto/TokenRefreshRequest.java diff --git a/member/src/main/java/com/won/smarketing/member/dto/TokenResponse.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/dto/TokenResponse.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/dto/TokenResponse.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/dto/TokenResponse.java diff --git a/member/src/main/java/com/won/smarketing/member/dto/ValidationResponse.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/dto/ValidationResponse.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/dto/ValidationResponse.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/dto/ValidationResponse.java diff --git a/member/src/main/java/com/won/smarketing/member/entity/Member.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/entity/Member.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/entity/Member.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/entity/Member.java diff --git a/member/src/main/java/com/won/smarketing/member/repository/MemberRepository.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/repository/MemberRepository.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/repository/MemberRepository.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/repository/MemberRepository.java diff --git a/member/src/main/java/com/won/smarketing/member/service/AuthService.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/service/AuthService.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/service/AuthService.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/service/AuthService.java diff --git a/member/src/main/java/com/won/smarketing/member/service/AuthServiceImpl.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/service/AuthServiceImpl.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/service/AuthServiceImpl.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/service/AuthServiceImpl.java diff --git a/member/src/main/java/com/won/smarketing/member/service/MemberService.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/service/MemberService.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/service/MemberService.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/service/MemberService.java diff --git a/member/src/main/java/com/won/smarketing/member/service/MemberServiceImpl.java b/smarketing-java/member/src/main/java/com/won/smarketing/member/service/MemberServiceImpl.java similarity index 100% rename from member/src/main/java/com/won/smarketing/member/service/MemberServiceImpl.java rename to smarketing-java/member/src/main/java/com/won/smarketing/member/service/MemberServiceImpl.java diff --git a/member/src/main/resources/application.yml b/smarketing-java/member/src/main/resources/application.yml similarity index 100% rename from member/src/main/resources/application.yml rename to smarketing-java/member/src/main/resources/application.yml diff --git a/settings.gradle b/smarketing-java/settings.gradle similarity index 100% rename from settings.gradle rename to smarketing-java/settings.gradle diff --git a/store/build.gradle b/smarketing-java/store/build.gradle similarity index 100% rename from store/build.gradle rename to smarketing-java/store/build.gradle diff --git a/store/src/main/java/com/won/smarketing/store/StoreServiceApplication.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/StoreServiceApplication.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/StoreServiceApplication.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/StoreServiceApplication.java diff --git a/store/src/main/java/com/won/smarketing/store/config/JpaConfig.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/config/JpaConfig.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/config/JpaConfig.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/config/JpaConfig.java diff --git a/store/src/main/java/com/won/smarketing/store/controller/MenuController.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/controller/MenuController.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/controller/MenuController.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/controller/MenuController.java diff --git a/store/src/main/java/com/won/smarketing/store/controller/SalesController.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/controller/SalesController.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/controller/SalesController.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/controller/SalesController.java diff --git a/store/src/main/java/com/won/smarketing/store/controller/StoreController.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/controller/StoreController.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/controller/StoreController.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/controller/StoreController.java diff --git a/store/src/main/java/com/won/smarketing/store/dto/MenuCreateRequest.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/dto/MenuCreateRequest.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/dto/MenuCreateRequest.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/dto/MenuCreateRequest.java diff --git a/store/src/main/java/com/won/smarketing/store/dto/MenuResponse.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/dto/MenuResponse.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/dto/MenuResponse.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/dto/MenuResponse.java diff --git a/store/src/main/java/com/won/smarketing/store/dto/MenuUpdateRequest.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/dto/MenuUpdateRequest.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/dto/MenuUpdateRequest.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/dto/MenuUpdateRequest.java diff --git a/store/src/main/java/com/won/smarketing/store/dto/SalesResponse.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/dto/SalesResponse.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/dto/SalesResponse.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/dto/SalesResponse.java diff --git a/store/src/main/java/com/won/smarketing/store/dto/StoreCreateRequest.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/dto/StoreCreateRequest.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/dto/StoreCreateRequest.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/dto/StoreCreateRequest.java diff --git a/store/src/main/java/com/won/smarketing/store/dto/StoreResponse.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/dto/StoreResponse.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/dto/StoreResponse.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/dto/StoreResponse.java diff --git a/store/src/main/java/com/won/smarketing/store/dto/StoreUpdateRequest.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/dto/StoreUpdateRequest.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/dto/StoreUpdateRequest.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/dto/StoreUpdateRequest.java diff --git a/store/src/main/java/com/won/smarketing/store/entity/Menu.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/entity/Menu.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/entity/Menu.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/entity/Menu.java diff --git a/store/src/main/java/com/won/smarketing/store/entity/Sales.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/entity/Sales.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/entity/Sales.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/entity/Sales.java diff --git a/store/src/main/java/com/won/smarketing/store/entity/Store.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/entity/Store.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/entity/Store.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/entity/Store.java diff --git a/store/src/main/java/com/won/smarketing/store/repository/MenuRepository.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/repository/MenuRepository.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/repository/MenuRepository.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/repository/MenuRepository.java diff --git a/store/src/main/java/com/won/smarketing/store/repository/SalesRepository.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/repository/SalesRepository.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/repository/SalesRepository.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/repository/SalesRepository.java diff --git a/store/src/main/java/com/won/smarketing/store/repository/StoreRepository.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/repository/StoreRepository.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/repository/StoreRepository.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/repository/StoreRepository.java diff --git a/store/src/main/java/com/won/smarketing/store/service/MenuService.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/service/MenuService.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/service/MenuService.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/service/MenuService.java diff --git a/store/src/main/java/com/won/smarketing/store/service/MenuServiceImpl.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/service/MenuServiceImpl.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/service/MenuServiceImpl.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/service/MenuServiceImpl.java diff --git a/store/src/main/java/com/won/smarketing/store/service/SalesService.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/service/SalesService.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/service/SalesService.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/service/SalesService.java diff --git a/store/src/main/java/com/won/smarketing/store/service/SalesServiceImpl.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/service/SalesServiceImpl.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/service/SalesServiceImpl.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/service/SalesServiceImpl.java diff --git a/store/src/main/java/com/won/smarketing/store/service/StoreService.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/service/StoreService.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/service/StoreService.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/service/StoreService.java diff --git a/store/src/main/java/com/won/smarketing/store/service/StoreServiceImpl.java b/smarketing-java/store/src/main/java/com/won/smarketing/store/service/StoreServiceImpl.java similarity index 100% rename from store/src/main/java/com/won/smarketing/store/service/StoreServiceImpl.java rename to smarketing-java/store/src/main/java/com/won/smarketing/store/service/StoreServiceImpl.java diff --git a/store/src/main/resources/application.yml b/smarketing-java/store/src/main/resources/application.yml similarity index 100% rename from store/src/main/resources/application.yml rename to smarketing-java/store/src/main/resources/application.yml