diff --git a/backend/src/main/java/reviewme/review/controller/ReviewApi.java b/backend/src/main/java/reviewme/review/controller/ReviewApi.java index 4b1fe10e4..9deb9792f 100644 --- a/backend/src/main/java/reviewme/review/controller/ReviewApi.java +++ b/backend/src/main/java/reviewme/review/controller/ReviewApi.java @@ -11,19 +11,131 @@ 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.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestParam; -import reviewme.review.dto.request.CreateReviewRequest; +import reviewme.review.dto.request.create.CreateReviewRequest; import reviewme.review.dto.response.ReceivedReviewsResponse; +import reviewme.review.dto.response.ReceivedReviewsResponse2; import reviewme.review.dto.response.ReviewDetailResponse; import reviewme.review.dto.response.ReviewSetupResponse; +import reviewme.review.service.dto.response.detail.TemplateAnswerResponse; @Tag(name = "리뷰 관리") public interface ReviewApi { + /** + * v2 + */ + @Operation(summary = "리뷰 등록", description = "리뷰 작성 정보를 받아 리뷰를 등록한다.") + @ApiResponses(value = { + @ApiResponse( + responseCode = "201", + description = "응답 성공 : 리뷰 등록 완료", + headers = { + @Header(name = "Content-Type", description = APPLICATION_JSON_VALUE), + } + ), + @ApiResponse( + responseCode = "400", + description = "응답 실패 : 올바르지 않은 리뷰 요청 코드", + content = @Content( + mediaType = APPLICATION_JSON_VALUE, + examples = @ExampleObject(value = """ + { + "type": "about:blank", + "title": "Bad Request", + "status": 400, + "detail": "올바르지 않은 리뷰 요청 코드입니다.", + "instance": "/reviews" + } + """) + ) + ) + }) + ResponseEntity createReview(@Valid @RequestBody CreateReviewRequest request); + + + @Operation(summary = "내가 받은 리뷰 목록 조회", description = "내가 받은 리뷰들을 조회한다.") + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "응답 성공 : 리뷰 목록 응답", + content = @Content( + mediaType = APPLICATION_JSON_VALUE, + schema = @Schema(implementation = ReceivedReviewsResponse2.class) + ) + ), + @ApiResponse( + responseCode = "400", + description = "응답 실패 : 올바르지 않은 그룹 액세스 코드", + content = @Content( + mediaType = APPLICATION_JSON_VALUE, + examples = @ExampleObject(value = """ + { + "type": "about:blank", + "title": "Bad Request", + "status": 400, + "detail": "올바르지 않은 그룹 확인 코드입니다.", + "instance": "/reviews" + } + """) + ) + ) + }) + ResponseEntity findReceivedReviews2( + @Parameter( + description = "리뷰 그룹 액세스 코드", + required = true + ) @RequestHeader("GroupAccessCode") String groupAccessCode + ); + + @Operation(summary = "리뷰 상세 조회", description = "하나의 리뷰를 조회한다.") + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "응답 성공 : 리뷰 정보 응답", + content = @Content( + mediaType = APPLICATION_JSON_VALUE, + schema = @Schema(implementation = TemplateAnswerResponse.class) + ) + ), + @ApiResponse( + responseCode = "400", + description = "응답 실패 : 올바르지 않은 그룹 액세스 코드", + content = @Content( + mediaType = APPLICATION_JSON_VALUE, + examples = @ExampleObject(value = """ + { + "type": "about:blank", + "title": "Bad Request", + "status": 400, + "detail": "올바르지 않은 그룹 확인 코드입니다.", + "instance": "/reviews/{id}" + } + """) + ) + ) + }) + ResponseEntity findReceivedReviewDetailV2( + @Parameter( + description = "조회할 리뷰 ID", + required = true, + example = "1" + ) @PathVariable long id, + + @Parameter( + description = "리뷰 그룹 액세스 코드", + required = true + ) @RequestHeader("GroupAccessCode") String groupAccessCode); + + + /** + * v1 + */ @Operation(summary = "리뷰 등록", description = "리뷰 작성 정보를 받아 리뷰를 등록한다.") @ApiResponses(value = { @ApiResponse( @@ -51,7 +163,8 @@ public interface ReviewApi { ) ) }) - ResponseEntity createReview(@RequestBody CreateReviewRequest request); + ResponseEntity createReview(@RequestBody reviewme.review.dto.request.CreateReviewRequest request); + @Operation(summary = "리뷰 작성 정보 요청", description = "리뷰 작성을 위해 필요한 정보를 요청한다.") diff --git a/backend/src/main/java/reviewme/review/dto/request/create/CreateReviewAnswerRequest.java b/backend/src/main/java/reviewme/review/dto/request/create/CreateReviewAnswerRequest.java index f7992e6d9..63908c848 100644 --- a/backend/src/main/java/reviewme/review/dto/request/create/CreateReviewAnswerRequest.java +++ b/backend/src/main/java/reviewme/review/dto/request/create/CreateReviewAnswerRequest.java @@ -1,10 +1,18 @@ package reviewme.review.dto.request.create; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; +@Schema(name = "리뷰 답변 내용") public record CreateReviewAnswerRequest( + + @Schema(description = "질문 ID") long questionId, + + @Schema(description = "선택된 옵션 ID 목록", nullable = true) List selectedOptionIds, + + @Schema(description = "답변 내용", nullable = true) String text ) { } diff --git a/backend/src/main/java/reviewme/review/dto/request/create/CreateReviewRequest.java b/backend/src/main/java/reviewme/review/dto/request/create/CreateReviewRequest.java index 7c0fc347d..962e91569 100644 --- a/backend/src/main/java/reviewme/review/dto/request/create/CreateReviewRequest.java +++ b/backend/src/main/java/reviewme/review/dto/request/create/CreateReviewRequest.java @@ -1,9 +1,15 @@ package reviewme.review.dto.request.create; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; +@Schema(name = "리뷰 생성 요청") public record CreateReviewRequest( + + @Schema(description = "리뷰 요청 코드") String reviewRequestCode, + + @Schema(description = "답변 목록") List answers ) { } diff --git a/backend/src/main/java/reviewme/review/dto/response/ReceivedReviewResponse2.java b/backend/src/main/java/reviewme/review/dto/response/ReceivedReviewResponse2.java index 0cf779cc3..4513d43d2 100644 --- a/backend/src/main/java/reviewme/review/dto/response/ReceivedReviewResponse2.java +++ b/backend/src/main/java/reviewme/review/dto/response/ReceivedReviewResponse2.java @@ -8,7 +8,7 @@ public record ReceivedReviewResponse2( @Schema(description = "리뷰 ID") - long id, + long reviewId, @Schema(description = "리뷰 작성일") LocalDate createdAt, diff --git a/backend/src/main/java/reviewme/review/service/dto/response/detail/OptionGroupAnswerResponse.java b/backend/src/main/java/reviewme/review/service/dto/response/detail/OptionGroupAnswerResponse.java index 894dbaae8..cb0cdcae5 100644 --- a/backend/src/main/java/reviewme/review/service/dto/response/detail/OptionGroupAnswerResponse.java +++ b/backend/src/main/java/reviewme/review/service/dto/response/detail/OptionGroupAnswerResponse.java @@ -1,11 +1,21 @@ package reviewme.review.service.dto.response.detail; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; +@Schema(name = "옵션 그룹 정보") public record OptionGroupAnswerResponse( + + @Schema(description = "옵션 그룹 ID") long optionGroupId, + + @Schema(description = "최소 선택 수") long minCount, + + @Schema(description = "최대 선택 수") long maxCount, + + @Schema(description = "옵션 목록") List options ) { } diff --git a/backend/src/main/java/reviewme/review/service/dto/response/detail/OptionItemAnswerResponse.java b/backend/src/main/java/reviewme/review/service/dto/response/detail/OptionItemAnswerResponse.java index 6bd424f5f..ca6f3a072 100644 --- a/backend/src/main/java/reviewme/review/service/dto/response/detail/OptionItemAnswerResponse.java +++ b/backend/src/main/java/reviewme/review/service/dto/response/detail/OptionItemAnswerResponse.java @@ -1,8 +1,17 @@ package reviewme.review.service.dto.response.detail; +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(name = "옵션 및 선택 정보") public record OptionItemAnswerResponse( + + @Schema(description = "옵션 ID") long optionId, + + @Schema(description = "내용") String content, + + @Schema(description = "선택 여부") boolean isChecked ) { } diff --git a/backend/src/main/java/reviewme/review/service/dto/response/detail/QuestionAnswerResponse.java b/backend/src/main/java/reviewme/review/service/dto/response/detail/QuestionAnswerResponse.java index 000eb83c8..9d8be359b 100644 --- a/backend/src/main/java/reviewme/review/service/dto/response/detail/QuestionAnswerResponse.java +++ b/backend/src/main/java/reviewme/review/service/dto/response/detail/QuestionAnswerResponse.java @@ -1,14 +1,30 @@ package reviewme.review.service.dto.response.detail; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.annotation.Nullable; import reviewme.question.domain.QuestionType; +@Schema(name = "질문 및 답변 정보") public record QuestionAnswerResponse( + + @Schema(description = "질문 ID") long questionId, + + @Schema(description = "필수 여부") boolean required, + + @Schema(description = "질문 유형") QuestionType questionType, + + @Schema(description = "질문") String content, - @Nullable OptionGroupAnswerResponse optionGroup, - @Nullable String answer + + @Schema(description = "옵션 그룹", nullable = true) + @Nullable + OptionGroupAnswerResponse optionGroup, + + @Schema(description = "답변", nullable = true) + @Nullable + String answer ) { } diff --git a/backend/src/main/java/reviewme/review/service/dto/response/detail/SectionAnswerResponse.java b/backend/src/main/java/reviewme/review/service/dto/response/detail/SectionAnswerResponse.java index ad2887644..f0a386d92 100644 --- a/backend/src/main/java/reviewme/review/service/dto/response/detail/SectionAnswerResponse.java +++ b/backend/src/main/java/reviewme/review/service/dto/response/detail/SectionAnswerResponse.java @@ -1,10 +1,18 @@ package reviewme.review.service.dto.response.detail; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; +@Schema(name = "리뷰 섹션 정보") public record SectionAnswerResponse( + + @Schema(description = "섹션 ID") long sectionId, + + @Schema(description = "말머리") String header, + + @Schema(description = "질문 목록") List questions ) { } diff --git a/backend/src/main/java/reviewme/review/service/dto/response/detail/TemplateAnswerResponse.java b/backend/src/main/java/reviewme/review/service/dto/response/detail/TemplateAnswerResponse.java index 0e838236b..425c852f9 100644 --- a/backend/src/main/java/reviewme/review/service/dto/response/detail/TemplateAnswerResponse.java +++ b/backend/src/main/java/reviewme/review/service/dto/response/detail/TemplateAnswerResponse.java @@ -1,13 +1,25 @@ package reviewme.review.service.dto.response.detail; +import io.swagger.v3.oas.annotations.media.Schema; import java.time.LocalDate; import java.util.List; +@Schema(name = "리뷰 상세 정보") public record TemplateAnswerResponse( + + @Schema(description = "폼 ID") long formId, + + @Schema(description = "리뷰이 이름") String revieweeName, + + @Schema(description = "프로젝트 이름") String projectName, + + @Schema(description = "리뷰 작성일") LocalDate createdAt, + + @Schema(description = "섹션 목록") List sections ) { } diff --git a/backend/src/main/java/reviewme/template/controller/TemplateApi.java b/backend/src/main/java/reviewme/template/controller/TemplateApi.java new file mode 100644 index 000000000..b44927a87 --- /dev/null +++ b/backend/src/main/java/reviewme/template/controller/TemplateApi.java @@ -0,0 +1,51 @@ +package reviewme.template.controller; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +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 org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestParam; +import reviewme.template.dto.response.TemplateResponse; + +@Tag(name = "리뷰 폼 관리") +public interface TemplateApi { + + @Operation(summary = "리뷰 폼 요청", description = "리뷰 작성을 위한 리뷰 폼을 요청한다.") + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "응답 성공 : 리뷰 폼 응답", + content = @Content( + mediaType = APPLICATION_JSON_VALUE, + schema = @Schema(implementation = TemplateResponse.class) + ) + ), + @ApiResponse( + responseCode = "400", + description = "응답 실패 : 올바르지 않은 리뷰 요청 코드입니다.", + content = @Content( + mediaType = APPLICATION_JSON_VALUE, + examples = @ExampleObject(value = """ + { + "type": "about:blank", + "title": "Bad Request", + "status": 400, + "detail": "올바르지 않은 리뷰 요청 코드입니다.", + "instance": "/reviews/write" + } + """) + ) + ) + }) + ResponseEntity getReviewForm( + @Parameter(description = "리뷰 요청 코드", required = true) + @RequestParam String reviewRequestCode + ); +} diff --git a/backend/src/main/java/reviewme/template/controller/TemplateController.java b/backend/src/main/java/reviewme/template/controller/TemplateController.java index dad6acd04..7f0d463bd 100644 --- a/backend/src/main/java/reviewme/template/controller/TemplateController.java +++ b/backend/src/main/java/reviewme/template/controller/TemplateController.java @@ -10,7 +10,7 @@ @RestController @RequiredArgsConstructor -public class TemplateController { +public class TemplateController implements TemplateApi { private final TemplateService templateService; diff --git a/backend/src/main/java/reviewme/template/dto/response/OptionGroupResponse.java b/backend/src/main/java/reviewme/template/dto/response/OptionGroupResponse.java index 7fe5732ed..74ec6fcde 100644 --- a/backend/src/main/java/reviewme/template/dto/response/OptionGroupResponse.java +++ b/backend/src/main/java/reviewme/template/dto/response/OptionGroupResponse.java @@ -1,12 +1,21 @@ package reviewme.template.dto.response; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; +@Schema(name = "옵션 그룹 응답") public record OptionGroupResponse( + @Schema(description = "옵션 그룹 ID") long optionGroupId, + + @Schema(description = "최소 선택 수") int minCount, + + @Schema(description = "최대 선택 수") int maxCount, + + @Schema(description = "옵션 목록") List options ) { } diff --git a/backend/src/main/java/reviewme/template/dto/response/OptionItemResponse.java b/backend/src/main/java/reviewme/template/dto/response/OptionItemResponse.java index a96160598..00efe0cf0 100644 --- a/backend/src/main/java/reviewme/template/dto/response/OptionItemResponse.java +++ b/backend/src/main/java/reviewme/template/dto/response/OptionItemResponse.java @@ -1,8 +1,14 @@ package reviewme.template.dto.response; +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(name = "옵션 응답") public record OptionItemResponse( + @Schema(description = "옵션 ID") long optionId, + + @Schema(description = "내용") String content ) { } diff --git a/backend/src/main/java/reviewme/template/dto/response/QuestionResponse.java b/backend/src/main/java/reviewme/template/dto/response/QuestionResponse.java index 8c8a9582d..759a65a9c 100644 --- a/backend/src/main/java/reviewme/template/dto/response/QuestionResponse.java +++ b/backend/src/main/java/reviewme/template/dto/response/QuestionResponse.java @@ -1,15 +1,32 @@ package reviewme.template.dto.response; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.annotation.Nullable; +@Schema(name = "질문 응답") public record QuestionResponse( + @Schema(description = "질문 ID") long questionId, + + @Schema(description = "필수 여부") boolean required, + + @Schema(description = "질문") String content, + + @Schema(description = "질문 유형", examples = {"CHECKBOX", "TEXT"}) String questionType, - @Nullable OptionGroupResponse optionGroup, + + @Schema(description = "옵션 그룹", nullable = true) + @Nullable + OptionGroupResponse optionGroup, + + @Schema(description = "가이드라인 제공 여부") boolean hasGuideline, - @Nullable String guideline + + @Schema(description = "가이드라인", nullable = true) + @Nullable + String guideline ) { } diff --git a/backend/src/main/java/reviewme/template/dto/response/SectionResponse.java b/backend/src/main/java/reviewme/template/dto/response/SectionResponse.java index 5cdc9a3a5..89bc81e0f 100644 --- a/backend/src/main/java/reviewme/template/dto/response/SectionResponse.java +++ b/backend/src/main/java/reviewme/template/dto/response/SectionResponse.java @@ -1,14 +1,26 @@ package reviewme.template.dto.response; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.annotation.Nullable; import java.util.List; +@Schema(name = "섹션 응답") public record SectionResponse( + @Schema(description = "섹션 ID") long sectionId, + + @Schema(description = "노출 조건") String visible, - @Nullable Long onSelectedOptionId, + + @Schema(description = "선택된 옵션 ID", nullable = true) + @Nullable + Long onSelectedOptionId, + + @Schema(description = "말머리") String header, + + @Schema(description = "질문 목록") List questions ) { } diff --git a/backend/src/main/java/reviewme/template/dto/response/TemplateResponse.java b/backend/src/main/java/reviewme/template/dto/response/TemplateResponse.java index 8df16a786..e0ac347fc 100644 --- a/backend/src/main/java/reviewme/template/dto/response/TemplateResponse.java +++ b/backend/src/main/java/reviewme/template/dto/response/TemplateResponse.java @@ -1,12 +1,21 @@ package reviewme.template.dto.response; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; +@Schema(name = "리뷰 폼 응답") public record TemplateResponse( + @Schema(description = "폼 ID") long formId, + + @Schema(description = "리뷰이 이름") String revieweeName, + + @Schema(description = "프로젝트 이름") String projectName, + + @Schema(description = "섹션 목록") List sections ) { }