From 01d874fb54571081477f5c301f706a73a565babe Mon Sep 17 00:00:00 2001 From: sehi55 Date: Thu, 13 Aug 2026 04:02:35 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=EA=B8=B0=EB=8A=A5:=20=ED=94=BC=EB=B6=80=20?= =?UTF-8?q?=EC=A0=90=EC=88=98=20=EC=8B=A0=EB=A2=B0=EB=8F=84=20=EC=A0=95?= =?UTF-8?q?=EC=B1=85=20=EA=B4=80=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/SkinScorePolicyService.java | 34 +++++++++++++ .../skinpolicy/domain/SkinScorePolicy.java | 21 ++++++++ .../SkinScorePolicyJpaEntity.java | 44 +++++++++++++++++ .../SkinScorePolicyJpaRepository.java | 6 +++ .../SkinScorePolicyController.java | 42 ++++++++++++++++ src/main/resources/static/css/admin.css | 8 +++ .../templates/fragments/sidebar.html | 6 +++ .../templates/skin-score-policy.html | 46 +++++++++++++++++ .../SkinScorePolicyServiceTest.java | 49 +++++++++++++++++++ 9 files changed, 256 insertions(+) create mode 100644 src/main/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyService.java create mode 100644 src/main/java/com/seoulection/admin/skinpolicy/domain/SkinScorePolicy.java create mode 100644 src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaEntity.java create mode 100644 src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaRepository.java create mode 100644 src/main/java/com/seoulection/admin/skinpolicy/presentation/SkinScorePolicyController.java create mode 100644 src/main/resources/templates/skin-score-policy.html create mode 100644 src/test/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyServiceTest.java diff --git a/src/main/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyService.java b/src/main/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyService.java new file mode 100644 index 0000000..3f49c1c --- /dev/null +++ b/src/main/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyService.java @@ -0,0 +1,34 @@ +package com.seoulection.admin.skinpolicy.application; + +import com.seoulection.admin.skinpolicy.domain.SkinScorePolicy; +import com.seoulection.admin.skinpolicy.infrastructure.SkinScorePolicyJpaEntity; +import com.seoulection.admin.skinpolicy.infrastructure.SkinScorePolicyJpaRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +public class SkinScorePolicyService { + private final SkinScorePolicyJpaRepository repository; + + public SkinScorePolicyService(SkinScorePolicyJpaRepository repository) { + this.repository = repository; + } + + @Transactional(readOnly = true) + public List findAll() { + return repository.findAll().stream().map(SkinScorePolicyJpaEntity::toDomain) + .sorted(java.util.Comparator.comparing(SkinScorePolicy::featureKey)).toList(); + } + + @Transactional + public void update(String featureKey, double surveyReliability, double photoReliability, + double inconsistentSurveyFactor, String policyVersion) { + SkinScorePolicy current = repository.findById(featureKey) + .orElseThrow(() -> new IllegalArgumentException("없는 피부 항목입니다: " + featureKey)) + .toDomain(); + repository.save(SkinScorePolicyJpaEntity.from(new SkinScorePolicy(featureKey, current.label(), + surveyReliability, photoReliability, inconsistentSurveyFactor, policyVersion.trim()))); + } +} diff --git a/src/main/java/com/seoulection/admin/skinpolicy/domain/SkinScorePolicy.java b/src/main/java/com/seoulection/admin/skinpolicy/domain/SkinScorePolicy.java new file mode 100644 index 0000000..c468786 --- /dev/null +++ b/src/main/java/com/seoulection/admin/skinpolicy/domain/SkinScorePolicy.java @@ -0,0 +1,21 @@ +package com.seoulection.admin.skinpolicy.domain; + +public record SkinScorePolicy(String featureKey, String label, double surveyReliability, + double photoReliability, double inconsistentSurveyFactor, + String policyVersion) { + public SkinScorePolicy { + validate(surveyReliability, "설문 신뢰도"); + validate(photoReliability, "사진 신뢰도"); + validate(inconsistentSurveyFactor, "불일치 계수"); + if (surveyReliability + photoReliability <= 0) { + throw new IllegalArgumentException("설문·사진 신뢰도가 모두 0일 수 없습니다."); + } + if (policyVersion == null || policyVersion.isBlank()) { + throw new IllegalArgumentException("정책 버전은 비워둘 수 없습니다."); + } + } + + private static void validate(double value, String name) { + if (value < 0 || value > 1) throw new IllegalArgumentException(name + "는 0~1이어야 합니다."); + } +} diff --git a/src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaEntity.java b/src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaEntity.java new file mode 100644 index 0000000..8b604b7 --- /dev/null +++ b/src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaEntity.java @@ -0,0 +1,44 @@ +package com.seoulection.admin.skinpolicy.infrastructure; + +import com.seoulection.admin.skinpolicy.domain.SkinScorePolicy; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "skin_score_policy") +public class SkinScorePolicyJpaEntity { + @Id @Column(name = "feature_key", length = 64) + private String featureKey; + @Column(nullable = false, length = 64) + private String label; + @Column(name = "survey_reliability", nullable = false) + private double surveyReliability; + @Column(name = "photo_reliability", nullable = false) + private double photoReliability; + @Column(name = "inconsistent_survey_factor", nullable = false) + private double inconsistentSurveyFactor; + @Column(name = "policy_version", nullable = false, length = 32) + private String policyVersion; + + protected SkinScorePolicyJpaEntity() {} + + private SkinScorePolicyJpaEntity(SkinScorePolicy policy) { + this.featureKey = policy.featureKey(); + this.label = policy.label(); + this.surveyReliability = policy.surveyReliability(); + this.photoReliability = policy.photoReliability(); + this.inconsistentSurveyFactor = policy.inconsistentSurveyFactor(); + this.policyVersion = policy.policyVersion(); + } + + public static SkinScorePolicyJpaEntity from(SkinScorePolicy policy) { + return new SkinScorePolicyJpaEntity(policy); + } + + public SkinScorePolicy toDomain() { + return new SkinScorePolicy(featureKey, label, surveyReliability, photoReliability, + inconsistentSurveyFactor, policyVersion); + } +} diff --git a/src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaRepository.java b/src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaRepository.java new file mode 100644 index 0000000..1ee16cc --- /dev/null +++ b/src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaRepository.java @@ -0,0 +1,6 @@ +package com.seoulection.admin.skinpolicy.infrastructure; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SkinScorePolicyJpaRepository extends JpaRepository { +} diff --git a/src/main/java/com/seoulection/admin/skinpolicy/presentation/SkinScorePolicyController.java b/src/main/java/com/seoulection/admin/skinpolicy/presentation/SkinScorePolicyController.java new file mode 100644 index 0000000..ea65a6d --- /dev/null +++ b/src/main/java/com/seoulection/admin/skinpolicy/presentation/SkinScorePolicyController.java @@ -0,0 +1,42 @@ +package com.seoulection.admin.skinpolicy.presentation; + +import com.seoulection.admin.skinpolicy.application.SkinScorePolicyService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +@Controller +public class SkinScorePolicyController { + private final SkinScorePolicyService service; + + public SkinScorePolicyController(SkinScorePolicyService service) { + this.service = service; + } + + @GetMapping("/admin/skin-score-policy") + public String page(Model model) { + model.addAttribute("policies", service.findAll()); + return "skin-score-policy"; + } + + @PostMapping("/admin/skin-score-policy/{featureKey}") + public String update(@PathVariable String featureKey, + @RequestParam double surveyReliability, + @RequestParam double photoReliability, + @RequestParam double inconsistentSurveyFactor, + @RequestParam String policyVersion, + RedirectAttributes redirectAttributes) { + try { + service.update(featureKey, surveyReliability, photoReliability, + inconsistentSurveyFactor, policyVersion); + redirectAttributes.addFlashAttribute("successMessage", featureKey + " 정책을 저장했습니다."); + } catch (IllegalArgumentException e) { + redirectAttributes.addFlashAttribute("errorMessage", e.getMessage()); + } + return "redirect:/admin/skin-score-policy"; + } +} diff --git a/src/main/resources/static/css/admin.css b/src/main/resources/static/css/admin.css index 9e9b8ac..38f6a43 100644 --- a/src/main/resources/static/css/admin.css +++ b/src/main/resources/static/css/admin.css @@ -177,6 +177,7 @@ a { color: inherit; } } .alert-success { background: var(--success-soft); color: var(--success); } +.alert-error { background: var(--danger-soft); color: var(--danger); } .alert-notice { background: var(--warning-soft); color: var(--warning); } /* ── Cards ── */ @@ -243,6 +244,13 @@ input::placeholder { color: var(--text-tertiary); } .form-row { display: flex; gap: 10px; } .form-row input { flex: 1; } +.policy-form { + display: grid; + grid-template-columns: repeat(4, minmax(90px, 1fr)) auto; + gap: 8px; + align-items: center; +} + .toggle-group { display: flex; flex-wrap: wrap; gap: 8px; } .toggle-option { margin: 0; cursor: pointer; } .toggle-option input { position: absolute; width: 1px; height: 1px; opacity: 0; } diff --git a/src/main/resources/templates/fragments/sidebar.html b/src/main/resources/templates/fragments/sidebar.html index 69eb0ef..f584960 100644 --- a/src/main/resources/templates/fragments/sidebar.html +++ b/src/main/resources/templates/fragments/sidebar.html @@ -49,6 +49,12 @@ 설문 + + + + + 피부 점수 정책 + diff --git a/src/main/resources/templates/skin-score-policy.html b/src/main/resources/templates/skin-score-policy.html new file mode 100644 index 0000000..a19c741 --- /dev/null +++ b/src/main/resources/templates/skin-score-policy.html @@ -0,0 +1,46 @@ + + + + + + 피부 점수 정책 | Seoulection Admin + + + +
+ +
+

