룸톤 Roomtone 16
이 글은 룸톤 Roomtone 시리즈의 17번째 기록입니다. (총 22개)
오늘 한 일
- 운영 서버를 띄웠다. 서비스 도메인에 연결하고 운영용 비밀값 세 개를 넣은 뒤, 운영 데이터베이스에서 재생목록·승인곡을 실제로 읽어 오는 것까지 확인했다.
- 안드로이드 앱이 암호화된 곡을 받아 메모리 안에서만 풀어 재생하게 했다. 풀린 음원이 파일로 남지 않아 폰을 뒤져도 MP3가 나오지 않는다.
- 음원 714곡을 운영 키로 암호화해 운영 저장소에 올렸다. 은퇴곡 57곡은 재생에서 빠지니 뺐다(무료 용량 0.85GB 절약). 16분 걸렸고 실패는 없었다.
- 운영 키를 로컬과 같은 값으로 둘지 물었는데, 따져 보니 새 값이 맞았다. 올릴 때 로컬에서 평문으로 꺼내 운영 키로 새로 암호화하는 방식이라 맞출 이유가 없고, 로컬 키는 이미 여기저기 노출돼 있었다.
- 판매 방식을 바로잡았다. 매장을 직접 만나 계약하는 게 아니라 알아서 가입하고 결제해 쓰는 구조다. 이 전제가 바뀌면서 따라온 것을 한 번에 만들었다.
- 30초 미리듣기 — 구독하지 않은 사람에게는 서버가 앞 32초치만 주고 앱이 30초에서 자른다. 체험이 곧 판매 동선이다.
- 계정별 데이터 분리 — 가입한 매장끼리 스케줄표와 재생목록이 섞이지 않게 했다. 셀프 가입이면 두 번째 매장이 언제 올지 정할 수 없어서 출시 전 필수로 올렸다.
- 결제는 세 갈래를 다 열기로 했다. 웹에서 직접, 앱에서 웹 결제로 가는 링크, 앱 안 플레이 결제. 세금계산서가 필요한 매장은 웹으로, 편한 걸 원하면 플레이로 고른다.
- 구독 상태를 웹 결제와 플레이 결제로 나눠 적고, 전곡 권한은 둘 중 하나라도 살아 있으면 열리게 했다.
- 이유: 한 칸을 같이 쓰면 한쪽의 해지 알림이 다른 쪽에서 산 구독을 꺼 버린다.
- 앱 로그인 화면을 출시용으로 다듬었다. 서버 주소 입력칸을 배포본에서 숨기고, 가입할 때 약관·개인정보처리방침 동의를 받아 동의 시각을 남긴다. 앱과 웹에서 회원 탈퇴도 할 수 있다(플레이 정책상 앱에서 만든 계정은 앱에서 지울 수 있어야 한다).
- 계정당 동시 재생을 1대로 묶었다. 다른 기기가 재생 중이면 「이 기기에서 재생」 버튼으로만 가져온다.
- 이유: 가져가기를 자동으로 두면 두 기기가 곡마다 서로 뺏는다.
- 서비스 도메인의 첫 화면을 판매 페이지로 바꿨다. 소개, 요금·조건, 가입·로그인, 구독하기, 계정 삭제가 한 장에 있다. 요금은 전에 정한 월 1만원으로 적었다.
- 플레이 결제를 서버와 앱 양쪽에 붙였다. 앱이 결제하면 서버가 구글에 직접 물어 확인한 뒤에만 구매를 완료한다. 갱신·해지 알림도 받는다.
- 앱 식별자를
net.logstone.roomtone으로 확정했다. 한 번 올리면 영구히 못 바꾸고 구독 상품도 여기 묶인다. 최근 앱과 같은 규칙이다. - 반입·검수 도구가 운영 서버에 붙게 했다. 이관이 끝나 운영이 진짜 카탈로그가 됐는데 도구는 로컬만 보고 있었다.
- 플레이 업로드 서명 설정, 스토어 등록 문구, 데이터 보안 양식 답안을 준비했다. 개인정보처리방침에 새로 모으는 정보(기기 번호·플레이 구매·동의 시각)를 넣어 달라고 로그스톤 샵에 요청했다.
막힌 부분
- 결제 설정을 아직 안 넣은 상태에서 웹의 구독 버튼을 누르면 「플랜이 올바르지 않습니다」가 떴다.
- 원인: 상품 번호가 비어 있는 것과 요청이 틀린 것을 서버가 같은 오류로 돌려주고 있었다.
- 해결: 요청이 틀리면 400, 설정이 아직 없으면 503으로 가르고, 웹은 503일 때 「결제를 준비하고 있습니다」를 띄운다.
- 운영에서 파이썬 도구의 요청이 403으로 막혔다.
- 원인: Cloudflare가 파이썬 기본 요청 식별자를 봇으로 본다. 브라우저·curl·Node 요청은 통과한다.
- 해결: 도구 요청에 식별자를 붙였다.
- 운영 서버에서 9MB를 풀어 주는 게 무료 요금제의 요청당 CPU 한도에 걸릴지 몰랐다.
- 해결: 점검 명령을 만들어 운영에서 돌려 보니 3.1초에 정상이었다. 도구 방식을 바꾸지 않아도 된다.
미리듣기를 막다가 다른 문을 찾았다
30초 미리듣기를 설계하다, 같은 음원이 나가는 다른 경로 하나가 권한 확인이 느슨한 것을 찾았다. 실제로 샌 것은 없고 출시 전에 막았다.
- 해결: 그 경로를 관리자 전용으로 돌리고, 우회로 짐작되는 요청을 직접 넣어 전부 막히는 것을 확인했다.
- 교훈: 새 기능을 막을 때는 그 기능의 입구만 볼 게 아니라 같은 데이터가 나가는 다른 문을 찾아야 한다.
소리는 나는데 재생 바에 곡이 없었다
추천 재생목록을 틀면 소리는 나는데 하단 재생 바는 「재생 중이 아닙니다」였다.
재생 라이브러리의 play()는 이름과 달리 재생이 시작될 때가 아니라 곡이 끝나거나 멈출 때 끝나는 함수였다. 그걸 기다린 다음에 「지금 곡」을 적고 있어서, 첫 곡 내내 바가 비어 있고 둘째 곡부터는 한 곡씩 밀려 보였다.
await _audio.play(); // 곡이 끝날 때까지 여기서 기다린다
currentTrack = track; // 곡이 끝난 뒤에야 들어간다
같은 이유로 안 보이던 증상이 더 있었다. 둘째 곡부터 다음 곡 버튼이 안 먹었고, 첫 곡에선 일시정지가 안 됐고, 정시 전환 뒤에는 다음 스케줄 타이머가 그 곡이 끝날 때까지 걸리지 않았다. 정시 전환은 전환되는 순간만 확인했기 때문에 드러나지 않았다.
- 해결: 상태를 먼저 적고
play()는 기다리지 않되 재생 중 오류는 따로 받는다. 폰에서 제목 표시·다음 곡·일시정지를 확인했다.
처음 넣은 운영 키가 형식에 맞지 않았다
음원 이관을 두 곡만 먼저 돌렸는데 키를 읽는 첫 줄에서 멈췄다. 운영에 넣은 키가 10자짜리였다. 규격은 43자다.
서버는 키 형식을 검사하지 않아서 배포도 로그인도 멀쩡했고, 음원을 암호화하거나 푸는 순간에야 터지는 종류였다. 전체를 바로 돌렸다면 714곡을 못 쓰는 키로 올릴 뻔했다.
- 해결: 규격대로 새 키를 만들어 운영에 다시 넣고 재배포한 뒤 이관했다. 이관 스크립트는 형식이 틀린 키를 먼저 거절하고, 마지막에 운영 서버가 실제로 푸는지 확인한다.
- 교훈: 되돌리기 비싼 작업은 작게 한 번 끝까지 돌려 본다. 두 곡짜리 시험이 여기서 제값을 했다.
운영에 구독 중인 시험 계정이 딸려 들어가 있었다
어제 로컬 데이터베이스를 운영으로 옮길 때 계정까지 통째로 넣었다. 그 안에 개발용 시험 계정이 「구독 중」 상태로 남아 있었다. 출시 전에 지웠다.
- 해결: 운영에서 그 계정을 지웠다. 딸린 스케줄·재생목록은 없었다.
- 남은 것: 로컬 데이터를 운영으로 옮길 일이 또 있으면 계정은 걸러야 한다고 문서에 적었다. 운영 시험은 웹에서 새로 가입해서 한다.
다음에 할 일
- 폰의 릴리스 앱으로 운영 한 바퀴 — 가입, 30초 미리듣기, 회원 탈퇴
- 플레이 업로드 키 만들기
- 플레이 콘솔에 앱을 만들고 내부 테스트에 올리기
- 구독 상품(
roomtone_monthly, 월 10,000원)과 라이선스 테스터 등록 - 플레이 결제 연동 설정(서비스 계정·실시간 알림) 뒤 실결제 시험
- Creem 구독 상품 등록과 결제 비밀값 설정 — 결제 화면에 자동 갱신·무환불 다시 고지
- 앱 아이콘(아직 기본 아이콘)·스토어 그래픽·스크린샷
- 로그스톤 샵의 개인정보처리방침·환불 조항 갱신 회신을 받아 웹 페이지 문구 맞추기
- 두 기기로 동시 재생 제한 실물 확인
- 로그인 시도 횟수 제한 걸기
- 플레이 외부 결제 프로그램 등록 뒤 앱→웹 결제 링크 켜기
- 안드로이드 패키지에 딸려 오는 윈도우용 재생 엔진 빼기 검토(다운로드 6MB 남짓)
- 반입을 검수 콘솔로 통째로 옮기기 — 파일을 콘솔에 끌어다 놓고 프롬프트도 콘솔에서 입력(프롬프트 엑셀 제거), 그다음 분류·변환·업로드를 버튼 하나로(반입 배치 파일 은퇴)
- 검수 대기 15곡 마저 듣기
- 매장 안내방송 — 지정 시각에 한 번 끼어들고 복귀. 음원은 서버에 올리지 않고 기기의 로컬 파일을 고른다
- 보컬 검사를 여러 구간으로 넓히고 점수와 위치를 저장하기
- 검수 콘솔 끝잘림 18곡 페이드 처리
- 곡 제목을 한국어·영어 두 가지로
- 휴지통 30일 자동 정리 붙일지 검토
- 넓힌 키워드로 기존 곡 무드 백필
- 자동 분류가 안 된 5곡 에너지를 귀로 확정
- 앱 화면 더 다듬기 — 카드·가로 스크롤, 자켓 4분할, 셔플·반복 점 표시
Series: 룸톤 Roomtone
1 | 룸톤 Roomtone 2 | 룸톤 Roomtone 1 3 | 룸톤 Roomtone 2 4 | 룸톤 Roomtone 3 5 | 룸톤 Roomtone 4 6 | 룸톤 Roomtone 5 7 | 룸톤 Roomtone 6 8 | 룸톤 Roomtone 7 9 | 룸톤 Roomtone 8 10 | 룸톤 Roomtone 9 11 | 룸톤 Roomtone 10 12 | 룸톤 Roomtone 11 13 | 룸톤 Roomtone 12 14 | 룸톤 Roomtone 13 15 | 룸톤 Roomtone 14 16 | 룸톤 Roomtone 15 17 | 룸톤 Roomtone 16 읽는 중 18 | 룸톤 Roomtone 17 19 | 룸톤 Roomtone 18 20 | 룸톤 Roomtone 19 21 | 룸톤 Roomtone 20 22 | 룸톤 Roomtone 21