본문 바로가기
개발공부일지/Project

Project - React 를 사용한 SPA 홈페이지 구축

by Hynn1429 2023. 4. 17.
반응형

안녕하세요

Hynn 입니다.

 

오랜만에 작성하는 블로그 게시물이 되었습니다.

지난 기간동안, 개인적 학습결과물을 이용해, React 를 이용한 SPA 홈페이지 구축을 프로젝트로 진행했습니다.

 

3인에서 진행하는 프로젝트였고, 다양한 API 와 Library 및 배포환경에 대한 공부를 하면서 진행했습니다.

프로젝트에서 구현하고자 한 점은, OTT 서비스의 대한 쉽게 볼 수 있는 요금제와 각 특징, Youtube 의 경우, 해외 요금제와 원화를 비교하여, 현재 각 국가별 환율을 적용하여 일자별로 비교할 수 있는 서비스, 다인사용이 가능한 요금제의 경우, 쉐어를 할 수 있는 모집 게시판을 간단하게 구축하고자 했습니다.

간략하게 소개하고, 어떠한 점들을 중점적으로 다루었는지 작성해보도록 하겠습니다.

 

 

===========

 

===========

 

개발단계에서 제가 고려한 사항은 3가지 사항을 중점적으로 고려했습니다.

 

1. 실제 배포에서도 문제가 없도록 개발환경과 배포환경의 동일화

2. 실제 서비스에서 적용될 수 있는 서버 흐름

3. 실사용에 대한 고려

 

이러한 사항을 중점적으로 고려하고 작성을 했습니다.

주로 저는 Backend, Front Support 를 담당하고, 팀 내에서 배포를 담당하고 진행을 하였습니다.

 

이러한 구성요소를 고려하여 작성했을때, 가장 처음에 중요하게 생각한 점은 개발환경에서도 "HTTPS" 를 적용하는 것이였습니다.

실제 배포에서 사용한 AWS EC2 Instance 에서는 Nginx 를 사용해 Reverse-Proxy 로 처리하여 HTTPS 를 적용했습니다.

이러한 경우, 실제 로그인 구현이라던지, Token, Session 에서 실제 배포환경과의 차이가 존재하기 때문에, 로컬에서도 OpenSSL 을 이용해 Https 를 사용해 구성했습니다.

 

두번째로, 실제 서비스를 고려하고 작성을 해보니, 각각의 Front, Backend, DB, File Server 를 분리하게 되었습니다.

그렇게 하기 위해서 AWS 에서 서버 구성을 4개의 서버를 이용했습니다.

  • 이러한 구현을 고려할 때, 실제 서비스에 처리되는 연산, 로직은 모두 Backend 에서 처리하고, API 와의 통신, File Server 등과 통신해야 하기 때문에, 결과적으로 Front 는 Backend 와 통신 후 화면을 그에 맞추어 Rendering 하는 측면으로만 구성을 했습니다.

 

따라서, Backend 가 가장 중요한 위치에 있다고 볼 수 있겠습니다.

이러한 구성요소에 맞추어 작성을 하는데 초점을 두었습니다.

 

마지막으로 실 사용에 대한 처리를 위해, 실제 AWS, RDS 와 같은 상용 서비스를 직접 이용해보고, 이를 개발환경에서는 로컬에서, 실제 환경에서는 이러한 서버들에서 독립적으로 구동되는 구현을 위해 처리를 했습니다.

그러다 보니, Dotenv 를 사용한 환경변수 등에 대한 고려를 많이 했습니다.

 

 

코드를 작성할 때, Backend 를 처음 구성부터 담당했기 때문에, Directory 구조에 대해서 근본적으로 고민하고 이를 최대한 유지보수하기 쉬운 형태로 작성하고 싶었습니다.

따라서, 형태를 아래와 같이 작성했습니다.

 

  • bulkdata
  • lib
  • middleware
  • routes
  • src
  • app.js
  • config.js
  • server.js

큰 틀에서는 위와 같이 고려하고 구성을 했습니다.

 

