앱을 만드는 일과 운영하는 일은 조금 다르다. 로컬에서 잘 돌아가는 Flutter 앱도 실제 사용자에게 배포하려면 서버 주소, 데이터베이스, 환경변수, 오류 추적, 푸시 설정까지 하나씩 맞춰야 한다.
Strike Log도 처음에는 기능 구현이 중심이었다. 점수 계산, 클럽, 실시간 경기방, 배지, 알림까지 만들고 나니 다음 질문은 자연스럽게 “이걸 어디에 올리고 어떻게 유지할 것인가?”였다. 이번 편에서는 Railway와 Firebase를 중심으로 Flutter 앱 백엔드를 운영 환경에 올린 과정을 정리한다.

Railway에 서버와 MySQL을 올린 이유
Strike Log의 백엔드는 Node.js 기반 API 서버와 MySQL로 구성했다. 직접 VPS를 구성할 수도 있었지만, 초기 운영 단계에서는 배포와 DB 관리에 너무 많은 시간을 쓰고 싶지 않았다.
그래서 서버 배포에는 Railway를 사용했다. GitHub 저장소와 연결해두면 main 브랜치에 반영된 코드가 자동으로 빌드되고 배포된다. MySQL도 같은 프로젝트 안에서 생성해 서버와 연결했다. 작은 앱을 빠르게 운영 상태로 만들기에는 이 구성이 단순하고 관리하기 쉬웠다.
중요한 점은 로컬 개발 환경과 운영 환경을 분리하는 것이다. 로컬에서는 개발용 DB와 API 주소를 쓰고, 운영에서는 Railway MySQL과 Railway 배포 URL을 사용한다. 환경이 섞이면 테스트 데이터가 운영 DB에 들어가거나, 앱 심사 빌드가 로컬 서버를 바라보는 문제가 생길 수 있다.
운영 URL은 앱 빌드에 명확히 주입한다
Flutter 앱에서 API 주소를 관리할 때 가장 피하고 싶은 상황은 코드 안에 임시 주소가 남는 것이다. 개발 중에는 localhost나 내부망 IP를 자주 쓰지만, 릴리즈 빌드에 이런 값이 들어가면 실제 기기에서 API 호출이 실패한다.
Strike Log에서는 환경별 API URL을 분리해 관리했다. 개발 빌드에서는 개발 서버를 바라보고, 릴리즈 빌드에서는 Railway 운영 URL을 바라보도록 했다. 앱 내부에서는 한 곳에서만 base URL을 읽게 만들어 화면이나 서비스 코드가 직접 주소를 들고 있지 않게 했다.
또 릴리즈 환경에서 값이 비어 있을 때를 대비해 fallback도 두었다. fallback은 문제를 숨기기 위한 장치가 아니라, 잘못된 설정을 빠르게 드러내기 위한 최소한의 안전장치다. 운영 앱이 엉뚱한 서버를 바라보는 것보다 명확하게 실패하는 편이 낫다.

