Code Monkey home page Code Monkey logo

pennyway-was's Introduction

๐Ÿ’ฐ Pennyway

์ง€์ถœ ๊ด€๋ฆฌ SNS ํ”Œ๋žซํผ

Version # Revision Date Description Author
v0.0.1 2024.03.07 ํ”„๋กœ์ ํŠธ ๊ธฐ๋ณธ ์„ค๋ช… ์ž‘์„ฑ ์–‘์žฌ์„œ
v0.0.2 2024.03.29 ERD ์ถ”๊ฐ€, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „ ์ˆ˜์ •, Infra ์ถ”๊ฐ€ ์–‘์žฌ์„œ

๐Ÿ‘ช Backend Team

์–‘์žฌ์„œ ์ด์ง„์šฐ ์•ˆ์„ฑ์œค

๐ŸŒณ Branch Convention

๐Ÿ’ก Git-Flow ์ „๋žต์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • main
    • ๋ฐฐํฌ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์˜ ์ฝ”๋“œ๋งŒ์„ ๊ด€๋ฆฌํ•˜๋Š” ํ”„๋กœ๋•์…˜์šฉ ๋ธŒ๋žœ์น˜
    • PM(์–‘์žฌ์„œ)์˜ ์Šน์ธ ํ›„ ๋ณ‘ํ•ฉ ๊ฐ€๋Šฅ
  • dev
    • ๊ฐœ๋ฐœ ์ „์šฉ ๋ธŒ๋žœ์น˜
    • ํ•œ ๋ช… ์ด์ƒ์˜ ํŒ€์›์˜ ์Šน์ธ ํ›„ ๋ณ‘ํ•ฉ ๊ฐ€๋Šฅ
    • ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ์ด ์™„๋ฃŒ๋œ ๋ธŒ๋žœ์น˜๋ฅผ ๋ณ‘ํ•ฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰
  • ์ด์Šˆ ๊ธฐ๋ฐ˜ ๋ธŒ๋žœ์น˜
    • ์ด์Šˆ๋Š” {ํ‹ฐ์ผ“๋ฒˆํ˜ธ}-{๋ธŒ๋žœ์น˜๋ช…}์„ ํฌํ•จํ•œ๋‹ค.
    • feat/{ํ‹ฐ์ผ“๋ฒˆํ˜ธ}-{๋ธŒ๋žœ์น˜๋ช…}: ์‹ ๊ทœ ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ ์‹œ ๋ธŒ๋žœ์น˜๋ช…
    • fix/{ํ‹ฐ์ผ“๋ฒˆํ˜ธ}-{๋ธŒ๋žœ์น˜๋ช…}: ๋ฆฌํŒฉํ† ๋ง, ์ˆ˜์ • ์ž‘์—… ์‹œ ๋ธŒ๋žœ์น˜๋ช…
    • hotfix/{ํ‹ฐ์ผ“๋ฒˆํ˜ธ}-{๋ธŒ๋žœ์น˜๋ช…}: ๋น ๋ฅด๊ฒŒ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ๋ฒ„๊ทธ ์กฐ์น˜ ์‹œ ๋ธŒ๋žœ์น˜๋ช…

๐Ÿค Commit Convention

๐Ÿ’ก angular commit convention

  • feat: ์‹ ๊ทœ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
  • fix: ๋ฒ„๊ทธ ์ˆ˜์ •
  • docs: ๋ฌธ์„œ ์ˆ˜์ •
  • rename: ์ฃผ์„, ๋กœ๊ทธ, ๋ณ€์ˆ˜๋ช… ๋“ฑ ์ˆ˜์ •
  • style: ์ฝ”๋“œ ํฌ๋งทํŒ…, ์„ธ๋ฏธ์ฝœ๋ก  ๋ˆ„๋ฝ (์ฝ”๋“œ ๋ณ€๊ฒฝ ์—†๋Š” ๊ฒฝ์šฐ)
  • refactor: ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง
  • test: ํ…Œ์ŠคํŠธ ์ฝ”๋“œ, ๋ฆฌํŽ™ํ† ๋ง ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ถ”๊ฐ€
  • chore: ๋นŒ๋“œ ์—…๋ฌด ์ˆ˜์ •, ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ € ์ˆ˜์ •

๐Ÿ“Œ Architecture

1๏ธโƒฃ System Architecture

2๏ธโƒฃ Infrastructure Architecture

3๏ธโƒฃ Multi Module Architecture

4๏ธโƒฃ ERD


๐Ÿ“— Tech Stack

1๏ธโƒฃ Framework & Library

  • JDK 17
  • SpringBoot 3.2.3
  • Spring Boot Starter Security 3.2.4
  • Spring Data JPA 3.2.3
  • QueryDsl 5.0.0
  • Spring Doc Open API 2.4.0
  • Lombok 1.18.30
  • JUnit 5
  • jjwt 0.12.5
  • httpclient5 5.2.25.RELEASE
  • OpenFeign 4.0.6

2๏ธโƒฃ Build Tools

  • Gradle 7.6.4

3๏ธโƒฃ Database

  • MySQL 8
  • Redis 7.2.4

4๏ธโƒฃ Infra

  • AWS EC2 (for Build Server, Bastion Server)
  • AWS NAT Gateway
  • AWS S3
  • AWS Route53
  • AWS VPC
  • AWS Elastic Load Balancer
  • AWS SNS
  • Docker & Docker-compose
  • Ngnix
  • GitHub Actions

pennyway-was's People

Contributors

psychology50 avatar jinlee1703 avatar asn6878 avatar

Stargazers

King's meow avatar SunKyu Choi avatar TaeKyu Lim avatar seungwoo avatar ์ด์˜์ฐฌ avatar ์ตœํฌ์ง„ avatar Min Yul avatar J0YERIM avatar Geonwoo Pack avatar yanni avatar  avatar  avatar ๋ฐ•์„ฑ๋ฏผ avatar Jinyeong Seol avatar  avatar  avatar  avatar

pennyway-was's Issues

โœจ WAS ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ

์ถ”๊ฐ€ํ•  ๊ธฐ๋Šฅ

ํ•  ์ผ ๋ชฉ๋ก

  • ๋ฐฐํฌ ๋ฐฉ์‹ ์ •ํ•˜๊ธฐ
  • CI/CD ํŒŒ์ดํ”„๋ผ์ธ ์ˆ˜์ •
  • EC2 ์ธ์Šคํ„ด์Šค 8081 ํฌํŠธ ํ—ˆ์šฉ

์„ค๋ช…

ํ˜„์žฌ ๋ฐฐํฌ ์ž‘์—… ์‹œ Docker ์ด๋ฏธ์ง€๋ฅผ ๊ต์ฒดํ•˜๊ธฐ ์œ„ํ•œ ํ…€์ด ์žˆ์œผ๋‚˜, ์ด๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ๋ฅผ ํ•˜๊ณ ์ž ํ•จ

์ฐธ๊ณ  ์ž๋ฃŒ

โœจ Device Token ์Šค์ผ€์ค„๋ง

์ถ”๊ฐ€ํ•  ๊ธฐ๋Šฅ

ํ•  ์ผ ๋ชฉ๋ก

  • ๋งค์›” ํ™œ์„ฑ Device Token์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ›„, ์œ ํšจํ•˜์ง€ ์•Š์œผ๋ฉด ๋น„ํ™œ์„ฑ ํ† ํฐ์œผ๋กœ ๋ณ€๊ฒฝ
  • ์ˆ˜์ • ํƒ€์ž„ ์Šคํƒฌํ”„๊ฐ€ 2๊ฐœ์›”์ด ์ง€๋‚œ ํ™œ์„ฑํ™” ํ† ํฐ์„ ๋น„ํ™œ์„ฑ ํ† ํฐ์œผ๋กœ ๋ณ€๊ฒฝ

์„ค๋ช…

FCM์—์„œ ๊ถŒ์žฅํ•˜๋Š” Token ๊ด€๋ฆฌ ์ •์ฑ…

  • FCM ๊ถŒ์žฅ์‚ฌํ•ญ์— ๋”ฐ๋ฅด๋ฉด Server์— ์ €์žฅ๋œ FCM Token์€ ์ฃผ๊ธฐ์ ์œผ๋กœ ๋น„ํ™œ์„ฑ ์—ฌ๋ถ€๋ฅผ ๊ด€๋ฆฌํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

iOS์—์„œ FCM ๊ด€๋ฆฌ ์ •์ฑ…

1. ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์„ ์‹คํ–‰ํ–ˆ์„ ๋•Œ, ๊ธฐ๊ธฐ์— ์ €์žฅํ•œ Device Token ์กด์žฌ ์œ ๋ฌด ํ™•์ธ
   1-1. ์—†์œผ๋ฉด FCM ํ† ํฐ ๋ฐœ๊ธ‰ ์š”์ฒญ ํ›„
   1-2. ์„œ๋ฒ„์— ์ €์žฅ ์š”์ฒญ ํ›„ ์‚ฌ์šฉ์ž ๊ธฐ๊ธฐ์— "ํ† ํฐ"๊ณผ "๋ฐœ๊ธ‰๋ฐ›์€ ๋‚ ์งœ" ์ €์žฅ
   1-3. ์‹œ๋‚˜๋ฆฌ์˜ค ์ข…๋ฃŒ
2. Device Token ๋ฐœ๊ธ‰ ๋‚ ์งœ ํ™•์ธ
   2-1. ํ•œ ๋‹ฌ ์ด์ƒ ์ง€๋‚ฌ์œผ๋ฉด FCM ์žฌ๋ฐœ๊ธ‰ ์š”์ฒญ
   2-2. ๊ธฐ์กด ํ† ํฐ๊ณผ ์žฌ๋ฐœ๊ธ‰ ๋ฐ›์€ ํ† ํฐ์„ ์„œ๋ฒ„๋กœ ์ „๋‹ฌ
   2-3. ์‹œ๋‚˜๋ฆฌ์˜ค ์ข…๋ฃŒ
3. Device Token์ด ์กด์žฌํ•˜๊ณ , ํ•œ ๋‹ฌ ์ด์ƒ ์ง€๋‚˜์ง€ ์•Š์•˜์œผ๋ฉด ๊ทธ๋Œ€๋กœ ์‹œ๋‚˜๋ฆฌ์˜ค ์ข…๋ฃŒ.

BE์—์„œ FCM ๊ด€๋ฆฌ ์ •์ฑ…

  • ๋งค์›” FCM ํ† ํฐ์˜ API๋กœ ์ „์†กํ•ด ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆํ•˜๊ณ , ์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์„ ๋น„ํ™œ์„ฑ ํ† ํฐ์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.
  • ๊ฐ€๋” ์œ ํšจํ•˜์ง€ ์•Š์€๋ฐ ์œ ํšจํ•œ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ, ์ˆ˜์ •๋˜๊ณ  2๋‹ฌ ์ด์ƒ ์ง€๋‚œ ํ† ํฐ์€ ์ž๋™์œผ๋กœ ๋น„ํ™œ์„ฑํ™” ์ฒ˜๋ฆฌํ•œ๋‹ค.

๐Ÿ› Refresh Token ์žฌ๋ฐœ๊ธ‰ ์š”์ฒญ ์‹œ, RTR ๊ธฐ๋ฒ• ๋ฐ˜์˜ ์˜ค๋ฅ˜

๋ฒ„๊ทธ ๋‚ด์šฉ

  • RTR ๊ธฐ๋ฒ•์ด ์ ์šฉ๋˜์ง€ ์•Š์•„, AT๋Š” ์žฌ๋ฐœ๊ธ‰๋˜๋Š”๋ฐ RT๋Š” ๋ณ€๊ฒฝ๋œ ํ† ํฐ์ด redis์— ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ.

๋ฒ„๊ทธ ์œ„์น˜

  • kr.co.pennyway.domain.common.redis.refresh
  • RefreshTokenServiceImpl ํด๋ž˜์Šค์˜ refresh() ๋ฉ”์„œ๋“œ

image

  • ํ˜„์žฌ save()๋ฅผ ํ–ˆ์„ ๋•Œ, ์ •์ƒ์ ์œผ๋กœ ๋ณ€๊ฒฝ๊ฐ’์ด ์ €์žฅ๋˜์ง€ ์•Š๊ณ  ์žˆ๋‹ค๊ณ  ์ถ”์ธก

์žฌํ˜„

image

  • refresh()๋ฅผ ํ˜ธ์ถœํ•ด๋„ redis ๋‚ด token ์ •๋ณด๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Œ.

ํ• ์ผ

  • ์žฌ๋ฐœ๊ธ‰๋œ refresh token์ด redis์— ๋ฐ˜์˜๋˜๋„๋ก ์ˆ˜์ •

โœจ AOP ๊ธฐ๋Šฅ์œผ๋กœ Controller ๊ณ„์ธต Request, Response ๋กœ๊ทธ ๊ด€๋ฆฌ

์ถ”๊ฐ€ํ•  ๊ธฐ๋Šฅ

  • ์ปค์Šคํ…€ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๋ชจ๋“  request, response์— ๋Œ€ํ•œ log๋ฅผ ๋‚จ๊ธฐ๋Š” AOP ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ

