Skip to content

formaro/PODO-R-FE

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

150 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ‡[ํฌ๋„์•Œ] ๊ทน์žฅ ์ขŒ์„ ๋ฆฌ๋ทฐ์‚ฌ์ดํŠธ๐Ÿ‡

๐ŸŽ‰ ํฌ๋„์•Œ ์†Œ๊ฐœ | About Us

KakaoTalk_20221014_194653280

๊ทน์žฅ ์ขŒ์„?! ์ข‹์€ ์ž๋ฆฌ๋Š” ์—†๋Š” ์ƒํƒœ์— ์ตœ์„ ์˜ ์„ ํƒ์€?

KakaoTalk_20221003_034649228

๐Ÿ‘‰ ๋‚˜๋งŒ ์•Œ๊ณ  ์žˆ๋˜ ์ข‹์€ ์ขŒ์„์ด๋‚˜ ๊ฟ€ ๊ฐ™์€ ์ขŒ์„์„ ๊ณต์œ ํ•˜๊ณ  ์‹ถ์œผ์‹  ๋ถ„!
๐Ÿ‘‰ ํ‚ค ํฐ ์‚ฌ๋žŒ๋„ ํ‚ค ์ž‘์€ ์‚ฌ๋žŒ๋„ ๊ณต์—ฐ์ด ๋‹ค ๋ณด์ด๋Š” ์ž๋ฆฌ๋ฅผ ๊ณต์œ ํ•˜๊ณ  ์‹ถ์œผ์‹  ๋ถ„ !
๐Ÿ‘‰ ๊ทน์žฅ ์ขŒ์„์ด ์–ด๋–ป๊ฒŒ ๋ณด์ผ์ง€ ๋ชจ๋ฅด๊ฒ ๋‹ค๋ฉด ํฌ๋„์•Œ์—์„œ ํ™•์ธํ•˜์„ธ์š”!

  • ํฌ๋„์•Œ์€ ์ˆจ๊ฒจ์ง„ ๊ฟ€ ์ž๋ฆฌ๋‚˜ ์ตœ์„ ์˜ ์ขŒ์„ ์„ ํƒ์„ ๋„์šธ ์ˆ˜ ์žˆ๋Š” ์›น ์‚ฌ์ดํŠธ ์ž…๋‹ˆ๋‹ค.

๐ŸŒŽ ์›น์‚ฌ์ดํŠธ | Website ํฌ๋„์•Œ ๋ฐ”๋กœ๊ฐ€๊ธฐ


๐Ÿ”ญ๋ชฉ์ฐจ | Contents

  1. ๊ฐœ๋ฐœ๊ธฐ๊ฐ„ | Project Period
  2. ์•„ํ‚คํ…์ณ | Architecture
  3. ์ฃผ์š” ๊ธฐ๋Šฅ | Main Function
  4. ๊ฐœ๋ฐœํ™˜๊ฒฝ | Development Enviornment
  5. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ | Library
  6. ERD
  7. ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…| Trouble shooting
  8. ํŒ€์› | TEAM

โŒš ๊ฐœ๋ฐœ๊ธฐ๊ฐ„ | Project Period

2022.08.26 ~ 2022.10.03 (6์ฃผ๊ฐ„)


๐Ÿ›  ์•„ํ‚คํ…์ณ | Architecture

KakaoTalk_20221003_032628588

โš” ์ฃผ์š” ๊ธฐ๋Šฅ | Main Function

