글 목록으로

AI 모델5.6 Sol

Kill Bet 개발 이야기 1호: Overwatch 점수방 공개 안내

GOTO 개발팀이 Kill Bet의 Overwatch 점수방을 만들며 정리한 계산 규칙, 공유 방 구조, 화면 UX, 공개 전 검증 내용을 안내드립니다.

주황색 방패와 교차한 두 검 아래 Kill Bet 이름이 적힌 로고만든 기록

안녕하세요, GOTO 개발팀입니다.

이 글은 2026년 8월 27일 처음 공개한 뒤, 9월 1일 운영 배포와 최종 검증 결과를 반영해 보완했습니다.

이번 Kill Bet 개발 이야기 1호에서는 Kill Bet의 Overwatch 점수방을 공개하기까지의 과정을 안내드립니다. Kill Bet은 친구들과 게임 기록을 입력하고 점수 경쟁을 확인할 수 있도록 만든 파티 점수판입니다.

GOTO 개발팀은 아직 완성된 답을 가지고 서비스를 크게 발표하기보다, 작은 불편을 발견하고 직접 만들어 보며 다음 질문을 찾아가는 방식으로 프로젝트를 진행하고 있습니다. Kill Bet도 같은 방식으로 시작했습니다. 친구들과 Overwatch를 하고 난 뒤 기록을 점수로 바꾸고, 여러 판을 이어서 순위로 확인할 수 있으면 좋겠다는 생각이 출발점이었습니다.

현재 서비스는 Cloudflare Worker로 배포되어 있으며, 커스텀 도메인과 Go-To 서비스 목록 연결도 완료되어 있습니다. 서비스 주소는 https://kill-bet.goto-dev-world.com/ 입니다.

현재 운영 화면은 Overwatch 전용으로 정리되어 있습니다. 리그 오브 레전드(LoL)와 PUBG는 후속 실험으로 남겨두고, 이번 글에서는 Overwatch 점수방을 먼저 공개하기까지 GOTO 개발팀이 어떤 기준으로 기능과 화면을 정리했는지 말씀드리겠습니다.

1. 한 판 계산기에서 시작했습니다

처음부터 방 생성, 코드 참가, 실시간 공유를 모두 붙이지는 않았습니다. 먼저 확인해야 할 질문은 단순했습니다.

Overwatch 한 판의 기록을 어떤 규칙으로 점수로 바꾸면 친구들이 납득할 수 있을까?

초기 요청도 이 범위에서 시작했습니다.

킬, 어시, 데스, 힐량, 딜량만 집어넣어서 각 값에 배율을 정해서 한 판 끝날 때마다 값을 산출해서 총합 값을 계산해가는 것으로 하겠습니다.

그래서 첫 구현은 서버 없이 브라우저 안에서 끝냈습니다. localStorage에 기록을 저장하고, 기록 추가와 삭제, 전체 초기화, 누적 점수, 목표 점수 진행률, 역할별 배율 조정을 먼저 만들었습니다.

이 단계에서 중요한 것은 공유 기능이 아니었습니다. 점수식이 실제로 읽기 좋은지, 입력해야 하는 값이 너무 많지는 않은지, 여러 판을 누적했을 때 순위가 자연스럽게 보이는지를 먼저 확인하고자 했습니다.

2. 역할별 점수 규칙을 정리했습니다

Overwatch 기준 첫 입력 항목은 킬, 도움, 데스, 피해, 치유였습니다. 이후 탱커 역할에는 경감도 추가했습니다.

역할별 기본값은 다르게 두었습니다. 힐러는 도움과 치유의 비중이 크고, 딜러는 킬과 피해의 비중이 크며, 탱커는 도움과 경감까지 함께 보도록 잡았습니다.

역할킬 배율도움 배율피해 단위치유 단위경감 단위데스 조정무데스 보너스
탱커1.522508001000310
딜러311801000기본 OFF310
힐러21.5200500기본 OFF310

기본 점수는 좋은 기록을 먼저 더하는 방식입니다.

기본 점수 =
(킬 x 킬 배율)
+ (도움 x 도움 배율)
+ (피해 / 피해 단위)
+ (치유 / 치유 단위)
+ (경감 / 경감 단위)

가장 많이 고민한 값은 데스였습니다. 데스는 단순히 몇 점을 빼는 항목이라기보다 경기 전체의 안정성에 영향을 주는 값처럼 느껴졌습니다. 그래서 데스가 1 이상이면 기본 점수를 데스 x 데스 조정으로 나누고, 데스가 0이면 무데스 보너스를 더하는 방식으로 정리했습니다.

데스가 1 이상일땐 데스 x 데스패널티 배율로만 진행하겠습니다. 0데스일 때는 기본점수 + 0데스 보너스를 넣는 것으로 하겠습니다.

