/funco-client

funco service client react SPA repository

Primary LanguageTypeScript

funco-logo

πŸ“š Table of Contents



🀝 Team Member

λ°•μ„Έμ›… [νŒ€μž₯, BE, Infra] μ†Œμž¬μ—΄ [CTO, BE] 이선주 [BE] μ΄νƒœν˜Έ [BE] μ—„μ†Œν˜„ [FE] ν™©μ£Όμ˜ [FE]

πŸ•ŠοΈ Deploy URL


πŸ“ Specification



πŸ“’ Introduction

μ„œλΉ„μŠ€ μ†Œκ°œ ν•œ 쀄

  • νŒ”λ‘œμœ™ νˆ¬μžκ°€ κ°€λŠ₯ν•œ 가상화폐 λͺ¨μ˜ 투자 μ„œλΉ„μŠ€
  • νŒ”λ‘œμœ™ 투자 : λ‹€λ₯Έ μ‚¬λžŒμ—κ²Œ νˆ¬μžν•˜κ³ , κ·Έ μ‚¬λžŒμ˜ 투자 λ‚΄μ—­κ³Ό λ™μΌν•˜κ²Œ μžλ™ 투자되고 정산받을 수 μžˆλŠ” κΈ°λŠ₯


πŸ› οΈ Skills

λΆ„λ₯˜ 기술 μŠ€νƒ
BE Java SpringBoot Spring Data JPA Spring Security Spring Batch QueryDsl JWT OAuth
FE TypeScript React Recoil Vite Node.js npm
Infra AmazonEC2 Nginx Ubuntu Docker Jenkins MariaDB Redis
ν˜‘μ—…λ„κ΅¬ GitLab Figma Mattermost Notion Gather


🌐 System Architecture


πŸ’Ύ ERD



🏠 Service Layout

landing quote asking-price trade
메인 νŽ˜μ΄μ§€ μ‹œμ„Έ ν˜Έκ°€ 거래
Investment-details follow ranking notification
νˆ¬μžλ‚΄μ—­ νŒ”λ‘œμš° λž­ν‚Ή μ•Œλ¦Ό


βš™οΈ Function

🎯 가상화폐 거래

  • μ‹œκ°„λŒ€ 별 코인 μ‹œμ„Έ 차트 쑰회
  • μ‹€μ‹œκ°„ 코인 μ‹œμ„Έ 쑰회 및 검색
  • μ‹œμž₯κ°€(κ°„νŽΈ 거래) 맀수, 맀도
  • 지정가(μ˜ˆμ•½ 거래) 맀수, 맀도
  • 가상화폐 체결, 미체결 λ‚΄μ—­ 쑰회
  • 거래 체결 μ‹œ μ•Œλ¦Ό
  • 관심 코인 μΆ”κ°€, 쑰회, μ‚­μ œ
  • 보유 코인 쑰회

🎯 νˆ¬μžλ‚΄μ—­

  • λ³΄μœ μžμ‚° λͺ©λ‘ 쑰회
  • 일별, 월별 투자 손읡 쑰회
  • κΈ°κ°„/κ±°λž˜μ’…λ₯˜/μžμ‚°μ’…λ₯˜ 별 μžμ‚° 변동 λ‚΄μ—­ 쑰회
  • νŒ”λ‘œμž‰, νŒ”λ‘œμ›Œ 투자 μžμ‚° 쑰회
  • νŒ”λ‘œμš° 거래, 보유 λ‚΄μ—­ 쑰회
  • λͺ¨λ“  가상화폐 미체결 거래 λ‚΄μ—­ 쑰회

🎯 νŒ”λ‘œμš°

  • νŒ”λ‘œμš° μ‹œ μžμ‚° 동기화
  • νŒ”λ‘œμž‰μ˜ νˆ¬μžμ— 따라 μžλ™ 투자
  • νŒ”λ‘œμš° μ •μ‚° μ‹œ μ•Œλ¦Ό

🎯 λž­ν‚Ή

  • 정각 κΈ°μ€€ 30λΆ„ λ§ˆλ‹€ λž­ν‚Ή μ—…λ°μ΄νŠΈ
  • 총 νŒ”λ‘œμ›Œ κΈˆμ•‘μ— λ”°λ₯Έ λž­ν‚Ή 쑰회
  • 총 μžμ‚°μ— λ”°λ₯Έ λž­ν‚Ή 쑰회

🎯 νšŒμ›

πŸ’‘ νšŒμ›μ€ Spring Security & JWT & Oauth2.0 μ‚¬μš©ν•˜μ—¬ ꡬ글 μ†Œμ…œ 둜그인 κ΅¬ν˜„

  • νšŒμ› κ°€μž…
  • 둜그인, λ‘œκ·Έμ•„μ›ƒ
  • μœ μ € 투자 포트폴리였 쑰회
  • λ‹‰λ„€μž„ μˆ˜μ •
  • ν•œμ€„ μ†Œκ°œ μˆ˜μ •

