diff --git a/content-service/build.gradle b/content-service/build.gradle index 0120aef..2346bcc 100644 --- a/content-service/build.gradle +++ b/content-service/build.gradle @@ -1,3 +1,9 @@ +configurations { + // Exclude JPA and PostgreSQL from inherited dependencies (Phase 3: Redis migration) + implementation.exclude group: 'org.springframework.boot', module: 'spring-boot-starter-data-jpa' + implementation.exclude group: 'org.postgresql', module: 'postgresql' +} + dependencies { // Kafka Consumer implementation 'org.springframework.kafka:spring-kafka' @@ -17,7 +23,4 @@ dependencies { // Jackson for JSON implementation 'com.fasterxml.jackson.core:jackson-databind' - - // H2 Database for local testing - runtimeOnly 'com.h2database:h2' } diff --git a/content-service/src/main/java/com/kt/event/content/biz/service/JobManagementService.java b/content-service/src/main/java/com/kt/event/content/biz/service/JobManagementService.java index 9c27dc8..798dfdb 100644 --- a/content-service/src/main/java/com/kt/event/content/biz/service/JobManagementService.java +++ b/content-service/src/main/java/com/kt/event/content/biz/service/JobManagementService.java @@ -4,6 +4,7 @@ import com.kt.event.common.exception.BusinessException; import com.kt.event.common.exception.ErrorCode; import com.kt.event.content.biz.domain.Job; import com.kt.event.content.biz.dto.JobInfo; +import com.kt.event.content.biz.dto.RedisJobData; import com.kt.event.content.biz.usecase.in.GetJobStatusUseCase; import com.kt.event.content.biz.usecase.out.JobReader; import lombok.RequiredArgsConstructor; @@ -25,9 +26,22 @@ public class JobManagementService implements GetJobStatusUseCase { @Override public JobInfo execute(String jobId) { - Job job = jobReader.findById(jobId) + RedisJobData jobData = jobReader.getJob(jobId) .orElseThrow(() -> new BusinessException(ErrorCode.COMMON_001, "Job을 찾을 수 없습니다")); + // RedisJobData를 Job 도메인 객체로 변환 + Job job = Job.builder() + .id(jobData.getId()) + .eventDraftId(jobData.getEventDraftId()) + .jobType(jobData.getJobType()) + .status(Job.Status.valueOf(jobData.getStatus())) + .progress(jobData.getProgress()) + .resultMessage(jobData.getResultMessage()) + .errorMessage(jobData.getErrorMessage()) + .createdAt(jobData.getCreatedAt()) + .updatedAt(jobData.getUpdatedAt()) + .build(); + return JobInfo.from(job); } } diff --git a/content-service/src/main/java/com/kt/event/content/biz/service/mock/MockGenerateImagesService.java b/content-service/src/main/java/com/kt/event/content/biz/service/mock/MockGenerateImagesService.java index db8aea0..0bf1e04 100644 --- a/content-service/src/main/java/com/kt/event/content/biz/service/mock/MockGenerateImagesService.java +++ b/content-service/src/main/java/com/kt/event/content/biz/service/mock/MockGenerateImagesService.java @@ -7,6 +7,7 @@ import com.kt.event.content.biz.domain.Job; import com.kt.event.content.biz.domain.Platform; import com.kt.event.content.biz.dto.ContentCommand; import com.kt.event.content.biz.dto.JobInfo; +import com.kt.event.content.biz.dto.RedisJobData; import com.kt.event.content.biz.usecase.in.GenerateImagesUseCase; import com.kt.event.content.biz.usecase.out.ContentWriter; import com.kt.event.content.biz.usecase.out.JobWriter; @@ -53,14 +54,24 @@ public class MockGenerateImagesService implements GenerateImagesUseCase { .updatedAt(java.time.LocalDateTime.now()) .build(); - // Job 저장 - Job savedJob = jobWriter.save(job); + // Job 저장 (Job 도메인을 RedisJobData로 변환) + RedisJobData jobData = RedisJobData.builder() + .id(job.getId()) + .eventDraftId(job.getEventDraftId()) + .jobType(job.getJobType()) + .status(job.getStatus().name()) + .progress(job.getProgress()) + .createdAt(job.getCreatedAt()) + .updatedAt(job.getUpdatedAt()) + .build(); + + jobWriter.saveJob(jobData, 3600); // TTL 1시간 log.info("[MOCK] Job 생성 완료: jobId={}", jobId); // 비동기로 이미지 생성 시뮬레이션 processImageGeneration(jobId, command); - return JobInfo.from(savedJob); + return JobInfo.from(job); } @Async @@ -128,36 +139,16 @@ public class MockGenerateImagesService implements GenerateImagesUseCase { } // Job 상태 업데이트: COMPLETED - Job completedJob = Job.builder() - .id(jobId) - .eventDraftId(command.getEventDraftId()) - .jobType("image-generation") - .status(Job.Status.COMPLETED) - .progress(100) - .resultMessage(String.format("%d개의 이미지가 성공적으로 생성되었습니다.", images.size())) - .createdAt(java.time.LocalDateTime.now()) - .updatedAt(java.time.LocalDateTime.now()) - .build(); - - jobWriter.save(completedJob); + String resultMessage = String.format("%d개의 이미지가 성공적으로 생성되었습니다.", images.size()); + jobWriter.updateJobStatus(jobId, "COMPLETED", 100); + jobWriter.updateJobResult(jobId, resultMessage); log.info("[MOCK] Job 완료: jobId={}, 생성된 이미지 수={}", jobId, images.size()); } catch (Exception e) { log.error("[MOCK] 이미지 생성 실패: jobId={}", jobId, e); // Job 상태 업데이트: FAILED - Job failedJob = Job.builder() - .id(jobId) - .eventDraftId(command.getEventDraftId()) - .jobType("image-generation") - .status(Job.Status.FAILED) - .progress(0) - .errorMessage(e.getMessage()) - .createdAt(java.time.LocalDateTime.now()) - .updatedAt(java.time.LocalDateTime.now()) - .build(); - - jobWriter.save(failedJob); + jobWriter.updateJobError(jobId, e.getMessage()); } } } diff --git a/content-service/src/main/java/com/kt/event/content/biz/service/mock/MockRegenerateImageService.java b/content-service/src/main/java/com/kt/event/content/biz/service/mock/MockRegenerateImageService.java index e1aac30..b92fe43 100644 --- a/content-service/src/main/java/com/kt/event/content/biz/service/mock/MockRegenerateImageService.java +++ b/content-service/src/main/java/com/kt/event/content/biz/service/mock/MockRegenerateImageService.java @@ -3,6 +3,7 @@ package com.kt.event.content.biz.service.mock; import com.kt.event.content.biz.domain.Job; import com.kt.event.content.biz.dto.ContentCommand; import com.kt.event.content.biz.dto.JobInfo; +import com.kt.event.content.biz.dto.RedisJobData; import com.kt.event.content.biz.usecase.in.RegenerateImageUseCase; import com.kt.event.content.biz.usecase.out.JobWriter; import lombok.RequiredArgsConstructor; @@ -41,11 +42,21 @@ public class MockRegenerateImageService implements RegenerateImageUseCase { .updatedAt(java.time.LocalDateTime.now()) .build(); - // Job 저장 - Job savedJob = jobWriter.save(job); + // Job 저장 (Job 도메인을 RedisJobData로 변환) + RedisJobData jobData = RedisJobData.builder() + .id(job.getId()) + .eventDraftId(job.getEventDraftId()) + .jobType(job.getJobType()) + .status(job.getStatus().name()) + .progress(job.getProgress()) + .createdAt(job.getCreatedAt()) + .updatedAt(job.getUpdatedAt()) + .build(); + + jobWriter.saveJob(jobData, 3600); // TTL 1시간 log.info("[MOCK] 재생성 Job 생성 완료: jobId={}", jobId); - return JobInfo.from(savedJob); + return JobInfo.from(job); } } diff --git a/content-service/src/main/java/com/kt/event/content/biz/usecase/out/JobReader.java b/content-service/src/main/java/com/kt/event/content/biz/usecase/out/JobReader.java index de6f982..d5cdf12 100644 --- a/content-service/src/main/java/com/kt/event/content/biz/usecase/out/JobReader.java +++ b/content-service/src/main/java/com/kt/event/content/biz/usecase/out/JobReader.java @@ -1,6 +1,5 @@ package com.kt.event.content.biz.usecase.out; -import com.kt.event.content.biz.domain.Job; import com.kt.event.content.biz.dto.RedisJobData; import java.util.Optional; @@ -17,13 +16,4 @@ public interface JobReader { * @return Job 데이터 */ Optional getJob(String jobId); - - /** - * 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정) - * JPA 기반 JobGateway에서만 사용 - * - * @param jobId Job ID - * @return Job 도메인 객체 - */ - Optional findById(String jobId); } diff --git a/content-service/src/main/java/com/kt/event/content/biz/usecase/out/JobWriter.java b/content-service/src/main/java/com/kt/event/content/biz/usecase/out/JobWriter.java index 3286f4a..e89b89a 100644 --- a/content-service/src/main/java/com/kt/event/content/biz/usecase/out/JobWriter.java +++ b/content-service/src/main/java/com/kt/event/content/biz/usecase/out/JobWriter.java @@ -1,6 +1,5 @@ package com.kt.event.content.biz.usecase.out; -import com.kt.event.content.biz.domain.Job; import com.kt.event.content.biz.dto.RedisJobData; /** @@ -40,13 +39,4 @@ public interface JobWriter { * @param errorMessage 에러 메시지 */ void updateJobError(String jobId, String errorMessage); - - /** - * 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정) - * JPA 기반 JobGateway에서만 사용 - * - * @param job Job 도메인 객체 - * @return 저장된 Job - */ - Job save(Job job); } diff --git a/content-service/src/main/java/com/kt/event/content/infra/ContentApplication.java b/content-service/src/main/java/com/kt/event/content/infra/ContentApplication.java index ebe6902..da40634 100644 --- a/content-service/src/main/java/com/kt/event/content/infra/ContentApplication.java +++ b/content-service/src/main/java/com/kt/event/content/infra/ContentApplication.java @@ -2,24 +2,16 @@ package com.kt.event.content.infra; 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.EnableJpaAuditing; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.scheduling.annotation.EnableAsync; /** * Content Service Application + * Phase 3: JPA removed, using Redis for storage */ @SpringBootApplication(scanBasePackages = { "com.kt.event.content", "com.kt.event.common" }) -@EntityScan(basePackages = { - "com.kt.event.content.infra.gateway.entity", - "com.kt.event.common.entity" -}) -@EnableJpaRepositories(basePackages = "com.kt.event.content.infra.gateway.repository") -@EnableJpaAuditing @EnableAsync public class ContentApplication { diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/ContentGateway.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/ContentGateway.java deleted file mode 100644 index 305bc0e..0000000 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/ContentGateway.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.kt.event.content.infra.gateway; - -import com.kt.event.content.biz.domain.Content; -import com.kt.event.content.biz.domain.GeneratedImage; -import com.kt.event.content.biz.usecase.out.ContentReader; -import com.kt.event.content.biz.usecase.out.ContentWriter; -import com.kt.event.content.infra.gateway.entity.ContentEntity; -import com.kt.event.content.infra.gateway.entity.GeneratedImageEntity; -import com.kt.event.content.infra.gateway.repository.ContentJpaRepository; -import com.kt.event.content.infra.gateway.repository.GeneratedImageJpaRepository; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -/** - * Content 영속성 Gateway - * ContentReader, ContentWriter outbound port 구현 - */ -@Slf4j -@Component -@RequiredArgsConstructor -public class ContentGateway implements ContentReader, ContentWriter { - - private final ContentJpaRepository contentRepository; - private final GeneratedImageJpaRepository imageRepository; - - // ======================================== - // ContentReader 구현 - // ======================================== - - @Override - @Transactional(readOnly = true) - public Optional findByEventDraftIdWithImages(Long eventDraftId) { - log.debug("이벤트 콘텐츠 조회 (with images): eventDraftId={}", eventDraftId); - return contentRepository.findByEventDraftIdWithImages(eventDraftId) - .map(ContentEntity::toDomain); - } - - @Override - @Transactional(readOnly = true) - public Optional findImageById(Long imageId) { - log.debug("이미지 조회: imageId={}", imageId); - return imageRepository.findById(imageId) - .map(GeneratedImageEntity::toDomain); - } - - @Override - @Transactional(readOnly = true) - public List findImagesByEventDraftId(Long eventDraftId) { - log.debug("이미지 목록 조회: eventDraftId={}", eventDraftId); - return imageRepository.findByEventDraftId(eventDraftId).stream() - .map(GeneratedImageEntity::toDomain) - .collect(Collectors.toList()); - } - - // ======================================== - // ContentWriter 구현 - // ======================================== - - @Override - @Transactional - public Content save(Content content) { - log.debug("콘텐츠 저장: eventDraftId={}", content.getEventDraftId()); - - // Content Entity 조회 또는 생성 - ContentEntity contentEntity = contentRepository.findByEventDraftId(content.getEventDraftId()) - .orElseGet(() -> ContentEntity.create( - content.getEventDraftId(), - content.getEventTitle(), - content.getEventDescription() - )); - - // Content 업데이트 - contentEntity.update(content.getEventTitle(), content.getEventDescription()); - - // 저장 - ContentEntity saved = contentRepository.save(contentEntity); - - return saved.toDomain(); - } - - @Override - @Transactional - public GeneratedImage saveImage(GeneratedImage image) { - log.debug("이미지 저장: eventDraftId={}, style={}, platform={}", - image.getEventDraftId(), image.getStyle(), image.getPlatform()); - - // Content Entity 조회 - ContentEntity contentEntity = contentRepository.findByEventDraftId(image.getEventDraftId()) - .orElseThrow(() -> new IllegalStateException("Content를 먼저 저장해야 합니다")); - - // GeneratedImageEntity 생성 - GeneratedImageEntity imageEntity = GeneratedImageEntity.create( - image.getEventDraftId(), - image.getStyle(), - image.getPlatform(), - image.getCdnUrl(), - image.getPrompt() - ); - - // Content와 연결 - contentEntity.addImage(imageEntity); - - // 선택 상태 설정 - if (image.isSelected()) { - imageEntity.select(); - } - - // 저장 - GeneratedImageEntity saved = imageRepository.save(imageEntity); - - return saved.toDomain(); - } -} diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/JobGateway.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/JobGateway.java deleted file mode 100644 index 54efe06..0000000 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/JobGateway.java +++ /dev/null @@ -1,180 +0,0 @@ -package com.kt.event.content.infra.gateway; - -import com.kt.event.content.biz.domain.Job; -import com.kt.event.content.biz.dto.RedisJobData; -import com.kt.event.content.biz.usecase.out.JobReader; -import com.kt.event.content.biz.usecase.out.JobWriter; -import com.kt.event.content.infra.gateway.entity.JobEntity; -import com.kt.event.content.infra.gateway.repository.JobJpaRepository; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -/** - * Job 영속성 Gateway - * JobReader, JobWriter outbound port 구현 - * Phase 3에서 삭제 예정 - */ -@Slf4j -@Component -@Primary -@RequiredArgsConstructor -public class JobGateway implements JobReader, JobWriter { - - private final JobJpaRepository jobRepository; - - // ======================================== - // JobReader 구현 - // ======================================== - - @Override - @Transactional(readOnly = true) - public Optional getJob(String jobId) { - log.debug("[JPA] Job 조회: jobId={}", jobId); - return jobRepository.findById(jobId) - .map(entity -> RedisJobData.builder() - .id(entity.getId()) - .eventDraftId(entity.getEventDraftId()) - .jobType(entity.getJobType()) - .status(entity.getStatus().name()) - .progress(entity.getProgress()) - .resultMessage(entity.getResultMessage()) - .errorMessage(entity.getErrorMessage()) - .createdAt(entity.getCreatedAt()) - .updatedAt(entity.getUpdatedAt()) - .build()); - } - - /** - * 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정) - */ - @Transactional(readOnly = true) - public Optional findById(String jobId) { - log.debug("Job 조회: jobId={}", jobId); - return jobRepository.findById(jobId) - .map(JobEntity::toDomain); - } - - /** - * 이벤트별 Job 조회 (추가 메서드) - */ - @Transactional(readOnly = true) - public List findByEventDraftId(Long eventDraftId) { - log.debug("이벤트별 Job 조회: eventDraftId={}", eventDraftId); - return jobRepository.findByEventDraftId(eventDraftId).stream() - .map(JobEntity::toDomain) - .collect(Collectors.toList()); - } - - /** - * 최신 Job 조회 (추가 메서드) - */ - @Transactional(readOnly = true) - public Optional findLatestByEventDraftIdAndJobType(Long eventDraftId, String jobType) { - log.debug("최신 Job 조회: eventDraftId={}, jobType={}", eventDraftId, jobType); - return jobRepository.findFirstByEventDraftIdAndJobTypeOrderByCreatedAtDesc(eventDraftId, jobType) - .map(JobEntity::toDomain); - } - - // ======================================== - // JobWriter 구현 - // ======================================== - - @Override - @Transactional - public void saveJob(RedisJobData jobData, long ttlSeconds) { - log.debug("[JPA] Job 저장: jobId={}, status={}, ttl={}초", jobData.getId(), jobData.getStatus(), ttlSeconds); - - JobEntity entity = jobRepository.findById(jobData.getId()) - .orElseGet(() -> JobEntity.create( - jobData.getId(), - jobData.getEventDraftId(), - jobData.getJobType() - )); - - // Job 상태 업데이트 - entity.updateStatus(Job.Status.valueOf(jobData.getStatus()), jobData.getProgress()); - if (jobData.getResultMessage() != null) { - entity.setResultMessage(jobData.getResultMessage()); - } - if (jobData.getErrorMessage() != null) { - entity.setErrorMessage(jobData.getErrorMessage()); - } - - jobRepository.save(entity); - // Note: TTL은 JPA에서는 무시됨 (Redis 전용) - } - - @Override - @Transactional - public void updateJobStatus(String jobId, String status, Integer progress) { - log.debug("[JPA] Job 상태 업데이트: jobId={}, status={}, progress={}", jobId, status, progress); - jobRepository.findById(jobId).ifPresent(entity -> { - entity.updateStatus(Job.Status.valueOf(status), progress); - jobRepository.save(entity); - }); - } - - @Override - @Transactional - public void updateJobResult(String jobId, String resultMessage) { - log.debug("[JPA] Job 결과 업데이트: jobId={}, resultMessage={}", jobId, resultMessage); - jobRepository.findById(jobId).ifPresent(entity -> { - entity.setResultMessage(resultMessage); - jobRepository.save(entity); - }); - } - - @Override - @Transactional - public void updateJobError(String jobId, String errorMessage) { - log.debug("[JPA] Job 에러 업데이트: jobId={}, errorMessage={}", jobId, errorMessage); - jobRepository.findById(jobId).ifPresent(entity -> { - entity.setErrorMessage(errorMessage); - entity.updateStatus(Job.Status.FAILED, entity.getProgress()); - jobRepository.save(entity); - }); - } - - /** - * 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정) - */ - @Transactional - public Job save(Job job) { - log.debug("Job 저장: jobId={}, status={}", job.getId(), job.getStatus()); - - JobEntity entity = jobRepository.findById(job.getId()) - .orElseGet(() -> JobEntity.create( - job.getId(), - job.getEventDraftId(), - job.getJobType() - )); - - // Job 상태 업데이트 - entity.updateStatus(job.getStatus(), job.getProgress()); - if (job.getResultMessage() != null) { - entity.setResultMessage(job.getResultMessage()); - } - if (job.getErrorMessage() != null) { - entity.setErrorMessage(job.getErrorMessage()); - } - - JobEntity saved = jobRepository.save(entity); - return saved.toDomain(); - } - - /** - * Job 삭제 (추가 메서드) - */ - @Transactional - public void delete(String jobId) { - log.debug("Job 삭제: jobId={}", jobId); - jobRepository.deleteById(jobId); - } -} diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/RedisGateway.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/RedisGateway.java index bcae8fb..bd7845e 100644 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/RedisGateway.java +++ b/content-service/src/main/java/com/kt/event/content/infra/gateway/RedisGateway.java @@ -317,55 +317,6 @@ public class RedisGateway implements RedisAIDataReader, RedisImageWriter, ImageW } } - /** - * 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정) - * Job 도메인 객체를 RedisJobData로 변환하여 저장 - * - * @param job Job 도메인 객체 - * @return 저장된 Job - */ - @Override - public Job save(Job job) { - log.debug("[Redis] Job 저장 (호환성): jobId={}, status={}", job.getId(), job.getStatus()); - - RedisJobData jobData = RedisJobData.builder() - .id(job.getId()) - .eventDraftId(job.getEventDraftId()) - .jobType(job.getJobType()) - .status(job.getStatus().name()) - .progress(job.getProgress()) - .resultMessage(job.getResultMessage()) - .errorMessage(job.getErrorMessage()) - .createdAt(job.getCreatedAt()) - .updatedAt(job.getUpdatedAt()) - .build(); - - saveJob(jobData, 86400); // 24시간 TTL - return job; - } - - /** - * 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정) - * - * @param jobId Job ID - * @return Job 도메인 객체 - */ - @Override - public Optional findById(String jobId) { - log.debug("[Redis] Job 조회 (호환성): jobId={}", jobId); - return getJob(jobId).map(data -> Job.builder() - .id(data.getId()) - .eventDraftId(data.getEventDraftId()) - .jobType(data.getJobType()) - .status(Job.Status.valueOf(data.getStatus())) - .progress(data.getProgress()) - .resultMessage(data.getResultMessage()) - .errorMessage(data.getErrorMessage()) - .createdAt(data.getCreatedAt()) - .updatedAt(data.getUpdatedAt()) - .build()); - } - // ==================== Helper Methods ==================== private String getString(Map map, String key) { diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/entity/ContentEntity.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/entity/ContentEntity.java deleted file mode 100644 index 5b57ce6..0000000 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/entity/ContentEntity.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.kt.event.content.infra.gateway.entity; - -import com.kt.event.common.entity.BaseTimeEntity; -import com.kt.event.content.biz.domain.Content; -import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * 콘텐츠 엔티티 - * 이벤트에 대한 전체 콘텐츠 정보를 저장 - */ -@Entity -@Table(name = "contents") -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor -public class ContentEntity extends BaseTimeEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** - * 이벤트 ID (이벤트 초안 ID) - */ - @Column(name = "event_draft_id", nullable = false) - private Long eventDraftId; - - /** - * 이벤트 제목 - */ - @Column(name = "event_title", nullable = false, length = 200) - private String eventTitle; - - /** - * 이벤트 설명 - */ - @Column(name = "event_description", columnDefinition = "TEXT") - private String eventDescription; - - /** - * 생성된 이미지 목록 - */ - @OneToMany(mappedBy = "content", cascade = CascadeType.ALL, orphanRemoval = true) - private List images = new ArrayList<>(); - - /** - * 정적 팩토리 메서드: 새 콘텐츠 생성 - * - * @param eventDraftId 이벤트 초안 ID - * @param eventTitle 이벤트 제목 - * @param eventDescription 이벤트 설명 - * @return ContentEntity - */ - public static ContentEntity create(Long eventDraftId, String eventTitle, String eventDescription) { - ContentEntity entity = new ContentEntity(); - entity.eventDraftId = eventDraftId; - entity.eventTitle = eventTitle; - entity.eventDescription = eventDescription; - return entity; - } - - /** - * 도메인 모델로 변환 - * - * @return Content 도메인 모델 - */ - public Content toDomain() { - return Content.builder() - .id(id) - .eventDraftId(eventDraftId) - .eventTitle(eventTitle) - .eventDescription(eventDescription) - .images(images.stream() - .map(GeneratedImageEntity::toDomain) - .collect(Collectors.toList())) - .createdAt(getCreatedAt()) - .updatedAt(getUpdatedAt()) - .build(); - } - - /** - * 콘텐츠 정보 업데이트 - * - * @param eventTitle 이벤트 제목 - * @param eventDescription 이벤트 설명 - */ - public void update(String eventTitle, String eventDescription) { - this.eventTitle = eventTitle; - this.eventDescription = eventDescription; - } - - /** - * 이미지 추가 - * - * @param image 생성된 이미지 엔티티 - */ - public void addImage(GeneratedImageEntity image) { - images.add(image); - image.assignContent(this); - } -} diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/entity/GeneratedImageEntity.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/entity/GeneratedImageEntity.java deleted file mode 100644 index b90e75b..0000000 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/entity/GeneratedImageEntity.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.kt.event.content.infra.gateway.entity; - -import com.kt.event.common.entity.BaseTimeEntity; -import com.kt.event.content.biz.domain.GeneratedImage; -import com.kt.event.content.biz.domain.ImageStyle; -import com.kt.event.content.biz.domain.Platform; -import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; - -/** - * 생성된 이미지 엔티티 - * AI가 생성한 이미지 정보를 저장 - */ -@Entity -@Table(name = "generated_images", indexes = { - @Index(name = "idx_event_draft_id", columnList = "event_draft_id"), - @Index(name = "idx_style_platform", columnList = "style,platform") -}) -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor -public class GeneratedImageEntity extends BaseTimeEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** - * 콘텐츠 (양방향 관계) - */ - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "content_id") - private ContentEntity content; - - /** - * 이벤트 ID (이벤트 초안 ID) - */ - @Column(name = "event_draft_id", nullable = false) - private Long eventDraftId; - - /** - * 이미지 스타일 - */ - @Enumerated(EnumType.STRING) - @Column(name = "style", nullable = false, length = 20) - private ImageStyle style; - - /** - * 플랫폼 - */ - @Enumerated(EnumType.STRING) - @Column(name = "platform", nullable = false, length = 20) - private Platform platform; - - /** - * CDN URL (Azure Blob Storage) - */ - @Column(name = "cdn_url", nullable = false, length = 500) - private String cdnUrl; - - /** - * 프롬프트 - */ - @Column(name = "prompt", columnDefinition = "TEXT") - private String prompt; - - /** - * 선택 여부 - */ - @Column(name = "selected", nullable = false) - private boolean selected; - - /** - * 정적 팩토리 메서드: 새 이미지 생성 - * - * @param eventDraftId 이벤트 초안 ID - * @param style 이미지 스타일 - * @param platform 플랫폼 - * @param cdnUrl CDN URL - * @param prompt 프롬프트 - * @return GeneratedImageEntity - */ - public static GeneratedImageEntity create(Long eventDraftId, ImageStyle style, Platform platform, - String cdnUrl, String prompt) { - GeneratedImageEntity entity = new GeneratedImageEntity(); - entity.eventDraftId = eventDraftId; - entity.style = style; - entity.platform = platform; - entity.cdnUrl = cdnUrl; - entity.prompt = prompt; - entity.selected = false; - return entity; - } - - /** - * 도메인 모델로 변환 - * - * @return GeneratedImage 도메인 모델 - */ - public GeneratedImage toDomain() { - return GeneratedImage.builder() - .id(id) - .eventDraftId(eventDraftId) - .style(style) - .platform(platform) - .cdnUrl(cdnUrl) - .prompt(prompt) - .selected(selected) - .createdAt(getCreatedAt()) - .updatedAt(getUpdatedAt()) - .build(); - } - - /** - * 콘텐츠 할당 (양방향 관계 설정용) - * - * @param content 콘텐츠 엔티티 - */ - protected void assignContent(ContentEntity content) { - this.content = content; - } - - /** - * 이미지 선택 - */ - public void select() { - this.selected = true; - } - - /** - * 이미지 선택 해제 - */ - public void deselect() { - this.selected = false; - } -} diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/entity/JobEntity.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/entity/JobEntity.java deleted file mode 100644 index 82839fc..0000000 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/entity/JobEntity.java +++ /dev/null @@ -1,172 +0,0 @@ -package com.kt.event.content.infra.gateway.entity; - -import com.kt.event.common.entity.BaseTimeEntity; -import com.kt.event.content.biz.domain.Job; -import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; - -/** - * Job 엔티티 - * 이미지 생성 작업 정보를 저장 - */ -@Entity -@Table(name = "jobs", indexes = { - @Index(name = "idx_event_draft_id", columnList = "event_draft_id"), - @Index(name = "idx_status", columnList = "status") -}) -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor -public class JobEntity extends BaseTimeEntity { - - @Id - @Column(name = "id", length = 36) - private String id; - - /** - * 이벤트 ID (이벤트 초안 ID) - */ - @Column(name = "event_draft_id", nullable = false) - private Long eventDraftId; - - /** - * Job 타입 - */ - @Column(name = "job_type", nullable = false, length = 50) - private String jobType; - - /** - * Job 상태 - */ - @Enumerated(EnumType.STRING) - @Column(name = "status", nullable = false, length = 20) - private Job.Status status; - - /** - * 진행률 (0-100) - */ - @Column(name = "progress", nullable = false) - private int progress; - - /** - * 결과 메시지 - */ - @Column(name = "result_message", columnDefinition = "TEXT") - private String resultMessage; - - /** - * 에러 메시지 - */ - @Column(name = "error_message", columnDefinition = "TEXT") - private String errorMessage; - - /** - * 정적 팩토리 메서드: 새 Job 생성 - * - * @param id Job ID (UUID) - * @param eventDraftId 이벤트 초안 ID - * @param jobType Job 타입 - * @return JobEntity - */ - public static JobEntity create(String id, Long eventDraftId, String jobType) { - JobEntity entity = new JobEntity(); - entity.id = id; - entity.eventDraftId = eventDraftId; - entity.jobType = jobType; - entity.status = Job.Status.PENDING; - entity.progress = 0; - return entity; - } - - /** - * 도메인 모델로 변환 - * - * @return Job 도메인 모델 - */ - public Job toDomain() { - return Job.builder() - .id(id) - .eventDraftId(eventDraftId) - .jobType(jobType) - .status(status) - .progress(progress) - .resultMessage(resultMessage) - .errorMessage(errorMessage) - .createdAt(getCreatedAt()) - .updatedAt(getUpdatedAt()) - .build(); - } - - /** - * Job 시작 - */ - public void start() { - this.status = Job.Status.PROCESSING; - this.progress = 0; - } - - /** - * 진행률 업데이트 - * - * @param progress 진행률 (0-100) - */ - public void updateProgress(int progress) { - if (progress < 0 || progress > 100) { - throw new IllegalArgumentException("진행률은 0-100 사이여야 합니다"); - } - this.progress = progress; - } - - /** - * Job 완료 처리 - * - * @param resultMessage 결과 메시지 - */ - public void complete(String resultMessage) { - this.status = Job.Status.COMPLETED; - this.progress = 100; - this.resultMessage = resultMessage; - } - - /** - * Job 실패 처리 - * - * @param errorMessage 에러 메시지 - */ - public void fail(String errorMessage) { - this.status = Job.Status.FAILED; - this.errorMessage = errorMessage; - } - - /** - * Job 상태 업데이트 - * - * @param status 새 상태 - * @param progress 진행률 - */ - public void updateStatus(Job.Status status, int progress) { - this.status = status; - this.progress = progress; - } - - /** - * 결과 메시지 설정 - * - * @param resultMessage 결과 메시지 - */ - public void setResultMessage(String resultMessage) { - this.resultMessage = resultMessage; - } - - /** - * 에러 메시지 설정 - * - * @param errorMessage 에러 메시지 - */ - public void setErrorMessage(String errorMessage) { - this.errorMessage = errorMessage; - } -} diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/mock/MockRedisGateway.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/mock/MockRedisGateway.java index dd09350..417ca40 100644 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/mock/MockRedisGateway.java +++ b/content-service/src/main/java/com/kt/event/content/infra/gateway/mock/MockRedisGateway.java @@ -1,11 +1,14 @@ package com.kt.event.content.infra.gateway.mock; +import com.kt.event.content.biz.domain.Content; import com.kt.event.content.biz.domain.GeneratedImage; import com.kt.event.content.biz.domain.ImageStyle; import com.kt.event.content.biz.domain.Job; import com.kt.event.content.biz.domain.Platform; import com.kt.event.content.biz.dto.RedisImageData; import com.kt.event.content.biz.dto.RedisJobData; +import com.kt.event.content.biz.usecase.out.ContentReader; +import com.kt.event.content.biz.usecase.out.ContentWriter; import com.kt.event.content.biz.usecase.out.ImageReader; import com.kt.event.content.biz.usecase.out.ImageWriter; import com.kt.event.content.biz.usecase.out.JobReader; @@ -13,6 +16,7 @@ import com.kt.event.content.biz.usecase.out.JobWriter; import com.kt.event.content.biz.usecase.out.RedisAIDataReader; import com.kt.event.content.biz.usecase.out.RedisImageWriter; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; @@ -31,12 +35,15 @@ import java.util.stream.Collectors; */ @Slf4j @Component +@Primary @Profile({"local", "test"}) -public class MockRedisGateway implements RedisAIDataReader, RedisImageWriter, ImageWriter, ImageReader, JobWriter, JobReader { +public class MockRedisGateway implements RedisAIDataReader, RedisImageWriter, ImageWriter, ImageReader, JobWriter, JobReader, ContentReader, ContentWriter { private final Map> aiDataCache = new HashMap<>(); - // In-memory storage for images and jobs + // In-memory storage for contents, images, and jobs + private final Map contentStorage = new ConcurrentHashMap<>(); + private final Map imageByIdStorage = new ConcurrentHashMap<>(); private final Map imageStorage = new ConcurrentHashMap<>(); private final Map jobStorage = new ConcurrentHashMap<>(); @@ -259,52 +266,136 @@ public class MockRedisGateway implements RedisAIDataReader, RedisImageWriter, Im } } + // ==================== ContentReader 구현 ==================== + /** - * 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정) - * Job 도메인 객체를 RedisJobData로 변환하여 저장 - * - * @param job Job 도메인 객체 - * @return 저장된 Job + * 이벤트 초안 ID로 콘텐츠 조회 (이미지 목록 포함) */ @Override - public Job save(Job job) { - log.debug("[MOCK] Job 저장 (호환성): jobId={}, status={}", job.getId(), job.getStatus()); + public Optional findByEventDraftIdWithImages(Long eventDraftId) { + try { + Content content = contentStorage.get(eventDraftId); + if (content == null) { + log.warn("[MOCK] Content를 찾을 수 없음: eventDraftId={}", eventDraftId); + return Optional.empty(); + } - RedisJobData jobData = RedisJobData.builder() - .id(job.getId()) - .eventDraftId(job.getEventDraftId()) - .jobType(job.getJobType()) - .status(job.getStatus().name()) - .progress(job.getProgress()) - .resultMessage(job.getResultMessage()) - .errorMessage(job.getErrorMessage()) - .createdAt(job.getCreatedAt()) - .updatedAt(job.getUpdatedAt()) - .build(); + // 이미지 목록 조회 및 Content 재생성 (immutable pattern) + List images = findImagesByEventDraftId(eventDraftId); + Content contentWithImages = Content.builder() + .id(content.getId()) + .eventDraftId(content.getEventDraftId()) + .eventTitle(content.getEventTitle()) + .eventDescription(content.getEventDescription()) + .images(images) + .createdAt(content.getCreatedAt()) + .updatedAt(content.getUpdatedAt()) + .build(); - saveJob(jobData, 86400); // 24시간 TTL - return job; + return Optional.of(contentWithImages); + } catch (Exception e) { + log.error("[MOCK] Content 조회 실패: eventDraftId={}", eventDraftId, e); + return Optional.empty(); + } } /** - * 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정) - * - * @param jobId Job ID - * @return Job 도메인 객체 + * 이미지 ID로 이미지 조회 */ @Override - public Optional findById(String jobId) { - log.debug("[MOCK] Job 조회 (호환성): jobId={}", jobId); - return getJob(jobId).map(data -> Job.builder() - .id(data.getId()) - .eventDraftId(data.getEventDraftId()) - .jobType(data.getJobType()) - .status(Job.Status.valueOf(data.getStatus())) - .progress(data.getProgress()) - .resultMessage(data.getResultMessage()) - .errorMessage(data.getErrorMessage()) - .createdAt(data.getCreatedAt()) - .updatedAt(data.getUpdatedAt()) - .build()); + public Optional findImageById(Long imageId) { + try { + GeneratedImage image = imageByIdStorage.get(imageId); + if (image == null) { + log.warn("[MOCK] 이미지를 찾을 수 없음: imageId={}", imageId); + return Optional.empty(); + } + return Optional.of(image); + } catch (Exception e) { + log.error("[MOCK] 이미지 조회 실패: imageId={}", imageId, e); + return Optional.empty(); + } + } + + /** + * 이벤트 초안 ID로 이미지 목록 조회 + */ + @Override + public List findImagesByEventDraftId(Long eventDraftId) { + try { + return imageByIdStorage.values().stream() + .filter(image -> image.getEventDraftId().equals(eventDraftId)) + .collect(Collectors.toList()); + } catch (Exception e) { + log.error("[MOCK] 이미지 목록 조회 실패: eventDraftId={}", eventDraftId, e); + return new ArrayList<>(); + } + } + + // ==================== ContentWriter 구현 ==================== + + private static Long nextContentId = 1L; + private static Long nextImageId = 1L; + + /** + * 콘텐츠 저장 + */ + @Override + public Content save(Content content) { + try { + // ID가 없으면 생성하여 새 Content 객체 생성 (immutable pattern) + Long id = content.getId() != null ? content.getId() : nextContentId++; + + Content savedContent = Content.builder() + .id(id) + .eventDraftId(content.getEventDraftId()) + .eventTitle(content.getEventTitle()) + .eventDescription(content.getEventDescription()) + .images(content.getImages()) + .createdAt(content.getCreatedAt()) + .updatedAt(content.getUpdatedAt()) + .build(); + + contentStorage.put(savedContent.getEventDraftId(), savedContent); + log.info("[MOCK] Content 저장 완료: contentId={}, eventDraftId={}", + savedContent.getId(), savedContent.getEventDraftId()); + + return savedContent; + } catch (Exception e) { + log.error("[MOCK] Content 저장 실패: eventDraftId={}", content.getEventDraftId(), e); + throw e; + } + } + + /** + * 이미지 저장 + */ + @Override + public GeneratedImage saveImage(GeneratedImage image) { + try { + // ID가 없으면 생성하여 새 GeneratedImage 객체 생성 (immutable pattern) + Long id = image.getId() != null ? image.getId() : nextImageId++; + + GeneratedImage savedImage = GeneratedImage.builder() + .id(id) + .eventDraftId(image.getEventDraftId()) + .style(image.getStyle()) + .platform(image.getPlatform()) + .cdnUrl(image.getCdnUrl()) + .prompt(image.getPrompt()) + .selected(image.isSelected()) + .createdAt(image.getCreatedAt()) + .updatedAt(image.getUpdatedAt()) + .build(); + + imageByIdStorage.put(savedImage.getId(), savedImage); + log.info("[MOCK] 이미지 저장 완료: imageId={}, eventDraftId={}, style={}, platform={}", + savedImage.getId(), savedImage.getEventDraftId(), savedImage.getStyle(), savedImage.getPlatform()); + + return savedImage; + } catch (Exception e) { + log.error("[MOCK] 이미지 저장 실패: eventDraftId={}", image.getEventDraftId(), e); + throw e; + } } } diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/repository/ContentJpaRepository.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/repository/ContentJpaRepository.java deleted file mode 100644 index 927c63d..0000000 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/repository/ContentJpaRepository.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.kt.event.content.infra.gateway.repository; - -import com.kt.event.content.infra.gateway.entity.ContentEntity; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; - -import java.util.Optional; - -/** - * 콘텐츠 JPA 리포지토리 - */ -public interface ContentJpaRepository extends JpaRepository { - - /** - * 이벤트 초안 ID로 콘텐츠 조회 (이미지 목록 포함) - * - * @param eventDraftId 이벤트 초안 ID - * @return 콘텐츠 엔티티 - */ - @Query("SELECT DISTINCT c FROM ContentEntity c " + - "LEFT JOIN FETCH c.images " + - "WHERE c.eventDraftId = :eventDraftId") - Optional findByEventDraftIdWithImages(@Param("eventDraftId") Long eventDraftId); - - /** - * 이벤트 초안 ID로 콘텐츠 조회 - * - * @param eventDraftId 이벤트 초안 ID - * @return 콘텐츠 엔티티 - */ - Optional findByEventDraftId(Long eventDraftId); - - /** - * 이벤트 초안 ID로 콘텐츠 존재 여부 확인 - * - * @param eventDraftId 이벤트 초안 ID - * @return 존재 여부 - */ - boolean existsByEventDraftId(Long eventDraftId); -} diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/repository/GeneratedImageJpaRepository.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/repository/GeneratedImageJpaRepository.java deleted file mode 100644 index 9156916..0000000 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/repository/GeneratedImageJpaRepository.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.kt.event.content.infra.gateway.repository; - -import com.kt.event.content.biz.domain.ImageStyle; -import com.kt.event.content.biz.domain.Platform; -import com.kt.event.content.infra.gateway.entity.GeneratedImageEntity; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; - -import java.util.List; - -/** - * 생성된 이미지 JPA 리포지토리 - */ -public interface GeneratedImageJpaRepository extends JpaRepository { - - /** - * 이벤트 초안 ID로 이미지 목록 조회 - * - * @param eventDraftId 이벤트 초안 ID - * @return 이미지 엔티티 목록 - */ - List findByEventDraftId(Long eventDraftId); - - /** - * 이벤트 초안 ID와 스타일로 이미지 목록 조회 - * - * @param eventDraftId 이벤트 초안 ID - * @param style 이미지 스타일 - * @return 이미지 엔티티 목록 - */ - List findByEventDraftIdAndStyle(Long eventDraftId, ImageStyle style); - - /** - * 이벤트 초안 ID와 플랫폼으로 이미지 목록 조회 - * - * @param eventDraftId 이벤트 초안 ID - * @param platform 플랫폼 - * @return 이미지 엔티티 목록 - */ - List findByEventDraftIdAndPlatform(Long eventDraftId, Platform platform); - - /** - * 이벤트 초안 ID와 선택 여부로 이미지 목록 조회 - * - * @param eventDraftId 이벤트 초안 ID - * @param selected 선택 여부 - * @return 이미지 엔티티 목록 - */ - List findByEventDraftIdAndSelected(Long eventDraftId, boolean selected); - - /** - * 이벤트 초안 ID로 선택된 이미지 목록 조회 - * - * @param eventDraftId 이벤트 초안 ID - * @return 선택된 이미지 엔티티 목록 - */ - @Query("SELECT i FROM GeneratedImageEntity i WHERE i.eventDraftId = :eventDraftId AND i.selected = true") - List findSelectedImages(@Param("eventDraftId") Long eventDraftId); - - /** - * 이벤트 초안 ID로 모든 이미지 선택 해제 - * - * @param eventDraftId 이벤트 초안 ID - */ - @Query("UPDATE GeneratedImageEntity i SET i.selected = false WHERE i.eventDraftId = :eventDraftId") - void deselectAllByEventDraftId(@Param("eventDraftId") Long eventDraftId); -} diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/repository/JobJpaRepository.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/repository/JobJpaRepository.java deleted file mode 100644 index 2001f36..0000000 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/repository/JobJpaRepository.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.kt.event.content.infra.gateway.repository; - -import com.kt.event.content.biz.domain.Job; -import com.kt.event.content.infra.gateway.entity.JobEntity; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.List; -import java.util.Optional; - -/** - * Job JPA 리포지토리 - */ -public interface JobJpaRepository extends JpaRepository { - - /** - * 이벤트 초안 ID로 Job 목록 조회 - * - * @param eventDraftId 이벤트 초안 ID - * @return Job 엔티티 목록 - */ - List findByEventDraftId(Long eventDraftId); - - /** - * 이벤트 초안 ID와 상태로 Job 목록 조회 - * - * @param eventDraftId 이벤트 초안 ID - * @param status Job 상태 - * @return Job 엔티티 목록 - */ - List findByEventDraftIdAndStatus(Long eventDraftId, Job.Status status); - - /** - * 이벤트 초안 ID와 Job 타입으로 최신 Job 조회 - * - * @param eventDraftId 이벤트 초안 ID - * @param jobType Job 타입 - * @return Job 엔티티 - */ - Optional findFirstByEventDraftIdAndJobTypeOrderByCreatedAtDesc(Long eventDraftId, String jobType); -} diff --git a/content-service/src/main/resources/application.yml b/content-service/src/main/resources/application.yml index 4c5ada1..d9f41b7 100644 --- a/content-service/src/main/resources/application.yml +++ b/content-service/src/main/resources/application.yml @@ -2,22 +2,6 @@ spring: application: name: content-service - datasource: - url: jdbc:postgresql://4.217.131.139:5432/contentdb - username: eventuser - password: Hi5Jessica! - driver-class-name: org.postgresql.Driver - - jpa: - database-platform: org.hibernate.dialect.PostgreSQLDialect - hibernate: - ddl-auto: update - show-sql: true - properties: - hibernate: - format_sql: true - use_sql_comments: true - data: redis: host: 4.217.131.139 @@ -47,4 +31,3 @@ azure: logging: level: com.kt.event: DEBUG - org.hibernate.SQL: DEBUG