ํ•  ์ผ ๋ชฉ๋ก

  • ์ปค์Šคํ…€ ์–ด๋…ธํ…Œ์ด์…˜ ์ž‘์„ฑ
  • request, response ์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•˜๋Š” AOP ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ
  • ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ž‘์„ฑ

์„ค๋ช…

  • ์„œ๋ฒ„์—์„œ ๊ด€๋ฆฌํ•ด์•ผ ํ•  ๋กœ๊ทธ๋“ค
  • Log์— ๋Œ€ํ•œ Convention์ด ์—†๋Š” ์ƒํƒœ๋กœ ๊ฐœ๋ฐœ์„ ์ง€์†ํ•  ์‹œ, ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์›์ธ์„ ํŒŒ์•…ํ•˜๊ธฐ ๋งค์šฐ ํž˜๋“ค๋‹ค๋Š” ๋ฌธ์ œ ์ธ์ง€
  • ์ตœ์†Œํ•œ request, response์— ๋Œ€ํ•œ log๋ฅผ ๊ด€๋ฆฌ๋ฅผ ํ•„์ˆ˜์ ์œผ๋กœ ํ•ด์•ผํ•˜๋ฉฐ, ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด AOP ๊ธฐ๋Šฅ ํ™œ์šฉ
    • ๋‹จ, ๋ชจ๋“  ์š”์ฒญ๊ณผ ์‘๋‹ต์— ๋Œ€ํ•ด ๋ณด์•ˆ์ด ์ค‘์š”ํ•œ ํ•ญ๋ชฉ๋“ค์€ ์•”ํ˜ธํ™”๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค.
    • ๋”ฐ๋ผ์„œ ๋กœ๊ทธ ๋ ˆ๋ฒจ์€ ๋ชจ๋‘ info๋กœ ์„ค์ •

๐Ÿ› OAuth ๊ณ„์ • ์—ฐ๋™ ์‹คํŒจ

๋ฒ„๊ทธ ๋‚ด์šฉ

  • [4-1] ๊ณ„์ • ์—ฐ๋™์—์„œ Entity๊ฐ€ ๋งคํ•‘๋˜์ง€ ์•Š์•„ OAuth ์ •๋ณด๊ฐ€ ํ…Œ์ด๋ธ”์— ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ.

๋ฒ„๊ทธ ์œ„์น˜

@Mapper
@RequiredArgsConstructor
public class UserOauthSignMapper {
    ...

    /**
     * ๊ธฐ์กด ๊ณ„์ •์ด ์กด์žฌํ•˜๋ฉด Oauth ๊ณ„์ •์„ ์ƒ์„ฑํ•˜์—ฌ ์—ฐ๋™ํ•˜๊ณ , ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒˆ๋กœ์šด ๊ณ„์ •์„ ์ƒ์„ฑํ•œ๋‹ค.
     *
     * @param request {@link SignUpReq.OauthInfo}
     */
    @Transactional
    public User saveUser(SignUpReq.OauthInfo request, Pair<Boolean, String> isSignUpUser, Provider provider, String oauthId) {
        User user;

        if (isSignUpUser.getLeft().equals(Boolean.TRUE)) {
            user = userService.readUserByUsername(isSignUpUser.getRight())
                    .orElseThrow(() -> new UserErrorException(UserErrorCode.NOT_FOUND));
            Oauth.of(provider, oauthId, user);
        } else {
            user = User.builder()
                    .username(request.username())
                    .name(request.name())
                    .phone(request.phone())
                    .role(Role.USER)
                    .profileVisibility(ProfileVisibility.PUBLIC).build();
            userService.createUser(user);
            Oauth.of(provider, oauthId, user);
        }

        return user;
    }
}
  • ์•„๋งˆ๋„ ์˜์†ํ™”๋œ User entity์—์„œ Oauth ์ •๋ณด๋ฅผ ๋งคํ•‘ํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด์„œ, OauthService.save()๋„ ํ•ด์ฃผ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋ผ๊ณ  ์ถ”์ธก

์žฌํ˜„

  • iOS ์š”์ฒญ์ด ์žˆ์–ด์•ผ ํ•ด์„œ ์žฌํ˜„์€ ๋ถˆ๊ฐ€ํ•˜์ง€๋งŒ, ํšŒ์˜๋ฅผ ํ†ตํ•ด์„œ ๋ ˆ์ฝ”๋“œ๊ฐ€ ๊ฐฑ์‹ ๋˜์ง€ ์•Š์Œ์„ ํ™•์ธ.

