[#44] 매장 기능 도입 #45

Merged
pricelees merged 116 commits from feat/#44 into main 2025-09-20 03:15:06 +00:00
4 changed files with 24 additions and 67 deletions
Showing only changes of commit 0ef47b7f94 - Show all commits

View File

@ -16,11 +16,11 @@ import roomescape.common.dto.response.CommonApiResponse
import roomescape.theme.web.* import roomescape.theme.web.*
@Tag(name = "5. 관리자 테마 API", description = "관리자 페이지에서 테마를 조회 / 추가 / 삭제할 때 사용합니다.") @Tag(name = "5. 관리자 테마 API", description = "관리자 페이지에서 테마를 조회 / 추가 / 삭제할 때 사용합니다.")
interface HQAdminThemeAPI { interface AdminThemeAPI {
@AdminOnly(type = AdminType.HQ, privilege = Privilege.READ_SUMMARY) @AdminOnly(type = AdminType.HQ, privilege = Privilege.READ_SUMMARY)
@Operation(summary = "모든 테마 조회", description = "관리자 페이지에서 요약된 테마 목록을 조회합니다.", tags = ["관리자 로그인이 필요한 API"]) @Operation(summary = "모든 테마 조회", description = "관리자 페이지에서 요약된 테마 목록을 조회합니다.", tags = ["관리자 로그인이 필요한 API"])
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
fun findAdminThemes(): ResponseEntity<CommonApiResponse<AdminThemeSummaryListResponse>> fun getAdminThemeSummaries(): ResponseEntity<CommonApiResponse<AdminThemeSummaryListResponse>>
@AdminOnly(type = AdminType.HQ, privilege = Privilege.READ_DETAIL) @AdminOnly(type = AdminType.HQ, privilege = Privilege.READ_DETAIL)
@Operation(summary = "테마 상세 조회", description = "해당 테마의 상세 정보를 조회합니다.", tags = ["관리자 로그인이 필요한 API"]) @Operation(summary = "테마 상세 조회", description = "해당 테마의 상세 정보를 조회합니다.", tags = ["관리자 로그인이 필요한 API"])
@ -42,24 +42,21 @@ interface HQAdminThemeAPI {
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
fun updateTheme( fun updateTheme(
@PathVariable id: Long, @PathVariable id: Long,
@Valid @RequestBody themeUpdateRequest: ThemeUpdateRequest @Valid @RequestBody request: ThemeUpdateRequest
): ResponseEntity<CommonApiResponse<Unit>> ): ResponseEntity<CommonApiResponse<Unit>>
}
interface StoreAdminThemeAPI { @AdminOnly(privilege = Privilege.READ_SUMMARY)
@AdminOnly(type = AdminType.STORE, privilege = Privilege.READ_SUMMARY)
@Operation(summary = "테마 조회", description = "현재 open 상태인 모든 테마 ID + 이름 조회", tags = ["관리자 로그인이 필요한 API"]) @Operation(summary = "테마 조회", description = "현재 open 상태인 모든 테마 ID + 이름 조회", tags = ["관리자 로그인이 필요한 API"])
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
fun findActiveThemes(): ResponseEntity<CommonApiResponse<SimpleActiveThemeListResponse>> fun getActiveThemes(): ResponseEntity<CommonApiResponse<SimpleActiveThemeListResponse>>
} }
interface PublicThemeAPI { interface PublicThemeAPI {
@Public @Public
@Operation(summary = "입력된 모든 ID에 대한 테마 조회") @Operation(summary = "입력된 모든 ID에 대한 테마 조회")
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
fun findThemesByIds(request: ThemeIdListRequest): ResponseEntity<CommonApiResponse<ThemeInfoListResponse>> fun findThemeInfosByIds(request: ThemeIdListRequest): ResponseEntity<CommonApiResponse<ThemeInfoListResponse>>
@Public
@Operation(summary = "입력된 테마 ID에 대한 정보 조회") @Operation(summary = "입력된 테마 ID에 대한 정보 조회")
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
fun findThemeInfoById(@PathVariable id: Long): ResponseEntity<CommonApiResponse<ThemeInfoResponse>> fun findThemeInfoById(@PathVariable id: Long): ResponseEntity<CommonApiResponse<ThemeInfoResponse>>

View File

@ -1,19 +1,20 @@
package roomescape.theme.web package roomescape.theme.web
import jakarta.validation.Valid
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.* import org.springframework.web.bind.annotation.*
import roomescape.common.dto.response.CommonApiResponse import roomescape.common.dto.response.CommonApiResponse
import roomescape.theme.business.ThemeService import roomescape.theme.business.ThemeService
import roomescape.theme.docs.HQAdminThemeAPI import roomescape.theme.docs.AdminThemeAPI
import roomescape.theme.docs.StoreAdminThemeAPI
import java.net.URI import java.net.URI
@RestController @RestController
class HQAdminThemeController( class AdminThemeController(
private val themeService: ThemeService, private val themeService: ThemeService,
) : HQAdminThemeAPI { ) : AdminThemeAPI {
@GetMapping("/admin/themes") @GetMapping("/admin/themes")
override fun findAdminThemes(): ResponseEntity<CommonApiResponse<AdminThemeSummaryListResponse>> { override fun getAdminThemeSummaries(): ResponseEntity<CommonApiResponse<AdminThemeSummaryListResponse>> {
val response = themeService.findAdminThemes() val response = themeService.findAdminThemes()
return ResponseEntity.ok(CommonApiResponse(response)) return ResponseEntity.ok(CommonApiResponse(response))
@ -27,7 +28,9 @@ class HQAdminThemeController(
} }
@PostMapping("/admin/themes") @PostMapping("/admin/themes")
override fun createTheme(themeCreateRequest: ThemeCreateRequest): ResponseEntity<CommonApiResponse<ThemeCreateResponse>> { override fun createTheme(
@Valid @RequestBody themeCreateRequest: ThemeCreateRequest
): ResponseEntity<CommonApiResponse<ThemeCreateResponse>> {
val response = themeService.createTheme(themeCreateRequest) val response = themeService.createTheme(themeCreateRequest)
return ResponseEntity.created(URI.create("/admin/themes/${response.id}")) return ResponseEntity.created(URI.create("/admin/themes/${response.id}"))
@ -44,21 +47,15 @@ class HQAdminThemeController(
@PatchMapping("/admin/themes/{id}") @PatchMapping("/admin/themes/{id}")
override fun updateTheme( override fun updateTheme(
@PathVariable id: Long, @PathVariable id: Long,
themeUpdateRequest: ThemeUpdateRequest @Valid @RequestBody request: ThemeUpdateRequest
): ResponseEntity<CommonApiResponse<Unit>> { ): ResponseEntity<CommonApiResponse<Unit>> {
themeService.updateTheme(id, themeUpdateRequest) themeService.updateTheme(id, request)
return ResponseEntity.ok().build() return ResponseEntity.ok().build()
} }
}
@RestController
class StoreAdminController(
private val themeService: ThemeService
) : StoreAdminThemeAPI {
@GetMapping("/admin/themes/active") @GetMapping("/admin/themes/active")
override fun findActiveThemes(): ResponseEntity<CommonApiResponse<SimpleActiveThemeListResponse>> { override fun getActiveThemes(): ResponseEntity<CommonApiResponse<SimpleActiveThemeListResponse>> {
val response = themeService.findActiveThemes() val response = themeService.findActiveThemes()
return ResponseEntity.ok(CommonApiResponse(response)) return ResponseEntity.ok(CommonApiResponse(response))

View File

@ -1,18 +1,8 @@
package roomescape.theme.web package roomescape.theme.web
import roomescape.common.dto.OperatorInfo import roomescape.common.dto.AuditInfo
import roomescape.theme.infrastructure.persistence.Difficulty import roomescape.theme.infrastructure.persistence.Difficulty
import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.theme.infrastructure.persistence.ThemeEntity
import java.time.LocalDateTime
/**
* Theme API DTO
*
* Structure:
* - HQ Admin DTO: 본사 관리자가 사용하는 테마 관련 DTO들
* - Store Admin DTO: 매장 관리자가 사용하는 테마 관련 DTO들
*/
// ======================================== // ========================================
// HQ Admin DTO (본사) // HQ Admin DTO (본사)
@ -103,48 +93,21 @@ fun List<ThemeEntity>.toAdminThemeSummaryListResponse() = AdminThemeSummaryListR
) )
data class AdminThemeDetailResponse( data class AdminThemeDetailResponse(
val id: Long, val theme: ThemeInfoResponse,
val name: String,
val description: String,
val thumbnailUrl: String,
val difficulty: Difficulty,
val price: Int,
val minParticipants: Short,
val maxParticipants: Short,
val availableMinutes: Short,
val expectedMinutesFrom: Short,
val expectedMinutesTo: Short,
val isActive: Boolean, val isActive: Boolean,
val createdAt: LocalDateTime, val audit: AuditInfo
val createdBy: OperatorInfo,
val updatedAt: LocalDateTime,
val updatedBy: OperatorInfo,
) )
fun ThemeEntity.toAdminThemeDetailResponse(createdBy: OperatorInfo, updatedBy: OperatorInfo) = fun ThemeEntity.toAdminThemeDetailResponse(audit: AuditInfo) =
AdminThemeDetailResponse( AdminThemeDetailResponse(
id = this.id, theme = this.toInfoResponse(),
name = this.name,
description = this.description,
thumbnailUrl = this.thumbnailUrl,
difficulty = this.difficulty,
price = this.price,
minParticipants = this.minParticipants,
maxParticipants = this.maxParticipants,
availableMinutes = this.availableMinutes,
expectedMinutesFrom = this.expectedMinutesFrom,
expectedMinutesTo = this.expectedMinutesTo,
isActive = this.isActive, isActive = this.isActive,
createdAt = this.createdAt, audit = audit
createdBy = createdBy,
updatedAt = this.updatedAt,
updatedBy = updatedBy
) )
// ======================================== // ========================================
// Store Admin DTO // Store Admin DTO
// ======================================== // ========================================
data class SimpleActiveThemeResponse( data class SimpleActiveThemeResponse(
val id: Long, val id: Long,
val name: String val name: String