From 75e407aee471f3ef2c9d68f5024424b7d1a5b048 Mon Sep 17 00:00:00 2001 From: uykhc Date: Tue, 14 Apr 2026 23:07:34 +0900 Subject: [PATCH 01/27] refactor(openapi): migrate from swagger annotations to static openapi.yaml --- .github/PULL_REQUEST_TEMPLATE/dev.md | 2 + .github/PULL_REQUEST_TEMPLATE/main.md | 1 + .github/workflows/ci.yml | 8 + .../image/controller/ImageController.kt | 15 +- .../domain/auth/controller/AuthController.kt | 40 - .../auth/controller/SocialAuthController.kt | 11 - .../domain/auth/dto/LoginRequest.kt | 5 - .../domain/auth/dto/RegisterRequest.kt | 7 - .../domain/auth/dto/SignupRequest.kt | 7 - .../domain/auth/dto/SocialLoginRequest.kt | 5 - .../event/controller/EventController.kt | 11 - .../domain/event/dto/core/EventDto.kt | 15 - .../event/dto/request/CreateEventRequest.kt | 23 - .../event/dto/request/UpdateEventRequest.kt | 23 - .../event/dto/response/EventDetailResponse.kt | 52 - .../domain/event/dto/response/GuestPreview.kt | 10 - .../domain/event/dto/response/MyRole.kt | 6 - .../domain/event/dto/response/ViewerStatus.kt | 8 - .../controller/EventRegistrationController.kt | 36 - .../controller/MyRegistrationController.kt | 10 +- .../controller/RegistrationController.kt | 14 - .../registration/dto/core/RegistrationDto.kt | 9 - .../dto/core/RegistrationWithEventDto.kt | 10 - .../dto/request/CreateRegistrationRequest.kt | 4 - .../dto/request/DeleteRegistrationRequest.kt | 5 - .../UpdateRegistrationStatusRequest.kt | 2 - .../response/CreateRegistrationResponse.kt | 4 - .../response/GetEventRegistrationsResponse.kt | 14 - .../response/GetMyRegistrationsResponse.kt | 14 - .../dto/response/GetRegistrationResponse.kt | 2 - .../dto/response/PatchRegistrationResponse.kt | 3 - .../response/RegistrationGuestsResponse.kt | 10 - .../domain/user/controller/UserController.kt | 54 +- .../user/identity/dto/core/UserIdentityDto.kt | 7 - src/main/resources/application.yaml | 7 + src/main/resources/static/docs/openapi.yaml | 1181 +++++++++++++++++ .../resources/static/docs/swagger-ui.html | 36 + 37 files changed, 1239 insertions(+), 432 deletions(-) create mode 100644 src/main/resources/static/docs/openapi.yaml create mode 100644 src/main/resources/static/docs/swagger-ui.html diff --git a/.github/PULL_REQUEST_TEMPLATE/dev.md b/.github/PULL_REQUEST_TEMPLATE/dev.md index ad0b6ad0..558f1a66 100644 --- a/.github/PULL_REQUEST_TEMPLATE/dev.md +++ b/.github/PULL_REQUEST_TEMPLATE/dev.md @@ -2,6 +2,8 @@ ### ๐Ÿงช ๋กœ์ปฌ ํ…Œ์ŠคํŠธ ์—ฌ๋ถ€ (์ž‘์—…์ž ์ฒดํฌ) - [ ] ๋กœ์ปฌ์—์„œ Swagger ํ˜น์€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋กœ ๋™์ž‘์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. +- [ ] API ๋ณ€๊ฒฝ์ด ์žˆ๋‹ค๋ฉด `src/main/resources/static/docs/openapi.yaml`์„ ํ•จ๊ป˜ ๊ฐฑ์‹ ํ–ˆ์Šต๋‹ˆ๋‹ค. +- [ ] `/docs/swagger-ui.html`์—์„œ ๋ณ€๊ฒฝ API๊ฐ€ ์˜๋„๋Œ€๋กœ ๋ณด์ด๋Š”์ง€ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ### ๐Ÿ“„ documentation ์ตœ์‹ ํ™” ์—ฌ๋ถ€ > ๋ณ€๊ฒฝ์‚ฌํ•ญ๊ณผ ๊ด€๋ จ๋œ API์˜ swagger documentation์ด ์‹ค์ œ ๋™์ž‘๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. diff --git a/.github/PULL_REQUEST_TEMPLATE/main.md b/.github/PULL_REQUEST_TEMPLATE/main.md index e46646af..15cd0692 100644 --- a/.github/PULL_REQUEST_TEMPLATE/main.md +++ b/.github/PULL_REQUEST_TEMPLATE/main.md @@ -5,6 +5,7 @@ - [ ] CI ์„ฑ๊ณต - [ ] ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ • ํ™•์ธ - [ ] dev ์„œ๋ฒ„์—์„œ ๋ณ€๊ฒฝ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์˜๋„๋Œ€๋กœ ๋™์ž‘ํ•จ์„ ํ™•์ธ +- [ ] API ๋ณ€๊ฒฝ์ด ์žˆ๋‹ค๋ฉด `src/main/resources/static/docs/openapi.yaml` ๋ฐ˜์˜ ์™„๋ฃŒ ### ๐Ÿ“ ์—…๋ฐ์ดํŠธ ์‚ฌํ•ญ ์š”์•ฝ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d75114a4..80cda61f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,14 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Set up Node 20 + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Lint OpenAPI YAML + run: npx @redocly/cli@latest lint src/main/resources/static/docs/openapi.yaml + - name: Set up JDK 21 uses: actions/setup-java@v4 with: diff --git a/src/main/kotlin/com/wafflestudio/spring2025/common/image/controller/ImageController.kt b/src/main/kotlin/com/wafflestudio/spring2025/common/image/controller/ImageController.kt index d774bdb0..1cdb9ea8 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/common/image/controller/ImageController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/common/image/controller/ImageController.kt @@ -4,10 +4,6 @@ import com.wafflestudio.spring2025.common.image.dto.ImageUploadResponse import com.wafflestudio.spring2025.common.image.service.ImageService import com.wafflestudio.spring2025.domain.auth.LoggedInUser import com.wafflestudio.spring2025.domain.user.model.User -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 org.springframework.http.MediaType import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PostMapping @@ -22,21 +18,12 @@ import org.springframework.web.multipart.MultipartFile class ImageController( private val imageService: ImageService, ) { - @Operation(summary = "์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", description = "์„œ๋ฒ„ ์ €์žฅ์†Œ์— ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.") - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์„ฑ๊ณต"), - ApiResponse(responseCode = "400", description = "์ž˜๋ชป๋œ ์š”์ฒญ (ํŒŒ์ผ ๋ˆ„๋ฝ/ํ˜•์‹ ์˜ค๋ฅ˜ ๋“ฑ)"), - ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ)"), - ], - ) @PostMapping( consumes = [MediaType.MULTIPART_FORM_DATA_VALUE], ) fun uploadImage( - @Parameter(hidden = true) @LoggedInUser user: User?, + @LoggedInUser user: User?, @RequestPart("image") image: MultipartFile, - @Parameter(description = "์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•  ์ƒ์œ„ ๊ฒฝ๋กœ", required = false) @RequestParam(name = "prefix", required = false) prefix: String?, ): ResponseEntity { diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/AuthController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/AuthController.kt index fae13d16..f35d874e 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/AuthController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/AuthController.kt @@ -5,10 +5,6 @@ import com.wafflestudio.spring2025.domain.auth.dto.LoginResponse import com.wafflestudio.spring2025.domain.auth.dto.SignupRequest import com.wafflestudio.spring2025.domain.auth.service.AuthService import com.wafflestudio.spring2025.domain.auth.service.EmailVerificationService -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.servlet.http.HttpServletRequest import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PathVariable @@ -19,23 +15,10 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/api/auth") -@Tag(name = "Auth", description = "์ธ์ฆ API") class AuthController( private val authService: AuthService, private val emailVerificationService: EmailVerificationService, ) { - @Operation( - summary = "์ด๋ฉ”์ผ ํšŒ์›๊ฐ€์ž…", - description = "์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์ธ์ฆ ์ด๋ฉ”์ผ์„ ๋ฐœ์†กํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฉ”์ผ ์ธ์ฆ ํ›„ ๊ฐ€์ž…์ด ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.", - ) - @ApiResponses( - value = [ - ApiResponse(responseCode = "204", description = "์ธ์ฆ ์ด๋ฉ”์ผ ๋ฐœ์†ก ์„ฑ๊ณต"), - ApiResponse(responseCode = "400", description = "์ž˜๋ชป๋œ ์š”์ฒญ (์œ ํšจํ•˜์ง€ ์•Š์€ email/password/name)"), - ApiResponse(responseCode = "409", description = "์ด๋ฏธ ์กด์žฌํ•˜๋Š” email"), - ApiResponse(responseCode = "503", description = "์ด๋ฉ”์ผ ์„œ๋น„์Šค ์žฅ์• "), - ], - ) @PostMapping("/signup") fun signup( @RequestBody signupRequest: SignupRequest, @@ -51,16 +34,6 @@ class AuthController( return ResponseEntity.noContent().build() } - @Operation( - summary = "์ด๋ฉ”์ผ ์ธ์ฆ", - description = "์ด๋ฉ”์ผ๋กœ ๋ฐ›์€ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  ํšŒ์›๊ฐ€์ž…์„ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค", - ) - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "์ธ์ฆ ์„ฑ๊ณต, ์œ ์ € ๋“ฑ๋ก ์™„๋ฃŒ"), - ApiResponse(responseCode = "400", description = "์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋งŒ๋ฃŒ๋œ ์ธ์ฆ ์ฝ”๋“œ"), - ], - ) @PostMapping("/email-verification/{verificationCode}") fun verifyEmail( @PathVariable verificationCode: String, @@ -69,13 +42,6 @@ class AuthController( return ResponseEntity.ok().build() } - @Operation(summary = "๋กœ๊ทธ์ธ", description = "email๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ JWT ํ† ํฐ์„ ๋ฐœ๊ธ‰๋ฐ›์Šต๋‹ˆ๋‹ค") - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "๋กœ๊ทธ์ธ ์„ฑ๊ณต, JWT ํ† ํฐ ๋ฐ˜ํ™˜"), - ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ"), - ], - ) @PostMapping("/login") fun login( @RequestBody loginRequest: LoginRequest, @@ -84,12 +50,6 @@ class AuthController( return ResponseEntity.ok(LoginResponse(token)) } - @Operation(summary = "๋กœ๊ทธ์•„์›ƒ", description = "ํ˜„์žฌ JWT ํ† ํฐ์„ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•˜์—ฌ ๋กœ๊ทธ์•„์›ƒํ•ฉ๋‹ˆ๋‹ค") - @ApiResponses( - value = [ - ApiResponse(responseCode = "204", description = "๋กœ๊ทธ์•„์›ƒ ์„ฑ๊ณต"), - ], - ) @PostMapping("/logout") fun logout(request: HttpServletRequest): ResponseEntity { val token = resolveToken(request) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt index b43a4ced..dbd09f73 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt @@ -4,9 +4,6 @@ import com.wafflestudio.spring2025.domain.auth.dto.LoginResponse import com.wafflestudio.spring2025.domain.auth.dto.SocialLoginRequest import com.wafflestudio.spring2025.domain.auth.model.SocialProvider import com.wafflestudio.spring2025.domain.auth.service.SocialAuthService -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.responses.ApiResponse -import io.swagger.v3.oas.annotations.responses.ApiResponses import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody @@ -18,14 +15,6 @@ import org.springframework.web.bind.annotation.RestController class SocialAuthController( private val socialAuthService: SocialAuthService, ) { - @Operation(summary = "์†Œ์…œ ๋กœ๊ทธ์ธ", description = "์†Œ์…œ ๋กœ๊ทธ์ธ์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.") - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "์†Œ์…œ ๋กœ๊ทธ์ธ ์„ฑ๊ณต"), - ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ"), - ApiResponse(responseCode = "409", description = "์ด๋ฏธ ๊ฐ€์ž…๋œ ์ด๋ฉ”์ผ"), - ], - ) @PostMapping suspend fun social( @RequestBody socialLoginRequest: SocialLoginRequest, diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/LoginRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/LoginRequest.kt index bf17a881..0d5ffea7 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/LoginRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/LoginRequest.kt @@ -1,11 +1,6 @@ package com.wafflestudio.spring2025.domain.auth.dto -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "๋กœ๊ทธ์ธ ์š”์ฒญ") data class LoginRequest( - @Schema(description = "์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ", example = "user@example.com", required = true) val email: String, - @Schema(description = "์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ", example = "mypassword", required = true) val password: String, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt index 470bcb7f..32ee7ed3 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt @@ -1,15 +1,8 @@ package com.wafflestudio.spring2025.domain.auth.dto -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "ํšŒ์›๊ฐ€์ž… ์š”์ฒญ") data class RegisterRequest( - @Schema(description = "์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ", example = "user@example.com", required = true) val email: String, - @Schema(description = "์‚ฌ์šฉ์ž ์ด๋ฆ„", example = "ํ™๊ธธ๋™", required = true) val name: String, - @Schema(description = "๋น„๋ฐ€๋ฒˆํ˜ธ", example = "password123", required = true) val password: String, - @Schema(description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL", example = "https://cdn.example.com/profile.png") val profileImage: String? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SignupRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SignupRequest.kt index 94c273ff..53618934 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SignupRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SignupRequest.kt @@ -1,15 +1,8 @@ package com.wafflestudio.spring2025.domain.auth.dto -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "ํšŒ์›๊ฐ€์ž… ์š”์ฒญ") data class SignupRequest( - @Schema(description = "์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ", example = "user@example.com", required = true) val email: String, - @Schema(description = "์‚ฌ์šฉ์ž ์ด๋ฆ„", example = "ํ™๊ธธ๋™", required = true) val name: String, - @Schema(description = "๋น„๋ฐ€๋ฒˆํ˜ธ", example = "password123", required = true) val password: String, - @Schema(description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL", example = "https://cdn.example.com/profile.png") val profileImage: String? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SocialLoginRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SocialLoginRequest.kt index f83e60f3..28fc2bad 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SocialLoginRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SocialLoginRequest.kt @@ -1,11 +1,6 @@ package com.wafflestudio.spring2025.domain.auth.dto -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "์†Œ์…œ ๋กœ๊ทธ์ธ ์š”์ฒญ") data class SocialLoginRequest( - @Schema(description = "์†Œ์…œ๋กœ๊ทธ์ธ ์ œ๊ณต์ž", example = "GOOGLE", required = true) val provider: String, - @Schema(description = "์ธ๊ฐ€ ์ฝ”๋“œ (authorization code)", required = true) val code: String, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/controller/EventController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/controller/EventController.kt index 7ba5fae8..7e1a9de5 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/controller/EventController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/controller/EventController.kt @@ -10,8 +10,6 @@ import com.wafflestudio.spring2025.domain.event.dto.response.MyEventsInfiniteRes import com.wafflestudio.spring2025.domain.event.dto.response.UpdateEventResponse import com.wafflestudio.spring2025.domain.event.service.EventService import com.wafflestudio.spring2025.domain.user.model.User -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping @@ -26,12 +24,10 @@ import java.time.Instant @RestController @RequestMapping("/api/events") -@Tag(name = "Event", description = "์ด๋ฒคํŠธ ๊ด€๋ฆฌ API") class EventController( private val eventService: EventService, ) { @AuthRequired - @Operation(summary = "์ด๋ฒคํŠธ ์ƒ์„ฑ", description = "์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค") @PostMapping // POST /api/events fun create( @LoggedInUser user: User, @@ -54,7 +50,6 @@ class EventController( return ResponseEntity.ok(CreateEventResponse(publicId)) } - @Operation(summary = "์ด๋ฒคํŠธ ์ƒ์„ธ ์กฐํšŒ", description = "์ด๋ฒคํŠธ ์ƒ์„ธ ์ •๋ณด๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค") @GetMapping("/{publicId}") // GET /api/events/{publicId} fun getById( @LoggedInUser user: User?, // nullable @@ -69,10 +64,6 @@ class EventController( } @AuthRequired - @Operation( - summary = "๋‚ด๊ฐ€ ๋งŒ๋“  ์ด๋ฒคํŠธ ๋ชฉ๋ก ์กฐํšŒ (๋ฌดํ•œ ์Šคํฌ๋กค)", - description = "๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ์„ฑํ•œ ์ด๋ฒคํŠธ ๋ชฉ๋ก์„ ๋ฌดํ•œ ์Šคํฌ๋กค ๋ฐฉ์‹(cursor)์œผ๋กœ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค", - ) @GetMapping("/me") fun getMyEvents( @LoggedInUser user: User, @@ -89,7 +80,6 @@ class EventController( } @AuthRequired - @Operation(summary = "์ด๋ฒคํŠธ ์ˆ˜์ •", description = "์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค") @PutMapping("/{publicId}") // PUT /api/events/{publicId} fun update( @LoggedInUser user: User, @@ -116,7 +106,6 @@ class EventController( } @AuthRequired - @Operation(summary = "์ด๋ฒคํŠธ ์‚ญ์ œ", description = "์ด๋ฒคํŠธ๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค") @DeleteMapping("/{publicId}") // DELETE /api/events/{publicId} fun delete( @LoggedInUser user: User, diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/core/EventDto.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/core/EventDto.kt index 2b4765a2..778ea5ca 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/core/EventDto.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/core/EventDto.kt @@ -1,35 +1,20 @@ package com.wafflestudio.spring2025.domain.event.dto.core import com.wafflestudio.spring2025.domain.event.model.Event -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ผ์ • ์ •๋ณด") data class EventDto( - @Schema(description = "์ผ์ • ID (publicId)") val id: String, - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ") val title: String, - @Schema(description = "์ด๋ฒคํŠธ ์„ค๋ช…") val description: String?, - @Schema(description = "์žฅ์†Œ") val location: String?, - @Schema(description = "์‹œ์ž‘ ์‹œ๊ฐ„ (epoch milliseconds)") val startsAt: Long?, - @Schema(description = "์ข…๋ฃŒ ์‹œ๊ฐ„ (epoch milliseconds)") val endsAt: Long?, - @Schema(description = "์ •์›") val capacity: Int?, - @Schema(description = "๋Œ€๊ธฐ ๋ช…๋‹จ ์‚ฌ์šฉ ์—ฌ๋ถ€") val waitlistEnabled: Boolean, - @Schema(description = "์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (epoch milliseconds)") val registrationStartsAt: Long?, - @Schema(description = "์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (epoch milliseconds)") val registrationEndsAt: Long, - @Schema(description = "์ž‘์„ฑ์ž ID") val createdBy: Long, - @Schema(description = "์ƒ์„ฑ ์ผ์‹œ (epoch milliseconds)") val createdAt: Long?, - @Schema(description = "์ˆ˜์ • ์ผ์‹œ (epoch milliseconds)") val updatedAt: Long?, ) { constructor(event: Event) : this( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/CreateEventRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/CreateEventRequest.kt index db6254ca..1c46a314 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/CreateEventRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/CreateEventRequest.kt @@ -1,38 +1,15 @@ package com.wafflestudio.spring2025.domain.event.dto.request -import io.swagger.v3.oas.annotations.media.Schema import java.time.Instant -@Schema(description = "์ผ์ • ์ƒ์„ฑ ์š”์ฒญ") data class CreateEventRequest( - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ", example = "์ •๊ธฐ ๋ชจ์ž„") val title: String, - @Schema(description = "์ด๋ฒคํŠธ ์„ค๋ช…", example = "์ •๊ธฐ ๋ชจ์ž„์ž…๋‹ˆ๋‹ค") val description: String? = null, - @Schema(description = "์žฅ์†Œ", example = "๊ฐ•์˜์‹ค 101") val location: String? = null, - @Schema( - description = "์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T18:00:00Z", - ) val startsAt: Instant? = null, - @Schema( - description = "์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T20:00:00Z", - ) val endsAt: Instant? = null, - @Schema(description = "์ •์›", example = "30") val capacity: Int, - @Schema(description = "๋Œ€๊ธฐ ๋ช…๋‹จ ์‚ฌ์šฉ ์—ฌ๋ถ€", example = "true") val waitlistEnabled: Boolean, - @Schema( - description = "์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601). null์ธ ๊ฒฝ์šฐ ์š”์ฒญ ์‹œ์ ์œผ๋กœ ์ž๋™ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.", - example = "2026-02-02T17:00:00Z", - ) val registrationStartsAt: Instant? = null, - @Schema( - description = "์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T17:30:00Z", - ) val registrationEndsAt: Instant, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/UpdateEventRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/UpdateEventRequest.kt index e237b56c..2206d5c5 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/UpdateEventRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/UpdateEventRequest.kt @@ -1,38 +1,15 @@ package com.wafflestudio.spring2025.domain.event.dto.request -import io.swagger.v3.oas.annotations.media.Schema import java.time.Instant -@Schema(description = "์ผ์ • ์ˆ˜์ • ์š”์ฒญ") data class UpdateEventRequest( - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ", example = "์ •๊ธฐ ๋ชจ์ž„") val title: String? = null, - @Schema(description = "์ด๋ฒคํŠธ ์„ค๋ช…", example = "์ •๊ธฐ ๋ชจ์ž„์ž…๋‹ˆ๋‹ค") val description: String? = null, - @Schema(description = "์žฅ์†Œ", example = "๊ฐ•์˜์‹ค 101") val location: String? = null, - @Schema( - description = "์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T18:00:00Z", - ) val startsAt: Instant? = null, - @Schema( - description = "์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T20:00:00Z", - ) val endsAt: Instant? = null, - @Schema(description = "์ •์›", example = "30") val capacity: Int? = null, - @Schema(description = "๋Œ€๊ธฐ ๋ช…๋‹จ ์‚ฌ์šฉ ์—ฌ๋ถ€", example = "true") val waitlistEnabled: Boolean? = null, - @Schema( - description = "์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T17:00:00Z", - ) val registrationStartsAt: Instant? = null, - @Schema( - description = "์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T17:30:00Z", - ) val registrationEndsAt: Instant? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/EventDetailResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/EventDetailResponse.kt index 08d7cccd..4456f298 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/EventDetailResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/EventDetailResponse.kt @@ -1,97 +1,45 @@ package com.wafflestudio.spring2025.domain.event.dto.response -import io.swagger.v3.oas.annotations.media.Schema import java.time.Instant -@Schema(description = "์ผ์ • ์ƒ์„ธ ์กฐํšŒ ์‘๋‹ต") data class EventDetailResponse( - @Schema(description = "์ด๋ฒคํŠธ ์ •๋ณด") val event: EventInfo, - @Schema(description = "์ด๋ฒคํŠธ ์ƒ์„ฑ์ž ์ •๋ณด") val creator: CreatorInfo, - @Schema(description = "์กฐํšŒ์ž(viewer) ์ •๋ณด") val viewer: ViewerInfo, - @Schema(description = "์กฐํšŒ์ž๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๋™์ž‘") val capabilities: CapabilitiesInfo, - @Schema(description = "์ฐธ์—ฌ์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ชฉ๋ก") val guestsPreview: List, ) -@Schema(description = "์ด๋ฒคํŠธ ์ •๋ณด ๋ธ”๋ก") data class EventInfo( - @Schema(description = "์ด๋ฒคํŠธ publicId", example = "dj8sadj10djnkas") val publicId: String, - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ", example = "์ œ2ํšŒ ๊ธฐํš ์„ธ๋ฏธ๋‚˜") val title: String, - @Schema(description = "์ด๋ฒคํŠธ ์„ค๋ช…", example = "์ผ์ • ์ƒ์„ธ ์„ค๋ช…...", nullable = true) val description: String?, - @Schema(description = "์žฅ์†Œ", example = "์„œ์šธ๋Œ€", nullable = true) val location: String?, - @Schema(description = "์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)", example = "2026-02-02T18:00:00Z", nullable = true) val startsAt: Instant?, - @Schema(description = "์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601)", example = "2026-02-02T20:00:00Z", nullable = true) val endsAt: Instant?, - @Schema(description = "์ •์›", example = "10", nullable = true) val capacity: Int?, - @Schema(description = "์ด ์‹ ์ฒญ์ž ์ˆ˜(ํ™•์ •+๋Œ€๊ธฐ ๋“ฑ)", example = "8") val totalApplicants: Int, - @Schema(description = "์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)", example = "2026-02-02T17:00:00Z", nullable = true) val registrationStartsAt: Instant?, - @Schema(description = "์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601)", example = "2026-02-02T17:00:00Z") val registrationEndsAt: Instant, ) -@Schema(description = "์ƒ์„ฑ์ž ์ •๋ณด ๋ธ”๋ก") data class CreatorInfo( - @Schema(description = "์ด๋ฆ„", example = "ํ™๊ธธ๋™") val name: String, - @Schema(description = "์ด๋ฉ”์ผ", example = "user@example.com") val email: String, - @Schema(description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€", example = "https://example.com/profile.png", nullable = true) val profileImage: String?, ) -@Schema(description = "์กฐํšŒ์ž(viewer) ์ •๋ณด ๋ธ”๋ก") data class ViewerInfo( - @Schema( - description = "viewer์˜ ๋“ฑ๋ก ์ƒํƒœ (RegistrationStatus ์‚ฌ์šฉ)", - example = "WAITLISTED", - ) val status: ViewerStatus, - @Schema( - description = "viewer ์ด๋ฆ„ (๋น„ํšŒ์›์ด๋ฉด null)", - example = "ํ™๊ธธ๋™", - nullable = true, - ) val name: String?, - @Schema( - description = "๋Œ€๊ธฐ ์ˆœ๋ฒˆ (WAITLISTED์ผ ๋•Œ๋งŒ ์ˆซ์ž, ์•„๋‹ˆ๋ฉด null)", - example = "3", - nullable = true, - ) val waitlistPosition: Int?, - @Schema( - description = "registrationPublicId (๊ฒŒ์ŠคํŠธ๋ฉด ๊ฐ’, ์•„๋‹ˆ๋ฉด null)", - example = "1", - nullable = true, - ) val registrationPublicId: String?, - @Schema( - description = "์˜ˆ์•ฝ ์ด๋ฉ”์ผ(๊ฒŒ์ŠคํŠธ๋ฉด guestEmail, ๋กœ๊ทธ์ธ ์œ ์ €๋ฉด user email ๋“ฑ ์ •์ฑ…์— ๋”ฐ๋ฆ„)", - example = "skdfsj@gmaldkl", - nullable = true, - ) val reservationEmail: String?, ) -@Schema(description = "๊ฐ€๋Šฅํ•œ ๋™์ž‘ ๋ธ”๋ก") data class CapabilitiesInfo( - @Schema(description = "๊ณต์œ  ๋งํฌ ๊ฐ€๋Šฅ ์—ฌ๋ถ€", example = "false") val shareLink: Boolean, - @Schema(description = "์ฐธ์—ฌ ์‹ ์ฒญ ๊ฐ€๋Šฅ ์—ฌ๋ถ€(ํ™•์ • ์ž๋ฆฌ ์‹ ์ฒญ)", example = "false") val apply: Boolean, - @Schema(description = "๋Œ€๊ธฐ ์‹ ์ฒญ ๊ฐ€๋Šฅ ์—ฌ๋ถ€(์ •์› ์ฐผ์„ ๋•Œ)", example = "false") val wait: Boolean, - @Schema(description = "์‹ ์ฒญ ์ทจ์†Œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€", example = "true") val cancel: Boolean, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/GuestPreview.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/GuestPreview.kt index 01781f48..2f3314a7 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/GuestPreview.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/GuestPreview.kt @@ -1,21 +1,11 @@ package com.wafflestudio.spring2025.domain.event.dto.response -import io.swagger.v3.oas.annotations.media.Schema - /** * ์ด๋ฒคํŠธ ์ฐธ์—ฌ์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ •๋ณด * (ํšŒ์›/๋น„ํšŒ์› ํฌํ•จ) */ -@Schema(description = "์ฐธ์—ฌ์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ •๋ณด") data class GuestPreview( - @Schema(description = "์ฐธ์—ฌ์ž ID (๋น„ํšŒ์›์ด๋ฉด null)", example = "1", nullable = true) val id: Long?, - @Schema(description = "์ฐธ์—ฌ์ž ์ด๋ฆ„", example = "ํ™๊ธธ๋™") val name: String, - @Schema( - description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL", - example = "https://example.com/profile.png", - nullable = true, - ) val profileImage: String?, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/MyRole.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/MyRole.kt index d1a8b89a..c06024ed 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/MyRole.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/MyRole.kt @@ -1,21 +1,15 @@ package com.wafflestudio.spring2025.domain.event.dto.response -import io.swagger.v3.oas.annotations.media.Schema - /** * ์š”์ฒญ์ž ์—ญํ•  * - CREATOR: ์ด๋ฒคํŠธ ์ƒ์„ฑ์ž * - PARTICIPANT: ์ด๋ฒคํŠธ ์ฐธ์—ฌ์ž (CONFIRMED / WAITLISTED) * - NONE: ๋กœ๊ทธ์ธ์€ ํ–ˆ์ง€๋งŒ ์ฐธ์—ฌํ•˜์ง€ ์•Š์Œ */ -@Schema(description = "์š”์ฒญ์ž ์—ญํ• ") enum class MyRole { - @Schema(description = "์ด๋ฒคํŠธ ์ƒ์„ฑ์ž") CREATOR, - @Schema(description = "์ด๋ฒคํŠธ ์ฐธ์—ฌ์ž") PARTICIPANT, - @Schema(description = "์ด๋ฒคํŠธ ๋ฏธ์ฐธ์—ฌ์ž") NONE, } diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/ViewerStatus.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/ViewerStatus.kt index a250a6db..d85fe72a 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/ViewerStatus.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/ViewerStatus.kt @@ -1,25 +1,17 @@ package com.wafflestudio.spring2025.domain.event.dto.response -import io.swagger.v3.oas.annotations.media.Schema - /** * ์ด๋ฒคํŠธ ์ƒ์„ธ ์กฐํšŒ ์‹œ, * "viewer(์š”์ฒญ์ž)"๊ฐ€ ํ•ด๋‹น ์ด๋ฒคํŠธ์™€ ์–ด๋–ค ๊ด€๊ณ„์— ์žˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ƒํƒœ */ -@Schema(description = "์ด๋ฒคํŠธ ์กฐํšŒ์ž(Viewer)์˜ ์ƒํƒœ") enum class ViewerStatus { - @Schema(description = "์ด๋ฒคํŠธ ์ƒ์„ฑ์ž") HOST, - @Schema(description = "์ฐธ์—ฌ ํ™•์ •๋œ ์‚ฌ์šฉ์ž") CONFIRMED, - @Schema(description = "๋Œ€๊ธฐ ์ค‘์ธ ์‚ฌ์šฉ์ž") WAITLISTED, - @Schema(description = "๊ฐ•์ œ ์ทจ์†Œ(์ฐจ๋‹จ)๋œ ์‚ฌ์šฉ์ž") BANNED, - @Schema(description = "์ด๋ฒคํŠธ์™€ ์•„๋ฌด ๊ด€๊ณ„ ์—†๋Š” ์‚ฌ์šฉ์ž") NONE, } diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/EventRegistrationController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/EventRegistrationController.kt index 4fb815e9..213bc67d 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/EventRegistrationController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/EventRegistrationController.kt @@ -6,11 +6,6 @@ import com.wafflestudio.spring2025.domain.registration.dto.response.CreateRegist import com.wafflestudio.spring2025.domain.registration.dto.response.GetEventRegistrationsResponse import com.wafflestudio.spring2025.domain.registration.service.RegistrationService import com.wafflestudio.spring2025.domain.user.model.User -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 @@ -22,35 +17,9 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/api/events/{eventId}/registrations") -@Tag(name = "Registration", description = "์ด๋ฒคํŠธ ๊ธฐ์ค€ ์‹ ์ฒญ API") class EventRegistrationController( private val registrationService: RegistrationService, ) { - @Operation( - summary = "์ด๋ฒคํŠธ ์ฐธ์—ฌ ์‹ ์ฒญ", - description = - "ํŠน์ • ์ด๋ฒคํŠธ์— ์‹ ์ฒญํ•ฉ๋‹ˆ๋‹ค. ์ •์›์ด ๋‚จ์•„์žˆ์œผ๋ฉด CONFIRMED๋กœ ๋“ฑ๋ก๋˜๊ณ , ์ •์›์ด ์ฐผ์œผ๋‚˜ ๋Œ€๊ธฐ ๋ช…๋‹จ์ด ํ—ˆ์šฉ๋œ ๊ฒฝ์šฐ WAITLISTED๋กœ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค. " + - "์ •์›์ด ์ฐผ๊ณ  ๋Œ€๊ธฐ ๋ช…๋‹จ์ด ๋น„ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ ์‹ ์ฒญ์ด ๊ฑฐ์ ˆ๋ฉ๋‹ˆ๋‹ค.", - ) - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "์‹ ์ฒญ ์„ฑ๊ณต"), - ApiResponse( - responseCode = "400", - description = - "์œ ํšจํ•˜์ง€ ์•Š์€ ์š”์ฒญ: 3003(Wrong guest name), 3004(Wrong guest email), 2204(Invalid registration window)", - ), - ApiResponse( - responseCode = "403", - description = "๊ถŒํ•œ ์—†์Œ: 3006(Banned user cannot register)", - ), - ApiResponse(responseCode = "404", description = "์ด๋ฒคํŠธ ์—†์Œ: 2001(Event not found)"), - ApiResponse( - responseCode = "409", - description = "์‹ ์ฒญ ๋ถˆ๊ฐ€: 3001(Registration already exists), 3005(Host cannot register), 2301(Event is full)", - ), - ], - ) @PostMapping fun create( @PathVariable eventId: String, @@ -67,17 +36,12 @@ class EventRegistrationController( return ResponseEntity.ok(registration) } - @Operation( - summary = "์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ", - description = "ํŠน์ • ์ด๋ฒคํŠธ์— ์†ํ•œ ์‹ ์ฒญ ๋ชฉ๋ก์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ์‹ ์ฒญ ์ƒํƒœ(CONFIRMED/WAITLISTED/BANNED)์™€ ์‹ ์ฒญ ์‹œ๊ฐ์„ ํฌํ•จํ•ด ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.", - ) @GetMapping fun list( @PathVariable eventId: String, @LoggedInUser user: User?, @RequestParam(required = false) status: String?, @RequestParam(required = false) orderBy: String?, - @Parameter(description = "๋‹ค์Œ ํŽ˜์ด์ง€ ์‹œ์ž‘ offset (์—†์œผ๋ฉด 0๋ถ€ํ„ฐ)") @RequestParam(required = false) cursor: Int?, ): ResponseEntity = ResponseEntity.ok( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/MyRegistrationController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/MyRegistrationController.kt index 6da5b2c9..71022123 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/MyRegistrationController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/MyRegistrationController.kt @@ -5,9 +5,6 @@ import com.wafflestudio.spring2025.domain.auth.LoggedInUser import com.wafflestudio.spring2025.domain.registration.dto.response.GetMyRegistrationsResponse import com.wafflestudio.spring2025.domain.registration.service.RegistrationService import com.wafflestudio.spring2025.domain.user.model.User -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.Parameter -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.RequestMapping @@ -17,17 +14,12 @@ import org.springframework.web.bind.annotation.RestController @AuthRequired @RestController @RequestMapping("/api/registrations") -@Tag(name = "Registration", description = "๋‚ด ์‹ ์ฒญ ์กฐํšŒ API") class MyRegistrationController( private val registrationService: RegistrationService, ) { - @Operation( - summary = "๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ", - description = "๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ์ตœ์‹  ์‹ ์ฒญ ์ˆœ์œผ๋กœ ๋ฐ˜ํ™˜๋˜๋ฉฐ page/size๋กœ ํŽ˜์ด์ง•ํ•ฉ๋‹ˆ๋‹ค.", - ) @GetMapping("/me") fun myRegistrations( - @Parameter(hidden = true) @LoggedInUser user: User, + @LoggedInUser user: User, @RequestParam(defaultValue = "0") page: Int, @RequestParam(defaultValue = "20") size: Int, ): ResponseEntity { diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt index 2ffccbe6..f2568d12 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt @@ -10,8 +10,6 @@ import com.wafflestudio.spring2025.domain.registration.exception.RegistrationErr import com.wafflestudio.spring2025.domain.registration.exception.RegistrationValidationException import com.wafflestudio.spring2025.domain.registration.service.RegistrationService import com.wafflestudio.spring2025.domain.user.model.User -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping @@ -23,16 +21,9 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/api/registrations/{registrationId}") -@Tag(name = "Registration", description = "์‹ ์ฒญ ๋‹จ๊ฑด ๋ฆฌ์†Œ์Šค API") class RegistrationController( private val registrationService: RegistrationService, ) { - @Operation( - summary = "์‹ ์ฒญ ๋‹จ๊ฑด ์ƒํƒœ ๋ณ€๊ฒฝ", - description = - "์‹ ์ฒญ ๋‹จ๊ฑด ๋ฆฌ์†Œ์Šค์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. " + - "์‚ฌ์šฉ์ž๊ฐ€ ๋ณธ์ธ์˜ ์‹ ์ฒญ์„ ์ทจ์†Œํ•˜๋Š” ๊ฒฝ์šฐ์™€ ๊ด€๋ฆฌ์ž๊ฐ€ ๊ฐ•์ œ ์ทจ์†Œ/๋ฐด ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๋กœ์ง ๋ ˆ๋ฒจ์—์„œ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.", - ) @PatchMapping fun updateStatus( @PathVariable registrationId: String, @@ -45,11 +36,6 @@ class RegistrationController( return ResponseEntity.ok(response) } - @Operation( - summary = "์‹ ์ฒญ ๋‹จ๊ฑด ์ •๋ณด ์š”์ฒญ", - description = - "์‹ ์ฒญ ๋‹จ๊ฑด์˜ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.", - ) @GetMapping fun getRegistrationInformation( @PathVariable registrationId: String, diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationDto.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationDto.kt index e6764f91..33f1410e 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationDto.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationDto.kt @@ -2,23 +2,14 @@ package com.wafflestudio.spring2025.domain.registration.dto.core import com.wafflestudio.spring2025.domain.registration.model.Registration import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์ •๋ณด") data class RegistrationDto( - @Schema(description = "์‹ ์ฒญ ๊ณต๊ฐœ ID") val registrationPublicId: String, - @Schema(description = "์‚ฌ์šฉ์ž ID") val userId: Long?, - @Schema(description = "์ด๋ฒคํŠธ ID") val eventId: Long, - @Schema(description = "๋น„ํšŒ์› ์ด๋ฆ„") val guestName: String?, - @Schema(description = "๋น„ํšŒ์› ์ด๋ฉ”์ผ") val guestEmail: String?, - @Schema(description = "์‹ ์ฒญ ์ƒํƒœ") val status: RegistrationStatus, - @Schema(description = "์‹ ์ฒญ ์ผ์‹œ (epoch milliseconds)") val createdAt: Long, ) { constructor(registration: Registration) : this( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationWithEventDto.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationWithEventDto.kt index 5255eb9e..70c08a66 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationWithEventDto.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationWithEventDto.kt @@ -2,13 +2,9 @@ package com.wafflestudio.spring2025.domain.registration.dto.core import com.wafflestudio.spring2025.domain.event.model.Event import com.wafflestudio.spring2025.domain.registration.model.Registration -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ์ •๋ณด") data class RegistrationWithEventDto( - @Schema(description = "์‹ ์ฒญ ์ •๋ณด") val registration: RegistrationDto, - @Schema(description = "์ด๋ฒคํŠธ ์š”์•ฝ ์ •๋ณด") val event: EventSummaryDto, ) { constructor(registration: Registration, event: Event) : this( @@ -17,17 +13,11 @@ data class RegistrationWithEventDto( ) } -@Schema(description = "์ด๋ฒคํŠธ ์š”์•ฝ ์ •๋ณด") data class EventSummaryDto( - @Schema(description = "์ด๋ฒคํŠธ ID") val id: Long, - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ") val title: String, - @Schema(description = "์žฅ์†Œ") val location: String?, - @Schema(description = "์‹œ์ž‘ ์‹œ๊ฐ„ (epoch milliseconds)") val startsAt: Long?, - @Schema(description = "์ข…๋ฃŒ ์‹œ๊ฐ„ (epoch milliseconds)") val endsAt: Long?, ) { constructor(event: Event) : this( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/CreateRegistrationRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/CreateRegistrationRequest.kt index baf7052f..820bd1e5 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/CreateRegistrationRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/CreateRegistrationRequest.kt @@ -1,14 +1,10 @@ package com.wafflestudio.spring2025.domain.registration.dto.request import com.fasterxml.jackson.annotation.JsonAlias -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์š”์ฒญ") data class CreateRegistrationRequest( - @Schema(description = "๋น„ํšŒ์› ์ด๋ฆ„") @JsonAlias("guest_name") val guestName: String? = null, - @Schema(description = "๋น„ํšŒ์› ์ด๋ฉ”์ผ") @JsonAlias("guest_email") val guestEmail: String? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt index 3f34c5f8..0df46b98 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt @@ -1,11 +1,6 @@ package com.wafflestudio.spring2025.domain.registration.dto.request -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "์ด๋ฒคํŠธ ์ทจ์†Œ ์š”์ฒญ") data class DeleteRegistrationRequest( - @Schema(description = "๋น„ํšŒ์› ์ด๋ฆ„") val guestName: String? = null, - @Schema(description = "๋น„ํšŒ์› ์ด๋ฉ”์ผ") val guestEmail: String? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/UpdateRegistrationStatusRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/UpdateRegistrationStatusRequest.kt index f87d15fb..2182cddc 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/UpdateRegistrationStatusRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/UpdateRegistrationStatusRequest.kt @@ -1,9 +1,7 @@ package com.wafflestudio.spring2025.domain.registration.dto.request import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์ƒํƒœ ๋ณ€๊ฒฝ ์š”์ฒญ") data class UpdateRegistrationStatusRequest( val status: RegistrationStatus? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/CreateRegistrationResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/CreateRegistrationResponse.kt index eb4ea566..3abe25e8 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/CreateRegistrationResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/CreateRegistrationResponse.kt @@ -1,9 +1,5 @@ package com.wafflestudio.spring2025.domain.registration.dto.response -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์‘๋‹ต") data class CreateRegistrationResponse( - @Schema(description = "์‹ ์ฒญ id") val registrationPublicId: String, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetEventRegistrationsResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetEventRegistrationsResponse.kt index 39a7951b..c5837bd2 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetEventRegistrationsResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetEventRegistrationsResponse.kt @@ -3,36 +3,22 @@ package com.wafflestudio.spring2025.domain.registration.dto.response import com.wafflestudio.spring2025.domain.registration.model.Registration import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus import com.wafflestudio.spring2025.domain.user.model.User -import io.swagger.v3.oas.annotations.media.Schema import java.time.Instant -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ ์‘๋‹ต") data class GetEventRegistrationsResponse( - @Schema(description = "์‹ ์ฒญ์ž ๋ชฉ๋ก") val participants: List, - @Schema(description = "ํ•„ํ„ฐ์— ๋”ฐ๋ผ ๋ณ€ํ•˜๋Š” ์ฐธ์—ฌ์ž ์ˆ˜") val totalCount: Int?, - @Schema(description = "๋‹ค์Œ ํŽ˜์ด์ง€ ์‹œ์ž‘ offset (์—†์œผ๋ฉด null)") val nextCursor: Int?, - @Schema(description = "๋‹ค์Œ ํŽ˜์ด์ง€ ์กด์žฌ ์—ฌ๋ถ€") val hasNext: Boolean, ) -@Schema(description = "์‹ ์ฒญ์ž ์ •๋ณด") data class EventRegistrationItem( - @Schema(description = "์‹ ์ฒญ ๊ณต๊ฐœ ID") val registrationId: String, - @Schema(description = "์ด๋ฆ„") val name: String, - @Schema(description = "์ด๋ฉ”์ผ (๊ด€๋ฆฌ์ž ์š”์ฒญ ์‹œ ๋…ธ์ถœ)") val email: String?, - @Schema(description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL") val profileImage: String?, - @Schema(description = "์‹ ์ฒญ ์ผ์‹œ") val createdAt: Instant, - @Schema(description = "์‹ ์ฒญ ์ƒํƒœ") val status: RegistrationStatus, - @Schema(description = "๋Œ€๊ธฐ ์ˆœ๋ฒˆ (status๊ฐ€ WAITLISTED์ผ ๋•Œ๋งŒ ์•„๋‹ˆ๋ฉด null)") val waitingNum: Int?, ) { constructor( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt index 74c36966..5c597315 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt @@ -3,36 +3,22 @@ package com.wafflestudio.spring2025.domain.registration.dto.response import com.wafflestudio.spring2025.domain.event.model.Event import com.wafflestudio.spring2025.domain.registration.model.Registration import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus -import io.swagger.v3.oas.annotations.media.Schema import java.time.Instant -@Schema(description = "๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์‘๋‹ต") data class GetMyRegistrationsResponse( - @Schema(description = "์‹ ์ฒญ ๋ชฉ๋ก") val registrations: List, ) -@Schema(description = "๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ์š”์•ฝ") data class MyRegistrationItem( - @Schema(description = "์ด๋ฒคํŠธ ๊ณต๊ฐœ ID") val publicId: String, - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ") val title: String, - @Schema(description = "์ด๋ฒคํŠธ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)") val startsAt: Instant?, - @Schema(description = "์ด๋ฒคํŠธ ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601)") val endsAt: Instant?, - @Schema(description = "์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)") val registrationStartsAt: Instant?, - @Schema(description = "์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601)") val registrationEndsAt: Instant?, - @Schema(description = "์ •์›") val capacity: Int?, - @Schema(description = "ํ˜„์žฌ ์‹ ์ฒญ ์ˆ˜ + ๋Œ€๊ธฐ ์ˆ˜") val registrationCnt: Int, - @Schema(description = "์‹ ์ฒญ ์ƒํƒœ") val status: MyRegistrationStatus, - @Schema(description = "๋Œ€๊ธฐ ์ˆœ๋ฒˆ (WAITLISTED๊ฐ€ ์•„๋‹ˆ๋ฉด null)") val waitlistedNum: Int?, ) { constructor( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetRegistrationResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetRegistrationResponse.kt index e03dd30c..d241cd32 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetRegistrationResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetRegistrationResponse.kt @@ -1,9 +1,7 @@ package com.wafflestudio.spring2025.domain.registration.dto.response import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์ •๋ณด ์š”์ฒญ ์‘๋‹ต") data class GetRegistrationResponse( val status: RegistrationStatus, val guestName: String, diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/PatchRegistrationResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/PatchRegistrationResponse.kt index 5f8f534a..e328c6db 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/PatchRegistrationResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/PatchRegistrationResponse.kt @@ -1,8 +1,5 @@ package com.wafflestudio.spring2025.domain.registration.dto.response -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์ƒํƒœ ๋ณ€๊ฒฝ") data class PatchRegistrationResponse( val patchEmail: String? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/RegistrationGuestsResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/RegistrationGuestsResponse.kt index 5d0d0855..fe52c458 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/RegistrationGuestsResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/RegistrationGuestsResponse.kt @@ -1,29 +1,19 @@ package com.wafflestudio.spring2025.domain.registration.dto.response import com.fasterxml.jackson.annotation.JsonProperty -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ด๋ฒคํŠธ ์ฐธ์—ฌ์ž ๋ช…๋‹จ ์‘๋‹ต") data class RegistrationGuestsResponse( - @Schema(description = "ํ™•์ • ์ฐธ์—ฌ์ž ๋ชฉ๋ก") val guests: List, @JsonProperty("confirmed_count") - @Schema(description = "ํ™•์ • ์ฐธ์—ฌ์ž ์ˆ˜") val confirmedCount: Int, @JsonProperty("waiting_count") - @Schema(description = "๋Œ€๊ธฐ ์ฐธ์—ฌ์ž ์ˆ˜") val waitingCount: Int, ) { - @Schema(description = "์ฐธ์—ฌ์ž ์ •๋ณด") data class Guest( - @Schema(description = "์‹ ์ฒญ ๊ณต๊ฐœ ID") val registrationPublicId: String, - @Schema(description = "์ด๋ฆ„") val name: String, - @Schema(description = "์ด๋ฉ”์ผ (๊ด€๋ฆฌ์ž ์š”์ฒญ ์‹œ ๋…ธ์ถœ)") val email: String?, @JsonProperty("profile_image") - @Schema(description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL") val profileImage: String?, ) } diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/user/controller/UserController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/user/controller/UserController.kt index 85c924bd..8f214cf1 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/user/controller/UserController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/user/controller/UserController.kt @@ -7,11 +7,6 @@ import com.wafflestudio.spring2025.domain.user.dto.PatchMeRequest import com.wafflestudio.spring2025.domain.user.dto.PatchMeResponse import com.wafflestudio.spring2025.domain.user.model.User import com.wafflestudio.spring2025.domain.user.service.UserService -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.PatchMapping @@ -22,27 +17,19 @@ import org.springframework.web.bind.annotation.RestController @AuthRequired @RestController @RequestMapping("/api/users") -@Tag(name = "User", description = "์‚ฌ์šฉ์ž API") class UserController( private val userService: UserService, ) { - @Operation(summary = "๋ณธ์ธ ์ •๋ณด ์กฐํšŒ", description = "๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค") - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ ์„ฑ๊ณต"), - ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ)"), - ], - ) @AuthRequired @GetMapping("/me") fun me( - @Parameter(hidden = true) @LoggedInUser user: User, + @LoggedInUser user: User, ): ResponseEntity = ResponseEntity.ok(userService.me(user)) @AuthRequired @PatchMapping("/me") fun patchMe( - @Parameter(hidden = true) @LoggedInUser user: User, + @LoggedInUser user: User, @RequestBody request: PatchMeRequest, ): ResponseEntity { userService.patchMe( @@ -54,41 +41,4 @@ class UserController( ) return ResponseEntity.ok(userService.me(user)) } - -// @Operation(summary = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", description = "๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œ(๊ต์ฒด)ํ•ฉ๋‹ˆ๋‹ค") -// @ApiResponses( -// value = [ -// ApiResponse(responseCode = "204", description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์„ฑ๊ณต"), -// ApiResponse(responseCode = "400", description = "์ž˜๋ชป๋œ ์š”์ฒญ (ํŒŒ์ผ ๋ˆ„๋ฝ/ํ˜•์‹ ์˜ค๋ฅ˜ ๋“ฑ)"), -// ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ)"), -// ], -// ) -// @AuthRequired -// @PutMapping( -// "/me/profile-image", -// consumes = [MediaType.MULTIPART_FORM_DATA_VALUE], -// ) -// fun uploadProfileImage( -// @Parameter(hidden = true) @LoggedInUser user: User?, -// @RequestPart("image") image: MultipartFile, -// ): ResponseEntity { -// userService.updateProfileImage(user, image) -// return ResponseEntity.noContent().build() -// } -// -// @Operation(summary = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์‚ญ์ œ", description = "๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋ฅผ ์‚ญ์ œ(๊ธฐ๋ณธ ์ด๋ฏธ์ง€๋กœ ๋ณต๊ท€)ํ•ฉ๋‹ˆ๋‹ค") -// @ApiResponses( -// value = [ -// ApiResponse(responseCode = "204", description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์‚ญ์ œ ์„ฑ๊ณต"), -// ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ)"), -// ], -// ) -// @AuthRequired -// @DeleteMapping("/me/profile-image") -// fun deleteProfileImage( -// @Parameter(hidden = true) @LoggedInUser user: User?, -// ): ResponseEntity { -// userService.deleteProfileImage(user) -// return ResponseEntity.noContent().build() -// } } diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/user/identity/dto/core/UserIdentityDto.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/user/identity/dto/core/UserIdentityDto.kt index 092180d5..1a0f9e05 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/user/identity/dto/core/UserIdentityDto.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/user/identity/dto/core/UserIdentityDto.kt @@ -1,19 +1,12 @@ package com.wafflestudio.spring2025.domain.user.identity.dto.core import com.wafflestudio.spring2025.domain.user.identity.model.UserIdentity -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์†Œ์…œ ๊ณ„์ • ์ •๋ณด") data class UserIdentityDto( - @Schema(description = "์†Œ์…œ ๊ณ„์ • ID") val id: Long, - @Schema(description = "์‚ฌ์šฉ์ž ID") val userId: Long, - @Schema(description = "์†Œ์…œ ๋กœ๊ทธ์ธ ์ œ๊ณต์ž") val provider: String, - @Schema(description = "์ œ๊ณต์ž ์‚ฌ์šฉ์ž ID") val providerUserId: String, - @Schema(description = "์ƒ์„ฑ ์ผ์‹œ (epoch milliseconds)") val createdAt: Long, ) { constructor(identity: UserIdentity) : this( diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 00626212..69f7caf8 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -95,6 +95,13 @@ aws: server: forward-headers-strategy: framework +springdoc: + api-docs: + enabled: false + swagger-ui: + url: /docs/openapi.yaml + disable-swagger-default-url: true + --- spring: config: diff --git a/src/main/resources/static/docs/openapi.yaml b/src/main/resources/static/docs/openapi.yaml new file mode 100644 index 00000000..cdfaeb8b --- /dev/null +++ b/src/main/resources/static/docs/openapi.yaml @@ -0,0 +1,1181 @@ +openapi: 3.0.1 +info: + title: Moiming - Event Schedule Management System API + description: ๋ชจ์ž„ ์ผ์ • ๊ด€๋ฆฌ ์‹œ์Šคํ…œ '๋ชจ์ด๋ฐ' API ๋ฌธ์„œ + version: "1.0" +servers: +- url: http://localhost:8080 + description: Generated server url +tags: +- name: Event + description: ์ด๋ฒคํŠธ ๊ด€๋ฆฌ API +- name: Registration + description: ์‹ ์ฒญ API +- name: Auth + description: ์ธ์ฆ API +- name: User + description: ์‚ฌ์šฉ์ž API +- name: Image + description: ์ด๋ฏธ์ง€ API +paths: + /api/events/{publicId}: + get: + tags: + - Event + summary: ์ด๋ฒคํŠธ ์ƒ์„ธ ์กฐํšŒ + description: ์ด๋ฒคํŠธ ์ƒ์„ธ ์ •๋ณด๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค + parameters: + - name: publicId + in: path + required: true + schema: + type: string + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/EventDetailResponse" + put: + tags: + - Event + summary: ์ด๋ฒคํŠธ ์ˆ˜์ • + description: ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + parameters: + - name: publicId + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateEventRequest" + required: true + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/UpdateEventResponse" + "401": + description: ์ธ์ฆ ํ•„์š” + delete: + tags: + - Event + summary: ์ด๋ฒคํŠธ ์‚ญ์ œ + description: ์ด๋ฒคํŠธ๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + parameters: + - name: publicId + in: path + required: true + schema: + type: string + responses: + "204": + description: No Content + "401": + description: ์ธ์ฆ ํ•„์š” + /api/images: + post: + tags: + - Image + summary: ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ + description: ์„œ๋ฒ„ ์ €์žฅ์†Œ์— ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. + parameters: + - name: prefix + in: query + description: ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•  ์ƒ์œ„ ๊ฒฝ๋กœ + required: false + schema: + type: string + requestBody: + content: + multipart/form-data: + schema: + required: + - image + type: object + properties: + image: + type: string + format: binary + responses: + "401": + description: ์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ) + content: + '*/*': + schema: + $ref: "#/components/schemas/ImageUploadResponse" + "200": + description: ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์„ฑ๊ณต + content: + '*/*': + schema: + $ref: "#/components/schemas/ImageUploadResponse" + "400": + description: ์ž˜๋ชป๋œ ์š”์ฒญ (ํŒŒ์ผ ๋ˆ„๋ฝ/ํ˜•์‹ ์˜ค๋ฅ˜ ๋“ฑ) + content: + '*/*': + schema: + $ref: "#/components/schemas/ImageUploadResponse" + /api/events: + post: + tags: + - Event + summary: ์ด๋ฒคํŠธ ์ƒ์„ฑ + description: ์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateEventRequest" + required: true + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateEventResponse" + "401": + description: ์ธ์ฆ ํ•„์š” + /api/events/{eventId}/registrations: + get: + tags: + - Registration + summary: ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ + description: ํŠน์ • ์ด๋ฒคํŠธ์— ์†ํ•œ ์‹ ์ฒญ ๋ชฉ๋ก์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ์‹ ์ฒญ ์ƒํƒœ(CONFIRMED/WAITLISTED/BANNED)์™€ ์‹ ์ฒญ + ์‹œ๊ฐ์„ ํฌํ•จํ•ด ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + parameters: + - name: eventId + in: path + required: true + schema: + type: string + - name: status + in: query + required: false + schema: + type: string + - name: orderBy + in: query + required: false + schema: + type: string + - name: cursor + in: query + description: ๋‹ค์Œ ํŽ˜์ด์ง€ ์‹œ์ž‘ offset (์—†์œผ๋ฉด 0๋ถ€ํ„ฐ) + required: false + schema: + type: integer + format: int32 + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/GetEventRegistrationsResponse" + post: + tags: + - Registration + summary: ์ด๋ฒคํŠธ ์ฐธ์—ฌ ์‹ ์ฒญ + description: "ํŠน์ • ์ด๋ฒคํŠธ์— ์‹ ์ฒญํ•ฉ๋‹ˆ๋‹ค. ์ •์›์ด ๋‚จ์•„์žˆ์œผ๋ฉด CONFIRMED๋กœ ๋“ฑ๋ก๋˜๊ณ , ์ •์›์ด ์ฐผ์œผ๋‚˜ ๋Œ€๊ธฐ ๋ช…๋‹จ์ด ํ—ˆ์šฉ๋œ ๊ฒฝ\ + ์šฐ WAITLISTED๋กœ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค. ์ •์›์ด ์ฐผ๊ณ  ๋Œ€๊ธฐ ๋ช…๋‹จ์ด ๋น„ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ ์‹ ์ฒญ์ด ๊ฑฐ์ ˆ๋ฉ๋‹ˆ๋‹ค." + parameters: + - name: eventId + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateRegistrationRequest" + required: true + responses: + "200": + description: ์‹ ์ฒญ ์„ฑ๊ณต + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateRegistrationResponse" + "409": + description: "์‹ ์ฒญ ๋ถˆ๊ฐ€: 3001(Registration already exists), 3005(Host cannot\ + \ register), 2301(Event is full)" + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateRegistrationResponse" + "400": + description: "์œ ํšจํ•˜์ง€ ์•Š์€ ์š”์ฒญ: 3003(Wrong guest name), 3004(Wrong guest email),\ + \ 2204(Invalid registration window)" + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateRegistrationResponse" + "403": + description: "๊ถŒํ•œ ์—†์Œ: 3006(Banned user cannot register)" + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateRegistrationResponse" + "404": + description: "์ด๋ฒคํŠธ ์—†์Œ: 2001(Event not found)" + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateRegistrationResponse" + /api/auth/social: + post: + tags: + - Auth + summary: ์†Œ์…œ ๋กœ๊ทธ์ธ + description: ์†Œ์…œ ๋กœ๊ทธ์ธ์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/SocialLoginRequest" + required: true + responses: + "200": + description: ์†Œ์…œ ๋กœ๊ทธ์ธ ์„ฑ๊ณต + content: + '*/*': + schema: + $ref: "#/components/schemas/LoginResponse" + "409": + description: ์ด๋ฏธ ๊ฐ€์ž…๋œ ์ด๋ฉ”์ผ + content: + '*/*': + schema: + $ref: "#/components/schemas/LoginResponse" + "401": + description: ์ธ์ฆ ์‹คํŒจ + content: + '*/*': + schema: + $ref: "#/components/schemas/LoginResponse" + /api/auth/signup: + post: + tags: + - Auth + summary: ์ด๋ฉ”์ผ ํšŒ์›๊ฐ€์ž… + description: ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์ธ์ฆ ์ด๋ฉ”์ผ์„ ๋ฐœ์†กํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฉ”์ผ ์ธ์ฆ ํ›„ ๊ฐ€์ž…์ด ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค. + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/SignupRequest" + required: true + responses: + "409": + description: ์ด๋ฏธ ์กด์žฌํ•˜๋Š” email + "204": + description: ์ธ์ฆ ์ด๋ฉ”์ผ ๋ฐœ์†ก ์„ฑ๊ณต + "400": + description: ์ž˜๋ชป๋œ ์š”์ฒญ (์œ ํšจํ•˜์ง€ ์•Š์€ email/password/name) + "503": + description: ์ด๋ฉ”์ผ ์„œ๋น„์Šค ์žฅ์•  + /api/auth/logout: + post: + tags: + - Auth + summary: ๋กœ๊ทธ์•„์›ƒ + description: ํ˜„์žฌ JWT ํ† ํฐ์„ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•˜์—ฌ ๋กœ๊ทธ์•„์›ƒํ•ฉ๋‹ˆ๋‹ค + responses: + "204": + description: ๋กœ๊ทธ์•„์›ƒ ์„ฑ๊ณต + /api/auth/login: + post: + tags: + - Auth + summary: ๋กœ๊ทธ์ธ + description: email๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ JWT ํ† ํฐ์„ ๋ฐœ๊ธ‰๋ฐ›์Šต๋‹ˆ๋‹ค + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/LoginRequest" + required: true + responses: + "401": + description: ์ธ์ฆ ์‹คํŒจ + content: + '*/*': + schema: + $ref: "#/components/schemas/LoginResponse" + "200": + description: "๋กœ๊ทธ์ธ ์„ฑ๊ณต, JWT ํ† ํฐ ๋ฐ˜ํ™˜" + content: + '*/*': + schema: + $ref: "#/components/schemas/LoginResponse" + /api/auth/email-verification/{verificationCode}: + post: + tags: + - Auth + summary: ์ด๋ฉ”์ผ ์ธ์ฆ + description: ์ด๋ฉ”์ผ๋กœ ๋ฐ›์€ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  ํšŒ์›๊ฐ€์ž…์„ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค + parameters: + - name: verificationCode + in: path + required: true + schema: + type: string + responses: + "400": + description: ์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋งŒ๋ฃŒ๋œ ์ธ์ฆ ์ฝ”๋“œ + "200": + description: "์ธ์ฆ ์„ฑ๊ณต, ์œ ์ € ๋“ฑ๋ก ์™„๋ฃŒ" + /api/users/me: + get: + tags: + - User + summary: ๋ณธ์ธ ์ •๋ณด ์กฐํšŒ + description: ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + responses: + "401": + description: ์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ) + content: + '*/*': + schema: + $ref: "#/components/schemas/UserDto" + "200": + description: ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ ์„ฑ๊ณต + content: + '*/*': + schema: + $ref: "#/components/schemas/UserDto" + patch: + tags: + - User + summary: ๋ณธ์ธ ์ •๋ณด ์ˆ˜์ • + description: ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PatchMeRequest" + required: true + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/UserDto" + "401": + description: ์ธ์ฆ ํ•„์š” + /api/registrations/{registrationId}: + get: + tags: + - Registration + summary: ์‹ ์ฒญ ๋‹จ๊ฑด ์ •๋ณด ์š”์ฒญ + description: ์‹ ์ฒญ ๋‹จ๊ฑด์˜ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + parameters: + - name: registrationId + in: path + required: true + schema: + type: string + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/GetRegistrationResponse" + delete: + tags: + - Registration + summary: ์‹ ์ฒญ ๋‹จ๊ฑด ์ทจ์†Œ + description: ์‹ ์ฒญ ๋‹จ๊ฑด ๋ฆฌ์†Œ์Šค๋ฅผ ์ทจ์†Œํ•ฉ๋‹ˆ๋‹ค. + parameters: + - name: registrationId + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DeleteRegistrationRequest" + required: true + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/DeleteRegistrationResponse" + patch: + tags: + - Registration + summary: ์‹ ์ฒญ ๋‹จ๊ฑด ์ƒํƒœ ๋ณ€๊ฒฝ + description: ์‹ ์ฒญ ๋‹จ๊ฑด ๋ฆฌ์†Œ์Šค์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋ณธ์ธ์˜ ์‹ ์ฒญ์„ ์ทจ์†Œํ•˜๋Š” ๊ฒฝ์šฐ์™€ ๊ด€๋ฆฌ์ž๊ฐ€ ๊ฐ•์ œ ์ทจ์†Œ/๋ฐด ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ + ๋กœ์ง ๋ ˆ๋ฒจ์—์„œ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. + parameters: + - name: registrationId + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateRegistrationStatusRequest" + required: true + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/PatchRegistrationResponse" + /api/registrations/me: + get: + tags: + - Registration + summary: ๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ + description: ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ์ตœ์‹  ์‹ ์ฒญ ์ˆœ์œผ๋กœ ๋ฐ˜ํ™˜๋˜๋ฉฐ page/size๋กœ ํŽ˜์ด์ง•ํ•ฉ๋‹ˆ๋‹ค. + security: + - bearerAuth: [] + parameters: + - name: page + in: query + required: false + schema: + type: integer + format: int32 + default: 0 + - name: size + in: query + required: false + schema: + type: integer + format: int32 + default: 20 + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/GetMyRegistrationsResponse" + "401": + description: ์ธ์ฆ ํ•„์š” + /api/events/me: + get: + tags: + - Event + summary: ๋‚ด๊ฐ€ ๋งŒ๋“  ์ด๋ฒคํŠธ ๋ชฉ๋ก ์กฐํšŒ (๋ฌดํ•œ ์Šคํฌ๋กค) + description: ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ์„ฑํ•œ ์ด๋ฒคํŠธ ๋ชฉ๋ก์„ ๋ฌดํ•œ ์Šคํฌ๋กค ๋ฐฉ์‹(cursor)์œผ๋กœ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + parameters: + - name: cursor + in: query + required: false + schema: + type: string + format: date-time + - name: size + in: query + required: false + schema: + type: integer + format: int32 + default: 5 + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/MyEventsInfiniteResponse" + "401": + description: ์ธ์ฆ ํ•„์š” +components: + schemas: + UpdateEventRequest: + type: object + properties: + title: + type: string + description: ์ด๋ฒคํŠธ ์ œ๋ชฉ + example: ์ •๊ธฐ ๋ชจ์ž„ + description: + type: string + description: ์ด๋ฒคํŠธ ์„ค๋ช… + example: ์ •๊ธฐ ๋ชจ์ž„์ž…๋‹ˆ๋‹ค + location: + type: string + description: ์žฅ์†Œ + example: ๊ฐ•์˜์‹ค 101 + startsAt: + type: string + description: ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T18:00:00Z + endsAt: + type: string + description: ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T20:00:00Z + capacity: + type: integer + description: ์ •์› + format: int32 + example: 30 + waitlistEnabled: + type: boolean + description: ๋Œ€๊ธฐ ๋ช…๋‹จ ์‚ฌ์šฉ ์—ฌ๋ถ€ + example: true + registrationStartsAt: + type: string + description: ์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T17:00:00Z + registrationEndsAt: + type: string + description: ์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T17:30:00Z + description: ์ผ์ • ์ˆ˜์ • ์š”์ฒญ + UpdateEventResponse: + required: + - registrationEndsAt + - title + - waitlistEnabled + type: object + properties: + title: + type: string + description: + type: string + location: + type: string + startsAt: + type: string + format: date-time + endsAt: + type: string + format: date-time + capacity: + type: integer + format: int32 + waitlistEnabled: + type: boolean + registrationStartsAt: + type: string + format: date-time + registrationEndsAt: + type: string + format: date-time + ImageUploadResponse: + required: + - key + - url + type: object + properties: + key: + type: string + url: + type: string + CreateEventRequest: + required: + - capacity + - registrationEndsAt + - title + - waitlistEnabled + type: object + properties: + title: + type: string + description: ์ด๋ฒคํŠธ ์ œ๋ชฉ + example: ์ •๊ธฐ ๋ชจ์ž„ + description: + type: string + description: ์ด๋ฒคํŠธ ์„ค๋ช… + example: ์ •๊ธฐ ๋ชจ์ž„์ž…๋‹ˆ๋‹ค + location: + type: string + description: ์žฅ์†Œ + example: ๊ฐ•์˜์‹ค 101 + startsAt: + type: string + description: ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T18:00:00Z + endsAt: + type: string + description: ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T20:00:00Z + capacity: + type: integer + description: ์ •์› + format: int32 + example: 30 + waitlistEnabled: + type: boolean + description: ๋Œ€๊ธฐ ๋ช…๋‹จ ์‚ฌ์šฉ ์—ฌ๋ถ€ + example: true + registrationStartsAt: + type: string + description: ์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601). null์ธ ๊ฒฝ์šฐ ์š”์ฒญ ์‹œ์ ์œผ๋กœ ์ž๋™ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. + format: date-time + example: 2026-02-02T17:00:00Z + registrationEndsAt: + type: string + description: ์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T17:30:00Z + description: ์ผ์ • ์ƒ์„ฑ ์š”์ฒญ + CreateEventResponse: + required: + - publicId + type: object + properties: + publicId: + type: string + CreateRegistrationRequest: + type: object + properties: + guestName: + type: string + description: ๋น„ํšŒ์› ์ด๋ฆ„ + guestEmail: + type: string + description: ๋น„ํšŒ์› ์ด๋ฉ”์ผ + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์š”์ฒญ + CreateRegistrationResponse: + required: + - registrationPublicId + type: object + properties: + registrationPublicId: + type: string + description: ์‹ ์ฒญ id + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์‘๋‹ต + SocialLoginRequest: + required: + - code + - provider + type: object + properties: + provider: + type: string + description: ์†Œ์…œ๋กœ๊ทธ์ธ ์ œ๊ณต์ž + example: GOOGLE + code: + type: string + description: ์ธ๊ฐ€ ์ฝ”๋“œ (authorization code) + description: ์†Œ์…œ ๋กœ๊ทธ์ธ ์š”์ฒญ + LoginResponse: + required: + - token + type: object + properties: + token: + type: string + SignupRequest: + required: + - email + - name + - password + type: object + properties: + email: + type: string + description: ์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ + example: user@example.com + name: + type: string + description: ์‚ฌ์šฉ์ž ์ด๋ฆ„ + example: ํ™๊ธธ๋™ + password: + type: string + description: ๋น„๋ฐ€๋ฒˆํ˜ธ + example: password123 + profileImage: + type: string + description: ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL + example: https://cdn.example.com/profile.png + description: ํšŒ์›๊ฐ€์ž… ์š”์ฒญ + LoginRequest: + required: + - email + - password + type: object + properties: + email: + type: string + description: ์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ + example: user@example.com + password: + type: string + description: ์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ + example: mypassword + description: ๋กœ๊ทธ์ธ ์š”์ฒญ + PatchMeRequest: + type: object + properties: + name: + type: string + email: + type: string + password: + type: string + profileImage: + type: string + UserDto: + required: + - email + - id + - name + type: object + properties: + id: + type: integer + format: int64 + email: + type: string + name: + type: string + profileImage: + type: string + UpdateRegistrationStatusRequest: + type: object + properties: + status: + type: string + enum: + - HOST + - CONFIRMED + - WAITLISTED + - BANNED + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์ƒํƒœ ๋ณ€๊ฒฝ ์š”์ฒญ + PatchRegistrationResponse: + type: object + properties: + patchEmail: + type: string + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์ƒํƒœ ๋ณ€๊ฒฝ + GetRegistrationResponse: + required: + - guestName + - registrationPublicId + - reservationEmail + - status + - waitlistPosition + type: object + properties: + status: + type: string + enum: + - HOST + - CONFIRMED + - WAITLISTED + - BANNED + guestName: + type: string + waitlistPosition: + type: integer + format: int32 + registrationPublicId: + type: string + reservationEmail: + type: string + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์ •๋ณด ์š”์ฒญ ์‘๋‹ต + GetMyRegistrationsResponse: + required: + - registrations + type: object + properties: + registrations: + type: array + description: ์‹ ์ฒญ ๋ชฉ๋ก + items: + $ref: "#/components/schemas/MyRegistrationItem" + description: ๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์‘๋‹ต + MyRegistrationItem: + required: + - publicId + - registrationCnt + - status + - title + type: object + properties: + publicId: + type: string + description: ์ด๋ฒคํŠธ ๊ณต๊ฐœ ID + title: + type: string + description: ์ด๋ฒคํŠธ ์ œ๋ชฉ + startsAt: + type: string + description: ์ด๋ฒคํŠธ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + endsAt: + type: string + description: ์ด๋ฒคํŠธ ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + registrationStartsAt: + type: string + description: ์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + registrationEndsAt: + type: string + description: ์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + capacity: + type: integer + description: ์ •์› + format: int32 + registrationCnt: + type: integer + description: ํ˜„์žฌ ์‹ ์ฒญ ์ˆ˜ + ๋Œ€๊ธฐ ์ˆ˜ + format: int32 + status: + type: string + description: ์‹ ์ฒญ ์ƒํƒœ + enum: + - CONFIRMED + - WAITLISTED + - BANNED + waitlistedNum: + type: integer + description: ๋Œ€๊ธฐ ์ˆœ๋ฒˆ (WAITLISTED๊ฐ€ ์•„๋‹ˆ๋ฉด null) + format: int32 + description: ๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ์š”์•ฝ + CapabilitiesInfo: + required: + - apply + - cancel + - shareLink + - wait + type: object + properties: + shareLink: + type: boolean + description: ๊ณต์œ  ๋งํฌ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ + example: false + apply: + type: boolean + description: ์ฐธ์—ฌ ์‹ ์ฒญ ๊ฐ€๋Šฅ ์—ฌ๋ถ€(ํ™•์ • ์ž๋ฆฌ ์‹ ์ฒญ) + example: false + wait: + type: boolean + description: ๋Œ€๊ธฐ ์‹ ์ฒญ ๊ฐ€๋Šฅ ์—ฌ๋ถ€(์ •์› ์ฐผ์„ ๋•Œ) + example: false + cancel: + type: boolean + description: ์‹ ์ฒญ ์ทจ์†Œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ + example: true + description: ๊ฐ€๋Šฅํ•œ ๋™์ž‘ ๋ธ”๋ก + CreatorInfo: + required: + - email + - name + type: object + properties: + name: + type: string + description: ์ด๋ฆ„ + example: ํ™๊ธธ๋™ + email: + type: string + description: ์ด๋ฉ”์ผ + example: user@example.com + profileImage: + type: string + description: ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ + nullable: true + example: https://example.com/profile.png + description: ์ƒ์„ฑ์ž ์ •๋ณด ๋ธ”๋ก + EventDetailResponse: + required: + - capabilities + - creator + - event + - guestsPreview + - viewer + type: object + properties: + event: + $ref: "#/components/schemas/EventInfo" + creator: + $ref: "#/components/schemas/CreatorInfo" + viewer: + $ref: "#/components/schemas/ViewerInfo" + capabilities: + $ref: "#/components/schemas/CapabilitiesInfo" + guestsPreview: + type: array + description: ์ฐธ์—ฌ์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ชฉ๋ก + items: + $ref: "#/components/schemas/GuestPreview" + description: ์ผ์ • ์ƒ์„ธ ์กฐํšŒ ์‘๋‹ต + EventInfo: + required: + - publicId + - registrationEndsAt + - title + - totalApplicants + type: object + properties: + publicId: + type: string + description: ์ด๋ฒคํŠธ publicId + example: dj8sadj10djnkas + title: + type: string + description: ์ด๋ฒคํŠธ ์ œ๋ชฉ + example: ์ œ2ํšŒ ๊ธฐํš ์„ธ๋ฏธ๋‚˜ + description: + type: string + description: ์ด๋ฒคํŠธ ์„ค๋ช… + nullable: true + example: ์ผ์ • ์ƒ์„ธ ์„ค๋ช…... + location: + type: string + description: ์žฅ์†Œ + nullable: true + example: ์„œ์šธ๋Œ€ + startsAt: + type: string + description: ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + nullable: true + example: 2026-02-02T18:00:00Z + endsAt: + type: string + description: ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + nullable: true + example: 2026-02-02T20:00:00Z + capacity: + type: integer + description: ์ •์› + format: int32 + nullable: true + example: 10 + totalApplicants: + type: integer + description: ์ด ์‹ ์ฒญ์ž ์ˆ˜(ํ™•์ •+๋Œ€๊ธฐ ๋“ฑ) + format: int32 + example: 8 + registrationStartsAt: + type: string + description: ์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + nullable: true + example: 2026-02-02T17:00:00Z + registrationEndsAt: + type: string + description: ์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T17:00:00Z + description: ์ด๋ฒคํŠธ ์ •๋ณด ๋ธ”๋ก + GuestPreview: + required: + - name + type: object + properties: + id: + type: integer + description: ์ฐธ์—ฌ์ž ID (๋น„ํšŒ์›์ด๋ฉด null) + format: int64 + nullable: true + example: 1 + name: + type: string + description: ์ฐธ์—ฌ์ž ์ด๋ฆ„ + example: ํ™๊ธธ๋™ + profileImage: + type: string + description: ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL + nullable: true + example: https://example.com/profile.png + description: ์ฐธ์—ฌ์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ •๋ณด + ViewerInfo: + required: + - status + type: object + properties: + status: + type: string + description: ์ด๋ฒคํŠธ ์กฐํšŒ์ž(Viewer)์˜ ์ƒํƒœ + example: WAITLISTED + enum: + - HOST + - CONFIRMED + - WAITLISTED + - BANNED + - NONE + name: + type: string + description: viewer ์ด๋ฆ„ (๋น„ํšŒ์›์ด๋ฉด null) + nullable: true + example: ํ™๊ธธ๋™ + waitlistPosition: + type: integer + description: "๋Œ€๊ธฐ ์ˆœ๋ฒˆ (WAITLISTED์ผ ๋•Œ๋งŒ ์ˆซ์ž, ์•„๋‹ˆ๋ฉด null)" + format: int32 + nullable: true + example: 3 + registrationPublicId: + type: string + description: "registrationPublicId (๊ฒŒ์ŠคํŠธ๋ฉด ๊ฐ’, ์•„๋‹ˆ๋ฉด null)" + nullable: true + example: "1" + reservationEmail: + type: string + description: "์˜ˆ์•ฝ ์ด๋ฉ”์ผ(๊ฒŒ์ŠคํŠธ๋ฉด guestEmail, ๋กœ๊ทธ์ธ ์œ ์ €๋ฉด user email ๋“ฑ ์ •์ฑ…์— ๋”ฐ๋ฆ„)" + nullable: true + example: skdfsj@gmaldkl + description: ์กฐํšŒ์ž(viewer) ์ •๋ณด ๋ธ”๋ก + EventRegistrationItem: + required: + - createdAt + - name + - registrationId + - status + type: object + properties: + registrationId: + type: string + description: ์‹ ์ฒญ ๊ณต๊ฐœ ID + name: + type: string + description: ์ด๋ฆ„ + email: + type: string + description: ์ด๋ฉ”์ผ (๊ด€๋ฆฌ์ž ์š”์ฒญ ์‹œ ๋…ธ์ถœ) + profileImage: + type: string + description: ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL + createdAt: + type: string + description: ์‹ ์ฒญ ์ผ์‹œ + format: date-time + status: + type: string + description: ์‹ ์ฒญ ์ƒํƒœ + enum: + - HOST + - CONFIRMED + - WAITLISTED + - BANNED + waitingNum: + type: integer + description: ๋Œ€๊ธฐ ์ˆœ๋ฒˆ (status๊ฐ€ WAITLISTED์ผ ๋•Œ๋งŒ ์•„๋‹ˆ๋ฉด null) + format: int32 + description: ์‹ ์ฒญ์ž ์ •๋ณด + GetEventRegistrationsResponse: + required: + - hasNext + - participants + type: object + properties: + participants: + type: array + description: ์‹ ์ฒญ์ž ๋ชฉ๋ก + items: + $ref: "#/components/schemas/EventRegistrationItem" + totalCount: + type: integer + description: ํ•„ํ„ฐ์— ๋”ฐ๋ผ ๋ณ€ํ•˜๋Š” ์ฐธ์—ฌ์ž ์ˆ˜ + format: int32 + nextCursor: + type: integer + description: ๋‹ค์Œ ํŽ˜์ด์ง€ ์‹œ์ž‘ offset (์—†์œผ๋ฉด null) + format: int32 + hasNext: + type: boolean + description: ๋‹ค์Œ ํŽ˜์ด์ง€ ์กด์žฌ ์—ฌ๋ถ€ + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ ์‘๋‹ต + MyEventResponse: + required: + - publicId + - registrationEndsAt + - title + - totalApplicants + type: object + properties: + publicId: + type: string + title: + type: string + startsAt: + type: string + format: date-time + endsAt: + type: string + format: date-time + registrationStartsAt: + type: string + format: date-time + registrationEndsAt: + type: string + format: date-time + capacity: + type: integer + format: int32 + totalApplicants: + type: integer + format: int32 + MyEventsInfiniteResponse: + required: + - events + - hasNext + type: object + properties: + events: + type: array + items: + $ref: "#/components/schemas/MyEventResponse" + nextCursor: + type: string + format: date-time + hasNext: + type: boolean + DeleteRegistrationRequest: + type: object + properties: + guestName: + type: string + description: ๋น„ํšŒ์› ์ด๋ฆ„ + guestEmail: + type: string + description: ๋น„ํšŒ์› ์ด๋ฉ”์ผ + description: ์ด๋ฒคํŠธ ์ทจ์†Œ ์š”์ฒญ + DeleteRegistrationResponse: + type: object + securitySchemes: + bearerAuth: + type: http + description: JWT ํ† ํฐ์„ ์ž…๋ ฅํ•˜์„ธ์š” + name: bearerAuth + scheme: bearer + bearerFormat: JWT diff --git a/src/main/resources/static/docs/swagger-ui.html b/src/main/resources/static/docs/swagger-ui.html new file mode 100644 index 00000000..517735db --- /dev/null +++ b/src/main/resources/static/docs/swagger-ui.html @@ -0,0 +1,36 @@ + + + + + + MoiMing API Docs + + + + +
+ + + + + From 8cebad2e2c6fcf0090845539c8496c69ecebad0a Mon Sep 17 00:00:00 2001 From: uykhc Date: Tue, 14 Apr 2026 23:07:34 +0900 Subject: [PATCH 02/27] refactor(openapi): migrate from swagger annotations to static openapi.yaml --- .github/PULL_REQUEST_TEMPLATE/dev.md | 2 + .github/PULL_REQUEST_TEMPLATE/main.md | 1 + .github/workflows/ci.yml | 8 + .../image/controller/ImageController.kt | 15 +- .../domain/auth/controller/AuthController.kt | 40 - .../auth/controller/SocialAuthController.kt | 11 - .../domain/auth/dto/LoginRequest.kt | 5 - .../domain/auth/dto/RegisterRequest.kt | 7 - .../domain/auth/dto/SignupRequest.kt | 7 - .../domain/auth/dto/SocialLoginRequest.kt | 5 - .../event/controller/EventController.kt | 11 - .../domain/event/dto/core/EventDto.kt | 15 - .../event/dto/request/CreateEventRequest.kt | 23 - .../event/dto/request/UpdateEventRequest.kt | 23 - .../event/dto/response/EventDetailResponse.kt | 53 - .../domain/event/dto/response/GuestPreview.kt | 10 - .../domain/event/dto/response/MyRole.kt | 6 - .../domain/event/dto/response/ViewerStatus.kt | 8 - .../controller/EventRegistrationController.kt | 36 - .../controller/MyRegistrationController.kt | 10 +- .../controller/RegistrationController.kt | 14 - .../registration/dto/core/RegistrationDto.kt | 9 - .../dto/core/RegistrationWithEventDto.kt | 10 - .../dto/request/CreateRegistrationRequest.kt | 4 - .../dto/request/DeleteRegistrationRequest.kt | 5 - .../UpdateRegistrationStatusRequest.kt | 2 - .../response/CreateRegistrationResponse.kt | 4 - .../response/GetEventRegistrationsResponse.kt | 14 - .../response/GetMyRegistrationsResponse.kt | 14 - .../dto/response/GetRegistrationResponse.kt | 2 - .../dto/response/PatchRegistrationResponse.kt | 3 - .../response/RegistrationGuestsResponse.kt | 10 - .../domain/user/controller/UserController.kt | 54 +- .../user/identity/dto/core/UserIdentityDto.kt | 7 - src/main/resources/application.yaml | 7 + src/main/resources/static/docs/openapi.yaml | 1181 +++++++++++++++++ .../resources/static/docs/swagger-ui.html | 36 + 37 files changed, 1239 insertions(+), 433 deletions(-) create mode 100644 src/main/resources/static/docs/openapi.yaml create mode 100644 src/main/resources/static/docs/swagger-ui.html diff --git a/.github/PULL_REQUEST_TEMPLATE/dev.md b/.github/PULL_REQUEST_TEMPLATE/dev.md index ad0b6ad0..558f1a66 100644 --- a/.github/PULL_REQUEST_TEMPLATE/dev.md +++ b/.github/PULL_REQUEST_TEMPLATE/dev.md @@ -2,6 +2,8 @@ ### ๐Ÿงช ๋กœ์ปฌ ํ…Œ์ŠคํŠธ ์—ฌ๋ถ€ (์ž‘์—…์ž ์ฒดํฌ) - [ ] ๋กœ์ปฌ์—์„œ Swagger ํ˜น์€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋กœ ๋™์ž‘์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. +- [ ] API ๋ณ€๊ฒฝ์ด ์žˆ๋‹ค๋ฉด `src/main/resources/static/docs/openapi.yaml`์„ ํ•จ๊ป˜ ๊ฐฑ์‹ ํ–ˆ์Šต๋‹ˆ๋‹ค. +- [ ] `/docs/swagger-ui.html`์—์„œ ๋ณ€๊ฒฝ API๊ฐ€ ์˜๋„๋Œ€๋กœ ๋ณด์ด๋Š”์ง€ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ### ๐Ÿ“„ documentation ์ตœ์‹ ํ™” ์—ฌ๋ถ€ > ๋ณ€๊ฒฝ์‚ฌํ•ญ๊ณผ ๊ด€๋ จ๋œ API์˜ swagger documentation์ด ์‹ค์ œ ๋™์ž‘๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. diff --git a/.github/PULL_REQUEST_TEMPLATE/main.md b/.github/PULL_REQUEST_TEMPLATE/main.md index e46646af..15cd0692 100644 --- a/.github/PULL_REQUEST_TEMPLATE/main.md +++ b/.github/PULL_REQUEST_TEMPLATE/main.md @@ -5,6 +5,7 @@ - [ ] CI ์„ฑ๊ณต - [ ] ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ • ํ™•์ธ - [ ] dev ์„œ๋ฒ„์—์„œ ๋ณ€๊ฒฝ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์˜๋„๋Œ€๋กœ ๋™์ž‘ํ•จ์„ ํ™•์ธ +- [ ] API ๋ณ€๊ฒฝ์ด ์žˆ๋‹ค๋ฉด `src/main/resources/static/docs/openapi.yaml` ๋ฐ˜์˜ ์™„๋ฃŒ ### ๐Ÿ“ ์—…๋ฐ์ดํŠธ ์‚ฌํ•ญ ์š”์•ฝ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d75114a4..80cda61f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,14 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Set up Node 20 + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Lint OpenAPI YAML + run: npx @redocly/cli@latest lint src/main/resources/static/docs/openapi.yaml + - name: Set up JDK 21 uses: actions/setup-java@v4 with: diff --git a/src/main/kotlin/com/wafflestudio/spring2025/common/image/controller/ImageController.kt b/src/main/kotlin/com/wafflestudio/spring2025/common/image/controller/ImageController.kt index d774bdb0..1cdb9ea8 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/common/image/controller/ImageController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/common/image/controller/ImageController.kt @@ -4,10 +4,6 @@ import com.wafflestudio.spring2025.common.image.dto.ImageUploadResponse import com.wafflestudio.spring2025.common.image.service.ImageService import com.wafflestudio.spring2025.domain.auth.LoggedInUser import com.wafflestudio.spring2025.domain.user.model.User -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 org.springframework.http.MediaType import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PostMapping @@ -22,21 +18,12 @@ import org.springframework.web.multipart.MultipartFile class ImageController( private val imageService: ImageService, ) { - @Operation(summary = "์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", description = "์„œ๋ฒ„ ์ €์žฅ์†Œ์— ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.") - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์„ฑ๊ณต"), - ApiResponse(responseCode = "400", description = "์ž˜๋ชป๋œ ์š”์ฒญ (ํŒŒ์ผ ๋ˆ„๋ฝ/ํ˜•์‹ ์˜ค๋ฅ˜ ๋“ฑ)"), - ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ)"), - ], - ) @PostMapping( consumes = [MediaType.MULTIPART_FORM_DATA_VALUE], ) fun uploadImage( - @Parameter(hidden = true) @LoggedInUser user: User?, + @LoggedInUser user: User?, @RequestPart("image") image: MultipartFile, - @Parameter(description = "์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•  ์ƒ์œ„ ๊ฒฝ๋กœ", required = false) @RequestParam(name = "prefix", required = false) prefix: String?, ): ResponseEntity { diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/AuthController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/AuthController.kt index fae13d16..f35d874e 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/AuthController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/AuthController.kt @@ -5,10 +5,6 @@ import com.wafflestudio.spring2025.domain.auth.dto.LoginResponse import com.wafflestudio.spring2025.domain.auth.dto.SignupRequest import com.wafflestudio.spring2025.domain.auth.service.AuthService import com.wafflestudio.spring2025.domain.auth.service.EmailVerificationService -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.servlet.http.HttpServletRequest import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PathVariable @@ -19,23 +15,10 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/api/auth") -@Tag(name = "Auth", description = "์ธ์ฆ API") class AuthController( private val authService: AuthService, private val emailVerificationService: EmailVerificationService, ) { - @Operation( - summary = "์ด๋ฉ”์ผ ํšŒ์›๊ฐ€์ž…", - description = "์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์ธ์ฆ ์ด๋ฉ”์ผ์„ ๋ฐœ์†กํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฉ”์ผ ์ธ์ฆ ํ›„ ๊ฐ€์ž…์ด ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.", - ) - @ApiResponses( - value = [ - ApiResponse(responseCode = "204", description = "์ธ์ฆ ์ด๋ฉ”์ผ ๋ฐœ์†ก ์„ฑ๊ณต"), - ApiResponse(responseCode = "400", description = "์ž˜๋ชป๋œ ์š”์ฒญ (์œ ํšจํ•˜์ง€ ์•Š์€ email/password/name)"), - ApiResponse(responseCode = "409", description = "์ด๋ฏธ ์กด์žฌํ•˜๋Š” email"), - ApiResponse(responseCode = "503", description = "์ด๋ฉ”์ผ ์„œ๋น„์Šค ์žฅ์• "), - ], - ) @PostMapping("/signup") fun signup( @RequestBody signupRequest: SignupRequest, @@ -51,16 +34,6 @@ class AuthController( return ResponseEntity.noContent().build() } - @Operation( - summary = "์ด๋ฉ”์ผ ์ธ์ฆ", - description = "์ด๋ฉ”์ผ๋กœ ๋ฐ›์€ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  ํšŒ์›๊ฐ€์ž…์„ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค", - ) - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "์ธ์ฆ ์„ฑ๊ณต, ์œ ์ € ๋“ฑ๋ก ์™„๋ฃŒ"), - ApiResponse(responseCode = "400", description = "์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋งŒ๋ฃŒ๋œ ์ธ์ฆ ์ฝ”๋“œ"), - ], - ) @PostMapping("/email-verification/{verificationCode}") fun verifyEmail( @PathVariable verificationCode: String, @@ -69,13 +42,6 @@ class AuthController( return ResponseEntity.ok().build() } - @Operation(summary = "๋กœ๊ทธ์ธ", description = "email๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ JWT ํ† ํฐ์„ ๋ฐœ๊ธ‰๋ฐ›์Šต๋‹ˆ๋‹ค") - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "๋กœ๊ทธ์ธ ์„ฑ๊ณต, JWT ํ† ํฐ ๋ฐ˜ํ™˜"), - ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ"), - ], - ) @PostMapping("/login") fun login( @RequestBody loginRequest: LoginRequest, @@ -84,12 +50,6 @@ class AuthController( return ResponseEntity.ok(LoginResponse(token)) } - @Operation(summary = "๋กœ๊ทธ์•„์›ƒ", description = "ํ˜„์žฌ JWT ํ† ํฐ์„ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•˜์—ฌ ๋กœ๊ทธ์•„์›ƒํ•ฉ๋‹ˆ๋‹ค") - @ApiResponses( - value = [ - ApiResponse(responseCode = "204", description = "๋กœ๊ทธ์•„์›ƒ ์„ฑ๊ณต"), - ], - ) @PostMapping("/logout") fun logout(request: HttpServletRequest): ResponseEntity { val token = resolveToken(request) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt index b43a4ced..dbd09f73 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt @@ -4,9 +4,6 @@ import com.wafflestudio.spring2025.domain.auth.dto.LoginResponse import com.wafflestudio.spring2025.domain.auth.dto.SocialLoginRequest import com.wafflestudio.spring2025.domain.auth.model.SocialProvider import com.wafflestudio.spring2025.domain.auth.service.SocialAuthService -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.responses.ApiResponse -import io.swagger.v3.oas.annotations.responses.ApiResponses import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody @@ -18,14 +15,6 @@ import org.springframework.web.bind.annotation.RestController class SocialAuthController( private val socialAuthService: SocialAuthService, ) { - @Operation(summary = "์†Œ์…œ ๋กœ๊ทธ์ธ", description = "์†Œ์…œ ๋กœ๊ทธ์ธ์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.") - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "์†Œ์…œ ๋กœ๊ทธ์ธ ์„ฑ๊ณต"), - ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ"), - ApiResponse(responseCode = "409", description = "์ด๋ฏธ ๊ฐ€์ž…๋œ ์ด๋ฉ”์ผ"), - ], - ) @PostMapping suspend fun social( @RequestBody socialLoginRequest: SocialLoginRequest, diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/LoginRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/LoginRequest.kt index bf17a881..0d5ffea7 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/LoginRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/LoginRequest.kt @@ -1,11 +1,6 @@ package com.wafflestudio.spring2025.domain.auth.dto -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "๋กœ๊ทธ์ธ ์š”์ฒญ") data class LoginRequest( - @Schema(description = "์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ", example = "user@example.com", required = true) val email: String, - @Schema(description = "์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ", example = "mypassword", required = true) val password: String, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt index 470bcb7f..32ee7ed3 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt @@ -1,15 +1,8 @@ package com.wafflestudio.spring2025.domain.auth.dto -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "ํšŒ์›๊ฐ€์ž… ์š”์ฒญ") data class RegisterRequest( - @Schema(description = "์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ", example = "user@example.com", required = true) val email: String, - @Schema(description = "์‚ฌ์šฉ์ž ์ด๋ฆ„", example = "ํ™๊ธธ๋™", required = true) val name: String, - @Schema(description = "๋น„๋ฐ€๋ฒˆํ˜ธ", example = "password123", required = true) val password: String, - @Schema(description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL", example = "https://cdn.example.com/profile.png") val profileImage: String? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SignupRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SignupRequest.kt index 94c273ff..53618934 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SignupRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SignupRequest.kt @@ -1,15 +1,8 @@ package com.wafflestudio.spring2025.domain.auth.dto -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "ํšŒ์›๊ฐ€์ž… ์š”์ฒญ") data class SignupRequest( - @Schema(description = "์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ", example = "user@example.com", required = true) val email: String, - @Schema(description = "์‚ฌ์šฉ์ž ์ด๋ฆ„", example = "ํ™๊ธธ๋™", required = true) val name: String, - @Schema(description = "๋น„๋ฐ€๋ฒˆํ˜ธ", example = "password123", required = true) val password: String, - @Schema(description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL", example = "https://cdn.example.com/profile.png") val profileImage: String? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SocialLoginRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SocialLoginRequest.kt index f83e60f3..28fc2bad 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SocialLoginRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/SocialLoginRequest.kt @@ -1,11 +1,6 @@ package com.wafflestudio.spring2025.domain.auth.dto -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "์†Œ์…œ ๋กœ๊ทธ์ธ ์š”์ฒญ") data class SocialLoginRequest( - @Schema(description = "์†Œ์…œ๋กœ๊ทธ์ธ ์ œ๊ณต์ž", example = "GOOGLE", required = true) val provider: String, - @Schema(description = "์ธ๊ฐ€ ์ฝ”๋“œ (authorization code)", required = true) val code: String, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/controller/EventController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/controller/EventController.kt index 7ba5fae8..7e1a9de5 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/controller/EventController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/controller/EventController.kt @@ -10,8 +10,6 @@ import com.wafflestudio.spring2025.domain.event.dto.response.MyEventsInfiniteRes import com.wafflestudio.spring2025.domain.event.dto.response.UpdateEventResponse import com.wafflestudio.spring2025.domain.event.service.EventService import com.wafflestudio.spring2025.domain.user.model.User -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping @@ -26,12 +24,10 @@ import java.time.Instant @RestController @RequestMapping("/api/events") -@Tag(name = "Event", description = "์ด๋ฒคํŠธ ๊ด€๋ฆฌ API") class EventController( private val eventService: EventService, ) { @AuthRequired - @Operation(summary = "์ด๋ฒคํŠธ ์ƒ์„ฑ", description = "์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค") @PostMapping // POST /api/events fun create( @LoggedInUser user: User, @@ -54,7 +50,6 @@ class EventController( return ResponseEntity.ok(CreateEventResponse(publicId)) } - @Operation(summary = "์ด๋ฒคํŠธ ์ƒ์„ธ ์กฐํšŒ", description = "์ด๋ฒคํŠธ ์ƒ์„ธ ์ •๋ณด๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค") @GetMapping("/{publicId}") // GET /api/events/{publicId} fun getById( @LoggedInUser user: User?, // nullable @@ -69,10 +64,6 @@ class EventController( } @AuthRequired - @Operation( - summary = "๋‚ด๊ฐ€ ๋งŒ๋“  ์ด๋ฒคํŠธ ๋ชฉ๋ก ์กฐํšŒ (๋ฌดํ•œ ์Šคํฌ๋กค)", - description = "๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ์„ฑํ•œ ์ด๋ฒคํŠธ ๋ชฉ๋ก์„ ๋ฌดํ•œ ์Šคํฌ๋กค ๋ฐฉ์‹(cursor)์œผ๋กœ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค", - ) @GetMapping("/me") fun getMyEvents( @LoggedInUser user: User, @@ -89,7 +80,6 @@ class EventController( } @AuthRequired - @Operation(summary = "์ด๋ฒคํŠธ ์ˆ˜์ •", description = "์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค") @PutMapping("/{publicId}") // PUT /api/events/{publicId} fun update( @LoggedInUser user: User, @@ -116,7 +106,6 @@ class EventController( } @AuthRequired - @Operation(summary = "์ด๋ฒคํŠธ ์‚ญ์ œ", description = "์ด๋ฒคํŠธ๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค") @DeleteMapping("/{publicId}") // DELETE /api/events/{publicId} fun delete( @LoggedInUser user: User, diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/core/EventDto.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/core/EventDto.kt index 2b4765a2..778ea5ca 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/core/EventDto.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/core/EventDto.kt @@ -1,35 +1,20 @@ package com.wafflestudio.spring2025.domain.event.dto.core import com.wafflestudio.spring2025.domain.event.model.Event -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ผ์ • ์ •๋ณด") data class EventDto( - @Schema(description = "์ผ์ • ID (publicId)") val id: String, - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ") val title: String, - @Schema(description = "์ด๋ฒคํŠธ ์„ค๋ช…") val description: String?, - @Schema(description = "์žฅ์†Œ") val location: String?, - @Schema(description = "์‹œ์ž‘ ์‹œ๊ฐ„ (epoch milliseconds)") val startsAt: Long?, - @Schema(description = "์ข…๋ฃŒ ์‹œ๊ฐ„ (epoch milliseconds)") val endsAt: Long?, - @Schema(description = "์ •์›") val capacity: Int?, - @Schema(description = "๋Œ€๊ธฐ ๋ช…๋‹จ ์‚ฌ์šฉ ์—ฌ๋ถ€") val waitlistEnabled: Boolean, - @Schema(description = "์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (epoch milliseconds)") val registrationStartsAt: Long?, - @Schema(description = "์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (epoch milliseconds)") val registrationEndsAt: Long, - @Schema(description = "์ž‘์„ฑ์ž ID") val createdBy: Long, - @Schema(description = "์ƒ์„ฑ ์ผ์‹œ (epoch milliseconds)") val createdAt: Long?, - @Schema(description = "์ˆ˜์ • ์ผ์‹œ (epoch milliseconds)") val updatedAt: Long?, ) { constructor(event: Event) : this( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/CreateEventRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/CreateEventRequest.kt index db6254ca..1c46a314 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/CreateEventRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/CreateEventRequest.kt @@ -1,38 +1,15 @@ package com.wafflestudio.spring2025.domain.event.dto.request -import io.swagger.v3.oas.annotations.media.Schema import java.time.Instant -@Schema(description = "์ผ์ • ์ƒ์„ฑ ์š”์ฒญ") data class CreateEventRequest( - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ", example = "์ •๊ธฐ ๋ชจ์ž„") val title: String, - @Schema(description = "์ด๋ฒคํŠธ ์„ค๋ช…", example = "์ •๊ธฐ ๋ชจ์ž„์ž…๋‹ˆ๋‹ค") val description: String? = null, - @Schema(description = "์žฅ์†Œ", example = "๊ฐ•์˜์‹ค 101") val location: String? = null, - @Schema( - description = "์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T18:00:00Z", - ) val startsAt: Instant? = null, - @Schema( - description = "์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T20:00:00Z", - ) val endsAt: Instant? = null, - @Schema(description = "์ •์›", example = "30") val capacity: Int, - @Schema(description = "๋Œ€๊ธฐ ๋ช…๋‹จ ์‚ฌ์šฉ ์—ฌ๋ถ€", example = "true") val waitlistEnabled: Boolean, - @Schema( - description = "์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601). null์ธ ๊ฒฝ์šฐ ์š”์ฒญ ์‹œ์ ์œผ๋กœ ์ž๋™ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.", - example = "2026-02-02T17:00:00Z", - ) val registrationStartsAt: Instant? = null, - @Schema( - description = "์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T17:30:00Z", - ) val registrationEndsAt: Instant, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/UpdateEventRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/UpdateEventRequest.kt index e237b56c..2206d5c5 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/UpdateEventRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/request/UpdateEventRequest.kt @@ -1,38 +1,15 @@ package com.wafflestudio.spring2025.domain.event.dto.request -import io.swagger.v3.oas.annotations.media.Schema import java.time.Instant -@Schema(description = "์ผ์ • ์ˆ˜์ • ์š”์ฒญ") data class UpdateEventRequest( - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ", example = "์ •๊ธฐ ๋ชจ์ž„") val title: String? = null, - @Schema(description = "์ด๋ฒคํŠธ ์„ค๋ช…", example = "์ •๊ธฐ ๋ชจ์ž„์ž…๋‹ˆ๋‹ค") val description: String? = null, - @Schema(description = "์žฅ์†Œ", example = "๊ฐ•์˜์‹ค 101") val location: String? = null, - @Schema( - description = "์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T18:00:00Z", - ) val startsAt: Instant? = null, - @Schema( - description = "์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T20:00:00Z", - ) val endsAt: Instant? = null, - @Schema(description = "์ •์›", example = "30") val capacity: Int? = null, - @Schema(description = "๋Œ€๊ธฐ ๋ช…๋‹จ ์‚ฌ์šฉ ์—ฌ๋ถ€", example = "true") val waitlistEnabled: Boolean? = null, - @Schema( - description = "์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T17:00:00Z", - ) val registrationStartsAt: Instant? = null, - @Schema( - description = "์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601)", - example = "2026-02-02T17:30:00Z", - ) val registrationEndsAt: Instant? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/EventDetailResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/EventDetailResponse.kt index 84e7616a..685cfd04 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/EventDetailResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/EventDetailResponse.kt @@ -1,99 +1,46 @@ package com.wafflestudio.spring2025.domain.event.dto.response -import io.swagger.v3.oas.annotations.media.Schema import java.time.Instant -@Schema(description = "์ผ์ • ์ƒ์„ธ ์กฐํšŒ ์‘๋‹ต") data class EventDetailResponse( - @Schema(description = "์ด๋ฒคํŠธ ์ •๋ณด") val event: EventInfo, - @Schema(description = "์ด๋ฒคํŠธ ์ƒ์„ฑ์ž ์ •๋ณด") val creator: CreatorInfo, - @Schema(description = "์กฐํšŒ์ž(viewer) ์ •๋ณด") val viewer: ViewerInfo, - @Schema(description = "์กฐํšŒ์ž๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๋™์ž‘") val capabilities: CapabilitiesInfo, - @Schema(description = "์ฐธ์—ฌ์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ชฉ๋ก") val guestsPreview: List, ) -@Schema(description = "์ด๋ฒคํŠธ ์ •๋ณด ๋ธ”๋ก") data class EventInfo( - @Schema(description = "์ด๋ฒคํŠธ publicId", example = "dj8sadj10djnkas") val publicId: String, - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ", example = "์ œ2ํšŒ ๊ธฐํš ์„ธ๋ฏธ๋‚˜") val title: String, - @Schema(description = "์ด๋ฒคํŠธ ์„ค๋ช…", example = "์ผ์ • ์ƒ์„ธ ์„ค๋ช…...", nullable = true) val description: String?, - @Schema(description = "์žฅ์†Œ", example = "์„œ์šธ๋Œ€", nullable = true) val location: String?, - @Schema(description = "์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)", example = "2026-02-02T18:00:00Z", nullable = true) val startsAt: Instant?, - @Schema(description = "์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601)", example = "2026-02-02T20:00:00Z", nullable = true) val endsAt: Instant?, - @Schema(description = "์ •์›", example = "10", nullable = true) val capacity: Int?, - @Schema(description = "์ฐธ์—ฌ์ž ์ˆ˜(์ฐธ์—ฌ ํ™•์ • ์ธ์›)", example = "5") val confirmedCount: Int, - @Schema(description = "๋Œ€๊ธฐ์ž ์ˆ˜", example = "5") val waitlistCount: Int, - @Schema(description = "์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)", example = "2026-02-02T17:00:00Z", nullable = true) val registrationStartsAt: Instant?, - @Schema(description = "์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601)", example = "2026-02-02T17:00:00Z") val registrationEndsAt: Instant, ) -@Schema(description = "์ƒ์„ฑ์ž ์ •๋ณด ๋ธ”๋ก") data class CreatorInfo( - @Schema(description = "์ด๋ฆ„", example = "ํ™๊ธธ๋™") val name: String, - @Schema(description = "์ด๋ฉ”์ผ", example = "user@example.com") val email: String, - @Schema(description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€", example = "https://example.com/profile.png", nullable = true) val profileImage: String?, ) -@Schema(description = "์กฐํšŒ์ž(viewer) ์ •๋ณด ๋ธ”๋ก") data class ViewerInfo( - @Schema( - description = "viewer์˜ ๋“ฑ๋ก ์ƒํƒœ (RegistrationStatus ์‚ฌ์šฉ)", - example = "WAITLISTED", - ) val status: ViewerStatus, - @Schema( - description = "viewer ์ด๋ฆ„ (๋น„ํšŒ์›์ด๋ฉด null)", - example = "ํ™๊ธธ๋™", - nullable = true, - ) val name: String?, - @Schema( - description = "๋Œ€๊ธฐ ์ˆœ๋ฒˆ (WAITLISTED์ผ ๋•Œ๋งŒ ์ˆซ์ž, ์•„๋‹ˆ๋ฉด null)", - example = "3", - nullable = true, - ) val waitlistPosition: Int?, - @Schema( - description = "registrationPublicId (๊ฒŒ์ŠคํŠธ๋ฉด ๊ฐ’, ์•„๋‹ˆ๋ฉด null)", - example = "1", - nullable = true, - ) val registrationPublicId: String?, - @Schema( - description = "์˜ˆ์•ฝ ์ด๋ฉ”์ผ(๊ฒŒ์ŠคํŠธ๋ฉด guestEmail, ๋กœ๊ทธ์ธ ์œ ์ €๋ฉด user email ๋“ฑ ์ •์ฑ…์— ๋”ฐ๋ฆ„)", - example = "skdfsj@gmaldkl", - nullable = true, - ) val reservationEmail: String?, ) -@Schema(description = "๊ฐ€๋Šฅํ•œ ๋™์ž‘ ๋ธ”๋ก") data class CapabilitiesInfo( - @Schema(description = "๊ณต์œ  ๋งํฌ ๊ฐ€๋Šฅ ์—ฌ๋ถ€", example = "false") val shareLink: Boolean, - @Schema(description = "์ฐธ์—ฌ ์‹ ์ฒญ ๊ฐ€๋Šฅ ์—ฌ๋ถ€(ํ™•์ • ์ž๋ฆฌ ์‹ ์ฒญ)", example = "false") val apply: Boolean, - @Schema(description = "๋Œ€๊ธฐ ์‹ ์ฒญ ๊ฐ€๋Šฅ ์—ฌ๋ถ€(์ •์› ์ฐผ์„ ๋•Œ)", example = "false") val wait: Boolean, - @Schema(description = "์‹ ์ฒญ ์ทจ์†Œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€", example = "true") val cancel: Boolean, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/GuestPreview.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/GuestPreview.kt index 01781f48..2f3314a7 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/GuestPreview.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/GuestPreview.kt @@ -1,21 +1,11 @@ package com.wafflestudio.spring2025.domain.event.dto.response -import io.swagger.v3.oas.annotations.media.Schema - /** * ์ด๋ฒคํŠธ ์ฐธ์—ฌ์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ •๋ณด * (ํšŒ์›/๋น„ํšŒ์› ํฌํ•จ) */ -@Schema(description = "์ฐธ์—ฌ์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ •๋ณด") data class GuestPreview( - @Schema(description = "์ฐธ์—ฌ์ž ID (๋น„ํšŒ์›์ด๋ฉด null)", example = "1", nullable = true) val id: Long?, - @Schema(description = "์ฐธ์—ฌ์ž ์ด๋ฆ„", example = "ํ™๊ธธ๋™") val name: String, - @Schema( - description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL", - example = "https://example.com/profile.png", - nullable = true, - ) val profileImage: String?, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/MyRole.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/MyRole.kt index d1a8b89a..c06024ed 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/MyRole.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/MyRole.kt @@ -1,21 +1,15 @@ package com.wafflestudio.spring2025.domain.event.dto.response -import io.swagger.v3.oas.annotations.media.Schema - /** * ์š”์ฒญ์ž ์—ญํ•  * - CREATOR: ์ด๋ฒคํŠธ ์ƒ์„ฑ์ž * - PARTICIPANT: ์ด๋ฒคํŠธ ์ฐธ์—ฌ์ž (CONFIRMED / WAITLISTED) * - NONE: ๋กœ๊ทธ์ธ์€ ํ–ˆ์ง€๋งŒ ์ฐธ์—ฌํ•˜์ง€ ์•Š์Œ */ -@Schema(description = "์š”์ฒญ์ž ์—ญํ• ") enum class MyRole { - @Schema(description = "์ด๋ฒคํŠธ ์ƒ์„ฑ์ž") CREATOR, - @Schema(description = "์ด๋ฒคํŠธ ์ฐธ์—ฌ์ž") PARTICIPANT, - @Schema(description = "์ด๋ฒคํŠธ ๋ฏธ์ฐธ์—ฌ์ž") NONE, } diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/ViewerStatus.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/ViewerStatus.kt index a250a6db..d85fe72a 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/ViewerStatus.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/dto/response/ViewerStatus.kt @@ -1,25 +1,17 @@ package com.wafflestudio.spring2025.domain.event.dto.response -import io.swagger.v3.oas.annotations.media.Schema - /** * ์ด๋ฒคํŠธ ์ƒ์„ธ ์กฐํšŒ ์‹œ, * "viewer(์š”์ฒญ์ž)"๊ฐ€ ํ•ด๋‹น ์ด๋ฒคํŠธ์™€ ์–ด๋–ค ๊ด€๊ณ„์— ์žˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ƒํƒœ */ -@Schema(description = "์ด๋ฒคํŠธ ์กฐํšŒ์ž(Viewer)์˜ ์ƒํƒœ") enum class ViewerStatus { - @Schema(description = "์ด๋ฒคํŠธ ์ƒ์„ฑ์ž") HOST, - @Schema(description = "์ฐธ์—ฌ ํ™•์ •๋œ ์‚ฌ์šฉ์ž") CONFIRMED, - @Schema(description = "๋Œ€๊ธฐ ์ค‘์ธ ์‚ฌ์šฉ์ž") WAITLISTED, - @Schema(description = "๊ฐ•์ œ ์ทจ์†Œ(์ฐจ๋‹จ)๋œ ์‚ฌ์šฉ์ž") BANNED, - @Schema(description = "์ด๋ฒคํŠธ์™€ ์•„๋ฌด ๊ด€๊ณ„ ์—†๋Š” ์‚ฌ์šฉ์ž") NONE, } diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/EventRegistrationController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/EventRegistrationController.kt index 4fb815e9..213bc67d 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/EventRegistrationController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/EventRegistrationController.kt @@ -6,11 +6,6 @@ import com.wafflestudio.spring2025.domain.registration.dto.response.CreateRegist import com.wafflestudio.spring2025.domain.registration.dto.response.GetEventRegistrationsResponse import com.wafflestudio.spring2025.domain.registration.service.RegistrationService import com.wafflestudio.spring2025.domain.user.model.User -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 @@ -22,35 +17,9 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/api/events/{eventId}/registrations") -@Tag(name = "Registration", description = "์ด๋ฒคํŠธ ๊ธฐ์ค€ ์‹ ์ฒญ API") class EventRegistrationController( private val registrationService: RegistrationService, ) { - @Operation( - summary = "์ด๋ฒคํŠธ ์ฐธ์—ฌ ์‹ ์ฒญ", - description = - "ํŠน์ • ์ด๋ฒคํŠธ์— ์‹ ์ฒญํ•ฉ๋‹ˆ๋‹ค. ์ •์›์ด ๋‚จ์•„์žˆ์œผ๋ฉด CONFIRMED๋กœ ๋“ฑ๋ก๋˜๊ณ , ์ •์›์ด ์ฐผ์œผ๋‚˜ ๋Œ€๊ธฐ ๋ช…๋‹จ์ด ํ—ˆ์šฉ๋œ ๊ฒฝ์šฐ WAITLISTED๋กœ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค. " + - "์ •์›์ด ์ฐผ๊ณ  ๋Œ€๊ธฐ ๋ช…๋‹จ์ด ๋น„ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ ์‹ ์ฒญ์ด ๊ฑฐ์ ˆ๋ฉ๋‹ˆ๋‹ค.", - ) - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "์‹ ์ฒญ ์„ฑ๊ณต"), - ApiResponse( - responseCode = "400", - description = - "์œ ํšจํ•˜์ง€ ์•Š์€ ์š”์ฒญ: 3003(Wrong guest name), 3004(Wrong guest email), 2204(Invalid registration window)", - ), - ApiResponse( - responseCode = "403", - description = "๊ถŒํ•œ ์—†์Œ: 3006(Banned user cannot register)", - ), - ApiResponse(responseCode = "404", description = "์ด๋ฒคํŠธ ์—†์Œ: 2001(Event not found)"), - ApiResponse( - responseCode = "409", - description = "์‹ ์ฒญ ๋ถˆ๊ฐ€: 3001(Registration already exists), 3005(Host cannot register), 2301(Event is full)", - ), - ], - ) @PostMapping fun create( @PathVariable eventId: String, @@ -67,17 +36,12 @@ class EventRegistrationController( return ResponseEntity.ok(registration) } - @Operation( - summary = "์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ", - description = "ํŠน์ • ์ด๋ฒคํŠธ์— ์†ํ•œ ์‹ ์ฒญ ๋ชฉ๋ก์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ์‹ ์ฒญ ์ƒํƒœ(CONFIRMED/WAITLISTED/BANNED)์™€ ์‹ ์ฒญ ์‹œ๊ฐ์„ ํฌํ•จํ•ด ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.", - ) @GetMapping fun list( @PathVariable eventId: String, @LoggedInUser user: User?, @RequestParam(required = false) status: String?, @RequestParam(required = false) orderBy: String?, - @Parameter(description = "๋‹ค์Œ ํŽ˜์ด์ง€ ์‹œ์ž‘ offset (์—†์œผ๋ฉด 0๋ถ€ํ„ฐ)") @RequestParam(required = false) cursor: Int?, ): ResponseEntity = ResponseEntity.ok( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/MyRegistrationController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/MyRegistrationController.kt index 6da5b2c9..71022123 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/MyRegistrationController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/MyRegistrationController.kt @@ -5,9 +5,6 @@ import com.wafflestudio.spring2025.domain.auth.LoggedInUser import com.wafflestudio.spring2025.domain.registration.dto.response.GetMyRegistrationsResponse import com.wafflestudio.spring2025.domain.registration.service.RegistrationService import com.wafflestudio.spring2025.domain.user.model.User -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.Parameter -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.RequestMapping @@ -17,17 +14,12 @@ import org.springframework.web.bind.annotation.RestController @AuthRequired @RestController @RequestMapping("/api/registrations") -@Tag(name = "Registration", description = "๋‚ด ์‹ ์ฒญ ์กฐํšŒ API") class MyRegistrationController( private val registrationService: RegistrationService, ) { - @Operation( - summary = "๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ", - description = "๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ์ตœ์‹  ์‹ ์ฒญ ์ˆœ์œผ๋กœ ๋ฐ˜ํ™˜๋˜๋ฉฐ page/size๋กœ ํŽ˜์ด์ง•ํ•ฉ๋‹ˆ๋‹ค.", - ) @GetMapping("/me") fun myRegistrations( - @Parameter(hidden = true) @LoggedInUser user: User, + @LoggedInUser user: User, @RequestParam(defaultValue = "0") page: Int, @RequestParam(defaultValue = "20") size: Int, ): ResponseEntity { diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt index 2ffccbe6..f2568d12 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt @@ -10,8 +10,6 @@ import com.wafflestudio.spring2025.domain.registration.exception.RegistrationErr import com.wafflestudio.spring2025.domain.registration.exception.RegistrationValidationException import com.wafflestudio.spring2025.domain.registration.service.RegistrationService import com.wafflestudio.spring2025.domain.user.model.User -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping @@ -23,16 +21,9 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/api/registrations/{registrationId}") -@Tag(name = "Registration", description = "์‹ ์ฒญ ๋‹จ๊ฑด ๋ฆฌ์†Œ์Šค API") class RegistrationController( private val registrationService: RegistrationService, ) { - @Operation( - summary = "์‹ ์ฒญ ๋‹จ๊ฑด ์ƒํƒœ ๋ณ€๊ฒฝ", - description = - "์‹ ์ฒญ ๋‹จ๊ฑด ๋ฆฌ์†Œ์Šค์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. " + - "์‚ฌ์šฉ์ž๊ฐ€ ๋ณธ์ธ์˜ ์‹ ์ฒญ์„ ์ทจ์†Œํ•˜๋Š” ๊ฒฝ์šฐ์™€ ๊ด€๋ฆฌ์ž๊ฐ€ ๊ฐ•์ œ ์ทจ์†Œ/๋ฐด ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๋กœ์ง ๋ ˆ๋ฒจ์—์„œ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.", - ) @PatchMapping fun updateStatus( @PathVariable registrationId: String, @@ -45,11 +36,6 @@ class RegistrationController( return ResponseEntity.ok(response) } - @Operation( - summary = "์‹ ์ฒญ ๋‹จ๊ฑด ์ •๋ณด ์š”์ฒญ", - description = - "์‹ ์ฒญ ๋‹จ๊ฑด์˜ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.", - ) @GetMapping fun getRegistrationInformation( @PathVariable registrationId: String, diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationDto.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationDto.kt index e6764f91..33f1410e 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationDto.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationDto.kt @@ -2,23 +2,14 @@ package com.wafflestudio.spring2025.domain.registration.dto.core import com.wafflestudio.spring2025.domain.registration.model.Registration import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์ •๋ณด") data class RegistrationDto( - @Schema(description = "์‹ ์ฒญ ๊ณต๊ฐœ ID") val registrationPublicId: String, - @Schema(description = "์‚ฌ์šฉ์ž ID") val userId: Long?, - @Schema(description = "์ด๋ฒคํŠธ ID") val eventId: Long, - @Schema(description = "๋น„ํšŒ์› ์ด๋ฆ„") val guestName: String?, - @Schema(description = "๋น„ํšŒ์› ์ด๋ฉ”์ผ") val guestEmail: String?, - @Schema(description = "์‹ ์ฒญ ์ƒํƒœ") val status: RegistrationStatus, - @Schema(description = "์‹ ์ฒญ ์ผ์‹œ (epoch milliseconds)") val createdAt: Long, ) { constructor(registration: Registration) : this( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationWithEventDto.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationWithEventDto.kt index 5255eb9e..70c08a66 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationWithEventDto.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/core/RegistrationWithEventDto.kt @@ -2,13 +2,9 @@ package com.wafflestudio.spring2025.domain.registration.dto.core import com.wafflestudio.spring2025.domain.event.model.Event import com.wafflestudio.spring2025.domain.registration.model.Registration -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ์ •๋ณด") data class RegistrationWithEventDto( - @Schema(description = "์‹ ์ฒญ ์ •๋ณด") val registration: RegistrationDto, - @Schema(description = "์ด๋ฒคํŠธ ์š”์•ฝ ์ •๋ณด") val event: EventSummaryDto, ) { constructor(registration: Registration, event: Event) : this( @@ -17,17 +13,11 @@ data class RegistrationWithEventDto( ) } -@Schema(description = "์ด๋ฒคํŠธ ์š”์•ฝ ์ •๋ณด") data class EventSummaryDto( - @Schema(description = "์ด๋ฒคํŠธ ID") val id: Long, - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ") val title: String, - @Schema(description = "์žฅ์†Œ") val location: String?, - @Schema(description = "์‹œ์ž‘ ์‹œ๊ฐ„ (epoch milliseconds)") val startsAt: Long?, - @Schema(description = "์ข…๋ฃŒ ์‹œ๊ฐ„ (epoch milliseconds)") val endsAt: Long?, ) { constructor(event: Event) : this( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/CreateRegistrationRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/CreateRegistrationRequest.kt index baf7052f..820bd1e5 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/CreateRegistrationRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/CreateRegistrationRequest.kt @@ -1,14 +1,10 @@ package com.wafflestudio.spring2025.domain.registration.dto.request import com.fasterxml.jackson.annotation.JsonAlias -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์š”์ฒญ") data class CreateRegistrationRequest( - @Schema(description = "๋น„ํšŒ์› ์ด๋ฆ„") @JsonAlias("guest_name") val guestName: String? = null, - @Schema(description = "๋น„ํšŒ์› ์ด๋ฉ”์ผ") @JsonAlias("guest_email") val guestEmail: String? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt index 3f34c5f8..0df46b98 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt @@ -1,11 +1,6 @@ package com.wafflestudio.spring2025.domain.registration.dto.request -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "์ด๋ฒคํŠธ ์ทจ์†Œ ์š”์ฒญ") data class DeleteRegistrationRequest( - @Schema(description = "๋น„ํšŒ์› ์ด๋ฆ„") val guestName: String? = null, - @Schema(description = "๋น„ํšŒ์› ์ด๋ฉ”์ผ") val guestEmail: String? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/UpdateRegistrationStatusRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/UpdateRegistrationStatusRequest.kt index f87d15fb..2182cddc 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/UpdateRegistrationStatusRequest.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/UpdateRegistrationStatusRequest.kt @@ -1,9 +1,7 @@ package com.wafflestudio.spring2025.domain.registration.dto.request import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์ƒํƒœ ๋ณ€๊ฒฝ ์š”์ฒญ") data class UpdateRegistrationStatusRequest( val status: RegistrationStatus? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/CreateRegistrationResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/CreateRegistrationResponse.kt index eb4ea566..3abe25e8 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/CreateRegistrationResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/CreateRegistrationResponse.kt @@ -1,9 +1,5 @@ package com.wafflestudio.spring2025.domain.registration.dto.response -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์‘๋‹ต") data class CreateRegistrationResponse( - @Schema(description = "์‹ ์ฒญ id") val registrationPublicId: String, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetEventRegistrationsResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetEventRegistrationsResponse.kt index 39a7951b..c5837bd2 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetEventRegistrationsResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetEventRegistrationsResponse.kt @@ -3,36 +3,22 @@ package com.wafflestudio.spring2025.domain.registration.dto.response import com.wafflestudio.spring2025.domain.registration.model.Registration import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus import com.wafflestudio.spring2025.domain.user.model.User -import io.swagger.v3.oas.annotations.media.Schema import java.time.Instant -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ ์‘๋‹ต") data class GetEventRegistrationsResponse( - @Schema(description = "์‹ ์ฒญ์ž ๋ชฉ๋ก") val participants: List, - @Schema(description = "ํ•„ํ„ฐ์— ๋”ฐ๋ผ ๋ณ€ํ•˜๋Š” ์ฐธ์—ฌ์ž ์ˆ˜") val totalCount: Int?, - @Schema(description = "๋‹ค์Œ ํŽ˜์ด์ง€ ์‹œ์ž‘ offset (์—†์œผ๋ฉด null)") val nextCursor: Int?, - @Schema(description = "๋‹ค์Œ ํŽ˜์ด์ง€ ์กด์žฌ ์—ฌ๋ถ€") val hasNext: Boolean, ) -@Schema(description = "์‹ ์ฒญ์ž ์ •๋ณด") data class EventRegistrationItem( - @Schema(description = "์‹ ์ฒญ ๊ณต๊ฐœ ID") val registrationId: String, - @Schema(description = "์ด๋ฆ„") val name: String, - @Schema(description = "์ด๋ฉ”์ผ (๊ด€๋ฆฌ์ž ์š”์ฒญ ์‹œ ๋…ธ์ถœ)") val email: String?, - @Schema(description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL") val profileImage: String?, - @Schema(description = "์‹ ์ฒญ ์ผ์‹œ") val createdAt: Instant, - @Schema(description = "์‹ ์ฒญ ์ƒํƒœ") val status: RegistrationStatus, - @Schema(description = "๋Œ€๊ธฐ ์ˆœ๋ฒˆ (status๊ฐ€ WAITLISTED์ผ ๋•Œ๋งŒ ์•„๋‹ˆ๋ฉด null)") val waitingNum: Int?, ) { constructor( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt index 74c36966..5c597315 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt @@ -3,36 +3,22 @@ package com.wafflestudio.spring2025.domain.registration.dto.response import com.wafflestudio.spring2025.domain.event.model.Event import com.wafflestudio.spring2025.domain.registration.model.Registration import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus -import io.swagger.v3.oas.annotations.media.Schema import java.time.Instant -@Schema(description = "๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์‘๋‹ต") data class GetMyRegistrationsResponse( - @Schema(description = "์‹ ์ฒญ ๋ชฉ๋ก") val registrations: List, ) -@Schema(description = "๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ์š”์•ฝ") data class MyRegistrationItem( - @Schema(description = "์ด๋ฒคํŠธ ๊ณต๊ฐœ ID") val publicId: String, - @Schema(description = "์ด๋ฒคํŠธ ์ œ๋ชฉ") val title: String, - @Schema(description = "์ด๋ฒคํŠธ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)") val startsAt: Instant?, - @Schema(description = "์ด๋ฒคํŠธ ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601)") val endsAt: Instant?, - @Schema(description = "์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601)") val registrationStartsAt: Instant?, - @Schema(description = "์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601)") val registrationEndsAt: Instant?, - @Schema(description = "์ •์›") val capacity: Int?, - @Schema(description = "ํ˜„์žฌ ์‹ ์ฒญ ์ˆ˜ + ๋Œ€๊ธฐ ์ˆ˜") val registrationCnt: Int, - @Schema(description = "์‹ ์ฒญ ์ƒํƒœ") val status: MyRegistrationStatus, - @Schema(description = "๋Œ€๊ธฐ ์ˆœ๋ฒˆ (WAITLISTED๊ฐ€ ์•„๋‹ˆ๋ฉด null)") val waitlistedNum: Int?, ) { constructor( diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetRegistrationResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetRegistrationResponse.kt index e03dd30c..d241cd32 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetRegistrationResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetRegistrationResponse.kt @@ -1,9 +1,7 @@ package com.wafflestudio.spring2025.domain.registration.dto.response import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์ •๋ณด ์š”์ฒญ ์‘๋‹ต") data class GetRegistrationResponse( val status: RegistrationStatus, val guestName: String, diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/PatchRegistrationResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/PatchRegistrationResponse.kt index 5f8f534a..e328c6db 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/PatchRegistrationResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/PatchRegistrationResponse.kt @@ -1,8 +1,5 @@ package com.wafflestudio.spring2025.domain.registration.dto.response -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "์ด๋ฒคํŠธ ์‹ ์ฒญ ์ƒํƒœ ๋ณ€๊ฒฝ") data class PatchRegistrationResponse( val patchEmail: String? = null, ) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/RegistrationGuestsResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/RegistrationGuestsResponse.kt index 5d0d0855..fe52c458 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/RegistrationGuestsResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/RegistrationGuestsResponse.kt @@ -1,29 +1,19 @@ package com.wafflestudio.spring2025.domain.registration.dto.response import com.fasterxml.jackson.annotation.JsonProperty -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์ด๋ฒคํŠธ ์ฐธ์—ฌ์ž ๋ช…๋‹จ ์‘๋‹ต") data class RegistrationGuestsResponse( - @Schema(description = "ํ™•์ • ์ฐธ์—ฌ์ž ๋ชฉ๋ก") val guests: List, @JsonProperty("confirmed_count") - @Schema(description = "ํ™•์ • ์ฐธ์—ฌ์ž ์ˆ˜") val confirmedCount: Int, @JsonProperty("waiting_count") - @Schema(description = "๋Œ€๊ธฐ ์ฐธ์—ฌ์ž ์ˆ˜") val waitingCount: Int, ) { - @Schema(description = "์ฐธ์—ฌ์ž ์ •๋ณด") data class Guest( - @Schema(description = "์‹ ์ฒญ ๊ณต๊ฐœ ID") val registrationPublicId: String, - @Schema(description = "์ด๋ฆ„") val name: String, - @Schema(description = "์ด๋ฉ”์ผ (๊ด€๋ฆฌ์ž ์š”์ฒญ ์‹œ ๋…ธ์ถœ)") val email: String?, @JsonProperty("profile_image") - @Schema(description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL") val profileImage: String?, ) } diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/user/controller/UserController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/user/controller/UserController.kt index 85c924bd..8f214cf1 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/user/controller/UserController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/user/controller/UserController.kt @@ -7,11 +7,6 @@ import com.wafflestudio.spring2025.domain.user.dto.PatchMeRequest import com.wafflestudio.spring2025.domain.user.dto.PatchMeResponse import com.wafflestudio.spring2025.domain.user.model.User import com.wafflestudio.spring2025.domain.user.service.UserService -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.PatchMapping @@ -22,27 +17,19 @@ import org.springframework.web.bind.annotation.RestController @AuthRequired @RestController @RequestMapping("/api/users") -@Tag(name = "User", description = "์‚ฌ์šฉ์ž API") class UserController( private val userService: UserService, ) { - @Operation(summary = "๋ณธ์ธ ์ •๋ณด ์กฐํšŒ", description = "๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค") - @ApiResponses( - value = [ - ApiResponse(responseCode = "200", description = "์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ ์„ฑ๊ณต"), - ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ)"), - ], - ) @AuthRequired @GetMapping("/me") fun me( - @Parameter(hidden = true) @LoggedInUser user: User, + @LoggedInUser user: User, ): ResponseEntity = ResponseEntity.ok(userService.me(user)) @AuthRequired @PatchMapping("/me") fun patchMe( - @Parameter(hidden = true) @LoggedInUser user: User, + @LoggedInUser user: User, @RequestBody request: PatchMeRequest, ): ResponseEntity { userService.patchMe( @@ -54,41 +41,4 @@ class UserController( ) return ResponseEntity.ok(userService.me(user)) } - -// @Operation(summary = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", description = "๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œ(๊ต์ฒด)ํ•ฉ๋‹ˆ๋‹ค") -// @ApiResponses( -// value = [ -// ApiResponse(responseCode = "204", description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์„ฑ๊ณต"), -// ApiResponse(responseCode = "400", description = "์ž˜๋ชป๋œ ์š”์ฒญ (ํŒŒ์ผ ๋ˆ„๋ฝ/ํ˜•์‹ ์˜ค๋ฅ˜ ๋“ฑ)"), -// ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ)"), -// ], -// ) -// @AuthRequired -// @PutMapping( -// "/me/profile-image", -// consumes = [MediaType.MULTIPART_FORM_DATA_VALUE], -// ) -// fun uploadProfileImage( -// @Parameter(hidden = true) @LoggedInUser user: User?, -// @RequestPart("image") image: MultipartFile, -// ): ResponseEntity { -// userService.updateProfileImage(user, image) -// return ResponseEntity.noContent().build() -// } -// -// @Operation(summary = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์‚ญ์ œ", description = "๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋ฅผ ์‚ญ์ œ(๊ธฐ๋ณธ ์ด๋ฏธ์ง€๋กœ ๋ณต๊ท€)ํ•ฉ๋‹ˆ๋‹ค") -// @ApiResponses( -// value = [ -// ApiResponse(responseCode = "204", description = "ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์‚ญ์ œ ์„ฑ๊ณต"), -// ApiResponse(responseCode = "401", description = "์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ)"), -// ], -// ) -// @AuthRequired -// @DeleteMapping("/me/profile-image") -// fun deleteProfileImage( -// @Parameter(hidden = true) @LoggedInUser user: User?, -// ): ResponseEntity { -// userService.deleteProfileImage(user) -// return ResponseEntity.noContent().build() -// } } diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/user/identity/dto/core/UserIdentityDto.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/user/identity/dto/core/UserIdentityDto.kt index 092180d5..1a0f9e05 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/user/identity/dto/core/UserIdentityDto.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/user/identity/dto/core/UserIdentityDto.kt @@ -1,19 +1,12 @@ package com.wafflestudio.spring2025.domain.user.identity.dto.core import com.wafflestudio.spring2025.domain.user.identity.model.UserIdentity -import io.swagger.v3.oas.annotations.media.Schema -@Schema(description = "์†Œ์…œ ๊ณ„์ • ์ •๋ณด") data class UserIdentityDto( - @Schema(description = "์†Œ์…œ ๊ณ„์ • ID") val id: Long, - @Schema(description = "์‚ฌ์šฉ์ž ID") val userId: Long, - @Schema(description = "์†Œ์…œ ๋กœ๊ทธ์ธ ์ œ๊ณต์ž") val provider: String, - @Schema(description = "์ œ๊ณต์ž ์‚ฌ์šฉ์ž ID") val providerUserId: String, - @Schema(description = "์ƒ์„ฑ ์ผ์‹œ (epoch milliseconds)") val createdAt: Long, ) { constructor(identity: UserIdentity) : this( diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 7fefbb20..473a1ff9 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -95,6 +95,13 @@ aws: server: forward-headers-strategy: framework +springdoc: + api-docs: + enabled: false + swagger-ui: + url: /docs/openapi.yaml + disable-swagger-default-url: true + --- spring: config: diff --git a/src/main/resources/static/docs/openapi.yaml b/src/main/resources/static/docs/openapi.yaml new file mode 100644 index 00000000..cdfaeb8b --- /dev/null +++ b/src/main/resources/static/docs/openapi.yaml @@ -0,0 +1,1181 @@ +openapi: 3.0.1 +info: + title: Moiming - Event Schedule Management System API + description: ๋ชจ์ž„ ์ผ์ • ๊ด€๋ฆฌ ์‹œ์Šคํ…œ '๋ชจ์ด๋ฐ' API ๋ฌธ์„œ + version: "1.0" +servers: +- url: http://localhost:8080 + description: Generated server url +tags: +- name: Event + description: ์ด๋ฒคํŠธ ๊ด€๋ฆฌ API +- name: Registration + description: ์‹ ์ฒญ API +- name: Auth + description: ์ธ์ฆ API +- name: User + description: ์‚ฌ์šฉ์ž API +- name: Image + description: ์ด๋ฏธ์ง€ API +paths: + /api/events/{publicId}: + get: + tags: + - Event + summary: ์ด๋ฒคํŠธ ์ƒ์„ธ ์กฐํšŒ + description: ์ด๋ฒคํŠธ ์ƒ์„ธ ์ •๋ณด๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค + parameters: + - name: publicId + in: path + required: true + schema: + type: string + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/EventDetailResponse" + put: + tags: + - Event + summary: ์ด๋ฒคํŠธ ์ˆ˜์ • + description: ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + parameters: + - name: publicId + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateEventRequest" + required: true + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/UpdateEventResponse" + "401": + description: ์ธ์ฆ ํ•„์š” + delete: + tags: + - Event + summary: ์ด๋ฒคํŠธ ์‚ญ์ œ + description: ์ด๋ฒคํŠธ๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + parameters: + - name: publicId + in: path + required: true + schema: + type: string + responses: + "204": + description: No Content + "401": + description: ์ธ์ฆ ํ•„์š” + /api/images: + post: + tags: + - Image + summary: ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ + description: ์„œ๋ฒ„ ์ €์žฅ์†Œ์— ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. + parameters: + - name: prefix + in: query + description: ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•  ์ƒ์œ„ ๊ฒฝ๋กœ + required: false + schema: + type: string + requestBody: + content: + multipart/form-data: + schema: + required: + - image + type: object + properties: + image: + type: string + format: binary + responses: + "401": + description: ์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ) + content: + '*/*': + schema: + $ref: "#/components/schemas/ImageUploadResponse" + "200": + description: ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์„ฑ๊ณต + content: + '*/*': + schema: + $ref: "#/components/schemas/ImageUploadResponse" + "400": + description: ์ž˜๋ชป๋œ ์š”์ฒญ (ํŒŒ์ผ ๋ˆ„๋ฝ/ํ˜•์‹ ์˜ค๋ฅ˜ ๋“ฑ) + content: + '*/*': + schema: + $ref: "#/components/schemas/ImageUploadResponse" + /api/events: + post: + tags: + - Event + summary: ์ด๋ฒคํŠธ ์ƒ์„ฑ + description: ์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateEventRequest" + required: true + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateEventResponse" + "401": + description: ์ธ์ฆ ํ•„์š” + /api/events/{eventId}/registrations: + get: + tags: + - Registration + summary: ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ + description: ํŠน์ • ์ด๋ฒคํŠธ์— ์†ํ•œ ์‹ ์ฒญ ๋ชฉ๋ก์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ์‹ ์ฒญ ์ƒํƒœ(CONFIRMED/WAITLISTED/BANNED)์™€ ์‹ ์ฒญ + ์‹œ๊ฐ์„ ํฌํ•จํ•ด ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + parameters: + - name: eventId + in: path + required: true + schema: + type: string + - name: status + in: query + required: false + schema: + type: string + - name: orderBy + in: query + required: false + schema: + type: string + - name: cursor + in: query + description: ๋‹ค์Œ ํŽ˜์ด์ง€ ์‹œ์ž‘ offset (์—†์œผ๋ฉด 0๋ถ€ํ„ฐ) + required: false + schema: + type: integer + format: int32 + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/GetEventRegistrationsResponse" + post: + tags: + - Registration + summary: ์ด๋ฒคํŠธ ์ฐธ์—ฌ ์‹ ์ฒญ + description: "ํŠน์ • ์ด๋ฒคํŠธ์— ์‹ ์ฒญํ•ฉ๋‹ˆ๋‹ค. ์ •์›์ด ๋‚จ์•„์žˆ์œผ๋ฉด CONFIRMED๋กœ ๋“ฑ๋ก๋˜๊ณ , ์ •์›์ด ์ฐผ์œผ๋‚˜ ๋Œ€๊ธฐ ๋ช…๋‹จ์ด ํ—ˆ์šฉ๋œ ๊ฒฝ\ + ์šฐ WAITLISTED๋กœ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค. ์ •์›์ด ์ฐผ๊ณ  ๋Œ€๊ธฐ ๋ช…๋‹จ์ด ๋น„ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ ์‹ ์ฒญ์ด ๊ฑฐ์ ˆ๋ฉ๋‹ˆ๋‹ค." + parameters: + - name: eventId + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateRegistrationRequest" + required: true + responses: + "200": + description: ์‹ ์ฒญ ์„ฑ๊ณต + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateRegistrationResponse" + "409": + description: "์‹ ์ฒญ ๋ถˆ๊ฐ€: 3001(Registration already exists), 3005(Host cannot\ + \ register), 2301(Event is full)" + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateRegistrationResponse" + "400": + description: "์œ ํšจํ•˜์ง€ ์•Š์€ ์š”์ฒญ: 3003(Wrong guest name), 3004(Wrong guest email),\ + \ 2204(Invalid registration window)" + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateRegistrationResponse" + "403": + description: "๊ถŒํ•œ ์—†์Œ: 3006(Banned user cannot register)" + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateRegistrationResponse" + "404": + description: "์ด๋ฒคํŠธ ์—†์Œ: 2001(Event not found)" + content: + '*/*': + schema: + $ref: "#/components/schemas/CreateRegistrationResponse" + /api/auth/social: + post: + tags: + - Auth + summary: ์†Œ์…œ ๋กœ๊ทธ์ธ + description: ์†Œ์…œ ๋กœ๊ทธ์ธ์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/SocialLoginRequest" + required: true + responses: + "200": + description: ์†Œ์…œ ๋กœ๊ทธ์ธ ์„ฑ๊ณต + content: + '*/*': + schema: + $ref: "#/components/schemas/LoginResponse" + "409": + description: ์ด๋ฏธ ๊ฐ€์ž…๋œ ์ด๋ฉ”์ผ + content: + '*/*': + schema: + $ref: "#/components/schemas/LoginResponse" + "401": + description: ์ธ์ฆ ์‹คํŒจ + content: + '*/*': + schema: + $ref: "#/components/schemas/LoginResponse" + /api/auth/signup: + post: + tags: + - Auth + summary: ์ด๋ฉ”์ผ ํšŒ์›๊ฐ€์ž… + description: ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์ธ์ฆ ์ด๋ฉ”์ผ์„ ๋ฐœ์†กํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฉ”์ผ ์ธ์ฆ ํ›„ ๊ฐ€์ž…์ด ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค. + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/SignupRequest" + required: true + responses: + "409": + description: ์ด๋ฏธ ์กด์žฌํ•˜๋Š” email + "204": + description: ์ธ์ฆ ์ด๋ฉ”์ผ ๋ฐœ์†ก ์„ฑ๊ณต + "400": + description: ์ž˜๋ชป๋œ ์š”์ฒญ (์œ ํšจํ•˜์ง€ ์•Š์€ email/password/name) + "503": + description: ์ด๋ฉ”์ผ ์„œ๋น„์Šค ์žฅ์•  + /api/auth/logout: + post: + tags: + - Auth + summary: ๋กœ๊ทธ์•„์›ƒ + description: ํ˜„์žฌ JWT ํ† ํฐ์„ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•˜์—ฌ ๋กœ๊ทธ์•„์›ƒํ•ฉ๋‹ˆ๋‹ค + responses: + "204": + description: ๋กœ๊ทธ์•„์›ƒ ์„ฑ๊ณต + /api/auth/login: + post: + tags: + - Auth + summary: ๋กœ๊ทธ์ธ + description: email๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ JWT ํ† ํฐ์„ ๋ฐœ๊ธ‰๋ฐ›์Šต๋‹ˆ๋‹ค + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/LoginRequest" + required: true + responses: + "401": + description: ์ธ์ฆ ์‹คํŒจ + content: + '*/*': + schema: + $ref: "#/components/schemas/LoginResponse" + "200": + description: "๋กœ๊ทธ์ธ ์„ฑ๊ณต, JWT ํ† ํฐ ๋ฐ˜ํ™˜" + content: + '*/*': + schema: + $ref: "#/components/schemas/LoginResponse" + /api/auth/email-verification/{verificationCode}: + post: + tags: + - Auth + summary: ์ด๋ฉ”์ผ ์ธ์ฆ + description: ์ด๋ฉ”์ผ๋กœ ๋ฐ›์€ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  ํšŒ์›๊ฐ€์ž…์„ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค + parameters: + - name: verificationCode + in: path + required: true + schema: + type: string + responses: + "400": + description: ์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋งŒ๋ฃŒ๋œ ์ธ์ฆ ์ฝ”๋“œ + "200": + description: "์ธ์ฆ ์„ฑ๊ณต, ์œ ์ € ๋“ฑ๋ก ์™„๋ฃŒ" + /api/users/me: + get: + tags: + - User + summary: ๋ณธ์ธ ์ •๋ณด ์กฐํšŒ + description: ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + responses: + "401": + description: ์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ) + content: + '*/*': + schema: + $ref: "#/components/schemas/UserDto" + "200": + description: ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ ์„ฑ๊ณต + content: + '*/*': + schema: + $ref: "#/components/schemas/UserDto" + patch: + tags: + - User + summary: ๋ณธ์ธ ์ •๋ณด ์ˆ˜์ • + description: ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PatchMeRequest" + required: true + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/UserDto" + "401": + description: ์ธ์ฆ ํ•„์š” + /api/registrations/{registrationId}: + get: + tags: + - Registration + summary: ์‹ ์ฒญ ๋‹จ๊ฑด ์ •๋ณด ์š”์ฒญ + description: ์‹ ์ฒญ ๋‹จ๊ฑด์˜ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + parameters: + - name: registrationId + in: path + required: true + schema: + type: string + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/GetRegistrationResponse" + delete: + tags: + - Registration + summary: ์‹ ์ฒญ ๋‹จ๊ฑด ์ทจ์†Œ + description: ์‹ ์ฒญ ๋‹จ๊ฑด ๋ฆฌ์†Œ์Šค๋ฅผ ์ทจ์†Œํ•ฉ๋‹ˆ๋‹ค. + parameters: + - name: registrationId + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DeleteRegistrationRequest" + required: true + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/DeleteRegistrationResponse" + patch: + tags: + - Registration + summary: ์‹ ์ฒญ ๋‹จ๊ฑด ์ƒํƒœ ๋ณ€๊ฒฝ + description: ์‹ ์ฒญ ๋‹จ๊ฑด ๋ฆฌ์†Œ์Šค์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋ณธ์ธ์˜ ์‹ ์ฒญ์„ ์ทจ์†Œํ•˜๋Š” ๊ฒฝ์šฐ์™€ ๊ด€๋ฆฌ์ž๊ฐ€ ๊ฐ•์ œ ์ทจ์†Œ/๋ฐด ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ + ๋กœ์ง ๋ ˆ๋ฒจ์—์„œ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. + parameters: + - name: registrationId + in: path + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateRegistrationStatusRequest" + required: true + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/PatchRegistrationResponse" + /api/registrations/me: + get: + tags: + - Registration + summary: ๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ + description: ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ์ตœ์‹  ์‹ ์ฒญ ์ˆœ์œผ๋กœ ๋ฐ˜ํ™˜๋˜๋ฉฐ page/size๋กœ ํŽ˜์ด์ง•ํ•ฉ๋‹ˆ๋‹ค. + security: + - bearerAuth: [] + parameters: + - name: page + in: query + required: false + schema: + type: integer + format: int32 + default: 0 + - name: size + in: query + required: false + schema: + type: integer + format: int32 + default: 20 + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/GetMyRegistrationsResponse" + "401": + description: ์ธ์ฆ ํ•„์š” + /api/events/me: + get: + tags: + - Event + summary: ๋‚ด๊ฐ€ ๋งŒ๋“  ์ด๋ฒคํŠธ ๋ชฉ๋ก ์กฐํšŒ (๋ฌดํ•œ ์Šคํฌ๋กค) + description: ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ์„ฑํ•œ ์ด๋ฒคํŠธ ๋ชฉ๋ก์„ ๋ฌดํ•œ ์Šคํฌ๋กค ๋ฐฉ์‹(cursor)์œผ๋กœ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค + security: + - bearerAuth: [] + parameters: + - name: cursor + in: query + required: false + schema: + type: string + format: date-time + - name: size + in: query + required: false + schema: + type: integer + format: int32 + default: 5 + responses: + "200": + description: OK + content: + '*/*': + schema: + $ref: "#/components/schemas/MyEventsInfiniteResponse" + "401": + description: ์ธ์ฆ ํ•„์š” +components: + schemas: + UpdateEventRequest: + type: object + properties: + title: + type: string + description: ์ด๋ฒคํŠธ ์ œ๋ชฉ + example: ์ •๊ธฐ ๋ชจ์ž„ + description: + type: string + description: ์ด๋ฒคํŠธ ์„ค๋ช… + example: ์ •๊ธฐ ๋ชจ์ž„์ž…๋‹ˆ๋‹ค + location: + type: string + description: ์žฅ์†Œ + example: ๊ฐ•์˜์‹ค 101 + startsAt: + type: string + description: ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T18:00:00Z + endsAt: + type: string + description: ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T20:00:00Z + capacity: + type: integer + description: ์ •์› + format: int32 + example: 30 + waitlistEnabled: + type: boolean + description: ๋Œ€๊ธฐ ๋ช…๋‹จ ์‚ฌ์šฉ ์—ฌ๋ถ€ + example: true + registrationStartsAt: + type: string + description: ์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T17:00:00Z + registrationEndsAt: + type: string + description: ์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T17:30:00Z + description: ์ผ์ • ์ˆ˜์ • ์š”์ฒญ + UpdateEventResponse: + required: + - registrationEndsAt + - title + - waitlistEnabled + type: object + properties: + title: + type: string + description: + type: string + location: + type: string + startsAt: + type: string + format: date-time + endsAt: + type: string + format: date-time + capacity: + type: integer + format: int32 + waitlistEnabled: + type: boolean + registrationStartsAt: + type: string + format: date-time + registrationEndsAt: + type: string + format: date-time + ImageUploadResponse: + required: + - key + - url + type: object + properties: + key: + type: string + url: + type: string + CreateEventRequest: + required: + - capacity + - registrationEndsAt + - title + - waitlistEnabled + type: object + properties: + title: + type: string + description: ์ด๋ฒคํŠธ ์ œ๋ชฉ + example: ์ •๊ธฐ ๋ชจ์ž„ + description: + type: string + description: ์ด๋ฒคํŠธ ์„ค๋ช… + example: ์ •๊ธฐ ๋ชจ์ž„์ž…๋‹ˆ๋‹ค + location: + type: string + description: ์žฅ์†Œ + example: ๊ฐ•์˜์‹ค 101 + startsAt: + type: string + description: ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T18:00:00Z + endsAt: + type: string + description: ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T20:00:00Z + capacity: + type: integer + description: ์ •์› + format: int32 + example: 30 + waitlistEnabled: + type: boolean + description: ๋Œ€๊ธฐ ๋ช…๋‹จ ์‚ฌ์šฉ ์—ฌ๋ถ€ + example: true + registrationStartsAt: + type: string + description: ์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601). null์ธ ๊ฒฝ์šฐ ์š”์ฒญ ์‹œ์ ์œผ๋กœ ์ž๋™ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. + format: date-time + example: 2026-02-02T17:00:00Z + registrationEndsAt: + type: string + description: ์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T17:30:00Z + description: ์ผ์ • ์ƒ์„ฑ ์š”์ฒญ + CreateEventResponse: + required: + - publicId + type: object + properties: + publicId: + type: string + CreateRegistrationRequest: + type: object + properties: + guestName: + type: string + description: ๋น„ํšŒ์› ์ด๋ฆ„ + guestEmail: + type: string + description: ๋น„ํšŒ์› ์ด๋ฉ”์ผ + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์š”์ฒญ + CreateRegistrationResponse: + required: + - registrationPublicId + type: object + properties: + registrationPublicId: + type: string + description: ์‹ ์ฒญ id + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์‘๋‹ต + SocialLoginRequest: + required: + - code + - provider + type: object + properties: + provider: + type: string + description: ์†Œ์…œ๋กœ๊ทธ์ธ ์ œ๊ณต์ž + example: GOOGLE + code: + type: string + description: ์ธ๊ฐ€ ์ฝ”๋“œ (authorization code) + description: ์†Œ์…œ ๋กœ๊ทธ์ธ ์š”์ฒญ + LoginResponse: + required: + - token + type: object + properties: + token: + type: string + SignupRequest: + required: + - email + - name + - password + type: object + properties: + email: + type: string + description: ์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ + example: user@example.com + name: + type: string + description: ์‚ฌ์šฉ์ž ์ด๋ฆ„ + example: ํ™๊ธธ๋™ + password: + type: string + description: ๋น„๋ฐ€๋ฒˆํ˜ธ + example: password123 + profileImage: + type: string + description: ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL + example: https://cdn.example.com/profile.png + description: ํšŒ์›๊ฐ€์ž… ์š”์ฒญ + LoginRequest: + required: + - email + - password + type: object + properties: + email: + type: string + description: ์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ + example: user@example.com + password: + type: string + description: ์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ + example: mypassword + description: ๋กœ๊ทธ์ธ ์š”์ฒญ + PatchMeRequest: + type: object + properties: + name: + type: string + email: + type: string + password: + type: string + profileImage: + type: string + UserDto: + required: + - email + - id + - name + type: object + properties: + id: + type: integer + format: int64 + email: + type: string + name: + type: string + profileImage: + type: string + UpdateRegistrationStatusRequest: + type: object + properties: + status: + type: string + enum: + - HOST + - CONFIRMED + - WAITLISTED + - BANNED + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์ƒํƒœ ๋ณ€๊ฒฝ ์š”์ฒญ + PatchRegistrationResponse: + type: object + properties: + patchEmail: + type: string + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์ƒํƒœ ๋ณ€๊ฒฝ + GetRegistrationResponse: + required: + - guestName + - registrationPublicId + - reservationEmail + - status + - waitlistPosition + type: object + properties: + status: + type: string + enum: + - HOST + - CONFIRMED + - WAITLISTED + - BANNED + guestName: + type: string + waitlistPosition: + type: integer + format: int32 + registrationPublicId: + type: string + reservationEmail: + type: string + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์ •๋ณด ์š”์ฒญ ์‘๋‹ต + GetMyRegistrationsResponse: + required: + - registrations + type: object + properties: + registrations: + type: array + description: ์‹ ์ฒญ ๋ชฉ๋ก + items: + $ref: "#/components/schemas/MyRegistrationItem" + description: ๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์‘๋‹ต + MyRegistrationItem: + required: + - publicId + - registrationCnt + - status + - title + type: object + properties: + publicId: + type: string + description: ์ด๋ฒคํŠธ ๊ณต๊ฐœ ID + title: + type: string + description: ์ด๋ฒคํŠธ ์ œ๋ชฉ + startsAt: + type: string + description: ์ด๋ฒคํŠธ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + endsAt: + type: string + description: ์ด๋ฒคํŠธ ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + registrationStartsAt: + type: string + description: ์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + registrationEndsAt: + type: string + description: ์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + capacity: + type: integer + description: ์ •์› + format: int32 + registrationCnt: + type: integer + description: ํ˜„์žฌ ์‹ ์ฒญ ์ˆ˜ + ๋Œ€๊ธฐ ์ˆ˜ + format: int32 + status: + type: string + description: ์‹ ์ฒญ ์ƒํƒœ + enum: + - CONFIRMED + - WAITLISTED + - BANNED + waitlistedNum: + type: integer + description: ๋Œ€๊ธฐ ์ˆœ๋ฒˆ (WAITLISTED๊ฐ€ ์•„๋‹ˆ๋ฉด null) + format: int32 + description: ๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ์š”์•ฝ + CapabilitiesInfo: + required: + - apply + - cancel + - shareLink + - wait + type: object + properties: + shareLink: + type: boolean + description: ๊ณต์œ  ๋งํฌ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ + example: false + apply: + type: boolean + description: ์ฐธ์—ฌ ์‹ ์ฒญ ๊ฐ€๋Šฅ ์—ฌ๋ถ€(ํ™•์ • ์ž๋ฆฌ ์‹ ์ฒญ) + example: false + wait: + type: boolean + description: ๋Œ€๊ธฐ ์‹ ์ฒญ ๊ฐ€๋Šฅ ์—ฌ๋ถ€(์ •์› ์ฐผ์„ ๋•Œ) + example: false + cancel: + type: boolean + description: ์‹ ์ฒญ ์ทจ์†Œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ + example: true + description: ๊ฐ€๋Šฅํ•œ ๋™์ž‘ ๋ธ”๋ก + CreatorInfo: + required: + - email + - name + type: object + properties: + name: + type: string + description: ์ด๋ฆ„ + example: ํ™๊ธธ๋™ + email: + type: string + description: ์ด๋ฉ”์ผ + example: user@example.com + profileImage: + type: string + description: ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ + nullable: true + example: https://example.com/profile.png + description: ์ƒ์„ฑ์ž ์ •๋ณด ๋ธ”๋ก + EventDetailResponse: + required: + - capabilities + - creator + - event + - guestsPreview + - viewer + type: object + properties: + event: + $ref: "#/components/schemas/EventInfo" + creator: + $ref: "#/components/schemas/CreatorInfo" + viewer: + $ref: "#/components/schemas/ViewerInfo" + capabilities: + $ref: "#/components/schemas/CapabilitiesInfo" + guestsPreview: + type: array + description: ์ฐธ์—ฌ์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ชฉ๋ก + items: + $ref: "#/components/schemas/GuestPreview" + description: ์ผ์ • ์ƒ์„ธ ์กฐํšŒ ์‘๋‹ต + EventInfo: + required: + - publicId + - registrationEndsAt + - title + - totalApplicants + type: object + properties: + publicId: + type: string + description: ์ด๋ฒคํŠธ publicId + example: dj8sadj10djnkas + title: + type: string + description: ์ด๋ฒคํŠธ ์ œ๋ชฉ + example: ์ œ2ํšŒ ๊ธฐํš ์„ธ๋ฏธ๋‚˜ + description: + type: string + description: ์ด๋ฒคํŠธ ์„ค๋ช… + nullable: true + example: ์ผ์ • ์ƒ์„ธ ์„ค๋ช…... + location: + type: string + description: ์žฅ์†Œ + nullable: true + example: ์„œ์šธ๋Œ€ + startsAt: + type: string + description: ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + nullable: true + example: 2026-02-02T18:00:00Z + endsAt: + type: string + description: ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + nullable: true + example: 2026-02-02T20:00:00Z + capacity: + type: integer + description: ์ •์› + format: int32 + nullable: true + example: 10 + totalApplicants: + type: integer + description: ์ด ์‹ ์ฒญ์ž ์ˆ˜(ํ™•์ •+๋Œ€๊ธฐ ๋“ฑ) + format: int32 + example: 8 + registrationStartsAt: + type: string + description: ์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + nullable: true + example: 2026-02-02T17:00:00Z + registrationEndsAt: + type: string + description: ์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601) + format: date-time + example: 2026-02-02T17:00:00Z + description: ์ด๋ฒคํŠธ ์ •๋ณด ๋ธ”๋ก + GuestPreview: + required: + - name + type: object + properties: + id: + type: integer + description: ์ฐธ์—ฌ์ž ID (๋น„ํšŒ์›์ด๋ฉด null) + format: int64 + nullable: true + example: 1 + name: + type: string + description: ์ฐธ์—ฌ์ž ์ด๋ฆ„ + example: ํ™๊ธธ๋™ + profileImage: + type: string + description: ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL + nullable: true + example: https://example.com/profile.png + description: ์ฐธ์—ฌ์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ •๋ณด + ViewerInfo: + required: + - status + type: object + properties: + status: + type: string + description: ์ด๋ฒคํŠธ ์กฐํšŒ์ž(Viewer)์˜ ์ƒํƒœ + example: WAITLISTED + enum: + - HOST + - CONFIRMED + - WAITLISTED + - BANNED + - NONE + name: + type: string + description: viewer ์ด๋ฆ„ (๋น„ํšŒ์›์ด๋ฉด null) + nullable: true + example: ํ™๊ธธ๋™ + waitlistPosition: + type: integer + description: "๋Œ€๊ธฐ ์ˆœ๋ฒˆ (WAITLISTED์ผ ๋•Œ๋งŒ ์ˆซ์ž, ์•„๋‹ˆ๋ฉด null)" + format: int32 + nullable: true + example: 3 + registrationPublicId: + type: string + description: "registrationPublicId (๊ฒŒ์ŠคํŠธ๋ฉด ๊ฐ’, ์•„๋‹ˆ๋ฉด null)" + nullable: true + example: "1" + reservationEmail: + type: string + description: "์˜ˆ์•ฝ ์ด๋ฉ”์ผ(๊ฒŒ์ŠคํŠธ๋ฉด guestEmail, ๋กœ๊ทธ์ธ ์œ ์ €๋ฉด user email ๋“ฑ ์ •์ฑ…์— ๋”ฐ๋ฆ„)" + nullable: true + example: skdfsj@gmaldkl + description: ์กฐํšŒ์ž(viewer) ์ •๋ณด ๋ธ”๋ก + EventRegistrationItem: + required: + - createdAt + - name + - registrationId + - status + type: object + properties: + registrationId: + type: string + description: ์‹ ์ฒญ ๊ณต๊ฐœ ID + name: + type: string + description: ์ด๋ฆ„ + email: + type: string + description: ์ด๋ฉ”์ผ (๊ด€๋ฆฌ์ž ์š”์ฒญ ์‹œ ๋…ธ์ถœ) + profileImage: + type: string + description: ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL + createdAt: + type: string + description: ์‹ ์ฒญ ์ผ์‹œ + format: date-time + status: + type: string + description: ์‹ ์ฒญ ์ƒํƒœ + enum: + - HOST + - CONFIRMED + - WAITLISTED + - BANNED + waitingNum: + type: integer + description: ๋Œ€๊ธฐ ์ˆœ๋ฒˆ (status๊ฐ€ WAITLISTED์ผ ๋•Œ๋งŒ ์•„๋‹ˆ๋ฉด null) + format: int32 + description: ์‹ ์ฒญ์ž ์ •๋ณด + GetEventRegistrationsResponse: + required: + - hasNext + - participants + type: object + properties: + participants: + type: array + description: ์‹ ์ฒญ์ž ๋ชฉ๋ก + items: + $ref: "#/components/schemas/EventRegistrationItem" + totalCount: + type: integer + description: ํ•„ํ„ฐ์— ๋”ฐ๋ผ ๋ณ€ํ•˜๋Š” ์ฐธ์—ฌ์ž ์ˆ˜ + format: int32 + nextCursor: + type: integer + description: ๋‹ค์Œ ํŽ˜์ด์ง€ ์‹œ์ž‘ offset (์—†์œผ๋ฉด null) + format: int32 + hasNext: + type: boolean + description: ๋‹ค์Œ ํŽ˜์ด์ง€ ์กด์žฌ ์—ฌ๋ถ€ + description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ ์‘๋‹ต + MyEventResponse: + required: + - publicId + - registrationEndsAt + - title + - totalApplicants + type: object + properties: + publicId: + type: string + title: + type: string + startsAt: + type: string + format: date-time + endsAt: + type: string + format: date-time + registrationStartsAt: + type: string + format: date-time + registrationEndsAt: + type: string + format: date-time + capacity: + type: integer + format: int32 + totalApplicants: + type: integer + format: int32 + MyEventsInfiniteResponse: + required: + - events + - hasNext + type: object + properties: + events: + type: array + items: + $ref: "#/components/schemas/MyEventResponse" + nextCursor: + type: string + format: date-time + hasNext: + type: boolean + DeleteRegistrationRequest: + type: object + properties: + guestName: + type: string + description: ๋น„ํšŒ์› ์ด๋ฆ„ + guestEmail: + type: string + description: ๋น„ํšŒ์› ์ด๋ฉ”์ผ + description: ์ด๋ฒคํŠธ ์ทจ์†Œ ์š”์ฒญ + DeleteRegistrationResponse: + type: object + securitySchemes: + bearerAuth: + type: http + description: JWT ํ† ํฐ์„ ์ž…๋ ฅํ•˜์„ธ์š” + name: bearerAuth + scheme: bearer + bearerFormat: JWT diff --git a/src/main/resources/static/docs/swagger-ui.html b/src/main/resources/static/docs/swagger-ui.html new file mode 100644 index 00000000..517735db --- /dev/null +++ b/src/main/resources/static/docs/swagger-ui.html @@ -0,0 +1,36 @@ + + + + + + MoiMing API Docs + + + + +
+ + + + + From bd0c580f019074351099b9e8f766889f849c4811 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 18 Apr 2026 22:18:27 +0900 Subject: [PATCH 03/27] =?UTF-8?q?:memo:=20swagger=20=EB=B6=88=EC=9D=BC?= =?UTF-8?q?=EC=B9=98=20=EB=B6=80=EB=B6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/static/docs/openapi.yaml | 125 ++++++++++++++++---- 1 file changed, 99 insertions(+), 26 deletions(-) diff --git a/src/main/resources/static/docs/openapi.yaml b/src/main/resources/static/docs/openapi.yaml index cdfaeb8b..6fa1daac 100644 --- a/src/main/resources/static/docs/openapi.yaml +++ b/src/main/resources/static/docs/openapi.yaml @@ -108,12 +108,6 @@ paths: type: string format: binary responses: - "401": - description: ์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ) - content: - '*/*': - schema: - $ref: "#/components/schemas/ImageUploadResponse" "200": description: ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์„ฑ๊ณต content: @@ -125,7 +119,13 @@ paths: content: '*/*': schema: - $ref: "#/components/schemas/ImageUploadResponse" + $ref: "#/components/schemas/ErrorResponse" + "401": + description: ์ธ์ฆ ์‹คํŒจ (์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ) + content: + '*/*': + schema: + $ref: "#/components/schemas/ErrorResponse" /api/events: post: tags: @@ -212,31 +212,29 @@ paths: schema: $ref: "#/components/schemas/CreateRegistrationResponse" "409": - description: "์‹ ์ฒญ ๋ถˆ๊ฐ€: 3001(Registration already exists), 3005(Host cannot\ - \ register), 2301(Event is full)" + description: "์‹ ์ฒญ ๋ถˆ๊ฐ€: REGISTRATION_ALREADY_EXISTS, REGISTRATION_BLOCKED_HOST, EVENT_FULL" content: '*/*': schema: - $ref: "#/components/schemas/CreateRegistrationResponse" + $ref: "#/components/schemas/ErrorResponse" "400": - description: "์œ ํšจํ•˜์ง€ ์•Š์€ ์š”์ฒญ: 3003(Wrong guest name), 3004(Wrong guest email),\ - \ 2204(Invalid registration window)" + description: "์œ ํšจํ•˜์ง€ ์•Š์€ ์š”์ฒญ: REGISTRATION_WRONG_NAME, REGISTRATION_WRONG_EMAIL, NOT_WITHIN_REGISTRATION_WINDOW" content: '*/*': schema: - $ref: "#/components/schemas/CreateRegistrationResponse" + $ref: "#/components/schemas/ErrorResponse" "403": - description: "๊ถŒํ•œ ์—†์Œ: 3006(Banned user cannot register)" + description: "๊ถŒํ•œ ์—†์Œ: REGISTRATION_BLOCKED_BANNED" content: '*/*': schema: - $ref: "#/components/schemas/CreateRegistrationResponse" + $ref: "#/components/schemas/ErrorResponse" "404": - description: "์ด๋ฒคํŠธ ์—†์Œ: 2001(Event not found)" + description: "์ด๋ฒคํŠธ ์—†์Œ: EVENT_NOT_FOUND" content: '*/*': schema: - $ref: "#/components/schemas/CreateRegistrationResponse" + $ref: "#/components/schemas/ErrorResponse" /api/auth/social: post: tags: @@ -261,13 +259,13 @@ paths: content: '*/*': schema: - $ref: "#/components/schemas/LoginResponse" + $ref: "#/components/schemas/ErrorResponse" "401": description: ์ธ์ฆ ์‹คํŒจ content: '*/*': schema: - $ref: "#/components/schemas/LoginResponse" + $ref: "#/components/schemas/ErrorResponse" /api/auth/signup: post: tags: @@ -316,7 +314,7 @@ paths: content: '*/*': schema: - $ref: "#/components/schemas/LoginResponse" + $ref: "#/components/schemas/ErrorResponse" "200": description: "๋กœ๊ทธ์ธ ์„ฑ๊ณต, JWT ํ† ํฐ ๋ฐ˜ํ™˜" content: @@ -354,7 +352,7 @@ paths: content: '*/*': schema: - $ref: "#/components/schemas/UserDto" + $ref: "#/components/schemas/ErrorResponse" "200": description: ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ ์„ฑ๊ณต content: @@ -522,43 +520,52 @@ components: title: type: string description: ์ด๋ฒคํŠธ ์ œ๋ชฉ + nullable: true example: ์ •๊ธฐ ๋ชจ์ž„ description: type: string description: ์ด๋ฒคํŠธ ์„ค๋ช… + nullable: true example: ์ •๊ธฐ ๋ชจ์ž„์ž…๋‹ˆ๋‹ค location: type: string description: ์žฅ์†Œ + nullable: true example: ๊ฐ•์˜์‹ค 101 startsAt: type: string description: ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) format: date-time + nullable: true example: 2026-02-02T18:00:00Z endsAt: type: string description: ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601) format: date-time + nullable: true example: 2026-02-02T20:00:00Z capacity: type: integer description: ์ •์› format: int32 + nullable: true example: 30 waitlistEnabled: type: boolean description: ๋Œ€๊ธฐ ๋ช…๋‹จ ์‚ฌ์šฉ ์—ฌ๋ถ€ + nullable: true example: true registrationStartsAt: type: string description: ์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) format: date-time + nullable: true example: 2026-02-02T17:00:00Z registrationEndsAt: type: string description: ์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601) format: date-time + nullable: true example: 2026-02-02T17:30:00Z description: ์ผ์ • ์ˆ˜์ • ์š”์ฒญ UpdateEventResponse: @@ -572,22 +579,28 @@ components: type: string description: type: string + nullable: true location: type: string + nullable: true startsAt: type: string format: date-time + nullable: true endsAt: type: string format: date-time + nullable: true capacity: type: integer format: int32 + nullable: true waitlistEnabled: type: boolean registrationStartsAt: type: string format: date-time + nullable: true registrationEndsAt: type: string format: date-time @@ -616,20 +629,24 @@ components: description: type: string description: ์ด๋ฒคํŠธ ์„ค๋ช… + nullable: true example: ์ •๊ธฐ ๋ชจ์ž„์ž…๋‹ˆ๋‹ค location: type: string description: ์žฅ์†Œ + nullable: true example: ๊ฐ•์˜์‹ค 101 startsAt: type: string description: ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) format: date-time + nullable: true example: 2026-02-02T18:00:00Z endsAt: type: string description: ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601) format: date-time + nullable: true example: 2026-02-02T20:00:00Z capacity: type: integer @@ -644,6 +661,7 @@ components: type: string description: ์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601). null์ธ ๊ฒฝ์šฐ ์š”์ฒญ ์‹œ์ ์œผ๋กœ ์ž๋™ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. format: date-time + nullable: true example: 2026-02-02T17:00:00Z registrationEndsAt: type: string @@ -664,9 +682,11 @@ components: guestName: type: string description: ๋น„ํšŒ์› ์ด๋ฆ„ + nullable: true guestEmail: type: string description: ๋น„ํšŒ์› ์ด๋ฉ”์ผ + nullable: true description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์š”์ฒญ CreateRegistrationResponse: required: @@ -720,6 +740,7 @@ components: profileImage: type: string description: ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL + nullable: true example: https://cdn.example.com/profile.png description: ํšŒ์›๊ฐ€์ž… ์š”์ฒญ LoginRequest: @@ -742,12 +763,16 @@ components: properties: name: type: string + nullable: true email: type: string + nullable: true password: type: string + nullable: true profileImage: type: string + nullable: true UserDto: required: - email @@ -764,11 +789,13 @@ components: type: string profileImage: type: string + nullable: true UpdateRegistrationStatusRequest: type: object properties: status: type: string + nullable: true enum: - HOST - CONFIRMED @@ -780,6 +807,7 @@ components: properties: patchEmail: type: string + nullable: true description: ์ด๋ฒคํŠธ ์‹ ์ฒญ ์ƒํƒœ ๋ณ€๊ฒฝ GetRegistrationResponse: required: @@ -836,22 +864,27 @@ components: type: string description: ์ด๋ฒคํŠธ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) format: date-time + nullable: true endsAt: type: string description: ์ด๋ฒคํŠธ ์ข…๋ฃŒ ์‹œ๊ฐ„ (ISO-8601) format: date-time + nullable: true registrationStartsAt: type: string description: ์‹ ์ฒญ ์‹œ์ž‘ ์‹œ๊ฐ„ (ISO-8601) format: date-time + nullable: true registrationEndsAt: type: string description: ์‹ ์ฒญ ๋งˆ๊ฐ ์‹œ๊ฐ„ (ISO-8601) format: date-time + nullable: true capacity: type: integer description: ์ •์› format: int32 + nullable: true registrationCnt: type: integer description: ํ˜„์žฌ ์‹ ์ฒญ ์ˆ˜ + ๋Œ€๊ธฐ ์ˆ˜ @@ -867,6 +900,7 @@ components: type: integer description: ๋Œ€๊ธฐ ์ˆœ๋ฒˆ (WAITLISTED๊ฐ€ ์•„๋‹ˆ๋ฉด null) format: int32 + nullable: true description: ๋‚ด ์ด๋ฒคํŠธ ์‹ ์ฒญ ์š”์•ฝ CapabilitiesInfo: required: @@ -941,7 +975,8 @@ components: - publicId - registrationEndsAt - title - - totalApplicants + - confirmedCount + - waitlistCount type: object properties: publicId: @@ -980,9 +1015,14 @@ components: format: int32 nullable: true example: 10 - totalApplicants: + confirmedCount: + type: integer + description: ์ฐธ์—ฌ ํ™•์ • ์‹ ์ฒญ์ž ์ˆ˜ + format: int32 + example: 8 + waitlistCount: type: integer - description: ์ด ์‹ ์ฒญ์ž ์ˆ˜(ํ™•์ •+๋Œ€๊ธฐ ๋“ฑ) + description: ๋Œ€๊ธฐ์ž ์ˆ˜ format: int32 example: 8 registrationStartsAt: @@ -1072,9 +1112,11 @@ components: email: type: string description: ์ด๋ฉ”์ผ (๊ด€๋ฆฌ์ž ์š”์ฒญ ์‹œ ๋…ธ์ถœ) + nullable: true profileImage: type: string description: ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL + nullable: true createdAt: type: string description: ์‹ ์ฒญ ์ผ์‹œ @@ -1091,6 +1133,7 @@ components: type: integer description: ๋Œ€๊ธฐ ์ˆœ๋ฒˆ (status๊ฐ€ WAITLISTED์ผ ๋•Œ๋งŒ ์•„๋‹ˆ๋ฉด null) format: int32 + nullable: true description: ์‹ ์ฒญ์ž ์ •๋ณด GetEventRegistrationsResponse: required: @@ -1107,10 +1150,12 @@ components: type: integer description: ํ•„ํ„ฐ์— ๋”ฐ๋ผ ๋ณ€ํ•˜๋Š” ์ฐธ์—ฌ์ž ์ˆ˜ format: int32 + nullable: true nextCursor: type: integer description: ๋‹ค์Œ ํŽ˜์ด์ง€ ์‹œ์ž‘ offset (์—†์œผ๋ฉด null) format: int32 + nullable: true hasNext: type: boolean description: ๋‹ค์Œ ํŽ˜์ด์ง€ ์กด์žฌ ์—ฌ๋ถ€ @@ -1120,7 +1165,8 @@ components: - publicId - registrationEndsAt - title - - totalApplicants + - confirmedCount + - waitlistCount type: object properties: publicId: @@ -1130,19 +1176,26 @@ components: startsAt: type: string format: date-time + nullable: true endsAt: type: string format: date-time + nullable: true registrationStartsAt: type: string format: date-time + nullable: true registrationEndsAt: type: string format: date-time capacity: type: integer format: int32 - totalApplicants: + nullable: true + confirmedCount: + type: integer + format: int32 + waitlistCount: type: integer format: int32 MyEventsInfiniteResponse: @@ -1158,6 +1211,7 @@ components: nextCursor: type: string format: date-time + nullable: true hasNext: type: boolean DeleteRegistrationRequest: @@ -1166,12 +1220,31 @@ components: guestName: type: string description: ๋น„ํšŒ์› ์ด๋ฆ„ + nullable: true guestEmail: type: string description: ๋น„ํšŒ์› ์ด๋ฉ”์ผ + nullable: true description: ์ด๋ฒคํŠธ ์ทจ์†Œ ์š”์ฒญ DeleteRegistrationResponse: type: object + ErrorResponse: + required: + - code + - message + - title + type: object + properties: + code: + type: string + description: ์—๋Ÿฌ ์ฝ”๋“œ + title: + type: string + description: ์—๋Ÿฌ ์ œ๋ชฉ + message: + type: string + description: ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ + description: ์—๋Ÿฌ ์‘๋‹ต securitySchemes: bearerAuth: type: http From 33f66300703b9d476ecf61f3cda116f2b49c477d Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 19:55:45 +0900 Subject: [PATCH 04/27] =?UTF-8?q?:zap:=20=EB=8C=80=EA=B8=B0=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EA=B3=84=EC=82=B0=20=EC=8B=9C=20=EB=AA=A8=EB=93=A0?= =?UTF-8?q?=20=EB=8C=80=EA=B8=B0=20=EC=8B=A0=EC=B2=AD=20=EA=B1=B4=20?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD=20(=EB=A9=94=EB=AA=A8=EB=A6=AC?= =?UTF-8?q?=20=EC=B5=9C=EC=A0=81=ED=99=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/event/service/EventService.kt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt index e52f056d..4275a045 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt @@ -121,17 +121,16 @@ class EventService( .countByEventIdAndStatus(eventID = eventId, registrationStatus = RegistrationStatus.WAITLISTED) .toInt() - val totalApplicants = confirmedCount + waitlistedCount - val waitlistPosition: Int? = if (myReg?.status == RegistrationStatus.WAITLISTED) { - val waitlistedRegs = - registrationRepository.findByEventIdAndStatusOrderByCreatedAtAsc( - eventID = eventId, - registrationStatus = RegistrationStatus.WAITLISTED, - ) - val idx = waitlistedRegs.indexOfFirst { it.id == myReg.id } - if (idx >= 0) idx + 1 else null + registrationRepository + .findWaitlistPositionsByRegistrationPublicIds( + eventId = eventId, + status = RegistrationStatus.WAITLISTED, + registrationPublicIds = listOf(myReg.registrationPublicId), + ).firstOrNull() + ?.waitlistNumber + ?.toInt() } else { null } From adb4a94ab5b6a9ce03d34751b1571b70d4b810d7 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 19:58:35 +0900 Subject: [PATCH 05/27] =?UTF-8?q?:zap:=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=8B=9C=20user=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=ED=9A=9F=EC=88=98=20=EC=A4=84=EC=9D=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring2025/domain/event/service/EventService.kt | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt index 4275a045..762ec817 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt @@ -96,10 +96,9 @@ class EventService( val event = getEventByPublicId(publicId) val eventId = requireNotNull(event.id) { "Event id is null: publicId=$publicId" } - val creatorUser = - userRepository.findById(event.createdBy).orElseThrow { - EventNotFoundException() - } + val userIdsToFetch = listOfNotNull(event.createdBy, requesterId).distinct() + val usersById = userRepository.findAllById(userIdsToFetch).associateBy { it.id!! } + val creatorUser = usersById[event.createdBy] ?: throw EventNotFoundException() val myReg = if (requesterId == null) { @@ -149,10 +148,7 @@ class EventService( } } - val viewerName: String? = - requesterId?.let { - userRepository.findById(it).orElse(null)?.name - } + val viewerName: String? = requesterId?.let { usersById[it]?.name } val viewer = if (viewerStatus == ViewerStatus.NONE) { From f36546d7abb77ffededb83c3a30ea3aee81d1634 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 20:00:57 +0900 Subject: [PATCH 06/27] =?UTF-8?q?:zap:=20guest=20preview=20=EA=B5=AC?= =?UTF-8?q?=EC=84=B1=20=EC=8B=9C=20db=EC=97=90=EC=84=9C=20=EC=B2=98?= =?UTF-8?q?=EC=9D=8C=EB=B6=80=ED=84=B0=205=EA=B1=B4=EB=A7=8C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=20(?= =?UTF-8?q?=EB=A9=94=EB=AA=A8=EB=A6=AC=20=EC=B5=9C=EC=A0=81=ED=99=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring2025/domain/event/service/EventService.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt index 762ec817..e451a6b9 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt @@ -23,6 +23,7 @@ import com.wafflestudio.spring2025.domain.registration.repository.RegistrationRe import com.wafflestudio.spring2025.domain.registration.service.WaitlistReconciliationService import com.wafflestudio.spring2025.domain.user.repository.UserRepository import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Pageable import org.springframework.data.domain.Sort import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -179,18 +180,17 @@ class EventService( registrationEndsAt = event.registrationEndsAt, ) - val confirmedRegs = + val previewRegs = registrationRepository.findByEventIdAndStatusOrderByCreatedAtAsc( eventID = eventId, registrationStatus = RegistrationStatus.CONFIRMED, + pageable = Pageable.ofSize(5), ) - val previewRegs = confirmedRegs.take(5) - val previewUserIds = previewRegs.mapNotNull { it.userId }.distinct() - val usersById = + val previewUsersById = userRepository.findAllById(previewUserIds).associateBy { it.id!! } val guestsPreview = @@ -203,7 +203,7 @@ class EventService( profileImage = null, ) } else { - usersById[uid]?.let { + previewUsersById[uid]?.let { GuestPreview( id = it.id!!, name = it.name, From 4186c111cd27f69f68f75c9c771860c04e47a340 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 20:02:38 +0900 Subject: [PATCH 07/27] =?UTF-8?q?:zap:=20event=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20N+1=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/event/service/EventService.kt | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt index e451a6b9..6392e094 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt @@ -271,19 +271,31 @@ class EventService( val sliced = fetched.take(pageSize) val nextCursor = sliced.lastOrNull()?.createdAt + val eventIds = sliced.map { requireNotNull(it.id) } + + val confirmedCounts = + if (eventIds.isEmpty()) { + emptyMap() + } else { + registrationRepository + .countByEventIdsAndStatuses(eventIds = eventIds, listOf(RegistrationStatus.CONFIRMED)) + .associate { it.eventId to it.totalCount.toInt() } + } + + val waitlistedCounts = + if (eventIds.isEmpty()) { + emptyMap() + } else { + registrationRepository + .countByEventIdsAndStatuses(eventIds = eventIds, listOf(RegistrationStatus.WAITLISTED)) + .associate { it.eventId to it.totalCount.toInt() } + } + val responses = sliced.map { event -> val eventId = requireNotNull(event.id) - - val confirmedCount = - registrationRepository - .countByEventIdAndStatus(eventID = eventId, registrationStatus = RegistrationStatus.CONFIRMED) - .toInt() - - val waitlistedCount = - registrationRepository - .countByEventIdAndStatus(eventID = eventId, registrationStatus = RegistrationStatus.WAITLISTED) - .toInt() + val confirmedCount = confirmedCounts[eventId] ?: 0 + val waitlistedCount = waitlistedCounts[eventId] ?: 0 MyEventResponse( publicId = event.publicId, From 8080f1f0b455e1628e0778847e500ce01db9a70c Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 20:03:53 +0900 Subject: [PATCH 08/27] =?UTF-8?q?:zap:=20event=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=EB=8C=80=EC=83=81=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=8B=9C=20=EC=B2=98=EC=9D=8C=EB=B6=80=ED=84=B0=20CONFIRMED+WA?= =?UTF-8?q?ITLISTED=EB=A7=8C=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring2025/domain/event/service/EventService.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt index 6392e094..7d41b3e9 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/event/service/EventService.kt @@ -385,9 +385,10 @@ class EventService( // ์•Œ๋ฆผ ๋Œ€์ƒ: CONFIRMED + WAITLISTED (BANNED ์ œ์™ธ) val registrationsToNotify = - registrationRepository - .findByEventId(eventId) - .filter { it.status == RegistrationStatus.CONFIRMED || it.status == RegistrationStatus.WAITLISTED } + registrationRepository.findByEventIdAndStatusIn( + eventID = eventId, + statuses = listOf(RegistrationStatus.CONFIRMED, RegistrationStatus.WAITLISTED), + ) // ์ด๋ฉ”์ผ ๋ฐ์ดํ„ฐ ๊ตฌ์„ฑ (์‚ญ์ œ ์ „์— user ์ •๋ณด ์กฐํšŒ) val hostUser = userRepository.findById(event.createdBy).orElse(null) From 2cc448120d04ce50352f7106007cf39cda140776 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 20:04:27 +0900 Subject: [PATCH 09/27] =?UTF-8?q?:zap:=20event=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=BF=BC=EB=A6=AC=20=EC=B5=9C=EC=A0=81=ED=99=94?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=9C=20repository=20method=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../registration/repository/RegistrationRepository.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/repository/RegistrationRepository.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/repository/RegistrationRepository.kt index 5ed64233..3c5afa24 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/repository/RegistrationRepository.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/repository/RegistrationRepository.kt @@ -41,6 +41,11 @@ interface RegistrationRepository : eventId: Long, ): Registration? + fun findByEventIdAndStatusIn( + eventID: Long, + statuses: Collection, + ): List + fun countByEventId(eventID: Long): Long fun countByEventIdAndStatus( @@ -66,6 +71,12 @@ interface RegistrationRepository : registrationStatus: RegistrationStatus, ): List + fun findByEventIdAndStatusOrderByCreatedAtAsc( + eventID: Long, + registrationStatus: RegistrationStatus, + pageable: Pageable, + ): List + @Query( """ SELECT * FROM registrations From 63b791ffd88b15bce982d666ffbb2eb70aea6699 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 20:33:51 +0900 Subject: [PATCH 10/27] =?UTF-8?q?:zap:=20reconcileWaitlist=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=20waitlist=EC=8B=A0=EC=B2=AD=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20(=EB=A9=94=EB=AA=A8=EB=A6=AC=20=EC=B5=9C?= =?UTF-8?q?=EC=A0=81=ED=99=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../registration/service/RegistrationService.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt index a87b211a..a3a8fd01 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt @@ -28,6 +28,7 @@ import com.wafflestudio.spring2025.domain.user.model.User import com.wafflestudio.spring2025.domain.user.repository.UserRepository import org.springframework.dao.DuplicateKeyException import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Pageable import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import org.springframework.transaction.support.TransactionSynchronization @@ -755,23 +756,26 @@ RegistrationService( val available = capacity - confirmed if (available <= 0) return - val waitlistedRegs = + val totalWaitlisted = + registrationRepository.countByEventIdAndStatus(eventId, RegistrationStatus.WAITLISTED).toInt() + + val promoted = registrationRepository.findByEventIdAndStatusOrderByCreatedAtAsc( eventId, RegistrationStatus.WAITLISTED, + Pageable.ofSize(available), ) val waitlistNumbers = - waitlistedRegs.withIndex().associate { indexed -> - indexed.value.registrationPublicId to (indexed.index + 1) + promoted.withIndex().associate { (index, reg) -> + reg.registrationPublicId to (index + 1) } - val promoted = waitlistedRegs.take(available) promoted.forEach { it.status = RegistrationStatus.CONFIRMED } registrationRepository.saveAll(promoted) val confirmedAfter = confirmed + promoted.size - val remainingWaitlisted = waitlistedRegs.size - promoted.size + val remainingWaitlisted = totalWaitlisted - promoted.size val totalCount = confirmedAfter + remainingWaitlisted val emailDataList = From 5ed23a64f1f7d1c53c8dbd7cb2682b12335700c7 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 20:35:23 +0900 Subject: [PATCH 11/27] =?UTF-8?q?:zap:=20registration=20create=20=EC=8B=9C?= =?UTF-8?q?=20user=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=ED=9A=9F=EC=88=98=20=EC=A4=84=EC=9D=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/registration/service/RegistrationService.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt index a3a8fd01..87dfaaba 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt @@ -97,6 +97,11 @@ RegistrationService( registrationRepository.findByUserIdAndEventId(userId, eventPk) } + val userIdsToFetch = listOfNotNull(lockedEvent.createdBy, userId).distinct() + val fetchedUsersById = userRepository.findAllById(userIdsToFetch).associateBy { it.id!! } + val hostEmail = fetchedUsersById[lockedEvent.createdBy]?.email + val user = userId?.let { fetchedUsersById[it] } + val saved = try { if (existingRegistration != null) { @@ -113,8 +118,7 @@ RegistrationService( -> throw RegistrationConflictException(RegistrationErrorCode.REGISTRATION_ALREADY_EXISTS) } } else { - val hostEmail = userRepository.findById(lockedEvent.createdBy).orElse(null)?.email - val registrationEmail = userId?.let { userRepository.findById(it).orElse(null)?.email } ?: guestEmail + val registrationEmail = user?.email ?: guestEmail if (hostEmail != null && hostEmail == registrationEmail) { throw RegistrationValidationException(RegistrationErrorCode.REGISTRATION_BLOCKED_HOST) From 0848edd14828d293bf893a1b80ad5908617eec33 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 20:36:57 +0900 Subject: [PATCH 12/27] =?UTF-8?q?:zap:=20registration=20create=20=EC=8B=9C?= =?UTF-8?q?=20waitlist=20count=20=EC=A4=91=EB=B3=B5=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/RegistrationService.kt | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt index 87dfaaba..36800e33 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt @@ -148,19 +148,11 @@ RegistrationService( throw RegistrationConflictException(RegistrationErrorCode.REGISTRATION_ALREADY_EXISTS) } - val waitlistedNumber: Int? = - if (saved.status == RegistrationStatus.WAITLISTED) { - registrationRepository - .countByEventIdAndStatus(eventPk, RegistrationStatus.WAITLISTED) - .toInt() - } else { - null - } - - val user = - userId?.let { id -> - userRepository.findById(id).orElse(null) - } + val waitlistedCount = + registrationRepository + .countByEventIdAndStatus(eventPk, RegistrationStatus.WAITLISTED) + .toInt() + val waitlistedNumber: Int? = if (saved.status == RegistrationStatus.WAITLISTED) waitlistedCount else null val recipientEmail = user?.email ?: guestEmail @@ -169,10 +161,6 @@ RegistrationService( registrationRepository .countByEventIdAndStatus(eventPk, RegistrationStatus.CONFIRMED) .toInt() - val waitlistedCount = - registrationRepository - .countByEventIdAndStatus(eventPk, RegistrationStatus.WAITLISTED) - .toInt() val totalCount = confirmedCount + waitlistedCount val emailData = From 4f822e0f4bb866b1fdaa90ecc2cf943bc7a0fbae Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 20:37:18 +0900 Subject: [PATCH 13/27] =?UTF-8?q?:zap:=20registration=20delete=20=EC=8B=9C?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=20lock=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/registration/service/RegistrationService.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt index 36800e33..f5061e42 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt @@ -253,8 +253,6 @@ RegistrationService( } } - eventLockRepository.lockById(registration.eventId) - if (!isRegistrationEnabled(event)) { throw RegistrationValidationException(RegistrationErrorCode.NOT_WITHIN_REGISTRATION_WINDOW) } From 9ff360af56fcf0dcf0a45f4420a4c36e8f172a84 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 20:38:03 +0900 Subject: [PATCH 14/27] =?UTF-8?q?:zap:=20=EB=8C=80=EA=B8=B0=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EA=B3=84=EC=82=B0=20=EC=8B=9C=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EB=A9=94=EB=AA=A8=EB=A6=AC=20=EB=A1=9C?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../registration/service/RegistrationService.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt index f5061e42..a7a3dffc 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt @@ -576,13 +576,14 @@ RegistrationService( val status = registration.status val waitlistPosition = if (status == RegistrationStatus.WAITLISTED) { - val waitlistedRegs = - registrationRepository.findByEventIdAndStatusOrderByCreatedAtAsc( - registration.eventId, - RegistrationStatus.WAITLISTED, - ) - val idx = waitlistedRegs.indexOfFirst { it.id == registration.id } - if (idx >= 0) idx + 1 else 0 + registrationRepository + .findWaitlistPositionsByRegistrationPublicIds( + eventId = registration.eventId, + status = RegistrationStatus.WAITLISTED, + registrationPublicIds = listOf(registration.registrationPublicId), + ).firstOrNull() + ?.waitlistNumber + ?.toInt() ?: 0 } else { 0 } From 936cfb1d80e09886ac22a5e0c35672ffc1cbc188 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Sat, 2 May 2026 20:38:43 +0900 Subject: [PATCH 15/27] =?UTF-8?q?:zap:=20reconcileWaitlist=EC=97=90?= =?UTF-8?q?=EC=84=9C=20user=20=EC=A1=B0=ED=9A=8C=20N+1=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/registration/service/RegistrationService.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt index a7a3dffc..00df08fc 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt @@ -769,12 +769,12 @@ RegistrationService( val remainingWaitlisted = totalWaitlisted - promoted.size val totalCount = confirmedAfter + remainingWaitlisted + val promotedUserIds = promoted.mapNotNull { it.userId }.distinct() + val promotedUsersById = userRepository.findAllById(promotedUserIds).associateBy { it.id!! } + val emailDataList = promoted.mapNotNull { registration -> - val user: User? = - registration.userId?.let { uid -> - userRepository.findById(uid).orElse(null) - } + val user: User? = registration.userId?.let { promotedUsersById[it] } val recipientEmail = user?.email ?: registration.guestEmail val recipientName = user?.name ?: registration.guestName ?: "์ฐธ์—ฌ์ž" From fe12ce10e6c2f3ee220ecfa577ef5b18adb0bb0d Mon Sep 17 00:00:00 2001 From: uykhc Date: Sat, 2 May 2026 22:53:53 +0900 Subject: [PATCH 16/27] docs(openapi): fix Redocly lint errors for security scheme and operation security --- src/main/resources/static/docs/openapi.yaml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/resources/static/docs/openapi.yaml b/src/main/resources/static/docs/openapi.yaml index 6fa1daac..ee0b86b3 100644 --- a/src/main/resources/static/docs/openapi.yaml +++ b/src/main/resources/static/docs/openapi.yaml @@ -20,6 +20,7 @@ tags: paths: /api/events/{publicId}: get: + security: [] tags: - Event summary: ์ด๋ฒคํŠธ ์ƒ์„ธ ์กฐํšŒ @@ -85,6 +86,8 @@ paths: description: ์ธ์ฆ ํ•„์š” /api/images: post: + security: + - bearerAuth: [] tags: - Image summary: ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ @@ -151,6 +154,8 @@ paths: description: ์ธ์ฆ ํ•„์š” /api/events/{eventId}/registrations: get: + security: + - bearerAuth: [] tags: - Registration summary: ์ด๋ฒคํŠธ ์‹ ์ฒญ ๋ชฉ๋ก ์กฐํšŒ @@ -187,6 +192,7 @@ paths: schema: $ref: "#/components/schemas/GetEventRegistrationsResponse" post: + security: [] tags: - Registration summary: ์ด๋ฒคํŠธ ์ฐธ์—ฌ ์‹ ์ฒญ @@ -237,6 +243,7 @@ paths: $ref: "#/components/schemas/ErrorResponse" /api/auth/social: post: + security: [] tags: - Auth summary: ์†Œ์…œ ๋กœ๊ทธ์ธ @@ -268,6 +275,7 @@ paths: $ref: "#/components/schemas/ErrorResponse" /api/auth/signup: post: + security: [] tags: - Auth summary: ์ด๋ฉ”์ผ ํšŒ์›๊ฐ€์ž… @@ -289,6 +297,8 @@ paths: description: ์ด๋ฉ”์ผ ์„œ๋น„์Šค ์žฅ์•  /api/auth/logout: post: + security: + - bearerAuth: [] tags: - Auth summary: ๋กœ๊ทธ์•„์›ƒ @@ -298,6 +308,7 @@ paths: description: ๋กœ๊ทธ์•„์›ƒ ์„ฑ๊ณต /api/auth/login: post: + security: [] tags: - Auth summary: ๋กœ๊ทธ์ธ @@ -323,6 +334,7 @@ paths: $ref: "#/components/schemas/LoginResponse" /api/auth/email-verification/{verificationCode}: post: + security: [] tags: - Auth summary: ์ด๋ฉ”์ผ ์ธ์ฆ @@ -383,6 +395,7 @@ paths: description: ์ธ์ฆ ํ•„์š” /api/registrations/{registrationId}: get: + security: [] tags: - Registration summary: ์‹ ์ฒญ ๋‹จ๊ฑด ์ •๋ณด ์š”์ฒญ @@ -401,6 +414,7 @@ paths: schema: $ref: "#/components/schemas/GetRegistrationResponse" delete: + security: [] tags: - Registration summary: ์‹ ์ฒญ ๋‹จ๊ฑด ์ทจ์†Œ @@ -425,6 +439,8 @@ paths: schema: $ref: "#/components/schemas/DeleteRegistrationResponse" patch: + security: + - bearerAuth: [] tags: - Registration summary: ์‹ ์ฒญ ๋‹จ๊ฑด ์ƒํƒœ ๋ณ€๊ฒฝ @@ -1249,6 +1265,5 @@ components: bearerAuth: type: http description: JWT ํ† ํฐ์„ ์ž…๋ ฅํ•˜์„ธ์š” - name: bearerAuth scheme: bearer bearerFormat: JWT From b045dfc2cab132ef8e1cb8e4148d730eb6ac5a96 Mon Sep 17 00:00:00 2001 From: uykhc Date: Sat, 2 May 2026 23:02:41 +0900 Subject: [PATCH 17/27] refactor(swagger): remove leftover @Schema annotations for static OpenAPI docs --- .../registration/dto/response/GetMyRegistrationsResponse.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt index ced9b0f2..0aca3e06 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/response/GetMyRegistrationsResponse.kt @@ -17,11 +17,8 @@ data class MyRegistrationItem( val registrationStartsAt: Instant?, val registrationEndsAt: Instant?, val capacity: Int?, - @Schema(description = "ํ™•์ • ์ฐธ์—ฌ์ž ์ˆ˜") val confirmedCount: Int, - @Schema(description = "๋Œ€๊ธฐ์ž ์ˆ˜") val waitlistCount: Int, - @Schema(description = "์‹ ์ฒญ ์ƒํƒœ") val status: MyRegistrationStatus, val waitlistedNum: Int?, ) { From 5e1d0d9824a8c46db03a85be8160f8d0178d496f Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Mon, 4 May 2026 17:57:28 +0900 Subject: [PATCH 18/27] =?UTF-8?q?:bug:=20api=20spec=EC=97=90=20=EB=A7=9E?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20registration=20delete=20reques?= =?UTF-8?q?t=20dto=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/RegistrationController.kt | 4 ---- .../dto/request/DeleteRegistrationRequest.kt | 11 ---------- .../service/RegistrationService.kt | 22 ------------------- .../spring2025/RegistrationIntegrationTest.kt | 6 ----- 4 files changed, 43 deletions(-) delete mode 100644 src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt index 2ffccbe6..b3a09f28 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt @@ -1,7 +1,6 @@ package com.wafflestudio.spring2025.domain.registration.controller import com.wafflestudio.spring2025.domain.auth.LoggedInUser -import com.wafflestudio.spring2025.domain.registration.dto.request.DeleteRegistrationRequest import com.wafflestudio.spring2025.domain.registration.dto.request.UpdateRegistrationStatusRequest import com.wafflestudio.spring2025.domain.registration.dto.response.DeleteRegistrationResponse import com.wafflestudio.spring2025.domain.registration.dto.response.GetRegistrationResponse @@ -62,15 +61,12 @@ class RegistrationController( @DeleteMapping fun delete( @PathVariable registrationId: String, - @RequestBody request: DeleteRegistrationRequest, @LoggedInUser user: User?, ): ResponseEntity { val response = registrationService.delete( registrationPublicId = registrationId, userId = user?.id, - guestName = request.guestName, - guestEmail = request.guestEmail, ) return ResponseEntity.ok(response) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt deleted file mode 100644 index 3f34c5f8..00000000 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.wafflestudio.spring2025.domain.registration.dto.request - -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(description = "์ด๋ฒคํŠธ ์ทจ์†Œ ์š”์ฒญ") -data class DeleteRegistrationRequest( - @Schema(description = "๋น„ํšŒ์› ์ด๋ฆ„") - val guestName: String? = null, - @Schema(description = "๋น„ํšŒ์› ์ด๋ฉ”์ผ") - val guestEmail: String? = null, -) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt index a87b211a..47660431 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt @@ -205,22 +205,9 @@ RegistrationService( fun delete( registrationPublicId: String, userId: Long?, - guestName: String?, - guestEmail: String?, ): DeleteRegistrationResponse { - if (userId == null) { - if (guestName.isNullOrBlank()) { - throw RegistrationValidationException(RegistrationErrorCode.REGISTRATION_WRONG_NAME) - } - if (guestEmail.isNullOrBlank()) { - throw RegistrationValidationException(RegistrationErrorCode.REGISTRATION_WRONG_EMAIL) - } - } - deleteInternal( userId = userId, - guestName = guestName, - guestEmail = guestEmail, registrationPublicId = registrationPublicId, ) return DeleteRegistrationResponse() @@ -228,8 +215,6 @@ RegistrationService( private fun deleteInternal( userId: Long?, - guestName: String?, - guestEmail: String?, registrationPublicId: String, ) { // eventId๋ฅผ ์–ป๊ธฐ ์œ„ํ•œ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์กฐํšŒ (๋ฝ ์—†์Œ) @@ -251,13 +236,6 @@ RegistrationService( if (registration.userId != userId) { throw RegistrationForbiddenException(RegistrationErrorCode.REGISTRATION_DELETE_UNAUTHORIZED) } - } else { - if (registration.userId != null || - registration.guestName != guestName || - registration.guestEmail != guestEmail - ) { - throw RegistrationForbiddenException(RegistrationErrorCode.REGISTRATION_DELETE_UNAUTHORIZED) - } } eventLockRepository.lockById(registration.eventId) diff --git a/src/test/kotlin/com/wafflestudio/spring2025/RegistrationIntegrationTest.kt b/src/test/kotlin/com/wafflestudio/spring2025/RegistrationIntegrationTest.kt index 48b9cd3d..f2b1564a 100644 --- a/src/test/kotlin/com/wafflestudio/spring2025/RegistrationIntegrationTest.kt +++ b/src/test/kotlin/com/wafflestudio/spring2025/RegistrationIntegrationTest.kt @@ -6,7 +6,6 @@ import com.wafflestudio.spring2025.common.email.service.EmailService import com.wafflestudio.spring2025.domain.event.model.Event import com.wafflestudio.spring2025.domain.event.repository.EventRepository import com.wafflestudio.spring2025.domain.registration.dto.request.CreateRegistrationRequest -import com.wafflestudio.spring2025.domain.registration.dto.request.DeleteRegistrationRequest import com.wafflestudio.spring2025.domain.registration.dto.request.UpdateRegistrationStatusRequest import com.wafflestudio.spring2025.domain.registration.model.Registration import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus @@ -243,7 +242,6 @@ class RegistrationIntegrationTest .perform( delete("/api/registrations/$participantRegistrationId") .header("Authorization", "Bearer $hostToken") - .content(mapper.writeValueAsString(DeleteRegistrationRequest())) .contentType(MediaType.APPLICATION_JSON), ).andExpect(status().isForbidden) .andExpect(jsonPath("$.code").value("REGISTRATION_DELETE_UNAUTHORIZED")) @@ -252,7 +250,6 @@ class RegistrationIntegrationTest .perform( delete("/api/registrations/$participantRegistrationId") .header("Authorization", "Bearer $participantToken") - .content(mapper.writeValueAsString(DeleteRegistrationRequest())) .contentType(MediaType.APPLICATION_JSON), ).andExpect(status().isOk) @@ -276,7 +273,6 @@ class RegistrationIntegrationTest .perform( delete("/api/registrations/$confirmedRegistrationId") .header("Authorization", "Bearer $confirmedUserToken") - .content(mapper.writeValueAsString(DeleteRegistrationRequest())) .contentType(MediaType.APPLICATION_JSON), ).andExpect(status().isOk) @@ -347,7 +343,6 @@ class RegistrationIntegrationTest .perform( delete("/api/registrations/${registration.registrationPublicId}") .header("Authorization", "Bearer $participantToken") - .content(mapper.writeValueAsString(DeleteRegistrationRequest())) .contentType(MediaType.APPLICATION_JSON), ).andExpect(status().isBadRequest) .andExpect(jsonPath("$.code").value("NOT_WITHIN_REGISTRATION_WINDOW")) @@ -378,7 +373,6 @@ class RegistrationIntegrationTest .perform( delete("/api/registrations/${registration.registrationPublicId}") .header("Authorization", "Bearer $participantToken") - .content(mapper.writeValueAsString(DeleteRegistrationRequest())) .contentType(MediaType.APPLICATION_JSON), ).andExpect(status().isBadRequest) .andExpect(jsonPath("$.code").value("NOT_WITHIN_REGISTRATION_WINDOW")) From 7cf4198147f90b61476f4391e791bc5f314cffb2 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Mon, 4 May 2026 20:29:59 +0900 Subject: [PATCH 19/27] =?UTF-8?q?:bug:=20=EC=B0=B8=EC=97=AC=20=EC=B7=A8?= =?UTF-8?q?=EC=86=8C=20=EC=8B=9C=20=EA=B6=8C=ED=95=9C=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/registration/service/RegistrationService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt index 47660431..1eb74ea2 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt @@ -232,7 +232,7 @@ RegistrationService( registrationRepository.lockByRegistrationPublicId(registrationPublicId) ?: throw RegistrationNotFoundException() - if (userId != null) { + if (registration.userId != null) { if (registration.userId != userId) { throw RegistrationForbiddenException(RegistrationErrorCode.REGISTRATION_DELETE_UNAUTHORIZED) } From 04ca11974c40e52205a6a57f1a2b0d144f158b6e Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Mon, 4 May 2026 21:20:29 +0900 Subject: [PATCH 20/27] =?UTF-8?q?:memo:=20=EB=B6=88=EC=9D=BC=EC=B9=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/auth/controller/SocialAuthController.kt | 2 +- src/main/resources/static/docs/openapi.yaml | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt index dbd09f73..14da8c08 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/controller/SocialAuthController.kt @@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController -@RequestMapping("api/auth/social") +@RequestMapping("/api/auth/social") class SocialAuthController( private val socialAuthService: SocialAuthService, ) { diff --git a/src/main/resources/static/docs/openapi.yaml b/src/main/resources/static/docs/openapi.yaml index 6fa1daac..bb9bacb4 100644 --- a/src/main/resources/static/docs/openapi.yaml +++ b/src/main/resources/static/docs/openapi.yaml @@ -572,6 +572,7 @@ components: required: - registrationEndsAt - title + - capacity - waitlistEnabled type: object properties: @@ -849,7 +850,8 @@ components: MyRegistrationItem: required: - publicId - - registrationCnt + - confirmedCount + - waitlistCount - status - title type: object @@ -885,9 +887,13 @@ components: description: ์ •์› format: int32 nullable: true - registrationCnt: + confirmedCount: + type: integer + description: ์ฐธ์—ฌ ํ™•์ •์ž ์ˆ˜ + format: int32 + waitlistCount: type: integer - description: ํ˜„์žฌ ์‹ ์ฒญ ์ˆ˜ + ๋Œ€๊ธฐ ์ˆ˜ + description: ์ฐธ์—ฌ ํ™•์ •์ž ์ˆ˜ format: int32 status: type: string From e4c5c724bc02fc260c2d87a30de675bb883d3a9c Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Mon, 4 May 2026 21:24:27 +0900 Subject: [PATCH 21/27] =?UTF-8?q?:memo:=20=EB=B6=88=EC=9D=BC=EC=B9=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/static/docs/openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/static/docs/openapi.yaml b/src/main/resources/static/docs/openapi.yaml index 7fcbefff..e83c7598 100644 --- a/src/main/resources/static/docs/openapi.yaml +++ b/src/main/resources/static/docs/openapi.yaml @@ -909,7 +909,7 @@ components: format: int32 waitlistCount: type: integer - description: ์ฐธ์—ฌ ํ™•์ •์ž ์ˆ˜ + description: ๋Œ€๊ธฐ์ž ์ˆ˜ format: int32 status: type: string From 8a06dfba03bc11a6aaaf1a6d14cc2b2fa52bedec Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Mon, 4 May 2026 21:25:14 +0900 Subject: [PATCH 22/27] =?UTF-8?q?:fire:=20=EC=95=88=20=EC=93=B0=EC=9D=B4?= =?UTF-8?q?=EB=8A=94=20RegisterRequest=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring2025/domain/auth/dto/RegisterRequest.kt | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt deleted file mode 100644 index 32ee7ed3..00000000 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/auth/dto/RegisterRequest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.wafflestudio.spring2025.domain.auth.dto - -data class RegisterRequest( - val email: String, - val name: String, - val password: String, - val profileImage: String? = null, -) From e45ead73669fb081994e7597c416d582741def07 Mon Sep 17 00:00:00 2001 From: uykhc Date: Tue, 5 May 2026 20:34:50 +0900 Subject: [PATCH 23/27] =?UTF-8?q?feat:=20prometheus=20=EB=AA=A8=EB=8B=88?= =?UTF-8?q?=ED=84=B0=EB=A7=81=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Spring Boot Actuator ๋ฐ Micrometer Prometheus registry ์˜์กด์„ฑ ์ถ”๊ฐ€ - docker-compose.dev์— prometheus ์„œ๋น„์Šค/๋ณผ๋ฅจ ๊ตฌ์„ฑ ์ถ”๊ฐ€ - management endpoint ๋…ธ์ถœ ๋ฒ”์œ„์— info, metrics, prometheus ์ถ”๊ฐ€ --- build.gradle.kts | 5 ++++- docker-compose.dev.yml | 17 +++++++++++++++++ src/main/resources/application.yaml | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index cfebb3cb..5b8d2200 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -44,7 +44,6 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-webflux") implementation("org.springframework.boot:spring-boot-starter-data-jdbc") implementation("org.springframework.boot:spring-boot-starter-data-redis") - implementation("org.springframework.boot:spring-boot-starter-actuator") implementation("org.springframework.boot:spring-boot-starter-mail") implementation("org.mindrot:jbcrypt:0.4") implementation("io.jsonwebtoken:jjwt-api:0.11.5") @@ -73,6 +72,10 @@ dependencies { // OCI Vault - SDK ์ง์ ‘ ์‚ฌ์šฉ (waffle-oci-vault 2.1.0์€ Spring Boot 3.5์™€ ํ˜ธํ™˜ ์•ˆ๋จ) implementation("com.oracle.oci.sdk:oci-java-sdk-secrets:3.80.1") implementation("com.oracle.oci.sdk:oci-java-sdk-common-httpclient-jersey3:3.80.1") + + // prometheus ์˜์กด์„ฑ ์ถ”๊ฐ€ + implementation("org.springframework.boot:spring-boot-starter-actuator") + implementation("io.micrometer:micrometer-registry-prometheus") } kotlin { diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 99b4dc2e..b723e04d 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -76,6 +76,23 @@ services: limits: memory: 64M + prometheus: + image: prom/prometheus:latest + container_name: prometheus-dev + restart: unless-stopped + ports: + - "127.0.0.1:9090:9090" + volumes: + - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - prometheus_data_dev:/prometheus + command: + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus" + depends_on: + app: + condition: service_healthy + volumes: mysql_data_dev: redis_data_dev: + prometheus_data_dev: diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 473a1ff9..ee7ef521 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -68,7 +68,7 @@ management: endpoints: web: exposure: - include: health + include: health,info,prometheus,metrics endpoint: health: show-details: always From 810e3976fe42b36d8fd5d058caec1c0465b47f33 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Tue, 5 May 2026 20:56:45 +0900 Subject: [PATCH 24/27] =?UTF-8?q?:bug:=20=EB=8C=80=EA=B8=B0=20=EC=88=9C?= =?UTF-8?q?=EB=B2=88=20=EA=B3=84=EC=82=B0=20=EB=B0=A9=EC=8B=9D=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/registration/repository/RegistrationRepository.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/repository/RegistrationRepository.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/repository/RegistrationRepository.kt index 3c5afa24..1c91aa06 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/repository/RegistrationRepository.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/repository/RegistrationRepository.kt @@ -186,7 +186,7 @@ interface RegistrationRepository : ranked.waitlist_number AS waitlist_number FROM ( SELECT r.registration_public_id, - ROW_NUMBER() OVER (ORDER BY r.created_at ASC, r.registration_public_id ASC) AS waitlist_number + ROW_NUMBER() OVER (ORDER BY r.created_at ASC, r.id ASC) AS waitlist_number FROM registrations r WHERE r.event_id = :eventId AND r.status = :status ) ranked From 22762d1ca9dcd3d4c855254e70b3f5dc976b8003 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Mon, 4 May 2026 17:57:28 +0900 Subject: [PATCH 25/27] =?UTF-8?q?:bug:=20api=20spec=EC=97=90=20=EB=A7=9E?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20registration=20delete=20reques?= =?UTF-8?q?t=20dto=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/RegistrationController.kt | 4 ---- .../dto/request/DeleteRegistrationRequest.kt | 6 ----- .../service/RegistrationService.kt | 22 ------------------- .../spring2025/RegistrationIntegrationTest.kt | 6 ----- 4 files changed, 38 deletions(-) delete mode 100644 src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt index f2568d12..28381a59 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/controller/RegistrationController.kt @@ -1,7 +1,6 @@ package com.wafflestudio.spring2025.domain.registration.controller import com.wafflestudio.spring2025.domain.auth.LoggedInUser -import com.wafflestudio.spring2025.domain.registration.dto.request.DeleteRegistrationRequest import com.wafflestudio.spring2025.domain.registration.dto.request.UpdateRegistrationStatusRequest import com.wafflestudio.spring2025.domain.registration.dto.response.DeleteRegistrationResponse import com.wafflestudio.spring2025.domain.registration.dto.response.GetRegistrationResponse @@ -48,15 +47,12 @@ class RegistrationController( @DeleteMapping fun delete( @PathVariable registrationId: String, - @RequestBody request: DeleteRegistrationRequest, @LoggedInUser user: User?, ): ResponseEntity { val response = registrationService.delete( registrationPublicId = registrationId, userId = user?.id, - guestName = request.guestName, - guestEmail = request.guestEmail, ) return ResponseEntity.ok(response) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt deleted file mode 100644 index 0df46b98..00000000 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/dto/request/DeleteRegistrationRequest.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.wafflestudio.spring2025.domain.registration.dto.request - -data class DeleteRegistrationRequest( - val guestName: String? = null, - val guestEmail: String? = null, -) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt index 00df08fc..89d2f788 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt @@ -198,22 +198,9 @@ RegistrationService( fun delete( registrationPublicId: String, userId: Long?, - guestName: String?, - guestEmail: String?, ): DeleteRegistrationResponse { - if (userId == null) { - if (guestName.isNullOrBlank()) { - throw RegistrationValidationException(RegistrationErrorCode.REGISTRATION_WRONG_NAME) - } - if (guestEmail.isNullOrBlank()) { - throw RegistrationValidationException(RegistrationErrorCode.REGISTRATION_WRONG_EMAIL) - } - } - deleteInternal( userId = userId, - guestName = guestName, - guestEmail = guestEmail, registrationPublicId = registrationPublicId, ) return DeleteRegistrationResponse() @@ -221,8 +208,6 @@ RegistrationService( private fun deleteInternal( userId: Long?, - guestName: String?, - guestEmail: String?, registrationPublicId: String, ) { // eventId๋ฅผ ์–ป๊ธฐ ์œ„ํ•œ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์กฐํšŒ (๋ฝ ์—†์Œ) @@ -244,13 +229,6 @@ RegistrationService( if (registration.userId != userId) { throw RegistrationForbiddenException(RegistrationErrorCode.REGISTRATION_DELETE_UNAUTHORIZED) } - } else { - if (registration.userId != null || - registration.guestName != guestName || - registration.guestEmail != guestEmail - ) { - throw RegistrationForbiddenException(RegistrationErrorCode.REGISTRATION_DELETE_UNAUTHORIZED) - } } if (!isRegistrationEnabled(event)) { diff --git a/src/test/kotlin/com/wafflestudio/spring2025/RegistrationIntegrationTest.kt b/src/test/kotlin/com/wafflestudio/spring2025/RegistrationIntegrationTest.kt index 48b9cd3d..f2b1564a 100644 --- a/src/test/kotlin/com/wafflestudio/spring2025/RegistrationIntegrationTest.kt +++ b/src/test/kotlin/com/wafflestudio/spring2025/RegistrationIntegrationTest.kt @@ -6,7 +6,6 @@ import com.wafflestudio.spring2025.common.email.service.EmailService import com.wafflestudio.spring2025.domain.event.model.Event import com.wafflestudio.spring2025.domain.event.repository.EventRepository import com.wafflestudio.spring2025.domain.registration.dto.request.CreateRegistrationRequest -import com.wafflestudio.spring2025.domain.registration.dto.request.DeleteRegistrationRequest import com.wafflestudio.spring2025.domain.registration.dto.request.UpdateRegistrationStatusRequest import com.wafflestudio.spring2025.domain.registration.model.Registration import com.wafflestudio.spring2025.domain.registration.model.RegistrationStatus @@ -243,7 +242,6 @@ class RegistrationIntegrationTest .perform( delete("/api/registrations/$participantRegistrationId") .header("Authorization", "Bearer $hostToken") - .content(mapper.writeValueAsString(DeleteRegistrationRequest())) .contentType(MediaType.APPLICATION_JSON), ).andExpect(status().isForbidden) .andExpect(jsonPath("$.code").value("REGISTRATION_DELETE_UNAUTHORIZED")) @@ -252,7 +250,6 @@ class RegistrationIntegrationTest .perform( delete("/api/registrations/$participantRegistrationId") .header("Authorization", "Bearer $participantToken") - .content(mapper.writeValueAsString(DeleteRegistrationRequest())) .contentType(MediaType.APPLICATION_JSON), ).andExpect(status().isOk) @@ -276,7 +273,6 @@ class RegistrationIntegrationTest .perform( delete("/api/registrations/$confirmedRegistrationId") .header("Authorization", "Bearer $confirmedUserToken") - .content(mapper.writeValueAsString(DeleteRegistrationRequest())) .contentType(MediaType.APPLICATION_JSON), ).andExpect(status().isOk) @@ -347,7 +343,6 @@ class RegistrationIntegrationTest .perform( delete("/api/registrations/${registration.registrationPublicId}") .header("Authorization", "Bearer $participantToken") - .content(mapper.writeValueAsString(DeleteRegistrationRequest())) .contentType(MediaType.APPLICATION_JSON), ).andExpect(status().isBadRequest) .andExpect(jsonPath("$.code").value("NOT_WITHIN_REGISTRATION_WINDOW")) @@ -378,7 +373,6 @@ class RegistrationIntegrationTest .perform( delete("/api/registrations/${registration.registrationPublicId}") .header("Authorization", "Bearer $participantToken") - .content(mapper.writeValueAsString(DeleteRegistrationRequest())) .contentType(MediaType.APPLICATION_JSON), ).andExpect(status().isBadRequest) .andExpect(jsonPath("$.code").value("NOT_WITHIN_REGISTRATION_WINDOW")) From 942b79e64e4dd0e76657c3f1911732672f7c6395 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Mon, 4 May 2026 20:29:59 +0900 Subject: [PATCH 26/27] =?UTF-8?q?:bug:=20=EC=B0=B8=EC=97=AC=20=EC=B7=A8?= =?UTF-8?q?=EC=86=8C=20=EC=8B=9C=20=EA=B6=8C=ED=95=9C=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/registration/service/RegistrationService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt index 89d2f788..46ea8c70 100644 --- a/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt +++ b/src/main/kotlin/com/wafflestudio/spring2025/domain/registration/service/RegistrationService.kt @@ -225,7 +225,7 @@ RegistrationService( registrationRepository.lockByRegistrationPublicId(registrationPublicId) ?: throw RegistrationNotFoundException() - if (userId != null) { + if (registration.userId != null) { if (registration.userId != userId) { throw RegistrationForbiddenException(RegistrationErrorCode.REGISTRATION_DELETE_UNAUTHORIZED) } From 458048cc31eb0c670d68226a35de22c135addcc1 Mon Sep 17 00:00:00 2001 From: Jisu Hong Date: Tue, 5 May 2026 22:23:34 +0900 Subject: [PATCH 27/27] =?UTF-8?q?:memo:=20swagger=EC=97=90=EC=84=9C=20Dele?= =?UTF-8?q?teRegistrationRequest=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/static/docs/openapi.yaml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/main/resources/static/docs/openapi.yaml b/src/main/resources/static/docs/openapi.yaml index e83c7598..9f62c069 100644 --- a/src/main/resources/static/docs/openapi.yaml +++ b/src/main/resources/static/docs/openapi.yaml @@ -425,12 +425,6 @@ paths: required: true schema: type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/DeleteRegistrationRequest" - required: true responses: "200": description: OK @@ -1236,18 +1230,6 @@ components: nullable: true hasNext: type: boolean - DeleteRegistrationRequest: - type: object - properties: - guestName: - type: string - description: ๋น„ํšŒ์› ์ด๋ฆ„ - nullable: true - guestEmail: - type: string - description: ๋น„ํšŒ์› ์ด๋ฉ”์ผ - nullable: true - description: ์ด๋ฒคํŠธ ์ทจ์†Œ ์š”์ฒญ DeleteRegistrationResponse: type: object ErrorResponse: