mirror of
https://github.com/won-ktds/smarketing-backend.git
synced 2026-06-12 20:39:09 +00:00
Merge branch 'main' of https://github.com/won-ktds/smarketing-backend into poster-content
This commit is contained in:
+5
-1
@@ -43,7 +43,11 @@ public class SecurityConfig {
|
||||
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.anyRequest().permitAll()
|
||||
.requestMatchers("/api/auth/**", "/api/member/register", "/api/member/check-duplicate/**",
|
||||
"/api/member/validate-password", "/swagger-ui/**", "/v3/api-docs/**",
|
||||
"/swagger-resources/**", "/webjars/**", "/actuator/**", "/health/**", "/error"
|
||||
).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
|
||||
+16
-16
@@ -43,22 +43,22 @@ podTemplate(
|
||||
echo "Image Org: ${props.image_org}"
|
||||
}
|
||||
|
||||
stage("Check Changes") {
|
||||
script {
|
||||
def changes = sh(
|
||||
script: "git diff --name-only HEAD~1 HEAD",
|
||||
returnStdout: true
|
||||
).trim()
|
||||
|
||||
if (!changes.contains("smarketing-java/")) {
|
||||
echo "No changes in smarketing-java, skipping build"
|
||||
currentBuild.result = 'SUCCESS'
|
||||
error("Stopping pipeline - no changes detected")
|
||||
}
|
||||
|
||||
echo "Changes detected in smarketing-java, proceeding with build"
|
||||
}
|
||||
}
|
||||
// stage("Check Changes") {
|
||||
// script {
|
||||
// def changes = sh(
|
||||
// script: "git diff --name-only HEAD~1 HEAD",
|
||||
// returnStdout: true
|
||||
// ).trim()
|
||||
//
|
||||
// if (!changes.contains("smarketing-java/")) {
|
||||
// echo "No changes in smarketing-java, skipping build"
|
||||
// currentBuild.result = 'SUCCESS'
|
||||
// error("Stopping pipeline - no changes detected")
|
||||
// }
|
||||
//
|
||||
// echo "Changes detected in smarketing-java, proceeding with build"
|
||||
// }
|
||||
// }
|
||||
|
||||
stage("Setup AKS") {
|
||||
container('azure-cli') {
|
||||
|
||||
@@ -182,29 +182,6 @@ spec:
|
||||
name: common-secret
|
||||
- secretRef:
|
||||
name: member-secret
|
||||
startupProbe:
|
||||
tcpSocket:
|
||||
port: 8081
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8081
|
||||
initialDelaySeconds: 120
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8081
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
@@ -248,29 +225,7 @@ spec:
|
||||
name: common-secret
|
||||
- secretRef:
|
||||
name: store-secret
|
||||
startupProbe:
|
||||
tcpSocket:
|
||||
port: 8082
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8082
|
||||
initialDelaySeconds: 120
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8082
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
@@ -314,29 +269,7 @@ spec:
|
||||
name: common-secret
|
||||
- secretRef:
|
||||
name: marketing-content-secret
|
||||
startupProbe:
|
||||
tcpSocket:
|
||||
port: 8083
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8083
|
||||
initialDelaySeconds: 120
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8083
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
@@ -380,29 +313,7 @@ spec:
|
||||
name: common-secret
|
||||
- secretRef:
|
||||
name: ai-recommend-secret
|
||||
startupProbe:
|
||||
tcpSocket:
|
||||
port: 8084
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8084
|
||||
initialDelaySeconds: 120
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8084
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
|
||||
|
||||
---
|
||||
# Services
|
||||
@@ -462,84 +373,44 @@ spec:
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
# deploy.yaml.template의 Ingress 부분 - 완전한 설정
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: smarketing-backend
|
||||
namespace: ${namespace}
|
||||
name: smarketing-ingress
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /$2
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "false"
|
||||
nginx.ingress.kubernetes.io/use-regex: "true"
|
||||
# nginx.ingress.kubernetes.io/rewrite-target: /$2 # 이 줄 제거
|
||||
# nginx.ingress.kubernetes.io/use-regex: "true" # 이 줄 제거
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: smarketing.20.249.184.228.nip.io
|
||||
http:
|
||||
paths:
|
||||
# Member 서비스 - 인증 관련
|
||||
- path: /api/auth(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
- path: /api/auth
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: member
|
||||
name: auth-service
|
||||
port:
|
||||
number: 80
|
||||
# Member 서비스 - 회원 관리 (누락된 경로!)
|
||||
- path: /api/member(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
- path: /api/store
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: member
|
||||
name: store-service
|
||||
port:
|
||||
number: 80
|
||||
# Store 서비스
|
||||
- path: /api/store(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
- path: /api/content
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: store
|
||||
name: content-service
|
||||
port:
|
||||
number: 80
|
||||
# Store 서비스 - 매출 관련
|
||||
- path: /api/sales(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
- path: /api/recommend
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: store
|
||||
name: recommend-service
|
||||
port:
|
||||
number: 80
|
||||
# Store 서비스 - 메뉴 관련
|
||||
- path: /api/menu(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
backend:
|
||||
service:
|
||||
name: store
|
||||
port:
|
||||
number: 80
|
||||
# Store 서비스 - 이미지 업로드
|
||||
- path: /api/images(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
backend:
|
||||
service:
|
||||
name: store
|
||||
port:
|
||||
number: 80
|
||||
# Marketing Content 서비스
|
||||
- path: /api/content(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
backend:
|
||||
service:
|
||||
name: marketing-content
|
||||
port:
|
||||
number: 80
|
||||
# AI Recommend 서비스
|
||||
- path: /api/recommend(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
backend:
|
||||
service:
|
||||
name: ai-recommend
|
||||
port:
|
||||
number: 80
|
||||
number: 80
|
||||
@@ -9,7 +9,7 @@ image_org=smarketing
|
||||
|
||||
# Application Settings
|
||||
replicas=1
|
||||
allowed_origins=http://20.249.171.38
|
||||
allowed_origins=http://20.249.154.194
|
||||
|
||||
# Security Settings
|
||||
jwt_secret_key=8O2HQ13etL2BWZvYOiWsJ5uWFoLi6NBUG8divYVoCgtHVvlk3dqRksMl16toztDUeBTSIuOOPvHIrYq11G2BwQ
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ public class PosterContentService implements PosterContentUseCase {
|
||||
// 콘텐츠 엔티티 생성
|
||||
Content content = Content.builder()
|
||||
.contentType(ContentType.POSTER)
|
||||
.platform(Platform.GENERAL)
|
||||
.platform(Platform.POSTER)
|
||||
.title(request.getTitle())
|
||||
.content(request.getContent())
|
||||
.images(request.getImages())
|
||||
|
||||
+8
-5
@@ -14,6 +14,7 @@ import com.won.smarketing.content.presentation.dto.SnsContentCreateRequest;
|
||||
import com.won.smarketing.content.presentation.dto.SnsContentCreateResponse;
|
||||
import com.won.smarketing.content.presentation.dto.SnsContentSaveRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@@ -34,6 +35,9 @@ public class SnsContentService implements SnsContentUseCase {
|
||||
private final AiContentGenerator aiContentGenerator;
|
||||
private final BlobStorageService blobStorageService;
|
||||
|
||||
@Value("${azure.storage.container.poster-images:content-images}")
|
||||
private String contentImageContainer;
|
||||
|
||||
/**
|
||||
* SNS 콘텐츠 생성
|
||||
*
|
||||
@@ -44,8 +48,10 @@ public class SnsContentService implements SnsContentUseCase {
|
||||
@Transactional
|
||||
public SnsContentCreateResponse generateSnsContent(SnsContentCreateRequest request, List<MultipartFile> files) {
|
||||
//파일들 주소 가져옴
|
||||
List<String> urls = blobStorageService.uploadImage(files, "containerName");
|
||||
request.setImages(urls);
|
||||
if(files != null) {
|
||||
List<String> urls = blobStorageService.uploadImage(files, contentImageContainer);
|
||||
request.setImages(urls);
|
||||
}
|
||||
|
||||
// AI를 사용하여 SNS 콘텐츠 생성
|
||||
String content = aiContentGenerator.generateSnsContent(request);
|
||||
@@ -67,8 +73,6 @@ public class SnsContentService implements SnsContentUseCase {
|
||||
CreationConditions conditions = CreationConditions.builder()
|
||||
.category(request.getCategory())
|
||||
.requirement(request.getRequirement())
|
||||
//.toneAndManner(request.getToneAndManner())
|
||||
//.emotionIntensity(request.getEmotionIntensity())
|
||||
.eventName(request.getEventName())
|
||||
.startDate(request.getStartDate())
|
||||
.endDate(request.getEndDate())
|
||||
@@ -76,7 +80,6 @@ public class SnsContentService implements SnsContentUseCase {
|
||||
|
||||
// 콘텐츠 엔티티 생성 및 저장
|
||||
Content content = Content.builder()
|
||||
// .contentType(ContentType.SNS_POST)
|
||||
.platform(Platform.fromString(request.getPlatform()))
|
||||
.title(request.getTitle())
|
||||
.content(request.getContent())
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ public enum Platform {
|
||||
FACEBOOK("페이스북"),
|
||||
KAKAO_STORY("카카오스토리"),
|
||||
YOUTUBE("유튜브"),
|
||||
GENERAL("일반");
|
||||
POSTER("포스터");
|
||||
|
||||
private final String displayName;
|
||||
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public class ContentController {
|
||||
@Operation(summary = "SNS 게시물 생성", description = "AI를 활용하여 SNS 게시물을 생성합니다.")
|
||||
@PostMapping(path = "/sns/generate", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public ResponseEntity<ApiResponse<SnsContentCreateResponse>> generateSnsContent(@Valid @RequestPart("request") String requestJson,
|
||||
@Valid @RequestPart("files") List<MultipartFile> images) throws JsonProcessingException {
|
||||
@Valid @RequestPart(name = "files", required = false) List<MultipartFile> images) throws JsonProcessingException {
|
||||
SnsContentCreateRequest request = objectMapper.readValue(requestJson, SnsContentCreateRequest.class);
|
||||
SnsContentCreateResponse response = snsContentUseCase.generateSnsContent(request, images);
|
||||
return ResponseEntity.ok(ApiResponse.success(response, "SNS 콘텐츠가 성공적으로 생성되었습니다."));
|
||||
|
||||
Reference in New Issue
Block a user