From e6a362dbfa1edf2f39471b2673a5171dc682b813 Mon Sep 17 00:00:00 2001 From: ssyoung02 Date: Thu, 22 Jan 2026 22:50:02 +0900 Subject: [PATCH 1/7] =?UTF-8?q?refactor=20(Challenge):=20=EC=B1=8C?= =?UTF-8?q?=EB=A6=B0=EC=A7=80=20=EB=A3=A8=ED=8B=B4=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?AI=20=ED=94=84=EB=A1=AC=ED=8F=AC=ED=8A=B8=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../prompt/ChallengePromptTemplate.java | 66 ++++++++++++------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java b/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java index 7f40299c..aa390bf5 100644 --- a/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java +++ b/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java @@ -9,32 +9,48 @@ public class ChallengePromptTemplate { private static final String CHALLENGE_RECOMMENDATION_TEMPLATE = """ - 당신은 피부 홈케어 및 셀프케어 전문가입니다. - 사용자가 선택한 홈케어 루틴 카테고리: "{homecareContent}" + 당신은 피부 홈케어 및 셀프케어 ‘체리쉬’ 앱의 7일 챌린지 루틴을 만드는 전문가입니다. + 사용자가 선택한 카테고리: "{homecareContent}" + + 목표: 사용자가 하루 1번 ‘했음/안했음’으로 체크할 수 있는 루틴 6개를 만드세요. + 결과 문구에는 빈도(매일/일일/주/일주일/N회/N번/항상/매번)를 절대 쓰지 마세요. + + [절대 금지(하나라도 나오면 실패)] + - 점검/확인/체크/정리/세탁/버리기 등 ‘관리/사후처리’ 목적 행동 + - 공중위생·기본 생활 의무 수준의 행동(샤워/양치/손씻기 등) + - 민간요법, 자연요법, 인터넷 카더라 및 DIY 레시피 형태의 루틴 제외 + - 전문 시술/의학적 관리처럼 보이거나 자극적·과도한 케어 + - 오타, 비표준어, 어색한 합성어, 실제 한국어에서 사용되지 않는 표현 금지 + - 외래어·영어·전문용어는 일반적인 한국어 표현으로 치환하여 작성합니다. + 예시: + - 엑스폴리에이션 → 각질 제거 제품 + - 덴탈 플로스 → 치실 + - 선스크린 → 선크림 + [작성 규칙] + - 각 루틴: 공백 포함 20자 이내 + - 루틴은 “뷰티/자기관리 효용”이 분명해야 합니다. + - 매일 반복 가능한 루틴만 작성 ("주 N회" 같은 주간 루틴 제외) + - 상식적이고 안전하며, 일반 사용자가 그대로 따라 해도 무리가 없는 수준이어야 합니다. + - 읽자마자 어떤 행동을 해야 하는지 떠올릴 수 있는 명확한 행동형 문장으로 작성합니다. + + [카테고리별 예시] + - 피부 컨디션: "아침 닦토하기", "세안 후 팩토하기", "매일 밤 모델링팩 하기", "손으로 얼굴 만지지 않기", "샤워 후 PDRN 마스크팩하기", "자기 전 페이스 괄사 마사지하기" + - 생활습관: "일어나자마자 물 한 잔", "6시간 이상 자기", "오후 3시 이후 카페인 금지", "잠들기 30분 전 폰 내려놓기", "12시 전에 눕기" + - 체형관리: "기상 직후 스트레칭 10분", "유산소 운동하기", "저녁 식사 후 야식 안 먹기", "계단으로 이동하기" + - 웰니스 • 마음챙김: "기상 직후 아침 명상", "일어나자마자 폰 보지 않기", "자기 전 스트레칭", "자기 전 감사일기 3가지", "내일 기대되는 것 1가지 적기" + + [출력 전 자체 검수(필수)] + - 6개를 만든 뒤, 아래 금지 단어/패턴이 포함되면 문장을 수정하거나 교체하세요: + 1) 빈도: 매일, 일일, 주, 일주일, N회, N번, 항상, 매번 + 2) 관리/사후처리: 점검, 확인, 체크, 정리, 세탁, 버리기 + - 검수 과정은 출력하지 말고, 최종 JSON만 출력하세요. + + 응답 형식(JSON만): + {{ + "routines": ["루틴1","루틴2","루틴3","루틴4","루틴5","루틴6"] + }} + """; - 위 카테고리에 맞는 매일 실천 가능한 루틴 6개를 추천해주세요. - - [작성 규칙] - - 각 루틴은 공백 포함 20자 이내 - - 짧고 명확하게 작성 - - 매일 반복 가능한 루틴만 작성 ("주 N회" 같은 주간 루틴 제외) - - [카테고리별 예시] - - 피부 컨디션: "아침 닦토하기", "세안 후 팩토하기", "매일 밤 모델링팩 하기", "손으로 얼굴 만지지 않기", "샤워 후 PDRN 마스크팩하기", "자기 전 페이스 괄사 마사지하기" - - 생활습관: "일어나자마자 물 한 잔", "6시간 이상 자기", "오후 3시 이후 카페인 금지", "잠들기 30분 전 폰 내려놓기", "12시 전에 눕기" - - 체형관리: "기상 직후 스트레칭 10분", "유산소 운동하기", "저녁 식사 후 야식 안 먹기", "계단으로 이동하기" - - 웰니스 • 마음챙김: "기상 직후 아침 명상", "일어나자마자 폰 보지 않기", "자기 전 스트레칭", "자기 전 감사일기 3가지", "내일 기대되는 것 1가지 적기" - - [공통 예시 (모든 카테고리에 활용 가능)] - - "물 2L 마시기", "베개 위 수건 깔기" - - 위 예시를 참고하되, 예시와 중복되지 않는 새로운 루틴을 추천해주세요. - - 응답은 반드시 다음 JSON 형식으로만 답변하세요: - {{ - "routines": ["루틴1", "루틴2", "루틴3", "루틴4", "루틴5", "루틴6"] - }} - """; /** * 챌린지 추천 프롬프트 템플릿 반환 From ff115bd3b9e2d8c8ec383257f4c13fb1e42fe4fc Mon Sep 17 00:00:00 2001 From: ssyoung02 Date: Thu, 22 Jan 2026 23:12:24 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor=20(Challenge):=20=EC=B1=8C?= =?UTF-8?q?=EB=A6=B0=EC=A7=80=20=EB=A3=A8=ED=8B=B4=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?AI=20=ED=94=84=EB=A1=AC=ED=8F=AC=ED=8A=B8=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infrastructure/prompt/ChallengePromptTemplate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java b/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java index aa390bf5..3b49d598 100644 --- a/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java +++ b/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java @@ -17,7 +17,7 @@ public class ChallengePromptTemplate { [절대 금지(하나라도 나오면 실패)] - 점검/확인/체크/정리/세탁/버리기 등 ‘관리/사후처리’ 목적 행동 - - 공중위생·기본 생활 의무 수준의 행동(샤워/양치/손씻기 등) + - 공중위생·기본 생활 의무 수준의 행동(샤워/양치/손씻기 등) 절대 금지 - 민간요법, 자연요법, 인터넷 카더라 및 DIY 레시피 형태의 루틴 제외 - 전문 시술/의학적 관리처럼 보이거나 자극적·과도한 케어 - 오타, 비표준어, 어색한 합성어, 실제 한국어에서 사용되지 않는 표현 금지 @@ -34,7 +34,7 @@ public class ChallengePromptTemplate { - 읽자마자 어떤 행동을 해야 하는지 떠올릴 수 있는 명확한 행동형 문장으로 작성합니다. [카테고리별 예시] - - 피부 컨디션: "아침 닦토하기", "세안 후 팩토하기", "매일 밤 모델링팩 하기", "손으로 얼굴 만지지 않기", "샤워 후 PDRN 마스크팩하기", "자기 전 페이스 괄사 마사지하기" + - 피부 컨디션: "아침 닦토하기", "세안 후 팩토하기", "매일 밤 모델링팩 하기", "손으로 얼굴 만지지 않기", "샤워 후 PDRN 마스크팩하기", "자기 전 페이스 괄사 마사지하기", "콜라겐 챙겨먹기" - 생활습관: "일어나자마자 물 한 잔", "6시간 이상 자기", "오후 3시 이후 카페인 금지", "잠들기 30분 전 폰 내려놓기", "12시 전에 눕기" - 체형관리: "기상 직후 스트레칭 10분", "유산소 운동하기", "저녁 식사 후 야식 안 먹기", "계단으로 이동하기" - 웰니스 • 마음챙김: "기상 직후 아침 명상", "일어나자마자 폰 보지 않기", "자기 전 스트레칭", "자기 전 감사일기 3가지", "내일 기대되는 것 1가지 적기" From f21d7f60f79574a4f6987b1de87a10ffdbba0b49 Mon Sep 17 00:00:00 2001 From: ssyoung02 Date: Thu, 22 Jan 2026 23:14:46 +0900 Subject: [PATCH 3/7] =?UTF-8?q?refactor=20(Challenge):=20=EC=B1=8C?= =?UTF-8?q?=EB=A6=B0=EC=A7=80=20=EB=A3=A8=ED=8B=B4=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?AI=20=ED=94=84=EB=A1=AC=ED=8F=AC=ED=8A=B8=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infrastructure/prompt/ChallengePromptTemplate.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java b/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java index 3b49d598..2c442582 100644 --- a/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java +++ b/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java @@ -34,14 +34,14 @@ public class ChallengePromptTemplate { - 읽자마자 어떤 행동을 해야 하는지 떠올릴 수 있는 명확한 행동형 문장으로 작성합니다. [카테고리별 예시] - - 피부 컨디션: "아침 닦토하기", "세안 후 팩토하기", "매일 밤 모델링팩 하기", "손으로 얼굴 만지지 않기", "샤워 후 PDRN 마스크팩하기", "자기 전 페이스 괄사 마사지하기", "콜라겐 챙겨먹기" - - 생활습관: "일어나자마자 물 한 잔", "6시간 이상 자기", "오후 3시 이후 카페인 금지", "잠들기 30분 전 폰 내려놓기", "12시 전에 눕기" + - 피부 컨디션: "세안 후 팩 하기", "매일 밤 모델링팩 하기", "손으로 얼굴 만지지 않기", "샤워 후 PDRN 마스크팩하기", "자기 전 페이스 괄사 마사지하기", "콜라겐 챙겨먹기" + - 생활습관: "일어나자마자 물 한 잔", "6시간 이상 자기", "오후 3시 이후 카페인 음료 피하기", "잠들기 30분 전 스마트폰 내려놓기", "12시 전에 눕기" - 체형관리: "기상 직후 스트레칭 10분", "유산소 운동하기", "저녁 식사 후 야식 안 먹기", "계단으로 이동하기" - - 웰니스 • 마음챙김: "기상 직후 아침 명상", "일어나자마자 폰 보지 않기", "자기 전 스트레칭", "자기 전 감사일기 3가지", "내일 기대되는 것 1가지 적기" + - 웰니스 • 마음챙김: "기상 직후 아침 명상", "일어나자마자 스마트폰 보지 않기", "자기 전 스트레칭", "자기 전 감사일기 3가지", "내일 기대되는 것 1가지 적기" [출력 전 자체 검수(필수)] - 6개를 만든 뒤, 아래 금지 단어/패턴이 포함되면 문장을 수정하거나 교체하세요: - 1) 빈도: 매일, 일일, 주, 일주일, N회, N번, 항상, 매번 + 1) 빈도: 매일, 일일, 일주일, N회, N번, 항상, 매번 2) 관리/사후처리: 점검, 확인, 체크, 정리, 세탁, 버리기 - 검수 과정은 출력하지 말고, 최종 JSON만 출력하세요. From b06f56c8287c6f1d4792d210bea47b641c810bfa Mon Sep 17 00:00:00 2001 From: ssyoung02 Date: Thu, 22 Jan 2026 23:16:00 +0900 Subject: [PATCH 4/7] =?UTF-8?q?refactor=20(Challenge):=20=EC=B1=8C?= =?UTF-8?q?=EB=A6=B0=EC=A7=80=20=EB=A3=A8=ED=8B=B4=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?AI=20=EB=AA=A8=EB=8D=B8=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-openai.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-openai.yaml b/src/main/resources/application-openai.yaml index 7c5e4a2b..1f6496ab 100644 --- a/src/main/resources/application-openai.yaml +++ b/src/main/resources/application-openai.yaml @@ -4,6 +4,6 @@ spring: api-key: ${OPENAI_API_KEY} chat: options: - model: ${OPENAI_MODEL:gpt-3.5-turbo} + model: ${OPENAI_MODEL:gpt-4.1-mini} temperature: ${OPENAI_TEMPERATURE:0.7} max-tokens: ${OPENAI_MAX_TOKENS:500} From 0b95354fcb8844dee27eb6bc8892ed330f95eabd Mon Sep 17 00:00:00 2001 From: ssyoung02 Date: Thu, 22 Jan 2026 23:23:00 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor=20(Challenge):=20=EC=B1=8C?= =?UTF-8?q?=EB=A6=B0=EC=A7=80=20=EB=A3=A8=ED=8B=B4=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?AI=20=ED=94=84=EB=A1=AC=ED=8F=AC=ED=8A=B8=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infrastructure/prompt/ChallengePromptTemplate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java b/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java index 2c442582..d179e03b 100644 --- a/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java +++ b/src/main/java/com/sopt/cherrish/domain/challenge/recommendation/infrastructure/prompt/ChallengePromptTemplate.java @@ -13,7 +13,7 @@ public class ChallengePromptTemplate { 사용자가 선택한 카테고리: "{homecareContent}" 목표: 사용자가 하루 1번 ‘했음/안했음’으로 체크할 수 있는 루틴 6개를 만드세요. - 결과 문구에는 빈도(매일/일일/주/일주일/N회/N번/항상/매번)를 절대 쓰지 마세요. + 결과 문구에는 빈도(매일/일일/일주일/N회/N번/항상/매번)를 절대 쓰지 마세요. [절대 금지(하나라도 나오면 실패)] - 점검/확인/체크/정리/세탁/버리기 등 ‘관리/사후처리’ 목적 행동 From 0c9c128f21d51b66553053a64a3c64c7c5649082 Mon Sep 17 00:00:00 2001 From: Kimgyuilli Date: Thu, 22 Jan 2026 23:56:25 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat(challenge):=20=EC=B2=B4=EB=A6=AC=20?= =?UTF-8?q?=EB=A0=88=EB=B2=A8=200~4=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/model/CherryLevel.java | 3 ++- .../core/exception/ChallengeErrorCode.java | 2 +- .../domain/model/DemoChallengeStatistics.java | 18 ++++++++++++------ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/sopt/cherrish/domain/challenge/core/domain/model/CherryLevel.java b/src/main/java/com/sopt/cherrish/domain/challenge/core/domain/model/CherryLevel.java index 0e431f3f..373d21ec 100644 --- a/src/main/java/com/sopt/cherrish/domain/challenge/core/domain/model/CherryLevel.java +++ b/src/main/java/com/sopt/cherrish/domain/challenge/core/domain/model/CherryLevel.java @@ -18,7 +18,8 @@ @RequiredArgsConstructor public enum CherryLevel { - LEVEL_1(1, "몽롱체리"), // 0-24% + LEVEL_0(0, "몽롱체리"), // completedCount == 0 + LEVEL_1(1, "몽롱체리"), // 1개 이상, 0-24% LEVEL_2(2, "뽀득체리"), // 25-49% LEVEL_3(3, "팡팡체리"), // 50-74% LEVEL_4(4, "꾸꾸체리"); // 75-100% diff --git a/src/main/java/com/sopt/cherrish/domain/challenge/core/exception/ChallengeErrorCode.java b/src/main/java/com/sopt/cherrish/domain/challenge/core/exception/ChallengeErrorCode.java index cad0aac7..ebcf8463 100644 --- a/src/main/java/com/sopt/cherrish/domain/challenge/core/exception/ChallengeErrorCode.java +++ b/src/main/java/com/sopt/cherrish/domain/challenge/core/exception/ChallengeErrorCode.java @@ -20,7 +20,7 @@ public enum ChallengeErrorCode implements ErrorType { DUPLICATE_ROUTINE_IDS("CH009", "중복된 루틴 ID가 포함되어 있습니다", 400), CHALLENGE_NOT_ACTIVE("CH010", "비활성 챌린지에는 루틴을 추가할 수 없습니다", 400), CUSTOM_ROUTINE_LIMIT_EXCEEDED("CH011", "최대로 추가할 수 있는 루틴은 20개입니다", 400), - INVALID_CHERRY_LEVEL("CH012", "유효하지 않은 체리 레벨입니다 (1-4)", 400); + INVALID_CHERRY_LEVEL("CH012", "유효하지 않은 체리 레벨입니다 (0-4)", 400); private final String code; private final String message; diff --git a/src/main/java/com/sopt/cherrish/domain/challenge/demo/domain/model/DemoChallengeStatistics.java b/src/main/java/com/sopt/cherrish/domain/challenge/demo/domain/model/DemoChallengeStatistics.java index 3939e690..57e4c602 100644 --- a/src/main/java/com/sopt/cherrish/domain/challenge/demo/domain/model/DemoChallengeStatistics.java +++ b/src/main/java/com/sopt/cherrish/domain/challenge/demo/domain/model/DemoChallengeStatistics.java @@ -47,14 +47,14 @@ public class DemoChallengeStatistics extends BaseTimeEntity { private Integer totalRoutineCount; @Column(nullable = false, name = "cherry_level") - private Integer cherryLevel = 1; + private Integer cherryLevel = 0; @Builder private DemoChallengeStatistics(DemoChallenge demoChallenge, Integer totalRoutineCount) { this.demoChallenge = demoChallenge; this.completedCount = 0; this.totalRoutineCount = totalRoutineCount; - this.cherryLevel = 1; + this.cherryLevel = 0; } /** @@ -86,10 +86,15 @@ public int getProgressPercentage() { /** * 완료 진행률 기반 체리 레벨 계산 + * - 레벨 0: completedCount == 0 (몽롱체리) + * - 레벨 1: 1개 이상, 0% ~ 24.99% + * - 레벨 2: 25% ~ 49.99% + * - 레벨 3: 50% ~ 74.99% + * - 레벨 4: 75% ~ 100% */ public int calculateCherryLevel() { - if (totalRoutineCount == 0) { - return 1; + if (completedCount == 0) { + return 0; } double progressPercentage = getProgressPercentage(); @@ -110,7 +115,7 @@ public int calculateCherryLevel() { * 현재 레벨 구간 내에서의 진척도 계산 (0-100%) */ public double getProgressToNextLevel() { - if (totalRoutineCount == 0) { + if (totalRoutineCount == 0 || completedCount == 0) { return 0.0; } @@ -130,11 +135,12 @@ public double getProgressToNextLevel() { /** * 다음 레벨까지 남은 루틴 개수 계산 + * 레벨 0, 1일 때는 레벨 2(25%)까지 남은 개수 반환 * 레벨 4일 때는 100%까지 남은 루틴 개수를 반환 */ public int getRemainingRoutinesToNextLevel() { double nextThreshold = switch (cherryLevel) { - case 1 -> LEVEL_2_THRESHOLD; + case 0, 1 -> LEVEL_2_THRESHOLD; case 2 -> LEVEL_3_THRESHOLD; case 3 -> LEVEL_4_THRESHOLD; default -> 100.0; From 91b78c85d4f4dd5eec7f23db9cd9fabec8cd2482 Mon Sep 17 00:00:00 2001 From: Kimgyuilli Date: Fri, 23 Jan 2026 00:21:19 +0900 Subject: [PATCH 7/7] =?UTF-8?q?docs(challenge):=20javadocs=20=EC=84=A4?= =?UTF-8?q?=EB=AA=85=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cherrish/domain/challenge/core/domain/model/CherryLevel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/sopt/cherrish/domain/challenge/core/domain/model/CherryLevel.java b/src/main/java/com/sopt/cherrish/domain/challenge/core/domain/model/CherryLevel.java index 373d21ec..6ae3bac8 100644 --- a/src/main/java/com/sopt/cherrish/domain/challenge/core/domain/model/CherryLevel.java +++ b/src/main/java/com/sopt/cherrish/domain/challenge/core/domain/model/CherryLevel.java @@ -35,6 +35,7 @@ public enum CherryLevel { * 레벨 숫자로 CherryLevel 찾기 * * @param level 체리 레벨 (1-4) + * 데모용으로 현재 (0-4) * @return 해당하는 CherryLevel enum * @throws ChallengeException 존재하지 않는 레벨인 경우 */