ํ• ์ผ

  • User entity์— List<Oauth>๋ฅผ ๊ด€๋ฆฌํ•˜์—ฌ ์—ฐ๊ด€๊ด€๊ณ„ ๋„์šฐ๋ฏธ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์ˆ˜์ •

๐Ÿ”ง Validation Check์‹œ Domain & Field ErrorCode ์ถ”๋ก  ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋…ผ์˜

As-is

ํ˜„์žฌ Pennyway WAS์˜ ์‘๋‹ต ์ฒด๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

{
   "code": "0000000", // ์ƒํƒœ(3), ์ด์œ (1), ๋„๋ฉ”์ธ(2), ํ•„๋“œ(1)
   "message": ""
}

์‚ฌ์šฉ์ž(domainCode=1)๊ฐ€ ํšŒ์›๊ฐ€์ž…์„ ์œ„ํ•ด ์ •๋ณด๋ฅผ ๋ณด๋ƒˆ๋Š”๋ฐ, ์•„์ด๋””(fieldCode=2)๊ฐ€ ๋ˆ„๋ฝ(reasonCode=0)๋˜์–ด ์—๋Ÿฌ(statusCode=422)๋ฅผ ์‘๋‹ตํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ผ ๋•Œ,
์—๋Ÿฌ ์ฝ”๋“œ๋Š” 4220012๊ฐ€ ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋งŒ์•ฝ @Valid๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Framework์— ์˜์กดํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

public class SignUpRequest {
    @NotNull(message = "์•„์ด๋””๋Š” ํ•„์ˆ˜๊ฐ’์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
    private final String username;
    ...
}

์—ฌ๊ธฐ์„œ username์ด ๋ˆ„๋ฝ๋˜๋ฉด, valid check์— ์‹คํŒจํ•˜๋ฏ€๋กœ ํ•ด๋‹น ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” Validator๋กœ ํ๋ฆ„์ด ๋„˜์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  MethodArgumentNotValidException์ด ๋ฐœ์ƒํ•˜์—ฌ @RestControllerAdvisor๋กœ ๋“ฑ๋กํ•œ ๊ณตํ†ต ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์˜ˆ์™ธ๋ฅผ ๋ฐ›๋„๋ก ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ

  • ์˜ˆ์™ธ๋ฅผ ๋ฐ›์€ ์‹œ์ ์—์„  ์–ด๋–ค ์š”์ฒญ์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜๊ฐ€ ์—†๋‹ค.
    • ๋˜‘๊ฐ™์ด MethodArgumentNotValidException๊ฐ€ ๋ฐœ์ƒํ–ˆ์ง€๋งŒ ํšŒ์›๊ฐ€์ž… ๊ณผ์ •์—์„œ ํ•„๋“œ ๋ˆ„๋ฝ์— ์˜ํ•จ์ธ์ง€, ๊ฒŒ์‹œ๋ฌผ ๋“ฑ๋ก์—์„œ ํ•„๋“œ ๋ˆ„๋ฝ์ด ๋œ ๊ฑด์ง€ ์•Œ ๋ฐฉ๋„๊ฐ€ ์—†๋‹ค.
    • MethodArgumentNotValidException ๋‚ด๋ถ€์— ์ปค์Šคํ…€ ์˜ˆ์™ธ๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ณ ๋ฏผํ•ด๋ณด์•˜์ง€๋งŒ, ํ•ด๋‹น ์˜ˆ์™ธ๋ฅผ ์ƒ์„ฑํ•ด๋‚ด๋Š” ์ œ์–ด์ž์˜ ๋กœ์ง์— ๊ด€์—ฌํ•  ๋ฐฉ๋„๊ฐ€ ์—†๋‹ค.
  • ์œ„์˜ ์ด์œ ๋กœ ์ธํ•ด DomainCode์™€ FieldCode๋ฅผ ์œ ์ถ”ํ•  ๋ฐฉ๋ฒ•์ด ์—†๋‹ค.
    • Entity์™€ Dto์˜ ํ•„๋“œ๋ฅผ ์™„์ „ํžˆ ๋™์ผํ•˜๊ฒŒ ๋งž์ถ˜๋‹ค๋ฉด, ๋ˆ„๋ฝ๋œ ํ•„๋“œ๋ช…์„ ์ฐพ์•„๋‚ผ ์ˆ˜๋Š” ์žˆ๋‹ค.
    • ํ•˜์ง€๋งŒ ๋งŒ์•ฝ valid๊ฐ€ ์‹คํŒจํ•œ ํ•„๋“œ๋ช…์ด aDomain, bDomain ๋ชจ๋‘ ์กด์žฌํ•œ๋‹ค๋ฉด ์–ด๋Š Domain์˜ FieldError์ธ์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค.

ํ˜„์žฌ ์„ ํƒํ•œ ๋ฐฉ๋ฒ•

