From 7b864301e67417ebabfbf1c27fcce94027b19918 Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:13:06 +0900 Subject: [PATCH 01/16] =?UTF-8?q?[fix]=20#121=20http=20method=EB=A5=BC=20d?= =?UTF-8?q?elete=EC=97=90=EC=84=9C=20post=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin_be/domain/users/service/AdminUserService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/service/AdminUserService.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/service/AdminUserService.java index d6113c0f..1a857962 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/service/AdminUserService.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/service/AdminUserService.java @@ -85,7 +85,7 @@ public void deleteUbuntuAccount(String username) { try { log.info("Starting external API call to delete ubuntu account: {}", username); - userWebClient.delete() + userWebClient.post() .uri("/accounts/deleteuser/{username}", username) .retrieve() .toBodilessEntity() From b911d38e839e674aa7e297e47e854172af78c774 Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:13:39 +0900 Subject: [PATCH 02/16] =?UTF-8?q?[feat]=20#121=20Request=EB=A5=BC=20soft?= =?UTF-8?q?=20delete=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=B4=20Status?= =?UTF-8?q?=EC=97=90=20DELETED=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/DGU_AI_LAB/admin_be/domain/requests/entity/Status.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/entity/Status.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/entity/Status.java index 7c2fb5b6..2311b944 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/entity/Status.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/entity/Status.java @@ -1,5 +1,5 @@ package DGU_AI_LAB.admin_be.domain.requests.entity; public enum Status { - PENDING, DENIED, FULFILLED, ALL + PENDING, DENIED, FULFILLED, ALL, DELETED } From 5d325fd836fa92e59b2c274adbac143f1819db16 Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:37:16 +0900 Subject: [PATCH 03/16] =?UTF-8?q?[feat]=20#121=20Request=EB=A5=BC=20soft?= =?UTF-8?q?=20delete=ED=95=98=EB=8A=94=20=EB=B9=84=EC=A6=88=EB=8B=88?= =?UTF-8?q?=EC=8A=A4=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin_be/domain/requests/entity/Request.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/entity/Request.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/entity/Request.java index 1e107f7d..c8270681 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/entity/Request.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/entity/Request.java @@ -161,4 +161,14 @@ public void addGroup(Group group) { this.requestGroups.add(rg); } + /** + * Request의 상태를 DELETED로 변경합니다. (soft delete) + */ + public void delete() { + if (this.status == Status.DELETED) { + throw new BusinessException("이미 삭제된 요청입니다.", ErrorCode.INVALID_REQUEST_STATUS); + } + this.status = Status.DELETED; + } + } From e600bbeeb2947dab2cad0c70832b5c663ac8fd82 Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:37:48 +0900 Subject: [PATCH 04/16] =?UTF-8?q?[feat]=20#121=20=EC=9A=B0=EB=B6=84?= =?UTF-8?q?=ED=88=AC=20=EA=B3=84=EC=A0=95=20=EC=82=AD=EC=A0=9C=20=EC=8B=9C?= =?UTF-8?q?=20Request=EB=A5=BC=20soft=20delete=ED=95=98=EB=8F=84=EB=A1=9D?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../users/service/AdminUserService.java | 75 +++++++++++-------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/service/AdminUserService.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/service/AdminUserService.java index 1a857962..ca9c19d7 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/service/AdminUserService.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/service/AdminUserService.java @@ -3,7 +3,6 @@ import DGU_AI_LAB.admin_be.domain.requests.entity.Request; import DGU_AI_LAB.admin_be.domain.requests.repository.RequestRepository; import DGU_AI_LAB.admin_be.domain.users.dto.request.UserUpdateRequestDTO; -import DGU_AI_LAB.admin_be.domain.users.dto.response.MyInfoResponseDTO; import DGU_AI_LAB.admin_be.domain.users.dto.response.UserResponseDTO; import DGU_AI_LAB.admin_be.domain.users.dto.response.UserSummaryDTO; import DGU_AI_LAB.admin_be.domain.users.entity.User; @@ -19,6 +18,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClientResponseException; +import reactor.core.publisher.Mono; import java.util.List; @@ -43,35 +43,48 @@ public List getAllUsers() { } /** - * 유저 삭제 + * 유저 삭제 (soft delete 적용) + * 이와 동시에 해당 유저가 소유한 모든 Request(우분투 계정)의 상태를 'DELETED'로 변경하고 외부 시스템에서도 삭제합니다. */ + @Transactional public void deleteUser(Long userId) { - log.warn("[deleteUser] userId={} 삭제 시도", userId); - if (!userRepository.existsById(userId)) { - log.error("[deleteUser] userId={} 존재하지 않음", userId); - throw new EntityNotFoundException(ErrorCode.ENTITY_NOT_FOUND); + log.warn("[deleteUser] userId={} 논리적 삭제 시도", userId); + + User user = userRepository.findById(userId) + .orElseThrow(() -> { + log.error("[deleteUser] userId={} 존재하지 않음", userId); + return new EntityNotFoundException(ErrorCode.ENTITY_NOT_FOUND); + }); + + List userRequests = requestRepository.findAllByUser(user); + + if (!userRequests.isEmpty()) { + userRequests.forEach(request -> deleteUbuntuAccount(request.getUbuntuUsername())); + log.info("[deleteUser] userId={}와 연결된 모든 Request의 외부 계정 삭제 요청 완료", userId); + } else { + log.info("[deleteUser] userId={}와 연결된 Request가 없습니다. 외부 계정 삭제 요청을 건너뜁니다.", userId); } - userRepository.deleteById(userId); - log.info("[deleteUser] userId={} 삭제 완료", userId); + + user.updateUserInfo(null, false); + log.info("[deleteUser] userId={} 논리적 삭제 완료 (isActive=false)", userId); } /** * 유저 정보 수정 */ + @Transactional public UserResponseDTO updateUser(Long userId, UserUpdateRequestDTO request) { log.info("[updateUser] userId={} 정보 수정 시작", userId); - User user = userRepository.findById(userId) .orElseThrow(() -> new EntityNotFoundException(ErrorCode.ENTITY_NOT_FOUND)); - user.updateUserInfo(request.password(), request.isActive()); - log.info("[updateUser] userId={} 정보 수정 완료", userId); return UserResponseDTO.fromEntity(user); } /** * username으로 우분투 계정 삭제 + * Config Server에 요청을 보내 실제로 ubuntu 계정을 삭제하고, DB의 Request 엔티티 Status를 DELETED로 변경합니다. */ public void deleteUbuntuAccount(String username) { log.warn("[deleteUbuntuAccount] 우분투 계정 삭제 시도: {}", username); @@ -83,33 +96,35 @@ public void deleteUbuntuAccount(String username) { }); try { - log.info("Starting external API call to delete ubuntu account: {}", username); - + log.info("Starting Config Server API call to delete ubuntu account: {}", username); userWebClient.post() .uri("/accounts/deleteuser/{username}", username) .retrieve() + .onStatus(HttpStatus.BAD_REQUEST::equals, clientResponse -> + Mono.error(new BusinessException(ErrorCode.INVALID_USERNAME_FORMAT)) + ) + .onStatus(HttpStatus.NOT_FOUND::equals, clientResponse -> { + log.warn("외부 서버에 {} 계정이 이미 존재하지 않아 삭제가 불필요합니다.", username); + return Mono.empty(); + }) + .onStatus(WebClientResponseException.class::isInstance, clientResponse -> + clientResponse.bodyToMono(String.class) + .flatMap(body -> Mono.error(new BusinessException("우분투 계정 삭제 실패: " + body, ErrorCode.UBUNTU_USER_DELETION_FAILED))) + ) .toBodilessEntity() .block(); - log.info("External account deletion successful for account: {}", username); - - requestRepository.delete(request); - log.info("[deleteUbuntuAccount] {}에 대한 Request 정보 삭제 완료", username); - - } catch (WebClientResponseException e) { - log.error("External account deletion failed with status: {}, response body: {}", - e.getStatusCode(), e.getResponseBodyAsString(), e); + log.info("Config Server's deletion successful for account: {}", username); - // 외부 API가 404를 반환하면, 클라이언트에도 404를 반환하도록 한다. - if (e.getStatusCode() == HttpStatus.NOT_FOUND) { - throw new BusinessException(ErrorCode.ENTITY_NOT_FOUND); - } - // 404 이외의 다른 WebClient 에러는 기존 에러로 처리한다. - throw new BusinessException(ErrorCode.UBUNTU_USER_DELETION_FAILED); + request.delete(); + requestRepository.save(request); + log.info("[deleteUbuntuAccount] {}에 대한 Request 정보 상태를 DELETED로 변경 완료", username); + } catch (BusinessException e) { + throw e; } catch (Exception e) { - log.error("An unexpected error occurred during external account deletion.", e); - throw new BusinessException(ErrorCode.UBUNTU_USER_DELETION_FAILED); + log.error("An unexpected error occurred during Config Server's account deletion.", e); + throw new BusinessException("우분투 계정 삭제 중 예기치 않은 오류 발생.", ErrorCode.UBUNTU_USER_DELETION_FAILED); } } -} +} \ No newline at end of file From 86cc205d2ea4fed99f8dd54d60882f11f2a74217 Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:38:02 +0900 Subject: [PATCH 05/16] =?UTF-8?q?[feat]=20#121=20=EC=9C=A0=EC=A0=80=20?= =?UTF-8?q?=ED=83=88=ED=87=B4=20soft=20delete=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin_be/domain/users/controller/AdminUserController.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java index 3d7388f1..d762e389 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java @@ -9,7 +9,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -// 관리자용 유저 컨트롤러 @RestController @RequiredArgsConstructor @RequestMapping("/api/admin/users") @@ -33,7 +32,7 @@ public ResponseEntity> updateUser(@PathVariable Long id, @Val return SuccessResponse.ok(adminUserService.updateUser(id, request)); } - @DeleteMapping("/{id}") // TODO: soft delete로 수정하기 + @DeleteMapping("/{id}") public ResponseEntity> deleteUser(@PathVariable Long id) { adminUserService.deleteUser(id); return SuccessResponse.ok(null); From 919272790d8ee7d309a42e927030b6d7a8e54eef Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:39:41 +0900 Subject: [PATCH 06/16] =?UTF-8?q?[docs]=20#121=20=EA=B0=9C=EB=B0=9C?= =?UTF-8?q?=ED=95=9C=20=EB=82=B4=EC=9A=A9=EB=8C=80=EB=A1=9C=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin_be/domain/users/controller/AdminUserController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java index d762e389..ac4199fc 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java @@ -27,7 +27,7 @@ public ResponseEntity> getAllUsers() { return SuccessResponse.ok(adminUserService.getAllUsers()); } - @PutMapping("/{id}") // TODO: 관리자용 updateUser와 분리 필요 + @PutMapping("/{id}") // TODO: 관리자용 updateUser는 사용 여부 논의 필요 public ResponseEntity> updateUser(@PathVariable Long id, @Valid @RequestBody UserUpdateRequestDTO request) { return SuccessResponse.ok(adminUserService.updateUser(id, request)); } From 15edbf36fb7240d6254ae005645b8835079158f7 Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:40:40 +0900 Subject: [PATCH 07/16] =?UTF-8?q?[chore]=20#121=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=EC=9E=90=EC=9A=A9=20=EC=9C=A0=EC=A0=80=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20API=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/users/controller/AdminUserController.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java index ac4199fc..8605928d 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java @@ -27,11 +27,6 @@ public ResponseEntity> getAllUsers() { return SuccessResponse.ok(adminUserService.getAllUsers()); } - @PutMapping("/{id}") // TODO: 관리자용 updateUser는 사용 여부 논의 필요 - public ResponseEntity> updateUser(@PathVariable Long id, @Valid @RequestBody UserUpdateRequestDTO request) { - return SuccessResponse.ok(adminUserService.updateUser(id, request)); - } - @DeleteMapping("/{id}") public ResponseEntity> deleteUser(@PathVariable Long id) { adminUserService.deleteUser(id); From e308a944e16c94917f8b844ff6d1bd52bbadc15c Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:44:16 +0900 Subject: [PATCH 08/16] =?UTF-8?q?[docs]=20#121=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=EC=9E=90=EC=9A=A9=20=EC=9C=A0=EC=A0=80=20API=20=EB=AA=85?= =?UTF-8?q?=EC=84=B8=EC=84=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../users/controller/AdminUserController.java | 4 +- .../users/controller/docs/AdminUserApi.java | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java index 8605928d..64715b76 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java @@ -1,10 +1,8 @@ package DGU_AI_LAB.admin_be.domain.users.controller; -import DGU_AI_LAB.admin_be.domain.users.dto.request.UserUpdateRequestDTO; import DGU_AI_LAB.admin_be.domain.users.service.AdminUserService; import DGU_AI_LAB.admin_be.domain.users.service.UserService; import DGU_AI_LAB.admin_be.global.common.SuccessResponse; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -12,7 +10,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/admin/users") -public class AdminUserController { +public class AdminUserController implements DGU_AI_LAB.admin_be.domain.users.controller.AdminUserApi { private final AdminUserService adminUserService; private final UserService userService; diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java new file mode 100644 index 00000000..bc91a1d5 --- /dev/null +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java @@ -0,0 +1,47 @@ +package DGU_AI_LAB.admin_be.domain.users.controller; + +import DGU_AI_LAB.admin_be.domain.users.dto.request.UserUpdateRequestDTO; +import DGU_AI_LAB.admin_be.global.common.SuccessResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "1. Admin User API", description = "관리자용 사용자 계정 관리 API") +public interface AdminUserApi { + + @Operation(summary = "1.1 사용자 단일 조회", description = "ID를 통해 특정 사용자의 상세 정보를 조회합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "404", description = "사용자를 찾을 수 없음") + }) + @GetMapping("/{id}") + ResponseEntity> getUser(@PathVariable @Parameter(description = "사용자 ID") Long id); + + @Operation(summary = "1.2 전체 사용자 목록 조회", description = "등록된 모든 사용자의 요약 정보를 조회합니다.") + @GetMapping + ResponseEntity> getAllUsers(); + + @Operation(summary = "1.4 사용자 계정 비활성화 (Soft Delete)", description = "사용자 계정을 비활성화(탈퇴)합니다. DB에서 isActive 상태를 false로 변경하며, 사용자는 더 이상 로그인할 수 없습니다." + + "사용자와 관련된 모든 우분투 계정이 삭제됩니다. ") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "404", description = "사용자를 찾을 수 없음") + }) + @DeleteMapping("/{id}") + ResponseEntity> deleteUser(@PathVariable @Parameter(description = "사용자 ID") Long id); + + @Operation(summary = "1.5 우분투 계정 삭제", description = "특정 우분투 계정을 외부 Config Server에 요청하여 삭제하고, 해당 요청(Request)을 DB에서 논리적으로 삭제(DELETED 상태) 처리합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "404", description = "우분투 계정(요청)을 찾을 수 없음"), + @ApiResponse(responseCode = "502", description = "외부 서버 오류 또는 API 연동 실패") + }) + @DeleteMapping("/ubuntu/{username}") + ResponseEntity> deleteUbuntuAccount( + @PathVariable @Parameter(description = "우분투 계정명") String username + ); +} \ No newline at end of file From a9c9321294250f167a6ffad2f5ab2a3e9b2a3f6a Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:48:37 +0900 Subject: [PATCH 09/16] =?UTF-8?q?[docs]=20#121=20=EC=9C=A0=EC=A0=80?= =?UTF-8?q?=EC=9A=A9=20=EC=9C=A0=EC=A0=80=20API=20=EB=AA=85=EC=84=B8?= =?UTF-8?q?=EC=84=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../users/controller/UserController.java | 3 +- .../users/controller/docs/AdminUserApi.java | 11 ++-- .../domain/users/controller/docs/UserApi.java | 50 +++++++++++++++++++ .../dto/request/PasswordUpdateRequestDTO.java | 5 +- .../dto/request/PhoneUpdateRequestDTO.java | 3 ++ 5 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/UserController.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/UserController.java index 227590e3..759f9956 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/UserController.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/UserController.java @@ -1,5 +1,6 @@ package DGU_AI_LAB.admin_be.domain.users.controller; +import DGU_AI_LAB.admin_be.domain.users.controller.docs.UserApi; import DGU_AI_LAB.admin_be.domain.users.dto.request.PasswordUpdateRequestDTO; import DGU_AI_LAB.admin_be.domain.users.dto.request.PhoneUpdateRequestDTO; import DGU_AI_LAB.admin_be.domain.users.dto.response.UserResponseDTO; @@ -15,7 +16,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/users") -public class UserController { +public class UserController implements UserApi { private final UserService userService; diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java index bc91a1d5..502c59b2 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java @@ -1,6 +1,5 @@ -package DGU_AI_LAB.admin_be.domain.users.controller; +package DGU_AI_LAB.admin_be.domain.users.controller.docs; -import DGU_AI_LAB.admin_be.domain.users.dto.request.UserUpdateRequestDTO; import DGU_AI_LAB.admin_be.global.common.SuccessResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -13,7 +12,7 @@ @Tag(name = "1. Admin User API", description = "관리자용 사용자 계정 관리 API") public interface AdminUserApi { - @Operation(summary = "1.1 사용자 단일 조회", description = "ID를 통해 특정 사용자의 상세 정보를 조회합니다.") + @Operation(summary = "사용자 단일 조회", description = "ID를 통해 특정 사용자의 상세 정보를 조회합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공"), @ApiResponse(responseCode = "404", description = "사용자를 찾을 수 없음") @@ -21,11 +20,11 @@ public interface AdminUserApi { @GetMapping("/{id}") ResponseEntity> getUser(@PathVariable @Parameter(description = "사용자 ID") Long id); - @Operation(summary = "1.2 전체 사용자 목록 조회", description = "등록된 모든 사용자의 요약 정보를 조회합니다.") + @Operation(summary = "전체 사용자 목록 조회", description = "등록된 모든 사용자의 요약 정보를 조회합니다.") @GetMapping ResponseEntity> getAllUsers(); - @Operation(summary = "1.4 사용자 계정 비활성화 (Soft Delete)", description = "사용자 계정을 비활성화(탈퇴)합니다. DB에서 isActive 상태를 false로 변경하며, 사용자는 더 이상 로그인할 수 없습니다." + + @Operation(summary = "사용자 계정 비활성화 (Soft Delete)", description = "사용자 계정을 비활성화(탈퇴)합니다. DB에서 isActive 상태를 false로 변경하며, 사용자는 더 이상 로그인할 수 없습니다." + "사용자와 관련된 모든 우분투 계정이 삭제됩니다. ") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공"), @@ -34,7 +33,7 @@ public interface AdminUserApi { @DeleteMapping("/{id}") ResponseEntity> deleteUser(@PathVariable @Parameter(description = "사용자 ID") Long id); - @Operation(summary = "1.5 우분투 계정 삭제", description = "특정 우분투 계정을 외부 Config Server에 요청하여 삭제하고, 해당 요청(Request)을 DB에서 논리적으로 삭제(DELETED 상태) 처리합니다.") + @Operation(summary = "우분투 계정 삭제", description = "특정 우분투 계정을 외부 Config Server에 요청하여 삭제하고, 해당 요청(Request)을 DB에서 논리적으로 삭제(DELETED 상태) 처리합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공"), @ApiResponse(responseCode = "404", description = "우분투 계정(요청)을 찾을 수 없음"), diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java new file mode 100644 index 00000000..534188b2 --- /dev/null +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java @@ -0,0 +1,50 @@ +package DGU_AI_LAB.admin_be.domain.users.controller.docs; + +import DGU_AI_LAB.admin_be.domain.users.dto.request.PasswordUpdateRequestDTO; +import DGU_AI_LAB.admin_be.domain.users.dto.request.PhoneUpdateRequestDTO; +import DGU_AI_LAB.admin_be.domain.users.dto.response.UserResponseDTO; +import DGU_AI_LAB.admin_be.global.auth.CustomUserDetails; +import DGU_AI_LAB.admin_be.global.common.SuccessResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "2. User API", description = "일반 사용자 본인 정보 관리 API") +public interface UserApi { + + @Operation(summary = "사용자 정보 확인", description = "로그인된 사용자의 상세 정보를 조회합니다.") + @GetMapping("/me") + ResponseEntity> getMyInfo( + @AuthenticationPrincipal CustomUserDetails principal + ); + + @Operation(summary = "사용자 비밀번호 변경", description = "로그인된 사용자의 비밀번호를 변경합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "400", description = "잘못된 요청 (현재 비밀번호 불일치 등)"), + @ApiResponse(responseCode = "401", description = "인증 실패") + }) + @PatchMapping("/me/password") + ResponseEntity> updateUserPassword( + @AuthenticationPrincipal @Parameter(hidden = true) CustomUserDetails principal, + @RequestBody @Valid PasswordUpdateRequestDTO request + ); + + @Operation(summary = "사용자 연락처 변경", description = "로그인된 사용자의 연락처 정보를 변경합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "400", description = "잘못된 요청 (연락처 형식 오류 등)"), + @ApiResponse(responseCode = "401", description = "인증 실패") + }) + @PatchMapping("/me/phone") + ResponseEntity> updateUserPhone( + @AuthenticationPrincipal @Parameter(hidden = true) CustomUserDetails principal, + @RequestBody @Valid PhoneUpdateRequestDTO request + ); +} \ No newline at end of file diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/dto/request/PasswordUpdateRequestDTO.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/dto/request/PasswordUpdateRequestDTO.java index b3cd11de..d5a2a3ca 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/dto/request/PasswordUpdateRequestDTO.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/dto/request/PasswordUpdateRequestDTO.java @@ -1,11 +1,14 @@ package DGU_AI_LAB.admin_be.domain.users.dto.request; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; +@Schema(description = "사용자 비밀번호 변경 요청 DTO") public record PasswordUpdateRequestDTO( + @Schema(description = "현재 비밀번호", example = "1234") @NotBlank(message = "현재 비밀번호는 필수로 입력해야 합니다.") String currentPassword, + @Schema(description = "새 비밀번호", example = "1234!") @NotBlank(message = "새 비밀번호는 필수로 입력해야 합니다.") - // @Size(min = 8, message = "새 비밀번호는 최소 8자 이상이어야 합니다.") String newPassword ) {} \ No newline at end of file diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/dto/request/PhoneUpdateRequestDTO.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/dto/request/PhoneUpdateRequestDTO.java index a40df7fa..278316ec 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/dto/request/PhoneUpdateRequestDTO.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/dto/request/PhoneUpdateRequestDTO.java @@ -1,9 +1,12 @@ package DGU_AI_LAB.admin_be.domain.users.dto.request; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Pattern; +@Schema(description = "사용자 연락처 변경 요청 DTO") public record PhoneUpdateRequestDTO( + @Schema(description = "새 연락처", example = "010-1234-5678") @NotBlank(message = "연락처는 필수로 입력해야 합니다.") @Pattern(regexp = "^\\d{2,3}-\\d{3,4}-\\d{4}$", message = "유효한 전화번호 형식이 아닙니다. (예: 010-1234-5678)") String newPhone From dd9b8b66861d87958fe0aee94881d62124018105 Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:48:55 +0900 Subject: [PATCH 10/16] =?UTF-8?q?[docs]=20#121=20=EC=9C=A0=EC=A0=80?= =?UTF-8?q?=EC=9A=A9=20=EC=9C=A0=EC=A0=80=20API=20=EB=AA=85=EC=84=B8?= =?UTF-8?q?=EC=84=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin_be/domain/users/controller/AdminUserController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java index 64715b76..ed58fd92 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/AdminUserController.java @@ -1,5 +1,6 @@ package DGU_AI_LAB.admin_be.domain.users.controller; +import DGU_AI_LAB.admin_be.domain.users.controller.docs.AdminUserApi; import DGU_AI_LAB.admin_be.domain.users.service.AdminUserService; import DGU_AI_LAB.admin_be.domain.users.service.UserService; import DGU_AI_LAB.admin_be.global.common.SuccessResponse; @@ -10,7 +11,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/admin/users") -public class AdminUserController implements DGU_AI_LAB.admin_be.domain.users.controller.AdminUserApi { +public class AdminUserController implements AdminUserApi { private final AdminUserService adminUserService; private final UserService userService; From f077ed4cb9e668493b3990c20aa42bbcfd48fe41 Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:51:16 +0900 Subject: [PATCH 11/16] =?UTF-8?q?[docs]=20#121=20=EB=B6=84=EB=A5=98=20?= =?UTF-8?q?=EC=A0=9C=EB=AA=A9=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin_be/domain/users/controller/docs/AdminUserApi.java | 2 +- .../admin_be/domain/users/controller/docs/UserApi.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java index 502c59b2..1c35c9b6 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java @@ -9,7 +9,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -@Tag(name = "1. Admin User API", description = "관리자용 사용자 계정 관리 API") +@Tag(name = "1. 관리자용 유저 관리", description = "관리자용 사용자 계정 관리 API") public interface AdminUserApi { @Operation(summary = "사용자 단일 조회", description = "ID를 통해 특정 사용자의 상세 정보를 조회합니다.") diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java index 534188b2..9a7382e7 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java @@ -2,7 +2,6 @@ import DGU_AI_LAB.admin_be.domain.users.dto.request.PasswordUpdateRequestDTO; import DGU_AI_LAB.admin_be.domain.users.dto.request.PhoneUpdateRequestDTO; -import DGU_AI_LAB.admin_be.domain.users.dto.response.UserResponseDTO; import DGU_AI_LAB.admin_be.global.auth.CustomUserDetails; import DGU_AI_LAB.admin_be.global.common.SuccessResponse; import io.swagger.v3.oas.annotations.Operation; @@ -15,7 +14,7 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; -@Tag(name = "2. User API", description = "일반 사용자 본인 정보 관리 API") +@Tag(name = "2. 사용자용 마이 정보 관리", description = "일반 사용자 본인 정보 관리 API") public interface UserApi { @Operation(summary = "사용자 정보 확인", description = "로그인된 사용자의 상세 정보를 조회합니다.") From 1eeebdc7c322ca06199de5c08e15df6807d829b4 Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Tue, 2 Sep 2025 23:54:09 +0900 Subject: [PATCH 12/16] =?UTF-8?q?[docs]=20#121=20=EB=B6=84=EB=A5=98=20?= =?UTF-8?q?=EC=A0=9C=EB=AA=A9=20=EB=B2=88=ED=98=B8=20=EB=B6=99=EC=9D=B4?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../containerImage/controller/docs/ContainerImageApi.java | 4 ++-- .../domain/dashboard/controller/docs/DashBoardApi.java | 2 +- .../domain/requests/controller/docs/AcceptInfoApi.java | 2 +- .../domain/requests/controller/docs/AdminRequestApi.java | 2 +- .../admin_be/domain/requests/controller/docs/RequestApi.java | 2 +- .../resourceGroups/controller/docs/ResourceGroupApi.java | 2 +- .../admin_be/domain/users/controller/docs/AuthApi.java | 2 +- .../admin_be/domain/users/controller/docs/EmailApi.java | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/containerImage/controller/docs/ContainerImageApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/containerImage/controller/docs/ContainerImageApi.java index 95b1c3ba..ef409fb9 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/containerImage/controller/docs/ContainerImageApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/containerImage/controller/docs/ContainerImageApi.java @@ -15,10 +15,10 @@ import java.util.List; -@Tag(name = "이미지 관리", description = "컨테이너 이미지 생성 및 조회 API") +@Tag(name = "2. 이미지 관리", description = "컨테이너 이미지 조회 API") public interface ContainerImageApi { - @Operation(summary = "이미지 생성", description = "새로운 컨테이너 이미지를 등록합니다.") + @Operation(summary = "이미지 생성", description = "새로운 컨테이너 이미지를 등록합니다. -> 관리자용으로 만들어졌으니, 수정 필요합니다. ") @ApiResponse(responseCode = "200", description = "이미지 생성 성공", content = @Content(schema = @Schema(implementation = ContainerImageResponseDTO.class))) ResponseEntity createImage( diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/dashboard/controller/docs/DashBoardApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/dashboard/controller/docs/DashBoardApi.java index c1bd6063..8590fc7a 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/dashboard/controller/docs/DashBoardApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/dashboard/controller/docs/DashBoardApi.java @@ -18,7 +18,7 @@ import org.springframework.web.bind.annotation.RequestParam; -@Tag(name = "사용자 대시보드 API", description = "대시보드용 API") +@Tag(name = "2. 사용자 대시보드 API", description = "대시보드용 API") @RequestMapping("/api/dashboard") public interface DashBoardApi { diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AcceptInfoApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AcceptInfoApi.java index 2ddbe1be..9ec63cf4 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AcceptInfoApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AcceptInfoApi.java @@ -9,7 +9,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; -@Tag(name = "Config Server용 승인 정보 관리", description = "Ubuntu username별 승인 정보 조회 API") +@Tag(name = "0. Config Server용 승인 정보 관리", description = "Ubuntu username별 승인 정보 조회 API") public interface AcceptInfoApi { @Operation( diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AdminRequestApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AdminRequestApi.java index 1e809493..08e64cf2 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AdminRequestApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AdminRequestApi.java @@ -13,7 +13,7 @@ import java.util.List; -@Tag(name = "관리자용 서버 사용 신청 관리", description = "관리자용 서버 사용 신청 관리 API") +@Tag(name = "1. 관리자용 서버 사용 신청 관리", description = "관리자용 서버 사용 신청 관리 API") public interface AdminRequestApi { @Operation( diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/RequestApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/RequestApi.java index 0006f0f7..508265a1 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/RequestApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/RequestApi.java @@ -16,7 +16,7 @@ import java.util.List; -@Tag(name = "서버 사용 신청", description = "서버 사용 신청 API") +@Tag(name = "2. 서버 사용 신청", description = "서버 사용 신청 API") public interface RequestApi { @Operation( diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/resourceGroups/controller/docs/ResourceGroupApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/resourceGroups/controller/docs/ResourceGroupApi.java index 38bb27e9..96df3bcc 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/resourceGroups/controller/docs/ResourceGroupApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/resourceGroups/controller/docs/ResourceGroupApi.java @@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; -@Tag(name = "리소스 그룹 관리 API", description = "GPU 기종별 리소스 정보 조회 등 리소스 그룹 관련 API") +@Tag(name = "2. 리소스 그룹 관리 API", description = "GPU 기종별 리소스 정보 조회 등 리소스 그룹 관련 API") @RequestMapping("/api/resources") public interface ResourceGroupApi { diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AuthApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AuthApi.java index 4657cca5..b53cfa49 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AuthApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AuthApi.java @@ -13,7 +13,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; -@Tag(name = "인증", description = "회원가입 및 로그인 API") +@Tag(name = "0. 인증", description = "회원가입 및 로그인 API") public interface AuthApi { @Operation( diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/EmailApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/EmailApi.java index 68382f20..6e1ac852 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/EmailApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/EmailApi.java @@ -9,7 +9,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestParam; -@Tag(name = "회원가입 이메일 인증", description = "이메일 인증번호 발송 및 인증 확인 API") +@Tag(name = "0. 회원가입 이메일 인증", description = "이메일 인증번호 발송 및 인증 확인 API") public interface EmailApi { @Operation(summary = "이메일 인증번호 발송", description = "입력한 이메일 주소로 인증번호를 전송합니다.") From 2568835745d882308c97348357d7bfe74e4421c8 Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Wed, 3 Sep 2025 00:00:32 +0900 Subject: [PATCH 13/16] =?UTF-8?q?[docs]=20#121=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=EC=9E=90=EC=9A=A9=20=EC=82=AC=EC=9A=A9=20=EC=8B=A0=EC=B2=AD=20?= =?UTF-8?q?API=20=EB=AA=85=EC=84=B8=20=EC=9E=91=EC=84=B1=20&=20DTO=20valid?= =?UTF-8?q?ation=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AdminRequestController.java | 3 +- .../controller/docs/AdminRequestApi.java | 96 +++++++++++-------- .../dto/request/ApproveRequestDTO.java | 21 ++++ .../dto/request/RejectRequestDTO.java | 11 +++ .../users/controller/docs/AdminUserApi.java | 2 +- .../domain/users/controller/docs/UserApi.java | 2 +- 6 files changed, 92 insertions(+), 43 deletions(-) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/AdminRequestController.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/AdminRequestController.java index 841bda19..f5ebb5b7 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/AdminRequestController.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/AdminRequestController.java @@ -1,5 +1,6 @@ package DGU_AI_LAB.admin_be.domain.requests.controller; +import DGU_AI_LAB.admin_be.domain.requests.controller.docs.AdminRequestApi; import DGU_AI_LAB.admin_be.domain.requests.dto.request.ApproveModificationDTO; import DGU_AI_LAB.admin_be.domain.requests.dto.request.ApproveRequestDTO; import DGU_AI_LAB.admin_be.domain.requests.dto.request.RejectRequestDTO; @@ -20,7 +21,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/admin/requests") -public class AdminRequestController { +public class AdminRequestController implements AdminRequestApi { private final AdminRequestCommandService adminRequestCommandService; private final AdminRequestQueryService adminRequestQueryService; diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AdminRequestApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AdminRequestApi.java index 08e64cf2..811755b2 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AdminRequestApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/AdminRequestApi.java @@ -1,58 +1,74 @@ package DGU_AI_LAB.admin_be.domain.requests.controller.docs; +import DGU_AI_LAB.admin_be.domain.requests.dto.request.ApproveModificationDTO; import DGU_AI_LAB.admin_be.domain.requests.dto.request.ApproveRequestDTO; import DGU_AI_LAB.admin_be.domain.requests.dto.request.RejectRequestDTO; +import DGU_AI_LAB.admin_be.domain.requests.dto.response.ChangeRequestResponseDTO; +import DGU_AI_LAB.admin_be.domain.requests.dto.response.ContainerInfoDTO; +import DGU_AI_LAB.admin_be.domain.requests.dto.response.ResourceUsageDTO; import DGU_AI_LAB.admin_be.domain.requests.dto.response.SaveRequestResponseDTO; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.ArraySchema; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; import java.util.List; -@Tag(name = "1. 관리자용 서버 사용 신청 관리", description = "관리자용 서버 사용 신청 관리 API") +@Tag(name = "1. 관리자 서버 사용 신청 처리", description = "관리자용 서버 사용 신청 관리 API") public interface AdminRequestApi { - @Operation( - summary = "모든 신청 목록 조회", - description = "상태에 상관없이 모든 사용 신청을 조회합니다." - ) - @ApiResponse( - responseCode = "200", description = "조회 성공", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = SaveRequestResponseDTO.class))) - ) + @Operation(summary = "변경 요청 승인", description = "사용자의 변경 요청을 승인합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "404", description = "변경 요청을 찾을 수 없음"), + @ApiResponse(responseCode = "409", description = "요청 상태가 PENDING이 아님") + }) + @PatchMapping("/change/approve") + ResponseEntity approveModification( + @AuthenticationPrincipal(expression = "userId") Long adminId, + @RequestBody @Valid ApproveModificationDTO dto + ); + + @Operation(summary = "모든 리소스 사용량 조회", description = "현재 사용 중인 컨테이너들의 리소스 사용량을 조회합니다.") + @GetMapping("/usage") + ResponseEntity> getAllResourceUsage(); + + @Operation(summary = "모든 컨테이너 정보 조회", description = "현재 활성화된 모든 컨테이너의 상세 정보를 조회합니다.") + @GetMapping("/containers") + ResponseEntity> getAllActiveContainers(); + + @Operation(summary = "모든 요청 목록 조회", description = "모든 상태의 사용자 요청 목록을 조회합니다.") + @GetMapping ResponseEntity> getAllRequests(); - @Operation( - summary = "신청 승인", - description = "해당 신청의 상태를 FULFILLED로 변경하고 approvedAt을 현재 시각으로 설정합니다. expiresAt, volumeSizeGiB, imageId, rsgroupId를 갱신합니다." - ) - @ApiResponse( - responseCode = "200", description = "승인 성공", - content = @Content(schema = @Schema(implementation = SaveRequestResponseDTO.class)) - ) - ResponseEntity approve( - @io.swagger.v3.oas.annotations.parameters.RequestBody( - description = "승인 DTO", required = true - ) - ApproveRequestDTO dto - ); + @Operation(summary = "신규 신청 목록 조회", description = "PENDING 상태의 신규 사용자 신청 목록을 조회합니다.") + @GetMapping("/new") + ResponseEntity> getNewRequests(); - @Operation( - summary = "신청 거절", - description = "해당 신청의 상태를 DENIED로 변경하고 관리 코멘트를 기록합니다." - ) - @ApiResponse( - responseCode = "200", description = "거절 성공", - content = @Content(schema = @Schema(implementation = SaveRequestResponseDTO.class)) - ) - ResponseEntity reject( - @io.swagger.v3.oas.annotations.parameters.RequestBody( - description = "거절 DTO", required = true - ) - RejectRequestDTO dto - ); + @Operation(summary = "변경 요청 목록 조회", description = "PENDING 상태의 사용자 변경 요청 목록을 조회합니다.") + @GetMapping("/change") + ResponseEntity> getChangeRequests(); + + @Operation(summary = "신규 신청 승인", description = "신규 사용자 신청을 승인하고, 계정 및 리소스를 할당합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "404", description = "요청을 찾을 수 없음"), + @ApiResponse(responseCode = "409", description = "요청 상태가 PENDING이 아님"), + @ApiResponse(responseCode = "502", description = "외부 서버 오류") + }) + @PatchMapping("/approval") + ResponseEntity approve(@RequestBody @Valid ApproveRequestDTO dto); + + @Operation(summary = "신규 신청 거절", description = "신규 사용자 신청을 거절합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "404", description = "요청을 찾을 수 없음"), + @ApiResponse(responseCode = "409", description = "요청 상태가 PENDING 또는 FULFILLED가 아님") + }) + @PatchMapping("/reject") + ResponseEntity reject(@RequestBody @Valid RejectRequestDTO dto); } \ No newline at end of file diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/request/ApproveRequestDTO.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/request/ApproveRequestDTO.java index 505cd2a6..8191dcc9 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/request/ApproveRequestDTO.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/request/ApproveRequestDTO.java @@ -1,12 +1,33 @@ package DGU_AI_LAB.admin_be.domain.requests.dto.request; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; + import java.time.LocalDateTime; +@Schema(description = "관리자용 요청 승인 요청 DTO") public record ApproveRequestDTO( + + @Schema(description = "승인할 요청 ID", example = "1") + @NotNull(message = "요청 ID는 필수로 입력해야 합니다.") Long requestId, + + @Schema(description = "적용할 컨테이너 이미지 ID", example = "1") + @NotNull(message = "이미지 ID는 필수로 입력해야 합니다.") Long imageId, + + @Schema(description = "할당할 리소스 그룹 ID", example = "1") + @NotNull(message = "리소스 그룹 ID는 필수로 입력해야 합니다.") Integer resourceGroupId, + + @Schema(description = "할당할 볼륨 크기 (GiB)", example = "20") + @NotNull(message = "볼륨 크기는 필수로 입력해야 합니다.") Long volumeSizeGiB, + + @Schema(description = "만료일", example = "2025-12-31T23:59:59") + @NotNull(message = "만료일은 필수로 입력해야 합니다.") LocalDateTime expiresAt, + + @Schema(description = "관리자 승인 코멘트 (선택 사항)", example = "사용 목적에 따라 리소스를 할당함") String adminComment ) {} diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/request/RejectRequestDTO.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/request/RejectRequestDTO.java index d86dc9ed..8c4df972 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/request/RejectRequestDTO.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/request/RejectRequestDTO.java @@ -1,6 +1,17 @@ package DGU_AI_LAB.admin_be.domain.requests.dto.request; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +@Schema(description = "1. 관리자용 요청 거절 요청 DTO") public record RejectRequestDTO( + + @Schema(description = "거절할 요청 ID", example = "3") + @NotNull(message = "요청 ID는 필수로 입력해야 합니다.") Long requestId, + + @Schema(description = "관리자 거절 코멘트", example = "신청서 양식에 맞지 않아 거절합니다.") + @NotBlank(message = "거절 사유를 필수로 입력해야 합니다.") String adminComment ) {} diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java index 1c35c9b6..bfa20296 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/AdminUserApi.java @@ -9,7 +9,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -@Tag(name = "1. 관리자용 유저 관리", description = "관리자용 사용자 계정 관리 API") +@Tag(name = "1. 관리자 유저 관리", description = "관리자용 사용자 계정 관리 API") public interface AdminUserApi { @Operation(summary = "사용자 단일 조회", description = "ID를 통해 특정 사용자의 상세 정보를 조회합니다.") diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java index 9a7382e7..b5bf75b2 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/users/controller/docs/UserApi.java @@ -14,7 +14,7 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; -@Tag(name = "2. 사용자용 마이 정보 관리", description = "일반 사용자 본인 정보 관리 API") +@Tag(name = "2. 사용자 정보 관리", description = "일반 사용자 본인 정보 관리 API") public interface UserApi { @Operation(summary = "사용자 정보 확인", description = "로그인된 사용자의 상세 정보를 조회합니다.") From d7afad09298f4e594791d96aba5db40329bac23b Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Wed, 3 Sep 2025 00:03:39 +0900 Subject: [PATCH 14/16] =?UTF-8?q?[docs]=20#121=20Config=20Server=EC=9A=A9?= =?UTF-8?q?=20API=20=EB=AA=85=EC=84=B8=EC=84=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ConfigRequestController.java | 3 +- .../controller/docs/ConfigRequestApi.java | 51 +++++++++++++++++++ .../dto/response/AcceptInfoResponseDTO.java | 1 + 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/ConfigRequestApi.java diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/ConfigRequestController.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/ConfigRequestController.java index 67ae0349..56263d8a 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/ConfigRequestController.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/ConfigRequestController.java @@ -1,5 +1,6 @@ package DGU_AI_LAB.admin_be.domain.requests.controller; +import DGU_AI_LAB.admin_be.domain.requests.controller.docs.ConfigRequestApi; import DGU_AI_LAB.admin_be.domain.requests.dto.response.AcceptInfoResponseDTO; import DGU_AI_LAB.admin_be.domain.requests.service.ConfigRequestService; import lombok.RequiredArgsConstructor; @@ -9,7 +10,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/requests/config") -public class ConfigRequestController { +public class ConfigRequestController implements ConfigRequestApi { private final ConfigRequestService configRequestService; diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/ConfigRequestApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/ConfigRequestApi.java new file mode 100644 index 00000000..983db00c --- /dev/null +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/controller/docs/ConfigRequestApi.java @@ -0,0 +1,51 @@ +package DGU_AI_LAB.admin_be.domain.requests.controller.docs; + +import DGU_AI_LAB.admin_be.domain.requests.dto.response.AcceptInfoResponseDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@Tag(name = "0. Config Server용 API", description = "내부 Config Server 연동을 위한 API") +@RequestMapping("/api/requests/config") +public interface ConfigRequestApi { + + @Operation(summary = "우분투 계정명 사용 가능 여부 확인", description = "지정된 우분투 계정명이 사용 가능한지 확인합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공", + content = @io.swagger.v3.oas.annotations.media.Content( + mediaType = "application/json", + examples = { + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "사용 가능", + value = "{\"available\": true}" + ), + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "사용 불가능", + value = "{\"available\": false}" + ) + } + ) + ) + }) + @GetMapping("/check-username") + ResponseEntity checkUbuntuUsername( + @RequestParam @Parameter(description = "확인할 우분투 계정명", example = "toni") String username + ); + + @Operation(summary = "요청 승인 정보 조회", description = "지정된 우분투 계정명에 대한 승인된 요청 정보를 조회합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "404", description = "승인된 요청을 찾을 수 없음") + }) + @GetMapping("/{username}") + ResponseEntity getAcceptInfo( + @PathVariable @Parameter(description = "승인 정보 조회 대상 계정명", example = "toni") String username + ); +} \ No newline at end of file diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/response/AcceptInfoResponseDTO.java b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/response/AcceptInfoResponseDTO.java index a6f456b3..62a97ea8 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/response/AcceptInfoResponseDTO.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/requests/dto/response/AcceptInfoResponseDTO.java @@ -8,6 +8,7 @@ @Builder public record AcceptInfoResponseDTO( + String username, String image, Long uid, From e1c232752ae8d8fe5d0c5d3923cee46571848657 Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Wed, 3 Sep 2025 00:04:22 +0900 Subject: [PATCH 15/16] =?UTF-8?q?[docs]=20#121=20=EC=A0=9C=EB=AA=A9=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin_be/domain/alarm/controller/docs/AlarmApi.java | 2 +- .../DGU_AI_LAB/admin_be/domain/pod/controller/docs/PodApi.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/alarm/controller/docs/AlarmApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/alarm/controller/docs/AlarmApi.java index bb8b40c9..53ffa2b4 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/alarm/controller/docs/AlarmApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/alarm/controller/docs/AlarmApi.java @@ -13,7 +13,7 @@ import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; -@Tag(name = "Slack 및 E-mail", description = "Slack 및 Email 알림 API") +@Tag(name = "0. Slack 및 E-mail", description = "Slack 및 Email 알림 API") public interface AlarmApi { @Operation( diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/pod/controller/docs/PodApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/pod/controller/docs/PodApi.java index bb168cc4..7b4a04be 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/pod/controller/docs/PodApi.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/pod/controller/docs/PodApi.java @@ -10,7 +10,7 @@ import java.util.List; -@Tag(name = "Kubernetes Pods", description = "쿠버네티스 Pod 조회 API") +@Tag(name = "0. Kubernetes Pods", description = "쿠버네티스 Pod 조회 API") public interface PodApi { @Operation( From 912f0316702dadae51034ca53bd32e98dd81cb9c Mon Sep 17 00:00:00 2001 From: saokiritoni Date: Wed, 3 Sep 2025 00:07:17 +0900 Subject: [PATCH 16/16] =?UTF-8?q?[docs]=20#121=20=EA=B7=B8=EB=A3=B9=20API?= =?UTF-8?q?=20=EB=AA=85=EC=84=B8=EC=84=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../groups/controller/GroupController.java | 3 +- .../groups/controller/docs/GroupApi.java | 32 +++++++++++++++++++ .../dto/request/CreateGroupRequestDTO.java | 4 +++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/main/java/DGU_AI_LAB/admin_be/domain/groups/controller/docs/GroupApi.java diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/groups/controller/GroupController.java b/src/main/java/DGU_AI_LAB/admin_be/domain/groups/controller/GroupController.java index 66e97889..2784ff62 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/groups/controller/GroupController.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/groups/controller/GroupController.java @@ -1,5 +1,6 @@ package DGU_AI_LAB.admin_be.domain.groups.controller; +import DGU_AI_LAB.admin_be.domain.groups.controller.docs.GroupApi; import DGU_AI_LAB.admin_be.domain.groups.dto.request.CreateGroupRequestDTO; import DGU_AI_LAB.admin_be.domain.groups.dto.response.GroupResponseDTO; import DGU_AI_LAB.admin_be.domain.groups.service.GroupService; @@ -16,7 +17,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/groups") -public class GroupController { +public class GroupController implements GroupApi { private final GroupService groupService; diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/groups/controller/docs/GroupApi.java b/src/main/java/DGU_AI_LAB/admin_be/domain/groups/controller/docs/GroupApi.java new file mode 100644 index 00000000..402aac03 --- /dev/null +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/groups/controller/docs/GroupApi.java @@ -0,0 +1,32 @@ +package DGU_AI_LAB.admin_be.domain.groups.controller.docs; + +import DGU_AI_LAB.admin_be.domain.groups.dto.request.CreateGroupRequestDTO; +import DGU_AI_LAB.admin_be.global.common.SuccessResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "2. 그룹 API", description = "사용자용 그룹 목록 조회, 그룹 생성 API") +public interface GroupApi { + + @Operation(summary = "모든 그룹 목록 조회", description = "시스템에 등록된 모든 그룹의 정보를 조회합니다. 사용 신청 단계에서 이 목록을 조회하고, 그룹을 선택할 수 있습니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "404", description = "조회된 그룹 정보 없음") + }) + @GetMapping + ResponseEntity> getGroups(); + + @Operation(summary = "새로운 그룹 생성", description = "새로운 그룹을 생성하고 DB에 저장합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "생성 성공"), + @ApiResponse(responseCode = "400", description = "잘못된 요청 (필수 필드 누락 등)"), + @ApiResponse(responseCode = "409", description = "중복된 GID를 가진 그룹이 이미 존재함") + }) + @PostMapping + ResponseEntity> createGroup(@RequestBody @Valid CreateGroupRequestDTO dto); +} \ No newline at end of file diff --git a/src/main/java/DGU_AI_LAB/admin_be/domain/groups/dto/request/CreateGroupRequestDTO.java b/src/main/java/DGU_AI_LAB/admin_be/domain/groups/dto/request/CreateGroupRequestDTO.java index 70864ee6..ddb0baa7 100644 --- a/src/main/java/DGU_AI_LAB/admin_be/domain/groups/dto/request/CreateGroupRequestDTO.java +++ b/src/main/java/DGU_AI_LAB/admin_be/domain/groups/dto/request/CreateGroupRequestDTO.java @@ -1,15 +1,19 @@ package DGU_AI_LAB.admin_be.domain.groups.dto.request; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; import lombok.Builder; +@Schema(description = "1. 그룹 생성 요청 DTO") @Builder public record CreateGroupRequestDTO( + @Schema(description = "할당할 우분투 GID (Group ID)", example = "1001") @NotNull @Positive Long ubuntuGid, + @Schema(description = "생성할 그룹명", example = "developers") @NotBlank String groupName ) {