v2_techspec_journeywishlist - 100-hours-a-week/KTB4-8th-BE GitHub Wiki

μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈ 도메인

λ°μ΄ν„°λ² μ΄μŠ€ μŠ€ν‚€λ§ˆ

  • μ£Όμš” ν…Œμ΄λΈ”
    • member: νšŒμ› 정보 (νšŒμ› ID)
    • outing_wishlist_entry: μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈ μš”μ†Œ (순번 λ“±)
    • outing_course: μ—¬ν–‰ μ½”μŠ€ (μ—¬ν–‰ μ½”μŠ€ ID)
    • outing_guide: μž₯μ†Œ/이벀트 정보 (단일 ν…Œμ΄λΈ” 상속)

API λͺ…μ„Έ

λͺ©μ°¨

μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈμ— μ—¬ν–‰ μ½”μŠ€ μΆ”κ°€ API

λͺ©μ°¨λ‘œ λŒμ•„κ°€κΈ°

  • API λͺ…μ„Έ: POST /api/v2/member/outing-wishlist/outing-courses

  • κΆŒν•œ

    • λ‘œκ·ΈμΈν•œ μ‚¬μš©μž (μœ νš¨ν•˜λ©° λΈ”λž™λ¦¬μŠ€νŠΈμ— λ“±μž¬λ˜μ§€ μ•Šμ€ μ•‘μ„ΈμŠ€ 토큰 보유)
  • κ΅¬ν˜„ 상세

    • μš”μ²­

      • λ³Έλ¬Έ (@Valid @RequestBody)

        • outing_course_id: Long(@NotNull @Positive)
    • 처리 둜직

      1. μš”μ²­ λ³Έλ¬Έ μœ νš¨μ„± 검증, μ‹€νŒ¨ μ‹œ 422 였λ₯˜ λ°˜ν™˜

        • "INVALID_OUTING_COURSE_ID", "μœ νš¨ν•˜μ§€ μ•Šμ€ μ½”μŠ€ IDμž…λ‹ˆλ‹€."
      2. μ•‘μ„ΈμŠ€ ν† ν°μ—μ„œ νšŒμ› id μΆ”μΆœ

        • Long.valueOf(jwt.getSubject)
      3. μ„œλΉ„μŠ€ 계측에 μš”μ²­

        • member_id
        • ...Request
      4. outing_course_idλ₯Ό 톡해 Repository에 ν•΄λ‹Ή μ—¬ν–‰ μ½”μŠ€μ˜ 쑴재 μ—¬λΆ€ 확인

        • μ—¬ν–‰ μ½”μŠ€κ°€ μ‘΄μž¬ν•˜λŠ” μ§€ 확인, μ‘΄μž¬ν•˜μ§€ μ•Šμ„ μ‹œ 404 였λ₯˜ λ°˜ν™˜

          • "OUTING_COURSE_NOT_FOUND", "μ—¬ν–‰ μ½”μŠ€λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."
          • .findById(outingCourseId).orElseThrow(() -> new OutingCourseNotFoundException())
            
          • μ½”μŠ€λŠ” Soft Delete 정책이 μ μš©λ˜μ–΄ WHERE delete_datetime = null의 μΆ”κ°€ 쑰건 ν•„μš”
      5. μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈ μ—”ν‹°ν‹° 생성 (member_id, type="place", outing_course_id, save_datetime)

        • (memberId, outingCourseId, Instant.now())
      6. Repository에 μ €μž₯

        • λ§Œμ•½ μ €μž₯ 쀑 ν•΄λ‹Ή μ½”μŠ€κ°€ 기쑴에 μ €μž₯된 μ½”μŠ€μ™€ 쀑볡인 경우 409 였λ₯˜ λ°˜ν™˜

          • "OUTING_COURSE_DUPLICATE", "기쑴에 μ €μž₯된 μ½”μŠ€μ™€ μ€‘λ³΅λ©λ‹ˆλ‹€."
          • ...Repository.findByMemberIdAndOutingCourseId(memberId, outingCourseId)
                .ifPresent(() -> new OutingCourseDuplicateException());
            ...Repository.save(...);
            
    • νŠΈλžœμž­μ…˜ 관리

      • μ—”ν‹°ν‹° 생성 및 Repository μ €μž₯은 μ›μžμ μœΌλ‘œ μ²˜λ¦¬λ˜μ–΄μ•Ό 함
      • (member_id, outing_course_id)에 UNIQUE μ œμ•½ 쑰건이 ν•„μš”ν•  λ“―?

μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈμ— μΆ”κ°€ν•œ μž₯μ†Œ λͺ©λ‘ 쑰회 API

λͺ©μ°¨λ‘œ λŒμ•„κ°€κΈ°

  • API λͺ…μ„Έ: GET /api/v2/member/outing-wishlist/places

  • κΆŒν•œ

    • λ‘œκ·ΈμΈν•œ μ‚¬μš©μž (μœ νš¨ν•˜λ©° λΈ”λž™λ¦¬μŠ€νŠΈμ— λ“±μž¬λ˜μ§€ μ•Šμ€ μ•‘μ„ΈμŠ€ 토큰 보유)
  • κ΅¬ν˜„ 상세

    • νŽ˜μ΄μ§€μ˜ sizeλŠ” 50으둜 μ„€μ •

    • μ •λ ¬ 쑰건은 졜근 μ €μž₯ 순 (desc), ID(desc)

    • μš”μ²­

      • νŒŒλΌλ―Έν„° (@RequestParam)

        • location: String(도, κ΄‘μ—­/νŠΉλ³„μ‹œμ˜ 영문λͺ…(ex: "incheon", "daegu", ...), @NotBlank, required = false)
        • cursor: String(μ‘°νšŒν•  νŽ˜μ΄μ§€μ˜ μ»€μ„œ, @NotBlank, required = false(μš”μ²­μ— μ œκ³΅λ˜μ§€ μ•Šμ„ μ‹œ 첫 νŽ˜μ΄μ§€ 쑰회))
    • 처리 둜직

      1. μš”μ²­ νŒŒλΌλ―Έν„°κ°€ μœ νš¨μ„± 검증, μ‹€νŒ¨ μ‹œ 422 였λ₯˜ λ°˜ν™˜

        • "INVALID_FILTER", "μœ νš¨ν•˜μ§€ μ•Šμ€ ν•„ν„° μ‘°κ±΄μž…λ‹ˆλ‹€."
        • "INVALID_CURSOR", "μœ νš¨ν•˜μ§€ μ•Šμ€ μ»€μ„œμž…λ‹ˆλ‹€."
      2. μ•‘μ„ΈμŠ€ ν† ν°μ—μ„œ νšŒμ› id μΆ”μΆœ

        • Long.valueOf(jwt.getSubject)
          
      3. μ„œλΉ„μŠ€ 계측에 μš”μ²­

        • memberId
        • location
        • cursor
      4. cursorκ°€ κ°€λ¦¬ν‚€λŠ” νŽ˜μ΄μ§€μ˜ 쑴재 확인, 없을 μ‹œ 404 였λ₯˜ λ°˜ν™˜

        • "PAGE_NOT_FOUND", "νŽ˜μ΄μ§€λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."
      5. νšŒμ›μ˜ μœ„μ‹œλ¦¬μŠ€νŠΈ μš”μ†Œ ν…Œμ΄λΈ”κ³Ό μž₯μ†Œ ν…Œμ΄λΈ”μ„ 쑰인, location에 따라 ν•œ 번 더 필터링 μ§„ν–‰ν•œ κ²°κ³Ό λ°˜ν™˜

        • μž₯μ†ŒλŠ” Soft Delete 정책이 μ μš©λ˜μ–΄ WHERE delete_datetime = null의 μΆ”κ°€ 쑰건 ν•„μš”
      6. 검색 κ²°κ³Όκ°€ 0건일 μ‹œ, 빈 리슀트 λ°˜ν™˜

μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈμ— μΆ”κ°€ν•œ 행사 λͺ©λ‘ 쑰회 API

