Skip to content

๐Ÿซง๐Ÿ“š ์ฑ…์—์„œ ํ๊ธ€ ํ”ผ์–ด๋‚œ ๊ฐ์ƒ์„ ๊ธฐ๋กํ•˜๊ณ , ๋น„๋ˆ—๋ฐฉ์šธ์ฒ˜๋Ÿผ ๊ณต์œ ํ•˜๋Š” ์„œ๋น„์Šค

Notifications You must be signed in to change notification settings

jeongeungyeong/pong-guel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

PONGGEUL(ํ๊ธ€ํ๊ธ€) ๐Ÿซง๐Ÿ“š

๋ณธ ์„œ๋น„์Šค๋Š” ์‚ฌ์šฉ์ž์˜ ๋…์„œ ์ทจํ–ฅ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž์œ ๋กœ์šด ๊ฐ์ƒํ‰์„ ์ž‘์„ฑํ•˜๊ณ  ๊ณต์œ ํ•˜๋Š” ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.
๋„ค์ด๋ฒ„ ๊ฒ€์ƒ‰ API๋กœ ๊ฒ€์ƒ‰์–ด๋กœ ์ฑ…์„ ์ง์ ‘ ๊ฒ€์ƒ‰ํ•˜๊ณ , ๊ฐ์ƒํ‰์„ ๋…ธํŠธ์— ์ž‘์„ฑํ•ด ๊ทธ๋•Œ ํ๊ธ€ํ๊ธ€ํ–ˆ๋˜ ๊ฐ์ƒ์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.
๋”๋ถˆ์–ด ์นœ๊ตฌ๋“ค์—๊ฒŒ ๋น„๋ˆ—๋ฐฉ์šธ ๋‚ ๋ฆฌ๋“ฏ ์ฑ…๊ณผ ๋…ธํŠธ๋ฅผ ์นด์นด์˜คํ†ก ๋ฉ”์‹œ์ง€๋กœ ๊ณต์œ ํ•ด ์ง€์†์ ์ธ ๋…์„œํ™œ๋™์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.


๋ชฉ์ฐจ

ย ย 2-1. ERD
ย ย 2-2. ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

๊ฐœ์š”

  • "์ „์— ์žฌ๋ฏธ์žˆ๊ฒŒ ์ฝ๋˜ ์ฑ…์ด ๋ญ์˜€์ง€?"
  • "์ฑ…๋ณ„๋กœ ์งง๊ฒŒ ๋…ธํŠธ๋ฅผ ์ ์–ด ๊ฐ์ƒ๋ฌธ์„ ์ •๋ฆฌํ•ด๋†“๊ณ  ์‹ถ๋‹ค!"
  • "์นœ๊ตฌ๋“ค์ด ๊ผญ ์ฝ์–ด์คฌ์œผ๋ฉด ์ข‹๊ฒ ๋Š”๋ฐ... ๊ฐ์ƒ๊ณผ ํ•จ๊ป˜ ์–ด๋–ป๊ฒŒ ์•Œ๋ ค์ฃผ์ง€?"
  • ํ๊ธ€ํ๊ธ€์—์„œ ์œ„ ๊ณ ๋ฏผ๋“ค ์ „๋ถ€ ํ•ด๊ฒฐํ•ด๋ณด์„ธ์š”!!!

์‹คํ–‰ ํ™˜๊ฒฝ

  • application-secret.yml ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํŒŒ์ผ ์ƒ์„ฑ
    ํ•ด๋‹น ํ”„๋กœ์ ํŠธ๋Š” ์•„๋ž˜ ํ•ญ๋ชฉ๋“ค์ด ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํŒŒ์ผ์— ์ „๋ถ€ ์กด์žฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    secret.yml
    spring:
      data:
        redis:
          host: 
          port: 
    
    kakao:
      client_id: 
      redirect_url:
      logout_redirect_url: #๋ฉ”์ธํŽ˜์ด์ง€
      user_base_url: 
      kauth_base_url: 
      user_info_url: 
      send_base_url: 
      send_me_url: 
      user_friend_url: 
      send_friends_url: 
    
    jwt:
      access_secret_key: 
      refresh_secret_key: 
      share_secret_key: 
    
    naver:
      client_id: 
      client_secret: 
      book_base_url: o
    
    share_book:
      share_base_url: 
    
    

๊ธฐ์ˆ  ์Šคํƒ

Java Spring SpringBoot SpringDataJPA SpringSecurity MySQL Redis Docker Figma

ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ

Notion Discord

  • ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ ์ „ ๋งŒ๋“ค์–ด์•ผ ํ•  API๋ฅผ ๋…ธ์…˜ ๋ณด๋“œ์— ์ „์ฒด์™€ ์„œ๋น„์Šค๋ณ„ ํ‹ฐ์ผ“์œผ๋กœ ์ž‘์„ฑํ•˜๊ณ 

  • ํƒ€์ผ“๋งˆ๋‹ค MoSCoW ๋ฐฉ์‹์œผ๋กœ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ •ํ•˜๋ฉฐ, ํ‹ฐ์ผ“๋งˆ๋‹ค ์ด์Šˆ ์ƒ์„ฑํ•˜์˜€๊ณ 

  • PR ์ƒ์„ฑํ•  ๋•Œ, ๋ณ€๊ฒฝ์‚ฌํ•ญ๊ณผ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ๋จธ์ง€ ์ง„ํ–‰

  • ๋””์Šค์ฝ”๋“œ webhook์„ ํ™œ์šฉํ•ด PR ๊ด€๋ จ ์•Œ๋ฆผ์„ ํ™•์ธํ•˜๊ณ  ๋‹ค์Œ ์ž‘์—… ์ง„ํ–‰

    ์ผ์ • ๊ด€๋ฆฌ

    ์ „์ฒด ์ผ์ • ๊ด€๋ฆฌ
    ์ „์ฒด ์ผ์ • ๊ด€๋ฆฌ
    ์‚ฌ์šฉ์ž
    ์‚ฌ์šฉ์ž
    ์ฑ…
    ์ฑ…
    ๋…ธํŠธ
    ๋…ธํŠธ
    ์ด์Šˆ ๊ด€๋ฆฌ
    PR ๊ด€๋ฆฌ
    PR ๋ณ€๊ฒฝ์‚ฌํ•ญ ์ž‘์„ฑ
    PR ์•Œ๋ฆผ
    ๋””์Šค์ฝ”๋“œ ์•Œ๋ฆผ

ERD ๋ฐ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

