diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/dto/response/BookmarkResponse.java b/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/dto/response/BookmarkResponse.java index cd5ed0d4..61ea52b7 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/dto/response/BookmarkResponse.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/dto/response/BookmarkResponse.java @@ -1,5 +1,6 @@ package com.rollthedice.backend.domain.bookmark.dto.response; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -9,6 +10,7 @@ @Builder @NoArgsConstructor @AllArgsConstructor +@Schema(description = "사용자가 북마크했는지 여부") public class BookmarkResponse { private Long id; private Boolean isBookmarked; diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/api/DebateApi.java b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/api/DebateApi.java index 9fe8eec2..f70a4d3b 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/api/DebateApi.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/api/DebateApi.java @@ -4,6 +4,7 @@ import com.rollthedice.backend.domain.debate.dto.request.DebateRoomRequest; import com.rollthedice.backend.domain.debate.dto.response.DebateMessageResponse; import com.rollthedice.backend.domain.debate.dto.response.DebateRoomResponse; +import com.rollthedice.backend.domain.debate.dto.response.DebateRoomSaveResponse; import com.rollthedice.backend.domain.debate.dto.response.DebateSummaryResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -29,7 +30,7 @@ public interface DebateApi { responseCode = "201", description = "Created" ) - void saveDebateRoom(@RequestBody DebateRoomRequest request); + DebateRoomSaveResponse saveDebateRoom(@RequestBody DebateRoomRequest request); @Operation( summary = "토론방 전체 조회", diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/api/DebateController.java b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/api/DebateController.java index 4e802ef3..9c5863aa 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/api/DebateController.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/api/DebateController.java @@ -4,6 +4,7 @@ import com.rollthedice.backend.domain.debate.dto.request.DebateRoomRequest; import com.rollthedice.backend.domain.debate.dto.response.DebateMessageResponse; import com.rollthedice.backend.domain.debate.dto.response.DebateRoomResponse; +import com.rollthedice.backend.domain.debate.dto.response.DebateRoomSaveResponse; import com.rollthedice.backend.domain.debate.dto.response.DebateSummaryResponse; import com.rollthedice.backend.domain.debate.service.DebateMessageService; import com.rollthedice.backend.domain.debate.service.DebateRoomService; @@ -25,8 +26,8 @@ public class DebateController implements DebateApi { @ResponseStatus(HttpStatus.CREATED) @PostMapping("") @Override - public void saveDebateRoom(@RequestBody @Valid final DebateRoomRequest request) { - debateRoomService.saveDebateRoom(request); + public DebateRoomSaveResponse saveDebateRoom(@RequestBody @Valid final DebateRoomRequest request) { + return debateRoomService.saveDebateRoom(request); } @ResponseStatus(HttpStatus.OK) diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/request/DebateMessageRequest.java b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/request/DebateMessageRequest.java index 405a1d84..698ffb0c 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/request/DebateMessageRequest.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/request/DebateMessageRequest.java @@ -3,6 +3,7 @@ import com.rollthedice.backend.domain.debate.entity.DebateMessage; import com.rollthedice.backend.domain.debate.entity.DebateRoom; import com.rollthedice.backend.domain.debate.entity.SenderType; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -12,6 +13,7 @@ @Builder @AllArgsConstructor @NoArgsConstructor +@Schema(description = "토론 메세지 생성") public class DebateMessageRequest { private String message; diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/request/DebateRoomRequest.java b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/request/DebateRoomRequest.java index 92f5bd0a..6a161e50 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/request/DebateRoomRequest.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/request/DebateRoomRequest.java @@ -1,6 +1,6 @@ package com.rollthedice.backend.domain.debate.dto.request; -import com.rollthedice.backend.domain.debate.entity.DebateRoom; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -10,6 +10,7 @@ @AllArgsConstructor @NoArgsConstructor @Builder +@Schema(description = "토론방 생성") public class DebateRoomRequest { private String topic; } diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateMessageResponse.java b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateMessageResponse.java index 3e5ff3e5..e8347bf2 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateMessageResponse.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateMessageResponse.java @@ -1,6 +1,7 @@ package com.rollthedice.backend.domain.debate.dto.response; import com.rollthedice.backend.domain.debate.entity.SenderType; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -10,7 +11,11 @@ @Builder @NoArgsConstructor @AllArgsConstructor +@Schema(description = "토론 내용 저장") public class DebateMessageResponse { + @Schema(description = "토론 메세지 내용") private String message; + + @Schema(description = "송신자의 타입입니다. (HUMAN, AI)") private SenderType senderType; } diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateRoomResponse.java b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateRoomResponse.java index 27d3d766..3db3309f 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateRoomResponse.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateRoomResponse.java @@ -1,5 +1,6 @@ package com.rollthedice.backend.domain.debate.dto.response; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -9,8 +10,14 @@ @Builder @NoArgsConstructor @AllArgsConstructor +@Schema(description = "토론방 정보") public class DebateRoomResponse { + @Schema(description = "토론방의 ID입니다.") private Long id; + + @Schema(description = "토론 주제입니다.") private String topic; + + @Schema(description = "토론이 종료되었는지 여부입니다.") private Boolean isClosed; } diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateRoomSaveResponse.java b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateRoomSaveResponse.java new file mode 100644 index 00000000..3dda3cf8 --- /dev/null +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateRoomSaveResponse.java @@ -0,0 +1,22 @@ +package com.rollthedice.backend.domain.debate.dto.response; + +import com.rollthedice.backend.domain.debate.entity.DebateRoom; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@Schema(description = "토론방 생성 결과") +public class DebateRoomSaveResponse { + @Schema(description = "토론방의 ID입니다.") + private Long id; + + @Schema(description = "토론 주제입니다.") + private String topic; + + @Builder + public DebateRoomSaveResponse(DebateRoom debateRoom) { + this.id = debateRoom.getId(); + this.topic = debateRoom.getTopic(); + } +} diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateSummaryResponse.java b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateSummaryResponse.java index a3a46c11..d79acf50 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateSummaryResponse.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/dto/response/DebateSummaryResponse.java @@ -10,6 +10,7 @@ @Builder @NoArgsConstructor @AllArgsConstructor +@Schema(description = "토론 요약 결과") public class DebateSummaryResponse { Long roomId; diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/service/DebateMessageService.java b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/service/DebateMessageService.java index 76d9b583..3c6a881c 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/service/DebateMessageService.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/service/DebateMessageService.java @@ -28,6 +28,7 @@ public void saveHumanDebateMessage(final Long roomId, DebateMessageRequest reque debateMessageRepository.save(request.toHumanMessageEntity(getDebateRoom(roomId))); } + @Transactional public void saveAIDebateMessage(Long roomId, DebateMessageRequest request) { debateMessageRepository.save(request.toAIMessageEntity(getDebateRoom(roomId))); } diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/service/DebateRoomService.java b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/service/DebateRoomService.java index 595359ed..469e0729 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/debate/service/DebateRoomService.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/debate/service/DebateRoomService.java @@ -2,6 +2,7 @@ import com.rollthedice.backend.domain.debate.dto.request.DebateRoomRequest; import com.rollthedice.backend.domain.debate.dto.response.DebateRoomResponse; +import com.rollthedice.backend.domain.debate.dto.response.DebateRoomSaveResponse; import com.rollthedice.backend.domain.debate.dto.response.DebateSummaryResponse; import com.rollthedice.backend.domain.debate.entity.DebateRoom; import com.rollthedice.backend.domain.debate.exception.DebateRoomNotFoundException; @@ -28,9 +29,11 @@ public class DebateRoomService { @Transactional - public void saveDebateRoom(DebateRoomRequest request) { + public DebateRoomSaveResponse saveDebateRoom(DebateRoomRequest request) { final Member member = authService.getMember(); - debateRoomRepository.save(debateRoomMapper.toEntity(member, request)); + DebateRoom debateRoom = debateRoomRepository + .save(debateRoomMapper.toEntity(member, request)); + return DebateRoomSaveResponse.builder().debateRoom(debateRoom).build(); } @Transactional(readOnly = true) diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/statistics/api/StatisticsApi.java b/backend/core/src/main/java/com/rollthedice/backend/domain/statistics/api/StatisticsApi.java index 3f8b53d7..6866c2bb 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/statistics/api/StatisticsApi.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/statistics/api/StatisticsApi.java @@ -13,7 +13,7 @@ public interface StatisticsApi { summary = "최근 일주일 날짜별 뉴스 조회수 조회", description = "최근 일주일간 날짜별로 뉴스 조회수를 조회합니다.", security = {@SecurityRequirement(name = "access_token")}, - tags = {"Statistics"} + tags = {"통계"} ) @ApiResponse( responseCode = "200", @@ -25,7 +25,7 @@ public interface StatisticsApi { summary = "카테고리별 조회수 조회", description = "카테고리별 조회수를 조회합니다.", security = {@SecurityRequirement(name = "access_token")}, - tags = {"Statistics"} + tags = {"통계"} ) @ApiResponse( responseCode = "200", diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/api/AuthApi.java b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/api/AuthApi.java new file mode 100644 index 00000000..b8528389 --- /dev/null +++ b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/api/AuthApi.java @@ -0,0 +1,43 @@ +package com.rollthedice.backend.global.oauth2.api; + +import com.rollthedice.backend.domain.member.dto.MemberUpdateDto; +import com.rollthedice.backend.global.oauth2.dto.LoginRequest; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; + +public interface AuthApi { + @Operation( + summary = "소셜 로그인", + description = "소셜 로그인을 합니다. 회원가입이 되어있지 않은 회원일 경우, 회원가입이 진행됩니다.", + security = {@SecurityRequirement(name = "access_token")}, + tags = {"인증"} + ) + @ApiResponse( + responseCode = "201", + description = "Created" + ) + ResponseEntity login( + @RequestBody LoginRequest request, + HttpServletResponse response + ); + + @Operation( + summary = "닉네임 입력", + description = "닉네임을 입력합니다. 해당 로직이 진행되어야 회원가입이 완료됩니다.", + security = {@SecurityRequirement(name = "access_token")}, + tags = {"인증"} + ) + @ApiResponse( + responseCode = "201", + description = "Created" + ) + ResponseEntity updateMember( + String email, + @RequestBody MemberUpdateDto memberUpdateDto + ); +} diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/controller/AuthController.java b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/api/AuthController.java similarity index 91% rename from backend/core/src/main/java/com/rollthedice/backend/global/oauth2/controller/AuthController.java rename to backend/core/src/main/java/com/rollthedice/backend/global/oauth2/api/AuthController.java index 5a38e5b1..dad5b0f7 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/controller/AuthController.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/api/AuthController.java @@ -1,4 +1,4 @@ -package com.rollthedice.backend.global.oauth2.controller; +package com.rollthedice.backend.global.oauth2.api; import com.rollthedice.backend.domain.member.dto.MemberUpdateDto; import com.rollthedice.backend.domain.member.service.MemberService; @@ -17,17 +17,19 @@ @Slf4j @RestController @RequiredArgsConstructor -public class AuthController { +public class AuthController implements AuthApi { private final AuthService authService; private final MemberService memberService; @PostMapping("/login") + @Override public ResponseEntity login(@RequestBody LoginRequest request, HttpServletResponse response) { authService.authenticateOrRegisterUser(request, response); return new ResponseEntity<>(HttpStatus.OK); } @PostMapping("/oauth2/sign-up") + @Override public ResponseEntity updateMember(@LoginMemberEmail String email, @RequestBody MemberUpdateDto memberUpdateDto) { memberService.update(memberUpdateDto); diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/service/AuthService.java b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/service/AuthService.java index 85bcaef7..b8c51277 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/service/AuthService.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/oauth2/service/AuthService.java @@ -15,6 +15,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.transaction.annotation.Transactional; import java.util.UUID; @@ -26,6 +27,7 @@ public class AuthService { private final OAuth2ProviderService oAuth2ProviderService; private final JwtService jwtService; + @Transactional public void authenticateOrRegisterUser(LoginRequest loginRequest, HttpServletResponse response) { OAuth2UserInfo userInfo = oAuth2ProviderService.getUserInfo(loginRequest); Member member = findOrElseRegisterMember(userInfo, loginRequest.getSocialType()); diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/security/jwt/dto/TokenResponse.java b/backend/core/src/main/java/com/rollthedice/backend/global/security/jwt/dto/TokenResponse.java new file mode 100644 index 00000000..8294fd43 --- /dev/null +++ b/backend/core/src/main/java/com/rollthedice/backend/global/security/jwt/dto/TokenResponse.java @@ -0,0 +1,14 @@ +package com.rollthedice.backend.global.security.jwt.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Schema(description = "AccessToken, RefreshToken 반환 포맷") +public class TokenResponse { + private String accessToken; + private String refreshToken; +} diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/security/jwt/service/JwtService.java b/backend/core/src/main/java/com/rollthedice/backend/global/security/jwt/service/JwtService.java index ed9abc12..a7228879 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/security/jwt/service/JwtService.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/security/jwt/service/JwtService.java @@ -3,7 +3,10 @@ import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.rollthedice.backend.domain.member.repository.MemberRepository; +import com.rollthedice.backend.global.security.jwt.dto.TokenResponse; import com.rollthedice.backend.global.security.jwt.refresh.service.RefreshTokenService; import com.rollthedice.backend.global.security.jwt.exception.NotFoundEmailException; import com.rollthedice.backend.global.security.jwt.exception.NotFoundTokenException; @@ -15,6 +18,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import java.io.IOException; import java.util.Date; import java.util.Optional; @@ -30,6 +34,7 @@ public class JwtService { private final MemberRepository memberRepository; private final RefreshTokenService refreshTokenService; + private final ObjectMapper objectMapper; @Value("${jwt.secret-key}") private String secretKey; @@ -43,12 +48,22 @@ public class JwtService { private String refreshHeader; public void sendAccessAndRefreshToken(HttpServletResponse response, String email) { - setTokenHeader(response, accessHeader, createAccessToken(email)); - + String accessToken = createAccessToken(email); String refreshToken = createRefreshToken(); + + try { + String token = objectMapper.writeValueAsString(TokenResponse.builder() + .accessToken(accessToken) + .refreshToken(refreshToken) + .build()); + response.getWriter().write(token); + } catch (IOException e) { + throw new RuntimeException(e); + } + + setTokenHeader(response, accessHeader, accessToken); setTokenHeader(response, refreshHeader, refreshToken); refreshTokenService.updateToken(email, refreshToken); - log.info("Access Token, Refresh Token 헤더 설정 완료"); } public String createAccessToken(String email) {