예를 들어 딜러가 킬 10, 도움 5, 데스 0, 피해 1800, 치유 0을 기록하면 다음과 같이 계산됩니다.

기본 점수 = (10 x 3) + (5 x 1) + (1800 / 180) + (0 / 1000)
          = 45

최종 점수 = 45 + 10
          = 55

점수가 길게 늘어지면 순위표가 읽기 어려워지기 때문에 최종 점수는 소수점 둘째 자리까지 반올림했습니다.

3. 공유 방과 실시간 갱신 구조를 붙였습니다

점수 규칙이 어느 정도 정리된 뒤에는 친구들이 같은 결과를 함께 볼 수 있어야 했습니다. 한 사람의 브라우저에만 기록이 남으면 결국 화면을 공유하거나 결과를 따로 보내야 하기 때문입니다.

그래서 실제 방 화면은 /rooms/[code] 구조로 만들었습니다. 방을 만들고, 친구가 6자리 코드로 참가하고, 준비 상태를 바꾼 뒤 경기를 시작하는 흐름입니다. 현재 /rooms 경로는 별도 목록 화면이 아니라 홈으로 이동하는 경로이고, 실제 공유 방은 코드가 붙은 /rooms/[code]에서 열립니다.

Supabase Realtime으로 MVP2를 설계하는 것으로 하겠습니다.

방 정보, 참가자, 역할별 점수 규칙, 라운드 기록은 Supabase DB에 저장합니다. 공유 방에서 저장하는 데이터는 방 코드와 게임 종류, 참가자 닉네임, 준비 상태, 점수 배율, 라운드 기록, 계산된 점수 snapshot입니다.

공개 전에는 보안 구조도 다시 정리했습니다. 현재 운영 구조에서는 브라우저가 Supabase table을 직접 읽지 않습니다. 참가자 인증을 통과한 Next API가 방 상태를 반환합니다. 참가자는 방 생성 또는 참가 시 participantId + participantSecret을 발급받고, DB에는 secret 원문이 아니라 hash만 저장합니다.

Realtime도 table direct subscription이 아니라 private Broadcast 방식으로 바꿨습니다. 클라이언트는 /api/rooms/[code]/realtime-token에서 짧은 TTL의 토큰을 받은 뒤 private room channel을 구독합니다. Broadcast payload에는 실제 방 데이터나 secret을 넣지 않고 room_changed 신호만 보내며, 클라이언트는 그 신호를 받으면 다시 인증된 API로 room state를 조회합니다.

방 정리는 방장이 방 폭파를 확정할 때만 실행됩니다. 이때 rooms 삭제를 기준으로 참가자, 역할 규칙, 라운드 기록이 cascade로 함께 정리됩니다. 브라우저를 닫거나 참가자가 방을 나가는 일만으로 방이 자동 삭제되지는 않으며, 자동 만료도 두지 않았습니다. 검증에서는 전체 데이터가 비었다고 쓰지 않고, 이번 E2E에서 생성한 코드만 대상으로 방과 종속 행의 잔여량이 0건인지 확인했습니다.

4. 기록표보다 점수판을 먼저 보이게 했습니다

공유 방을 만든 뒤에 화면을 다시 보니, 이 앱에서 중요한 화면은 긴 기록표가 아니었습니다. 친구들이 게임 후 가장 먼저 보고 싶은 것은 “내가 몇 점인지”, “누가 앞서고 있는지”, “1등과 몇 점 차이인지”, “다음 판에 얼마나 따라잡아야 하는지”였습니다.

그래서 공유 방은 누적 점수와 순위, 최근 흐름을 먼저 보여주는 점수판으로 정리했습니다. /calculator는 방에 들어가지 않고 한 판의 규칙과 예상 점수만 확인하는 단판 계산기로 분리했습니다.

개발 과정에서는 홈 화면을 밝은 파스텔 톤으로 정리하고, Overwatch만 활성화하면서 리그 오브 레전드(LoL)와 PUBG를 준비중 버튼으로 보여주는 흐름도 거쳤습니다. 다만 현재 공개 화면은 Overwatch 전용 홈입니다. 운영 화면에서는 Kill Bet · Overwatch를 앞에 두고, 새 방 만들기코드로 참가를 바로 선택하게 했습니다.

첫 화면을 다시 줄인 이유도 같은 맥락입니다. 처음 사용자는 방을 만들지, 친구 방에 들어갈지, 게임을 선택해야 하는지, 직접 방 코드를 정해야 하는지 한 번에 판단하기 어렵습니다. 그래서 방 만들기와 코드 참가를 명확히 나누고, 방 만들기는 자동 방 코드 생성을 기본값으로 바꿨습니다. 직접 방 코드를 정하는 기능은 보조 옵션으로 낮췄습니다.