Firebase는 앱 운영의 기반으로 사용했다
Firebase는 Strike Log에서 여러 역할을 맡았다. FCM을 통한 푸시 알림, Android 앱 설정, 향후 확장 가능한 앱 운영 기반이 여기에 들어간다.
특히 8편에서 다룬 FCM 푸시는 Firebase 설정이 제대로 되어 있어야 동작한다. 앱의 패키지명, Firebase 프로젝트, Android 설정 파일, 서버의 FCM 인증 정보가 서로 맞아야 한다. 이 중 하나라도 어긋나면 토큰은 발급되지만 푸시가 도착하지 않거나, 서버 전송 단계에서 실패할 수 있다.
운영 단계에서는 “앱이 실행된다”와 “운영 기능이 정상 동작한다”를 분리해서 봐야 한다. 로그인, API 호출, 푸시 토큰 등록, 알림 수신, 화면 라우팅까지 확인해야 실제 배포 가능한 상태라고 볼 수 있다.
Sentry로 운영 오류를 놓치지 않게 했다
개발 중에는 콘솔 로그만으로도 많은 문제를 찾을 수 있다. 하지만 앱이 사용자 기기에서 실행되기 시작하면 이야기가 달라진다. 어떤 화면에서 어떤 입력으로 오류가 났는지 직접 볼 수 없기 때문이다.
Strike Log에는 Sentry를 연결해 운영 오류를 추적할 수 있게 했다. Flutter 앱에서 발생한 예외와 서버 오류를 기록하면, 사용자가 직접 제보하지 않아도 문제가 생긴 지점을 확인할 수 있다.
특히 모바일 앱은 네트워크 상태, 기기 성능, OS 버전, 권한 설정에 따라 문제가 다르게 나타난다. 로컬 테스트에서는 재현되지 않는 오류가 실제 기기에서만 발생할 수 있으므로, 운영 초기에 오류 추적 도구를 붙여두는 편이 좋다.
Android 우선 출시 전략을 잡았다
Strike Log는 Android 우선 출시를 기준으로 운영 흐름을 정리했다. iOS까지 동시에 준비하면 인증서, 심사, 푸시 설정, 스토어 정책까지 한 번에 챙겨야 할 것이 많아진다.
초기 앱에서는 한 플랫폼에서 먼저 배포와 운영 흐름을 검증하는 편이 현실적이다. Android에서 API 연결, FCM 수신, 릴리즈 빌드, 사용자 피드백 흐름을 먼저 확인한 뒤 iOS로 확장하면 리스크가 줄어든다.
이 전략은 기능을 줄이는 것이 아니라 순서를 정하는 일에 가깝다. 서버와 DB, 알림, 오류 추적이 안정적으로 돌아가는지 먼저 확인하고, 그다음 플랫폼을 넓히는 방식이다.

운영 체크리스트
배포 전에는 다음 항목을 확인했다.
- Flutter 릴리즈 빌드가 운영 API URL을 바라보는가
- Railway 서버가 정상 배포되고 헬스 체크가 통과하는가
- MySQL 연결 정보가 운영 환경변수에만 들어가 있는가
- Firebase Android 설정이 실제 패키지명과 일치하는가
- FCM 토큰 등록과 푸시 수신이 실제 기기에서 동작하는가
- Sentry에 앱 오류와 서버 오류가 기록되는가
- 운영 DB에 테스트 데이터가 섞이지 않았는가
이런 항목은 한 번 확인하고 끝나는 것이 아니라, 배포할 때마다 다시 보는 기준이 된다. 기능이 늘어날수록 운영 체크리스트의 가치도 커진다.
마무리
Strike Log의 운영 구성은 거창한 인프라보다 “작게 시작하되 운영에 필요한 기본을 빠뜨리지 않는 것”에 초점을 맞췄다. Railway는 서버와 MySQL을 빠르게 올리는 역할을 했고, Firebase는 푸시와 앱 설정의 중심이 되었다. Sentry는 배포 이후의 오류를 확인하는 안전망이 되었다.
앱 개발의 끝은 기능 완성이 아니라 사용자가 실제로 쓸 수 있는 상태를 만드는 것이다. Railway와 Firebase를 연결하면서 Strike Log는 로컬 프로젝트에서 운영 가능한 Flutter 앱으로 한 단계 넘어갈 수 있었다.
'APP' 카테고리의 다른 글
| 볼링 앱 제작기 마무리: 기능보다 중요한 운영 설계 (0) | 2026.07.09 |
|---|---|
| FCM 푸시와 인앱 알림을 함께 연결하기 (0) | 2026.07.07 |
| 배지와 출석 streak로 다시 켜고 싶은 앱 만들기 (0) | 2026.07.06 |
| 클럽 운영 기능 만들기: 가입 승인제와 1인 1클럽 정책 (0) | 2026.07.03 |
| Socket.IO로 클럽 실시간 볼링 경기방 만들기 (0) | 2026.07.01 |
