코드 하나로 앱 두 개: 연예견에서 묘하냥이 나오기까지
묘하냥은 연예견과 같은 코드로 만든 고양이 버전이에요. 기능은 똑같고, 이름과 색, 로고, 문구만 달라요. 빌드할 때 어떤 브랜드인지 하나만 정하면 연예견이나 묘하냥이 나와요. 2026년 7월 1일에 시작해서 앱스토어에 두 앱이 모두 올라가기까지, 그리고 그 뒤로 남은 흔적을 정리하기까지의 기록이에요.
단계 0: 연예견을 그대로 둔 채 이음매 만들기
첫 원칙은 “연예견은 한 글자도 달라지지 않는다”였어요. 이미 쓰는 사람이 있는 앱이니까요. 그래서 브랜드 설정을 한곳(src/brand/)에 모으고, 아무것도 지정하지 않으면 지금의 연예견이 그대로 나오게 했어요. 색은 CSS 변수로 되어 있어서, 묘하냥일 때는 화면의 기준 색(코랄)을 캔디 핑크 계열로 덮어쓰기만 하면 됐어요.
앱 안의 문구는 사전 전체를 빌드할 때 한 번 훑어서 “연예견”을 “묘하냥”으로, “Pupstar”를 “Pawstar”로 바꿔요. 화면마다 고치는 대신 사전 단위로 바꾸니 빠뜨린 곳이 없었어요. iOS 빌드도 브랜드마다 하나씩, 두 개의 빌드 흐름을 만들었어요.
데이터는 하나, 관계는 브랜드마다
두 앱은 같은 데이터베이스를 써요. 계정도 하나라서 같은 계정으로 두 앱에 로그인할 수 있어요. 대신 아이, 게시물, 초대 같은 데이터에는 어느 브랜드의 것인지 표시가 붙고, 앱은 자기 브랜드의 데이터만 읽어요. 강아지와 고양이를 함께 키우는 사람은 두 앱을 같이 쓰되, 각 앱에는 그 앱의 아이만 보여요.
출시 뒤에 발견한 ‘연예견’들
여기까지는 계획대로였어요. 어려운 건 출시 뒤였어요. 코드 곳곳에 “이 앱은 연예견”이라는 가정이 숨어 있었거든요.
- 푸시 알림. 애플 푸시 서버에 보낼 때 앱 식별자를 연예견으로 고정해 두어서, 묘하냥 푸시는 전부 거절됐어요.
- 알림 목록. 브랜드 표시를 붙일 때 알림 표 하나를 빠뜨려서, 두 앱을 다 쓰는 사람은 다른 앱의 알림까지 받았어요.
- 링크. 약관, 개인정보처리방침, 초대 링크, 고객지원 이메일이 묘하냥 앱에서도 연예견 주소를 가리켰어요.
- 애플 로그인. 로그인에 쓰는 앱 식별자가 연예견으로 적혀 있었어요.
- 사진. 각 사이트가 다른 브랜드의 사진까지 함께 배포하고 있었어요. 묘하냥 사이트에 강아지 사진이 들어 있던 거죠.
빠뜨려도 새지 않게: 브랜드 벽
하나씩 고치다 보니, 다음에도 어딘가에서 브랜드 조건을 빠뜨릴 거라는 걸 인정하게 됐어요. 그래서 7월 16일, 앱이 모든 요청에 자기 브랜드를 헤더로 보내고, 데이터베이스가 그 헤더와 다른 브랜드의 줄은 아예 돌려주지 않는 규칙을 추가했어요. 앱 코드에서 조건 하나를 잊어도 다른 브랜드의 데이터가 보이지 않아요.
그런데 이 헤더가 또 다른 문제를 만들었어요. 서버 함수들이 허용하는 헤더 목록에 새 헤더가 없어서, 브라우저가 요청을 보내기 전 확인 단계에서 막혔어요. 그중 하나가 회원탈퇴였어요. 아무 오류 없이 조용히 동작하지 않았죠. 헤더를 허용 목록에 추가해서 고쳤어요.
사진 문제는 10월에 빌드가 다른 브랜드의 사진을 빼고, 어떤 페이지라도 빠진 파일을 가리키면 빌드가 실패하게 만들어서 막았어요.
정리하면
- 두 번째 브랜드를 만들 때 진짜 일은 색이 아니라, 코드 곳곳의 “당연히 이 앱” 가정을 찾는 거예요.
- 조건을 빠뜨릴 것을 전제로, 빠뜨려도 새지 않는 벽을 데이터베이스에 두는 게 안전했어요.
- 새 헤더나 새 규칙을 넣으면, 조용히 실패하는 곳이 없는지 확인해야 해요.
연예견 · 묘하냥 — 연예견(강아지)과 묘하냥(고양이)은 초대한 가족·친구에게만 우리 아이 사진을 나누는 비공개 사진 앱이에요. 홈 화면 위젯과 아이 목소리로 오는 알림이 있어요.