1. Bulkdata - 폴더명 정의 대로, 덤프 데이터베이스 및 번들 데이터를 각 구성요소별로 구분하여 처리합니다. 이 곳에서는 테이블 별 기초적으로 필요한 데이터를 정의하였습니다. 예를 들자면, 기존의 환율, 각 요금제 및 Platform 의 대한 정보나, 테스트를 위한 Bulkdata 가 이곳에 포함되었습니다.

 

2. Lib - 공통으로 사용되는 Utility Function, Library 를 작성했습니다.

 

3. middleware - Express 에서 사용하는 미들웨어 함수를 정의하는 디렉토리로 사용했습니다.

 

4. routes - SRC 에서 각 엔드포인트 별 Route 를 통합하고, 각 라우트를 정의하는 디렉토리 입니다.

 

5. SRC - 실제 클라이언트 사이드의 코드를 저장하는 디렉토리로 사용했습니다

 

6. App.js - Express 의 설정을 정의하는 파일입니다.

 

7. dotEnv 및 데이터베이스 연결등을 담당합니다.

 

8. server.js - 실제 서버를 구동하는 파일로 구성하였습니다.

 

 

 

실제 코드에서는 학습을 별도로 하여, 구성한 코드 위주로 몇가지 소개해드리고자 합니다.

 

1) Http & Https 구성

 

환경변수를 최대한 활용해야했고, 로컬에서 작성한 코드를 배포환경에서 가져올 때, 최소한의 수정, 즉 환경변수 설정만으로, 완벽히 구동되게 처리를 하는게 목표였습니다.

그러다 보니, 단순히 Http, Https 를 구성하는 코드에서도 각각 작성을 했어야 했고, 환경변수의 조건만으로, 유동적으로 변경되도록 조건문을 설정하였습니다.

 

아래의 코드 구성을 살펴보도록 하겠습니다.

 

const https = require('https')
const http = require('http')

먼저, NodeJS 의 기본 모듈로 지원하는 http, https 를 선언합니다. 이를 이용해, 환경변수의 값에 따른 조건을 부여하였습니다.

const useHttps = process.env.USE_HTTPS === 'true'

if (useHttps) {
  const privateKey = fs.readFileSync('key.pem', 'utf8')
  const certificate = fs.readFileSync('cert.pem', 'utf8')
  const credentials = { key: privateKey, cert: certificate }
  const httpsServer = https.createServer(credentials, app)
  httpsServer.listen(httpsport, () => {
    console.log(`HTTPS server is running on port ${httpsport}`)
  })
} else {
  const httpServer = http.createServer(app)
  httpServer.listen(httpport, () => {
    console.log(`HTTP server is running on port ${httpport}`)
  })
}

 

위의 코드를 살펴보면, 먼저 OpenSSL 을 사용해 생성한 로컬 인증서를 올바르게 처리하기 위해 fs 모듈을 추가로 사용하여, 위와 같이 지정하였습니다.

즉 dotenv 를 사용하여 처리하는 환경변수를 이용해 "USE_HTTPS" 의 값이 True,false 에 따른 어떠한 모드로 실행될지에 대한 정의를 구성했습니다.

 

즉, 배포환경에서는 http로 실행 후 Nginx 에 의해 Reverse-proxy 로 https 로 처리되고, 로컬환경에서는 https 로 구성이 되도록 환경변수 하나만으로 손쉽게 어떠한 서버가 실행될 지에 대한 구성을 처리한 것으로 이해하시면 되겠습니다.

 

2) Exchange (환율) API 처리하기

 

환율정보는 처음에는 통계은행의 환율정보를 사용하려고 했지만, 고려사항에 따라, API Layer 의 환율정보 API 를 사용하였습니다.

통계은행에서 제공하는 환율정보는, 대원화환율의 모든 국가를 제공하고 있습니다.

일반적으로 환율을 전체적으로 처리하기에는 통계은행의 환율이 가장 적합하다고 할 수 있습니다.

하지만 이 프로젝트에서 필요한 환율정보는 특정국가의 환율이 필요하고, 더 적게는 5개의 국가만을 특정하기 때문에, 이를 좀더 쉽게 데이터를 가져올 수 있는 API 를 원했습니다.

 

또한 뒤에서 소개할 API 와, APILayer 의 API 는 HTTPS 환경을 강력히 권장하거나, 필수요소이기 때문에, 개발단계에서부터 불가피하게 Https 를 적용했어야 했습니다. 특히나 이후에 다루게 될 SENS 는 http 환경에서는 올바른 구동이 되지 않았었습니다.

 

