mirror of
https://github.com/won-ktds/smarketing-backend.git
synced 2026-06-13 04:49:10 +00:00
add : init project
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
dependencies {
|
||||
implementation project(':common')
|
||||
|
||||
// HTTP Client for external AI API
|
||||
implementation 'org.springframework.boot:spring-boot-starter-webflux'
|
||||
}
|
||||
|
||||
bootJar {
|
||||
archiveFileName = "marketing-content-service.jar"
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.won.smarketing.content;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
|
||||
/**
|
||||
* 마케팅 콘텐츠 서비스 메인 애플리케이션 클래스
|
||||
* Clean Architecture 패턴을 적용한 마케팅 콘텐츠 관리 서비스
|
||||
*/
|
||||
@SpringBootApplication(scanBasePackages = {"com.won.smarketing.content", "com.won.smarketing.common"})
|
||||
@EntityScan(basePackages = {"com.won.smarketing.content.infrastructure.entity"})
|
||||
@EnableJpaRepositories(basePackages = {"com.won.smarketing.content.infrastructure.repository"})
|
||||
public class MarketingContentServiceApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MarketingContentServiceApplication.class, args);
|
||||
}
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
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.repository.ContentRepository;
|
||||
import com.won.smarketing.content.presentation.dto.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 콘텐츠 조회 서비스 구현체
|
||||
* 콘텐츠 수정, 조회, 삭제 기능 구현
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class ContentQueryService implements ContentQueryUseCase {
|
||||
|
||||
private final ContentRepository contentRepository;
|
||||
|
||||
/**
|
||||
* 콘텐츠 수정
|
||||
*
|
||||
* @param contentId 수정할 콘텐츠 ID
|
||||
* @param request 콘텐츠 수정 요청
|
||||
* @return 수정된 콘텐츠 정보
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public ContentUpdateResponse updateContent(Long contentId, ContentUpdateRequest request) {
|
||||
Content content = contentRepository.findById(ContentId.of(contentId))
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.CONTENT_NOT_FOUND));
|
||||
|
||||
// 제목과 기간 업데이트
|
||||
content.updateTitle(request.getTitle());
|
||||
content.updatePeriod(request.getStartDate(), request.getEndDate());
|
||||
|
||||
Content updatedContent = contentRepository.save(content);
|
||||
|
||||
return ContentUpdateResponse.builder()
|
||||
.contentId(updatedContent.getId().getValue())
|
||||
.contentType(updatedContent.getContentType().name())
|
||||
.platform(updatedContent.getPlatform().name())
|
||||
.title(updatedContent.getTitle())
|
||||
.content(updatedContent.getContent())
|
||||
.hashtags(updatedContent.getHashtags())
|
||||
.images(updatedContent.getImages())
|
||||
.status(updatedContent.getStatus().name())
|
||||
.updatedAt(updatedContent.getUpdatedAt())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 콘텐츠 목록 조회
|
||||
*
|
||||
* @param contentType 콘텐츠 타입
|
||||
* @param platform 플랫폼
|
||||
* @param period 기간
|
||||
* @param sortBy 정렬 기준
|
||||
* @return 콘텐츠 목록
|
||||
*/
|
||||
@Override
|
||||
public List<ContentResponse> getContents(String contentType, String platform, String period, String sortBy) {
|
||||
ContentType type = contentType != null ? ContentType.fromString(contentType) : null;
|
||||
Platform platformEnum = platform != null ? Platform.fromString(platform) : null;
|
||||
|
||||
List<Content> contents = contentRepository.findByFilters(type, platformEnum, period, sortBy);
|
||||
|
||||
return contents.stream()
|
||||
.map(this::toContentResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 진행 중인 콘텐츠 목록 조회
|
||||
*
|
||||
* @param period 기간
|
||||
* @return 진행 중인 콘텐츠 목록
|
||||
*/
|
||||
@Override
|
||||
public List<OngoingContentResponse> getOngoingContents(String period) {
|
||||
List<Content> contents = contentRepository.findOngoingContents(period);
|
||||
|
||||
return contents.stream()
|
||||
.map(this::toOngoingContentResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 콘텐츠 상세 조회
|
||||
*
|
||||
* @param contentId 콘텐츠 ID
|
||||
* @return 콘텐츠 상세 정보
|
||||
*/
|
||||
@Override
|
||||
public ContentDetailResponse getContentDetail(Long contentId) {
|
||||
Content content = contentRepository.findById(ContentId.of(contentId))
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.CONTENT_NOT_FOUND));
|
||||
|
||||
return ContentDetailResponse.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())
|
||||
.creationConditions(toCreationConditionsDto(content.getCreationConditions()))
|
||||
.createdAt(content.getCreatedAt())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 콘텐츠 삭제
|
||||
*
|
||||
* @param contentId 삭제할 콘텐츠 ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteContent(Long contentId) {
|
||||
Content content = contentRepository.findById(ContentId.of(contentId))
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.CONTENT_NOT_FOUND));
|
||||
|
||||
contentRepository.deleteById(ContentId.of(contentId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Content 엔티티를 ContentResponse DTO로 변환
|
||||
*
|
||||
* @param content Content 엔티티
|
||||
* @return ContentResponse DTO
|
||||
*/
|
||||
private ContentResponse toContentResponse(Content content) {
|
||||
return 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())
|
||||
.createdAt(content.getCreatedAt())
|
||||
.viewCount(0) // TODO: 실제 조회 수 구현 필요
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Content 엔티티를 OngoingContentResponse DTO로 변환
|
||||
*
|
||||
* @param content Content 엔티티
|
||||
* @return OngoingContentResponse DTO
|
||||
*/
|
||||
private OngoingContentResponse toOngoingContentResponse(Content content) {
|
||||
return OngoingContentResponse.builder()
|
||||
.contentId(content.getId().getValue())
|
||||
.contentType(content.getContentType().name())
|
||||
.platform(content.getPlatform().name())
|
||||
.title(content.getTitle())
|
||||
.status(content.getStatus().name())
|
||||
.createdAt(content.getCreatedAt())
|
||||
.viewCount(0) // TODO: 실제 조회 수 구현 필요
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* CreationConditions를 DTO로 변환
|
||||
*
|
||||
* @param conditions CreationConditions 도메인 객체
|
||||
* @return CreationConditionsDto
|
||||
*/
|
||||
private CreationConditionsDto toCreationConditionsDto(CreationConditions conditions) {
|
||||
if (conditions == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return CreationConditionsDto.builder()
|
||||
.category(conditions.getCategory())
|
||||
.requirement(conditions.getRequirement())
|
||||
.toneAndManner(conditions.getToneAndManner())
|
||||
.emotionIntensity(conditions.getEmotionIntensity())
|
||||
.eventName(conditions.getEventName())
|
||||
.startDate(conditions.getStartDate())
|
||||
.endDate(conditions.getEndDate())
|
||||
.photoStyle(conditions.getPhotoStyle())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package com.won.smarketing.content.application.service;
|
||||
|
||||
import com.won.smarketing.content.application.usecase.PosterContentUseCase;
|
||||
import com.won.smarketing.content.domain.model.Content;
|
||||
import com.won.smarketing.content.domain.model.ContentStatus;
|
||||
import com.won.smarketing.content.domain.model.ContentType;
|
||||
import com.won.smarketing.content.domain.model.CreationConditions;
|
||||
import com.won.smarketing.content.domain.model.Platform;
|
||||
import com.won.smarketing.content.domain.repository.ContentRepository;
|
||||
import com.won.smarketing.content.domain.service.AiPosterGenerator;
|
||||
import com.won.smarketing.content.presentation.dto.PosterContentCreateRequest;
|
||||
import com.won.smarketing.content.presentation.dto.PosterContentCreateResponse;
|
||||
import com.won.smarketing.content.presentation.dto.PosterContentSaveRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 포스터 콘텐츠 서비스 구현체
|
||||
* 홍보 포스터 생성 및 저장 기능 구현
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class PosterContentService implements PosterContentUseCase {
|
||||
|
||||
private final ContentRepository contentRepository;
|
||||
private final AiPosterGenerator aiPosterGenerator;
|
||||
|
||||
/**
|
||||
* 포스터 콘텐츠 생성
|
||||
*
|
||||
* @param request 포스터 콘텐츠 생성 요청
|
||||
* @return 생성된 포스터 콘텐츠 정보
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public PosterContentCreateResponse generatePosterContent(PosterContentCreateRequest request) {
|
||||
// AI를 사용하여 포스터 생성
|
||||
String generatedPoster = aiPosterGenerator.generatePoster(request);
|
||||
|
||||
// 다양한 사이즈의 포스터 생성
|
||||
Map<String, String> posterSizes = aiPosterGenerator.generatePosterSizes(generatedPoster);
|
||||
|
||||
// 생성 조건 정보 구성
|
||||
CreationConditions conditions = CreationConditions.builder()
|
||||
.category(request.getCategory())
|
||||
.requirement(request.getRequirement())
|
||||
.toneAndManner(request.getToneAndManner())
|
||||
.emotionIntensity(request.getEmotionIntensity())
|
||||
.eventName(request.getEventName())
|
||||
.startDate(request.getStartDate())
|
||||
.endDate(request.getEndDate())
|
||||
.photoStyle(request.getPhotoStyle())
|
||||
.build();
|
||||
|
||||
return PosterContentCreateResponse.builder()
|
||||
.contentId(null) // 임시 생성이므로 ID 없음
|
||||
.contentType(ContentType.POSTER.name())
|
||||
.title(request.getTitle())
|
||||
.image(generatedPoster)
|
||||
.posterSizes(posterSizes)
|
||||
.status(ContentStatus.DRAFT.name())
|
||||
.createdAt(LocalDateTime.now())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 포스터 콘텐츠 저장
|
||||
*
|
||||
* @param request 포스터 콘텐츠 저장 요청
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void savePosterContent(PosterContentSaveRequest request) {
|
||||
// 생성 조건 정보 구성
|
||||
CreationConditions conditions = CreationConditions.builder()
|
||||
.category(request.getCategory())
|
||||
.requirement(request.getRequirement())
|
||||
.toneAndManner(request.getToneAndManner())
|
||||
.emotionIntensity(request.getEmotionIntensity())
|
||||
.eventName(request.getEventName())
|
||||
.startDate(request.getStartDate())
|
||||
.endDate(request.getEndDate())
|
||||
.photoStyle(request.getPhotoStyle())
|
||||
.build();
|
||||
|
||||
// 콘텐츠 엔티티 생성 및 저장
|
||||
Content content = Content.builder()
|
||||
.contentType(ContentType.POSTER)
|
||||
.platform(Platform.GENERAL) // 포스터는 범용
|
||||
.title(request.getTitle())
|
||||
.content(null) // 포스터는 이미지가 주 콘텐츠
|
||||
.hashtags(null)
|
||||
.images(request.getImages())
|
||||
.status(ContentStatus.PUBLISHED)
|
||||
.creationConditions(conditions)
|
||||
.storeId(request.getStoreId())
|
||||
.createdAt(LocalDateTime.now())
|
||||
.updatedAt(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
contentRepository.save(content);
|
||||
}
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package com.won.smarketing.content.application.service;
|
||||
|
||||
import com.won.smarketing.content.application.usecase.SnsContentUseCase;
|
||||
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.CreationConditions;
|
||||
import com.won.smarketing.content.domain.model.Platform;
|
||||
import com.won.smarketing.content.domain.repository.ContentRepository;
|
||||
import com.won.smarketing.content.domain.service.AiContentGenerator;
|
||||
import com.won.smarketing.content.presentation.dto.SnsContentCreateRequest;
|
||||
import com.won.smarketing.content.presentation.dto.SnsContentCreateResponse;
|
||||
import com.won.smarketing.content.presentation.dto.SnsContentSaveRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* SNS 콘텐츠 서비스 구현체
|
||||
* SNS 게시물 생성 및 저장 기능 구현
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class SnsContentService implements SnsContentUseCase {
|
||||
|
||||
private final ContentRepository contentRepository;
|
||||
private final AiContentGenerator aiContentGenerator;
|
||||
|
||||
/**
|
||||
* SNS 콘텐츠 생성
|
||||
*
|
||||
* @param request SNS 콘텐츠 생성 요청
|
||||
* @return 생성된 SNS 콘텐츠 정보
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public SnsContentCreateResponse generateSnsContent(SnsContentCreateRequest request) {
|
||||
// AI를 사용하여 SNS 콘텐츠 생성
|
||||
String generatedContent = aiContentGenerator.generateSnsContent(request);
|
||||
|
||||
// 플랫폼에 맞는 해시태그 생성
|
||||
Platform platform = Platform.fromString(request.getPlatform());
|
||||
List<String> hashtags = aiContentGenerator.generateHashtags(generatedContent, platform);
|
||||
|
||||
// 생성 조건 정보 구성
|
||||
CreationConditions conditions = CreationConditions.builder()
|
||||
.category(request.getCategory())
|
||||
.requirement(request.getRequirement())
|
||||
.toneAndManner(request.getToneAndManner())
|
||||
.emotionIntensity(request.getEmotionIntensity())
|
||||
.eventName(request.getEventName())
|
||||
.startDate(request.getStartDate())
|
||||
.endDate(request.getEndDate())
|
||||
.build();
|
||||
|
||||
// 임시 콘텐츠 생성 (저장하지 않음)
|
||||
Content content = Content.builder()
|
||||
.contentType(ContentType.SNS_POST)
|
||||
.platform(platform)
|
||||
.title(request.getTitle())
|
||||
.content(generatedContent)
|
||||
.hashtags(hashtags)
|
||||
.images(request.getImages())
|
||||
.status(ContentStatus.DRAFT)
|
||||
.creationConditions(conditions)
|
||||
.storeId(request.getStoreId())
|
||||
.createdAt(LocalDateTime.now())
|
||||
.updatedAt(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
return SnsContentCreateResponse.builder()
|
||||
.contentId(null) // 임시 생성이므로 ID 없음
|
||||
.contentType(content.getContentType().name())
|
||||
.platform(content.getPlatform().name())
|
||||
.title(content.getTitle())
|
||||
.content(content.getContent())
|
||||
.hashtags(content.getHashtags())
|
||||
.images(content.getImages())
|
||||
.status(content.getStatus().name())
|
||||
.createdAt(content.getCreatedAt())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* SNS 콘텐츠 저장
|
||||
*
|
||||
* @param request SNS 콘텐츠 저장 요청
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void saveSnsContent(SnsContentSaveRequest request) {
|
||||
// 생성 조건 정보 구성
|
||||
CreationConditions conditions = CreationConditions.builder()
|
||||
.category(request.getCategory())
|
||||
.requirement(request.getRequirement())
|
||||
.toneAndManner(request.getToneAndManner())
|
||||
.emotionIntensity(request.getEmotionIntensity())
|
||||
.eventName(request.getEventName())
|
||||
.startDate(request.getStartDate())
|
||||
.endDate(request.getEndDate())
|
||||
.build();
|
||||
|
||||
// 콘텐츠 엔티티 생성 및 저장
|
||||
Content content = Content.builder()
|
||||
.contentType(ContentType.SNS_POST)
|
||||
.platform(Platform.fromString(request.getPlatform()))
|
||||
.title(request.getTitle())
|
||||
.content(request.getContent())
|
||||
.hashtags(request.getHashtags())
|
||||
.images(request.getImages())
|
||||
.status(ContentStatus.PUBLISHED)
|
||||
.creationConditions(conditions)
|
||||
.storeId(request.getStoreId())
|
||||
.createdAt(LocalDateTime.now())
|
||||
.updatedAt(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
contentRepository.save(content);
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.won.smarketing.content.application.usecase;
|
||||
|
||||
import com.won.smarketing.content.presentation.dto.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 콘텐츠 조회 관련 Use Case 인터페이스
|
||||
* 콘텐츠 수정, 조회, 삭제 기능 정의
|
||||
*/
|
||||
public interface ContentQueryUseCase {
|
||||
|
||||
/**
|
||||
* 콘텐츠 수정
|
||||
*
|
||||
* @param contentId 수정할 콘텐츠 ID
|
||||
* @param request 콘텐츠 수정 요청
|
||||
* @return 수정된 콘텐츠 정보
|
||||
*/
|
||||
ContentUpdateResponse updateContent(Long contentId, ContentUpdateRequest request);
|
||||
|
||||
/**
|
||||
* 콘텐츠 목록 조회
|
||||
*
|
||||
* @param contentType 콘텐츠 타입
|
||||
* @param platform 플랫폼
|
||||
* @param period 기간
|
||||
* @param sortBy 정렬 기준
|
||||
* @return 콘텐츠 목록
|
||||
*/
|
||||
List<ContentResponse> getContents(String contentType, String platform, String period, String sortBy);
|
||||
|
||||
/**
|
||||
* 진행 중인 콘텐츠 목록 조회
|
||||
*
|
||||
* @param period 기간
|
||||
* @return 진행 중인 콘텐츠 목록
|
||||
*/
|
||||
List<OngoingContentResponse> getOngoingContents(String period);
|
||||
|
||||
/**
|
||||
* 콘텐츠 상세 조회
|
||||
*
|
||||
* @param contentId 콘텐츠 ID
|
||||
* @return 콘텐츠 상세 정보
|
||||
*/
|
||||
ContentDetailResponse getContentDetail(Long contentId);
|
||||
|
||||
/**
|
||||
* 콘텐츠 삭제
|
||||
*
|
||||
* @param contentId 삭제할 콘텐츠 ID
|
||||
*/
|
||||
void deleteContent(Long contentId);
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.won.smarketing.content.application.usecase;
|
||||
|
||||
import com.won.smarketing.content.presentation.dto.PosterContentCreateRequest;
|
||||
import com.won.smarketing.content.presentation.dto.PosterContentCreateResponse;
|
||||
import com.won.smarketing.content.presentation.dto.PosterContentSaveRequest;
|
||||
|
||||
/**
|
||||
* 포스터 콘텐츠 관련 Use Case 인터페이스
|
||||
* 홍보 포스터 생성 및 저장 기능 정의
|
||||
*/
|
||||
public interface PosterContentUseCase {
|
||||
|
||||
/**
|
||||
* 포스터 콘텐츠 생성
|
||||
*
|
||||
* @param request 포스터 콘텐츠 생성 요청
|
||||
* @return 생성된 포스터 콘텐츠 정보
|
||||
*/
|
||||
PosterContentCreateResponse generatePosterContent(PosterContentCreateRequest request);
|
||||
|
||||
/**
|
||||
* 포스터 콘텐츠 저장
|
||||
*
|
||||
* @param request 포스터 콘텐츠 저장 요청
|
||||
*/
|
||||
void savePosterContent(PosterContentSaveRequest request);
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.won.smarketing.content.application.usecase;
|
||||
|
||||
import com.won.smarketing.content.presentation.dto.SnsContentCreateRequest;
|
||||
import com.won.smarketing.content.presentation.dto.SnsContentCreateResponse;
|
||||
import com.won.smarketing.content.presentation.dto.SnsContentSaveRequest;
|
||||
|
||||
/**
|
||||
* SNS 콘텐츠 관련 Use Case 인터페이스
|
||||
* SNS 게시물 생성 및 저장 기능 정의
|
||||
*/
|
||||
public interface SnsContentUseCase {
|
||||
|
||||
/**
|
||||
* SNS 콘텐츠 생성
|
||||
*
|
||||
* @param request SNS 콘텐츠 생성 요청
|
||||
* @return 생성된 SNS 콘텐츠 정보
|
||||
*/
|
||||
SnsContentCreateResponse generateSnsContent(SnsContentCreateRequest request);
|
||||
|
||||
/**
|
||||
* SNS 콘텐츠 저장
|
||||
*
|
||||
* @param request SNS 콘텐츠 저장 요청
|
||||
*/
|
||||
void saveSnsContent(SnsContentSaveRequest request);
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
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<String> hashtags;
|
||||
|
||||
/**
|
||||
* 이미지 URL 목록
|
||||
*/
|
||||
private List<String> 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();
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.won.smarketing.content.domain.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 콘텐츠 식별자 값 객체
|
||||
* 콘텐츠의 고유 식별자를 나타내는 도메인 객체
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@EqualsAndHashCode
|
||||
public class ContentId {
|
||||
|
||||
private Long value;
|
||||
|
||||
/**
|
||||
* ContentId 생성 팩토리 메서드
|
||||
*
|
||||
* @param value 식별자 값
|
||||
* @return ContentId 인스턴스
|
||||
*/
|
||||
public static ContentId of(Long value) {
|
||||
if (value == null || value <= 0) {
|
||||
throw new IllegalArgumentException("ContentId는 양수여야 합니다.");
|
||||
}
|
||||
return new ContentId(value);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.won.smarketing.content.domain.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 콘텐츠 상태 열거형
|
||||
* 콘텐츠의 생명주기 상태 정의
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum ContentStatus {
|
||||
|
||||
DRAFT("임시저장"),
|
||||
PUBLISHED("발행됨"),
|
||||
ARCHIVED("보관됨");
|
||||
|
||||
private final String displayName;
|
||||
|
||||
/**
|
||||
* 문자열로부터 ContentStatus 변환
|
||||
*
|
||||
* @param status 상태 문자열
|
||||
* @return ContentStatus
|
||||
*/
|
||||
public static ContentStatus fromString(String status) {
|
||||
if (status == null) {
|
||||
return DRAFT;
|
||||
}
|
||||
|
||||
for (ContentStatus s : ContentStatus.values()) {
|
||||
if (s.name().equalsIgnoreCase(status)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("알 수 없는 콘텐츠 상태: " + status);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.won.smarketing.content.domain.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 콘텐츠 타입 열거형
|
||||
* 지원되는 마케팅 콘텐츠 유형 정의
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum ContentType {
|
||||
|
||||
SNS_POST("SNS 게시물"),
|
||||
POSTER("홍보 포스터");
|
||||
|
||||
private final String displayName;
|
||||
|
||||
/**
|
||||
* 문자열로부터 ContentType 변환
|
||||
*
|
||||
* @param type 타입 문자열
|
||||
* @return ContentType
|
||||
*/
|
||||
public static ContentType fromString(String type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (ContentType contentType : ContentType.values()) {
|
||||
if (contentType.name().equalsIgnoreCase(type)) {
|
||||
return contentType;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("알 수 없는 콘텐츠 타입: " + type);
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.won.smarketing.content.domain.model;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 콘텐츠 생성 조건 도메인 모델
|
||||
* AI 콘텐츠 생성 시 사용되는 조건 정보
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@AllArgsConstructor
|
||||
@Builder(toBuilder = true)
|
||||
public class CreationConditions {
|
||||
|
||||
/**
|
||||
* 홍보 대상 카테고리
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 특별 요구사항
|
||||
*/
|
||||
private String requirement;
|
||||
|
||||
/**
|
||||
* 톤앤매너
|
||||
*/
|
||||
private String toneAndManner;
|
||||
|
||||
/**
|
||||
* 감정 강도
|
||||
*/
|
||||
private String emotionIntensity;
|
||||
|
||||
/**
|
||||
* 이벤트명
|
||||
*/
|
||||
private String eventName;
|
||||
|
||||
/**
|
||||
* 홍보 시작일
|
||||
*/
|
||||
private LocalDate startDate;
|
||||
|
||||
/**
|
||||
* 홍보 종료일
|
||||
*/
|
||||
private LocalDate endDate;
|
||||
|
||||
/**
|
||||
* 사진 스타일 (포스터용)
|
||||
*/
|
||||
private String photoStyle;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.won.smarketing.content.domain.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 플랫폼 열거형
|
||||
* 콘텐츠가 게시될 플랫폼 정의
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum Platform {
|
||||
|
||||
INSTAGRAM("인스타그램"),
|
||||
NAVER_BLOG("네이버 블로그"),
|
||||
GENERAL("범용");
|
||||
|
||||
private final String displayName;
|
||||
|
||||
/**
|
||||
* 문자열로부터 Platform 변환
|
||||
*
|
||||
* @param platform 플랫폼 문자열
|
||||
* @return Platform
|
||||
*/
|
||||
public static Platform fromString(String platform) {
|
||||
if (platform == null) {
|
||||
return GENERAL;
|
||||
}
|
||||
|
||||
for (Platform p : Platform.values()) {
|
||||
if (p.name().equalsIgnoreCase(platform)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("알 수 없는 플랫폼: " + platform);
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package com.won.smarketing.content.domain.repository;
|
||||
|
||||
import com.won.smarketing.content.domain.model.Content;
|
||||
import com.won.smarketing.content.domain.model.ContentId;
|
||||
import com.won.smarketing.content.domain.model.ContentType;
|
||||
import com.won.smarketing.content.domain.model.Platform;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 콘텐츠 저장소 인터페이스
|
||||
* 콘텐츠 도메인의 데이터 접근 추상화
|
||||
*/
|
||||
public interface ContentRepository {
|
||||
|
||||
/**
|
||||
* 콘텐츠 저장
|
||||
*
|
||||
* @param content 저장할 콘텐츠
|
||||
* @return 저장된 콘텐츠
|
||||
*/
|
||||
Content save(Content content);
|
||||
|
||||
/**
|
||||
* 콘텐츠 ID로 조회
|
||||
*
|
||||
* @param id 콘텐츠 ID
|
||||
* @return 콘텐츠 (Optional)
|
||||
*/
|
||||
Optional<Content> findById(ContentId id);
|
||||
|
||||
/**
|
||||
* 필터 조건으로 콘텐츠 목록 조회
|
||||
*
|
||||
* @param contentType 콘텐츠 타입
|
||||
* @param platform 플랫폼
|
||||
* @param period 기간
|
||||
* @param sortBy 정렬 기준
|
||||
* @return 콘텐츠 목록
|
||||
*/
|
||||
List<Content> findByFilters(ContentType contentType, Platform platform, String period, String sortBy);
|
||||
|
||||
/**
|
||||
* 진행 중인 콘텐츠 목록 조회
|
||||
*
|
||||
* @param period 기간
|
||||
* @return 진행 중인 콘텐츠 목록
|
||||
*/
|
||||
List<Content> findOngoingContents(String period);
|
||||
|
||||
/**
|
||||
* 콘텐츠 삭제
|
||||
*
|
||||
* @param id 삭제할 콘텐츠 ID
|
||||
*/
|
||||
void deleteById(ContentId id);
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.won.smarketing.content.domain.service;
|
||||
|
||||
import com.won.smarketing.content.domain.model.Platform;
|
||||
import com.won.smarketing.content.presentation.dto.SnsContentCreateRequest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI 콘텐츠 생성 도메인 서비스 인터페이스
|
||||
* SNS 콘텐츠 생성 및 해시태그 생성 기능 정의
|
||||
*/
|
||||
public interface AiContentGenerator {
|
||||
|
||||
/**
|
||||
* SNS 콘텐츠 생성
|
||||
*
|
||||
* @param request SNS 콘텐츠 생성 요청
|
||||
* @return 생성된 콘텐츠
|
||||
*/
|
||||
String generateSnsContent(SnsContentCreateRequest request);
|
||||
|
||||
/**
|
||||
* 플랫폼별 해시태그 생성
|
||||
*
|
||||
* @param content 콘텐츠 내용
|
||||
* @param platform 플랫폼
|
||||
* @return 해시태그 목록
|
||||
*/
|
||||
List<String> generateHashtags(String content, Platform platform);
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.won.smarketing.content.domain.service;
|
||||
|
||||
import com.won.smarketing.content.presentation.dto.PosterContentCreateRequest;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* AI 포스터 생성 도메인 서비스 인터페이스
|
||||
* 홍보 포스터 생성 및 다양한 사이즈 생성 기능 정의
|
||||
*/
|
||||
public interface AiPosterGenerator {
|
||||
|
||||
/**
|
||||
* 포스터 생성
|
||||
*
|
||||
* @param request 포스터 생성 요청
|
||||
* @return 생성된 포스터 이미지 URL
|
||||
*/
|
||||
String generatePoster(PosterContentCreateRequest request);
|
||||
|
||||
/**
|
||||
* 다양한 사이즈의 포스터 생성
|
||||
*
|
||||
* @param baseImage 기본 이미지
|
||||
* @return 사이즈별 포스터 URL 맵
|
||||
*/
|
||||
Map<String, String> generatePosterSizes(String baseImage);
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
package com.won.smarketing.content.presentation.controller;
|
||||
|
||||
import com.won.smarketing.common.dto.ApiResponse;
|
||||
import com.won.smarketing.content.application.usecase.ContentQueryUseCase;
|
||||
import com.won.smarketing.content.application.usecase.PosterContentUseCase;
|
||||
import com.won.smarketing.content.application.usecase.SnsContentUseCase;
|
||||
import com.won.smarketing.content.presentation.dto.*;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 마케팅 콘텐츠 관리를 위한 REST API 컨트롤러
|
||||
* SNS 콘텐츠 생성, 포스터 생성, 콘텐츠 관리 기능 제공
|
||||
*/
|
||||
@Tag(name = "마케팅 콘텐츠 관리", description = "AI 기반 마케팅 콘텐츠 생성 및 관리 API")
|
||||
@RestController
|
||||
@RequestMapping("/api/content")
|
||||
@RequiredArgsConstructor
|
||||
public class ContentController {
|
||||
|
||||
private final SnsContentUseCase snsContentUseCase;
|
||||
private final PosterContentUseCase posterContentUseCase;
|
||||
private final ContentQueryUseCase contentQueryUseCase;
|
||||
|
||||
/**
|
||||
* SNS 게시물 생성
|
||||
*
|
||||
* @param request SNS 콘텐츠 생성 요청
|
||||
* @return 생성된 SNS 콘텐츠 정보
|
||||
*/
|
||||
@Operation(summary = "SNS 게시물 생성", description = "AI를 활용하여 SNS 게시물을 생성합니다.")
|
||||
@PostMapping("/sns/generate")
|
||||
public ResponseEntity<ApiResponse<SnsContentCreateResponse>> generateSnsContent(@Valid @RequestBody SnsContentCreateRequest request) {
|
||||
SnsContentCreateResponse response = snsContentUseCase.generateSnsContent(request);
|
||||
return ResponseEntity.ok(ApiResponse.success(response, "SNS 콘텐츠가 성공적으로 생성되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* SNS 게시물 저장
|
||||
*
|
||||
* @param request SNS 콘텐츠 저장 요청
|
||||
* @return 저장 성공 응답
|
||||
*/
|
||||
@Operation(summary = "SNS 게시물 저장", description = "생성된 SNS 게시물을 저장합니다.")
|
||||
@PostMapping("/sns/save")
|
||||
public ResponseEntity<ApiResponse<Void>> saveSnsContent(@Valid @RequestBody SnsContentSaveRequest request) {
|
||||
snsContentUseCase.saveSnsContent(request);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "SNS 콘텐츠가 성공적으로 저장되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 홍보 포스터 생성
|
||||
*
|
||||
* @param request 포스터 콘텐츠 생성 요청
|
||||
* @return 생성된 포스터 콘텐츠 정보
|
||||
*/
|
||||
@Operation(summary = "홍보 포스터 생성", description = "AI를 활용하여 홍보 포스터를 생성합니다.")
|
||||
@PostMapping("/poster/generate")
|
||||
public ResponseEntity<ApiResponse<PosterContentCreateResponse>> generatePosterContent(@Valid @RequestBody PosterContentCreateRequest request) {
|
||||
PosterContentCreateResponse response = posterContentUseCase.generatePosterContent(request);
|
||||
return ResponseEntity.ok(ApiResponse.success(response, "포스터 콘텐츠가 성공적으로 생성되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 홍보 포스터 저장
|
||||
*
|
||||
* @param request 포스터 콘텐츠 저장 요청
|
||||
* @return 저장 성공 응답
|
||||
*/
|
||||
@Operation(summary = "홍보 포스터 저장", description = "생성된 홍보 포스터를 저장합니다.")
|
||||
@PostMapping("/poster/save")
|
||||
public ResponseEntity<ApiResponse<Void>> savePosterContent(@Valid @RequestBody PosterContentSaveRequest request) {
|
||||
posterContentUseCase.savePosterContent(request);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "포스터 콘텐츠가 성공적으로 저장되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 콘텐츠 수정
|
||||
*
|
||||
* @param contentId 수정할 콘텐츠 ID
|
||||
* @param request 콘텐츠 수정 요청
|
||||
* @return 수정된 콘텐츠 정보
|
||||
*/
|
||||
@Operation(summary = "콘텐츠 수정", description = "기존 콘텐츠를 수정합니다.")
|
||||
@PutMapping("/{contentId}")
|
||||
public ResponseEntity<ApiResponse<ContentUpdateResponse>> updateContent(
|
||||
@Parameter(description = "콘텐츠 ID", required = true)
|
||||
@PathVariable Long contentId,
|
||||
@Valid @RequestBody ContentUpdateRequest request) {
|
||||
ContentUpdateResponse response = contentQueryUseCase.updateContent(contentId, request);
|
||||
return ResponseEntity.ok(ApiResponse.success(response, "콘텐츠가 성공적으로 수정되었습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 콘텐츠 목록 조회
|
||||
*
|
||||
* @param contentType 콘텐츠 타입 필터
|
||||
* @param platform 플랫폼 필터
|
||||
* @param period 기간 필터
|
||||
* @param sortBy 정렬 기준
|
||||
* @return 콘텐츠 목록
|
||||
*/
|
||||
@Operation(summary = "콘텐츠 목록 조회", description = "다양한 필터와 정렬 옵션으로 콘텐츠 목록을 조회합니다.")
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<ContentResponse>>> getContents(
|
||||
@Parameter(description = "콘텐츠 타입")
|
||||
@RequestParam(required = false) String contentType,
|
||||
@Parameter(description = "플랫폼")
|
||||
@RequestParam(required = false) String platform,
|
||||
@Parameter(description = "기간")
|
||||
@RequestParam(required = false) String period,
|
||||
@Parameter(description = "정렬 기준")
|
||||
@RequestParam(required = false) String sortBy) {
|
||||
List<ContentResponse> response = contentQueryUseCase.getContents(contentType, platform, period, sortBy);
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
|
||||
/**
|
||||
* 진행 중인 콘텐츠 목록 조회
|
||||
*
|
||||
* @param period 기간 필터
|
||||
* @return 진행 중인 콘텐츠 목록
|
||||
*/
|
||||
@Operation(summary = "진행 콘텐츠 조회", description = "현재 진행 중인 콘텐츠 목록을 조회합니다.")
|
||||
@GetMapping("/ongoing")
|
||||
public ResponseEntity<ApiResponse<List<OngoingContentResponse>>> getOngoingContents(
|
||||
@Parameter(description = "기간")
|
||||
@RequestParam(required = false) String period) {
|
||||
List<OngoingContentResponse> response = contentQueryUseCase.getOngoingContents(period);
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
|
||||
/**
|
||||
* 콘텐츠 상세 조회
|
||||
*
|
||||
* @param contentId 조회할 콘텐츠 ID
|
||||
* @return 콘텐츠 상세 정보
|
||||
*/
|
||||
@Operation(summary = "콘텐츠 상세 조회", description = "특정 콘텐츠의 상세 정보를 조회합니다.")
|
||||
@GetMapping("/{contentId}")
|
||||
public ResponseEntity<ApiResponse<ContentDetailResponse>> getContentDetail(
|
||||
@Parameter(description = "콘텐츠 ID", required = true)
|
||||
@PathVariable Long contentId) {
|
||||
ContentDetailResponse response = contentQueryUseCase.getContentDetail(contentId);
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
|
||||
/**
|
||||
* 콘텐츠 삭제
|
||||
*
|
||||
* @param contentId 삭제할 콘텐츠 ID
|
||||
* @return 삭제 성공 응답
|
||||
*/
|
||||
@Operation(summary = "콘텐츠 삭제", description = "콘텐츠를 삭제합니다.")
|
||||
@DeleteMapping("/{contentId}")
|
||||
public ResponseEntity<ApiResponse<Void>> deleteContent(
|
||||
@Parameter(description = "콘텐츠 ID", required = true)
|
||||
@PathVariable Long contentId) {
|
||||
contentQueryUseCase.deleteContent(contentId);
|
||||
return ResponseEntity.ok(ApiResponse.success(null, "콘텐츠가 성공적으로 삭제되었습니다."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
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}
|
||||
username: ${POSTGRES_USER:postgres}
|
||||
password: ${POSTGRES_PASSWORD:postgres}
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: ${JPA_DDL_AUTO:update}
|
||||
show-sql: ${JPA_SHOW_SQL:true}
|
||||
properties:
|
||||
hibernate:
|
||||
dialect: org.hibernate.dialect.PostgreSQLDialect
|
||||
format_sql: true
|
||||
|
||||
external:
|
||||
claude-ai:
|
||||
api-key: ${CLAUDE_AI_API_KEY:your-claude-api-key}
|
||||
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
|
||||
|
||||
logging:
|
||||
level:
|
||||
com.won.smarketing.content: ${LOG_LEVEL:DEBUG}
|
||||
Reference in New Issue
Block a user