λͺ©μ°¨λ‘œ λŒμ•„κ°€κΈ°

  • API λͺ…μ„Έ: GET /api/v2/member/outing-wishlist/events

  • κΆŒν•œ

    • λ‘œκ·ΈμΈν•œ μ‚¬μš©μž (μœ νš¨ν•˜λ©° λΈ”λž™λ¦¬μŠ€νŠΈμ— λ“±μž¬λ˜μ§€ μ•Šμ€ μ•‘μ„ΈμŠ€ 토큰 보유)
  • κ΅¬ν˜„ 상세

    • νŽ˜μ΄μ§€μ˜ sizeλŠ” 50으둜 μ„€μ •

    • μ •λ ¬ 쑰건은 졜근 μ €μž₯ 순 (desc), ID(desc)

    • μš”μ²­

      • νŒŒλΌλ―Έν„° (@RequestParam)

        • ongoing: Boolean(ν˜„μž¬ 운영 쀑인 ν–‰μ‚¬λ§Œ μ‘°νšŒν•  μ§€ μ—¬λΆ€, @NotBlank, required = false)
        • cursor: String(μ‘°νšŒν•  νŽ˜μ΄μ§€μ˜ μ»€μ„œ, @NotBlank, required = false(μš”μ²­μ— μ œκ³΅λ˜μ§€ μ•Šμ„ μ‹œ 첫 νŽ˜μ΄μ§€ 쑰회))
    • 처리 둜직

      1. μš”μ²­ νŒŒλΌλ―Έν„°κ°€ μœ νš¨μ„± 검증, μ‹€νŒ¨ μ‹œ 422 였λ₯˜ λ°˜ν™˜

        • "INVALID_FILTER", "μœ νš¨ν•˜μ§€ μ•Šμ€ ν•„ν„° μ‘°κ±΄μž…λ‹ˆλ‹€."
        • "INVALID_CURSOR", "μœ νš¨ν•˜μ§€ μ•Šμ€ μ»€μ„œμž…λ‹ˆλ‹€."
      2. μ•‘μ„ΈμŠ€ ν† ν°μ—μ„œ νšŒμ› id μΆ”μΆœ

        • Long.valueOf(jwt.getSubject)
          
      3. μ„œλΉ„μŠ€ 계측에 μš”μ²­

        • memberId
        • ongoing
        • cursor
      4. cursorκ°€ κ°€λ¦¬ν‚€λŠ” νŽ˜μ΄μ§€μ˜ 쑴재 확인, 없을 μ‹œ 404 였λ₯˜ λ°˜ν™˜

        • "PAGE_NOT_FOUND", "νŽ˜μ΄μ§€λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."
      5. νšŒμ›μ˜ μœ„μ‹œλ¦¬μŠ€νŠΈ μš”μ†Œ ν…Œμ΄λΈ”κ³Ό 행사 ν…Œμ΄λΈ”μ„ μ‘°μΈν•˜κ³ , ongoing = trueμ‹œ ν˜„μž¬ μ‹œκ°„ < event.end_datetime둜 필터링 μ§„ν–‰ν•œ κ²°κ³Ό λ°˜ν™˜

        • ν–‰μ‚¬λŠ” Soft Delete 정책이 μ μš©λ˜μ–΄ WHERE delete_datetime = null의 μΆ”κ°€ 쑰건 ν•„μš”
      6. 검색 κ²°κ³Όκ°€ 0건일 μ‹œ, 빈 리슀트 λ°˜ν™˜

μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈμ— μΆ”κ°€ν•œ μ—¬ν–‰ μ½”μŠ€ λͺ©λ‘ 쑰회 API

