From 5d77ccfd10a6f774d7cfb45e873c32fcc232ffd1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?=
 <78216059+bayy1216@users.noreply.github.com>
Date: Fri, 31 May 2024 20:45:43 +0900
Subject: [PATCH 1/3] =?UTF-8?q?[Feat]:=20api=20=EB=A0=88=EC=9D=B4=EC=96=B4?=
 =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20(#14)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../controller/admin/AdminController.java     |  9 +++
 .../zzansuni/controller/admin/AdminReq.java   | 62 +++++++++++++++++++
 .../challengegroup/ChallengeGroupCommand.java | 45 ++++++++++++++
 .../challengegroup/ChallengeGroupService.java | 11 ++++
 4 files changed, 127 insertions(+)
 create mode 100644 zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminReq.java
 create mode 100644 zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupCommand.java
 create mode 100644 zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java

diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminController.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminController.java
index c31bcb0..1e9063f 100644
--- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminController.java
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminController.java
@@ -7,6 +7,7 @@
 import org.haedal.zzansuni.controller.auth.AuthReq;
 import org.haedal.zzansuni.core.api.ApiResponse;
 import org.haedal.zzansuni.domain.auth.AuthService;
+import org.haedal.zzansuni.domain.challengegroup.ChallengeGroupService;
 import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -18,6 +19,7 @@
 @RestController
 public class AdminController {
     private final AuthService authService;
+    private final ChallengeGroupService challengeGroupService;
 
     @ResponseStatus(HttpStatus.CREATED)
     @Operation(summary= "매니저 등록", description = "매니저를 등록한다.")
@@ -26,4 +28,11 @@ public ApiResponse<Void> createManager(@RequestBody @Valid AuthReq.EmailSignupRe
         authService.createManager(request.toCommand());
         return ApiResponse.success(null, "매니저 등록 성공");
     }
+
+    @ResponseStatus(HttpStatus.CREATED)
+    @Operation(summary = "챌린지 그룹 생성", description = "챌린지 그룹과 해당하는 챌린지를 생성합니다")
+    public ApiResponse<Void> createChallengeGroup(@RequestBody @Valid AdminReq.CreateChallengeGroupRequest request) {
+        challengeGroupService.createChallengeGroup(request.toCommand());
+        return ApiResponse.success(null, "챌린지 그룹 생성 성공");
+    }
 }
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminReq.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminReq.java
new file mode 100644
index 0000000..d785ab2
--- /dev/null
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminReq.java
@@ -0,0 +1,62 @@
+package org.haedal.zzansuni.controller.admin;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import org.haedal.zzansuni.domain.challengegroup.ChallengeCategory;
+import org.haedal.zzansuni.domain.challengegroup.ChallengeGroupCommand;
+import org.haedal.zzansuni.domain.challengegroup.DayType;
+
+import java.time.LocalDate;
+import java.util.List;
+
+public class AdminReq {
+    public record CreateChallengeGroupRequest(
+            @NotBlank(message = "title은 필수값입니다.")
+            String title,
+            @NotBlank(message = "content는 필수값입니다.")
+            String content,
+            @NotNull(message = "category는 필수값입니다.")
+            ChallengeCategory category,
+            @NotNull(message = "challenges는 필수값입니다.")
+            List<CreateChallengeRequest> challenges
+    ){
+       public ChallengeGroupCommand.Create toCommand() {
+            return ChallengeGroupCommand.Create.builder()
+                    .title(title)
+                    .content(content)
+                    .category(category)
+                    .challenges(challenges.stream().map(CreateChallengeRequest::toCommand).toList())
+                    .build();
+        }
+    }
+
+    public record CreateChallengeRequest(
+            @NotNull(message = "startDate는 필수값입니다.")
+            LocalDate startDate,
+            @NotNull(message = "endDate는 필수값입니다.")
+            LocalDate endDate,
+            @NotNull(message = "dayType은 필수값입니다.")
+            DayType dayType,
+            @NotNull(message = "requiredCount는 필수값입니다.")
+            Integer requiredCount,
+            @NotNull(message = "onceExp는 필수값입니다.")
+            Integer onceExp,
+            @NotNull(message = "successExp는 필수값입니다.")
+            Integer successExp,
+            @NotNull(message = "difficulty는 필수값입니다.")
+            Integer difficulty
+    ){
+        public ChallengeGroupCommand.CreateChallenge toCommand() {
+            return ChallengeGroupCommand.CreateChallenge.builder()
+                    .startDate(startDate)
+                    .endDate(endDate)
+                    .dayType(dayType)
+                    .requiredCount(requiredCount)
+                    .onceExp(onceExp)
+                    .successExp(successExp)
+                    .difficulty(difficulty)
+                    .build();
+        }
+    }
+
+}
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupCommand.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupCommand.java
new file mode 100644
index 0000000..11d66ae
--- /dev/null
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupCommand.java
@@ -0,0 +1,45 @@
+package org.haedal.zzansuni.domain.challengegroup;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Builder;
+import lombok.Getter;
+import org.haedal.zzansuni.controller.admin.AdminReq;
+
+import java.time.LocalDate;
+import java.util.List;
+
+public class ChallengeGroupCommand {
+    @Builder
+    @Getter
+    public static class Create {
+        @NotBlank(message = "title은 필수값입니다.")
+        private final String title;
+        @NotBlank(message = "content는 필수값입니다.")
+        private final String content;
+        @NotNull(message = "category는 필수값입니다.")
+        private final ChallengeCategory category;
+        @NotNull(message = "challenges는 필수값입니다.")
+        private final List<CreateChallenge> challenges;
+
+    }
+
+    @Builder
+    @Getter
+    public static class CreateChallenge {
+        @NotNull(message = "startDate는 필수값입니다.")
+        private final LocalDate startDate;
+        @NotNull(message = "endDate는 필수값입니다.")
+        private final LocalDate endDate;
+        @NotNull(message = "dayType은 필수값입니다.")
+        private final DayType dayType;
+        @NotNull(message = "requiredCount는 필수값입니다.")
+        private final Integer requiredCount;
+        @NotNull(message = "onceExp는 필수값입니다.")
+        private final Integer onceExp;
+        @NotNull(message = "successExp는 필수값입니다.")
+        private final Integer successExp;
+        @NotNull(message = "difficulty는 필수값입니다.")
+        private final Integer difficulty;
+    }
+}
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java
new file mode 100644
index 0000000..863eed1
--- /dev/null
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java
@@ -0,0 +1,11 @@
+package org.haedal.zzansuni.domain.challengegroup;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class ChallengeGroupService {
+    public void createChallengeGroup(ChallengeGroupCommand.Create command) {
+    }
+}

From 0df67b6668d1e7fb315107a34239ddf5e7cf119c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?=
 <78216059+bayy1216@users.noreply.github.com>
Date: Sat, 1 Jun 2024 00:54:24 +0900
Subject: [PATCH 2/3] =?UTF-8?q?[Feat]:=20=EC=82=AD=EC=A0=9C=20api=20?=
 =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#14)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../controller/admin/AdminController.java         | 15 ++++++++++-----
 .../challengegroup/ChallengeGroupService.java     |  3 +++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminController.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminController.java
index 1e9063f..5cd69f5 100644
--- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminController.java
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminController.java
@@ -9,10 +9,7 @@
 import org.haedal.zzansuni.domain.auth.AuthService;
 import org.haedal.zzansuni.domain.challengegroup.ChallengeGroupService;
 import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.ResponseStatus;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 @Tag(name = "admin", description = "관리자 API")
 @RequiredArgsConstructor
@@ -23,7 +20,7 @@ public class AdminController {
 
     @ResponseStatus(HttpStatus.CREATED)
     @Operation(summary= "매니저 등록", description = "매니저를 등록한다.")
-    @PostMapping("/api/auth/manager")
+    @PostMapping("/api/admin/auth/manager")
     public ApiResponse<Void> createManager(@RequestBody @Valid AuthReq.EmailSignupRequest request) {
         authService.createManager(request.toCommand());
         return ApiResponse.success(null, "매니저 등록 성공");
@@ -31,8 +28,16 @@ public ApiResponse<Void> createManager(@RequestBody @Valid AuthReq.EmailSignupRe
 
     @ResponseStatus(HttpStatus.CREATED)
     @Operation(summary = "챌린지 그룹 생성", description = "챌린지 그룹과 해당하는 챌린지를 생성합니다")
+    @PostMapping("/api/admin/challengeGroups")
     public ApiResponse<Void> createChallengeGroup(@RequestBody @Valid AdminReq.CreateChallengeGroupRequest request) {
         challengeGroupService.createChallengeGroup(request.toCommand());
         return ApiResponse.success(null, "챌린지 그룹 생성 성공");
     }
+
+    @Operation(summary = "챌린지 그룹 삭제", description = "챌린지 그룹을 삭제합니다")
+    @DeleteMapping("/api/admin/challengeGroups/{challengeGroupId}")
+    public ApiResponse<Void> deleteChallengeGroup(@PathVariable Long challengeGroupId) {
+        challengeGroupService.deleteChallengeGroup(challengeGroupId);
+        return ApiResponse.success(null, "챌린지 그룹 삭제 성공");
+    }
 }
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java
index 863eed1..5234da5 100644
--- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java
@@ -8,4 +8,7 @@
 public class ChallengeGroupService {
     public void createChallengeGroup(ChallengeGroupCommand.Create command) {
     }
+
+    public void deleteChallengeGroup(Long challengeGroupId) {
+    }
 }

From a2ed34bbbccaa922401c74606464e7e0d1ffe3d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?=
 <78216059+bayy1216@users.noreply.github.com>
Date: Sat, 1 Jun 2024 16:11:16 +0900
Subject: [PATCH 3/3] =?UTF-8?q?[Feat]:=20=EC=B1=8C=EB=A6=B0=EC=A7=80=20?=
 =?UTF-8?q?=EA=B7=B8=EB=A3=B9,=20=EC=B1=8C=EB=A6=B0=EC=A7=80=20=EC=83=9D?=
 =?UTF-8?q?=EC=84=B1=20(#14)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../zzansuni/controller/admin/AdminReq.java   |  5 ++++-
 .../domain/challengegroup/ChallengeGroup.java | 15 +++++++++++++
 .../challengegroup/ChallengeGroupCommand.java |  5 +++--
 .../challengegroup/ChallengeGroupReader.java  |  5 +++++
 .../challengegroup/ChallengeGroupService.java | 10 +++++++++
 .../challengegroup/ChallengeGroupStore.java   |  6 ++++++
 .../challengegroup/challenge/Challenge.java   | 13 ++++++++++++
 .../ChallengeGroupReaderImpl.java             | 20 ++++++++++++++++++
 .../ChallengeGroupRepository.java             |  7 +++++++
 .../ChallengeGroupStoreImpl.java              | 21 +++++++++++++++++++
 10 files changed, 104 insertions(+), 3 deletions(-)
 create mode 100644 zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupReader.java
 create mode 100644 zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupStore.java
 create mode 100644 zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupReaderImpl.java
 create mode 100644 zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupRepository.java
 create mode 100644 zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupStoreImpl.java

diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminReq.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminReq.java
index d785ab2..408fc4a 100644
--- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminReq.java
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/admin/AdminReq.java
@@ -15,6 +15,8 @@ public record CreateChallengeGroupRequest(
             String title,
             @NotBlank(message = "content는 필수값입니다.")
             String content,
+            @NotBlank(message = "guide는 필수값입니다.")
+            String guide,
             @NotNull(message = "category는 필수값입니다.")
             ChallengeCategory category,
             @NotNull(message = "challenges는 필수값입니다.")
@@ -24,8 +26,9 @@ public ChallengeGroupCommand.Create toCommand() {
             return ChallengeGroupCommand.Create.builder()
                     .title(title)
                     .content(content)
+                    .guide(guide)
                     .category(category)
-                    .challenges(challenges.stream().map(CreateChallengeRequest::toCommand).toList())
+                    .createChallenges(challenges.stream().map(CreateChallengeRequest::toCommand).toList())
                     .build();
         }
     }
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroup.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroup.java
index 103b6ed..0757e44 100644
--- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroup.java
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroup.java
@@ -36,4 +36,19 @@ public class ChallengeGroup extends BaseTimeEntity {
 
     @OneToMany(mappedBy = "challengeGroup", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
     private List<Challenge> challenges = new ArrayList<>();
+
+    public static ChallengeGroup create(ChallengeGroupCommand.Create command) {
+        List<Challenge> challenges = new ArrayList<>();
+        ChallengeGroup group =  ChallengeGroup.builder()
+                .category(command.getCategory())
+                .title(command.getTitle())
+                .content(command.getContent())
+                .guide(command.getGuide())
+                .cumulativeCount(0)
+                .challenges(challenges)
+                .build();
+        command.getCreateChallenges().stream().map(challenge -> Challenge.create(challenge, group))
+                .forEach(challenges::add);
+        return group;
+    }
 }
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupCommand.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupCommand.java
index 11d66ae..adc1b63 100644
--- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupCommand.java
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupCommand.java
@@ -4,7 +4,6 @@
 import jakarta.validation.constraints.NotNull;
 import lombok.Builder;
 import lombok.Getter;
-import org.haedal.zzansuni.controller.admin.AdminReq;
 
 import java.time.LocalDate;
 import java.util.List;
@@ -17,10 +16,12 @@ public static class Create {
         private final String title;
         @NotBlank(message = "content는 필수값입니다.")
         private final String content;
+        @NotBlank(message = "guide는 필수값입니다.")
+        private final String guide;
         @NotNull(message = "category는 필수값입니다.")
         private final ChallengeCategory category;
         @NotNull(message = "challenges는 필수값입니다.")
-        private final List<CreateChallenge> challenges;
+        private final List<CreateChallenge> createChallenges;
 
     }
 
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupReader.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupReader.java
new file mode 100644
index 0000000..d4e12e1
--- /dev/null
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupReader.java
@@ -0,0 +1,5 @@
+package org.haedal.zzansuni.domain.challengegroup;
+
+public interface ChallengeGroupReader {
+    ChallengeGroup getById(Long challengeGroupId);
+}
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java
index 5234da5..838f7c4 100644
--- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupService.java
@@ -2,13 +2,23 @@
 
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 @Service
 @RequiredArgsConstructor
 public class ChallengeGroupService {
+    private final ChallengeGroupStore challengeGroupStore;
+    private final ChallengeGroupReader challengeGroupReader;
+
+    @Transactional
     public void createChallengeGroup(ChallengeGroupCommand.Create command) {
+        ChallengeGroup challengeGroup = ChallengeGroup.create(command);
+        challengeGroupStore.save(challengeGroup);
     }
 
+    @Transactional
     public void deleteChallengeGroup(Long challengeGroupId) {
+        ChallengeGroup challengeGroup = challengeGroupReader.getById(challengeGroupId);
+        challengeGroupStore.delete(challengeGroup.getId());
     }
 }
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupStore.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupStore.java
new file mode 100644
index 0000000..b811150
--- /dev/null
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/ChallengeGroupStore.java
@@ -0,0 +1,6 @@
+package org.haedal.zzansuni.domain.challengegroup;
+
+public interface ChallengeGroupStore {
+    ChallengeGroup save(ChallengeGroup challengeGroup);
+    void delete(Long challengeGroupId);
+}
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/Challenge.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/Challenge.java
index 23008b5..ed0c203 100644
--- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/Challenge.java
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/challengegroup/challenge/Challenge.java
@@ -17,6 +17,7 @@
 import lombok.NoArgsConstructor;
 import org.haedal.zzansuni.domain.BaseTimeEntity;
 import org.haedal.zzansuni.domain.challengegroup.ChallengeGroup;
+import org.haedal.zzansuni.domain.challengegroup.ChallengeGroupCommand;
 import org.haedal.zzansuni.domain.challengegroup.DayType;
 
 @Entity
@@ -50,4 +51,16 @@ public class Challenge extends BaseTimeEntity {
     private LocalDate endDate;
 
 
+    public static Challenge create(ChallengeGroupCommand.CreateChallenge command, ChallengeGroup group) {
+        return Challenge.builder()
+                .challengeGroup(group)
+                .requiredCount(command.getRequiredCount())
+                .dayType(command.getDayType())
+                .onceExp(command.getOnceExp())
+                .successExp(command.getSuccessExp())
+                .difficulty(command.getDifficulty())
+                .startDate(command.getStartDate())
+                .endDate(command.getEndDate())
+                .build();
+    }
 }
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupReaderImpl.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupReaderImpl.java
new file mode 100644
index 0000000..f0e0229
--- /dev/null
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupReaderImpl.java
@@ -0,0 +1,20 @@
+package org.haedal.zzansuni.infrastructure.challengegroup;
+
+import lombok.RequiredArgsConstructor;
+import org.haedal.zzansuni.domain.challengegroup.ChallengeGroup;
+import org.haedal.zzansuni.domain.challengegroup.ChallengeGroupReader;
+import org.springframework.stereotype.Component;
+
+import java.util.NoSuchElementException;
+
+@Component
+@RequiredArgsConstructor
+public class ChallengeGroupReaderImpl implements ChallengeGroupReader {
+    private final ChallengeGroupRepository challengeGroupRepository;
+    @Override
+    public ChallengeGroup getById(Long challengeGroupId) {
+        return challengeGroupRepository
+                .findById(challengeGroupId)
+                .orElseThrow(NoSuchElementException::new);
+    }
+}
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupRepository.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupRepository.java
new file mode 100644
index 0000000..ab6d895
--- /dev/null
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupRepository.java
@@ -0,0 +1,7 @@
+package org.haedal.zzansuni.infrastructure.challengegroup;
+
+import org.haedal.zzansuni.domain.challengegroup.ChallengeGroup;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface ChallengeGroupRepository extends JpaRepository<ChallengeGroup, Long> {
+}
diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupStoreImpl.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupStoreImpl.java
new file mode 100644
index 0000000..e7b14fd
--- /dev/null
+++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/ChallengeGroupStoreImpl.java
@@ -0,0 +1,21 @@
+package org.haedal.zzansuni.infrastructure.challengegroup;
+
+import lombok.RequiredArgsConstructor;
+import org.haedal.zzansuni.domain.challengegroup.ChallengeGroup;
+import org.haedal.zzansuni.domain.challengegroup.ChallengeGroupStore;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class ChallengeGroupStoreImpl implements ChallengeGroupStore {
+    private final ChallengeGroupRepository challengeGroupRepository;
+    @Override
+    public ChallengeGroup save(ChallengeGroup challengeGroup) {
+        return challengeGroupRepository.save(challengeGroup);
+    }
+
+    @Override
+    public void delete(Long challengeGroupId) {
+        challengeGroupRepository.deleteById(challengeGroupId);
+    }
+}