ERD
๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ
    โ”œโ”€โ”€ main
    โ”‚ย ย  โ”œโ”€โ”€ java
    โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ org
    โ”‚ย ย  โ”‚ย ย      โ””โ”€โ”€ example
    โ”‚ย ย  โ”‚ย ย          โ””โ”€โ”€ pongguel
    โ”‚ย ย  โ”‚ย ย              โ”œโ”€โ”€ PongguelApplication.java
    โ”‚ย ย  โ”‚ย ย              โ”œโ”€โ”€ book
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ controller
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ BookController.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ BookLikeController.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ BookSaveController.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ BookShareController.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ domain
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ Book.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ dto
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ BookDetailWithNoteListResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ DeleteSavedBookResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ LikeBookResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ LikedBookListResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ SaveSelectedBookResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ SavedBookListResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ SearchBookList.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ SearchBookRequest.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ SearchBookResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ SelectedBook.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ ShareBookResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ SharedBookDetailWithNoteListResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ repository
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ BookRepository.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ””โ”€โ”€ service
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ”œโ”€โ”€ BookService.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ”œโ”€โ”€ LikedBookService.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ”œโ”€โ”€ SavedBookService.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ”œโ”€โ”€ ShareBookByKakaoTalkService.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ””โ”€โ”€ SharedBooksDetailService.java
    โ”‚ย ย  โ”‚ย ย              โ”œโ”€โ”€ config
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ ApiConfig.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ RedisConfig.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ SecurityConfig.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ””โ”€โ”€ SwaggerConfig.java
    โ”‚ย ย  โ”‚ย ย              โ”œโ”€โ”€ exception
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ BadRequestException.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ BaseException.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ ConflictException.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ ErrorCode.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ ErrorResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ ForbiddenException.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ InternalServerException.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ NotFoundException.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ UnauthorizedException.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ””โ”€โ”€ handler
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ””โ”€โ”€ GlobalExceptionHandler.java
    โ”‚ย ย  โ”‚ย ย              โ”œโ”€โ”€ feign
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ client
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ SendKakaoTalkClient.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ dto
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ KakaoFriendsInfo.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ KakaoTalkFriendsSendRequest.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ KakaoTalkSendRequest.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ KakaoTalkSendResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ””โ”€โ”€ service
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ””โ”€โ”€ KakaoTalkService.java
    โ”‚ย ย  โ”‚ย ย              โ”œโ”€โ”€ jwt
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ JwtAuthenticationFilter.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ JwtTokenProvider.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ JwtUtil.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ controller
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ JwtController.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ domain
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ CustomUserDetails.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ dto
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ JwtTokenDto.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ TokenRefreshRequest.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ””โ”€โ”€ service
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ”œโ”€โ”€ JwtService.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ””โ”€โ”€ UserDetailService.java
    โ”‚ย ย  โ”‚ย ย              โ”œโ”€โ”€ main
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ controller
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ MainController.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ””โ”€โ”€ service
    โ”‚ย ย  โ”‚ย ย              โ”œโ”€โ”€ note
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ controller
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ NoteBookmarkController.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ NoteController.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ NoteDetailController.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ domain
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ Note.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ dto
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ BookmarkNoteResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ BookmarkedNoteListResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ NoteDeleteResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ NoteDetailResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ NoteListResponse.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ NoteWriteRequest.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ repository
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ NoteRepository.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ””โ”€โ”€ service
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ”œโ”€โ”€ NoteBookmarkService.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ”œโ”€โ”€ NoteDeleteService.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ”œโ”€โ”€ NoteDetailService.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย      โ””โ”€โ”€ NoteService.java
    โ”‚ย ย  โ”‚ย ย              โ”œโ”€โ”€ redis
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ RedisController.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ RedisParam.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ”œโ”€โ”€ RedisRepository.java
    โ”‚ย ย  โ”‚ย ย              โ”‚ย ย  โ””โ”€โ”€ RedisService.java
    โ”‚ย ย  โ”‚ย ย              โ””โ”€โ”€ user
    โ”‚ย ย  โ”‚ย ย                  โ”œโ”€โ”€ controller
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ KakaoReissueController.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ KakaoSignInController.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ KakaoSignOutController.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ””โ”€โ”€ UserDetailController.java
    โ”‚ย ย  โ”‚ย ย                  โ”œโ”€โ”€ domain
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ KakaoToken.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ Role.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ””โ”€โ”€ User.java
    โ”‚ย ย  โ”‚ย ย                  โ”œโ”€โ”€ dto
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ KakaoTokenInfo.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ KakaoUserInfoAndToken.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ KakaoUserInfoResponse.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ LoginResponse.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ LoginResult.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ PongUserInfo.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ””โ”€โ”€ UnlinkedUserDto.java
    โ”‚ย ย  โ”‚ย ย                  โ”œโ”€โ”€ repository
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ”œโ”€โ”€ KakaoTokenRepository.java
    โ”‚ย ย  โ”‚ย ย                  โ”‚ย ย  โ””โ”€โ”€ UserRepository.java
    โ”‚ย ย  โ”‚ย ย                  โ””โ”€โ”€ service
    โ”‚ย ย  โ”‚ย ย                      โ”œโ”€โ”€ KakaoSignInService.java
    โ”‚ย ย  โ”‚ย ย                      โ”œโ”€โ”€ KakaoSignOutService.java
    โ”‚ย ย  โ”‚ย ย                      โ”œโ”€โ”€ KakaoTokenReissueService.java
    โ”‚ย ย  โ”‚ย ย                      โ”œโ”€โ”€ UserService.java
    โ”‚ย ย  โ”‚ย ย                      โ””โ”€โ”€ ValidateUser.java
    โ”‚ย ย  โ””โ”€โ”€ resources
    โ”‚ย ย      โ”œโ”€โ”€ application-secret.yml
    โ”‚ย ย      โ”œโ”€โ”€ application.yml
    โ”‚ย ย      โ”œโ”€โ”€ static
    โ”‚ย ย      โ””โ”€โ”€ templates
    โ””โ”€โ”€ test
        โ””โ”€โ”€ java
            โ””โ”€โ”€ org
                โ””โ”€โ”€ example
                    โ””โ”€โ”€ pongguel
                        โ””โ”€โ”€ PongguelApplicationTests.java

๊ธฐ๋Šฅ๊ตฌํ˜„

์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฐ ํšŒ์›๊ฐ€์ž… (Kakao ๋กœ๊ทธ์ธ API)

  • ์นด์นด์˜ค ์ด๋ฉ”์ผ ์ค‘๋ณต์ฒดํฌ
  • ํšŒ์›์ •๋ณด๊ฐ€ ์—†์„ ์‹œ ํšŒ์›๊ฐ€์ž… ํ•จ๊ป˜ ์ง„ํ–‰
  • ๋กœ๊ทธ์ธ ์‹œ JWT(Json Web Token) ๋ฐœ๊ธ‰ -> ๋ชจ๋“  API ์š”์ฒญ์‹œ JWT ์ธ๊ฐ€

์„œ๋น„์Šค ๋กœ๊ทธ์•„์›ƒ

  • ์นด์นด์˜ค ์„œ๋น„์Šค ์ „์ฒด ๋กœ๊ทธ์•„์›ƒ
  • ๋กœ๊ทธ์•„์›ƒ ์‹œ Redis์— ์ €์žฅ๋œ Refresh Token ์‚ญ์ œ

