빈 화면과 끊기는 로그인을 줄인 가족용 맞고 웹게임 개선기
2026년 10월 24일 업데이트 — 맞고와 고스톱을 고르는 가족 화투
현재 FamilyHwatu 프로젝트는 2인 맞고뿐 아니라 3인 고스톱도 포함한다. 게임 선택 화면에서 두 모드로 나뉘고 난이도별 AI와 게임 저장, 무르기, 게임머니 리필과 기록 통계를 제공한다. 아래 글의 빈 화면과 로그인 개선은 당시 해결한 문제에 관한 기록이며 지금의 전체 게임 구성을 맞고 하나로 한정하지 않는다.

게임 선택 뒤에는 모드별 대기실과 게임 화면으로 이어진다. 맞고·고스톱의 승률, 최고 점수, 연승과 특수 상황 통계를 구분해 확인할 수 있다. 화면의 게임머니는 게임 안에서 사용하는 값이다. 이 글의 두 캡처는 프로젝트에 이미 있는 개발용 미리보기로 실행했으며 ‘어머니’라는 표시명과 잔액·저장 턴은 미리보기용 예시다. 실제 가족 계정이나 경기 이력은 가져오지 않았다.

프로젝트의 운영 범위도 덧붙인다. 가족이 사용할 전용 환경을 만들기 위한 개인 프로젝트이며 소스 코드 공개와 일반 사용자를 위한 서비스 운영은 구분한다. 공개 저장소가 있다고 해서 누구나 운영 서버에 가입하거나 이용할 권한을 얻는 것은 아니다.
이번 갱신은 로컬의 현재 화면과 기능 문서를 확인한 작업이다. 운영 로그인과 실제 게임 저장·정산을 다시 시험한 것은 아니므로 아래에 남긴 과거 검증 결과를 이번 캡처만으로 확대하지 않는다. 초기 로딩, 일시적인 로그인 실패 처리와 안내 페이지를 정리한 과정은 당시 기록으로 이어서 보존한다.
이전 개발 기록
아래는 최초 작성 당시의 개발 기록이다. 현재 기능과 화면은 위 업데이트 내용을 우선한다.
게임 기능 다음에 다듬어야 했던 것
이 프로젝트는 가족 구성원이 각자 계정으로 접속해 컴퓨터와 맞고를 즐기는 웹게임입니다. 최근 확정된 구현에는 회원 인증, 사용자별 게임머니, 진행 중인 판 저장, 여러 단계의 컴퓨터 난이도, 자동치기, 효과음과 음성, 설치형 웹앱 기능이 포함됐습니다.
게임 규칙이 갖춰진 뒤에는 게임 자체보다 서비스에 들어가는 과정에서 개선할 부분이 드러났습니다. 기존 HTML은 React가 실행되기 전까지 화면에 표시할 내용이 없었고, 서버가 늦게 준비되면 로그인 요청이 한 번 실패한 뒤 사용자가 다시 시도해야 했습니다. 서버 내부 오류도 항상 같은 형식으로 전달된다는 보장이 없었습니다.
또한 화투 이미지 출처 페이지는 있었지만 개인정보 처리방침과 자체 소스의 라이선스를 별도로 확인할 경로가 없었습니다. 게임판에서는 바닥패 영역의 위아래 여백도 가로 화면에서 조금 더 균형 있게 조정할 필요가 있었습니다.
첫 화면부터 빈틈을 없앤 로딩 구조
가장 눈에 띄는 변화는 초기 로딩 화면입니다. 이제 React 코드가 아직 내려오지 않았더라도 기본 HTML과 전용 CSS만으로 브랜드 영역, 카드 모양, 진행 상태가 즉시 표시됩니다. 자바스크립트가 준비되면 같은 형태의 React 로딩 컴포넌트가 자연스럽게 이어받습니다.
- 빈 화면 대신 정적인 로딩 화면을 먼저 표시합니다.
- 브라우저의 안전 영역을 고려해 휴대폰과 태블릿에서도 내용이 잘리지 않게 했습니다.
- 움직임 감소 설정을 사용하는 기기에서는 진행 애니메이션을 정지시킵니다.
- 로딩 CSS를 설치형 웹앱 캐시에 포함하고 캐시 버전을 갱신했습니다.
서비스 워커는 화면과 카드 같은 정적 자산만 저장합니다. 로그인이나 게임 저장 API 응답은 캐시 대상에서 제외해 오래된 인증 정보나 게임 결과가 재사용되지 않도록 구분했습니다.
서버가 늦게 시작되어도 로그인은 스스로 복구한다
로그인 흐름은 실패 원인에 따라 다르게 동작하도록 바뀌었습니다. 네트워크 단절이나 서버 준비 중에 발생할 수 있는 오류만 자동 재시도하고, 잘못된 아이디나 비밀번호처럼 사용자가 확인해야 하는 오류는 즉시 안내합니다.
- 로그인 전에 CSRF 보안 토큰을 발급받습니다.
- 토큰이 만료됐다면 새 토큰을 받은 뒤 요청을 한 번 다시 보냅니다.
- 네트워크 오류나 일시적인 서버 오류가 발생하면 짧게 기다린 뒤 재시도합니다.
- 대기 시간은 0.5초부터 점차 늘어나지만 최대 5초를 넘지 않습니다.
- 화면에는 자동 재시도 횟수와 서버 연결 대기 상태를 표시합니다.
- 로그인 창을 닫거나 화면을 벗어나면 진행 중인 요청과 대기를 즉시 중단합니다.
서버에도 전역 오류 처리기를 추가했습니다. 처리되지 않은 예외가 발생하더라도 프런트엔드가 이해할 수 있는 공통 JSON 형식과 사용자용 메시지를 반환합니다. 덕분에 HTML 오류 페이지나 해석할 수 없는 응답 때문에 안내가 사라지는 상황을 줄였습니다.
자동 재시도는 모든 실패를 숨기는 기능이 아닙니다. 인증 실패와 과도한 로그인 시도 제한처럼 다시 보내도 해결되지 않는 응답은 반복하지 않습니다.
프런트엔드와 백엔드는 이렇게 연결된다
프런트엔드
React 화면은 입장, 로그인, 대시보드, 가족 계정 관리, 게임, 출처와 정책 페이지로 나뉩니다. 실제 맞고 규칙은 별도의 TypeScript 게임 엔진에서 처리하며 점수 계산, 고·스톱, 폭탄, 흔들기, 미션과 특수패 판정을 화면 코드와 분리했습니다.
게임 상태는 먼저 브라우저의 IndexedDB에 저장됩니다. 서버에 연결할 수 있으면 같은 상태를 서버에도 전송하고, 연결할 수 없으면 기기 저장본을 유지합니다. 다시 게임을 열 때는 판의 생성 시각과 진행 턴을 비교해 더 최근 상태를 선택합니다.
백엔드
.NET 기반 API는 로그인 세션, 가족 계정, 게임 저장과 게임머니 정산을 담당합니다. 데이터베이스에는 계정별 저장 슬롯과 전적을 보관합니다. 저장 요청에는 게임 식별자, 상태 버전, 턴 번호와 상태 크기 검증을 적용합니다.
정산은 트랜잭션 안에서 현재 잔액을 잠근 뒤 처리합니다. 동일한 게임 결과가 다시 도착했을 때 이미 기록된 정산을 재사용하므로 중복 요청으로 게임머니가 두 번 반영되는 일을 막습니다. 같은 판의 오래된 턴이 더 최신 저장 상태를 덮어쓰지 않도록 턴 번호도 비교합니다.
사용자가 이용하는 방법
- 서비스를 열면 즉시 로딩 화면이 나타납니다.
- 가족 계정의 아이디와 비밀번호를 입력합니다. 개인 기기라면 로그인 유지 옵션을 사용할 수 있습니다.
- 대시보드에서 진행 중인 판을 이어 하거나 점당 가상 게임머니를 선택해 새 판을 시작합니다.
- 게임 시작 전 컴퓨터 난이도와 선공을 고른 뒤 패를 선택해 진행합니다. 필요하면 자동치기도 켤 수 있습니다.
- 게임 도중 나가더라도 판은 기기에 저장되며, 서버 연결이 가능하면 계정 저장본과 동기화됩니다.
- 화면 하단에서 개인정보 처리방침, 자체 코드의 MIT 라이선스, 화투 이미지의 별도 출처와 라이선스를 확인할 수 있습니다.
최근 게임판 조정에서는 바닥 덱과 바닥패 영역만 화면 높이에 따라 약 8~16픽셀 위로 이동시켰습니다. 카드 크기와 좌우 간격, 선택 안내창의 상대 위치는 유지해 기존 조작감을 바꾸지 않으면서 세로 여백의 균형을 맞췄습니다.
안정성과 보안에서 확인한 부분
- 비밀번호는 원문이 아니라 단방향 해시로 저장합니다.
- 인증 쿠키에는 자바스크립트 접근 제한과 사이트 간 전송 제한을 적용했습니다.
- 데이터를 변경하는 요청은 CSRF 토큰을 검증합니다.
- 로그인 API에는 IP 기준 요청 제한을 적용했습니다.
- 콘텐츠 보안 정책, 프레임 삽입 차단, 콘텐츠 유형 보호 등의 응답 헤더를 설정했습니다.
- 관리자와 일반 가족 계정의 권한을 구분하고, 중지되거나 인증 버전이 바뀐 계정의 기존 세션을 거부합니다.
- 게임 저장 크기와 정산 금액을 서버에서 다시 검증하며 클라이언트 계산만 신뢰하지 않습니다.
- 개인정보와 자체 코드, 제3자 카드 자산의 적용 조건을 서로 다른 페이지에서 구분해 안내합니다.
로그인 복구 테스트에는 만료된 보안 토큰, 반복되는 네트워크 오류, 서버 준비 지연, 사용자 취소, 잘못된 비밀번호를 재시도하지 않는 경우가 포함됐습니다. 로딩 화면과 정책 페이지의 필수 문구 및 연결 경로를 확인하는 테스트도 추가됐습니다.
최근 확정 버전에는 전체 테스트와 타입 검사, 프런트엔드 빌드를 완료한 기록이 있습니다. 현재 후속 변경은 타입 검사와 변경 형식 검사를 통과했지만, 이번 읽기 전용 분석 환경에서는 임시 파일 생성 제한 때문에 최신 전체 테스트를 다시 완료하지 못했습니다.
결과: 게임을 시작하기 전 경험까지 하나의 기능으로
이번 개선의 핵심은 새로운 맞고 규칙을 더하는 데 있지 않습니다. 사용자가 주소를 연 순간부터 로그인하고, 저장된 판을 불러오고, 정책을 확인하는 과정까지 끊기지 않도록 연결한 작업입니다.
초기 빈 화면은 명확한 로딩 상태로 바뀌었고, 일시적인 서버 지연은 자동 복구할 수 있게 됐습니다. 저장은 기기와 서버를 함께 활용하면서 중복 정산과 오래된 상태 덮어쓰기를 방지합니다. 정책과 라이선스도 서비스 안에서 직접 확인할 수 있습니다. 게임판의 작은 위치 조정까지 더해져 기능뿐 아니라 실제 사용 흐름의 완성도가 한 단계 높아졌습니다.
댓글 0
댓글 남기기