Skip to content

Conversation

@hardwoong
Copy link
Member

관련 이슈

closed #10

작업한 내용

1. 가게 생성 API 구현

  • API 엔드포인트: POST /api/v1/stores
  • 기능: 특정 지역에 가게를 추가합니다
  • 요청 DTO: StoreReqDTO.CreateStoreDTO
    • storeName: 가게명
    • storeAddress: 가게 주소
    • storeType: 가게 유형 (Enum: KOREAN, CHINESE, JAPANESE, WESTERN, CHICKEN, SNACK, MEAT, DOSIRAK, YASICK, DESSERT, FAST_FOOD, ASIAN, ETC)
    • regionName: 지역 이름
  • 응답 DTO: StoreResDTO.CreateStoreDTO
    • storeId: 생성된 가게 ID
    • createdAt: 생성 시간
  • 구현 컴포넌트:
    • StoreController: REST API 엔드포인트 제공
    • StoreCommandService / StoreCommandServiceImpl: 비즈니스 로직 처리
    • StoreConverter: DTO ↔ Entity 변환
    • StoreRepository: JPA Repository
    • StoreSuccessCode.STORE_CREATED: 성공 응답 코드
스크린샷 2025-11-10 오전 3 11 53

2. 가게 리뷰 추가 API 구현

  • API 엔드포인트: POST /api/v1/reviews
  • 기능: 가게에 리뷰를 작성합니다
  • 요청 DTO: ReviewReqDTO.CreateReviewDTO
    • storeId: 가게 ID (Long, @ExistStores Validation 적용)
    • reviewText: 리뷰 내용
    • score: 별점 (BigDecimal)
  • 응답 DTO: ReviewResDTO.CreateReviewDTO
    • reviewId: 생성된 리뷰 ID
    • createdAt: 생성 시간
  • 구현 컴포넌트:
    • ReviewController: REST API 엔드포인트 제공
    • ReviewCommandService / ReviewCommandServiceImpl: 비즈니스 로직 처리
    • ReviewConverter: DTO ↔ Entity 변환
    • ReviewRepository: JPA Repository
    • ReviewSuccessCode.REVIEW_CREATED: 성공 응답 코드
  • 특이사항:
    • 현재는 하드코딩된 사용자(user_id=1)로 리뷰가 작성됩니다
    • @ExistStores 커스텀 Validation으로 가게 존재 여부를 자동 검증합니다
스크린샷 2025-11-10 오전 3 12 07

3. 가게 미션 추가 API 구현

  • API 엔드포인트: POST /api/v1/missions
  • 기능: 가게에 미션을 추가합니다
  • 요청 DTO: MissionReqDTO.CreateMissionDTO
    • storeId: 가게 ID (Long, @ExistStores Validation 적용)
    • region: 지역 (Enum: SEOUL, BUSAN, DAEGU, INCHEON, GWANGJU, DAEJEON, ULSAN, GYEONGGI, GANGWON, CHUNGBUK, CHUNGNAM, JEONBUK, JEONNAM, GYEONGBUK, GYEONGNAM, JEJU)
    • missionMoney: 미션 보상 금액 (Long)
    • missionPoint: 미션 보상 포인트 (Long)
  • 응답 DTO: MissionResDTO.CreateMissionDTO
    • missionId: 생성된 미션 ID
    • createdAt: 생성 시간
  • 구현 컴포넌트:
    • MissionController: REST API 엔드포인트 제공
    • MissionCommandService / MissionCommandServiceImpl: 비즈니스 로직 처리
    • MissionConverter: DTO ↔ Entity 변환
    • MissionRepository: JPA Repository
    • MissionSuccessCode.MISSION_CREATED: 성공 응답 코드
  • 특이사항:
    • @ExistStores 커스텀 Validation으로 가게 존재 여부를 자동 검증합니다
스크린샷 2025-11-10 오전 3 12 34

4. 도전 중인 미션에 추가 API 구현

  • API 엔드포인트: POST /api/v1/missions/challenge
  • 기능: 가게의 미션을 도전 중인 미션에 추가합니다
  • 요청 DTO: MissionReqDTO.ChallengeMissionDTO
    • missionId: 미션 ID (Long, @ExistMissions Validation 적용)
  • 응답 DTO: MissionResDTO.ChallengeMissionDTO
    • challengeMissionId: 생성된 도전 미션 ID
    • createdAt: 생성 시간
  • 구현 컴포넌트:
    • MissionController: REST API 엔드포인트 제공
    • MissionCommandService / MissionCommandServiceImpl: 비즈니스 로직 처리
    • MissionConverter: DTO ↔ Entity 변환
    • UserMissionRepository: JPA Repository
    • MissionSuccessCode.MISSION_CHALLENGED: 성공 응답 코드
  • 특이사항:
    • 현재는 하드코딩된 사용자(user_id=1)로 미션이 도전됩니다
    • @ExistMissions 커스텀 Validation으로 미션 존재 여부를 자동 검증합니다
    • 미션에서 가게 정보를 자동으로 가져와 UserMission 엔티티에 저장합니다
스크린샷 2025-11-10 오전 3 12 54