  1. Valid check๋ฅผ ์œ„ํ•œ ์–ด๋…ธํ…Œ์ด์…˜ message์— domain ์ด๋ฆ„์„ ๋ช…์‹œํ•œ๋‹ค.
    • ex) user:์•„์ด๋””๋Š” ํ•„์ˆ˜๊ฐ’์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ „์—ญ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ•ธ๋“ค๋Ÿฌ์—์„œ :๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฌธ์ž์—ด์„ split ํ•˜์—ฌ Domain๊ณผ field๋ฅผ ์ถ”๋ก ํ•ด๋‚ธ๋‹ค.

๋ฌธ์ œ์ 

  • ๋กœ์ง์ด ๋ฌธ์ž์—ด์— ์˜์กดํ•˜๋ฉฐ, ํ”„๋กœ๊ทธ๋ž˜๋จธ์˜ ์ž‘์€ ์‹ค์ˆ˜์—๋„ ํ”„๋กœ๊ทธ๋žจ์ด ์˜ค์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • MethodArgumentTypeMismatchException๋Š” ์—ฌ์ „ํžˆ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†๋‹ค.

๋…ผ์˜ ์‚ฌํ•ญ

  • ํ•ด๋‹น ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•  ๋ฐฉ๋ฒ•์ด ์žˆ์„์ง€?
  • ํ˜น์€ ์—๋Ÿฌ ์ฝ”๋“œ ์‘๋‹ต ์ฒด๊ณ„๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•  ์ง€?

๐Ÿ› Oidc Public Key cache miss ๋Œ€์‘ ๋ฐฉ์•ˆ ํ•„์š”

๋ฒ„๊ทธ ๋‚ด์šฉ

  • Client์˜ idToken ์„œ๋ช… ๊ฒ€์ฆ ์‹œ No matching key found ์—๋Ÿฌ ๋ฐœ์ƒ

๋ฒ„๊ทธ ์œ„์น˜

    /**
     * ๊ณต๊ฐœํ‚ค๋กœ ์„œ๋ช…์„ ๊ฒ€์ฆํ•˜๋Š” ๋ฉ”์„œ๋“œ
     */
    private Jws<Claims> getOIDCTokenJws(String token, String modulus, String exponent) {
        try {
            return Jwts.parser()
                    .verifyWith(getRSAPublicKey(modulus, exponent))
                    .build()
                    .parseSignedClaims(token);
        } catch (JwtException e) {
            ...
        }
    }
  • OauthOidcProviderImpl์˜ ์„œ๋ช… ๊ฒ€์ฆ ์‹คํŒจ

์žฌํ˜„

  • Client๊ฐ€ ๋ฐœ๊ธ‰๋ฐ›์€ idToken์ด ํ•„์š”ํ•˜์—ฌ ๊ฐœ๋ณ„์ ์œผ๋กœ ์žฌํ˜„ ๋ถˆ๊ฐ€

ํ• ์ผ

  • cache miss์— ๋Œ€ํ•œ ๋Œ€์‘์ฑ… ๋งˆ๋ จ
    a. cache ttl ๊ธฐ๊ฐ„์„ ์ค„์ธ๋‹ค.
    b. cache miss๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋‹ค์‹œ Public Key๋ฅผ ์กฐํšŒํ•œ๋‹ค. โ‡พ ๊ฐ€์žฅ ํƒ€๋‹นํ•จ. ์„œ๋ช… ๊ฒ€์ฆ ์ „์— Payload๋ฅผ ๊ฒ€์ฆํ•˜๋ฏ€๋กœ, ์•…์˜์ ์ธ ๊ณต๊ฒฉ์„ ์ฐจ๋‹จํ•œ ์ƒํƒœ์—์„œ cache miss๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋ฉด ์žฌ์กฐํšŒ๋ฅผ ํ•˜๋Š” ๊ฒƒ์ด ๋งž์„ ๊ฒƒ ๊ฐ™์Œ.

๐Ÿ”ง EC2 ์„œ๋ฒ„์—์„œ AWS ๊ถŒํ•œ ์ธ์ฆ ๋ฐฉ์‹

