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