피부 점수 정책

+

설문과 사진 점수를 병합할 때 사용할 항목별 신뢰도를 관리합니다.

+
+
+
+

+ 입력값은 최종 퍼센트가 아니라 정규화 전 신뢰도입니다. + 예: 설문 0.8·사진 0.8은 최종 50:50입니다. 설문 답이 불일치하면 설문 신뢰도에 불일치 계수를 곱합니다. + 저장 즉시 새 피부 결과 조회와 추천에 반영됩니다. +

+
+ + + + + + + + +
피부 항목설문 신뢰도사진 신뢰도불일치 계수정책 버전

+
+ + + + + +
+
+
+
+
+
+ + diff --git a/src/test/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyServiceTest.java b/src/test/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyServiceTest.java new file mode 100644 index 0000000..30a97f0 --- /dev/null +++ b/src/test/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyServiceTest.java @@ -0,0 +1,49 @@ +package com.seoulection.admin.skinpolicy.application; + +import com.seoulection.admin.skinpolicy.domain.SkinScorePolicy; +import com.seoulection.admin.skinpolicy.infrastructure.SkinScorePolicyJpaEntity; +import com.seoulection.admin.skinpolicy.infrastructure.SkinScorePolicyJpaRepository; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; + +@ExtendWith(MockitoExtension.class) +class SkinScorePolicyServiceTest { + @Mock SkinScorePolicyJpaRepository repository; + @InjectMocks SkinScorePolicyService service; + + @Test + void updatePreservesFeatureLabelAndStoresReliabilities() { + var current = new SkinScorePolicy("water_score", "Hydration", 0.8, 0.2, 0.7, "v1"); + given(repository.findById("water_score")).willReturn( + Optional.of(SkinScorePolicyJpaEntity.from(current))); + + service.update("water_score", 0.7, 0.3, 0.6, "skin-score-v2"); + + var captor = ArgumentCaptor.forClass(SkinScorePolicyJpaEntity.class); + then(repository).should().save(captor.capture()); + assertThat(captor.getValue().toDomain()).isEqualTo( + new SkinScorePolicy("water_score", "Hydration", 0.7, 0.3, 0.6, "skin-score-v2")); + } + + @Test + void updateRejectsReliabilityOutsideZeroToOne() { + var current = new SkinScorePolicy("water_score", "Hydration", 0.8, 0.2, 0.7, "v1"); + given(repository.findById("water_score")).willReturn( + Optional.of(SkinScorePolicyJpaEntity.from(current))); + + assertThatThrownBy(() -> service.update("water_score", 1.1, 0.2, 0.7, "v2")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("0~1"); + } +} From 1944749f1886950b1679ae067a7047791717d149 Mon Sep 17 00:00:00 2001 From: sehi55 Date: Fri, 14 Aug 2026 04:46:59 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=EA=B8=B0=EB=8A=A5:=20=ED=94=BC=EB=B6=80=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=ED=8C=90=EC=A0=95=20=EA=B2=BD=EA=B3=84=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/SkinScorePolicyService.java | 6 +++--- .../skinpolicy/domain/SkinScorePolicy.java | 6 ++++++ .../SkinScorePolicyJpaEntity.java | 8 +++++++- .../SkinScorePolicyController.java | 8 +++----- src/main/resources/static/css/admin.css | 2 +- .../resources/templates/skin-score-policy.html | 18 +++++++++--------- .../SkinScorePolicyServiceTest.java | 14 +++++++------- 7 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyService.java b/src/main/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyService.java index 3f49c1c..acdb19b 100644 --- a/src/main/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyService.java +++ b/src/main/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyService.java @@ -23,12 +23,12 @@ public List findAll() { } @Transactional - public void update(String featureKey, double surveyReliability, double photoReliability, - double inconsistentSurveyFactor, String policyVersion) { + public void update(String featureKey, double badBoundary, double goodBoundary, String policyVersion) { SkinScorePolicy current = repository.findById(featureKey) .orElseThrow(() -> new IllegalArgumentException("없는 피부 항목입니다: " + featureKey)) .toDomain(); repository.save(SkinScorePolicyJpaEntity.from(new SkinScorePolicy(featureKey, current.label(), - surveyReliability, photoReliability, inconsistentSurveyFactor, policyVersion.trim()))); + current.surveyReliability(), current.photoReliability(), current.inconsistentSurveyFactor(), + badBoundary, goodBoundary, policyVersion.trim()))); } } diff --git a/src/main/java/com/seoulection/admin/skinpolicy/domain/SkinScorePolicy.java b/src/main/java/com/seoulection/admin/skinpolicy/domain/SkinScorePolicy.java index c468786..e0829ef 100644 --- a/src/main/java/com/seoulection/admin/skinpolicy/domain/SkinScorePolicy.java +++ b/src/main/java/com/seoulection/admin/skinpolicy/domain/SkinScorePolicy.java @@ -2,11 +2,17 @@ public record SkinScorePolicy(String featureKey, String label, double surveyReliability, double photoReliability, double inconsistentSurveyFactor, + double badBoundary, double goodBoundary, String policyVersion) { public SkinScorePolicy { validate(surveyReliability, "설문 신뢰도"); validate(photoReliability, "사진 신뢰도"); validate(inconsistentSurveyFactor, "불일치 계수"); + validate(badBoundary, "Bad 경계"); + validate(goodBoundary, "Good 경계"); + if (badBoundary > goodBoundary) { + throw new IllegalArgumentException("Bad 경계는 Good 경계보다 클 수 없습니다."); + } if (surveyReliability + photoReliability <= 0) { throw new IllegalArgumentException("설문·사진 신뢰도가 모두 0일 수 없습니다."); } diff --git a/src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaEntity.java b/src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaEntity.java index 8b604b7..f818ec1 100644 --- a/src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaEntity.java +++ b/src/main/java/com/seoulection/admin/skinpolicy/infrastructure/SkinScorePolicyJpaEntity.java @@ -19,6 +19,10 @@ public class SkinScorePolicyJpaEntity { private double photoReliability; @Column(name = "inconsistent_survey_factor", nullable = false) private double inconsistentSurveyFactor; + @Column(name = "bad_boundary", nullable = false) + private double badBoundary; + @Column(name = "good_boundary", nullable = false) + private double goodBoundary; @Column(name = "policy_version", nullable = false, length = 32) private String policyVersion; @@ -30,6 +34,8 @@ private SkinScorePolicyJpaEntity(SkinScorePolicy policy) { this.surveyReliability = policy.surveyReliability(); this.photoReliability = policy.photoReliability(); this.inconsistentSurveyFactor = policy.inconsistentSurveyFactor(); + this.badBoundary = policy.badBoundary(); + this.goodBoundary = policy.goodBoundary(); this.policyVersion = policy.policyVersion(); } @@ -39,6 +45,6 @@ public static SkinScorePolicyJpaEntity from(SkinScorePolicy policy) { public SkinScorePolicy toDomain() { return new SkinScorePolicy(featureKey, label, surveyReliability, photoReliability, - inconsistentSurveyFactor, policyVersion); + inconsistentSurveyFactor, badBoundary, goodBoundary, policyVersion); } } diff --git a/src/main/java/com/seoulection/admin/skinpolicy/presentation/SkinScorePolicyController.java b/src/main/java/com/seoulection/admin/skinpolicy/presentation/SkinScorePolicyController.java index ea65a6d..b489c9c 100644 --- a/src/main/java/com/seoulection/admin/skinpolicy/presentation/SkinScorePolicyController.java +++ b/src/main/java/com/seoulection/admin/skinpolicy/presentation/SkinScorePolicyController.java @@ -25,14 +25,12 @@ public String page(Model model) { @PostMapping("/admin/skin-score-policy/{featureKey}") public String update(@PathVariable String featureKey, - @RequestParam double surveyReliability, - @RequestParam double photoReliability, - @RequestParam double inconsistentSurveyFactor, + @RequestParam double badBoundary, + @RequestParam double goodBoundary, @RequestParam String policyVersion, RedirectAttributes redirectAttributes) { try { - service.update(featureKey, surveyReliability, photoReliability, - inconsistentSurveyFactor, policyVersion); + service.update(featureKey, badBoundary, goodBoundary, policyVersion); redirectAttributes.addFlashAttribute("successMessage", featureKey + " 정책을 저장했습니다."); } catch (IllegalArgumentException e) { redirectAttributes.addFlashAttribute("errorMessage", e.getMessage()); diff --git a/src/main/resources/static/css/admin.css b/src/main/resources/static/css/admin.css index 38f6a43..46d5ace 100644 --- a/src/main/resources/static/css/admin.css +++ b/src/main/resources/static/css/admin.css @@ -246,7 +246,7 @@ input::placeholder { color: var(--text-tertiary); } .policy-form { display: grid; - grid-template-columns: repeat(4, minmax(90px, 1fr)) auto; + grid-template-columns: minmax(90px, 1fr) repeat(2, minmax(80px, 1fr)) minmax(110px, 1fr) auto; gap: 8px; align-items: center; } diff --git a/src/main/resources/templates/skin-score-policy.html b/src/main/resources/templates/skin-score-policy.html index a19c741..40f751c 100644 --- a/src/main/resources/templates/skin-score-policy.html +++ b/src/main/resources/templates/skin-score-policy.html @@ -11,26 +11,26 @@

피부 점수 정책

-

설문과 사진 점수를 병합할 때 사용할 항목별 신뢰도를 관리합니다.

+

항목별 점수 원천과 피부 상태 판정 경계를 관리합니다.

- 입력값은 최종 퍼센트가 아니라 정규화 전 신뢰도입니다. - 예: 설문 0.8·사진 0.8은 최종 50:50입니다. 설문 답이 불일치하면 설문 신뢰도에 불일치 계수를 곱합니다. - 저장 즉시 새 피부 결과 조회와 추천에 반영됩니다. + CORE 항목은 설문 100%, 나머지 항목은 사진 100%로 고정됩니다. + 점수가 Bad 경계 이하이면 BAD, Good 경계 이상이면 GOOD, 사이는 OKAY로 판정합니다. + 경계 변경은 새 피부 결과 조회와 추천에 즉시 반영됩니다.

- + -
피부 항목설문 신뢰도사진 신뢰도불일치 계수정책 버전
피부 항목점수 원천Bad 경계Good 경계정책 버전

+
- - - + + +
diff --git a/src/test/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyServiceTest.java b/src/test/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyServiceTest.java index 30a97f0..8d1b1f0 100644 --- a/src/test/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyServiceTest.java +++ b/src/test/java/com/seoulection/admin/skinpolicy/application/SkinScorePolicyServiceTest.java @@ -23,26 +23,26 @@ class SkinScorePolicyServiceTest { @InjectMocks SkinScorePolicyService service; @Test - void updatePreservesFeatureLabelAndStoresReliabilities() { - var current = new SkinScorePolicy("water_score", "Hydration", 0.8, 0.2, 0.7, "v1"); + void updatePreservesFeatureSourceAndStoresBoundaries() { + var current = new SkinScorePolicy("water_score", "Hydration", 0.8, 0.2, 0.7, 0.398, 0.696, "v1"); given(repository.findById("water_score")).willReturn( Optional.of(SkinScorePolicyJpaEntity.from(current))); - service.update("water_score", 0.7, 0.3, 0.6, "skin-score-v2"); + service.update("water_score", 0.4, 0.7, "skin-score-v2"); var captor = ArgumentCaptor.forClass(SkinScorePolicyJpaEntity.class); then(repository).should().save(captor.capture()); assertThat(captor.getValue().toDomain()).isEqualTo( - new SkinScorePolicy("water_score", "Hydration", 0.7, 0.3, 0.6, "skin-score-v2")); + new SkinScorePolicy("water_score", "Hydration", 0.8, 0.2, 0.7, 0.4, 0.7, "skin-score-v2")); } @Test - void updateRejectsReliabilityOutsideZeroToOne() { - var current = new SkinScorePolicy("water_score", "Hydration", 0.8, 0.2, 0.7, "v1"); + void updateRejectsBoundaryOutsideZeroToOne() { + var current = new SkinScorePolicy("water_score", "Hydration", 0.8, 0.2, 0.7, 0.398, 0.696, "v1"); given(repository.findById("water_score")).willReturn( Optional.of(SkinScorePolicyJpaEntity.from(current))); - assertThatThrownBy(() -> service.update("water_score", 1.1, 0.2, 0.7, "v2")) + assertThatThrownBy(() -> service.update("water_score", 1.1, 0.7, "v2")) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("0~1"); } From 387e56255c33bb6fdfcfa61f31bc625f7d68d07c Mon Sep 17 00:00:00 2001 From: sehi55 Date: Sat, 15 Aug 2026 10:53:52 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EC=88=98=EC=A0=95:=20=EC=96=B4=EB=93=9C?= =?UTF-8?q?=EB=AF=BC=20=EB=B8=8C=EB=9E=9C=EB=93=9C=EB=AA=85=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/static/css/admin.css | 2 +- src/main/resources/templates/fragments/sidebar.html | 4 ++-- src/main/resources/templates/home.html | 2 +- src/main/resources/templates/products.html | 2 +- src/main/resources/templates/skin-score-policy.html | 2 +- src/main/resources/templates/survey.html | 2 +- src/main/resources/templates/videos.html | 2 +- src/main/resources/templates/youtubers.html | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/resources/static/css/admin.css b/src/main/resources/static/css/admin.css index 46d5ace..e9acc41 100644 --- a/src/main/resources/static/css/admin.css +++ b/src/main/resources/static/css/admin.css @@ -1,5 +1,5 @@ /* - * Seoulection Admin — 공용 디자인 시스템. + * MySeoulection Admin — 공용 디자인 시스템. * * 이전엔 페이지마다(products.html, videos.html, ...)