반응형

Flutter와 NestJS로 만든 볼링 점수 기록 앱 Strike Log 제작기

볼링을 치다 보면 생각보다 기록하고 싶은 데이터가 많습니다. 오늘 점수가 몇 점이었는지, 평균이 오르고 있는지, 스트라이크가 얼마나 나왔는지, 같이 치는 사람들과 기록을 공유할 수 있는지 같은 것들입니다.

처음에는 단순히 “볼링 점수를 저장하는 앱” 정도로 생각했습니다. 하지만 실제로 만들다 보니 점수 계산, 게임 기록, 시리즈 관리, 클럽 기능, 실시간 경기방, 배지, 푸시 알림까지 이어지는 꽤 큰 앱이 되었습니다.

이번 글부터는 제가 만든 볼링 기록 앱 Strike Log의 제작 과정을 하나씩 정리해보려고 합니다. 1편에서는 앱의 전체 방향과 기술 구조를 먼저 소개합니다.

Strike Log는 어떤 앱인가

Strike Log는 볼링 경기 기록과 통계를 관리하는 앱입니다. 핵심 기능은 10프레임 점수 입력, 스트라이크와 스페어 보너스 자동 계산, 개인 경기 기록 저장, 시리즈 기록, 클럽 경기 실시간 점수 공유입니다.

여기에 평균 점수, 최고 점수, 최근 기록 통계, 배지 시스템, 출석 streak, FCM 기반 푸시 알림까지 붙였습니다. 단순 기록 앱으로 시작했지만, 실제 사용 흐름을 생각하다 보니 “혼자 기록하는 앱”에서 “같이 치는 사람들과 기록을 공유하는 앱”으로 확장되었습니다.

기술 스택은 이렇게 구성했다

앱은 Flutter로 만들고, 백엔드는 NestJS로 구성했습니다. Flutter 앱은 모바일 화면, 점수 입력, 기록 조회, 클럽 경기방, 알림 화면을 담당합니다. API 서버는 사용자, 게임 기록, 클럽, 배지, 알림 같은 데이터를 관리합니다.

Strike Log의 Flutter 앱, NestJS API, MySQL, Socket.IO, FCM 구성

전체 구조를 단순하게 표현하면 Flutter 앱은 화면과 입력을 담당하고, NestJS API는 인증과 도메인 규칙을 처리합니다. MySQL은 사용자, 게임, 프레임, 클럽, 배지 데이터를 저장하고, Socket.IO는 클럽 경기의 실시간 점수 공유에 사용했습니다. Firebase Cloud Messaging은 푸시 알림 발송을 맡습니다.

앱 구조는 feature 단위로 나눴다

Flutter 코드는 크게 core와 features로 나눴습니다. core에는 API 클라이언트, 공통 위젯, 테마, 세션 관리, FCM, 소켓 서비스처럼 여러 화면에서 함께 쓰는 코드가 들어갑니다.

features에는 기능별 화면과 데이터 코드가 들어갑니다. 예를 들어 로그인과 회원가입은 auth, 점수 입력과 게임 저장은 game, 대시보드는 home, 클럽 기능은 group, 배지와 알림은 각각 badges, notifications로 분리했습니다.

처음부터 복잡한 상태관리 라이브러리를 넣지는 않았습니다. 현재 구조는 StatefulWidget과 setState 중심입니다. 작은 화면 단위로 상태를 관리하고, 필요한 통신은 서비스 클래스로 분리하는 방식입니다.

가장 중요한 도메인은 볼링 점수 계산이었다

이 앱에서 가장 핵심이 되는 부분은 결국 볼링 점수 계산입니다. 볼링은 단순히 각 프레임의 핀 수를 더하는 게임이 아닙니다. 스트라이크는 다음 두 번의 투구가 보너스로 붙고, 스페어는 다음 한 번의 투구가 보너스로 붙습니다.

특히 10프레임은 스트라이크나 스페어 여부에 따라 세 번째 투구가 생기기 때문에 예외 처리가 필요합니다. 그래서 점수 입력 화면과 별개로 점수 계산 로직을 분리했습니다. 프레임별 투구 데이터를 기반으로 총점, 누적 점수, 스트라이크 수, 스페어 수 같은 값을 계산하도록 만들었습니다.

백엔드는 기록 저장소가 아니라 도메인 서버에 가깝다

NestJS API는 단순히 게임을 저장하는 역할만 하지 않습니다. 사용자 인증, 게임 기록, 시리즈, 클럽, 가입 신청, 배지, 알림, FCM 토큰 관리까지 처리합니다.

게임을 저장하면 DB에 insert만 하는 것이 아니라 최고점 갱신 여부를 확인하고, 새로 획득한 배지가 있는지 평가하고, 필요한 경우 알림도 생성합니다. 즉 Strike Log의 백엔드는 기록 저장소라기보다 앱의 주요 규칙을 처리하는 도메인 서버에 가깝습니다.

앞으로 다룰 제작기

이번 1편에서는 Strike Log의 전체 그림을 소개했습니다. 다음 글부터는 Flutter 앱 구조 설계, 볼링 점수 계산 로직, NestJS 게임 기록 API, Socket.IO 실시간 클럽 경기방, 배지와 출석 streak, FCM 푸시 알림, Railway 배포 과정까지 차례로 정리할 예정입니다.

완성된 결과만 보여주기보다, 왜 그런 선택을 했는지와 어떤 문제가 있었는지도 함께 기록해보겠습니다. Flutter와 NestJS로 실제 서비스를 만들어보고 싶은 분들에게 작은 참고 사례가 되었으면 합니다.

반응형