토이 프로젝트 일지 6 : React/SpringBoot 기술 스택으로 코딩 테스트 서비스 만들기
1. 시작 계기
대학교 4학년쯤에 취업 시기가 다가오면서 우연히 플랫폼 비즈니스 제1기 교육생 모집 관련 공고를 보게 되었는데 React, SpringBoot부터 시작해서 이벤트 스토밍, Kafka, Kubernetes 등 정말 많은 걸 다루는 것을 보고 흥미가 생겨서 지원하게 되었다. 들어보니 새로운 내용들이 많아서 즐겁게 들을 수 있었고 그쪽에서 LV1 개인 역량 평가라는 것을 했는데 주제가 LV1 교육에서 들었던 내용을 기반으로 프로그램을 작성해 보는 것이다. 이왕이면 LV1 평가뿐만 아니라 차후에 취업 포트폴리오에도 쓸 수 있게 제대로 만들어 보자는 마음으로 프로그램을 작성하였고, 다음과 같이 관련 일지를 작성하게 되었다.
2. 프로젝트 개요
가. 프로젝트 소개
1. 프로젝트 유형: 개인 토이 프로젝트
2. 구현 서비스: 백준, 코드포스와 유사한 코딩 테스트 서비스
3. 개발 환경: VS Code
4. 활용 기술
프론트엔드: React, MUI
백엔드: Spring-Boot, JPA, MySQL, Docker, JWT
5. 개발 기간: 2023.9.27 ~ 2023.11.12
나. 프로젝트 목표
React, Spring-Boot, Docker에 이르는 기술 스택들을 조화롭게 활용해서 실전에 가까운 서비스를 완성한다.
3. 프로젝트 구현
가. RSA 기반 JWT를 이용한 인증 로직 구현하기
JWT를 이용한 로그인 및 인증 과정을 구현하는 것은 쉬운 일은 아니었다. Nest.js를 이용했을 때는 단순하게 JWT 로직 자체만 집중하면 되었는데 Spring인 경우에는 Spring Security와 연계해서 하려다 보니까 Spring Security에 있는 기존 로직을 상당히 수정하고 커스터마이징해야 했기 때문이다.
각 객체의 역할은 다음과 같다.
* FrontEnd
LocalStorage: React 컨텍스트에 저장을 해도 새로고침을 할 경우, 관련 데이터가 완전히 날아가 버리기 때문에 새로고침시에 이 부분을 확인하기 위해서 사용하게 되었다.
JwtContext: Jwt는 여러 객체가 인증이나 유저의 정보를 얻기 위해서 범용적으로 활용되기 때문에 관련 컨텍스트를 따로 만드는게 편리했다.
Alarm Context: 로그인이나 회원가입 여부를 알람으로 남길 때 라우터를 통한 이동 시에 알람이 삭제될 수 있기 때문에 이를 방지하기 위해서 최상위 Context에 알람을 일괄적으로 관리하도록 만들었다.
* Backend
JwtService: Jwt를 생성하거나 유효성을 검사하는 등의 로직들이 들어간 서비스 객체
OAuthResourceServer: 헤더를 통한 JWT 인증을 간편하게 만들어 주는 라이브러리
Authentication: Spring Security에서 유저 인증 및 암호화를 일괄적으로 관리해 주는데 사용되는 객체
나. 코딩테스트 문제 생성 및 조회하는 로직 구현하기
* Frontend
리스트 형태의 데이터 종속성이 필요한 경우에는 MUI에서 제공해 주는 DataGrid와 Dialog를 활용해서 문제 생성 관련 인터페이스를 제공했다.
* Backend
그림 6. E-R 다이어그램
문제를 생성하기 위해서는 다음과 같은 테이블을 생성해야 했다.
User: 문제를 생성하는 유저의 정보
Problem: 실제 문제에 대한 설명 및 정보
Example: 문제에 대한 예시 입출력 값들
Testcase: 유저에게는 공개되지 않으며, 채점을 위해서 별개로 사용되는 입출력 값들
Submission: 유저가 제출한 코드 및 채점 결과에 대한 정보
SubmissionOutput: 각각의 테스트케이스에 대한 채점 내역
또한, 관련 인터페이스의 정보를 일괄적으로 제한시키기 위해서 Req, Res 객체를 활용해서 설계했다.
다. 코딩테스트 문제를 채점하는 로직 구현하기
그림 10. 채점 관련 시퀸스 그래프
채점 관련 서버는 확장성이 있도록 Submission으로 분리했으며, 관련 채점 코드는 통신 관련 로직으로부터 분리해 독립적으로 관리되도록 Marking으로 분리했다. 유저가 관련 코드를 제출하면 Submission Server로 전송된 뒤에 모든 코드가 실행되면 Marking에서 Backend로 접속하도록 만들어서 비동기적으로 동작하도록 만들었다.









