11package io .wisoft .prepair .prepair_api .interview .question .service ;
22
3- import io .wisoft .prepair .prepair_api .external .member .enums .Notification ;
43import io .wisoft .prepair .prepair_api .external .member .MemberServiceClient ;
54import io .wisoft .prepair .prepair_api .external .member .dto .MemberSchedulerInfo ;
65import io .wisoft .prepair .prepair_api .external .openai .OpenAiClient ;
76import io .wisoft .prepair .prepair_api .external .openai .dto .QuestionWithTags ;
8- import io .wisoft .prepair .prepair_api .external .notification .email .EmailService ;
9- import io .wisoft .prepair .prepair_api .external .notification .kakao .KakaoService ;
107import io .wisoft .prepair .prepair_api .interview .prompt .PromptBuilder ;
118import io .wisoft .prepair .prepair_api .interview .question .entity .InterviewQuestion ;
129import io .wisoft .prepair .prepair_api .interview .question .repository .QuestionRepository ;
1310import lombok .RequiredArgsConstructor ;
1411import lombok .extern .slf4j .Slf4j ;
1512import org .springframework .stereotype .Service ;
16- import org .springframework .web .client .HttpClientErrorException ;
1713
1814import java .time .DayOfWeek ;
1915import java .time .LocalDate ;
2319@ Slf4j
2420@ Service
2521@ RequiredArgsConstructor
26- public class DailyQuestionGenerationService {
22+ public class TodayQuestionService {
2723
24+ private final QuestionPersistenceService questionPersistenceService ;
25+ private final QuestionNotificationService questionNotificationService ;
2826 private final QuestionRepository questionRepository ;
29- private final QuestionPersistenceService interviewQuestionService ;
3027 private final MemberServiceClient memberServiceClient ;
3128 private final OpenAiClient openAiClient ;
3229 private final PromptBuilder promptBuilder ;
33- private final EmailService emailService ;
34- private final KakaoService kakaoService ;
3530
36- public void generateTodayQuestions () {
31+ public void sendTodayQuestions () {
3732 List <MemberSchedulerInfo > members = memberServiceClient .getMembers ();
3833 DayOfWeek today = LocalDate .now (ZoneId .of ("Asia/Seoul" )).getDayOfWeek ();
3934
@@ -45,77 +40,36 @@ public void generateTodayQuestions() {
4540 .toList ();
4641
4742 log .info ("질문 생성 대상: {} / {} 명" , targetMembers .size (), members .size ());
48- targetMembers .forEach (this ::processTodayQuestion );
43+ targetMembers .forEach (this ::generateAndSend );
4944 }
5045
51- private void processTodayQuestion (MemberSchedulerInfo member ) {
46+ private void generateAndSend (MemberSchedulerInfo member ) {
5247 try {
5348 List <InterviewQuestion > previousQuestions = questionRepository .findByMemberId (member .id ());
5449 String prompt = promptBuilder .buildDailyQuestionPrompt (member .job (), previousQuestions );
5550 QuestionWithTags result = openAiClient .generateQuestion (prompt );
5651 log .info ("질문 생성 완료 | memberId={}" , member .id ());
5752
58- InterviewQuestion question = interviewQuestionService .saveTodayQuestion (member .id (), result );
53+ InterviewQuestion question = questionPersistenceService .saveTodayQuestion (member .id (), result );
5954 log .info ("질문 저장 완료 | memberId={}" , member .id ());
6055
61- notifyMember (member , question );
56+ questionNotificationService . notifyMember (member , question );
6257 } catch (Exception e ) {
6358 log .error ("질문 처리 실패 | memberId={}" , member .id (), e );
6459 }
6560 }
6661
67- private void notifyMember (MemberSchedulerInfo member , InterviewQuestion question ) {
68- Notification notification = member .notification ();
69-
70- if (notification == Notification .EMAIL || notification == Notification .BOTH ) {
71- sendEmail (member , question );
72- }
73-
74- if (notification == Notification .KAKAO || notification == Notification .BOTH ) {
75- sendKakao (member , question );
76- }
77- }
78-
79- private void sendEmail (MemberSchedulerInfo member , InterviewQuestion question ) {
80- try {
81- emailService .sendInterviewQuestion (
82- member .email (),
83- member .nickname (),
84- question .getQuestionTag (),
85- question .getQuestion ()
86- );
87- log .info ("이메일 발송 완료 | memberId={}" , member .id ());
88- } catch (Exception e ) {
89- log .error ("이메일 발송 실패 | memberId={}" , member .id (), e );
90- }
91- }
92-
93- private void sendKakao (MemberSchedulerInfo member , InterviewQuestion question ) {
94- if (!isValidKakaoToken (member )) return ;
95- try {
96- kakaoService .sendInterviewQuestion (
97- member .kakaoAccessToken (),
98- question .getQuestion (),
99- question .getQuestionTag ()
100- );
101- log .info ("카카오 발송 완료 | memberId={}" , member .id ());
102- } catch (HttpClientErrorException .Unauthorized e ) {
103- log .warn ("카카오 발송 실패 | memberId={} | reason=token_expired" , member .id ());
104- } catch (Exception e ) {
105- log .error ("카카오 발송 실패 | memberId={}" , member .id (), e );
62+ private boolean isValidFrequency (MemberSchedulerInfo member ) {
63+ if (member .frequency () == null ) {
64+ log .warn ("멤버 스킵 | memberId={} | reason=no_frequency" , member .id ());
65+ return false ;
10666 }
67+ return true ;
10768 }
10869
109- private boolean shouldSendToday (MemberSchedulerInfo member , DayOfWeek today ) {
110- return switch (member .frequency ()) {
111- case EVERY -> true ;
112- case WEEKLY -> today == DayOfWeek .MONDAY ;
113- };
114- }
115-
116- private boolean isValidKakaoToken (MemberSchedulerInfo member ) {
117- if (member .kakaoAccessToken () == null || member .kakaoAccessToken ().isBlank ()) {
118- log .warn ("멤버 스킵 | memberId={} | reason=no_kakao_token" , member .id ());
70+ private boolean isValidJob (MemberSchedulerInfo member ) {
71+ if (member .job () == null || member .job ().isBlank ()) {
72+ log .warn ("멤버 스킵 | memberId={} | reason=no_job" , member .id ());
11973 return false ;
12074 }
12175 return true ;
@@ -129,20 +83,10 @@ private boolean isValidNotification(MemberSchedulerInfo member) {
12983 return true ;
13084 }
13185
132- private boolean isValidFrequency (MemberSchedulerInfo member ) {
133- if (member .frequency () == null ) {
134- log .warn ("멤버 스킵 | memberId={} | reason=no_frequency" , member .id ());
135- return false ;
136- }
137- return true ;
138- }
139-
140- private boolean isValidJob (MemberSchedulerInfo member ) {
141- if (member .job () == null || member .job ().isBlank ()) {
142- log .warn ("멤버 스킵 | memberId={} | reason=no_job" , member .id ());
143- return false ;
144- }
145- return true ;
86+ private boolean shouldSendToday (MemberSchedulerInfo member , DayOfWeek today ) {
87+ return switch (member .frequency ()) {
88+ case EVERY -> true ;
89+ case WEEKLY -> today == DayOfWeek .MONDAY ;
90+ };
14691 }
147-
14892}
0 commit comments