diff --git a/src/main/kotlin/com/example/onui/domain/auth/presentation/AuthController.kt b/src/main/kotlin/com/example/onui/domain/auth/presentation/AuthController.kt index f6e2613..2a44a41 100644 --- a/src/main/kotlin/com/example/onui/domain/auth/presentation/AuthController.kt +++ b/src/main/kotlin/com/example/onui/domain/auth/presentation/AuthController.kt @@ -4,6 +4,7 @@ import com.example.onui.domain.auth.presentation.dto.response.TokenResponse import com.example.onui.domain.auth.service.AppleAuthService import com.example.onui.domain.auth.service.AuthService import com.example.onui.domain.auth.service.GoogleAuthService +import org.springframework.http.HttpStatus import org.springframework.validation.annotation.Validated import org.springframework.web.bind.annotation.* @@ -17,6 +18,7 @@ class AuthController( ) { @PostMapping("/google") + @ResponseStatus(HttpStatus.CREATED) fun oauthSignIn( @RequestParam(name = "token", required = true) token: String @@ -29,6 +31,7 @@ class AuthController( ): TokenResponse = authService.reissue(token) @PostMapping("/apple") + @ResponseStatus(HttpStatus.CREATED) fun oauthSignInWithApple( @RequestParam(name = "token", required = true) token: String diff --git a/src/main/kotlin/com/example/onui/domain/auth/service/GoogleAuthServiceImpl.kt b/src/main/kotlin/com/example/onui/domain/auth/service/GoogleAuthServiceImpl.kt index d5e2992..f932f96 100644 --- a/src/main/kotlin/com/example/onui/domain/auth/service/GoogleAuthServiceImpl.kt +++ b/src/main/kotlin/com/example/onui/domain/auth/service/GoogleAuthServiceImpl.kt @@ -4,6 +4,7 @@ import com.example.onui.domain.auth.presentation.dto.response.TokenResponse import com.example.onui.domain.auth.repository.RefreshTokenRepository import com.example.onui.domain.user.entity.User import com.example.onui.domain.user.repository.UserRepository +import com.example.onui.global.config.error.exception.InvalidTokenException import com.example.onui.global.config.jwt.TokenProvider import com.example.onui.infra.feign.google.GoogleAuthClient import com.example.onui.infra.feign.google.GoogleInfoClient @@ -31,12 +32,17 @@ class GoogleAuthServiceImpl( logger.info { token } - val response = googleInfo.googleInfo(ALT, token) + val response = try { + googleInfo.googleInfo(ALT, token) + } catch (e: Exception) { + throw InvalidTokenException + } refreshTokenRepository.findBySub(response.sub)?.let { refreshTokenRepository.delete(it) } + googleAuth.revokeToken(token) val tokenResponse = tokenProvider.receiveToken(response.sub) userRepository.findBySub(response.sub) @@ -47,8 +53,6 @@ class GoogleAuthServiceImpl( ) ) - googleAuth.revokeToken(token) - return tokenResponse } } \ No newline at end of file diff --git a/src/main/kotlin/com/example/onui/domain/diary/entity/Diary.kt b/src/main/kotlin/com/example/onui/domain/diary/entity/Diary.kt index f2ee99a..dd425da 100644 --- a/src/main/kotlin/com/example/onui/domain/diary/entity/Diary.kt +++ b/src/main/kotlin/com/example/onui/domain/diary/entity/Diary.kt @@ -2,6 +2,8 @@ import com.example.onui.domain.diary.presentation.response.DiaryDetailResponse import com.example.onui.domain.diary.presentation.response.DiaryResponse +import com.example.onui.domain.timeline.entity.Comment +import com.example.onui.domain.timeline.presentation.dto.response.TimelineResponse import com.example.onui.domain.user.entity.User import com.example.onui.global.common.entity.BaseTimeEntity import java.time.LocalDateTime @@ -54,6 +56,9 @@ Diary( var isPosted: Boolean = isPosted protected set + @OneToMany(mappedBy = "timeline", cascade = [CascadeType.REMOVE]) + var commentList: MutableList = arrayListOf() + fun toResponse() = DiaryResponse( this.id!!, this.mood, @@ -68,4 +73,14 @@ Diary( this.createdAt.toLocalDate(), this.image ) + + fun toTimelineResponse() = TimelineResponse( + this.id!!, + this.content, + this.mood, + this.tagList, + this.image, + this.user.name, + this.commentList.size + ) } \ No newline at end of file diff --git a/src/main/kotlin/com/example/onui/domain/diary/repository/DiaryRepository.kt b/src/main/kotlin/com/example/onui/domain/diary/repository/DiaryRepository.kt index 45bedc4..66d2dcb 100644 --- a/src/main/kotlin/com/example/onui/domain/diary/repository/DiaryRepository.kt +++ b/src/main/kotlin/com/example/onui/domain/diary/repository/DiaryRepository.kt @@ -14,4 +14,6 @@ interface DiaryRepository : JpaRepository { fun findByUserAndYearAndMonthAndDay(user: User, year: Int, month: Int, day: Int): Diary? fun existsByIdAndIsPosted(id: UUID, isPosted: Boolean): Boolean + + fun findByIdAndIsPosted(id: UUID, isPosted: Boolean): Diary? } \ No newline at end of file diff --git a/src/main/kotlin/com/example/onui/domain/timeline/entity/Comment.kt b/src/main/kotlin/com/example/onui/domain/timeline/entity/Comment.kt new file mode 100644 index 0000000..b7c0de7 --- /dev/null +++ b/src/main/kotlin/com/example/onui/domain/timeline/entity/Comment.kt @@ -0,0 +1,47 @@ +package com.example.onui.domain.timeline.entity + +import com.example.onui.domain.diary.entity.Diary +import com.example.onui.domain.timeline.presentation.dto.response.CommentResponse +import com.example.onui.domain.user.entity.User +import java.time.LocalDateTime +import java.util.* +import javax.persistence.* + +@Entity(name = "comment") +class Comment( + content: String, + user: User, + timeline: Diary, + id: UUID? = null +) { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(columnDefinition = "BINARY(16)") + var id: UUID? = id + protected set + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + var user: User = user + protected set + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "timeline_id", nullable = false) + var timeline: Diary = timeline + protected set + + @Column(name = "content", columnDefinition = "VARCHAR(50)", nullable = false) + var content: String = content + protected set + + @Column(name = "created_at", nullable = false) + var createdAt: LocalDateTime = LocalDateTime.now() + protected set + + fun toResponse() = CommentResponse( + this.id!!, + this.timeline.id!!, + this.user.id!!, + this.content + ) +} \ No newline at end of file diff --git a/src/main/kotlin/com/example/onui/domain/timeline/exception/AlreadyPostedTimeLineException.kt b/src/main/kotlin/com/example/onui/domain/timeline/exception/AlreadyPostedTimelineException.kt similarity index 77% rename from src/main/kotlin/com/example/onui/domain/timeline/exception/AlreadyPostedTimeLineException.kt rename to src/main/kotlin/com/example/onui/domain/timeline/exception/AlreadyPostedTimelineException.kt index bc3b5b7..331feb7 100644 --- a/src/main/kotlin/com/example/onui/domain/timeline/exception/AlreadyPostedTimeLineException.kt +++ b/src/main/kotlin/com/example/onui/domain/timeline/exception/AlreadyPostedTimelineException.kt @@ -3,4 +3,4 @@ import com.example.onui.global.config.error.data.ErrorCode import com.example.onui.global.config.error.exception.BusinessException -object AlreadyPostedTimeLineException : BusinessException(ErrorCode.ALREADY_POSTED_TIMELINE) +object AlreadyPostedTimelineException : BusinessException(ErrorCode.ALREADY_POSTED_TIMELINE) diff --git a/src/main/kotlin/com/example/onui/domain/timeline/exception/TimelineNotFoundException.kt b/src/main/kotlin/com/example/onui/domain/timeline/exception/TimelineNotFoundException.kt new file mode 100644 index 0000000..b5808f2 --- /dev/null +++ b/src/main/kotlin/com/example/onui/domain/timeline/exception/TimelineNotFoundException.kt @@ -0,0 +1,6 @@ +package com.example.onui.domain.timeline.exception + +import com.example.onui.global.config.error.data.ErrorCode +import com.example.onui.global.config.error.exception.BusinessException + +object TimelineNotFoundException : BusinessException(ErrorCode.TIMELINE_NOT_FOUND) diff --git a/src/main/kotlin/com/example/onui/domain/timeline/presentation/CommentController.kt b/src/main/kotlin/com/example/onui/domain/timeline/presentation/CommentController.kt new file mode 100644 index 0000000..57973e9 --- /dev/null +++ b/src/main/kotlin/com/example/onui/domain/timeline/presentation/CommentController.kt @@ -0,0 +1,32 @@ +package com.example.onui.domain.timeline.presentation + +import com.example.onui.domain.timeline.presentation.dto.request.CommentRequest +import com.example.onui.domain.timeline.service.TimelineService +import org.springframework.http.HttpStatus +import org.springframework.validation.annotation.Validated +import org.springframework.web.bind.annotation.* +import java.util.* +import javax.validation.Valid + +@Validated +@RestController +@RequestMapping("/comment") +class CommentController( + private val timelineService: TimelineService +) { + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + fun createComment( + @RequestParam("timeline_id", required = true) + timelineId: UUID, + @RequestBody @Valid + req: CommentRequest + ) = timelineService.comment(timelineId, req.comment) + + @GetMapping + fun getComment( + @RequestParam("timeline_id", required = true) + timelineId: UUID + ) = timelineService.getComment(timelineId) +} \ No newline at end of file diff --git a/src/main/kotlin/com/example/onui/domain/timeline/presentation/TimelineController.kt b/src/main/kotlin/com/example/onui/domain/timeline/presentation/TimelineController.kt index 33ab5e8..2613ea0 100644 --- a/src/main/kotlin/com/example/onui/domain/timeline/presentation/TimelineController.kt +++ b/src/main/kotlin/com/example/onui/domain/timeline/presentation/TimelineController.kt @@ -1,7 +1,7 @@ package com.example.onui.domain.timeline.presentation import com.example.onui.domain.timeline.exception.InvalidDateFormatException -import com.example.onui.domain.timeline.service.TimeLineService +import com.example.onui.domain.timeline.service.TimelineService import org.springframework.http.HttpStatus import org.springframework.validation.annotation.Validated import org.springframework.web.bind.annotation.* @@ -13,14 +13,12 @@ import java.util.* @RestController @RequestMapping("/tl") class TimelineController( - private val timelineService: TimeLineService + private val timelineService: TimelineService ) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - fun createTimeline( - @RequestParam("id", required = true) id: UUID - ) = timelineService.post(id) + fun createTimeline(@RequestParam("id", required = true) id: UUID) = timelineService.post(id) @GetMapping fun getByDate( diff --git a/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/request/CommentRequest.kt b/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/request/CommentRequest.kt new file mode 100644 index 0000000..c5ccbf7 --- /dev/null +++ b/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/request/CommentRequest.kt @@ -0,0 +1,11 @@ +package com.example.onui.domain.timeline.presentation.dto.request + +import javax.validation.constraints.NotBlank +import javax.validation.constraints.Size + +data class CommentRequest( + + @field:NotBlank(message = "comment는 null일 수 없습니다.") + @field:Size(max = 50, message = "댓글은 최대 50자 입니다.") + val comment: String +) diff --git a/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/response/CommentListResponse.kt b/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/response/CommentListResponse.kt new file mode 100644 index 0000000..06725fe --- /dev/null +++ b/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/response/CommentListResponse.kt @@ -0,0 +1,5 @@ +package com.example.onui.domain.timeline.presentation.dto.response + +data class CommentListResponse( + val commentList: MutableList? +) diff --git a/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/response/CommentResponse.kt b/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/response/CommentResponse.kt new file mode 100644 index 0000000..210d128 --- /dev/null +++ b/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/response/CommentResponse.kt @@ -0,0 +1,10 @@ +package com.example.onui.domain.timeline.presentation.dto.response + +import java.util.* + +data class CommentResponse( + val id: UUID, + val timeline: UUID, + val user: UUID, + val content: String +) diff --git a/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/response/TimelineResponse.kt b/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/response/TimelineResponse.kt index 21a61be..0f93e6c 100644 --- a/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/response/TimelineResponse.kt +++ b/src/main/kotlin/com/example/onui/domain/timeline/presentation/dto/response/TimelineResponse.kt @@ -1,17 +1,14 @@ package com.example.onui.domain.timeline.presentation.dto.response import com.example.onui.domain.diary.entity.Mood -import java.time.DayOfWeek -import java.time.LocalDateTime import java.util.* data class TimelineResponse( val id: UUID, val content: String?, val mood: Mood, - val tag: MutableList, + val tagList: MutableList, val image: String?, - val dayOfWeek: DayOfWeek, - val createdAt: LocalDateTime, - val isUpdated: Boolean -) \ No newline at end of file + val writer: String, + val commentCount: Int +) diff --git a/src/main/kotlin/com/example/onui/domain/timeline/repository/CommentRepository.kt b/src/main/kotlin/com/example/onui/domain/timeline/repository/CommentRepository.kt new file mode 100644 index 0000000..adafc20 --- /dev/null +++ b/src/main/kotlin/com/example/onui/domain/timeline/repository/CommentRepository.kt @@ -0,0 +1,13 @@ +package com.example.onui.domain.timeline.repository + +import com.example.onui.domain.diary.entity.Diary +import com.example.onui.domain.timeline.entity.Comment +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository +import java.util.* + +@Repository +interface CommentRepository : JpaRepository { + + fun findAllByTimelineOrderByCreatedAtAsc(timeline: Diary): MutableList +} \ No newline at end of file diff --git a/src/main/kotlin/com/example/onui/domain/timeline/repository/QTimelineRepository.kt b/src/main/kotlin/com/example/onui/domain/timeline/repository/QTimelineRepository.kt index 452a3b3..a6e45b0 100644 --- a/src/main/kotlin/com/example/onui/domain/timeline/repository/QTimelineRepository.kt +++ b/src/main/kotlin/com/example/onui/domain/timeline/repository/QTimelineRepository.kt @@ -1,11 +1,11 @@ package com.example.onui.domain.timeline.repository -import com.example.onui.domain.diary.presentation.response.DiaryDetailResponse +import com.example.onui.domain.timeline.presentation.dto.response.TimelineResponse import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import java.time.LocalDate interface QTimelineRepository { - fun findPageByDate(pageable: Pageable, date: LocalDate): Page + fun findPageByDate(pageable: Pageable, date: LocalDate): Page } diff --git a/src/main/kotlin/com/example/onui/domain/timeline/repository/QTimelineRepositoryImpl.kt b/src/main/kotlin/com/example/onui/domain/timeline/repository/QTimelineRepositoryImpl.kt index e9214bc..6682381 100644 --- a/src/main/kotlin/com/example/onui/domain/timeline/repository/QTimelineRepositoryImpl.kt +++ b/src/main/kotlin/com/example/onui/domain/timeline/repository/QTimelineRepositoryImpl.kt @@ -1,7 +1,7 @@ package com.example.onui.domain.timeline.repository import com.example.onui.domain.diary.entity.QDiary.diary -import com.example.onui.domain.diary.presentation.response.DiaryDetailResponse +import com.example.onui.domain.timeline.presentation.dto.response.TimelineResponse import com.querydsl.jpa.impl.JPAQueryFactory import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl @@ -14,7 +14,7 @@ class QTimelineRepositoryImpl( private val query: JPAQueryFactory ) : QTimelineRepository { - override fun findPageByDate(pageable: Pageable, date: LocalDate): Page { + override fun findPageByDate(pageable: Pageable, date: LocalDate): Page { val query = query.selectFrom(diary).where( diary.isPosted.eq(true).and( diary.day.eq(date.dayOfMonth).and( @@ -25,7 +25,7 @@ class QTimelineRepositoryImpl( ) ).orderBy(diary.createdAt.desc()).offset(pageable.offset).limit(pageable.pageSize.toLong()) - val iterable = query.fetch().map { it.toDetailResponse() } + val iterable = query.fetch().map { it.toTimelineResponse() } return PageImpl(iterable, pageable, iterable.size.toLong()) } diff --git a/src/main/kotlin/com/example/onui/domain/timeline/service/TimeLineService.kt b/src/main/kotlin/com/example/onui/domain/timeline/service/TimeLineService.kt deleted file mode 100644 index 8556d52..0000000 --- a/src/main/kotlin/com/example/onui/domain/timeline/service/TimeLineService.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.onui.domain.timeline.service - -import com.example.onui.domain.diary.presentation.response.DiaryDetailResponse -import org.springframework.data.domain.Page -import java.time.LocalDate -import java.util.* - -interface TimeLineService { - - fun post(id: UUID): DiaryDetailResponse - - fun searchByDate(idx: Int, size: Int, date: LocalDate): Page -} diff --git a/src/main/kotlin/com/example/onui/domain/timeline/service/TimelineService.kt b/src/main/kotlin/com/example/onui/domain/timeline/service/TimelineService.kt new file mode 100644 index 0000000..a8537f5 --- /dev/null +++ b/src/main/kotlin/com/example/onui/domain/timeline/service/TimelineService.kt @@ -0,0 +1,19 @@ +package com.example.onui.domain.timeline.service + +import com.example.onui.domain.timeline.presentation.dto.response.CommentListResponse +import com.example.onui.domain.timeline.presentation.dto.response.CommentResponse +import com.example.onui.domain.timeline.presentation.dto.response.TimelineResponse +import org.springframework.data.domain.Page +import java.time.LocalDate +import java.util.* + +interface TimelineService { + + fun post(id: UUID): TimelineResponse + + fun searchByDate(idx: Int, size: Int, date: LocalDate): Page + + fun comment(timelineId: UUID, comment: String): CommentResponse + + fun getComment(timelineId: UUID): CommentListResponse +} diff --git a/src/main/kotlin/com/example/onui/domain/timeline/service/TimelineServiceImpl.kt b/src/main/kotlin/com/example/onui/domain/timeline/service/TimelineServiceImpl.kt index 7211091..def6f7b 100644 --- a/src/main/kotlin/com/example/onui/domain/timeline/service/TimelineServiceImpl.kt +++ b/src/main/kotlin/com/example/onui/domain/timeline/service/TimelineServiceImpl.kt @@ -2,9 +2,14 @@ import com.example.onui.domain.diary.entity.Diary import com.example.onui.domain.diary.exception.DiaryNotFoundException -import com.example.onui.domain.diary.presentation.response.DiaryDetailResponse import com.example.onui.domain.diary.repository.DiaryRepository -import com.example.onui.domain.timeline.exception.AlreadyPostedTimeLineException +import com.example.onui.domain.timeline.entity.Comment +import com.example.onui.domain.timeline.exception.AlreadyPostedTimelineException +import com.example.onui.domain.timeline.exception.TimelineNotFoundException +import com.example.onui.domain.timeline.presentation.dto.response.CommentListResponse +import com.example.onui.domain.timeline.presentation.dto.response.CommentResponse +import com.example.onui.domain.timeline.presentation.dto.response.TimelineResponse +import com.example.onui.domain.timeline.repository.CommentRepository import com.example.onui.domain.timeline.repository.QTimelineRepository import com.example.onui.global.common.facade.UserFacade import com.example.onui.global.config.error.exception.PermissionDeniedException @@ -21,36 +26,52 @@ import java.util.* class TimelineServiceImpl( private val userFacade: UserFacade, private val qTimelineRepository: QTimelineRepository, - private val diaryRepository: DiaryRepository -) : TimeLineService { + private val diaryRepository: DiaryRepository, + private val commentRepository: CommentRepository +) : TimelineService { @Transactional - override fun post(id: UUID): DiaryDetailResponse { + override fun post(id: UUID): TimelineResponse { val user = userFacade.getCurrentUser() - val diary = diaryRepository.findByIdOrNull(id) - ?: throw DiaryNotFoundException + val diary = diaryRepository.findByIdOrNull(id) ?: throw DiaryNotFoundException if (diary.user != user) throw PermissionDeniedException - if (diaryRepository.existsByIdAndIsPosted(id, true)) throw AlreadyPostedTimeLineException + if (diaryRepository.existsByIdAndIsPosted(id, true)) throw AlreadyPostedTimelineException return diaryRepository.save( Diary( - diary.user, - diary.content, - diary.mood, - diary.tagList, - diary.createdAt, - diary.image, - diary.id, - true + diary.user, diary.content, diary.mood, diary.tagList, diary.createdAt, diary.image, diary.id, true ) - ).toDetailResponse() + ).toTimelineResponse() } - override fun searchByDate(idx: Int, size: Int, date: LocalDate) = qTimelineRepository - .findPageByDate( - PageRequest.of(idx, size, Sort.by("diary.createdAt").descending()), date - ) + override fun searchByDate(idx: Int, size: Int, date: LocalDate) = qTimelineRepository.findPageByDate( + PageRequest.of(idx, size, Sort.by("diary.createdAt").descending()), date + ) + + @Transactional + override fun comment(timelineId: UUID, comment: String): CommentResponse { + + val timeline = diaryRepository.findByIdAndIsPosted(timelineId, true) ?: throw TimelineNotFoundException + + return commentRepository.save( + Comment( + comment, userFacade.getCurrentUser(), timeline + ) + ).toResponse() + } + + override fun getComment(timelineId: UUID): CommentListResponse { + + val timeline = diaryRepository.findByIdAndIsPosted(timelineId, true) ?: throw TimelineNotFoundException + + val commentList = + commentRepository.findAllByTimelineOrderByCreatedAtAsc(timeline).map { it.toResponse() }.toMutableList() + + return CommentListResponse(if (commentList.isEmpty()) null else commentList) + } + + } \ No newline at end of file diff --git a/src/main/kotlin/com/example/onui/domain/user/entity/User.kt b/src/main/kotlin/com/example/onui/domain/user/entity/User.kt index 1c5db18..c977d46 100644 --- a/src/main/kotlin/com/example/onui/domain/user/entity/User.kt +++ b/src/main/kotlin/com/example/onui/domain/user/entity/User.kt @@ -1,6 +1,7 @@ package com.example.onui.domain.user.entity import com.example.onui.domain.diary.entity.Diary +import com.example.onui.domain.timeline.entity.Comment import com.example.onui.domain.user.presentation.dto.response.UserProfileResponse import org.hibernate.annotations.DynamicUpdate import java.util.* @@ -31,6 +32,9 @@ class User( @OneToMany(mappedBy = "user", cascade = [CascadeType.REMOVE]) var diaryList: MutableList = arrayListOf() + @OneToMany(mappedBy = "user", cascade = [CascadeType.REMOVE]) + var commentList: MutableList = arrayListOf() + fun toResponse() = UserProfileResponse( this.sub, this.name diff --git a/src/main/kotlin/com/example/onui/global/config/error/data/ErrorCode.kt b/src/main/kotlin/com/example/onui/global/config/error/data/ErrorCode.kt index 82a7c50..b4100ad 100644 --- a/src/main/kotlin/com/example/onui/global/config/error/data/ErrorCode.kt +++ b/src/main/kotlin/com/example/onui/global/config/error/data/ErrorCode.kt @@ -23,6 +23,7 @@ enum class ErrorCode( // 404 DIARY_NOT_FOUND(HttpStatus.NOT_FOUND, "감정 기록을 찾을 수 없습니다."), + TIMELINE_NOT_FOUND(HttpStatus.NOT_FOUND, "타임라인을 찾을 수 없습니다."), // 500 INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부 에러")