λͺ©μ°¨λ‘œ λŒμ•„κ°€κΈ°

  • API λͺ…μ„Έ: GET /api/v2/member/outing-wishlist/outing-courses

  • κΆŒν•œ

    • λ‘œκ·ΈμΈν•œ μ‚¬μš©μž (μœ νš¨ν•˜λ©° λΈ”λž™λ¦¬μŠ€νŠΈμ— λ“±μž¬λ˜μ§€ μ•Šμ€ μ•‘μ„ΈμŠ€ 토큰 보유)
  • κ΅¬ν˜„ 상세

    • νŽ˜μ΄μ§€μ˜ sizeλŠ” 50으둜 μ„€μ •

    • μ •λ ¬ 쑰건은 졜근 μ €μž₯ 순 (desc), ID(desc)

    • μš”μ²­

      • νŒŒλΌλ―Έν„° (@RequestParam)

        • location: String(도, κ΄‘μ—­/νŠΉλ³„μ‹œμ˜ 영문λͺ…(ex: "incheon", "daegu", ...), @NotBlank, required = false)
        • cursor: String(μ‘°νšŒν•  νŽ˜μ΄μ§€μ˜ μ»€μ„œ, @NotBlank, required = false(μš”μ²­μ— μ œκ³΅λ˜μ§€ μ•Šμ„ μ‹œ 첫 νŽ˜μ΄μ§€ 쑰회))
    • 처리 둜직

      1. μš”μ²­ νŒŒλΌλ―Έν„°κ°€ μœ νš¨μ„± 검증, μ‹€νŒ¨ μ‹œ 422 였λ₯˜ λ°˜ν™˜

        • "INVALID_FILTER", "μœ νš¨ν•˜μ§€ μ•Šμ€ ν•„ν„° μ‘°κ±΄μž…λ‹ˆλ‹€."
        • "INVALID_CURSOR", "μœ νš¨ν•˜μ§€ μ•Šμ€ μ»€μ„œμž…λ‹ˆλ‹€."
      2. μ•‘μ„ΈμŠ€ ν† ν°μ—μ„œ νšŒμ› id μΆ”μΆœ

        • Long.valueOf(jwt.getSubject)
          
      3. μ„œλΉ„μŠ€ 계측에 μš”μ²­

        • memberId
        • location
        • cursor
      4. cursorκ°€ κ°€λ¦¬ν‚€λŠ” νŽ˜μ΄μ§€μ˜ 쑴재 확인, 없을 μ‹œ 404 였λ₯˜ λ°˜ν™˜

        • "PAGE_NOT_FOUND", "νŽ˜μ΄μ§€λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."
      5. νšŒμ›μ˜ μœ„μ‹œλ¦¬μŠ€νŠΈ μš”μ†Œ ν…Œμ΄λΈ”κ³Ό μ—¬ν–‰ μ½”μŠ€ ν…Œμ΄λΈ”μ„ μ‘°μΈν•˜κ³ , location에 따라 ν•œ 번 더 필터링 μ§„ν–‰ν•œ κ²°κ³Ό λ°˜ν™˜

        • μ—¬ν–‰ μ½”μŠ€λŠ” Soft Delete 정책이 μ μš©λ˜μ–΄ WHERE delete_datetime = null의 μΆ”κ°€ 쑰건 ν•„μš”
      6. 검색 κ²°κ³Όκ°€ 0건일 μ‹œ, 빈 리슀트 λ°˜ν™˜

μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈμ— μΆ”κ°€ν•œ μž₯μ†Œ 상세 쑰회 API

λͺ©μ°¨λ‘œ λŒμ•„κ°€κΈ°

  • API λͺ…μ„Έ: GET /api/v2/member/outing-wishlist/places/{placeId}

  • μš”μ²­

    • 경둜 λ³€μˆ˜ (@PathVariable)

      • placeId: Long (@Positive)
  • κΆŒν•œ

    • λ‘œκ·ΈμΈν•œ μ‚¬μš©μž
  • κ΅¬ν˜„ 상세

    • 처리 둜직
      1. placeId의 μœ νš¨μ„± 검증, μ‹€νŒ¨ μ‹œ 422 였λ₯˜ λ°˜ν™˜

        • "INVALID_PLACE_ID", "μœ νš¨ν•˜μ§€ μ•Šμ€ μž₯μ†Œ IDμž…λ‹ˆλ‹€."
      2. μ„œλΉ„μŠ€ 계측에 μš”μ²­

        • memberId
        • placeId
      3. placeId의 쑴재 μ—¬λΆ€ 확인, μ‘΄μž¬ν•˜μ§€ μ•Šμ„ μ‹œ 404 였λ₯˜ λ°˜ν™˜

        • "PLACE_NOT_FOUND", "μž₯μ†Œλ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."
        • ...Repository.findById(placeId).orElseThrow(() -> new PlaceNotFoundException())
          
        • μž₯μ†ŒλŠ” Soft Delete 정책이 μ μš©λ˜μ–΄ WHERE delete_datetime = null의 μΆ”κ°€ 쑰건 ν•„μš”
      4. Repositoryμ—μ„œ placeIdκ°€ κ°€λ¦¬ν‚€λŠ” μž₯μ†Œ 쑰회 ν›„ λ°˜ν™˜

μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈμ— μΆ”κ°€ν•œ 행사 상세 쑰회 API