๋…ผ์˜ ์ฃผ์ œ

  • AWS access key, refresh key ์ฃผ์ž… ๋ฐฉ์‹์— ๋Œ€ํ•ด์„œ

๋…ผ์˜ ๋‚ด์šฉ

  • ํ˜„์žฌ AWS Config ๊ถŒํ•œ ์„ค์ • ๋ฐฉ์‹์€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์ฃผ์ž…ํ•˜์—ฌ ์ธ์ฆํ•จ.
@Getter
@Configuration
public class AwsSnsConfig {
    private final String accessKey;
    private final String secretKey;
    private final String region;

    public AwsSnsConfig(
            @Value("${spring.cloud.aws.sns.credentials.access-key}") String accessKey,
            @Value("${spring.cloud.aws.sns.credentials.secret-key}") String secretKey,
            @Value("${spring.cloud.aws.sns.region.static}") String region
    ) {
        this.accessKey = accessKey;
        this.secretKey = secretKey;
        this.region = region;
    }

    @Bean
    public AwsCredentials awsSnsCredentials() {
        return AwsBasicCredentials.create(accessKey, secretKey);
    }

    ...
}
  • ํ•˜์ง€๋งŒ AWS ๊ถŒ๊ณ  ์‚ฌํ•ญ์— ๋”ฐ๋ฅด๋ฉด EC2 ์„œ๋ฒ„์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ธ์ฆ์„ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
@Configuration
public class AwsConfiguration {
    @Value("${cloud.aws.credentials.access-key}")
    private String awsAccessKey;

    @Value("${cloud.aws.credentials.secret-key}")
    private String awsSecretKey;

    @Value("${cloud.aws.region.static}")
    private String region;

    @Value("${spring.profiles.active:}")
    private String activeProfile;

    @Bean
    public AmazonSNSClient amazonSNSClient(Environment environment ) {
        if(StringUtils.equals(activeProfile , "")){
            return (AmazonSNSClient) AmazonSNSClientBuilder
                    .standard()
                    .withRegion(region)
                    .withCredentials(InstanceProfileCredentialsProvider.getInstance())
                    .build();
        }else{
            return (AmazonSNSClient) AmazonSNSClientBuilder
                    .standard()
                    .withRegion(region)
                    .withCredentials(new AWSStaticCredentialsProvider(
                            new BasicAWSCredentials(environment.getProperty("cloud.aws.credentials.access-key"), environment.getProperty("cloud.aws.credentials.secret-key"))))
                    .build();
        }
    }
}

๋”ฐ๋ผ์„œ ์ถ”ํ›„ ์œ„์˜ ๋ฐฉ์‹๋Œ€๋กœ ๋ณ€๊ฒฝํ•ด๋ณด๊ณ ์ž ํ•˜๋Š”๋ฐ, ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹œ๋‚˜์š”?

๐Ÿ› ๋ฏธ์ธ์ฆ ์‚ฌ์šฉ์ž ์†Œ์…œ ๋กœ๊ทธ์ธ/ํšŒ์›๊ฐ€์ž… soft delete ์ •์ฑ… ๋ฐ˜์˜ ์—ฌ๋ถ€ ๊ฒ€์‚ฌ

๋ฒ„๊ทธ ๋‚ด์šฉ

  • #67 ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ์†Œ์…œ ๊ณ„์ • ์—ฐ๋™์—์„œ ๋ฐœ๊ฒฌํ•œ Soft Delete ์ •์ฑ…์ด ๋ฐ˜์˜๋˜๊ณ  ์žˆ๋Š”์ง€ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋กœ ๊ฒ€ํ† 

๋ฒ„๊ทธ ์œ„์น˜

  • ์•„์ง ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ง€ ์•Œ ์ˆ˜ ์—†์Œ.

์žฌํ˜„

  • ์—†์Œ

ํ• ์ผ

  • OauthController์™€ ๊ด€๋ จ๋œ UseCase์— ๋Œ€ํ•œ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ž‘์„ฑ
  • ํ•„์š” ์‹œ, Soft Delete ์ •์ฑ…์„ ๋ฐ˜์˜ํ•˜์—ฌ ๋กœ์ง ๊ฐœ์„  ํ•„์š”
  • (LoC๊ฐ€ ์ƒ๊ฐ๋ณด๋‹ค ๋งŽ์ง€ ์•Š์œผ๋ฉด idToken์˜ oauth_id ๊ฒ€์‚ฌ ํ•ญ๋ชฉ์„ OauthOidcHelper๋กœ ๋„ฃ์–ด๋ฒ„๋ฆด ์˜ˆ์ •...ใ…Ž)