๋งˆ์ดํŽ˜์ด์ง€

  • ์‚ฌ์šฉ์ž ๋งˆ์ดํŽ˜์ด์ง€
  • ํšŒ์› ํƒˆํ‡ด ์‹œ ๋ชจ๋“  ์ •๋ณด ์‚ญ์ œ ๋ฐ ์นด์นด์˜ค ์—ฐ๊ฒฐ ๋Š๊ธฐ

์ฑ… ์กฐํšŒ ๋ฐ ์ €์žฅ (Naver ์ฑ… ๊ฒ€์ƒ‰ API)

  • ๊ฒ€์ƒ‰์–ด๋Š” ์ž๋™์œผ๋กœ ์ธ์ฝ”๋”ฉ๋˜์–ด ์ „๋‹ฌ
  • ์ฑ… ๊ฒ€์ƒ‰์€ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์˜ˆ์™ธ
  • ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ์ฑ…์˜ ISBN์„ ๋ฐ”ํƒ•์œผ๋กœ ์ฑ…์„ ์ƒ์„ธ์กฐํšŒํ•˜๊ณ  DB์— ์ €์žฅ

๋‚ด ์„œ์žฌ

  • ์ €์žฅ๋œ ์ฑ… ์ข‹์•„์š” ๊ธฐ๋Šฅ
  • ์ €์žฅ๋œ ์ฑ… ์ƒ์„ธ๋ณด๊ธฐ ๊ธฐ๋Šฅ (์ฑ…์˜ ์ •๋ณด์™€ ์ž‘์„ฑ๋œ ๋…ธํŠธ๋ฆฌ์ŠคํŠธ ํ•จ๊ป˜ ์กฐํšŒ)
  • ์ €์žฅ๋œ ์ฑ… ๋…ธํŠธ ์ž‘์„ฑ ๊ธฐ๋Šฅ
  • ์ €์žฅ๋œ ์ฑ… ์‚ญ์ œ ๊ธฐ๋Šฅ, ์ฑ…๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  ๋…ธํŠธ๋„ ํ•จ๊ป˜ ์‚ญ์ œ
  • ์ €์žฅ๋œ ์ฑ… ๊ณต์œ  ๊ธฐ๋Šฅ, ๊ณต์œ ํ† ํฐ ๋ฐ ๊ณต์œ  URL ์ƒ์„ฑ ๋ฐ ์นด์นด์˜คํ†ก ๋ฉ”์‹œ์ง€ ์ „์†ก
  • ์ข‹์•„์š”, ๋…ธํŠธ ์ „์ฒด ๋ชฉ๋ก ์กฐํšŒ

์ฑ… ๊ณต์œ ํ•˜๊ธฐ (Kakao ๋ฉ”์‹œ์ง€ API)

  • ์‚ฌ์šฉ์ž์—๊ฒŒ 10๋ถ„๊ฐ„ ์œ ํšจํ•œ ๊ณต์œ ํ† ํฐ ์ƒ์„ฑ

  • ๊ณต์œ URL์„ ํฌํ•จํ•ด ์นด์นด์˜คํ†ก ๋ฉ”์‹œ์ง€๋กœ ์ „๋‹ฌ

  • ๊ณต์œ ๋œ ์ฑ…์˜ URL์€ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์˜ˆ์™ธ

  • ๊ณต์œ ๋œ ์ฑ…์˜ ๋…ธํŠธ๋“ค๋„ ํ•จ๊ป˜ ์—ด๋žŒ ๊ฐ€๋Šฅ

    ์นด์นด์˜คํ†ก ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ

๋…ธํŠธ

  • ๋…ธํŠธ๋Š” ์ตœ์‹ ์ˆœ์œผ๋กœ ์ •๋ ฌ
  • ์ €์žฅํ•œ ์ฑ…์— ๋Œ€ํ•ด์„œ ์ œํ•œ์—†์ด ๋…ธํŠธ ์ƒ์„ฑ
  • ์‚ฌ์šฉ์ž๋Š” ๋…ธํŠธ ์ˆ˜์ •, ํœด์ง€ํ†ต ์ด๋™(softDelete), ์˜๊ตฌ ์‚ญ์ œ, ์ฆ๊ฒจ์ฐพ๊ธฐ(๋ถ๋งˆํฌ) ๊ฐ€๋Šฅ
  • ์ฆ๊ฒจ์ฐพ๊ธฐํ•œ ๋…ธํŠธ๋“ค ์ „์ฒด ์กฐํšŒ (๋ณด๊ด€ํ•จ์œผ๋กœ ์ด๋™ํ•œ ๋…ธํŠธ๋“ค์€ ์ œ์™ธ)
  • ์ „์ฒด ๋…ธํŠธ๋ชฉ๋ก (ํ™œ์„ฑํ™”, ํœด์ง€ํ†ต) ์กฐํšŒ
  • ํœด์ง€ํ†ต์œผ๋กœ ์ด๋™ํ•œ ๋…ธํŠธ๋Š” 30์ผ ๋™์•ˆ ์–ธ์ œ๋“ ์ง€ ํ™œ์„ฑํ™” ๊ฐ€๋Šฅ, 30์ผ ๋’ค ์˜๊ตฌ ์‚ญ์ œ

API ๋ช…์„ธ

Swagger