하지만 이를 이용할때 코드 작성에서는, 일반적인 API 사용이 아닌, 특정 국가의 리스트, 일자별 환율을 적용했어야 했습니다.
따라서, 환율 정보는 아래와 같이 파일을 구성하여, 유지보수나, 이후에 국가가 추가되거나 변경될 때 보다 손쉽게 코드를 적용할 수 있도록 처리했습니다.

 

  • Countrylist
  • DefineData
  • Function
  • Header
  • Repository
  • run

즉, 필요한 국가의 목록은 CountryList 에서 객체로 정의합니다. 

그리고 Definedata 는 최초에 필요한 날짜, 여기서는 오늘날짜로부터 한달 전 날짜의 배열을 생성하고, 이를 내보내 필요한 날짜를 최초에 설정합니다.

그리고 Header 에서는 API 에서 요구하는 Header 의 정보를 정의합니다.

그리고 Function 에서 API 요청하여 응답을 받은 뒤, 데이터베이스에 저장할 수 있도록 함수를 내보냅니다. 그리고 난뒤 Repository 에서 환율정보를 저장합니다.

마지막으로, run 에서는 NodeJS 에서 사용할 수 있는 라이브러리인 Node-Schedule 을 활용해, 매일 9시 30분에 환율정보를 업데이트 하도록 처리했습니다.

 

즉 최초에 구동되어, 환율정보를 가져오면, 매일 9시30분에 환율의 최신정보를 업데이트 하도록 작성했습니다.

 

3) SENS 사용

 

이 API 는 사용에서 다소 애를 먹었습니다.

SENS의 경우, 네이버 클라우드에서 제공하는 API 중 하나로, SMS를 발송하는 API 입니다.

일반적으로 회원가입을 위한 API 는 아니였기 때문에, 실제 회원가입에서 이를 활용하기 위해 주어진 기능을 이용해서 몇가지 기능을 조합하여, 동작하도록  처리했습니다.

 

먼저 이 API 의 경우, 실제 사용자의 전화번호가 들어가기 때문에, 동작자체가 HTTPS 에서 구현이 되어, 로컬에서 HTTPS 를 사용한 주요 이유중 하나였습니다.

또한, 문자 전송을 한 뒤, 실제 문자내용을 확인하기 위해서는 발송이 되었을때, RequestedID, 그리고 이를 이용해 MessageID를 서버에서 가져오고, 이 MessageID 를 이용해 메시지 본문의 내용을 비교할 수 있었습니다.

그래서 라우터 포인트에서 이를 각각 처리하는 4개의 메서드로 구분하였습니다.

 

즉, 작성 구조상, 사용자가 전화번호를 입력 후, 인증번호 발송을 누르면 Math.floor 를 사용해 인증번호를 무작위로 생성하도록 구성하고, Mesage 내용에 인증번호를  "[ ] "에 감싸서 발송되도록 처리했습니다. 이는 이후에 메시지 본문에서 인증번호를 쉽게 정규식으로 가져오기 위함을 처리해둔 것입니다.

 

그리고 인증번호가 전송되면, 응답코드에 포함된 ReqeustID 를 사용해 messageID 를 확인하고, 곧바로 MessageContent 를 확인하는 로직이 실행되고, 이를 이용해 사용자가 입력한 인증번호와, 실제 전송된 인증번호를 비교하여, 일치하지 않을 경우 회원가입이 처리되지 않는 로직을 구현하였습니다.

 

4) AWS S3 사용하기

 

AWS 사용을 처리할 때 가장 처리가 힘들었습니다.

프로젝트를 시작하는 시점에 AWS-SDK 의 버전이 변경되어, Version2 의 대한 일부 기능이 동작하지 않았던 상황이 있었습니다.

즉, 변경된 버전에 맞추어 코드를 구성해야 했고, 검색으로 최신버전의 대한 환경이나 예제코드를 찾는데 시간이 다수 소요되었습니다.

 

