- 배포 url : https://grab-the-crown.onrender.com/
- 왕관을 자바쓰는 실시간 채팅 기반 CS 퀴즈 게임
- 여러 명의 사용자가 게임방에 입장하여 제한 시간 내에 퀴즈를 풀고 정답을 맞추어 점수를 흭득 게임이 끝나면 가장 높은 점수를 받은 사용자가 왕관을 획득
- 게임의 목표가 왕관을 얻는다는 것과 프론트엔드, 백엔드 모두 자바스크립트를 이용해서 개발했기 때문에 프로젝트 이름을 왕관을 자바쓰(자바스크립트)로 정함
| 이름 | 링크 | 역할 |
|---|---|---|
| 김송이 | @kimsongie12 | 백엔드 게임방 생성/참가 로직, 깃 PR관리 |
| 김지우 | @jiu702 | 백엔드 로그인, 회원가입, 로그아웃, 채팅 패널티 점수 차감 로직 |
| 이정민 | @zshfz | 프론트엔드 |
| 이채린 | @Rix01 | 백엔드 소켓 통신, 게임 진행 로직, 채팅, 접속자 목록 API, 방 목록 API, 랭킹 목록 API |
- 프론트엔드 : React, Scss
- 백엔드 : Node.js
- DB : MySQL, Azure
- 협업 툴 : GitHub, Notion, EXCALIDRAW, Draw.io, ErdCloud
- 배포 환경 : Render
- React
- UserCard, RoomCard 등 반복적으로 사용되는 UI 요소를 독립적인 컴포넌트로 분리하여 재사용성과 유지보수성을 고려
- react-router-dom을 사용한 라우팅 처리
- ContextAPI를 사용하여 회원정보, 로그인, 로그아웃 기능을 구현함으로써 전역적으로 관리
- useRef 훅을 사용하여 채팅창 자동 스크롤, 카운트다운 타이머 유지 등의 기능을 구현
- Axios로 API 요청 처리
- .env 파일에 환경 변수로 서버 주소를 관리하여 로컬 환경이나 배포 환경에서 프로그램을 실행할 때 용이하게 함
- SCSS
- CSS에 중첩 구조를 사용하여 가독성 향상
- mixin 기능을 사용하여 공통적으로 많이 쓰이는 색상이나 스타일을 따로 정의하여 일관된 UI 설계
- Socket.io
- 채팅, 금칙어 필터링, 점수 갱신, 방 생성/삭제 등의 이벤트를 실시간으로 처리
- 클라이언트측에서는 socket.js에서 전역 소켓 객체를 초기화하고 각 페이지에서 해당 이벤트를 구독하고 해제하는 방식으로 구현
- Vite
- React 프로젝트의 빌드 속도와 개발 서버의 속도를 고려해 CRA(Create React App) 대신 Vite 사용
- Node.js + Express
- 프로젝트의 서버는 js 환경에서 실행되며, 주요 API 기능들은 Express 프레임워크를 통해 구축됨
- /register , /login/gameroom 등의 REST 엔드포인트는 Express 라우터를 통해 구현되었으며, 각 기능별로 미들웨어를 분리하여 가독성과 유지보수성 확보
- MySQL + mysql2
- 사용자 정보 , 게임방 , 문제 , 퀴즈 옵션 등의 모든 핵심 데이터를 MySQL 데이터베이스에 저장
- mysql2 라이브러리는 js에서 비동기 방식으로 MySQL과 연결하고 데이터를 조회하거나 삽입하는 데 사용
- Socket.io
- 실시간 기능을 위해 사용되었으며, 특히 게임 중 퀴즈 문제 출제 및 답안 제출, 실시간 점수 갱신, 게임방 접속자 관리, 채팅창 등 핵심적으로 활용
- Multer
- 회원가입 시 사용자의 프로필 이미지를 업로드 받기 위해 사용된 미들웨어
- /register API에서 profileImg 필드를 통해 업로드된 이미지를 서버의 uploads/profile/ 디렉토리에 저장하며 , 해당 경로는 DB에 함께 저장됨
- 사용자가 이미지를 업로드하지 않은 경우에는 기본 프로필 이미지를 제공하도록 설정
- bcrypt
- 회원가입 시 사용자 비밀번호를 평문으로 저장하지 않고, bcrypt를 사용하여 해시 처리한 후 데이터베이스에 저장
- 로그인 시 입력된 비밀번호와 해시를 비교하여 인증 수행
- 보안 강화를 위한 필수 요소로 SQL Injection 및 탈취 리스크 방지함
- JWT
- 로그인에 성공한 사용자에게는 서버가 JWT를 발급하며, 이후 요청마다 Authorization 헤더에 토큰을 포함시켜 사용자의 인증 상태 검증함
- /login API 호출 시 jwt 토큰을 생성하여 클라이언트에 응답하고, /ranking 과 같은 보호된 API 호출 시 유효한 토큰 필요함
- 세션 없이도 인증된 사용자 요청만 처리하는 구조 구현
| 홈 화면 |
|---|
![]() |
- 최초로 접속시 나타나는 화면
- 주제에 맞게 백그라운드 이미지에 왕관이 둥둥 떠다님
- 닉네임, 비밀번호, 프로필 이미지를 사용자로부터 받아 회원가입 처리
- 프로필 이미지를 선택하지 않았을 경우 기본 이미지로 대체
- 회원가입/로그인 실패 시 alert창으로 메시지 출력
| 로비 화면 |
|---|
![]() |
- 로그인 성공시 나타나는 화면
- 로그아웃 버튼 클릭 시 홈 화면으로 이동되면서 로그아웃 처리
- 접속시 접속자 목록에 현재 접속한 사용자 목록 출력
- 방 만들기 버튼 클릭 시 모달창이 출력되고 인원 수 선택후 방 만들기
- 사용자가 들어올때 마다 접속자 목록 실시간으로 반영
- 사용자가 방에 들어올때마다 UserCard 목록에 실시간으로 추가
- UserCard에 사용자 프로필 이미지, 닉네임, 점수 출력
| 로비 화면 |
|---|
![]() |
- 사용자가 방을 만들면 RoomCard 실시간 출력
- 방 인원이 다 차거나 이미 게임이 시작된 방에 입장하려고 하면 alert창으로 경고메시지 출력
| 채팅방 화면 |
|---|
![]() |
- 인원이 다 차면 자동으로 게임이 시작되고 5초 카운트다운 후 게임 시작
- 총 5라운드로 한 라운드당 5문제가 출제되고 문제는 게임마다 랜덤으로 출력됨
- 게임하는 내내 실시간 채팅 가능
- 채팅과 점수는 실시간으로 반영
| 채팅방 화면 |
|---|
![]() |
- 1등으로 정답을 맞추면 +30점, 2등 +20점, 3등 +10점, 4등부턴 0점
- 화면 오른쪽 채팅창에 사용자들이 입력한 메시지와 SYSTEM 메시지 출력
| 채팅방 화면 |
|---|
![]() |
- 욕설이나 금지어를 입력하면 10점 감점
| 채팅방 화면 |
|---|
![]() |
- 동점자가 발생할 확률을 낮추기 위해 마지막 라운드는 1등 50점, 2등 30점, 3등 10점 부여
| 채팅방 화면 |
|---|
![]() |
- 모든 문제가 출력되고 게임이 종료되면 가장 높은 점수를 받은 사용자는 왕관을 1개 얻게됨
- 왕관수에 따라 전체 사용자의 랭킹 출력
| 채팅방 화면 |
|---|
![]() |
- 언제든 방에서 나갈 수 있으며 방에 인원이 한명만 남게되면 방이 없어지고 해당 게임은 무효 처리
- 대부분의 메시지를 alert창으로 출력하는데 이를 화면에 직접 랜더링시킬 예정
- input 태그의 onChange 메서드를 커스텀 훅으로 모듈화 할 예정
- 새로고침 시 버그 수정 예정
- 시스템에서 전달하는 메시지와 유저가 입력한 메시지 구분되게 수정할 예정
- JWT의 만료 시간 설정, 재발급 로직, 토큰 블랙리스트 관리 등을 통해 인증 시스템의 안정성 강화 필요
- bcrypt 대신 argon2 과 같은 더 강력한 해싱 알고리즘 도입도 고려
- Multer로 서버에 이미지를 저장하고 있으나 AWS S3와 같은 외부 저장소 연동을 통해 서버 자원 부담을 줄이고 확장성을 높이는 개선 필요
- Socket.io 기반의 실시간 통신은 기본 기능은 구현되었지만, 연결 끊김 감지, 자동 재연결 , 에러 메시지 브로드캐스트 등 안정적인 커뮤니케이션 체계 강화 필요
첫 백엔드 프로젝트다. 다이어 그램 작성부터 기능 회의까지 정말 많은 회의를 하면서도 과연 기능 개발이 될까? 했다. 이런 과정이 있어서 수월하게 프로젝트를 마무리 할 수 있다는 것을 코드 구현하면서 깨달았다. 내가 구현한 부분도 좀더 다듬어서 다시 개발해보고 싶단 생각이 깊게들었다. 이번 프로젝트로 많은 생각과 꾸준한 공부가 필요하다는 것을 얻어가게 된 거 같다.
개발하기 전에 전체적으로 계획을 세우고 요구 명세서와 같은 준비 과정이 매우 중요함을 꺠달았다. 그리고 react와 node.js로 어떻게 웹 사이트를 만들 수 있는지 전체적인 구조를 이해할 수 있었다
전체적인 기능 완성 후에 발생하는 예상치 못한 오류들이 많아 디버깅 하는데에 가장 큰 시간을 들였던 것 같다. 이 경험을 통해 디버깅이 전체 개발에서 차지하는 비중이 크므로 초기 단계부터 꼼꼼한 설계가 중요하다는 것을 다시금 깨달았다.
개발 전에 명세서를 작성하고 다이어그램을 작성하는 등의 준비 과정이 생각보다 개발하는 데 중요한 역할을 한다는 사실을 깨달았다. 협업에 사용되는 깃과 깃허브를 어렵게만 생각하고 있었는데 생각보다 어렵지 않다는 것을 이번 프로젝트를 통해 알 수 있었기에 자신감을 얻었다. 또한, 수업 시간에 배웠던 내용들을 우리만의 프로젝트에 적용하는 과정이 재미있었다. 아직 스프링을 배우지 않아서 Node.js를 사용하였지만 스프링을 배운 이후엔 이번 프로젝트를 스프링에 적용시켜서 다시 만들어보고 싶다.