5. 회원가입 API 구현

  • API 엔드포인트: POST /api/v1/members/signup
  • 기능: 새로운 회원을 등록합니다
  • 요청 DTO: MemberReqDTO.JoinDTO
    • name: 회원 이름
    • gender: 성별 (Enum: NONE, MALE, FEMALE)
    • birth: 생년월일 (LocalDate)
    • address: 주소
    • specAddress: 상세 주소
    • preferCategory: 선호 카테고리 ID 리스트 (List)
  • 응답 DTO: MemberResDTO.JoinDTO
    • memberId: 생성된 회원 ID
    • createdAt: 생성 시간
  • 구현 컴포넌트:
    • MemberController: REST API 엔드포인트 제공
    • MemberCommandService / MemberCommandServiceImpl: 비즈니스 로직 처리
    • MemberConverter: DTO ↔ Entity 변환
    • MemberRepository: JPA Repository
    • UserPreferRepository: 선호 카테고리 저장용 Repository
    • PreferCategoryRepository: 선호 카테고리 조회용 Repository
    • MemberSuccessCode.MEMBER_CREATED: 성공 응답 코드
  • 특이사항:
    • Stream API를 사용하여 선호 카테고리를 일괄 처리합니다
    • 선호 카테고리 존재 여부를 검증하고, 없으면 CategoryException을 발생시킵니다
    • @Transactional을 통해 회원 생성과 선호 카테고리 저장을 하나의 트랜잭션으로 처리합니다
스크린샷 2025-11-10 오전 3 13 14

6. Swagger Config 구현

  • 파일: SwaggerConfig.java
  • 기능: API 문서화를 위한 Swagger 설정
  • 구현 내용:
    • OpenAPI 3.0 스펙 기반 설정
    • JWT 토큰 인증 방식 설정
    • API 정보 (제목, 설명, 버전) 설정
  • 접속 URL: http://localhost:8080/swagger-ui/index.html
image

7. 커스텀 Validation 어노테이션 구현

  • @ExistStores: 가게 존재 여부 검증
    • 적용 위치: ReviewReqDTO.CreateReviewDTO.storeId, MissionReqDTO.CreateMissionDTO.storeId
    • Validator: StoreExistValidator
    • 에러 코드: StoreErrorCode.STORE_NOT_FOUND
  • @ExistMissions: 미션 존재 여부 검증
    • 적용 위치: MissionReqDTO.ChallengeMissionDTO.missionId
    • Validator: MissionExistValidator
    • 에러 코드: MissionErrorCode.MISSION_NOT_FOUND
  • 구현 패턴:
    • @Constraint(validatedBy = ...) 어노테이션 정의
    • ConstraintValidator 인터페이스 구현
    • Repository를 주입받아 DB에서 존재 여부 확인
    • 검증 실패 시 커스텀 에러 메시지 반환

PR Point 및 참고사항, 스크린샷

핵심 구현 사항

  1. 워크북 패턴 준수:

    • DTO 패턴: record 사용 (ReqDTO, ResDTO)
    • Converter 패턴: Entity ↔ DTO 변환 메서드 구현
    • Exception 패턴: ErrorCode, SuccessCode, Exception 클래스 구조 일치
    • Service 패턴: CommandService 인터페이스 + 구현체 분리
    • Controller 패턴: @Valid 사용, ApiResponse.onSuccess() 사용
  2. 트랜잭션 관리:

    • 모든 Command Service 메서드에 @Transactional 적용
    • 데이터 정합성 보장
  3. Validation 전략:

    • DTO 레벨에서 커스텀 Validation 어노테이션 사용
    • Service 레벨에서 비즈니스 로직 검증
    • 단일 책임 원칙 준수
  4. 에러 처리:

    • 도메인별 Exception 클래스 (StoreException, ReviewException, MissionException, MemberException, CategoryException)
    • 도메인별 ErrorCode 및 SuccessCode 정의
    • GlobalExceptionHandler를 통한 통일된 에러 응답

참고사항

  • 현재 리뷰 작성 및 미션 도전 API는 하드코딩된 사용자(user_id=1)를 사용합니다
  • 모든 API는 @Valid 어노테이션을 통해 요청 데이터 검증을 수행합니다
  • 커스텀 Validation 어노테이션(@ExistStores, @ExistMissions)을 통해 DB 존재 여부를 자동 검증합니다

@hardwoong hardwoong self-assigned this Nov 9, 2025
@hardwoong hardwoong added the enhancement New feature or request label Nov 9, 2025
@hardwoong hardwoong linked an issue Nov 9, 2025 that may be closed by this pull request
Copy link

@ggamnunq ggamnunq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good

List<UserPrefer> userPreferList = dto.preferCategory().stream()
.map(id -> {
// 선호 카테고리 존재 여부 검증
PreferCategory preferCategory = preferCategoryRepository.findById(id)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런거는 메서드로 따로 빼둬도 될듯요? (취향차이이긴 함)

.collect(Collectors.toList());

// 모든 선호 음식 추가: DB 적용
userPreferRepository.saveAll(userPreferList);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스터디 때도 말했지만, 한 번에 많은 데이터 저장할 때 다량의 insert 쿼리 발생하는거 조심

@RequiredArgsConstructor
public class MissionExistValidator implements ConstraintValidator<ExistMissions, Long> {

private final MissionRepository missionRepository;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repository 코드에는 웬만하면 service에서만 접근하게 하도록 하면 좋습니다.

@hardwoong hardwoong merged commit 59d8f9f into develop Nov 23, 2025
@hardwoong hardwoong deleted the Feat/chapter8 branch November 23, 2025 07:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] Week8 Mission

3 participants