No Title Method Path Authorization
1 ์นด์นด์˜ค ์ธ๊ฐ€์ฝ”๋“œ GET /api/kakao/sign-in X
2 ๋กœ๊ทธ์ธ ๋ฐ ํšŒ์›๊ฐ€์ž… GET /api/kakao/callback?code={์นด์นด์˜ค_์ธ๊ฐ€์ฝ”๋“œ} X
3 ๋กœ๊ทธ์•„์›ƒ GET /api/kakao-logout/sign-out X
4 ๋งˆ์ดํŽ˜์ด์ง€ GET /api/users/my-page O
5 ํšŒ์› ํƒˆํ‡ด GET /api/users/leave O
6 ์ฑ… ๊ฒ€์ƒ‰ GET /api/books/search X
7 ์ฑ… ์ €์žฅ POST /api/books/save O
8 ๋‚ด ์„œ์žฌ ์กฐํšŒ GET /api/saved-books/list O
9 ์„œ์žฌ ์ฑ… ์ƒ์„ธ ์กฐํšŒ GET /api/saved-books:bookId/detail O
10 ์„œ์žฌ ์ฑ… ์‚ญ์ œ DELETED /api/saved-books/:bookId/deleted O
11 ์„œ์žฌ ์ฑ… ์ข‹์•„์š” PATCH /api/liked-books/:bookId/like O
12 ์„œ์žฌ ์ฑ… ๋‚˜์—๊ฒŒ ๊ณต์œ ํ•˜๊ธฐ POST /api/saved-books/:bookId/share O
13 ์„œ์žฌ ์ฑ… ์นœ๊ตฌ์—๊ฒŒ ๊ณต์œ ํ•˜๊ธฐ POST /api/saved-books/:bookId/share-friends O
14 ์™ธ๋ถ€์ธ ์ฑ… ์ƒ์„ธ ์กฐํšŒ GET /api/shared/books/:shareToken O
15 ์™ธ๋ถ€์ธ ์ฑ… ๋…ธํŠธ ์ƒ์„ธ ์กฐํšŒ GET /api/shared/books/:shareToken/notes/:noteId O
16 ๋…ธํŠธ ์ƒ์„ฑ POST /api/notes/:bookId/write O
17 ๋…ธํŠธ ์ƒ์„ธ ์กฐํšŒ GET /api/notes-detail/:noteId/read O
18 ๋…ธํŠธ ์ˆ˜์ • PATCH /api/notes-detail/:noteId/update O
19 ๋…ธํŠธ ๋ณด๊ด€ํ•จ ์ด๋™ PATCH /api/notes-detail/:noteId/soft-delete O
20 ๋…ธํŠธ ์‚ญ์ œ DELETED /api/notes-detail/:noteId/final-delete O
21 ๋…ธํŠธ ์ฆ๊ฒจ์ฐพ๊ธฐ PATCH /api/notes-detail/{noteId}/read O
22 ๋…ธํŠธ ์ฆ๊ฒจ์ฐพ๊ธฐ ๋ชฉ๋ก ์กฐํšŒ GET /api/bookmarked-notes/list O
23 ๋…ธํŠธ ํ™œ์„ฑํ™” ๋ชฉ๋ก ์กฐํšŒ GET /api/notes/active-list O
24 ๋…ธํŠธ ํœด์ง€ํ†ต ๋ชฉ๋ก ์กฐํšŒ GET /api/notes/active-list O

ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

โšก WebClient์—์„œ JSON ์‘๋‹ต ํŒŒ์‹ฑ ๋ฌธ์ œ

๋ฌธ์ œ ์ƒํ™ฉ

์นด์นด์˜ค API์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ, JSON ์‘๋‹ต์„ ํŒŒ์‹ฑํ•˜๋Š” ๊ณผ์ •์—์„œ get() ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ ์‹œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ

์›์ธ ๋ถ„์„

  • JSON ๊ตฌ์กฐ์˜ ๋ณต์žก์„ฑ: ์นด์นด์˜ค API ์‘๋‹ต์˜ JSON ๊ตฌ์กฐ๊ฐ€ ์ค‘์ฒฉ๋˜์–ด ์žˆ์–ด get() ๋ฉ”์„œ๋“œ๋กœ ์ง์ ‘ ์ ‘๊ทผํ•˜๊ธฐ ์–ด๋ ค์›€
  • Null ๊ฐ’ ์ฒ˜๋ฆฌ: get() ๋ฉ”์„œ๋“œ๋Š” ํ‚ค๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด, ์•ˆ์ „ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”

ํ•ด๊ฒฐ ๊ณผ์ •

  • path() ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ: JSON ํŠธ๋ฆฌ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ๋Š” path() ๋ฉ”์„œ๋“œ๋กœ ์ „ํ™˜

  • ์ค‘์ฒฉ๋œ ๊ตฌ์กฐ ์ฒ˜๋ฆฌ: path().path() ํ˜•์‹์œผ๋กœ ์ค‘์ฒฉ๋œ JSON ๊ตฌ์กฐ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ์ฒ˜๋ฆฌ

    {
    Long id = jsonNode.path("id").asLong();
    String email = jsonNode.path("kakao_account").path("email").asText();
    String nickname = jsonNode.path("kakao_account").path("profile").path("nickname").asText();
    String thumbnail_image_url = jsonNode.path("kakao_account").path("profile").path("thumbnail_image_url").asText();
    }
    

๊ฒฐ๊ณผ

  • path() ๋ฉ”์„œ๋“œ๋ฅผ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•˜์—ฌ JSON ๋ฐ์ดํ„ฐ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ํŒŒ์‹ฑ
  • Null ์•ˆ์ „์„ฑ ํ™•๋ณด: path() ๋ฉ”์„œ๋“œ๋Š” ํ‚ค๊ฐ€ ์—†์„ ๊ฒฝ์šฐ MissingNode๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ NPE๋ฅผ ๋ฐฉ์ง€
  • ๊ธฐ๋ณธ๊ฐ’ ์ฒ˜๋ฆฌ: asText(), asLong() ๋“ฑ์˜ ๋ฉ”์„œ๋“œ๋Š” ํ•ด๋‹น ๋…ธ๋“œ๊ฐ€ ์—†๊ฑฐ๋‚˜ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ๊ฐ๊ฐ์˜ ๊ธฐ๋ณธ๊ฐ’(๋นˆ ๋ฌธ์ž์—ด, 0 ๋“ฑ)์„ ๋ฐ˜ํ™˜

โšก WebClient ๋„ค์ด๋ฒ„ ์ฑ… ๊ฒ€์ƒ‰ baseUrl ์ธ์‹ ๋ฌธ์ œ

๋ฌธ์ œ ์ƒํ™ฉ

WebClient์˜ Naver ์ฑ… ๊ด€๋ จ baseUrl์— ์ „์ฒด URL("https://openapi.naver.com/v1/search")์ด ์„ค์ •๋˜์–ด ์žˆ์—ˆ์ง€๋งŒ,
์‹ค์ œ ์š”์ฒญ ์‹œ ์ด baseUrl์ด ์ œ๋Œ€๋กœ ์ธ์‹๋˜์ง€ ์•Š์Œ

์›์ธ ๋ถ„์„

  • WebClient์—์„œ baseUrl์„ ์„ค์ •ํ–ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ , uri() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์™„์ „ํ•œ URI๋ฅผ ๊ตฌ์„ฑํ•˜์ง€ ์•Š์œผ๋ฉด baseUrl์ด ๋ฌด์‹œ ๊ฐ€๋Šฅ์„ฑ ์žˆ์Œ
  • ํŠนํžˆ UriBuilder๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ

ํ•ด๊ฒฐ ๊ณผ์ •

  • uriBuilder์— scheme("https")๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ถ”๊ฐ€

  • ์ค‘์ฒฉ๋œ ๊ตฌ์กฐ ์ฒ˜๋ฆฌ: path().path() ํ˜•์‹์œผ๋กœ ์ค‘์ฒฉ๋œ JSON ๊ตฌ์กฐ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ์ฒ˜๋ฆฌ

    {
      .uri(uriBuilder -> uriBuilder
      .scheme("https")  // ๋ช…์‹œ์ ์œผ๋กœ scheme ์ถ”๊ฐ€
      .host(bookBasehUrl)
      .path("/book.json")
      // ... ๋‚˜๋จธ์ง€ ์ฝ”๋“œ
    }
    

๊ฒฐ๊ณผ

  • ์™„์ „ํ•œ URL ๊ตฌ์„ฑ: scheme์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•จ์œผ๋กœ์จ, ์ „์ฒด URL์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ์„ฑ

โšก Feign JSON ์ง๋ ฌํ™” ๋ฌธ์ œ ๋ฐ ํŒŒ์‹ฑ ์˜ค๋ฅ˜

๋ฌธ์ œ ์ƒํ™ฉ

์ฑ… ๊ณต์œ ํ•˜๊ธฐ๋ฅผ ์ง„ํ–‰ํ•˜๋˜ ์ค‘ JSON ์ง๋ ฌํ™” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.
๋”๋ถˆ์–ด ์นœ๊ตฌ์—๊ฒŒ ๊ณต์œ ํ•˜๊ธฐ๋Š” ์‚ฌ์šฉ์ž ์นœ๊ตฌ ๋ชฉ๋ก์—์„œ ๋ถˆ๋Ÿฌ์˜จ UUID๊ฐ€ reqeust์— ํŒŒ์‹ฑ๋˜์ง€ ์•Š์•„ Bad request๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ–ˆ๋‹ค.

์›์ธ ๋ถ„์„

  • JSON ์ง๋ ฌํ™” ๋ฌธ์ œ: ๊ธฐ์กด์— ์‚ฌ์šฉํ•˜๋˜ record ํƒ€์ž…์ด Kakao API์˜ ์š”๊ตฌ์‚ฌํ•ญ๊ณผ ๋งž์ง€ ์•Š์•˜๋‹ค.
  • UUID ํŒŒ์‹ฑ ์˜ค๋ฅ˜: ์นœ๊ตฌ ๋ชฉ๋ก์˜ UUID๋ฅผ List ํ˜•ํƒœ๋กœ ํ•œ ๋ฒˆ์— ์ „์†กํ•˜๋Š” ๋ฐฉ์‹์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.
  • UUID NULL ์ธ์‹ ์˜ค๋ฅ˜

ํ•ด๊ฒฐ ๊ณผ์ •

  1. JSON ์ง๋ ฌํ™” ๋ฌธ์ œ
  • ๊ธฐ์กด record ํƒ€์ž…์„ Class ํ˜•์‹์œผ๋กœ ๋‹ค์‹œ ๋ณ€๊ฒฝ
  • kakao ์š”๊ตฌ์— ๋งž๋„๋ก ํด๋ž˜์Šค ๊ตฌ์กฐ ์ˆ˜์ •
  • ObjectMapper๋ฅผ ํ™œ์šฉํ•ด json์œผ๋กœ ์ง์ ‘ ํŒŒ์‹ฑํ•ด
  1. UUID ํŒŒ์‹ฑ ์˜ค๋ฅ˜
  • ์นœ๊ตฌ ๋ชฉ๋ก UUID๋ฅผ List๋กœ ํ•œ ๋ฒˆ์— ์ „์†กํ•˜๋Š” ๋Œ€์‹ , ๊ฐœ๋ณ„์ ์œผ๋กœ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝ
  1. UUID BAD REQUEST ๋ฌธ์ œ
  • ReqeustBody์˜ ์ˆœ์„œ ๋ฌธ์ œ
    • ์นœ๊ตฌ์—๊ฒŒ ์ „์†กํ•˜๊ธฐ reqeust๋Š” ๋‚˜์—๊ฒŒ ์ „์†กํ•˜๊ธฐ๋ฅผ ์ƒ์†๋ฐ›์•„ ์ง„ํ–‰ํ–ˆ๋‹ค.
    • ์ด ๊ณผ์ •์—์„œ uuid ๋ฆฌ์ŠคํŠธ์™€ contents๊ฐ€ ์„œ๋กœ ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋‹ค.
    • feignClient์—์„œ๋Š” ๊ฐ๊ฐ ๋ฐ›์ง€ ์•Š๊ณ  ํ•˜๋‚˜์˜ Map์œผ๋กœ ๋ฌถ์–ด ์‘๋‹ต ๋ณธ๋ฌธ์„ ์ „์†กํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.
    • ๊ณ„์†ํ•ด์„œ uuid๊ฐ€ null๋กœ ์ž…๋ ฅ๋ผ์„œ ๊ฒฐ๊ตญ ํ•˜๋‚˜์”ฉ ๋ถ„๋ฆฌํ•ด param ํ˜•ํƒœ๋กœ ์ „์†กํ–ˆ๋‹ค.

โšก JWT ํ† ํฐ ์œ ํšจ๊ธฐ๊ฐ„ ๋งŒ๋ฃŒ ์˜ค๋ฅ˜

๋ฌธ์ œ ์ƒํ™ฉ

์•ก์„ธ์Šค ํ† ํฐ ์œ ํšจ๊ธฐ๊ฐ„ ๋งŒ๋ฃŒ ์˜ค๋ฅ˜

์›์ธ ๋ถ„์„

  • application-secret.yml์— ํ† ํฐ๋ณ„ ์œ ํšจ๊ธฐ๊ฐ„์„ Long ํƒ€์ž…์œผ๋กœ ์ •์˜ํ–ˆ์œผ๋‚˜, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ด ๊ฐ’์„ ๋„ˆ๋ฌด ์งง๊ฒŒ ์ธ์‹ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ
  • ๋”๋ถˆ์–ด Local ํ™˜๊ฒฝ ์‹œ๊ฐ„๊ณผ JWT ํ™˜๊ฒฝ ์‹œ๊ฐ„์˜ ์ฐจ์ด๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜๋„ ๋ฐœ๊ฒฌ
  • ์•ก์„ธ์Šค ํ† ํฐ ๊ฒ€์ฆ 30์ดˆ ์—ฌ์œ  ์‹œ๊ฐ„์„ ์„ค์ •ํ•ด์คฌ์œผ๋ฉด์—๋„ ์—ฌ์ „ํžˆ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ

ํ•ด๊ฒฐ ๊ณผ์ •

  • ๊ฒฐ๊ตญ ํ•˜๋“œ ์ฝ”๋”ฉ์„ ์œ ํšจ๊ธฐ๊ฐ„ ์„ค์ •

๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐ๋ฒ• ๊ณ ๋ฏผํ•˜๊ธฐ

  • YAML์—์„œ Long ๋Œ€์‹  Integer๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ
  • ๋ฌธ์ž์—ด๋กœ ์ •์˜ํ•˜๊ณ  JAVA๋กœ ํŒŒ์‹ฑํ•˜๊ธฐ
jwt:
  token-expiration:
    access: "์œ ํšจ์‹œ๊ฐ„"
    refresh: "์œ ํšจ์‹œ๊ฐ„"
    share: "์œ ํšจ์‹œ๊ฐ„"
@Value("${jwt.access-token-expiration}")
private String accessTokenExpirationStr;
@Value("${jwt.refresh-token-expiration}")
private String refreshTokenExpirationStr;
@Value("${jwt.share-token-expiration}")
private String shareTokenExpirationStr;

private long getAccessTokenValidity() {
        return Long.parseLong(accessTokenExpirationStr);
    }

    private long getRefreshTokenValidity() {
        return Long.parseLong(refreshTokenExpirationStr);
    }

    private long getShareTokenValidity() {
        return Long.parseLong(shareTokenExpirationStr);
    }


๊ณ ๋ฏผ์˜ ํ”์ 

๐Ÿ“ RestTemplate์—์„œ WebClient๋กœ์˜ ์ „ํ™˜

๋Œ€๋ถ€๋ถ„ RestTemplate๋กœ OpenAPI ์‘๋‹ต๊ฐ’์„ ๋ฐ›์•„์˜ค๊ณค ํ–ˆ์—ˆ๋‹ค.
ํ•˜์ง€๋งŒ ๊ธฐ๋ณธ์ ์œผ๋กœ RestTemplate์€ ์‘๋‹ต๊ฐ’์„ ๋ฐ›์•„์˜ค๋Š” ๋ฐ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆด ์ˆ˜๋„ ์žˆ๋Š” ์ ์ด ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ์˜€๋‹ค.
๊ทธ๋ฆฌ๊ณ  RestTemplate๋Š” Spring์—์„œ ์ง€์› ์ค‘๋‹จ์„ ์˜ˆ๊ณ ํ–ˆ๊ณ , ์ƒˆ๋กœ์šด ๊ฐœ๋ฐœ์€ ๋Œ€๋ถ€๋ถ„ WebClient๋กœ ๋งŽ์ด ๊ตฌํ˜„๋˜๊ณ  ์žˆ์—ˆ๋‹ค.
ํŠนํžˆ WebClient๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์™€ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์Šคํƒ€์ผ์„ ์ง€์›ํ•ด ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ์ข‹๋‹ค๊ณ  ์•Œ๋ ค์ ธ ์žˆ์–ด,
์ƒˆ๋กœ์šด spring ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๊ณ  ์‹ถ์—ˆ๋‹ค!

WebClient์˜ ๋น„๋™๊ธฐ ํŠน์„ฑ์„ ํ™œ์šฉํ•˜๋ฉด ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์‘๋‹ต์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ๋งค๋ ฅ์ ์ด์—ˆ๋‹ค
๋กœ๊ทธ์ธ๊ณผ ์ฑ… ๊ฒ€์ƒ‰์˜ ๊ฒฝ์šฐ ๋น ๋ฅธ ์‘๋‹ต์ด ํ•„์š”ํ–ˆ๊ธฐ์— ์ ํ•ฉํ•œ ๋ฐฉ์‹์ด๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

WebClient ๋„์ž… ์‹œ ์ดˆ๊ธฐ ์„ค์ •์—์„œ RestTemplate๊ณผ ์•ฝ๊ฐ„์˜ ์ฐจ์ด๊ฐ€ ์žˆ์—ˆ๋‹ค.
JSON ์ธ์ฝ”๋”ฉ ๋ฌธ์ œ๋ฅผ config ํŒŒ์ผ์— ๋ฏธ๋ฆฌ ์„ค์ •ํ•ด์•ผ ํ–ˆ๋‹ค. ๋งŽ์€ ๋ธ”๋กœ๊ทธ๋“ค์—์„œ ์ด์— ๊ด€ํ•ด ๋ฏธ๋ฆฌ ๋ง์”€ํ•ด์ฃผ์…”์„œ ๋‚˜๋Š” ๋‹คํ–‰ํžˆ ์ดˆ๊ธฐ ์„ค์ •์— ๋„ฃ์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์Šคํƒ€์ผ๋กœ ์ธํ•ด ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•ด์ง€๊ณ  ๊ฐ€๋…์„ฑ์ด ์ข‹์•„์กŒ๋‹ค๊ณ  ๋Š๊ฒผ๋‹ค.
๋˜ํ•œ ์‘๋‹ต์—์„œ ์›ํ•˜๋Š” ์ •๋ณด๋งŒ ์‰ฝ๊ฒŒ ๊ฒฝ๋กœ๋ฅผ ์ฐพ์•„ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ์ข‹์•˜๋‹ค.
ํŠนํžˆ ํƒ€์ž„์•„์›ƒ ๊ธฐ๋Šฅ์ด ์ธ์ƒ์ ์ด์—ˆ๋Š”๋ฐ, ์ด๋ฅผ ํ†ตํ•ด ์ฒ˜๋ฆฌ ์†๋„๋ฅผ ๋” ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์–ด ์„œ๋น„์Šค ํ’ˆ์งˆ ํ–ฅ์ƒ์— ๋„์›€์ด ๋  ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€๋œ๋‹ค!
๊ฒฐ๊ณผ์ ์œผ๋กœ WebClient์˜ ๋น„๋™๊ธฐ ํŠน์„ฑ์„ ํ™œ์šฉํ•จ์œผ๋กœ์จ ์ „์ฒด ์„œ๋ฒ„์˜ ์‘๋‹ต์ด ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ ๋•Œ๋ณด๋‹ค ๋นจ๋ผ์ง์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๐Ÿ“ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—†์„ ๋•Œ ์นด์นด์˜ค ๋กœ๊ทธ์ธ ์ธ๊ฐ€์ฝ”๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ๋ฐ›์•„์˜ฌ๊นŒ?

์นด์นด์˜ค ๋กœ๊ทธ์ธ์˜ ๋Œ€๋ถ€๋ถ„ ๊ตฌํ˜„์€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ์„œ ์ธ๊ฐ€์ฝ”๋“œ๋ฅผ ๋ฐ›์•„์˜ค๊ณ ,
์„œ๋ฒ„์—์„œ ์ธ๊ฐ€์ฝ”๋“œ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ accessToken์„ ๋ฐœ๊ธ‰๋ฐ›๋Š” ๊ฒƒ์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค.

ํ•˜์ง€๋งŒ ํ˜„์žฌ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ๋งŒ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ์–ด์„œ ์ด ๋ถ€๋ถ„์„ ์„œ๋ฒ„ ํ˜ผ์ž์„œ ์ฒ˜๋ฆฌํ•  ์ˆœ ์—†์„๊นŒ? ๊ณ ๋ฏผํ•˜๊ฒŒ ๋๋‹ค.
์šฐ์„ , ์ธ๊ฐ€์ฝ”๋“œ๋Š” ๋™์ ์œผ๋กœ ๊ณ„์† ๋ณ€ํ™”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ธ๊ฐ€์ฝ”๋“œ๋ฅผ param์œผ๋กœ ์‚ฌ์šฉํ•˜์ž๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋ฐ›๋Š” url์—์„œ ๋ฐ”๋กœ ์นด์นด์˜ค accessToken์„ ๋ฐœ๊ธ‰๋ฐ›๊ณ  ํšŒ์›์ •๋ณด๊นŒ์ง€ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•˜๊ฒŒ ๋๋‹ค!

์ด ๋ฐฉ๋ฒ•์„ ์™ธ๋ถ€์ธ ์ฑ… ์ ‘๊ทผ์—์„œ๋„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ํ˜„์žฌ๋Š” Url์— ํ† ํฐ๊ณผ ์ธ๊ฐ€์ฝ”๋“œ๊ฐ€ ์ „๋ถ€ ๋‚˜์˜ค๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ์ธ์ •๋ณด์™€ ํ† ํฐ ํƒˆ์ทจ ๋ฌธ์ œ๊ฐ€ ๊ณ ๋ฏผ๋๋‹ค.
๊ณต์œ ํ† ํฐ์˜ ์‹œํฌ๋ฆฟํ‚ค๋ฅผ ๋”ฐ๋กœ ๋ถ„๋ฆฌํ•ด์ฃผ๊ณ , url์—๋Š” ๋ณด์ด์ง€ ์•Š๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ข€ ๋” ๊ณ ๋ฏผํ•ด ๋ด์•ผ๊ฒ ๋‹ค.

๐Ÿ“ ์นด์นด์˜คํ†ก ๋ฉ”์‹œ์ง€ ๊ณต์œ ํ•˜๊ธฐ๋ฅผ ํด๋ผ์ด์–ธํŠธ ์—†์ด ๊ตฌํ˜„ํ• ๊นŒ?

์ดˆ๊ธฐ ์š”๊ตฌ์‚ฌํ•ญ์—์„œ๋Š” ์นด์นด์˜คํ†ก ๋ฉ”์‹œ์ง€ ๊ณต์œ ํ•˜๊ธฐ๋Š” ๋”ฐ๋กœ ์—†์—ˆ๋‹ค.
"๋””์Šค์ฝ”๋“œ ์›นํ›…์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ๋‚ด ์„œ๋น„์Šค๋„ ์ด๋Ÿฐ ๊ธฐ๋Šฅ์ด ์žˆ์œผ๋ฉด ์ข‹๊ฒ ๋Š”๋ฐ?"์— ๋Œ€ํ•œ ๊ณ ๋ฏผ๋“ค์ด ํ•˜๋˜ ๋„์ค‘
์นด์นด์˜คํ†ก ๋กœ๊ทธ์ธ์„ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋‹ˆ ์นด์นด์˜คํ†ก ๊ณต์œ ํ•˜๊ธฐ์™€ ์นด์นด์˜คํ†ก ๋ฉ”์‹œ์ง€ ์ „์†กํ•˜๊ธฐ๊ฐ€ ๋– ์˜ฌ๋ž๋‹ค.

ํ•ด๋‹น API ๋ช…์„ธ์„œ๋ฅผ ํ™•์ธํ•ด๋ณด๋‹ˆ๊นŒ Restful ๋ฐฉ์‹์€ ์นด์นด์˜คํ†ก ๋ฉ”์‹œ์ง€ ์ „์†กํ•˜๊ธฐ๋งŒ ๊ฐ€๋Šฅํ–ˆ๋‹ค.
์นœ๊ตฌ์—๊ฒŒ ์‚ฌ์šฉ์ž๊ฐ€ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ˆ, ์˜คํžˆ๋ ค ์นด์นด์˜คํ†ก ๋ฉ”์‹œ์ง€ ์ „์†กํ•˜๊ธฐ๊ฐ€ ํ๊ธ€์— ๋” ์ž˜ ๋งž๋Š”๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค!

๊ณ ๋ฏผ๋œ ์ ๋“ค

  1. ํด๋ผ์ด์–ธํŠธ ์—†์ด ์„œ๋ฒ„์—์„œ ๊ณต์œ  ๋ฉ”์‹œ์ง€ ๋‚ด์šฉ ๊ณ ์ •
  2. ์„œ๋ฒ„์—์„œ ๊ณ ์ • ํ…œํ”Œ๋ฆฟ ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋กœ JSON ์ง์ ‘ ํŒŒ์‹ฑ ํ•„์š”
  3. ํ† ํฐ ๊ด€๋ฆฌ: ์นด์นด์˜ค ์•ก์„ธ์Šค ํ† ํฐ ๊ด€๋ฆฌ
  4. ์นœ๊ตฌ ์ •๋ณด ํ™œ์šฉ: ์นด์นด์˜ค API๋กœ ์‚ฌ์šฉ์ž ์นœ๊ตฌ ์ •๋ณด ์กฐํšŒ

์‚ฌ์šฉํ•œ ๋ฐฉ๋ฒ•

  1. openFeign ๋ฐฉ์‹์„ ํ™œ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค!
  2. ๋ฌผ๋ก  ๊ธฐ์กด webClient ๋ฐฉ์‹์œผ๋กœ๋„ ๊ฐ€๋Šฅํ–ˆ์ง€๋งŒ, ํ›จ์”ฌ ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•ด์ง€๊ณ  client ์ž‘์—…์„ ๋Œ€์‹  ํ•ด์ฃผ๊ธฐ์— ๋ฐฑ์—”๋“œ์˜ ๋ถ€๋‹ด์ด ๋œ์—ˆ๋‹ค.
  3. ์นด์นด์˜ค ํ† ํฐ์€ ์ž„์‹œ๋กœ ์„œ๋ฒ„ db์— ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์„ ํƒํ–ˆ๋‹ค. -> ์ถ”ํ›„์— ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ๋Œ๋ ค์„œ ๊ด€๋ฆฌํ•ด์ค„ ์˜ˆ์ •์ด๋‹ค.
  4. ๋ฉ”์‹œ์ง€๋Š” ๊ณ ์ •์œผ๋กœ ์„œ๋ฒ„์—์„œ ์ž‘์„ฑํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค. ์นด์นด์˜ค ๋ฉ”์‹œ์ง€ ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ์•˜์ง€๋งŒ ์ฑ… ํ‘œ์ง€๋ฅผ ํ•จ๊ป˜ ๋ณด์—ฌ์ฃผ๊ณ  ์‹ถ์–ด์„œ์˜€๋‹ค!

๊ตฌํ˜„ ๊ฒฐ๊ณผ

  • ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ ์ดˆ๊ธฐ ํ…Œ์ŠคํŠธ ์„ฑ๊ณต

๋ฉ”์‹œ์ง€ ์ „์†ก ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๋‹ค์–‘ํ•œ ๊ธฐ์ˆ ์  ๋„์ „์„ ๊ทน๋ณตํ•˜๋ฉฐ ์‹ค์šฉ์ ์ธ ๊ธฐ๋Šฅ์„ ์„ฑ๊ณต์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค!

๐Ÿ“ ํ”„๋ก ํŠธ ํ™”๋ฉด์€ ์–ด๋–ป๊ฒŒ ๊ตฌ์ƒํ• ๊นŒ?

ํ๊ธ€ํ๊ธ€ ์„œ๋น„์Šค๋Š” ์„œ๋กœ ์—ฐ๊ฒฐ๋œ ๊ธฐ๋Šฅ๋“ค์ด ๋งŽ์•„์„œ ์‰ฝ๊ฒŒ ๋กœ์ง์ด ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์•˜๋‹ค.
๋”๋ถˆ์–ด ์ •๋ณด๊ฐ€ ๋“ฑ๋ก๋˜์–ด ์žˆ์„ ๊ฒฝ์šฐ ํ•ด๋‹น ๋‚ด์—ญ๋“ค๊นŒ์ง€ ๋„˜๊ธธ ํ•„์š”๊ฐ€ ์žˆ์„๊นŒ? ๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค๋ฉด์„œ ๊ณ ๋ฏผ์„ ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.
์ด์ „ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•  ๋•Œ ํ”„๋ก ํŠธ๋„ ๊ฐ™์ด ๋งŒ๋“ค์–ด๋ดค๋˜ ๊ฒฝํ—˜์„ ๋ฐ”ํƒ•์œผ๋กœ ํ”ผ๊ทธ๋งˆ๋ฅผ ํ™œ์šฉํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ UI๋ฅผ ๊ตฌ์ƒํ–ˆ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-10-03 แ„‹แ…ฉแ„’แ…ฎ 5 10 55

์ด์ „ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ ํ•  ๋•Œ ํ”„๋ก ํŠธ๋„ ๊ฐ™์ด ๋งŒ๋“ค์–ด๋ดค๋˜ ๊ฒฝํ—˜ ๋•Œ๋ฌธ์— ํ”„๋ก ํŠธ๋ฅผ ๋จผ์ € ์ƒ๊ฐํ•ด๋ณด๊ณ 
๋กœ์ง์„ ์ƒ๊ฐํ•˜๋Š” ์ˆœ์„œ๋กœ ๋ฐ”๋€ ๊ณ„๊ธฐ๊ฐ€ ๋˜์—ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์ƒ๊ฐํ•˜๊ฒŒ ๋˜๋‹ˆ๊นŒ ์ดํ•ดํ•˜๊ธฐ๋„ ์‰ฝ๊ณ  ๋กœ์ง์ด ๋จธ๋ฆฟ์†์— ๊ทธ๋ ค์กŒ๋‹ค.


โœ‰ Git Commit Message Convention

์ปค๋ฐ‹ ์œ ํ˜•

์ปค๋ฐ‹ ์œ ํ˜• ์˜๋ฏธ
feat ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€
fix ๋ฒ„๊ทธ ์ˆ˜์ •
docs ๋ฌธ์„œ ์ˆ˜์ •
style ์ฝ”๋“œ formatting, ์„ธ๋ฏธ์ฝœ๋ก  ๋ˆ„๋ฝ, ์ฝ”๋“œ ์ž์ฒด์˜ ๋ณ€๊ฒฝ์ด ์—†๋Š” ๊ฒฝ์šฐ
refactor ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง
test ํ…Œ์ŠคํŠธ ์ฝ”๋“œ, ๋ฆฌํŒฉํ† ๋ง ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ถ”๊ฐ€
chore ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ € ์ˆ˜์ •, ๊ทธ ์™ธ ๊ธฐํƒ€ ์ˆ˜์ • ex) .gitignore

