MAKING · 제작기
로또르르 제작기: 넣었다가 뺀 것들의 기록
다른 프로젝트 안의 로또 게임을 떼어내 만든 번호 생성기 로또르르. 토스 인앱 대응과 미니앱 빌드, 분석 도구까지 붙였다가 전부 걷어내고 '추적 없는 웹앱'으로 돌아온 과정과, 용지 QR 스캔을 만든 이야기를 커밋 기록으로 돌아봤습니다.
로또르르는 한국 로또 6/45 번호를 뽑아 주는 웹앱입니다. 저장소의 첫 커밋은 2026년 5월 18일, 커밋 메시지의 첫 줄은 "별도 PWA로 분리한 초기 스캐폴드"입니다. 원래는 KKflow의 다른 프로젝트 안에 들어 있던 로또 게임이었고, 그것을 떼어내 독립된 앱으로 만든 것이 시작이었습니다. 저장소에 남은 커밋은 열 개 남짓으로 많지 않지만, 그 안에 "넣었다가 뺀 것"이 유난히 많습니다. 이 글은 그 기록을 따라간 제작기입니다. 코드는 Claude Code와 함께 작성했습니다.
첫날: 다섯 가지 추첨 모드
첫 커밋에 이미 지금 로또르르의 뼈대가 거의 다 들어 있었습니다.
- 추첨 모드 5가지 — 완전 랜덤, 홀짝 3:3, 저고 3:3, 합계 100~175, 내 패턴
- 동행복권 링크 — 회차 조회와 구매는 공식 사이트로 연결
- 클라이언트 전용 — 서버 없이 기록은 브라우저 저장소에만
- PWA 기본 — 웹 앱 매니페스트와 여섯 가지 크기의 아이콘
합계 100~175 모드는 화면에 "통계적으로 흔한 범위"라고 설명이 붙어 있습니다. 실제로 6개 번호의 합이 이 구간에 드는 조합이 전체의 약 79%입니다. 다만 흔한 범위라는 것이 당첨 확률이 높다는 뜻은 아닙니다. 그 이야기는 로또 6/45 확률 글에 따로 정리했습니다.
토스 안에서 열리는 로또 앱
같은 날 두 번째 커밋은 "optimize lottororo for Toss in-app browser"입니다. 토스 앱 안의 웹 화면(인앱 브라우저)에서 열렸을 때를 따로 다루기 시작했습니다.
- 접속한 환경이 토스 인앱인지 알아내는 판별 코드를 넣었습니다.
- 분석 도구(GA4)에 "토스 인앱 / 일반 웹" 구분을 붙여 따로 볼 수 있게 했습니다.
- 토스 안에서는 동행복권 링크를 같은 화면에서 열어 뒤로 가기가 자연스럽게 되도록 했습니다.
7월 1일에는 한 걸음 더 나아갔습니다. 커밋 기록에 "토스 인앱 출시 검토 후속 작업"이라고 적혀 있고, 토스 인앱 화면에서는 "사행성 정책을 고려해" 실제 구매로 이어지는 버튼과 안내 문구를 숨기고 당첨 결과 조회만 남겼습니다. 일반 웹에서는 구매 링크를 그대로 보여 주는 방식입니다. 그리고 7월 12일에는 토스 앱 안에서 돌아가는 미니앱 빌드까지 추가했습니다. 기존 화면 부품을 그대로 재사용해 별도의 미니앱 패키지를 만들고, 빌드 결과물 검증까지 마쳤다고 기록돼 있습니다.
그리고 전부 걷어내다
7월 29일, 분위기가 바뀝니다. 이날 커밋 하나의 제목은 "remove Toss mini-app integration and Google Analytics"이고, 본문 첫 줄은 이렇습니다.
"Web-only now: no analytics, no ads, no tracking of any kind."
토스 미니앱 빌드 설정과 전용 코드, 토스 인앱 판별 코드, 분석 도구 연결을 모두 삭제했습니다. 구매 버튼은 다시 어디서나 똑같이 보이게 했고, 개인정보처리방침에서 분석과 토스 관련 항목을 지우고 "추적하지 않는다"는 문장으로 바꿨습니다. 두 달 넘게 쌓은 토스 대응을 하루에 걷어낸 셈입니다.
왜 걷어냈는지는 커밋 기록에 적혀 있지 않습니다. 기록에 남은 것은 결과입니다. 지금의 로또르르는 분석 도구도, 광고도, 추적도 없는 웹앱입니다.
죽어 있던 다크 모드, 두 번
작은 버그 하나가 두 번에 걸쳐 고쳐진 기록도 있습니다.
- 7월 1일 — 다크 모드 스타일이 전부 "죽은 코드"였습니다. 스타일 도구(Tailwind)를 "다크 클래스를 붙이면 다크 모드" 방식으로 설정해 두고, 정작 그 클래스를 붙이는 코드가 어디에도 없었습니다. 시스템 설정을 따라가는 방식으로 바꿨습니다.
- 7월 29일 — 그런데 전역 스타일 파일에는 여전히 "다크 클래스가 있을 때" 적용되는 규칙이 남아 있었습니다. 방식을 바꾼 뒤로는 그 클래스가 붙을 일이 없으니, 다크 모드에서도 밝은 배경색이 유지되고 반투명 패널이 거의 흰색으로 남아 흰 글씨가 흰 배경 위에 올라가는 문제가 생겼습니다. 이 규칙들도 시스템 설정 기준으로 바꿨습니다.
설정을 한 곳에서 바꾸면, 그 설정을 전제로 쓰인 다른 곳까지 찾아서 함께 바꿔야 한다는 걸 보여 주는 기록입니다.
용지 QR을 찍으면 등수가 나온다
7월 29일에는 로또르르의 대표 기능이 된 용지 QR 스캔 당첨 확인이 들어갔습니다. 로또 용지에 인쇄된 QR 코드에는 회차와 고른 번호가 담겨 있습니다. 이걸 읽어서 그 회차의 당첨 번호와 비교하면 게임마다 몇 등인지 바로 알 수 있습니다.
- 카메라 스캔 — 브라우저에 내장된 바코드 인식 기능(BarcodeDetector)을 먼저 쓰고, 지원하지 않는 브라우저에서는 QR 해독 라이브러리(jsQR)를 그때 불러와 대신 씁니다.
- 사진 업로드 — 카메라 권한을 주기 싫거나 이미 찍어 둔 사진이 있으면 사진으로도 됩니다.
- 기기 안에서 처리 — 카메라 영상과 사진은 기기 안에서만 해독합니다. 서버로 가는 것은 당첨 번호를 조회할 회차 번호뿐입니다.
- 당첨 번호 조회용 중계 — 동행복권의 당첨 번호 데이터는 다른 사이트에서 브라우저로 직접 가져갈 수 없도록 막혀 있어서(CORS), 서버에 작은 중계 경로를 두고 결과를 캐시합니다. 아직 추첨하지 않은 회차는 "대기 중"으로 돌려줍니다.
- 결과 화면 — 맞은 번호를 강조해 보여 주고, 당첨이면 꽃가루 효과와 진동으로 알려 줍니다.
같은 날 결과 복사와 공유 버튼, 지난 추첨 기록(최대 10회), 게임별 홀짝·저고 비율 표시도 함께 들어갔습니다.
하루에 PR 여섯 개
7월 29일은 이 저장소에서 가장 바빴던 날입니다. QR 스캔과 위에서 말한 정리 외에도 작은 수정 네 개가 연달아 들어갔습니다.
- 검은 물방울 아이콘 — 아이콘과 공유 이미지에 물방울 이모지를 그대로 넣어 두었는데, 컬러 이모지 글꼴이 없는 환경에서 이미지를 만들면 이모지가 검은색 흑백 글리프로 그려졌습니다. 이모지 대신 물방울 모양을 직접 벡터로 그려 모든 아이콘을 다시 만들었습니다.
- 열리지 않는 구매 링크 — 동행복권 사이트가 개편되면서 예전 구매 페이지 주소가 더 이상 열리지 않았습니다. 온라인 구매는 어차피 공식 홈페이지 로그인이 필요하니, 항상 열리는 홈페이지 주소로 바꿨습니다.
- 개인정보처리방침 정리 — 연락처 항목을 뺐습니다.
- 한국어 줄바꿈 — 글자 단위가 아니라 어절 단위로 줄이 바뀌도록 고쳤습니다.
아직 반영되지 않은 다음 단계
저장소에는 8월 4일에 만들어진 개선 브랜치가 하나 더 있습니다. 전체 점검에서 찾은 버그 수정, 당첨 번호 조회와 내 번호 대조, 번호별 출현 빈도 통계, 오프라인에서도 번호를 뽑을 수 있게 하는 서비스 워커, 그리고 추첨·판정 로직을 화면 코드에서 분리하고 붙인 테스트 75개가 들어 있습니다. 화면이 처음 그려질 때 레이아웃이 크게 밀리던 현상(CLS)을 0.24~0.45에서 0으로 줄인 작업도 포함돼 있습니다. 다만 이 브랜치는 아직 실제 서비스에 합쳐지지 않았습니다.
돌아보며
로또르르의 기록에서 가장 눈에 띄는 것은 덜어낸 양입니다. 토스 인앱 대응, 미니앱 빌드, 분석 도구가 차례로 들어왔다가 한꺼번에 빠졌고, 남은 것은 "번호를 뽑고, 용지를 찍어 확인하는" 두 가지 일입니다. 번호 생성기라는 단순한 도구일수록 무엇을 더할지보다 무엇을 남길지가 더 어려운 결정이라는 걸 보여 주는 저장소입니다.