방 생성과 참가 뒤의 체감도 줄였습니다. create/join 응답에 포함된 room state를 짧게 sessionStorage에 저장하고, /rooms/[code] 진입 시 bootstrap state로 로비를 먼저 보여줍니다. 서버 확인 요청과 private Broadcast 연결은 뒤에서 진행합니다. 사용자는 방 화면이 뜰 때까지 불필요하게 기다리지 않고, 로비와 준비 버튼을 먼저 볼 수 있습니다.

Overwatch 방 내부는 어두운 HUD 톤을 바탕으로 만들었습니다. 주요 배경은 #070b10#0f1720 계열이고, 주요 행동은 오렌지 계열, 상태와 보조 행동은 청록/파란 계열로 구분했습니다. 대기방은 “누가 들어왔고, 누가 준비했으며, 방장이 언제 시작할 수 있는지”를 바로 보게 하는 화면으로 다듬었습니다.

직접 써보며 입력 흐름도 다시 고쳤습니다. 기록 저장 후에는 다음 라운드 번호로 넘어가되 마지막 기준을 유지하게 했고, 모바일에서는 본문 저장 버튼보다 하단 sticky 저장 바를 우선했습니다. 경기 시작 순간에는 모든 참가자가 기록 입력 탭으로 이동하게 했습니다.

삭제나 방 나가기, 방 정리처럼 실수하기 쉬운 액션은 window.confirm 대신 앱 내부 ConfirmDialog로 통일했습니다. 기록을 정리하면 기존 URL에서 결과를 다시 볼 수 없다는 점도 확인 문구에 담았습니다.

대표 이미지는 방패와 교차한 두 검을 중심으로 한 Kill Bet 로고를 사용했습니다. 서비스 이름과 경쟁 점수판의 성격을 한눈에 보여 주는 이미지로 골랐습니다.

5. 배포와 검증을 진행했습니다

현재 서비스는 Cloudflare Worker로 배포되어 있고, 커스텀 도메인과 Go-To 서비스 목록 연결도 완료됐습니다. 서비스 주소는 https://kill-bet.goto-dev-world.com/ 입니다.

이 글에서 확인 가능한 기술은 Next.js, React, TypeScript, Supabase DB, Supabase private Broadcast, OpenNext Cloudflare adapter입니다. 개발 환경은 Codex 데스크톱 앱과 PowerShell을 사용했습니다. 초기 구현에 사용한 모델은 5.6 Sol입니다.

공개 전에는 빌드, 테스트, 보안 검증을 거쳤습니다. 글에는 내부 기준보다 실제로 확인한 항목을 중심으로 남겼습니다.

확인 항목 결과
npm run lint Pass
npm run typecheck Pass
npm run test Pass, 22 files / 141 tests
npm run build Pass
npm audit Pass, 0 vulnerabilities
Supabase E2E 방 생성, 참가, 실시간 갱신 흐름 확인
테스트 데이터 정리 이번 E2E에서 생성한 테스트 데이터의 잔여량 0건 확인
운영 URL Cloudflare Worker, 커스텀 도메인, Go-To 서비스 목록 연결, HTTP → HTTPS 전환과 주요 보안 헤더 확인

글에서 서비스를 연결할 때는 실제 운영 주소인 https://kill-bet.goto-dev-world.com/ 를 기준으로 둡니다.

6. 다음 실험도 준비하겠습니다

이번 글에서는 Overwatch 기준 흐름만 다뤘습니다. 아직 경기 기록 데이터가 충분하지 않아 기본 배율 밸런스가 완성됐다고 말하기는 어렵습니다. GOTO 개발팀은 실제 사용 기록과 피드백을 보며 기본값을 계속 조정해 나가겠습니다.

다음 작업으로는 LoL과 PUBG의 점수 체계와 화면 구조를 더 다듬을 예정입니다. 리그 오브 레전드(LoL)는 승리/패배 기반 LP 점수 레이스, PUBG는 스쿼드 중심 점수 경쟁으로 따로 정리할 계획입니다.

스크린샷 업로드 인증, OCR 기반 자동 기록 인식, 회원가입은 첫 운영 공개 범위에 넣지 않았습니다. 지금은 친구들이 직접 기록을 입력하고, 같은 방에서 점수와 순위, 최근 흐름을 확인하는 구조에 집중했습니다.

다음에 확인하고 싶은 것은 이 점수판이 실제 친구들 사이에서 경쟁감을 만들어주는지입니다. 기록이 저장되는 것만으로는 부족합니다. 친구들이 점수판을 보고 “다음 판에 따라잡아야겠다”고 느끼는지, 입력해야 하는 숫자가 게임 뒤의 흐름을 방해하지 않는지, 역할별 배율이 공정하게 느껴지는지를 직접 써보며 계속 고쳐가겠습니다.