diff --git a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/EmailAsyncHandler.java b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/EmailAsyncHandler.java new file mode 100644 index 0000000..59a7513 --- /dev/null +++ b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/EmailAsyncHandler.java @@ -0,0 +1,25 @@ +package com.mzc.secondproject.serverless.domain.opic.handler; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.events.SNSEvent; +import com.google.gson.Gson; +import com.mzc.secondproject.serverless.domain.opic.service.EmailService; + +public class EmailAsyncHandler implements RequestHandler { + private final EmailService emailService = new EmailService(); + private final Gson gson = new Gson(); + + @Override + public Void handleRequest(SNSEvent event, Context context) { + for (SNSEvent.SNSRecord record : event.getRecords()) { + String messageBody = record.getSNS().getMessage(); + processMessage(messageBody); + } + return null; + } + private void processMessage(String body) { + // 메시지 파싱 및 타입 확인 (OPIC_REPORT_EMAIL) + // emailService.sendOPIcReportEmail 호출 + } +} \ No newline at end of file diff --git a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java index c79576d..8f9c13c 100644 --- a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java +++ b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java @@ -15,6 +15,7 @@ import com.mzc.secondproject.serverless.domain.opic.dto.response.CreateSessionResponse; import com.mzc.secondproject.serverless.domain.opic.dto.response.FeedbackResponse; import com.mzc.secondproject.serverless.domain.opic.dto.response.QuestionResponse; +import com.mzc.secondproject.serverless.domain.opic.dto.response.SessionReportResponse; import com.mzc.secondproject.serverless.domain.opic.model.OPIcAnswer; import com.mzc.secondproject.serverless.domain.opic.model.OPIcQuestion; import com.mzc.secondproject.serverless.domain.opic.model.OPIcSession; @@ -533,8 +534,8 @@ private APIGatewayProxyResponseEvent completeSession(APIGatewayProxyRequestEvent String userName = CognitoUtil.extractNickname(event).orElse("학습자"); if (userEmail != null && !userEmail.isEmpty()) { - emailService.sendOPIcReportEmail(userEmail, userName, sessionReport); - logger.info("리포트 이메일 발송 완료: to={}", userEmail); + publishEmailToSNS(userEmail, userName, sessionReport); + logger.info("이메일 발송 SNS 요청 발행: to={}", userEmail); } } catch (Exception e) { // 이메일 실패해도 세션 완료는 성공 처리 @@ -554,7 +555,29 @@ private APIGatewayProxyResponseEvent completeSession(APIGatewayProxyRequestEvent return ResponseGenerator.ok("세션이 완료되었습니다.", sessionReport); } - // ==================== 유틸리티 ==================== + /** + * 이메일 발송용 SNS 메시지 발행 + */ + private void publishEmailToSNS(String email, String userName, SessionReportResponse report) { + try { + String topicArn = System.getenv("NOTIFICATION_TOPIC_ARN"); + + Map message = new HashMap<>(); + message.put("type", "OPIC_REPORT_EMAIL"); + message.put("recipientEmail", email); + message.put("userName", userName); + message.put("report", report); // 세션 리포트 객체 전달 + + AwsClients.sns().publish(PublishRequest.builder() + .topicArn(topicArn) + .message(gson.toJson(message)) + .build()); + } catch (Exception e) { + logger.error("이메일 SNS 발행 실패", e); + } + } + + // ==================== 유틸리티 ====================Z /** * 질문 음성 URL 생성 (Polly + S3 캐싱) diff --git a/ServerlessFunction/template.yaml b/ServerlessFunction/template.yaml index 3ed8f0d..5680182 100644 --- a/ServerlessFunction/template.yaml +++ b/ServerlessFunction/template.yaml @@ -1622,7 +1622,7 @@ Resources: Method: POST Auth: Authorizer: CognitoAuthV2 - # 답변 상태 조회 (폴링용) ← 새로 추가! + # 답변 상태 조회 (폴링용) GetAnswerStatus: Type: Api Properties: @@ -1687,6 +1687,25 @@ Resources: Properties: Topic: !Ref AnswerProcessTopic + # 이메일 발송 전용 비동기 Lambda + OPIcEmailFunction: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Sub "${AWS::StackName}-opic-email-handler" + Handler: com.mzc.secondproject.serverless.domain.opic.handler.EmailAsyncHandler::handleRequest + Events: + SNSEvent: + Type: SNS + Properties: + Topic: !Ref NotificationTopic + Policies: + - Statement: + - Effect: Allow + Action: + - ses:SendEmail + - ses:SendRawEmail + Resource: "*" + ############################################# # Speaking Lambda Functions #############################################