본문 바로가기
abyss-s.log
뒤로가기

밸런스 게임 플랫폼 '너로 정했다!' 개발 회고

페이지 수정

티스토리 원문: https://tomymoon.tistory.com/214

LG U+ 유레카 SW교육과정에서 진행한 미니프로젝트 ‘너로 정했다!’ 개발 회고다. 유레카에서 진행한 첫 프로젝트라는 점에서 뜻깊었고, 곧 종합 프로젝트를 앞두고 있어 정리해보았다.

너로 정했다!

📝 프로젝트 소개

기본 정보

프로젝트 주제 선정 배경

미니프로젝트인만큼 규모는 작지만 실제로 이용할 수 있는 서비스를 만들고자 했다.

그래서 단순한 투표가 아닌 밸런스 게임 형식을 통해 선택의 재미와 고민을 나눌 수 있는, 실제로 활용 가능한 소셜 플랫폼을 만들고자 했다. 서비스 타겟은 우리 프론트엔드 대면반 사람들이었다. 교육과정 중 지친 일상 속에서 ‘무인도에서 누가 가장 잘 살아남을까?’ 같은 가볍고 유쾌한 질문을 통해, 구성원들이 매일 소통하고 웃을 수 있는 공간을 만들고 싶었다!

기술 스택 및 아키텍처

Frontend

React + Vite + TypeScript + Tailwind CSS + Redux Toolkit

Create React App이 아닌 Vite를 선택한 이유는 빠른 빌드 속도와 개발 서버 성능 때문이다. TypeScript와의 궁합도 좋고, 나를 제외한 3명의 팀원이 모두 Java 언어 기반의 앱 개발 경험이 있었기에 더 익숙할 것이라고 생각했다. 또한 Redux Toolkit을 선택한 이유는 전역 상태 관리가 필요했기 때문이다. 토스트 메시지나 인증 상태 같은 것들을 컴포넌트 간에 공유하는 데에 사용했다.

Backend

Spring Boot + MyBatis + JWT + MySQL + Swagger

백엔드는 Spring Boot로 구성했다. JPA보다는 MyBatis를 선택했는데, 물론 LG U+ 측의 요구사항이기도 했지만 우리 서버 자체가 복잡한 쿼리보다는 단순한 CRUD가 많아서 러닝 커브를 고려한 선택이기도 했다.

인프라 & 배포

Docker + AWS RDS (MySQL) + Render + Vercel

인프라는 전적으로 내가 담당한 부분이다!

처음에는 AWS Elastic Beanstalk + EC2를 사용했지만, 미니 프로젝트 특성상 Render가 무료에다가 배포도 아주 간단해서 바꾸게 되었다. 물론 성능은 많이 아쉬웠지만.. 😅

시스템 아키텍처

시스템 아키텍처

주요 기능 소개

기능 데모 1

기능 데모 2

1. 회원 인증 시스템

2. 밸런스 게임 투표

3. 익명 댓글 커뮤니티

4. 반응형 UI/UX

나의 역할

🎨 프론트엔드 개발

이번 프로젝트에서 프론트엔드를 맡으면서 단순한 화면 구현을 넘어 상태 관리, 보안, UX 향상까지 고려한 다양한 기능들을 직접 구현해볼 수 있었다.

1. Redux Toolkit 기반 전역 상태 관리

리덕스는 처음이었지만, 실제로 써보니 그 강력함을 체감할 수 있었다. 토스트 메시지 시스템을 구현하며, 어떤 컴포넌트에서든 dispatch(showToast())만 호출하면 전역에서 알림이 뜨도록 구성했는데 이 부분이 매우 유용했다!

// 사용 예시
dispatch(show({ message: '투표가 완료되었습니다!', type: 'success' }));

이 구조 덕분에 각 컴포넌트는 더 깔끔하게 유지됐고, 기능 간 의존성도 최소화할 수 있었다.

2. Axios 인터셉터 + JWT 자동 인증 처리

웹 시큐리티 과목을 수강한 후, 기존 로그인 방식을 전면 개편해 JWT 기반 인증 구조를 도입했다. 다음은 설계한 클라이언트 JWT 인증 과정이다!

