Coder Social home page Coder Social logo

hello_developer's Introduction

[ Hello Developer ] 개발자를 위한 커뮤니티 서비스

Nest

웹개발에 있어 개발 사이클의 전반적인 흐름을 경험하기 위해 진행한 개인 프로젝트 입니다.

기획, 디자인부터 운영과 배포까지 있어 전체적인 개발기간은 2022.02 ~ 2022.04 입니다.

모바일에서도 사용이 가능하도록 모바일 반응형 디자인을 구현했습니다.

실제 서비스는 헬로디벨로퍼 에서 사용이 가능합니다.


🎨 Enviroment

에디터

  • Visual Studio Code
  • DBeaver
  • Mysql Workbench

디자인

  • Figma

ETC

  • Notion
  • Slack

🔨 Tech Skills

🖥 백엔드

언어 / 프레임워크

  • Typescript
  • Nestjs

데이터베이스

  • Mysql + TypeORM

인프라

  • AWS EC2
  • AWS S3
  • AWS ACM
  • AWS Route53
  • AWS ELB(ALB)
  • AWS RDS
  • AWS ECR
  • Docker

인증

  • Passport.js
  • JWT

💻 프론트엔드

언어 / 라이브러리

  • Typescript
  • React

상태관리

  • Recoil

디자인

  • Styled-components

인프라

  • AWS S3
  • AWS CloudFront
  • AWS Route53

🔑 ETC

  • CI/CD : Github Actions
  • Markdown Editor/Viewer : Toast UI Editor

✍Database E-R Diagram



⚙ Module Structure

루트 모듈인 Application모듈을 기준으로 총 3개의 메인모듈이 존재합니다.

  • Auth : 인증(로그인, 회원가입, 토큰 등) 관련 모듈
  • Boards : 게시글(작성, 삭제 등) 관련 모듈
  • User: 사용자(프로필, 활동내역 등) 관련 모듈

하위 모듈의 경우 Global이 아닌 상위모듈에서 필요에 의하여 사용합니다.

graph TD;
    APP-->Auth;
    APP-->Boards;
    APP-->Users;
		Auth-->Email
		Auth-->Util
		Boards-->Util
		Boards-->AWS
    Boards-->Comments;
		Users-->AWS
Loading


🌐 System Architecture

배포 방식

EC2에서 Docker를 활용하여 배포하였습니다.

AWS ACM에서 발급받은 SSL인증서를 사용하여 ELB(ALB)를 통해 HTTPS를 적용했습니다.

배포과정은 아래 블로그에 정리했습니다.


CI/CD

Github Actions를 사용하여 Docker Image를 빌드하고 ECR에 업로드 합니다.

EC2에서는 ECR에 업로드된 이미지를 받아오고 Docker Image를 실행하여 배포합니다.

CI/CD 구축과정은 아래 블로그에 정리했습니다.

배포 방식

S3의 정적 웹 호스팅을 사용하여 CloudFront로 배포했습니다.

AWS ACM에서 SSL인증서를 발급받아 HTTPS를 적용했습니다.

배포과정은 아래 블로그에 정리했습니다.

CI/CD

Github Actions를 사용하여 리액트 프로젝트 빌드이후 S3에 업로드됩니다.

S3의 변경사항이 바로 적용될 수 있도록 CloudFront에서 Invalidate Cache를 적용했습니다.

CI/CD 구축과정은 아래 블로그에 정리했습니다.



✔ Test

Unit Test

각 API의 Controller와 Service 레이어에 대한 90개의 유닛테스트 케이스를 작성했습니다.

상위 레이어에 의존하는 로직의 경우 테스트의 격리를 위하여 Mocking 처리했습니다.

유닛테스트의 경우 Auth, User 등과 같이 모듈별로 폴더에 존재합니다.



E2E Test

모든 API에 대한 65개의 E2E 테스트 케이스를 작성했습니다.

테스트시간을 줄기이 위하여 실제 DB가 아닌 인-메모리 DB인 SQLite를 사용했습니다.

E2E 테스트의 경우 루트폴더 하위 test 폴더에 존재합니다.



📜 API Docs with Swagger