FE

  • ์†Œ์…œ ๋กœ๊ทธ์ธ (ํŠธ์œ„ํ„ฐ / ์นด์นด์˜ค)
  • ์‹ค์‹œ๊ฐ„ ๋ฆฌ๋ทฐ ํ™•์ธ (๋ฉ”์ธ ํŽ˜์ด์ง€ ์‹ค์‹œ๊ฐ„ ๋ฆฌ๋ทฐ SECTION)
  • ๋ฆฌ๋ทฐ ํ›„๊ธฐ (CRUD) / ๋ฆฌ๋ทฐ ๋Œ“๊ธ€ / ์ข‹์•„์š” ๊ธฐ๋Šฅ / ๋ฆฌ๋ทฐ ํŽ˜์ด์ง€ ๋ฌดํ•œ์Šคํฌ๋กค
  • ํƒœ๊ทธ, ํ•„ํ„ฐ, ๊ฒ€์ƒ‰์–ด๋ฅผ ํ†ตํ•œ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ
  • ํ”„๋กœํ•„ ์ˆ˜์ •
  • ํ”„๋กœํ•„ ๋‚ด์—์„œ ๋‚ด๊ฐ€ ์“ด ๋ฆฌ๋ทฐ ํ™•์ธ
  • ๊ทน์žฅ ์ •๋ณด ์ธํฌ MODAL (KAKAO MAP)
  • ๋ฐ˜์‘ํ˜•

BE

  • ๊ฐ„ํŽธํ•œ ์†Œ์…œ ๋กœ๊ทธ์ธ ํŠธ์œ„ํ„ฐ, ์นด์นด์˜คํ†ก ์ง€์›
  • ๋‹ค์–‘ํ•œ ๊ฒฝ์šฐ์˜ ๊ฒ€์ƒ‰ ์š”์ฒญ ์ผ๊ด„ ์ฒ˜๋ฆฌ (QueryDSL)
  • ์ž์ฃผ ์กฐํšŒํ•˜๋Š” ๋ฐ์ดํ„ฐ ์บ์‹ฑ ์ฒ˜๋ฆฌ (Redis, Spring Cache)
  • ๋ฐฐํฌ๋œ ์„œ๋ฒ„์˜ ์—๋Ÿฌ ๋กœ๊ทธ๋ฅผ ์‰ฝ๊ฒŒ ํ™•์ธ ๊ฐ€๋Šฅ (Slack Webhook, Logback)
  • RefreshToken ํ† ํฐ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ ์ •๋ณด ์ž๋™ ๊ฐฑ์‹  (JWT)
  • S3 ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ๋˜๋Š” ์ด๋ฏธ์ง€ ๋ฆฌ์‚ฌ์ด์ง• ์ฒ˜๋ฆฌ (Imgscalr)
  • CI/CD ์ž๋™ ๋ฐฐํฌ (Githib Action, S3, CodeDeploy)
  • ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ (NGINX)

โ› ๊ฐœ๋ฐœํ™˜๊ฒฝ | Development Environment

React Hook Form

๐ŸŽจ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ | Library

 "@fortawesome/react-fontawesome": "^0.2.0",
 "axios": "^0.27.2",
 "file-loader": "^6.2.0",
 "json-server": "^0.17.0",
 "moment": "^2.29.4",
 "react": "^18.2.0",
 "react-dom": "^18.2.0",
 "react-hook-form": "^7.34.2",
 "react-intersection-observer": "^9.4.0",
 "react-query": "^3.39.2",
 "react-router-dom": "^6.3.0",
 "react-scripts": "5.0.1",
 "react-select": "^5.4.0",
 "react-toastify": "^9.0.8",
 "recoil": "^0.7.5",
 "styled-components": "^5.3.5",
 "sweetalert2": "^11.4.33",
 "sweetalert2-react-content": "^5.0.3",
 "swiper": "^8.3.2",

๐Ÿ”‘ ERD

erd


๐Ÿ›  ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ… | Trouble shooting

(FE) ์›น ํŽ˜์ด์ง€ ์„ฑ๋Šฅ ์ตœ์ ํ™” ํ•˜๊ธฐ
ํŠธ๋Ÿฌ๋ธ” ์ด์Šˆ

Untitled

lighthouse๋ฅผ ์ด์šฉํ•œ ์„ฑ๋Šฅ ์ธก์ • ๊ฒฐ๊ณผ ์„ฑ๋Šฅ ๋ฐ ์ ‘๊ทผ์„ฑ, ๊ถŒ์žฅ์‚ฌํ•ญ์˜ ์ ์ˆ˜๊ฐ€ ๋งŒ์กฑ์Šค๋Ÿฝ๊ฒŒ ๋‚˜์˜ค์ง€ ์•Š์•„ ํ•ด๋‹น ์‚ฌํ•ญ๋“ค์„ ์ •๋ฆฌํ•˜๊ณ , ๊ฐœ์„ ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •.

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

