From c5a7254ce51e645c37867c19ccaae8d68b02c27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=84=9C=EC=9D=80?= <61147083+BangSun98@users.noreply.github.com> Date: Wed, 11 Jun 2025 16:30:30 +0900 Subject: [PATCH] update marketing-content update marketing-content --- .../marketing-content/build.gradle | 2 +- .../service/ContentQueryService.java | 22 +-- .../service/PosterContentService.java | 4 +- .../service/SnsContentService.java | 6 +- .../content/domain/model/Content.java | 18 ++ .../domain/model/CreationConditions.java | 10 ++ .../controller/ContentController.java | 2 +- .../presentation/dto/ContentResponse.java | 5 +- .../dto/PosterContentCreateRequest.java | 28 +++ .../dto/PosterContentCreateResponse.java | 12 +- .../dto/PosterContentSaveRequest.java | 43 ++++- .../dto/SnsContentCreateRequest.java | 160 ++++++++++++++++++ .../dto/SnsContentCreateResponse.java | 3 + .../dto/SnsContentSaveRequest.java | 44 +++++ .../src/main/resources/application.yml | 17 +- smarketing-java/member/build.gradle | 3 +- 16 files changed, 341 insertions(+), 38 deletions(-) create mode 100644 smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentCreateRequest.java diff --git a/smarketing-java/marketing-content/build.gradle b/smarketing-java/marketing-content/build.gradle index 771a2fc..188d7bd 100644 --- a/smarketing-java/marketing-content/build.gradle +++ b/smarketing-java/marketing-content/build.gradle @@ -1,4 +1,4 @@ dependencies { implementation project(':common') - runtimeOnly 'com.mysql:mysql-connector-j' + runtimeOnly 'org.postgresql:postgresql' } \ No newline at end of file diff --git a/smarketing-java/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 index a84e0a5..c196e58 100644 --- a/smarketing-java/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 @@ -40,18 +40,18 @@ public class ContentQueryService implements ContentQueryUseCase { // 제목과 기간 업데이트 content.updateTitle(request.getTitle()); - content.updatePeriod(request.getStartDate(), request.getEndDate()); + content.updatePeriod(request.getPromotionStartDate(), request.getPromotionEndDate()); Content updatedContent = contentRepository.save(content); return ContentUpdateResponse.builder() - .contentId(updatedContent.getId().getValue()) - .contentType(updatedContent.getContentType().name()) - .platform(updatedContent.getPlatform().name()) + .contentId(updatedContent.getId()) + //.contentType(updatedContent.getContentType().name()) + //.platform(updatedContent.getPlatform().name()) .title(updatedContent.getTitle()) .content(updatedContent.getContent()) - .hashtags(updatedContent.getHashtags()) - .images(updatedContent.getImages()) + //.hashtags(updatedContent.getHashtags()) + //.images(updatedContent.getImages()) .status(updatedContent.getStatus().name()) .updatedAt(updatedContent.getUpdatedAt()) .build(); @@ -105,7 +105,7 @@ public class ContentQueryService implements ContentQueryUseCase { .orElseThrow(() -> new BusinessException(ErrorCode.CONTENT_NOT_FOUND)); return ContentDetailResponse.builder() - .contentId(content.getId().getValue()) + .contentId(content.getId()) .contentType(content.getContentType().name()) .platform(content.getPlatform().name()) .title(content.getTitle()) @@ -140,7 +140,7 @@ public class ContentQueryService implements ContentQueryUseCase { */ private ContentResponse toContentResponse(Content content) { return ContentResponse.builder() - .contentId(content.getId().getValue()) + .contentId(content.getId()) .contentType(content.getContentType().name()) .platform(content.getPlatform().name()) .title(content.getTitle()) @@ -161,13 +161,13 @@ public class ContentQueryService implements ContentQueryUseCase { */ private OngoingContentResponse toOngoingContentResponse(Content content) { return OngoingContentResponse.builder() - .contentId(content.getId().getValue()) + .contentId(content.getId()) .contentType(content.getContentType().name()) .platform(content.getPlatform().name()) .title(content.getTitle()) .status(content.getStatus().name()) - .createdAt(content.getCreatedAt()) - .viewCount(0) // TODO: 실제 조회 수 구현 필요 + .promotionStartDate(content.getPromotionStartDate()) + //.viewCount(0) // TODO: 실제 조회 수 구현 필요 .build(); } diff --git a/smarketing-java/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 index c444d75..4db4d8a 100644 --- a/smarketing-java/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 @@ -61,10 +61,10 @@ public class PosterContentService implements PosterContentUseCase { .contentId(null) // 임시 생성이므로 ID 없음 .contentType(ContentType.POSTER.name()) .title(request.getTitle()) - .image(generatedPoster) + .posterImage(generatedPoster) .posterSizes(posterSizes) .status(ContentStatus.DRAFT.name()) - .createdAt(LocalDateTime.now()) + //.createdAt(LocalDateTime.now()) .build(); } diff --git a/smarketing-java/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 index 444be06..fec5d4e 100644 --- a/smarketing-java/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 @@ -39,7 +39,7 @@ public class SnsContentService implements SnsContentUseCase { */ @Override @Transactional -/* public SnsContentCreateResponse generateSnsContent(SnsContentCreateRequest request) { + public SnsContentCreateResponse generateSnsContent(SnsContentCreateRequest request) { // AI를 사용하여 SNS 콘텐츠 생성 String generatedContent = aiContentGenerator.generateSnsContent(request); @@ -80,11 +80,11 @@ public class SnsContentService implements SnsContentUseCase { .title(content.getTitle()) .content(content.getContent()) .hashtags(content.getHashtags()) - .images(content.getImages()) + .fixedImages(content.getImages()) .status(content.getStatus().name()) .createdAt(content.getCreatedAt()) .build(); - }*/ + } /** * SNS 콘텐츠 저장 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 index 440fd77..c83f178 100644 --- 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 @@ -216,6 +216,24 @@ public class Content { this.promotionEndDate = endDate; } + /** + * 홍보 기간 설정 + * + * 비즈니스 규칙: + * - 시작일은 종료일보다 이전이어야 함 + * - 과거 날짜로 설정 불가 (현재 시간 기준) + * + * @param startDate 홍보 시작일 + * @param endDate 홍보 종료일 + * @throws IllegalArgumentException 날짜가 유효하지 않은 경우 + */ + public void updatePeriod(LocalDateTime startDate, LocalDateTime endDate) { + validatePromotionPeriod(startDate, endDate); + + this.promotionStartDate = startDate; + this.promotionEndDate = endDate; + } + /** * 해시태그 추가 * diff --git a/smarketing-java/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 index b76a152..cf3c04e 100644 --- a/smarketing-java/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 @@ -53,4 +53,14 @@ public class CreationConditions { * 사진 스타일 (포스터용) */ private String photoStyle; + + /** + * 타겟 고객 + */ + private String targetAudience; + + /** + * 프로모션 타입 + */ + private String promotionType; } diff --git a/smarketing-java/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 index e65842a..4feb6b7 100644 --- a/smarketing-java/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 @@ -12,7 +12,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.util.List; /** 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 index c3ff5c3..964f4a2 100644 --- 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 @@ -98,6 +98,9 @@ public class ContentResponse { @Schema(description = "해시태그 개수", example = "8") private Integer hashtagCount; + @Schema(description = "조회수", example = "8") + private Integer viewCount; + // ==================== 비즈니스 메서드 ==================== /** @@ -227,7 +230,7 @@ public class ContentResponse { */ public static ContentResponse fromDomain(com.won.smarketing.content.domain.model.Content content) { ContentResponseBuilder builder = ContentResponse.builder() - .contentId(content.getId().getValue()) + .contentId(content.getId()) .contentType(content.getContentType().name()) .platform(content.getPlatform().name()) .title(content.getTitle()) 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 index 1e3a406..3ea3a15 100644 --- 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 @@ -1,3 +1,4 @@ +// smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentCreateRequest.java package com.won.smarketing.content.presentation.dto; import io.swagger.v3.oas.annotations.media.Schema; @@ -8,6 +9,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; @@ -20,6 +22,13 @@ import java.util.List; @Schema(description = "포스터 콘텐츠 생성 요청") public class PosterContentCreateRequest { + @Schema(description = "매장 ID", example = "1", required = true) + @NotNull(message = "매장 ID는 필수입니다") + private Long storeId; + + @Schema(description = "제목", example = "특별 이벤트 안내") + private String title; + @Schema(description = "홍보 대상", example = "메뉴", required = true) @NotBlank(message = "홍보 대상은 필수입니다") private String targetAudience; @@ -48,4 +57,23 @@ public class PosterContentCreateRequest { @NotNull(message = "이미지는 1개 이상 필수입니다") @Size(min = 1, message = "이미지는 1개 이상 업로드해야 합니다") private List images; + + // CreationConditions에 필요한 필드들 + @Schema(description = "콘텐츠 카테고리", example = "이벤트") + private String category; + + @Schema(description = "구체적인 요구사항", example = "신메뉴 출시 이벤트 포스터를 만들어주세요") + private String requirement; + + @Schema(description = "톤앤매너", example = "전문적") + private String toneAndManner; + + @Schema(description = "이벤트 시작일", example = "2024-01-15") + private LocalDate startDate; + + @Schema(description = "이벤트 종료일", example = "2024-01-31") + private LocalDate endDate; + + @Schema(description = "사진 스타일", example = "밝고 화사한") + private String photoStyle; } \ 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 index 04bb601..0c02b68 100644 --- 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 @@ -7,6 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; +import java.util.Map; /** * 포스터 콘텐츠 생성 응답 DTO @@ -27,8 +28,11 @@ public class PosterContentCreateResponse { @Schema(description = "생성된 포스터 텍스트 내용") private String content; - @Schema(description = "포스터 이미지 URL 목록") - private List posterImages; + @Schema(description = "생성된 포스터 타입") + private String contentType; + + @Schema(description = "포스터 이미지 URL") + private String posterImage; @Schema(description = "원본 이미지 URL 목록") private List originalImages; @@ -38,4 +42,8 @@ public class PosterContentCreateResponse { @Schema(description = "생성 상태", example = "DRAFT") private String status; + + @Schema(description = "포스터사이즈", example = "800x600") + private Map posterSizes; + } \ 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 index a7bd715..5335d11 100644 --- 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 @@ -1,3 +1,4 @@ +// smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/PosterContentSaveRequest.java package com.won.smarketing.content.presentation.dto; import io.swagger.v3.oas.annotations.media.Schema; @@ -6,6 +7,9 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import java.time.LocalDate; +import java.util.List; + /** * 포스터 콘텐츠 저장 요청 DTO */ @@ -19,15 +23,44 @@ public class PosterContentSaveRequest { @NotNull(message = "콘텐츠 ID는 필수입니다") private Long contentId; - @Schema(description = "최종 제목", example = "특별 이벤트 안내") - private String finalTitle; + @Schema(description = "매장 ID", example = "1", required = true) + @NotNull(message = "매장 ID는 필수입니다") + private Long storeId; - @Schema(description = "최종 콘텐츠 내용") - private String finalContent; + @Schema(description = "제목", example = "특별 이벤트 안내") + private String title; + + @Schema(description = "콘텐츠 내용") + private String content; @Schema(description = "선택된 포스터 이미지 URL") - private String selectedPosterImage; + private List images; @Schema(description = "발행 상태", example = "PUBLISHED") private String status; + + // CreationConditions에 필요한 필드들 + @Schema(description = "콘텐츠 카테고리", example = "이벤트") + private String category; + + @Schema(description = "구체적인 요구사항", example = "신메뉴 출시 이벤트 포스터를 만들어주세요") + private String requirement; + + @Schema(description = "톤앤매너", example = "전문적") + private String toneAndManner; + + @Schema(description = "감정 강도", example = "보통") + private String emotionIntensity; + + @Schema(description = "이벤트명", example = "신메뉴 출시 이벤트") + private String eventName; + + @Schema(description = "이벤트 시작일", example = "2024-01-15") + private LocalDate startDate; + + @Schema(description = "이벤트 종료일", example = "2024-01-31") + private LocalDate endDate; + + @Schema(description = "사진 스타일", example = "밝고 화사한") + private String photoStyle; } \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentCreateRequest.java b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentCreateRequest.java new file mode 100644 index 0000000..70235b5 --- /dev/null +++ b/smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentCreateRequest.java @@ -0,0 +1,160 @@ +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.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; +import java.util.List; + +/** + * SNS 콘텐츠 생성 요청 DTO + * + * AI 기반 SNS 콘텐츠 생성을 위한 요청 정보를 담고 있습니다. + * 사용자가 입력한 생성 조건을 바탕으로 AI가 적절한 SNS 콘텐츠를 생성합니다. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Schema(description = "SNS 콘텐츠 생성 요청") +public class SnsContentCreateRequest { + + // ==================== 기본 정보 ==================== + + @Schema(description = "매장 ID", example = "1", required = true) + @NotNull(message = "매장 ID는 필수입니다") + private Long storeId; + + @Schema(description = "대상 플랫폼", + example = "INSTAGRAM", + allowableValues = {"INSTAGRAM", "NAVER_BLOG", "FACEBOOK", "KAKAO_STORY"}, + required = true) + @NotBlank(message = "플랫폼은 필수입니다") + private String platform; + + @Schema(description = "콘텐츠 제목", example = "1", required = true) + @NotNull(message = "콘텐츠 제목은 필수입니다") + private String title; + + // ==================== 콘텐츠 생성 조건 ==================== + + @Schema(description = "콘텐츠 카테고리", + example = "메뉴소개", + allowableValues = {"메뉴소개", "이벤트", "일상", "인테리어", "고객후기", "기타"}) + private String category; + + @Schema(description = "구체적인 요구사항 또는 홍보하고 싶은 내용", + example = "새로 출시된 시그니처 버거를 홍보하고 싶어요") + @Size(max = 500, message = "요구사항은 500자 이하로 입력해주세요") + private String requirement; + + @Schema(description = "톤앤매너", + example = "친근함", + allowableValues = {"친근함", "전문적", "유머러스", "감성적", "트렌디"}) + private String toneAndManner; + + @Schema(description = "감정 강도", + example = "보통", + allowableValues = {"약함", "보통", "강함"}) + private String emotionIntensity; + + // ==================== 이벤트 정보 ==================== + + @Schema(description = "이벤트명 (이벤트 콘텐츠인 경우)", + example = "신메뉴 출시 이벤트") + @Size(max = 200, message = "이벤트명은 200자 이하로 입력해주세요") + private String eventName; + + @Schema(description = "이벤트 시작일 (이벤트 콘텐츠인 경우)", + example = "2024-01-15") + private LocalDate startDate; + + @Schema(description = "이벤트 종료일 (이벤트 콘텐츠인 경우)", + example = "2024-01-31") + private LocalDate endDate; + + // ==================== 미디어 정보 ==================== + + @Schema(description = "업로드된 이미지 파일 경로 목록") + private List images; + + @Schema(description = "사진 스타일 선호도", + example = "밝고 화사한", + allowableValues = {"밝고 화사한", "차분하고 세련된", "빈티지한", "모던한", "자연스러운"}) + private String photoStyle; + + // ==================== 추가 옵션 ==================== + + @Schema(description = "해시태그 포함 여부", example = "true") + @Builder.Default + private Boolean includeHashtags = true; + + @Schema(description = "이모지 포함 여부", example = "true") + @Builder.Default + private Boolean includeEmojis = true; + + @Schema(description = "콜투액션 포함 여부 (좋아요, 팔로우 요청 등)", example = "true") + @Builder.Default + private Boolean includeCallToAction = true; + + @Schema(description = "매장 위치 정보 포함 여부", example = "false") + @Builder.Default + private Boolean includeLocation = false; + + // ==================== 플랫폼별 옵션 ==================== + + @Schema(description = "인스타그램 스토리용 여부 (Instagram인 경우)", example = "false") + @Builder.Default + private Boolean forInstagramStory = false; + + @Schema(description = "네이버 블로그 포스팅용 여부 (Naver Blog인 경우)", example = "false") + @Builder.Default + private Boolean forNaverBlogPost = false; + + // ==================== AI 생성 옵션 ==================== + + @Schema(description = "대안 제목 생성 개수", example = "3") + @Builder.Default + private Integer alternativeTitleCount = 3; + + @Schema(description = "대안 해시태그 세트 생성 개수", example = "2") + @Builder.Default + private Integer alternativeHashtagSetCount = 2; + + @Schema(description = "AI 모델 버전 지정 (없으면 기본값 사용)", example = "gpt-4-turbo") + private String preferredAiModel; + + // ==================== 검증 메서드 ==================== + + /** + * 이벤트 날짜 유효성 검증 + * 시작일이 종료일보다 이후인지 확인 + */ + public boolean isValidEventDates() { + if (startDate != null && endDate != null) { + return !startDate.isAfter(endDate); + } + return true; + } + + /** + * 플랫폼별 필수 조건 검증 + */ + public boolean isValidForPlatform() { + if ("INSTAGRAM".equals(platform)) { + // 인스타그램은 이미지가 권장됨 + return images != null && !images.isEmpty(); + } + if ("NAVER_BLOG".equals(platform)) { + // 네이버 블로그는 상세한 내용이 필요 + return requirement != null && requirement.length() >= 20; + } + return true; + } +} 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 index 31a8435..ce5ee97 100644 --- 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 @@ -93,6 +93,9 @@ public class SnsContentCreateResponse { @Schema(description = "콘텐츠 카테고리", example = "음식/메뉴소개") private String category; + @Schema(description = "보정된 이미지 URL 목록") + private List fixedImages; + // ==================== 편집 가능 여부 ==================== @Schema(description = "제목 편집 가능 여부", example = "true") 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 index 5b4a2c7..9adb6c8 100644 --- 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 @@ -1,3 +1,4 @@ +// smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentSaveRequest.java package com.won.smarketing.content.presentation.dto; import io.swagger.v3.oas.annotations.media.Schema; @@ -8,6 +9,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; @@ -24,6 +26,26 @@ public class SnsContentSaveRequest { @NotNull(message = "콘텐츠 ID는 필수입니다") private Long contentId; + @Schema(description = "매장 ID", example = "1", required = true) + @NotNull(message = "매장 ID는 필수입니다") + private Long storeId; + + @Schema(description = "플랫폼", example = "INSTAGRAM", required = true) + @NotBlank(message = "플랫폼은 필수입니다") + 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 = "맛있는 신메뉴를 소개합니다!") private String finalTitle; @@ -32,4 +54,26 @@ public class SnsContentSaveRequest { @Schema(description = "발행 상태", example = "PUBLISHED") private String status; + + // CreationConditions에 필요한 필드들 + @Schema(description = "콘텐츠 카테고리", example = "메뉴소개") + private String category; + + @Schema(description = "구체적인 요구사항", example = "새로 출시된 시그니처 버거를 홍보하고 싶어요") + private String requirement; + + @Schema(description = "톤앤매너", example = "친근함") + private String toneAndManner; + + @Schema(description = "감정 강도", example = "보통") + private String emotionIntensity; + + @Schema(description = "이벤트명", example = "신메뉴 출시 이벤트") + private String eventName; + + @Schema(description = "이벤트 시작일", example = "2024-01-15") + private LocalDate startDate; + + @Schema(description = "이벤트 종료일", example = "2024-01-31") + private LocalDate endDate; } \ No newline at end of file diff --git a/smarketing-java/marketing-content/src/main/resources/application.yml b/smarketing-java/marketing-content/src/main/resources/application.yml index 82f02a3..9f7259f 100644 --- a/smarketing-java/marketing-content/src/main/resources/application.yml +++ b/smarketing-java/marketing-content/src/main/resources/application.yml @@ -1,15 +1,14 @@ server: port: ${SERVER_PORT:8083} - servlet: - context-path: / spring: application: name: marketing-content-service datasource: - url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:5432}/${POSTGRES_DB:contentdb} + url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:5432}/${POSTGRES_DB:MarketingContentDB} username: ${POSTGRES_USER:postgres} password: ${POSTGRES_PASSWORD:postgres} + driver-class-name: org.postgresql.Driver jpa: hibernate: ddl-auto: ${JPA_DDL_AUTO:update} @@ -29,14 +28,10 @@ external: base-url: ${CLAUDE_AI_BASE_URL:https://api.anthropic.com} model: ${CLAUDE_AI_MODEL:claude-3-sonnet-20240229} max-tokens: ${CLAUDE_AI_MAX_TOKENS:4000} - -springdoc: - swagger-ui: - path: /swagger-ui.html - operations-sorter: method - api-docs: - path: /api-docs - +jwt: + secret: ${JWT_SECRET:mySecretKeyForJWTTokenGenerationAndValidation123456789} + access-token-validity: ${JWT_ACCESS_VALIDITY:3600000} + refresh-token-validity: ${JWT_REFRESH_VALIDITY:604800000} logging: level: com.won.smarketing.content: ${LOG_LEVEL:DEBUG} diff --git a/smarketing-java/member/build.gradle b/smarketing-java/member/build.gradle index 771a2fc..c75e760 100644 --- a/smarketing-java/member/build.gradle +++ b/smarketing-java/member/build.gradle @@ -1,4 +1,5 @@ dependencies { implementation project(':common') - runtimeOnly 'com.mysql:mysql-connector-j' + // 데이터베이스 의존성 + runtimeOnly 'org.postgresql:postgresql' } \ No newline at end of file