์ปค๋ฐ‹ ๋ฉ”์„ธ์ง€ ์„ธ๋ถ€ ๋‚ด์šฉ

โ€ƒโ€ข ๊ธ€๋กœ ์ž‘์„ฑํ•˜์—ฌ ๋‚ด์šฉ์ด ์ž˜ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•  ๊ฒƒ

โ€ƒโ€ข ๋ณธ๋ฌธ์—๋Š” ๋ณ€๊ฒฝํ•œ ๋‚ด์šฉ๊ณผ ์ด์œ  ์„ค๋ช… (์–ด๋–ป๊ฒŒ๋ณด๋‹ค๋Š” ๋ฌด์—‡ & ์™œ๋ฅผ ์„ค๋ช…)
โ€ƒ
โ€ƒex )
โ€ƒrefactor : ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๋ณ€๊ฒฝ (title)
โ€ƒ( ๊ณต ๋ฐฑ )
โ€ƒ๊ธฐ์กด ๋กœ๊ทธ์ธ ๋ฐฉ์‹์—์„œ ~~ํ•œ ๋ฌธ์ œ๋กœ ~~ํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•˜์˜€์Šต๋‹ˆ๋‹ค. (content)

โ€ƒfeat : ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„

๐ŸŒฟ Git Branch ์ „๋žต