โœ๏ธ Device Token ๊ด€๋ฆฌ ์ •์ฑ…๊ณผ API ์„ค๊ณ„์—์„œ ์˜ˆ์™ธ ์‹œ๋‚˜๋ฆฌ์˜ค ๊ฒ€ํ† 

์ด์Šˆ ์ฃผ์ œ

  • Device API์—์„œ ์˜ˆ์™ธ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋Œ€ํ•œ ๋Œ€์‘ ๋ฐฉํ–ฅ ๋ชจ์ƒ‰

์ด์Šˆ ์„ค๋ช…

  • FCM์—์„œ ๊ถŒ์žฅํ•˜๋Š” Device Token ๊ด€๋ฆฌ ์ •์ฑ…์„ ์ค€์ˆ˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ถ”ํ›„ BE์—์„œ ์Šค์ผ€์ค„๋ง์„ ํ†ตํ•œ ๊ด€๋ฆฌ๋ฅผ ์ง„ํ–‰ํ•  ์˜ˆ์ •.
  • ํ˜„์žฌ ๋ฐฉ์‹์—์„œ 2๊ฐ€์ง€ ๋ฌธ์ œ์ ์ด ์กด์žฌํ•จ.
  1. Device Token์„ ๊ฐฑ์‹ ํ•  ๋•Œ ์‚ฌ์šฉ์ž Device ์ •๋ณด๋„ ํ•จ๊ป˜ ๋ฐ›์Œ.
    • ์‚ฌ์šฉ์ž์˜ os๊ฐ€ ๋ณ€๊ฒฝ๋  ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, device token ์ •๋ณด๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์Œ์—๋„ updated_at ํ•„๋“œ๊ฐ€ ๊ฐฑ์‹ ๋˜๋Š” ์ด์Šˆ
  2. Client์™€ Server๊ฐ€ ๋ณ„๋„์˜ ์ •์ฑ…์œผ๋กœ ํ† ํฐ์„ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ์Œ.
    • Server๋Š” Client๊ฐ€ ์ƒˆ๋กœ์šด ํ† ํฐ ๋“ฑ๋ก๊ณผ ํ† ํฐ ๊ฐฑ์‹ ์— ๋”ฐ๋ผ ์˜ฌ๋ฐ”๋ฅธ ์š”์ฒญ์„ ๋ณด๋‚ผ ๊ฒƒ์ด๋ผ ๊ธฐ๋Œ€ํ•จ.
    • ํ•˜์ง€๋งŒ ์‚ฌ์šฉ์ž๊ฐ€ App ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•˜๋Š” ๊ฒฝ์šฐ, Client๋Š” ์ƒˆ๋กœ์šด ํ† ํฐ ๋“ฑ๋ก์œผ๋กœ ๋ณด๋‚ด๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•จ.
    • ํ† ํฐ์ด ๊ฐฑ์‹ ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด Server๊ฐ€ ํ•ธ๋“ค๋งํ•˜๊ณ  ์žˆ์ง€๋งŒ, App ๋ฐ์ดํ„ฐ๊ฐ€ ์ œ๊ฑฐ๋œ ํ›„ FCM ํ† ํฐ๊นŒ์ง€ ์žฌ๋ฐœ๊ธ‰๋˜๋Š” ๊ฒฝ์šฐ ์“ฐ๋ ˆ๊ธฐ ๋ฐ์ดํ„ฐ๊ฐ€ ์ง€์†์ ์œผ๋กœ ์Œ“์ด๊ฒŒ ๋จ.
    • ํ˜„์žฌ ์ •์ฑ…์œผ๋กœ๋Š” ์“ฐ๋ ˆ๊ธฐ ๋ฐ์ดํ„ฐ๋ผ๊ณ  ํŒ๋‹จํ•˜๊ณ  ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋Š” ๊ทผ๊ฑฐ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Œ.

ํ•  ์ผ ๋ชฉ๋ก

  • Device ์ •๋ณด์™€ DeviceToken ํ…Œ์ด๋ธ” ๋ถ„๋ฆฌ ์—ฌ๋ถ€ ๋…ผ์˜
  • ์ง€์†์ ์œผ๋กœ ์Œ“์ด๋Š” ์“ฐ๋ ˆ๊ธฐ ๋ฐ์ดํ„ฐ์˜ ์ฒ˜๋ฆฌ ์ •์ฑ… ๋…ผ์˜

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.