⏰ Batch

  • QueryDslItemReaderλ₯Ό ν™œμš©ν•˜μ—¬ Chunk-oriented Processing으둜 데이터λ₯Ό μ²˜λ¦¬ν•˜μ—¬ μ €μž₯
  • 맀일 μ˜€μ „ 6μ‹œμ— μ „λ‚ μ˜ 거래 λ‚΄μ—­μœΌλ‘œ 일별 톡계 내역을 μƒμ„±ν•˜λŠ” Job
    • 체결 λ‚΄μ—­ ν…Œμ΄λΈ”μ˜ 데이터λ₯Ό λˆ„μ  κ³„μ‚°ν•˜μ—¬ λ„μΆœλœ 손읡을 μž„μ‹œ 손읡 ν…Œμ΄λΈ”μ— μ €μž₯ν•˜λŠ” Step
    • μž„μ‹œ 손읡 ν…Œμ΄λΈ”μ˜ 데이터λ₯Ό 일별 톡계 ν…Œμ΄λΈ”μ— μ €μž₯ν•˜λŠ” Step
  • 맀월 1일 μžμ •μ— μ „λ‹¬μ˜ 일별 톡계 λ‚΄μ—­μœΌλ‘œ 월별 톡계 내역을 μƒμ„±ν•˜λŠ” Job μ‹€ν–‰
    • μ „λ‹¬μ˜ 일별 톡계 ν…Œμ΄λΈ”μ˜ 데이터λ₯Ό λˆ„μ  κ³„μ‚°ν•˜μ—¬ 월별 톡계 ν…Œμ΄λΈ”μ— μ €μž₯ν•˜λŠ” Step

πŸ’ͺ Challenges

FrontEnd

  • 100μ—¬ 개의 μ½”μΈμ˜ μ‹œμ„Έλ₯Ό μ‹€μ‹œκ°„ μ›Ήμ†ŒμΌ“μœΌλ‘œ λ°›μ•„μ˜€λŠ”λ° 보유 및 관심 코인 λ¦¬μŠ€νŠΈμ—μ„œλŠ” λ°±μ—¬ 개의 코인 μ‹œμ„Έλ₯Ό μ‹€μ‹œκ°„μœΌλ‘œ λ°›μ•„μ˜¬ ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€
  • μ›Ήμ†ŒμΌ“μ„ λͺ¨λ“ˆν™” ν•˜μ—¬ λ‹€λ₯Έ νŒŒμΌμ—μ„œλ„ μ›Ήμ†ŒμΌ“μ˜ send μš”μ²­μ„ 보낼 수 μžˆλ„λ‘ ν–ˆμŠ΅λ‹ˆλ‹€

λž­ν‚Ή μ •λ ¬

  • λž­ν‚Ήμ€ μ–΄μ©” 수 없이 맀번 총 μžμ‚°κ³Ό 총 νŒ”λ‘œμ›Œ κΈˆμ•‘μ„ κ΅¬ν•΄μ•Όν•˜κΈ° λ•Œλ¬Έμ— μ„±λŠ₯에 λŒ€ν•œ 고민이 μžˆμ„ 수 밖에 μ—†μ—ˆμŠ΅λ‹ˆλ‹€.
  • μ‹€μ‹œκ°„μ€ 쿼리가 많이 λ°œμƒν•˜μ—¬ λ„ˆλ¬΄ μ„œλ²„μ— 뢀담이 갈 것 κ°™μ•„μ„œ 30λΆ„λ§ˆλ‹€ μŠ€μΌ€μ€„λ§μ„ 돌렀 계산을 ν•˜κ³  κ³„μ‚°ν•œ 값듀은 λ ˆλ””μŠ€μ— 넣도둝 ν–ˆμŠ΅λ‹ˆλ‹€.
    • μ‘°νšŒκ°€ 많이 μΌμ–΄λ‚˜κΈ° λ•Œλ¬Έμ— redis μ‚¬μš©μ„ κ³ λ €ν–ˆμŠ΅λ‹ˆλ‹€.
  • μ •λ ¬ κΈ°λŠ₯을 ν•„μš”λ‘œ ν–ˆκΈ° λ•Œλ¬Έμ— λ ˆλ””μŠ€μ˜ ZSet을 ν™œμš©ν•˜μ—¬ 정렬을 ν•˜μ˜€κ³  μ‘°νšŒν•  λ•Œλ§ˆλ‹€ λ ˆλ””μŠ€μ—μ„œ μΊμ‹±ν•˜μ—¬ λ³΄μ—¬μ£Όμ—ˆμŠ΅λ‹ˆλ‹€.
    • ZSet 연산은 O(log(n))으둜 λ‹¨μˆœνžˆ java의 timsort, Arrays.sort()의 평균 O(nlog(n))보닀 훨씬 νš¨μœ¨μ μž…λ‹ˆλ‹€.
    • zrange의 μ‹œκ°„λ³΅μž‘λ„λŠ” O(log(n) + m(λ°˜ν™˜λ°›λŠ” λ©€λ²„λ“€μ˜ 개수))둜 효율적으둜 νŽ˜μ΄μ§• 처리λ₯Ό ν–ˆμŠ΅λ‹ˆλ‹€.