๋ธŒ๋ Œ์น˜ ๋ช…๋ช… ๊ทœ์น™

feat/๊ธฐ๋Šฅ๋ช…

  • ex) feat/users_apply
๋ธŒ๋žœ์น˜ ์ž‘์„ฑ ๋ฐฉ๋ฒ•

  • ๋ธŒ๋žœ์น˜๋Š” ๊ธฐ๋Šฅ ๋‹จ์œ„๋กœ ๋‚˜๋ˆˆ๋‹ค.
  • feat ๋ธŒ๋žœ์น˜๋Š” dev ๋ธŒ๋žœ์น˜์—์„œ ํŒŒ์ƒํ•ด์„œ ๋งŒ๋“ ๋‹ค.
  • PR์„ ํ†ตํ•ด dev ๋ธŒ๋žœ์น˜์—์„œ ๊ธฐ๋Šฅ์ด ์™„์„ฑ๋˜๋ฉด main ๋ธŒ๋žœ์น˜๋กœ merge ํ•œ๋‹ค.

์ด๋ฆ„ ํ…์ŠคํŠธ
main ์ œํ’ˆ์œผ๋กœ ์ถœ์‹œ๋  ์ˆ˜ ์žˆ๋Š” ๋ธŒ๋žœ์น˜
dev ๋‹ค์Œ ์ถœ์‹œ ๋ฒ„์ „์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋ธŒ๋žœ์น˜
feat ๊ธฐ๋Šฅ์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋ธŒ๋žœ์น˜

About

๐Ÿซง๐Ÿ“š ์ฑ…์—์„œ ํ๊ธ€ ํ”ผ์–ด๋‚œ ๊ฐ์ƒ์„ ๊ธฐ๋กํ•˜๊ณ , ๋น„๋ˆ—๋ฐฉ์šธ์ฒ˜๋Ÿผ ๊ณต์œ ํ•˜๋Š” ์„œ๋น„์Šค

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published