Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import com.matzip.common.response.ApiResponse;
// import com.matzip.common.security.UserPrincipal;
import com.matzip.place.repository.PlaceRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
// import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -19,6 +21,7 @@

import java.util.List;

@Tag(name = "어드민", description = "맛집 등록 요청 승인/거절 관리 API")
@RequestMapping("/admin/api")
@RestController
public class AdminController {
Expand All @@ -31,6 +34,7 @@ public AdminController(PlaceRepository placeRepository, AdminPlaceRegisterReques
this.adminPlaceRegisterRequestService = adminPlaceRegisterRequestService;
}

@Operation(summary = "맛집 등록 요청 목록 (어드민)", description = "승인 대기(PENDING) 상태인 맛집 등록 요청 목록을 조회한다.")
@GetMapping("/requests/places")
public ApiResponse<List<PlaceRegisterRequestsResponseDto>> findPlaceRegisterRequests() {
List<PlaceRegisterRequestsResponseDto> data = placeRepository.findPendingPlaces()
Expand All @@ -41,6 +45,9 @@ public ApiResponse<List<PlaceRegisterRequestsResponseDto>> findPlaceRegisterRequ
return ApiResponse.success(data);
}

@Operation(summary = "맛집 등록 요청 상세 (어드민)", description = "특정 맛집 등록 요청의 상세 정보를 조회한다.")
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공", useReturnTypeSchema = true)
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "맛집을 찾을 수 없습니다.")
@GetMapping("/requests/places/{placeId}")
public ApiResponse<PlaceRegisterRequestDetailResponseDto> findPlaceRegisterRequestDetail(
@PathVariable("placeId") Long placeId
Expand All @@ -52,6 +59,7 @@ public ApiResponse<PlaceRegisterRequestDetailResponseDto> findPlaceRegisterReque
return ApiResponse.success(data);
}