지정가 μ˜ˆμ•½ 거래

  • μ„œλ²„μ—μ„œ μ‹€μ‹œκ°„μœΌλ‘œ λ“±λ‘λœ μ˜ˆμ•½ κ±°λž˜κ°€ μ²˜λ¦¬λ˜μ–΄μ•Ό ν–ˆλ‹€.
  • μ„œλ²„κ°€ μ›Ήμ†ŒμΌ“ ν΄λΌμ΄μ–ΈνŠΈκ°€ λΌμ„œ μ‹€μ‹œκ°„μœΌλ‘œ λ©”λͺ¨λ¦¬μ— 코인 μ‹œμ„Έλ“€μ„ 받아와 μ €μž₯ν•œλ‹€.
  • μ˜ˆμ•½ 거래λ₯Ό λ™μ‹œμ„± 처리λ₯Ό μœ„ν•΄ ConcurrentHashMap으둜 κ΄€λ¦¬ν–ˆκ³  각 코인 별 맀수, 맀도 μš°μ„ μˆœμœ„ 큐λ₯Ό μ‚¬μš©ν•΄ μ‹œμ„Έλ₯Ό κ°μ§€ν•˜μ—¬ κ±°λž˜κ°€ 될 수 μžˆλŠ” 데이터 λ˜λŠ” ν•˜λ‚˜μ˜ λ°μ΄ν„°λ§Œ ν™•μΈν•˜λ„λ‘ O(1)둜 κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€.
  • μ„±λŠ₯ μ΅œμ ν™”λ₯Ό μœ„ν•΄ μ˜ˆμ•½ κ±°λž˜μ— λ“±λ‘λœ μ½”μΈμ˜ μ‹œμ„Έ λ°μ΄ν„°λ§Œ μœ λ™μ μœΌλ‘œ λ°›μ•„μ˜€λ„λ‘ μ›Ήμ†ŒμΌ“ λ©”μ‹œμ§€λ₯Ό λ™μ μœΌλ‘œ μ²˜λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€.

μ •ν™•ν•œ μ†Œμˆ˜μ  μ—°μ‚°

  • ν•€ν…Œν¬ ν”„λ‘œμ νŠΈ νŠΉμ„± 상 μ •ν™•ν•œ μ†Œμˆ˜μ  연산을 닀뀄야 함. 우리의 경우 μ •ν™•ν•œ 코인 μˆ˜λŸ‰κ³Ό 가격에 λŒ€ν•œ μ •ν™•ν•˜κ³  일관적인 μ—°μ‚° κ²°κ³Όκ°€ ν•„μš”.
  • BigDecimal Utility class λ₯Ό λ§Œλ“€μ–΄ μ „μ—­μœΌλ‘œ μ‚¬μš©ν•¨μœΌλ‘œμ¨ 일관적인 μ—°μ‚°κ³Ό μ •ν™•ν•œ μ†Œμˆ˜μ  연산을 ν•  수 있게 됐닀.

νŽ˜μ΄μ§• 쿼리 μ΅œμ ν™”

  • Offset λ°©μ‹μ˜ Pagination은 Offset 값이 컀질수둝 그만큼의 rowλ₯Ό μ½μ–΄μ•Όν•˜λ―€λ‘œ μ„±λŠ₯μ €ν•˜κ°€ μΌμ–΄λ‚©λ‹ˆλ‹€.
  • 가상화폐 거래 μ‚¬μ΄νŠΈ νŠΉμ„±μƒ 무수히 λ§Žμ€ 거래 내역이 μ €μž₯ 될 κ²ƒμ΄λ―€λ‘œ Cursor Pagination을 μ‚¬μš©ν•˜μ—¬ 쑰회 μ„±λŠ₯을 μ΅œμ ν™” ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
  • μ΄λŸ¬ν•œ 방식은 Batch의 ItemReader에도 μ μš©ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
  • μ „λ‚ μ˜ λͺ¨λ“  거래 λ‚΄μ—­μœΌλ‘œ 일별 톡계λ₯Ό μƒμ„±ν•˜λŠ” Jobμ—μ„œ QueryDslNoOffsetItemReaderλ₯Ό μ‚¬μš©ν•˜μ—¬ Offset 없이 Chunk λ‹¨μœ„λ‘œ 데이터λ₯Ό 읽어 ν”„λ‘œμ„Έμ‹±ν•©λ‹ˆλ‹€.