λͺ©μ°¨λ‘œ λŒμ•„κ°€κΈ°

  • API λͺ…μ„Έ: GET /api/v2/member/outing-wishlist/events/{eventId}

  • μš”μ²­

    • 경둜 λ³€μˆ˜ (@PathVariable)

      • eventId: Long (@Positive)
  • κΆŒν•œ

    • λ‘œκ·ΈμΈν•œ μ‚¬μš©μž
  • κ΅¬ν˜„ 상세

    • 처리 둜직
      1. eventId의 μœ νš¨μ„± 검증, μ‹€νŒ¨ μ‹œ 422 였λ₯˜ λ°˜ν™˜

        • "INVALID_EVENT_ID", "μœ νš¨ν•˜μ§€ μ•Šμ€ 행사 IDμž…λ‹ˆλ‹€."
      2. μ„œλΉ„μŠ€ 계측에 μš”μ²­

        • memberId
        • eventId
      3. eventId의 쑴재 μ—¬λΆ€ 확인, μ‘΄μž¬ν•˜μ§€ μ•Šμ„ μ‹œ 404 였λ₯˜ λ°˜ν™˜

        • "EVENT_NOT_FOUND", "행사λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."
        • ...Repository.findById(eventId).orElseThrow(() -> new EventNotFoundException())
          
        • ν–‰μ‚¬λŠ” Soft Delete 정책이 μ μš©λ˜μ–΄ WHERE delete_datetime = null의 μΆ”κ°€ 쑰건 ν•„μš”
      4. Repositoryμ—μ„œ eventIdκ°€ κ°€λ¦¬ν‚€λŠ” 행사 쑰회 ν›„ λ°˜ν™˜

μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈμ— μΆ”κ°€ν•œ μ—¬ν–‰ μ½”μŠ€ 상세 쑰회 API

λͺ©μ°¨λ‘œ λŒμ•„κ°€κΈ°

  • API λͺ…μ„Έ: GET /api/v2/member/outing-wishlist/outing-courses/{outingCourseId}

  • κΆŒν•œ

    • λ‘œκ·ΈμΈν•œ μ‚¬μš©μž
  • μš”μ²­

    • 경둜 λ³€μˆ˜ (@PathVariable)

      • outingCourseId: Long (@Positive)
  • κ΅¬ν˜„ 상세

    • 처리 둜직

      1. outingCourseId의 μœ νš¨μ„± 검증, μ‹€νŒ¨ μ‹œ 422 였λ₯˜ λ°˜ν™˜

        • "INVALID_OUTING_COURSE_ID", "μœ νš¨ν•˜μ§€ μ•Šμ€ μ—¬ν–‰ μ½”μŠ€ IDμž…λ‹ˆλ‹€."
      2. μ„œλΉ„μŠ€ 계측에 μš”μ²­

        • memberId
        • outingCourseId
      3. outingCourseId의 쑴재 μ—¬λΆ€ 확인, μ‘΄μž¬ν•˜μ§€ μ•Šμ„ μ‹œ 404 였λ₯˜ λ°˜ν™˜

        • "OUTING_COURSE_NOT_FOUND", "μ—¬ν–‰ μ½”μŠ€λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."
        • ...Repository.findById(outingCourseId).orElseThrow(() -> new OutingCourseNotFoundException)
          
        • μ—¬ν–‰ μ½”μŠ€λŠ” Soft Delete 정책이 μ μš©λ˜μ–΄ WHERE delete_datetime = null의 μΆ”κ°€ 쑰건 ν•„μš”
      4. Repositoryμ—μ„œ outingCourseIdκ°€ κ°€λ¦¬ν‚€λŠ” μ—¬ν–‰ μ½”μŠ€ 쑰회 ν›„ λ°˜ν™˜

μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈμ—μ„œ μž₯μ†Œ 제거 API

λͺ©μ°¨λ‘œ λŒμ•„κ°€κΈ°

  • API λͺ…μ„Έ: DELETE /api/v2/member/outing-wishlist/places/{placeId}

  • μš”μ²­

    • 경둜 λ³€μˆ˜ (@PathVariable)

      • placeId: Long (@Positive)
  • κΆŒν•œ

    • λ‘œκ·ΈμΈν•œ μ‚¬μš©μž
  • κ΅¬ν˜„ 상세

    • 처리 둜직
      1. placeId의 μœ νš¨μ„± 검증, μ‹€νŒ¨ μ‹œ 422 였λ₯˜ λ°˜ν™˜

        • "INVALID_PLACE_ID", "μœ νš¨ν•˜μ§€ μ•Šμ€ μž₯μ†Œ IDμž…λ‹ˆλ‹€."
      2. μ„œλΉ„μŠ€ 계측에 μš”μ²­

        • memberId
        • placeId
      3. placeId의 쑴재 μ—¬λΆ€ 확인, μ‘΄μž¬ν•˜μ§€ μ•Šμ„ μ‹œ 404 였λ₯˜ λ°˜ν™˜

        • "PLACE_NOT_FOUND", "μž₯μ†Œλ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."
        • ...Repository.findById(placeId).orElseThrow(() -> new PlaceNotFoundException())
          
        • μž₯μ†ŒλŠ” Soft Delete 정책이 μ μš©λ˜μ–΄ WHERE delete_datetime = null의 μΆ”κ°€ 쑰건 ν•„μš”
      4. Repositoryμ—μ„œ placeIdκ°€ κ°€λ¦¬ν‚€λŠ” μž₯μ†Œ μ‚­μ œ

        • .delete()
  • νŠΈλžœμž­μ…˜ 관리

    • Soft Delete μ •μ±… (@Transactional ν•„μš”)

μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈμ—μ„œ 행사 제거 API

λͺ©μ°¨λ‘œ λŒμ•„κ°€κΈ°

  • API λͺ…μ„Έ: DELETE /api/v2/member/outing-wishlist/events/{eventId}

  • μš”μ²­

    • 경둜 λ³€μˆ˜ (@PathVariable)

      • eventId: Long (@Positive)
  • κΆŒν•œ

    • λ‘œκ·ΈμΈν•œ μ‚¬μš©μž
  • κ΅¬ν˜„ 상세

    • 처리 둜직
      1. eventId의 μœ νš¨μ„± 검증, μ‹€νŒ¨ μ‹œ 422 였λ₯˜ λ°˜ν™˜

        • "INVALID_EVENT_ID", "μœ νš¨ν•˜μ§€ μ•Šμ€ 행사 IDμž…λ‹ˆλ‹€."
      2. μ„œλΉ„μŠ€ 계측에 μš”μ²­

        • memberId
        • eventId
      3. eventId의 쑴재 μ—¬λΆ€ 확인, μ‘΄μž¬ν•˜μ§€ μ•Šμ„ μ‹œ 404 였λ₯˜ λ°˜ν™˜

        • "EVENT_NOT_FOUND", "행사λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."
        • ...Repository.findById(eventId).orElseThrow(() -> new EventNotFoundException())
          
        • ν–‰μ‚¬λŠ” Soft Delete 정책이 μ μš©λ˜μ–΄ WHERE delete_datetime = null의 μΆ”κ°€ 쑰건 ν•„μš”
      4. Repositoryμ—μ„œ eventIdκ°€ κ°€λ¦¬ν‚€λŠ” 행사 μ‚­μ œ

        • .delete()
  • νŠΈλžœμž­μ…˜ 관리

    • Soft Delete μ •μ±… (@Transactional ν•„μš”)

μ—¬ν–‰ μœ„μ‹œλ¦¬μŠ€νŠΈμ—μ„œ μ—¬ν–‰ μ½”μŠ€ 제거 API

λͺ©μ°¨λ‘œ λŒμ•„κ°€κΈ°

  • API λͺ…μ„Έ: DELETE /api/v2/member/outing-wishlist/outing-courses/{outingCourseId}

  • μš”μ²­

    • 경둜 λ³€μˆ˜ (@PathVariable)

      • outingCourseId: Long (@Positive)
  • κΆŒν•œ

    • λ‘œκ·ΈμΈν•œ μ‚¬μš©μž
  • κ΅¬ν˜„ 상세

    • 처리 둜직

      1. outingCourseId의 μœ νš¨μ„± 검증, μ‹€νŒ¨ μ‹œ 422 였λ₯˜ λ°˜ν™˜

        • "INVALID_OUTING_COURSE_ID", "μœ νš¨ν•˜μ§€ μ•Šμ€ μ—¬ν–‰ μ½”μŠ€ IDμž…λ‹ˆλ‹€."
      2. μ„œλΉ„μŠ€ 계측에 μš”μ²­

        • memberId
        • outingCourseId
      3. outingCourseId의 쑴재 μ—¬λΆ€ 확인, μ‘΄μž¬ν•˜μ§€ μ•Šμ„ μ‹œ 404 였λ₯˜ λ°˜ν™˜

        • "OUTING_COURSE_NOT_FOUND", "μ—¬ν–‰ μ½”μŠ€λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."
        • ...Repository.findById(outingCourseId).orElseThrow(() -> new OutingCourseNotFoundException())
          
        • μ—¬ν–‰ μ½”μŠ€λŠ” Soft Delete 정책이 μ μš©λ˜μ–΄ WHERE delete_datetime = null의 μΆ”κ°€ 쑰건 ν•„μš”
      4. Repositoryμ—μ„œ outingCourseIdκ°€ κ°€λ¦¬ν‚€λŠ” μ—¬ν–‰ μ½”μŠ€ μ‚­μ œ

        • .delete()
  • νŠΈλžœμž­μ…˜ 관리

    • Soft Delete μ •μ±… (@Transactional ν•„μš”)