์ด๋ฏธ์ง€ ๋ Œ๋”๋ง ์‹œ๊ฐ„์„ ์ค„์ด๊ธฐ ์œ„ํ•ด

  • ์ฐจ์„ธ๋Œ€ ํ˜•์‹์„ ์‚ฌ์šฉํ•ด ์ด๋ฏธ์ง€๋ฅผ ์ œ๊ณต jpg, png > webp๋กœ ๋ณ€๊ฒฝ
  • ๋™์  ์ด๋ฏธ์ง€ ์บ์‹ฑ์ฒ˜๋ฆฌ ์ง„ํ–‰. s3, cloudfront ์—์„œ ์บ์‹ฑ ์ •์ฑ… ๋ณ€๊ฒฝ

๋ฉ”์ธํŽ˜์ด์ง€ ๋ Œ๋”๋ง์„ ์ฐจ๋‹จ์‹œํ‚ค๊ณ  ๋ฆฌ์†Œ์Šค๋ฅผ ๋จผ์ € ๋ Œ๋”๋ง ํ•˜๋ ค๋Š”๊ฑธ ๋ฐฉ์ง€.
(๋ฆฌ์†Œ์Šค ๋งํฌ์— async๋ฅผ ๋„ฃ์–ด ๊ฐ™์ด ๋กœ๋”ฉ ์‹œํ‚ค๋„๋กํ•จ.)


์›นํฐํŠธ๊ฐ€ ๋กœ๋”ฉ๋˜๊ธฐ ์ „๊นŒ์ง€ ํ…์ŠคํŠธ๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š๋„๋ก ์ตœ์ ํ™”๋ฅผ ์ง„ํ–‰ํ•จ.
(font-display : swap;)


lighthouse ๊ฒฐ๊ณผ

Untitled (1)

(FE) ์ด๋ฏธ์ง€ ๋ Œ๋”๋ง ์†๋„ ๊ฐœ์„ 
ํŠธ๋Ÿฌ๋ธ” ์ด์Šˆ
์‚ฌ์šฉ์ž๊ฐ€ ๋ฎค์ง€์ปฌ ์ขŒ์„ ๋ฆฌ๋ทฐ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ์„œ๋กœ๋‹ค๋ฅธ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฎค์ง€์ปฌ์„ ์กฐํšŒํ•˜๊ณ  ๋‹ค์‹œ ๊ฐ™์€ ๋ฎค์ง€์ปฌ์„ ์กฐํšŒํ•  ๋•Œ๋งˆ๋‹ค ๋ Œ๋”๋ง์ด ๊ณ„์† ์ผ์–ด๋‚œ๋‹ค๋ฉด ์‚ฌ์šฉ์ž ํ”ผ๋กœ๋„๊ฐ€ ์˜ฌ๋ผ๊ฐ€ ์ดํƒˆ๋ฅ ์ด ๋†’์•„์งˆ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ

Untitled (2)

ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…
๋ฆฌ์•กํŠธ ์ฟผ๋ฆฌ์˜ ์บ์‹ฑ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด ๋ฐ”๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ Œ๋”๋ง ๋œ ํ™”๋ฉด์„ ์ถœ๋ ฅ

Untitled (3)

(BE) ๊ทน์žฅ๋ณ„ ์ขŒ์„ ์กฐํšŒ์‹œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์„ฑ๋Šฅ ๊ฐœ์„ 
๋ฌธ์ œ์ƒํ™ฉ
  • ๊ทน์žฅ๋ณ„ ์ขŒ์„ ์ •๋ณด๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ํ…Œ์ด๋ธ”์— ์ €์žฅํ•˜์˜€์Šต๋‹ˆ๋‹ค.