Restful API의 문서를 자동으로 구성해주는 Swagger 프레임워크를 사용해서 작성했습니다.

API 문서 URL : Hello Developer API Docs.

사용자 접근을 방지하기 위해 로그인계정을 설정했습니다. admin / 1234




📘 Logging with Sentry, Slack

서버에서 치명적인 500대의 HTTP 에러가 발생한경우에 로깅하도록 처리했습니다.

Sentry 내부에 상세 로그를 저장



에러 발생시 바로 확인이 가능하도록 Slack으로 메세지 푸쉬기능 구현



❗ 해결했던 문제들...

이미지 업로드 최적화하기

에디터를 통해 이미지 업로드 및 DB에 저장시 아래와 같은 상황이 발생했습니다.

  • 마크다운 에디터에서 이미지 삽입시 인코딩되어 본문의 길이가 길어지는 상황
  • 약 4kb의 이미지 삽입시 약 5100자의 문자열이 삽입
  • 본문의 길이가 늘어날수록 DB에서 차지하는 공간이 커지게되며, 삽입/삭제 등 데이터의 크기가 늘어날수록 더 많은양의 네트워크 트래픽을 요구

이미지 업로드 이벤트를 커스텀하여 AWS S3에 업로드 및 이미지 URL을 반환하여 업로드를 최적화 했습니다.

해결과정은 Tistory 블로그에 정리했습니다.

이미지 업로드시 게시글 ID 생성관련 이슈

기존 게시글을 작성하는 DB Column 생성시 UUID 형식의 랜덤한 게시글 ID가 생성되는 형식
하지만 이미지 업로드시에 게시글이 DB에 저장되는 시점보다 이전에 업로드 이벤트가 발생

위와 같은 문제점을 아래와 같이 방법으로 개선하였습니다.

  • 게시글 생성시 클라이언트에서 임시 게시글 ID 생성
  • 임시 게시글 ID를 기준으로 S3에 /temp-board-id/image.png 형식으로 업로드
  • 게시글이 저장되는 시점에 게시글 DTO에 UUID 문자열을 ID로 추가
  • 게시글이 저장되는 동시에 S3에 존재하는 temp-board-id를 실제 게시글 ID로 치환
sequenceDiagram
  participant Client
  participant Server
  participant AWS
  Client->>Server: Image Upload Req
  Server->>AWS: Image Upload in S3
  Server->>Client: Return Image URL
  Client->>Server: Save Board Req
  Server->>AWS: Change Folder Name
Loading

회원가입시 이메일 인증 구현하기

nodemailer + gmail을 사용하여 이메일 인증을 구현중 아래 문제가 발생했습니다.

  • 2022.05.30 이후 OAuth2.0 미사용시 Gmail API 사용 불가
  • 공식문서에서는 OAuth 사용방법과 관련된 자세한 방법이 나와있지 않았음

위 제약사항으로 인해 Gmail API의 OAuth와 nodemailer를 사용하여 인증메일 발송기능을 구현했습니다.

해결과정은 Tistory 블로그에 정리했습니다.

JWT Access Token의 짧은 수명으로 인한 유저의 불편한 경험개선

기본적으로 Access Token의 경우 localStorage등 클라이언트(브라우저)의 저장공간에서 보관합니다.
이에 따라서 수명이 길면 탈취당했을때 문제가 발생할 수 있습니다.
JWT Refresh Token을 활용하여 유저의 사용경험이 불편하지 않도록 개선했습니다.

  • 토큰의 유효시간의 경우 Access Token은 15분, Refresh Token은 10일로 지정
  • Refresh Token은 httpOnly, Secure 옵션으로 쿠키에 저장
  • 서버에서 401 Unauthorized 에러 반환시 Refresh Token을 활용한 재요청 및 Access Token 재발급
res.cookie('refreshToken', refreshToken, { httpOnly: true, path: '/', secure: true });


조회수 증가 API의 반복적인 호출 문제해결

