나만의 수야, 수호 만들기 회고
나만의 수야, 수호 만들기 회고
나만의 수야 수호 만들기?
다사다난하던 1학기가 끝나고, 모든 인턴에 떨어진 저는 시간적으로 여유가 생겼습니다.
무엇을 할 지 고민하다 이전에 틀만 만들어두었던 프로젝트를 고도화하기로 결정하였습니다.
그 프로젝트는 나만의 수야 수호 만들기 라는 프로젝트입니다.
나만의 수야 수호 만들기는 삼육대학교의 마스코트인 수야와 수호를 꾸밀 수 있는 프로그램입니다.
아이디어는 개발진스 라는 프로젝트를 모티브로 시작되었습니다.
기존의 형태는 캐릭터인 수야, 수호를 선택하고 , 그 위에 단색 펜으로 그림을 그리는 구조였습니다.

어떻게 고도화 할 것인가?
지금의 프로젝트는 단순한 정적 페이지이기 때문에 vercel을 통해 호스팅되고 있습니다.
프로젝트에 백엔드를 추가하고 같은 도메인에서 프론트엔드와 백엔드를 함께 배포할 것입니다.
왜 같은 도메인에 배포하나요?
백엔드는 nest 에 postgres,redis 를 연결하여 RESTAPI 서버로 사용합니다.
사용자가 그린 그림을 서버에 저장하도록 할 것이므로 유저 인증 기능이 필요합니다.
이때 유저의 인증과정에서 세션 방식을 채택하였는데 그 이유는 다음과 같습니다.
지금까지의 다른 팀 프로젝트에서는 인증이라고 하면 모두 jwt 방식을 사용하였습니다.
그때는 jwt를 많이 쓰는구나 하고 넘어갔지만, 이번에는 서버도 제가 담당하므로 확실한 이유가 있어야 합니다.
궁금하여 검색을 해 본 결과 세션과 jwt의 특징과 주요한 차이점은 다음과 같았습니다.
세션: 서버측에서 접속한 사용자 정보를 저장하고 , 세션ID를 클라이언트에 전달한다.
- 장점 : 서버에 저장하므로 , 클라이언트에 노출되지 않아 안전하다. 서버에서 만료하기 편하다.
- 단점 : 서버 부하가 증가할 수 있다. 또한 분산 환경에 대응이 복잡해진다.
jwt: 사용자 정보로 jwt를 생성해 클라이언트에 전달한다.
- 장점 : 클라이언트에서 저장하므로, 서버의 부담이 줄어들고 분산 환경에서 상태를 쉽게 공유할 수 있다.
- 단점 : jwt는 클라이언트에 저장되므로 보안을 고려해야 한다. 만료하기 어렵다.
사실 제가 구성한 프로젝트의 규모에서는 어느쪽을 택해도 상관 없기 때문에 해본적 없었던 세션 방식으로 구현해보기로 결정하였습니다.
세션ID는 클라이언트에 쿠키로 저장됩니다. 따라서 클라이언트에서 서버로 요청할 때 헤더에 쿠키를 담아서 보내주어야 이를 처리할 수 있습니다.
이때, 클라이언트에서는 프론트엔드 개발자에게 악명 높은 CORS 정책을 따라야만 쿠키를 전송할 수 있습니다.
브라우저에서는 보안을 위해 동일 출처 정책(Same-Origin Policy)을 따라, 동일한 출처에서만 리소스에 접근할 수 있도록 제한하고 있습니다.
하지만 다른 도메인의 리소스에 접근하는 일이 빈번하게 발생하므로 CORS(Cross-Origin Resource Sharing)를 따라 접근할 수 있는 것입니다.
CORS 정책을 따르기 위해서는 서버측에서 응답 헤더에 대해 설정을 해주어야 합니다.
또한 보안을 위해 쿠키의 HttpOnly를 설정해줍니다.
Access-Control-Allow-Origin: 허용된 출처를 나타냅니다.
Access-Control-Allow-Methods: 허용된 HTTP 메서드를 나타냅니다.
Access-Control-Allow-Credentials: 쿠키 및 자격 증명을 허용할지 여부를 나타냅니다.
SameSite=None: 쿠키가 항상 cross-site 요청에 포함되도록 허용합니다. 단, Secure 속성이 필요합니다.
SameSite=Lax: 일부 상황에서만 cross-site 요청에 포함되도록 허용합니다.(예: 탐색을 통한 GET 요청).
SameSite=Strict: 모든 cross-site 요청에서 쿠키가 전송되지 않도록 제한합니다.또한 클라이언트 쪽에서도 요청 헤더에 대해 설정을 해주어야 합니다.
credentials: include이때, 요청 헤더가 credentials: include 일때 Access-Control-Allow-Origin = '*' 로 설정해 두었다면 , 브라우저에서 오류가 발생합니다.
따라서 다른 도메인에서 쿠키를 보내기 위해서는 Access-Control-Allow-Origin 에 URL을 명시해야 합니다.
이제 쿠키를 보낼 준비가 되었습니다.
쿠키를 다른 도메인에 보내기 위해서 SameSite=none을 설정하기 위해서는 , secure=true여야 합니다.
secure를 사용하려면 프로토콜이 https여야 하기 때문에 서버의 프로토콜을 https로 변경해야 하는데, 서버의 프로토콜이 https가 되면 , http와도 다른 도메인이 되므로 , 클라이언트 또한 https로 변경되어야 합니다.
모두 변경하였다면 클라이언트, 서버 모두 https일 때 쿠키 전송을 위한 세팅을 마쳤습니다.
또한 정상적으로 쿠키가 전송되는 것을 확인할 수 있었습니다.
하지만 … 크로스 브라우징 테스트를 하던 중 safari에서 쿠키가 전달이 안되고 있는 것을 발견했습니다.

