Event 엔티티에 참여자 및 ROI 필드 추가 및 Frontend-Backend 통합
🔧 Backend 변경사항: - Event 엔티티에 participants, targetParticipants, roi 필드 추가 - EventDetailResponse DTO 및 EventService 매퍼 업데이트 - ROI 자동 계산 비즈니스 로직 구현 - SecurityConfig CORS 설정 추가 (localhost:3000 허용) 🎨 Frontend 변경사항: - TypeScript EventDetail 타입 정의 업데이트 - Events 페이지 실제 API 데이터 연동 (Mock 데이터 제거) - 참여자 수 및 ROI 기반 통계 계산 로직 개선 📝 문서: - Event 필드 추가 및 API 통합 테스트 결과서 작성 ✅ 테스트 완료: - Backend API 응답 검증 - CORS 설정 검증 - Frontend-Backend 통합 테스트 성공 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+3
@@ -36,6 +36,9 @@ public class EventDetailResponse {
|
||||
private EventStatus status;
|
||||
private UUID selectedImageId;
|
||||
private String selectedImageUrl;
|
||||
private Integer participants;
|
||||
private Integer targetParticipants;
|
||||
private Double roi;
|
||||
|
||||
@Builder.Default
|
||||
private List<GeneratedImageDto> generatedImages = new ArrayList<>();
|
||||
|
||||
+3
@@ -518,6 +518,9 @@ public class EventService {
|
||||
.status(event.getStatus())
|
||||
.selectedImageId(event.getSelectedImageId())
|
||||
.selectedImageUrl(event.getSelectedImageUrl())
|
||||
.participants(event.getParticipants())
|
||||
.targetParticipants(event.getTargetParticipants())
|
||||
.roi(event.getRoi())
|
||||
.generatedImages(
|
||||
event.getGeneratedImages().stream()
|
||||
.map(img -> EventDetailResponse.GeneratedImageDto.builder()
|
||||
|
||||
@@ -8,6 +8,12 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Spring Security 설정 클래스
|
||||
@@ -34,8 +40,8 @@ public class SecurityConfig {
|
||||
// CSRF 보호 비활성화 (개발 환경)
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
|
||||
// CORS 설정
|
||||
.cors(AbstractHttpConfigurer::disable)
|
||||
// CORS 설정 활성화
|
||||
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
||||
|
||||
// 폼 로그인 비활성화
|
||||
.formLogin(AbstractHttpConfigurer::disable)
|
||||
@@ -62,4 +68,54 @@ public class SecurityConfig {
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* CORS 설정
|
||||
* 개발 환경에서 프론트엔드(localhost:3000)의 요청을 허용합니다.
|
||||
*
|
||||
* @return CorsConfigurationSource CORS 설정 소스
|
||||
*/
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
|
||||
// 허용할 Origin (개발 환경)
|
||||
configuration.setAllowedOrigins(Arrays.asList(
|
||||
"http://localhost:3000",
|
||||
"http://127.0.0.1:3000"
|
||||
));
|
||||
|
||||
// 허용할 HTTP 메서드
|
||||
configuration.setAllowedMethods(Arrays.asList(
|
||||
"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"
|
||||
));
|
||||
|
||||
// 허용할 헤더
|
||||
configuration.setAllowedHeaders(Arrays.asList(
|
||||
"Authorization",
|
||||
"Content-Type",
|
||||
"X-Requested-With",
|
||||
"Accept",
|
||||
"Origin",
|
||||
"Access-Control-Request-Method",
|
||||
"Access-Control-Request-Headers"
|
||||
));
|
||||
|
||||
// 인증 정보 포함 허용
|
||||
configuration.setAllowCredentials(true);
|
||||
|
||||
// Preflight 요청 캐시 시간 (초)
|
||||
configuration.setMaxAge(3600L);
|
||||
|
||||
// 노출할 응답 헤더
|
||||
configuration.setExposedHeaders(Arrays.asList(
|
||||
"Authorization",
|
||||
"Content-Type"
|
||||
));
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,17 @@ public class Event extends BaseTimeEntity {
|
||||
@Column(name = "selected_image_url", length = 500)
|
||||
private String selectedImageUrl;
|
||||
|
||||
@Column(name = "participants")
|
||||
@Builder.Default
|
||||
private Integer participants = 0;
|
||||
|
||||
@Column(name = "target_participants")
|
||||
private Integer targetParticipants;
|
||||
|
||||
@Column(name = "roi")
|
||||
@Builder.Default
|
||||
private Double roi = 0.0;
|
||||
|
||||
@ElementCollection(fetch = FetchType.LAZY)
|
||||
@CollectionTable(
|
||||
name = "event_channels",
|
||||
@@ -139,6 +150,57 @@ public class Event extends BaseTimeEntity {
|
||||
this.channels.addAll(channels);
|
||||
}
|
||||
|
||||
/**
|
||||
* 목표 참여자 수 설정
|
||||
*/
|
||||
public void updateTargetParticipants(Integer targetParticipants) {
|
||||
if (targetParticipants != null && targetParticipants < 0) {
|
||||
throw new IllegalArgumentException("목표 참여자 수는 0 이상이어야 합니다.");
|
||||
}
|
||||
this.targetParticipants = targetParticipants;
|
||||
}
|
||||
|
||||
/**
|
||||
* 참여자 수 증가
|
||||
*/
|
||||
public void incrementParticipants() {
|
||||
this.participants = (this.participants == null ? 0 : this.participants) + 1;
|
||||
updateRoi();
|
||||
}
|
||||
|
||||
/**
|
||||
* 참여자 수 직접 설정
|
||||
*/
|
||||
public void updateParticipants(Integer participants) {
|
||||
if (participants != null && participants < 0) {
|
||||
throw new IllegalArgumentException("참여자 수는 0 이상이어야 합니다.");
|
||||
}
|
||||
this.participants = participants;
|
||||
updateRoi();
|
||||
}
|
||||
|
||||
/**
|
||||
* ROI 계산 및 업데이트
|
||||
* ROI = (참여자 수 / 목표 참여자 수) * 100
|
||||
*/
|
||||
private void updateRoi() {
|
||||
if (this.targetParticipants != null && this.targetParticipants > 0) {
|
||||
this.roi = ((double) (this.participants == null ? 0 : this.participants) / this.targetParticipants) * 100.0;
|
||||
} else {
|
||||
this.roi = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ROI 직접 설정 (외부 계산값 사용)
|
||||
*/
|
||||
public void updateRoi(Double roi) {
|
||||
if (roi != null && roi < 0) {
|
||||
throw new IllegalArgumentException("ROI는 0 이상이어야 합니다.");
|
||||
}
|
||||
this.roi = roi;
|
||||
}
|
||||
|
||||
/**
|
||||
* 이벤트 배포 (상태 변경: DRAFT → PUBLISHED)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user