// 401 응답 시 자동 토큰 재발급 및 재요청
if (error.response?.status === 401 && !originalRequest._retry) {
  const res = await axios.post('/token/refresh', { ... });
  const newAccessToken = res.data.accessToken;
  originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`;
  return axiosInstance(originalRequest);
}

이 부분을 구현하면서 가장 힘들었던 점은 중복 갱신 요청을 방지하고, 실패 시 일관된 예외 처리를 하는 것이었다. 덕분에 실제 서비스에서 인증 시스템이 어떻게 작동해야 하는지 깊이 이해할 수 있었다.

3. 캐릭터 랜덤 애니메이션 구현 (UX 강화)

메인 페이지가 너무 정적이라, 페이지에 생동감을 더하고 싶어서 framer-motion을 활용한 캐릭터 플로팅 애니메이션을 구현했다.

controls.start({
  x: `${x}vw`,
  y: `${y}vh`,
  transition: {
    duration,
    ease: 'easeInOut',
  },
});

덕분에 사용자가 메인 페이지에 접속했을때 심심하지 않고, 시각적으로 눈에 띄는 화면을 구성할 수 있었다.

🧑‍💻 백엔드 개발

이번 프로젝트에서 백엔드를 Spring Boot 기반으로 처음 개발해보았다.

1. JWT 인증 로직 구현

가장 중점을 둔 부분 중 하나는 JWT 기반 인증 시스템 구축이었다. 로그인 시 발급된 Access Token과 Refresh Token을 활용해 요청을 인증하고, 토큰이 만료된 경우에는 자동으로 재발급하는 구조를 구현했다.

이 과정에서 가장 어려웠던 점은 Spring Security 필터 체인과 HandlerInterceptor의 적용 순서, 그리고 예외 발생 시의 처리 흐름이었다. 직접 로그를 찍으며 흐름을 따라가고, 예외 상황에 따른 대응 방식들을 테스트하면서 흐름을 공부했다.

2. 🌐 WebMvcConfig 설정 및 CORS 정책 정리

전역 Config 설정과 CORS(Cross-Origin Resource Sharing) 문제를 해결하는데 시간을 다소 썼다.

트러블슈팅

1. 이미지 경로 하드코딩 문제

문제 상황

여러 컴포넌트에서 이미지 경로가 /assets/images/...처럼 하드코딩되어 있어 유지보수에 큰 어려움이 있었다.

해결 과정

결과

유지보수가 훨씬 쉬워졌고, 디자인 리소스 변경이 생겨도 일괄 적용이 가능해졌다.

2. Pagination 컴포넌트 리팩토링

문제 상황

기존에 Process라는 이름으로 구현된 페이지 인디케이터 컴포넌트는 역할이 모호하고 재사용이 어려운 구조였다.

해결 과정

<Pagination totalPages={4} currentPage={page} onPageChange={setPage} />

결과

구조가 명확해지고 다른 페이지에서도 재사용 가능한 컴포넌트로 발전했다.

프로젝트를 통해 배운 것들

1. 리더십과 협업

팀장으로서 최선을 다해 팀을 서포트하려고 노력했다. 팀장으로서 가장 크게 배운 점은 혼자 잘하는 것보다, 함께 성장하는 것이 중요하다는 사실이었다. 처음에는 빠르게 구현하는 데 집중했지만, 팀원들이 점차 React를 이해하고 함께 개발할 수 있게 되면서 팀 전체의 만족도가 훨씬 높아졌다. 팀원들도 팀이 너무 좋았다고 자주 얘기해주었다.

팀 협업

또한 코드리뷰도 적극적으로 하기 위해 노력했다! 후반부에는 급해서 거의 구두로 진행했지만..ㅎ

코드 리뷰 1

코드 리뷰 2

2. 풀스택 개발 경험

기존에는 프론트엔드에 집중했지만, 이번 프로젝트에서는 Spring 기반 백엔드도 함께 구축했다. 이 과정에서 교육과정에서 배운 REST API 설계, JWT 인증 흐름, DB 연동 등을 경험하며 시스템의 전반적인 흐름을 이해할 수 있게 되었다.

프론트만 할 때는 ‘이게 왜 안 되지?‘라는 생각이 많았다면, 이제는 ‘백엔드에서 어떤 응답이 와야 할까?‘를 먼저 고민하게 되었다.

3. DevOps 및 인프라 구축 경험

Docker를 이용한 백엔드 컨테이너화, AWS RDS 세팅, Render/Vercel 배포 자동화까지 처음부터 끝까지 직접 구축해보았는데 상당히 힘들었다.

spring.datasource.hikari.maximum-pool-size=100
spring.datasource.hikari.minimum-idle=10

실수 하나로 100번은 재배포한 것 같지만..? 덕분에 인프라 설정 하나하나의 중요성을 뼈저리게 느끼게 된 계기였다!!

프로젝트 결과

회고

이번 프로젝트에서 가장 힘들었던 부분은 JWT 토큰 갱신 로직이었다. 단순히 백엔드에서 토큰을 발급하는 것을 넘어서, 프론트엔드에서는 Axios 인터셉터로 자동 처리하고, 중복 갱신을 막는 로직까지 구현해야 했기 때문에 예상보다 훨씬 복잡했다. 게다가 도중에 프론트만 아니라 백엔드 API 코드까지 대폭 수정해야 했던 상황도 있었다. 하지만 팀원 모두가 자발적으로 함께 문제를 분석하고 토론하며 해결했다.

무엇보다 느낀 건, 기술적인 문제보다 중요한 건 소통이라는 점이었는데!

프로젝트 마지막 날, 모든 기능이 정상적으로 작동하는 것을 확인했을 때의 짜릿함은 아직도 생생한다. 다들 처음엔 React가 너무 어려웠는데, 덕분에 실력이 많이 늘은 것 같다고 말해주어서 팀 리더로서 뿌듯함과 보람을 느꼈다. 매일 슬랙과 구두를 통한 적극적인 질문과 코드 리뷰, 서로를 배려하는 태도 덕분에 팀 전체가 함께 성장할 수 있었다. 좋은 사람들과 함께해서 재밌는 경험이었고 덕분에 오빠 언니들과 더욱 친해질 수 있었다. 진짜 미니 플젝 4조 안녕..🥹

마지막 날 1

따수운 우리 팀.. 그리울거야

프로젝트 관련 링크 정리


페이지 수정
이 글 공유하기:

이전 글
AI 혜택 큐레이션 서비스 MoonoZ 개발 회고
다음 글
Context API로 검색 키워드 하이라이팅 구현하기