Echo Note는 처음부터 독립 앱으로 만든 프로젝트가 아니었다.

여러 학습 기능을 모아 두던 study365 안에서 시작한 단어 학습 기능이었다.

단어를 보고 발음을 듣고 복습하는 흐름을 다듬다 보니, 이 기능만 따로 꺼내 쓰고 싶어졌다.

그래서 화면과 학습 기능을 Echo Note 프로젝트로 옮겨 Android 앱으로 분리했다.

그런데 화면을 분리하고 나니 서버도 하나 더 만들어야 하는지 고민이 생겼다.

앱이 하나 늘어날 때마다 서버도 하나씩 늘려야 할까?

앱은 나누고 서버는 함께 쓰기

Echo Note에는 학습 콘텐츠를 관리하고 앱에 필요한 정보를 전달할 서버가 필요했다.

앞으로 다른 학습 앱을 만들 때도 비슷한 기능이 필요할 것 같았다.

앱마다 서버를 따로 만들면 배포와 데이터 관리, 오류 확인도 각각 해야 한다.

혼자 관리하는 프로젝트에서는 기능을 만드는 시간만큼 운영할 곳이 늘어나는 일도 부담이었다.

기존 study365의 Rails 서버를 공통 백엔드로 남기고, Echo Note는 독립된 앱으로 연결하기로 했다.

쉬운 설명: 앱은 손님이 이용하는 매장이고, 백엔드는 여러 매장이 함께 쓰는 창고와 사무실에 가깝다.

이렇게 하면 앱의 화면과 사용 흐름은 따로 바꾸면서 콘텐츠 관리와 서버 운영은 한곳에 모을 수 있다.

대신 공통 서버에 문제가 생기면 연결된 앱도 영향을 받을 수 있으므로, 함께 쓰는 범위를 신중하게 정해야 한다.

만들어 둔 기능을 모두 공개하지 않기

기존 서버에는 Echo Note 외에 개발 중인 학습 기능도 남아 있었다.

서버를 함께 쓴다는 이유로 이 기능들까지 외부에 열어 둘 필요는 없었다.

메뉴에서 링크를 지우는 것만으로는 주소를 직접 입력하는 요청을 막을 수 없다.

그래서 현재 서비스에 필요한 요청만 서버에서 받도록 공개 범위를 좁혔다.

쉬운 설명: 안내판에서 방 이름을 지우는 데서 끝내지 않고, 실제로 들어갈 수 있는 문도 정하는 것이다.

관리 화면은 별도의 접근 확인을 거치게 하고, 외부에 공개할 기능과 내부에서 쓸 기능을 구분했다.

나중에 새 앱을 연결할 때도 필요한 기능을 확인한 뒤 공개 범위를 넓히는 편이 낫다고 판단했다.

관리자 로그인도 관리할 일을 줄이기

관리 화면을 위해 별도의 비밀번호를 하나 더 만들고 싶지는 않았다.

Google 로그인으로 본인을 확인하되, 로그인 성공과 관리자 접근 허용은 따로 판단하도록 했다.

Google 계정으로 로그인할 수 있다는 사실만으로 누구나 관리자가 되어서는 안 되기 때문이다.

연동 과정에서는 로그인 후 돌아오는 주소와 실제 배포 설정이 맞지 않아 접속이 실패하기도 했다.

이때 배운 것은 로그인 버튼이 보인다는 것과 운영 환경에서 로그인이 끝까지 된다는 것은 다르다는 점이었다.

단어를 바로 보여 주면서 콘텐츠도 보호하기

학습 앱을 켤 때마다 모든 단어를 서버에서 받아야 한다면 연결이 느리거나 끊겼을 때 불편하다.

Echo Note는 초기 학습 데이터를 앱에 포함하고, 이후 변경된 콘텐츠를 확인하는 구조를 사용한다.

다만 원본 단어 파일을 읽기 쉬운 형태로 앱 안에 그대로 넣고 싶지는 않았다.

배포용 콘텐츠는 암호화하고, Android 앱에서 필요한 보호 절차를 거쳐 읽도록 구성했다.