์ขŒ์„์•„์ด๋”” ์ธต ๊ตฌ์—ญ ์—ด ์ขŒ์„๋ฒˆํ˜ธ ๊ทน์žฅ์•„์ด๋””
1 FIRST A 1 8 1
2 FIRST A 1 9 1
  • ๊ทน์žฅ์˜ ์ขŒ์„ ์ •๋ณด ๋ฐ์ดํ„ฐ๋ฅผ json ํ˜•ํƒœ๋กœ ๊ฐ€๊ณตํ•˜๋Š” ๊ณผ์ •์—์„œ ์—ฌ๋Ÿฌ๋ฒˆ์˜ ์ฟผ๋ฆฌ ํ˜ธ์ถœ์ด ํ•„์š”ํ–ˆ๊ณ  ์„œ๋ฒ„ ์‘๋‹ต์— ๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์˜๊ฒฌ์กฐ์œจ

  1. mongoDB ๊ฐ™์€ NoSQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ขŒ์„ ์ •๋ณด๋ฅผ json ํ˜•์‹์œผ๋กœ ์ €์žฅํ•˜๊ธฐ
  2. ์บ์‹œ๋ฅผ ์ ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ˜ธ์ถœ ํšŸ์ˆ˜๋ฅผ ์ค„์ด๊ธฐ
  • ๊ทน์žฅ๋ณ„ ์ขŒ์„ ์ •๋ณด๋Š” ๋ณ€๊ฒฝ์ด ๊ทน๋„๋กœ ์ ๊ณ  ์กฐํšŒ๊ฐ€ ๋งŽ์€ ๋ฐ์ดํ„ฐ ํŠน์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Œ
  • ์บ์‹œ๋ฅผ ์ ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •

๊ฒฐ๊ณผ

  • JMeter๋ฅผ ํ™œ์šฉํ•œ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ ์•ฝ 90%์˜ ์‘๋‹ต์‹œ๊ฐ„ ๊ฐ์†Œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
๋ผ๋ฒจ ํ‘œ๋ณธ์ˆ˜ ํ‰๊ท (ms) ์ตœ์†Œ๊ฐ’ ์ตœ๋Œ€๊ฐ’ ํ‘œ์ค€ํŽธ์ฐจ ์˜ค๋ฅ˜
cache 5000 341 5 725 156.5247 0
noCache 5000 3284 43 12071 1014.649 0

(BE) ๊ทน์žฅ๋ณ„ ์ขŒ์„ ์กฐํšŒ์‹œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์„ฑ๋Šฅ ๊ฐœ์„ 
๋ฌธ์ œ์ƒํ™ฉ
  • JWT ํ† ํฐ์„ ํฌํ•จํ•˜๋Š” ๋ชจ๋“  ์š”์ฒญ์€ ํ•„ํ„ฐ์—์„œ ํ•ด๋‹น ํ† ํฐ์„ ๊ฒ€์ฆํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์นฉ๋‹ˆ๋‹ค.
  • MemberRepository๋ฅผ ํ†ตํ•ด Member ๊ฐ์ฒด๋ฅผ ์ฐพ์•„์™€์„œ UserDetails๋ฅผ ๊ตฌ์„ฑํ•˜์˜€๋Š”๋ฐ
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class UserDetailsImpl implements UserDetails {

    private Member member;
		...
}

