mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 17:26:23 +00:00
Phase 3: content-service JPA 완전 제거 및 Redis 전용 전환
주요 변경사항: - JPA Entity 3개 삭제 (JobEntity, GeneratedImageEntity, ContentEntity) - JPA Repository 3개 삭제 (JobJpaRepository, GeneratedImageJpaRepository, ContentJpaRepository) - JPA Gateway 2개 삭제 (JobGateway, ContentGateway) - Port 인터페이스 정리: backward compatibility 메서드 제거 - Service 레이어 Redis DTO 전환 (JobManagementService, MockGenerateImagesService, MockRegenerateImageService) - MockRedisGateway에 ContentReader/ContentWriter 구현 추가 및 Immutable 패턴 처리 - application.yml에서 JPA/H2 설정 제거 - build.gradle에서 JPA 의존성 exclude 처리 - ContentApplication에서 JPA 어노테이션 제거 서비스는 이제 순수 Redis 기반 스토리지로 동작합니다. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
5e9e1759ce
commit
ff83dca1a1
@ -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 {
|
dependencies {
|
||||||
// Kafka Consumer
|
// Kafka Consumer
|
||||||
implementation 'org.springframework.kafka:spring-kafka'
|
implementation 'org.springframework.kafka:spring-kafka'
|
||||||
@ -17,7 +23,4 @@ dependencies {
|
|||||||
|
|
||||||
// Jackson for JSON
|
// Jackson for JSON
|
||||||
implementation 'com.fasterxml.jackson.core:jackson-databind'
|
implementation 'com.fasterxml.jackson.core:jackson-databind'
|
||||||
|
|
||||||
// H2 Database for local testing
|
|
||||||
runtimeOnly 'com.h2database:h2'
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.kt.event.common.exception.BusinessException;
|
|||||||
import com.kt.event.common.exception.ErrorCode;
|
import com.kt.event.common.exception.ErrorCode;
|
||||||
import com.kt.event.content.biz.domain.Job;
|
import com.kt.event.content.biz.domain.Job;
|
||||||
import com.kt.event.content.biz.dto.JobInfo;
|
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.in.GetJobStatusUseCase;
|
||||||
import com.kt.event.content.biz.usecase.out.JobReader;
|
import com.kt.event.content.biz.usecase.out.JobReader;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -25,9 +26,22 @@ public class JobManagementService implements GetJobStatusUseCase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JobInfo execute(String jobId) {
|
public JobInfo execute(String jobId) {
|
||||||
Job job = jobReader.findById(jobId)
|
RedisJobData jobData = jobReader.getJob(jobId)
|
||||||
.orElseThrow(() -> new BusinessException(ErrorCode.COMMON_001, "Job을 찾을 수 없습니다"));
|
.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);
|
return JobInfo.from(job);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.domain.Platform;
|
||||||
import com.kt.event.content.biz.dto.ContentCommand;
|
import com.kt.event.content.biz.dto.ContentCommand;
|
||||||
import com.kt.event.content.biz.dto.JobInfo;
|
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.in.GenerateImagesUseCase;
|
||||||
import com.kt.event.content.biz.usecase.out.ContentWriter;
|
import com.kt.event.content.biz.usecase.out.ContentWriter;
|
||||||
import com.kt.event.content.biz.usecase.out.JobWriter;
|
import com.kt.event.content.biz.usecase.out.JobWriter;
|
||||||
@ -53,14 +54,24 @@ public class MockGenerateImagesService implements GenerateImagesUseCase {
|
|||||||
.updatedAt(java.time.LocalDateTime.now())
|
.updatedAt(java.time.LocalDateTime.now())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Job 저장
|
// Job 저장 (Job 도메인을 RedisJobData로 변환)
|
||||||
Job savedJob = jobWriter.save(job);
|
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);
|
log.info("[MOCK] Job 생성 완료: jobId={}", jobId);
|
||||||
|
|
||||||
// 비동기로 이미지 생성 시뮬레이션
|
// 비동기로 이미지 생성 시뮬레이션
|
||||||
processImageGeneration(jobId, command);
|
processImageGeneration(jobId, command);
|
||||||
|
|
||||||
return JobInfo.from(savedJob);
|
return JobInfo.from(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Async
|
@Async
|
||||||
@ -128,36 +139,16 @@ public class MockGenerateImagesService implements GenerateImagesUseCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Job 상태 업데이트: COMPLETED
|
// Job 상태 업데이트: COMPLETED
|
||||||
Job completedJob = Job.builder()
|
String resultMessage = String.format("%d개의 이미지가 성공적으로 생성되었습니다.", images.size());
|
||||||
.id(jobId)
|
jobWriter.updateJobStatus(jobId, "COMPLETED", 100);
|
||||||
.eventDraftId(command.getEventDraftId())
|
jobWriter.updateJobResult(jobId, resultMessage);
|
||||||
.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);
|
|
||||||
log.info("[MOCK] Job 완료: jobId={}, 생성된 이미지 수={}", jobId, images.size());
|
log.info("[MOCK] Job 완료: jobId={}, 생성된 이미지 수={}", jobId, images.size());
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[MOCK] 이미지 생성 실패: jobId={}", jobId, e);
|
log.error("[MOCK] 이미지 생성 실패: jobId={}", jobId, e);
|
||||||
|
|
||||||
// Job 상태 업데이트: FAILED
|
// Job 상태 업데이트: FAILED
|
||||||
Job failedJob = Job.builder()
|
jobWriter.updateJobError(jobId, e.getMessage());
|
||||||
.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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.domain.Job;
|
||||||
import com.kt.event.content.biz.dto.ContentCommand;
|
import com.kt.event.content.biz.dto.ContentCommand;
|
||||||
import com.kt.event.content.biz.dto.JobInfo;
|
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.in.RegenerateImageUseCase;
|
||||||
import com.kt.event.content.biz.usecase.out.JobWriter;
|
import com.kt.event.content.biz.usecase.out.JobWriter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -41,11 +42,21 @@ public class MockRegenerateImageService implements RegenerateImageUseCase {
|
|||||||
.updatedAt(java.time.LocalDateTime.now())
|
.updatedAt(java.time.LocalDateTime.now())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Job 저장
|
// Job 저장 (Job 도메인을 RedisJobData로 변환)
|
||||||
Job savedJob = jobWriter.save(job);
|
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);
|
log.info("[MOCK] 재생성 Job 생성 완료: jobId={}", jobId);
|
||||||
|
|
||||||
return JobInfo.from(savedJob);
|
return JobInfo.from(job);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package com.kt.event.content.biz.usecase.out;
|
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 com.kt.event.content.biz.dto.RedisJobData;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -17,13 +16,4 @@ public interface JobReader {
|
|||||||
* @return Job 데이터
|
* @return Job 데이터
|
||||||
*/
|
*/
|
||||||
Optional<RedisJobData> getJob(String jobId);
|
Optional<RedisJobData> getJob(String jobId);
|
||||||
|
|
||||||
/**
|
|
||||||
* 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정)
|
|
||||||
* JPA 기반 JobGateway에서만 사용
|
|
||||||
*
|
|
||||||
* @param jobId Job ID
|
|
||||||
* @return Job 도메인 객체
|
|
||||||
*/
|
|
||||||
Optional<Job> findById(String jobId);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package com.kt.event.content.biz.usecase.out;
|
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 com.kt.event.content.biz.dto.RedisJobData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,13 +39,4 @@ public interface JobWriter {
|
|||||||
* @param errorMessage 에러 메시지
|
* @param errorMessage 에러 메시지
|
||||||
*/
|
*/
|
||||||
void updateJobError(String jobId, String errorMessage);
|
void updateJobError(String jobId, String errorMessage);
|
||||||
|
|
||||||
/**
|
|
||||||
* 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정)
|
|
||||||
* JPA 기반 JobGateway에서만 사용
|
|
||||||
*
|
|
||||||
* @param job Job 도메인 객체
|
|
||||||
* @return 저장된 Job
|
|
||||||
*/
|
|
||||||
Job save(Job job);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,24 +2,16 @@ package com.kt.event.content.infra;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
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;
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Content Service Application
|
* Content Service Application
|
||||||
|
* Phase 3: JPA removed, using Redis for storage
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication(scanBasePackages = {
|
@SpringBootApplication(scanBasePackages = {
|
||||||
"com.kt.event.content",
|
"com.kt.event.content",
|
||||||
"com.kt.event.common"
|
"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
|
@EnableAsync
|
||||||
public class ContentApplication {
|
public class ContentApplication {
|
||||||
|
|
||||||
|
|||||||
@ -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<Content> findByEventDraftIdWithImages(Long eventDraftId) {
|
|
||||||
log.debug("이벤트 콘텐츠 조회 (with images): eventDraftId={}", eventDraftId);
|
|
||||||
return contentRepository.findByEventDraftIdWithImages(eventDraftId)
|
|
||||||
.map(ContentEntity::toDomain);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(readOnly = true)
|
|
||||||
public Optional<GeneratedImage> findImageById(Long imageId) {
|
|
||||||
log.debug("이미지 조회: imageId={}", imageId);
|
|
||||||
return imageRepository.findById(imageId)
|
|
||||||
.map(GeneratedImageEntity::toDomain);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(readOnly = true)
|
|
||||||
public List<GeneratedImage> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<RedisJobData> 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<Job> findById(String jobId) {
|
|
||||||
log.debug("Job 조회: jobId={}", jobId);
|
|
||||||
return jobRepository.findById(jobId)
|
|
||||||
.map(JobEntity::toDomain);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트별 Job 조회 (추가 메서드)
|
|
||||||
*/
|
|
||||||
@Transactional(readOnly = true)
|
|
||||||
public List<Job> 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<Job> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<Job> 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 ====================
|
// ==================== Helper Methods ====================
|
||||||
|
|
||||||
private String getString(Map<Object, Object> map, String key) {
|
private String getString(Map<Object, Object> map, String key) {
|
||||||
|
|||||||
@ -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<GeneratedImageEntity> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +1,14 @@
|
|||||||
package com.kt.event.content.infra.gateway.mock;
|
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.GeneratedImage;
|
||||||
import com.kt.event.content.biz.domain.ImageStyle;
|
import com.kt.event.content.biz.domain.ImageStyle;
|
||||||
import com.kt.event.content.biz.domain.Job;
|
import com.kt.event.content.biz.domain.Job;
|
||||||
import com.kt.event.content.biz.domain.Platform;
|
import com.kt.event.content.biz.domain.Platform;
|
||||||
import com.kt.event.content.biz.dto.RedisImageData;
|
import com.kt.event.content.biz.dto.RedisImageData;
|
||||||
import com.kt.event.content.biz.dto.RedisJobData;
|
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.ImageReader;
|
||||||
import com.kt.event.content.biz.usecase.out.ImageWriter;
|
import com.kt.event.content.biz.usecase.out.ImageWriter;
|
||||||
import com.kt.event.content.biz.usecase.out.JobReader;
|
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.RedisAIDataReader;
|
||||||
import com.kt.event.content.biz.usecase.out.RedisImageWriter;
|
import com.kt.event.content.biz.usecase.out.RedisImageWriter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.context.annotation.Profile;
|
import org.springframework.context.annotation.Profile;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -31,12 +35,15 @@ import java.util.stream.Collectors;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
|
@Primary
|
||||||
@Profile({"local", "test"})
|
@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<Long, Map<String, Object>> aiDataCache = new HashMap<>();
|
private final Map<Long, Map<String, Object>> aiDataCache = new HashMap<>();
|
||||||
|
|
||||||
// In-memory storage for images and jobs
|
// In-memory storage for contents, images, and jobs
|
||||||
|
private final Map<Long, Content> contentStorage = new ConcurrentHashMap<>();
|
||||||
|
private final Map<Long, GeneratedImage> imageByIdStorage = new ConcurrentHashMap<>();
|
||||||
private final Map<String, RedisImageData> imageStorage = new ConcurrentHashMap<>();
|
private final Map<String, RedisImageData> imageStorage = new ConcurrentHashMap<>();
|
||||||
private final Map<String, RedisJobData> jobStorage = new ConcurrentHashMap<>();
|
private final Map<String, RedisJobData> jobStorage = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@ -259,52 +266,136 @@ public class MockRedisGateway implements RedisAIDataReader, RedisImageWriter, Im
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== ContentReader 구현 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정)
|
* 이벤트 초안 ID로 콘텐츠 조회 (이미지 목록 포함)
|
||||||
* Job 도메인 객체를 RedisJobData로 변환하여 저장
|
|
||||||
*
|
|
||||||
* @param job Job 도메인 객체
|
|
||||||
* @return 저장된 Job
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Job save(Job job) {
|
public Optional<Content> findByEventDraftIdWithImages(Long eventDraftId) {
|
||||||
log.debug("[MOCK] Job 저장 (호환성): jobId={}, status={}", job.getId(), job.getStatus());
|
try {
|
||||||
|
Content content = contentStorage.get(eventDraftId);
|
||||||
|
if (content == null) {
|
||||||
|
log.warn("[MOCK] Content를 찾을 수 없음: eventDraftId={}", eventDraftId);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
RedisJobData jobData = RedisJobData.builder()
|
// 이미지 목록 조회 및 Content 재생성 (immutable pattern)
|
||||||
.id(job.getId())
|
List<GeneratedImage> images = findImagesByEventDraftId(eventDraftId);
|
||||||
.eventDraftId(job.getEventDraftId())
|
Content contentWithImages = Content.builder()
|
||||||
.jobType(job.getJobType())
|
.id(content.getId())
|
||||||
.status(job.getStatus().name())
|
.eventDraftId(content.getEventDraftId())
|
||||||
.progress(job.getProgress())
|
.eventTitle(content.getEventTitle())
|
||||||
.resultMessage(job.getResultMessage())
|
.eventDescription(content.getEventDescription())
|
||||||
.errorMessage(job.getErrorMessage())
|
.images(images)
|
||||||
.createdAt(job.getCreatedAt())
|
.createdAt(content.getCreatedAt())
|
||||||
.updatedAt(job.getUpdatedAt())
|
.updatedAt(content.getUpdatedAt())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
saveJob(jobData, 86400); // 24시간 TTL
|
return Optional.of(contentWithImages);
|
||||||
return job;
|
} catch (Exception e) {
|
||||||
|
log.error("[MOCK] Content 조회 실패: eventDraftId={}", eventDraftId, e);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 기존 호환성을 위한 메서드 (Phase 3에서 삭제 예정)
|
* 이미지 ID로 이미지 조회
|
||||||
*
|
|
||||||
* @param jobId Job ID
|
|
||||||
* @return Job 도메인 객체
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Optional<Job> findById(String jobId) {
|
public Optional<GeneratedImage> findImageById(Long imageId) {
|
||||||
log.debug("[MOCK] Job 조회 (호환성): jobId={}", jobId);
|
try {
|
||||||
return getJob(jobId).map(data -> Job.builder()
|
GeneratedImage image = imageByIdStorage.get(imageId);
|
||||||
.id(data.getId())
|
if (image == null) {
|
||||||
.eventDraftId(data.getEventDraftId())
|
log.warn("[MOCK] 이미지를 찾을 수 없음: imageId={}", imageId);
|
||||||
.jobType(data.getJobType())
|
return Optional.empty();
|
||||||
.status(Job.Status.valueOf(data.getStatus()))
|
}
|
||||||
.progress(data.getProgress())
|
return Optional.of(image);
|
||||||
.resultMessage(data.getResultMessage())
|
} catch (Exception e) {
|
||||||
.errorMessage(data.getErrorMessage())
|
log.error("[MOCK] 이미지 조회 실패: imageId={}", imageId, e);
|
||||||
.createdAt(data.getCreatedAt())
|
return Optional.empty();
|
||||||
.updatedAt(data.getUpdatedAt())
|
}
|
||||||
.build());
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 이벤트 초안 ID로 이미지 목록 조회
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<GeneratedImage> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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<ContentEntity, Long> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트 초안 ID로 콘텐츠 조회 (이미지 목록 포함)
|
|
||||||
*
|
|
||||||
* @param eventDraftId 이벤트 초안 ID
|
|
||||||
* @return 콘텐츠 엔티티
|
|
||||||
*/
|
|
||||||
@Query("SELECT DISTINCT c FROM ContentEntity c " +
|
|
||||||
"LEFT JOIN FETCH c.images " +
|
|
||||||
"WHERE c.eventDraftId = :eventDraftId")
|
|
||||||
Optional<ContentEntity> findByEventDraftIdWithImages(@Param("eventDraftId") Long eventDraftId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트 초안 ID로 콘텐츠 조회
|
|
||||||
*
|
|
||||||
* @param eventDraftId 이벤트 초안 ID
|
|
||||||
* @return 콘텐츠 엔티티
|
|
||||||
*/
|
|
||||||
Optional<ContentEntity> findByEventDraftId(Long eventDraftId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트 초안 ID로 콘텐츠 존재 여부 확인
|
|
||||||
*
|
|
||||||
* @param eventDraftId 이벤트 초안 ID
|
|
||||||
* @return 존재 여부
|
|
||||||
*/
|
|
||||||
boolean existsByEventDraftId(Long eventDraftId);
|
|
||||||
}
|
|
||||||
@ -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<GeneratedImageEntity, Long> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트 초안 ID로 이미지 목록 조회
|
|
||||||
*
|
|
||||||
* @param eventDraftId 이벤트 초안 ID
|
|
||||||
* @return 이미지 엔티티 목록
|
|
||||||
*/
|
|
||||||
List<GeneratedImageEntity> findByEventDraftId(Long eventDraftId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트 초안 ID와 스타일로 이미지 목록 조회
|
|
||||||
*
|
|
||||||
* @param eventDraftId 이벤트 초안 ID
|
|
||||||
* @param style 이미지 스타일
|
|
||||||
* @return 이미지 엔티티 목록
|
|
||||||
*/
|
|
||||||
List<GeneratedImageEntity> findByEventDraftIdAndStyle(Long eventDraftId, ImageStyle style);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트 초안 ID와 플랫폼으로 이미지 목록 조회
|
|
||||||
*
|
|
||||||
* @param eventDraftId 이벤트 초안 ID
|
|
||||||
* @param platform 플랫폼
|
|
||||||
* @return 이미지 엔티티 목록
|
|
||||||
*/
|
|
||||||
List<GeneratedImageEntity> findByEventDraftIdAndPlatform(Long eventDraftId, Platform platform);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트 초안 ID와 선택 여부로 이미지 목록 조회
|
|
||||||
*
|
|
||||||
* @param eventDraftId 이벤트 초안 ID
|
|
||||||
* @param selected 선택 여부
|
|
||||||
* @return 이미지 엔티티 목록
|
|
||||||
*/
|
|
||||||
List<GeneratedImageEntity> 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<GeneratedImageEntity> 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);
|
|
||||||
}
|
|
||||||
@ -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<JobEntity, String> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트 초안 ID로 Job 목록 조회
|
|
||||||
*
|
|
||||||
* @param eventDraftId 이벤트 초안 ID
|
|
||||||
* @return Job 엔티티 목록
|
|
||||||
*/
|
|
||||||
List<JobEntity> findByEventDraftId(Long eventDraftId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트 초안 ID와 상태로 Job 목록 조회
|
|
||||||
*
|
|
||||||
* @param eventDraftId 이벤트 초안 ID
|
|
||||||
* @param status Job 상태
|
|
||||||
* @return Job 엔티티 목록
|
|
||||||
*/
|
|
||||||
List<JobEntity> findByEventDraftIdAndStatus(Long eventDraftId, Job.Status status);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트 초안 ID와 Job 타입으로 최신 Job 조회
|
|
||||||
*
|
|
||||||
* @param eventDraftId 이벤트 초안 ID
|
|
||||||
* @param jobType Job 타입
|
|
||||||
* @return Job 엔티티
|
|
||||||
*/
|
|
||||||
Optional<JobEntity> findFirstByEventDraftIdAndJobTypeOrderByCreatedAtDesc(Long eventDraftId, String jobType);
|
|
||||||
}
|
|
||||||
@ -2,22 +2,6 @@ spring:
|
|||||||
application:
|
application:
|
||||||
name: content-service
|
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:
|
data:
|
||||||
redis:
|
redis:
|
||||||
host: 4.217.131.139
|
host: 4.217.131.139
|
||||||
@ -47,4 +31,3 @@ azure:
|
|||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
com.kt.event: DEBUG
|
com.kt.event: DEBUG
|
||||||
org.hibernate.SQL: DEBUG
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user