앱 웹뷰에서 동작하는 광고 기반 출석·보상 게임입니다.
프론트엔드 구현을 전담해 개발 3일 + QA 2일, 5일 만에 출시했습니다.
아래 보드는 실제 게임과 같은 슬라이딩 규칙으로 동작합니다.
펭귄은 민 방향으로 벽에 부딪힐 때까지 미끄러지고, 중간에 멈출 수 없습니다.
펭귄을 한 번 미는 흐름을 기준으로 역할을 나눴습니다. 층끼리 서로를 모르게 해서, 각각 따로 만들고 마지막에 조립할 수 있었습니다.
export const slideFrom = (pos: Position, dir: Direction, board: CollisionBoard): Position => { let current = pos while (true) { const next = step(current, dir) if (isBlocked(next, board)) return current // 벽이나 경계 직전 칸에서 멈춘다 current = next } }
처음엔 setInterval이 실행될 때마다 0.25초씩 더했는데, 웹뷰가 백그라운드로 가면 실행이 늦춰지거나 멈춰서 시간이 덜 흘렀습니다. 그래서 실행 횟수 대신 시작 시각과의 차이로 계산하도록 바꿨습니다.
하루 수천 대의 기기에서 User ID 없이 이벤트가 쌓이는 문제가, 1년 넘게 이어지고 있었습니다.
문제 브릿지가 응답하지 않으면 에러도 나지 않아 에러 캡처 코드가 실행되지 않았고, 그래서 월 18건으로 실제보다 훨씬 적게 집계되고 있었습니다.
해결 5초 타임아웃으로 '응답 없음'을 실패로 바꿔 셀 수 있게 하고, 원인별로 태깅했습니다
(timeout · missing_user_id · bridge_error. 자체 호스팅 Sentry 부하는 10% 샘플링 후 집계 때 10배 역산)
재보니 처음 원인으로 의심한 앱-웹 브릿지 무응답은 일 ~350대로 일부였습니다.
대부분은 SDK가 초기화되기 전에 넣은 User ID(setUserId)가 내부 큐에서 사라지는 경우였고, 이 경로만 일 ~4,300대였습니다.
인증 게이트 — 앱에서 User ID를 받을 때까지 하위 화면을 렌더하지 않아서, User ID 없이 이벤트가 나갈 수 없습니다.
자체 버퍼링 — SDK 초기화는 렌더와 별개로 진행되고, 그사이 발생한 이벤트는 웹 버퍼에 모아뒀다가 초기화가 끝나고 User ID를 다시 넣은 뒤에 내보냅니다.
일별 익명 적재 기기 — 인증 게이트 + 버퍼링 완전 적용 첫날 4,000+ → 0 (커밋 기록 기준)
주간 게임 보상 수령 건수입니다. 첫 주 이후에도 줄지 않아,
일회성 이벤트가 아니라 매일 돌아오는 사용 패턴으로 자리 잡았습니다.
주간 보상 수령 이벤트 (Amplitude 실측) · 누적 사용자 62,000+명 · 누적 수령 590,000+건