게시글 상세보기를 누르게되면 조회수를 증가하기 위해 API를 호출하게 됩니다.
이때 이미 조회한 게시물도 계속 API 호출이 들어오게 됩니다.
사용자가 악의적으로 새로고침 테러를 하는것을 방지하기 위해 쿠키를 설정하여 해결했습니다.

  • 게시글 상세보기 페이지 접속시 24시간동안 유지되는 쿠키 생성
  • 게시글 상세보기 페이지 접속시 쿠키 여부에 따라 조회수 호출여부 결정



🚫 개선 및 구현이 필요한 문제들

많은 양의 게시글 로딩시 데이터를 한번에 렌더링하는 문제

게시글 목록 또는 검색기능 사용시 DB에 존재하는 모든 데이터를 한번에 응답받습니다.
약 1000개의 데이터가 존재할 경우 렌더링시 매우 버벅이게 되며 유저에게는 안좋은 경험으로 와닿습니다.

현재 생각중인 해결방안은 아래와 같습니다.

  • 클라이언트 : 무한스크롤을 구현하여 특정 시점에 서버에 데이터 요청
  • 서버 : 쿼리스트링을 통해 반환할 데이터의 범위를 받고, 데이터베이스 측에서 필터링을 통해 데이터 반환

Swagger 문서 데이터로 인해 길어지는 코드

현재는 Controller에 데코레이터를 사용하여 문서에 필요한 내용을 정의해둔 상태입니다

하지만 데코레이터 내부에 모든 내용을 정의할 경우 아래와 같이 코드가 매우 길어지게 됩니다.

  @ApiOperation({ summary: '회원가입 API' })
  @ApiCreatedResponse({
    description: `회원가입 성공시 201 코드와 생성된 사용자의 아이디 반환`,
    schema: {
      type: 'object',
      properties: { userId: { type: 'string' } },
    },
  })
  @ApiBadRequestResponse({
    description: `
      이메일 형식이 올바르지 않을경우 - invalid_email
      비밀번호 형식이 올바르지 않을경우 - invalid_password
      닉네임 형식이 올바르지 않을경우 - invalid_nickname
      중복된 이메일인 경우 - exist_email
      중복된 닉네임인 경우 - exist_nickname`,
    schema: {
      type: 'object',
      properties: {
        statusCode: { type: 'number' },
        message: {
          example: 'invalid_email, invalid_password, invalid_nickname, exist_email, exist_nickname',
        },
      },
    },
  })
  @UsePipes(ValidationPipe)
  @Post('register')
  async register(@Body() registerDto: RegisterDto) {
    const userId = await this.authService.register(registerDto);
    return { userId };
  }

Swagger 문서에 필요한 내용은 외부파일로 분리하여 코드를 개선할 예정입니다.


23.04.28 - 모듈 내 module.swagger.ts 생성 및 applyDecorator를 사용하여 분리완료

  @ApiRegister('회원가입 API')
  @UsePipes(ValidationPipe)
  @Post('register')
  async register(@Body() registerDto: RegisterDto) {
    const userId = await this.authService.register(registerDto);
    return { userId };
  }


처음 도입하고 경험한 기술과 개념들이 들이 매우 많았습니다.
TDD 부터 시작해서 CI/CD, AWS, 새로운 프레임워크/라이브러리 등..
새로운걸 배울때마다 계속해서 기록하고 꾸준하게 노력했습니다.
처음 마주하는 문제더라도 꾸준히 노력하면 해결할수 있다는 자신감을 얻을 수 있었습니다.

hello_developer's People

Contributors

imkdw avatar

Stargazers

Claudianus Mamertus avatar Suha Son avatar monkeyKing avatar Seungsoo Choi avatar  avatar  avatar  avatar  avatar Pearlii avatar songdoeon avatar lango avatar KANGUK LEE avatar jay.prog avatar 임경석 avatar Dongdong avatar  avatar Hayden Lee avatar Gukin Han avatar 문용균 avatar Hyeon Young Jang avatar Choco Ham avatar  avatar Parkjoontae avatar EJ avatar  avatar LeeJISeop avatar  avatar  avatar  avatar jw avatar Dev.SoNB avatar  avatar Kyoungchan Cho avatar Kim JaeGwang avatar pienk avatar JangHyeok Moon avatar  avatar  avatar 이찬호 avatar

Watchers

 avatar

Forkers

sw5614 senspond20

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.