@Operation(summary = "맛집 등록 요청 승인/거절 (어드민)", description = "맛집 등록 요청을 승인(APPROVED) 또는 거절(REJECTED)한다. 거절 시 사유를 함께 전달한다.")
@PostMapping("/requests/places/{placeId}/review")
public ApiResponse<?> reviewPlaceRegisterRequest(
@PathVariable("placeId") Long placeId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,28 @@
import com.matzip.place.dto.LocationDto;
import com.matzip.place.dto.PhotoDto;
import com.matzip.place.dto.TagDto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

import java.time.LocalDate;
import java.util.List;

@Builder
public record PlaceRegisterRequestDetailResponseDto(Long placeId, String placeName, LocalDate requestDate, List<PhotoDto> photos,
String address, LocationDto location, String description,
List<MenusResponse> menus, List<CategoryDto> categories, List<TagDto> tags) {
public record PlaceRegisterRequestDetailResponseDto(
@Schema(description = "맛집 ID", example = "15") Long placeId,
@Schema(description = "맛집 이름", example = "우돈탄 다산본점") String placeName,
@Schema(description = "등록 요청일", example = "2025-08-12") LocalDate requestDate,
List<PhotoDto> photos,
@Schema(description = "주소", example = "경기 남양주시 다산중앙로82번길 25") String address,
LocationDto location,
@Schema(description = "맛집 설명", example = "직원이 엄청 친절해요! 근데 화장실에 갔고 냄새나요 ㅠㅠㅠ 그래도 맛은 있어서 괜찮아요") String description,
List<MenusResponse> menus, List<CategoryDto> categories, List<TagDto> tags) {

@Builder
public record MenusResponse(
String name,
Integer price,
Boolean isRecommended
@Schema(description = "메뉴 이름", example = "숙성우대갈비") String name,
@Schema(description = "가격(원)", example = "32000") Integer price,
@Schema(description = "대표 메뉴 여부", example = "true") Boolean isRecommended
) {
public static MenusResponse from(Menu menu) {
return MenusResponse.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@
import com.matzip.place.domain.entity.Place;
import com.matzip.place.dto.CategoryDto;
import com.matzip.place.dto.TagDto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

import java.time.LocalDate;
import java.util.List;

@Builder
public record PlaceRegisterRequestsResponseDto(Long placeId, String placeName, LocalDate requestDate, Campus campus,
List<CategoryDto> categories, List<TagDto> tags) {
public record PlaceRegisterRequestsResponseDto(
@Schema(description = "맛집 ID", example = "15") Long placeId,
@Schema(description = "맛집 이름", example = "우돈탄 다산본점") String placeName,
@Schema(description = "등록 요청일", example = "2025-08-12") LocalDate requestDate,
@Schema(description = "캠퍼스", example = "SINGWAN") Campus campus,
List<CategoryDto> categories, List<TagDto> tags) {

public static PlaceRegisterRequestsResponseDto from(Place place) {
return PlaceRegisterRequestsResponseDto.builder()
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/matzip/auth/controller/AuthController.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import com.matzip.common.exception.BusinessException;
import com.matzip.common.exception.code.ErrorCode;
import com.matzip.common.response.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
Expand All @@ -24,6 +26,7 @@
import java.time.Duration;


@Tag(name = "인증", description = "카카오 로그인 및 JWT 토큰 발급 API")
@RestController
@RequestMapping("/api/v1/auth")
@RequiredArgsConstructor
Expand All @@ -39,6 +42,7 @@ public class AuthController {
private final StatelessStateSigner stateSigner;
private final KakaoAuthorizeUrlBuilder kakaoAuthorizeUrlBuilder;

@Operation(summary = "카카오 인가 URL 리다이렉트", description = "허용된 clientOrigin을 검증하고 카카오 로그인 페이지(302)로 리다이렉트한다.")
@GetMapping("/authorize")
public ResponseEntity<Void> authorize(@RequestParam("clientOrigin") String clientOrigin) {

Expand Down Expand Up @@ -66,6 +70,7 @@ public ResponseEntity<Void> authorize(@RequestParam("clientOrigin") String clien
* @param body
* @return
*/
@Operation(summary = "액세스 토큰 재발급", description = "쿠키 또는 요청 본문의 리프레시 토큰으로 액세스 토큰을 재발급하고, 회전된 리프레시 토큰을 쿠키로 설정한다.")
@PostMapping("/token")
public ResponseEntity<ApiResponse<TokenResponseDto>> reissue(
@CookieValue(value = RT_COOKIE_NAME, required = false) String rtCookie,
Expand Down Expand Up @@ -106,6 +111,7 @@ private ResponseCookie buildRtCookie(String rt, long maxAgeMs) {
.build();
}

@Operation(summary = "카카오 로그인 콜백", description = "카카오 인가 코드를 받아 로그인을 처리하고, 성공/실패에 따라 프론트 페이지로 리다이렉트(302)한다.")
@GetMapping("/callback")
public ResponseEntity<Void> kakaoCallback(
@RequestParam("code") @NotBlank String code,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.matzip.auth.dto.response.LoginResponseDto;
import com.matzip.auth.service.AuthService;
import com.matzip.common.response.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
Expand All @@ -14,6 +16,7 @@

import java.time.Duration;

@Tag(name = "인증", description = "카카오 로그인 및 JWT 토큰 발급 API")
@RequestMapping("/api/v2/auth")
@RestController
public class AuthControllerV2 {
Expand All @@ -24,6 +27,7 @@ public AuthControllerV2(AuthService authService) {
this.authService = authService;
}

@Operation(summary = "카카오 로그인 (v2)", description = "인가 코드와 redirectUri로 로그인하고, 액세스 토큰을 본문으로, 리프레시 토큰을 쿠키로 반환한다.")
@GetMapping("/oauth2")
public ResponseEntity<ApiResponse<String>> kakaoLogin(@RequestParam("code") String code,
@RequestParam("redirectUri") String redirectUri) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import com.matzip.lottery.dto.response.LotteryEventView;
import com.matzip.lottery.dto.response.ParticipatedEventResponseDto;
import com.matzip.lottery.service.LotteryEventService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;

import java.util.List;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
Expand All @@ -19,6 +21,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "이벤트", description = "추첨 이벤트 조회 및 응모 API")
@RequestMapping("/api/v1/events")
@RestController
public class LotteryEventController {
Expand All @@ -29,26 +32,36 @@ public LotteryEventController(LotteryEventService lotteryEventService) {
this.lotteryEventService = lotteryEventService;
}

@Operation(summary = "현재 진행 중인 이벤트 조회", description = "진행 중인 추첨 이벤트를 조회한다. 비로그인 시 익명 응답, 로그인 시 사용 티켓 수 등이 포함된다.")
@GetMapping
public ApiResponse<LotteryEventView> findEvent(@AuthenticationPrincipal UserPrincipal user) {
Long userId = (user != null) ? user.getUserId() : null;
LotteryEventView data = lotteryEventService.getCurrentEvent(userId);
return ApiResponse.success(data);
}

@Operation(summary = "내가 응모한 이벤트 목록", description = "인증된 사용자가 응모한 이벤트 목록을 조회한다. 인증 필요.")
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공", useReturnTypeSchema = true)
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "인증이 필요합니다.")
@GetMapping("/entries")
public ApiResponse<List<ParticipatedEventResponseDto>> getParticipatedEvents(@AuthenticationPrincipal UserPrincipal user) {
List<ParticipatedEventResponseDto> data = lotteryEventService.getParticipatedEvents(user.getUserId());
return ApiResponse.success(data);
}

@Operation(summary = "이벤트 응모 결과 조회", description = "특정 이벤트에 대한 응모/당첨 결과를 조회한다. 인증 필요.")
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공", useReturnTypeSchema = true)
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "인증이 필요합니다.")
@GetMapping("/{eventId}/entries")
public ApiResponse<EventEntryResultResponseDto> getEntryResult(@PathVariable Long eventId,
@AuthenticationPrincipal UserPrincipal user) {
EventEntryResultResponseDto data = lotteryEventService.getEntryResult(eventId, user.getUserId());
return ApiResponse.success(data);
}

@Operation(summary = "이벤트 응모", description = "연락처와 약관 동의 정보로 이벤트에 응모한다. 인증 필요.")
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "응모 성공", useReturnTypeSchema = true)
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "인증이 필요합니다.")
@PostMapping("/{eventId}/apply")
public ApiResponse<ApplyEventResponseDto> applyForPrize(@PathVariable Long eventId,
@Validated @RequestBody ApplyEventRequestDto request,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.matzip.lottery.dto.response;

import com.matzip.lottery.domain.WinnerContact;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;


@Builder
public record ApplyEventResponseDto(
String phoneNumber,
@Schema(description = "연락처", example = "010-1234-5678") String phoneNumber,
AgreementsResponse agreements
) {

public record AgreementsResponse(boolean termsAgreed, boolean privacyAgreed) {
public record AgreementsResponse(
@Schema(description = "이용약관 동의 여부", example = "true") boolean termsAgreed,
@Schema(description = "개인정보 수집 동의 여부", example = "true") boolean privacyAgreed) {
}

public static ApplyEventResponseDto from(WinnerContact contact) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package com.matzip.lottery.dto.response;

import com.matzip.lottery.domain.LotteryEvent;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

import java.time.LocalDateTime;

@Builder
public record EventEntryResultResponseDto(
Long eventId,
@Schema(description = "이벤트 ID", example = "3") Long eventId,
LotteryEventResponseDto.PrizeResponse prize,
int totalWinnersCount,
int participantsCount,
int usedTicketsCount,
boolean isWinner,
LocalDateTime eventEndDate,
boolean isPhoneSubmitted
@Schema(description = "총 당첨자 수", example = "3") int totalWinnersCount,
@Schema(description = "참여자 수", example = "27") int participantsCount,
@Schema(description = "사용한 응모권 수", example = "3") int usedTicketsCount,
@Schema(description = "당첨 여부", example = "true") boolean isWinner,
@Schema(description = "이벤트 종료 일시", example = "2025-08-21T00:00:00") LocalDateTime eventEndDate,
@Schema(description = "연락처 제출 여부", example = "true") boolean isPhoneSubmitted
) {

public static EventEntryResultResponseDto of(LotteryEvent event, int participantsCount, int usedTicketsCount,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package com.matzip.lottery.dto.response;

import com.matzip.lottery.domain.LotteryEvent;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

import java.time.LocalDateTime;

@Builder
public record LotteryEventAnonymousResponseDto(Long eventId, LotteryEventResponseDto.PrizeResponse prize,
int totalWinnersCount, int participantsCount, LocalDateTime eventEndDate)
public record LotteryEventAnonymousResponseDto(
@Schema(description = "이벤트 ID", example = "3") Long eventId,
LotteryEventResponseDto.PrizeResponse prize,
@Schema(description = "총 당첨자 수", example = "3") int totalWinnersCount,
@Schema(description = "참여자 수", example = "27") int participantsCount,
@Schema(description = "이벤트 종료 일시", example = "2025-08-21T00:00:00") LocalDateTime eventEndDate)
implements LotteryEventView {

public static LotteryEventAnonymousResponseDto empty() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

import com.matzip.lottery.domain.LotteryEvent;
import com.matzip.lottery.domain.Prize;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

import java.time.LocalDateTime;

@Builder
public record LotteryEventResponseDto(Long eventId, PrizeResponse prize, int totalWinnersCount, int participantsCount,
int usedTicketsCount, LocalDateTime eventEndDate)
public record LotteryEventResponseDto(
@Schema(description = "이벤트 ID", example = "3") Long eventId,
PrizeResponse prize,
@Schema(description = "총 당첨자 수", example = "3") int totalWinnersCount,
@Schema(description = "참여자 수", example = "27") int participantsCount,
@Schema(description = "사용한 응모권 수", example = "3") int usedTicketsCount,
@Schema(description = "이벤트 종료 일시", example = "2025-08-21T00:00:00") LocalDateTime eventEndDate)
implements LotteryEventView {

public static LotteryEventResponseDto empty() {
Expand All @@ -28,7 +34,9 @@ public static LotteryEventResponseDto of(LotteryEvent lotteryEvent, int particip
}

@Builder
record PrizeResponse(String description, String imageUrl) {
record PrizeResponse(
@Schema(description = "경품 설명", example = "BHC 뿌링클 치킨 기프티콘 1장") String description,
@Schema(description = "경품 이미지 URL", example = "https://example.com/images/bhc_bburinkle_chicken.png") String imageUrl) {

public static PrizeResponse from(Prize prize) {
return PrizeResponse.builder()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package com.matzip.lottery.dto.response;

import com.matzip.lottery.domain.LotteryEvent;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

import java.time.LocalDateTime;

@Builder
public record ParticipatedEventResponseDto(
Long eventId,
@Schema(description = "이벤트 ID", example = "3") Long eventId,
LotteryEventResponseDto.PrizeResponse prize,
int totalWinnersCount,
int participantsCount,
LocalDateTime eventEndDate
@Schema(description = "총 당첨자 수", example = "3") int totalWinnersCount,
@Schema(description = "참여자 수", example = "27") int participantsCount,
@Schema(description = "이벤트 종료 일시", example = "2025-08-21T00:00:00") LocalDateTime eventEndDate
) {

public static ParticipatedEventResponseDto of(LotteryEvent event, int participantsCount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.matzip.place.dto.response.PlaceCommonResponseDto;
import com.matzip.place.service.PlaceReadService;
import com.matzip.place.domain.Campus;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import com.matzip.place.service.CategoryService;
Expand All @@ -14,6 +16,7 @@

import java.util.List;

@Tag(name = "카테고리", description = "카테고리 및 카테고리별 맛집 조회 API")
@RestController
@RequestMapping("/api/v1/categories")
@RequiredArgsConstructor
Expand All @@ -22,6 +25,7 @@ public class CategoryController {
private final PlaceReadService placeReadService;
private final CategoryService categoryService;

@Operation(summary = "카테고리별 맛집 목록", description = "특정 카테고리에 속한 캠퍼스별 맛집 목록을 조회한다.")
@GetMapping("/{categoryId}/places")
public ApiResponse<List<PlaceCommonResponseDto>> getPlacesByCategory(
@PathVariable Long categoryId,
Expand All @@ -31,6 +35,7 @@ public ApiResponse<List<PlaceCommonResponseDto>> getPlacesByCategory(
return ApiResponse.success(places);
}

@Operation(summary = "전체 카테고리 목록", description = "등록에 사용할 수 있는 전체 카테고리 목록을 조회한다.")
@GetMapping
public ApiResponse<List<CategoryDto>> getAllCategories() {
List<CategoryDto> categories = categoryService.getAllCategories();
Expand Down
Loading
Loading