@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
    private final MemberRepository memberRepository;
    @Override
    public UserDetails loadUserByUsername(String subject) throws UsernameNotFoundException {
        Member member = memberRepository.findById(Long.parseLong(subject))
                .orElseThrow(() -> new UsernameNotFoundException("๋“ฑ๋ก๋˜์ง€์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค."));
        return new UserDetailsImpl(member);
    }
}
  • ์‚ฌ์šฉ์ž ๊ถŒํ•œ์ด ํ•„์š” ์—†๋Š” ์š”์ฒญ์—๋„ ํ† ํฐ์ด ํฌํ•จ๋˜์–ด์žˆ๋‹ค๋ฉด UserDetails๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์กฐํšŒํ•˜์—ฌ ์‘๋‹ต์‹œ๊ฐ„์ด ๊ธธ์–ด์ง€๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ˆ˜์ •๋ฐฉํ–ฅ

  1. JWT Token์€ ์„œ๋ฒ„์—์„œ SecretKey๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์ฆํ•œ ๊ฒƒ
  2. Token์— ๋‹ด๊ธด ์•„์ด๋””๋Š” ํ† ํฐ์ด ์œ ํšจํ•˜๋‹ค๋ฉด ์ •ํ™•ํ•œ ๊ฒƒ
  • UserDetaileService๋ฅผ ์‚ญ์ œํ•˜๊ณ , UserDetailsImpl์— Member ๊ฐ์ฒด ๋Œ€์‹  Id๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ 

  • JwtTokenProvider์—์„œ ์ธ์ฆ์ •๋ณด๋ฅผ ์กฐํšŒํ•  ๋•Œ, JWT ํ† ํฐ์˜ Sub ํ•„๋“œ์— ์ €์žฅํ•ด๋‘” id๊ฐ’์œผ๋กœ UserDetails๋ฅผ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class UserDetailsImpl implements UserDetails {

    private Long memberId;
		...
}

@Component
@Slf4j
@RequiredArgsConstructor
public class JwtTokenProvider {
		...
		public Authentication getAuthentication(String jwtToken) {
			  Claims claims = getClaims(jwtToken);
			  UserDetailsImpl userDetails = new UserDetailsImpl(Long.parseLong(laims.getSubject()));
			  return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
		}
		...
}
  • ๊ฐ๊ฐ์˜ ์—”ํ‹ฐํ‹ฐ๋“ค๊ณผ Member ๊ฐ์ฒด๊ฐ€ ๋งบ์€ ์—ฐ๊ด€๊ด€๊ณ„๋Š” ์ œ๊ฑฐํ•œ ํ›„์— Auditing ์†์„ฑ์— @CreatedBy @LastModifiedBy ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {

		...

    @CreatedBy // ์ƒ์„ฑ์ž
    private Long createdBy;

    @LastModifiedBy //์ˆ˜์ •์ž
    private Long modifiedBy;
}

@RequiredArgsConstructor
@Component
public class LoginUserAuditorAware implements AuditorAware<Long> {

    @Override
    public Optional<Long> getCurrentAuditor() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (null == authentication || !authentication.isAuthenticated() || authentication.getPrincipal().equals("anonymousUser")) {
            return Optional.empty();
        }
        UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();

        return Optional.ofNullable(userDetails.getMemberId());
    }
}

๊ฒฐ๊ณผ

  • JMeter๋ฅผ ํ™œ์šฉํ•œ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ ์•ฝ 80%์˜ ์‘๋‹ต์‹œ๊ฐ„ ๊ฐ์†Œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
๋ผ๋ฒจ ํ‘œ๋ณธ์ˆ˜ ํ‰๊ท (ms) ์ตœ์†Œ๊ฐ’ ์ตœ๋Œ€๊ฐ’ ํ‘œ์ค€ํŽธ์ฐจ ์˜ค๋ฅ˜
๋ฉค๋ฒ„ ๊ฐ์ฒด ์‚ฌ์šฉ 5000 939 34 1893 199.3258 0
Token id๊ฐ’ ์‚ฌ์šฉ 5000 125 7 382 53.45967 0

๐Ÿคธ๐Ÿปโ€ ํŒ€์› | TEAM

kimhun RIM yelim suweon yongwon YURI
๊น€ ํ›ˆ ๊น€ํœ˜๋ฆผ ๊น€์˜ˆ๋ฆผ ๋ฐ•์ˆ˜์› ๋ฐ•์šฉ์› ๊น€์œ ๋ฆฌ
BE(๋ฆฌ๋”) BE FE(๋ถ€๋ฆฌ๋”) FE FE DESINGER
๐Ÿ”— ๐Ÿ”— ๐Ÿ”— ๐Ÿ”— ๐Ÿ”— ๐Ÿ”—

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • JavaScript 98.1%
  • Other 1.9%