RDS 와 S3를 사용할때, 가장 중점적으로 고려하고 구성한 점은, 작성자가 허용한 IAM 사용자가 아닐 경우, 디렉토리를 알더라도, 실제 파일을 불러올 수 없도록 보안규칙을 설정하였던 점입니다.

하지만 보안그룹을 Fully-Access 로 구성하여도, RDS 와 AWS S3 에 액세스가 간헐적으로 되지 않는 문제가 있었습니다.

 

결과적으로 확인한 문제는, AWS 의 보안그룹이 동일하게 설정되더라도, 각 보안그룹의 Priority 가 다르게 적용되는 것을 알 수 있었습니다.

이번 프로젝트가 종료되고 나서, 주말에 시간을 내어 AWS 보안그룹을 이해하는 기초사항에 대해서는 추가로 학습을 할 예정입니다만, 같은 보안그룹이 적용되더라도, 우선순위에 따라 적용이 되지 않는 문제, 즉 모두 허용으로 하더라도, 일부 충돌사항이 발생하면 우선순위가 높은 보안그룹이 우선적용되면서, 의도한 대로 동작하지 않는 문제가 발생될 수 있다는 점을 알게 되었습니다.

 

두번째로, AWS S3 의 컨텐츠의 이미지URL을 사용해 랜더링 시, 이를 일반적인 GET 으로만 처리할 경우, 파일을 다운로드 하는 형태로 동작이 되었습니다. 이 경우에는, 단순히 파일의 경로를 RDS 에 저장하고, 이를 GET으로 가져오는 것이 아니라, "SignedURL" 로 처리해야 하는 과정이 필요함을 알게 되었습니다.

 

이를 처리하기 위해, 각 이미지파일은 업로드시, S3 의 Directory 경로를 RDS 에 저장하고, 저장된 경로를 활용해 SignedURL 을 생성하여, Front-end 에 전달하는 로직을 구성하였습니다. 당연히 File-upload 에 사용된 Multer d역시 multer-s3 를 같이 사용하여 구성했습니다. 

 

5) 배포 환경 자동화 구성

 

Github Actions 가 보다 자동화에 도움이 되는 것은 사실이지만, 불완전하게 Docker 를 다루고 싶진 않았습니다.

따라서 현재 제가 가진 Skill 을 활용할 수 있는 방안에 대해서 고민했고, Shell-Script & Crontab 을 이용해, 일정시간마다 Shell-Script 을 실행하고, 이 스크립트에서 조건에 따라, 스크립트를 수행하도록 처리하였습니다.

실제 스크립트 작성된 것은 아래와 같이 작성했습니다.

즉, 이 파일이 실행될 때, github repository 에서 pull 을 가져오고, 최신이 아닐 경우, Front 와 backend 에서 지정된 명령을 순차로 처리하도록 구성했습니다.

더블어 백앤드의 경우, server.js 가 실행된 상태에서는 작동이 되지 않기때문에, PM2 를 추가로 활용하여, background 에서 동작하도록 구성했습니다.

 

그리고 난뒤, 실제 서버의 nginx의 재시작까지 포함하도록 처리하면 되겠습니다.

이제 Crontab 에서 파일들의 자동 실행 시간을 지정하면 작성이 마무리 됩니다.

다음 프로젝트에서는 Github-Actions 를 활용해 자동화를 조금 더 스마트하게 구성할 계획입니다.

 

기존에 진행한 프로젝트보다, 조금 더 실제사용이라는 가정하에 작성한 프로젝트이다 보니, 부족한점이 많았습니다.

코드를 보다 나뉘어 작성함으로서, 유지보수 측면이나, 코드의 가독성 측면을 신경을 많이 쓰지 못했고, 이로 인한 유지보수측면에서의 불안한 점이 존재했다고 생각합니다.

 

이후 프로젝트에서는 이러한 유지보수측면, 코드의 재사용이 더 손쉽게 처리함으로서, 효율적인 코드 작성이 될 수 있도록 공부를 더 많이 해야하겠습니다.

 

실제 홈페이지의 화면을 간단하게 소개하고, 마무리하도록 하겠습니다.

 

감사합니다.

 

 

 

 

반응형

'개발공부일지 > Project' 카테고리의 다른 글

Small Project 1 - 로그인/게시판 기능 구현  (0) 2023.01.04

댓글