쉬운 설명: 학습 자료를 미리 가져다 두되, 포장을 풀어 사용하는 과정은 앱이 맡게 한 것이다.

이것이 화면에 표시되는 내용을 절대로 복사할 수 없게 만든다는 뜻은 아니다.

원본 자료가 그대로 묶여 배포되는 일을 줄이고, 콘텐츠를 전달하는 과정을 관리하려는 선택이었다.

설치 확인과 학습 데이터 보관

앱에 필요한 정보를 요청했다고 해서 서버가 무조건 응답하도록 만들지는 않았다.

Android에서는 Google Play Integrity를 활용해 설치된 앱에 관한 신호를 확인하고, 서버에서 요청을 판단한다.

쉬운 설명: 앱이 스스로 정식 앱이라고 말하는 것만 믿지 않고, 배포 경로와 앱 상태를 확인할 때 참고할 근거를 받는 것이다.

그 결과를 어떤 기능에 적용할지는 앱의 목적과 실제 설치 환경에 맞춰 정해야 한다.

확인을 붙였다는 이유만으로 정상 사용자가 학습 화면에 도달하지 못하는 일이 생겨서는 안 된다.

콘텐츠를 갱신할 때도 새 데이터를 검증한 뒤 교체하고, 통신이나 검증에 실패하면 마지막으로 확인된 데이터를 유지하도록 했다.

보호 장치를 넣는 일과 사용하던 학습 데이터를 지키는 일은 함께 생각해야 했다.

서버가 켜졌는데 연결되지 않았던 이유

처음 배포할 때는 서버 프로그램이 실행됐는데도 외부 요청이 제대로 도착하지 않았다.

Docker와 Kamal로 실행되는 구성에서 외부 요청을 전달하는 쪽과 앱이 받는 쪽의 연결 설정이 맞지 않았다.

연결을 맞춘 뒤에는 서버 상태를 확인하는 요청이 접근 제한에 걸리는 문제도 발견했다.

프로세스 실행, 요청 전달, 상태 확인은 서로 이어져 있지만 각각 확인해야 하는 단계였다.

문제를 해결할 때도 제한을 통째로 풀기보다 어느 단계에서 요청이 멈추는지부터 확인했다.

작은 앱의 서버라도 앱 코드 바깥의 설정 때문에 사용하지 못할 수 있다는 점을 다시 배웠다.

배포 성공과 실제 사용 가능은 별개

배포 명령이 끝났다는 것만으로 작업을 마치지는 않았다.

공개해야 할 요청이 응답하는지, 제한해야 할 요청은 막히는지, 관리자 로그인이 끝까지 되는지를 나누어 확인했다.

서버 테스트와 별개로 실제 배포 경로로 설치한 앱에서 첫 학습 화면에 도달하는지도 확인해야 했다.

로컬에서 설치한 앱과 Google Play에서 설치한 앱은 서명이나 설치 상태를 확인하는 조건이 다를 수 있기 때문이다.

이 글의 초안을 쓸 때는 출시 전이었지만, 이후 Echo Note는 Google Play에 공개했다.

출시 뒤에도 앱 업데이트와 서버 설정이 함께 맞는지 확인하는 일은 계속 남는다.

Google Play에서 Echo Note 보기

Echo Note 개인정보처리방침 보기

앱 하나를 분리하며 정리한 것

이번 작업은 서버를 하나 더 만드는 대신, 기존 서버가 맡을 일과 공개할 범위를 정리하는 과정이었다.

사용자가 보는 앱은 독립시킬 수 있고, 그 뒤에서 필요한 운영 기능은 함께 쓸 수 있다.

다만 함께 쓴다는 이유로 모든 기능을 열어 두거나, 서버가 켜졌다는 이유로 사용 가능하다고 판단해서는 안 된다.

한 줄 요약: 앱을 독립시킨다고 서버까지 따로 만들 필요는 없지만, 공개 범위와 접근 권한, 실제 설치본의 동작은 각각 확인해야 한다.