검색을 해보니, safari 기본 설정에서는 SameSite=none을 해주었더라도 다른 도메인끼리 쿠키를 전달할 수 없도록 바뀌었다고 합니다.
따라서, safari에 대응하기 위해서는 클라이언트와 서버가 같은 도메인이 되어야 합니다.
오라클 클라우드에 배포하기
앞서 클라이언트와 서버를 같은 도메인에 배포해야 하는 결론에 다다랐습니다.
따라서 기존의 프론트엔드는 vercel에 호스팅 되어있었는데, 이를 클라우드로 호스팅 되도록 모두 변경해야 합니다.
클라우드에는 aws,gcp,azure 등등 유명한 서비스가 많습니다. 보통 많은 사람들이 사용하는 것은 aws 일 것입니다.
하지만 aws에서 무료로 제공되는 ec2 인스턴스의 성능이 낮기 때문에 oracle을 채택하였습니다.
oracle 클라우드는 비교적 후발주자로서 프리티어로 제공하는 인스턴스의 성능이 다른 클라우드 서비스보다 좋으며(4코어 24기가), 트래픽 아웃바운드를 10TB 까지 무료로 제공해줍니다.
대신 단점으로는, 유저풀이 적기 때문에 정보와 오류에 대한 해결방법이 적다는 점입니다.
그래도 이 단점을 상쇄할 만큼 성능적인 부분이 앞서기 때문에, oralce 인스턴스로 결정했습니다.
이전에 aws를 사용해 본 경험이 있는데, 용어가 약간 다를뿐 기본적으로 제공하는 서비스의 구조는 비슷해서 금방 적응할 수 있었습니다.
또한 전반적인 진행은 정리가 잘 된 블로그를 따라 진행하였습니다.
배포 과정
프로젝트는 다음과 같은 구조를 가지도록 구성하였습니다.

nest에 postgreSQL DB와 세션 DB로 redis를 활용하였고 도커와 도커 컴포즈를 사용하여 쉽게 배포 하기 위해 노력했습니다.
처음 구성해보았는데 한 번 해보고 나니 전체적인 프로젝트의 흐름을 파악할 수 있는 좋은 경험이였습니다.
후기
고도화를 진행하면서, 어떻게 사용자들이 편하게 사용할 수 있을지에 대해서 많은 시간 고민하였습니다.
물론, 타겟 유저층이 학교 사람들이기 떄문에 많은 유저를 확보할 수 있을거라고는 생각하지 않았습니다.
하지만 얼마나 많은 사람들이 이용해줄까 하는 호기심에 구글 애널리틱스를 추가하여 배포한 날로부터 측정하였습니다.


1월 3일에 배포를 한 후, 약 300명 정도의 사람들이 접속하였지만 확실히 배포하고 며칠 뒤부터는 많은 관심을 끌지 못한 것을 볼 수 있습니다.
이렇게 이번 배포를 통해 유저를 끌어모은다는 것이 쉽지 않은 일이구나라는 것을 표면적으로 느낄 수 있었습니다.
하지만, 많은 것을 배우며 제작하면서 즐거웠기 때문에 만족스러운 프로젝트였습니다.