프로젝트에서 직접 겪은 문제를 문제 → 원인 → 해결 → 배운 점 순서로 기록합니다.
이 사이트의 리듬게임은 mp3를 넣으면 채보를 자동으로 만든다. 드럼·박자를 분석해 노트 시각을 고르고, 레인은 계단(D F J K), 트릴(D F K J), 연타 같은 익숙한 패턴으로 깐다. 패턴을 넣고 나서 '너…
웹 리듬게임은 기기마다 소리가 귀에 닿는 시각이 다르다. 스피커와 유선 이어폰은 수십 ms, 블루투스는 150ms가 넘기도 하고, 아이폰 사파리는 AudioContext.outputLatency 를 알려주지 않아서…
모든 게임 랭킹에 '달성 일자'를 넣기로 했다. 새 기록은 저장할 때 날짜를 넣으면 되지만, 몇 년 동안 쌓인 예전 기록에는 날짜 필드가 아예 없었다. 새 기록: 서버 시각만 허용 클라이언트 시계는 믿을 수 없어서…
2021년에 만든 멜론게임(합이 10이 되게 드래그해서 지우는 게임)을 다시 만들었다. 조건은 하나였다. 랭킹이 쌓여 있는 게임이라 판정·점수·시간은 한 치도 달라지면 안 된다 . 문제: 규칙이 그리기 코드 속에 섞…
리듬게임에 보스곡을 넣으면서 '매우 어려움 Lv18, 숫자만이 아니라 체감도 18'을 목표로 잡았다. 그런데 자동 채보기로 밀도를 아무리 올려도 레벨이 15에서 더 오르지 않았다. 원인: 채보기는 음원에 있는 타격만…
리듬게임을 개편하고 휴대폰으로 쳐 보니 노트가 내려오는 화면 전체가 찢어지고 깜빡였다. PC에서는 멀쩡했고, 게임 로직이나 판정에는 아무 문제가 없었다. 원인 1: 입력 지연을 줄이려고 켠 옵션 개편하면서 캔버스를…
2021년 Create React App으로 만든 이 사이트를 2026년에 Next.js App Router + TypeScript로 옮겼다. 기능은 그대로 두고 기반만 바꾸는 작업이었는데, 생각보다 걸리는 지점이…
개인공부 목록 페이지를 output: "export" 로 정적 생성했는데, 빌드된 HTML을 열어보니 글 링크가 하나도 없었다. 브라우저에서는 멀쩡히 보이는데 크롤러가 받는 HTML에는 목록이 통째로 빠져 있었다.…
개인공부 글을 빌드 시점에 Firestore에서 읽어 정적 페이지로 만들도록 바꿨다. 그런데 네트워크가 막힌 환경에서 빌드를 돌려보니 에러 없이 성공 했고, 글이 0개인 페이지가 만들어졌다. 원인 Firestore…
모바일에서 모달을 띄운 상태로 뒤로가기를 누르면, 모달이 닫히는 게 아니라 이전 페이지로 이동해버린다. 사용자 입장에서는 "닫기"를 누른 건데 페이지를 잃는 셈이다. 아이디어 모달이 열릴 때 같은 URL로 히스토리를…
주문·선물 안내 메시지에 상품 목록이 들어가는데, 상품이 여러 개면 내부에서 이어 붙일 때 쓰던 구분자( ||| )가 고객에게 그대로 보이는 문제가 있었다. 템플릿 메시지는 본문 길이 제한도 있어서 목록을 그냥 줄바…
주문서에서 "할인 금액이 가장 큰 쿠폰 조합"을 자동으로 골라주는 기능을 검토했다. 조건은 이렇다. 쿠폰마다 적용 가능한 상품 조건이 다르다. 한 상품에는 쿠폰 한 장, 쿠폰도 한 번만 쓸 수 있다. 주문 전체에 거…
파일 업로드 API에서 응답의 다운로드 URL을 ServletUriComponentsBuilder.fromCurrentContextPath() 로 만들었다. 로컬에서는 멀쩡했는데 운영에 올리자 http://10.x.…
한 서비스에서 주 DB와 문자 발송용 DB를 둘 다 JPA로 붙여야 했다. 설정 클래스를 하나 더 만들었더니 기동 단계에서 이런 에러가 났다. The bean 'entityManagerFactory', defined…
여러 배송지를 한 번에 입력하는 모달에서, 엑셀을 업로드해 주소 목록을 채운 뒤 "검증" 버튼을 누르면 빈 목록 기준으로 검증되는 버그가 있었다. 화면에는 주소가 분명히 보이는데 핸들러는 예전 값을 보고 있었다. 원…
시즌 이벤트 페이지에 댓글을 달면 포인트를 주는 API를 만들었다. 포인트 지급은 다른 시스템의 API를 HTTP로 호출해야 했고, 요구사항은 두 가지였다. 포인트 지급이 실패해도 댓글은 남아야 한다. 포인트는 회원…
관리자 기능 곳곳에 if (isAdmin(user) || isCsManager(user)) 같은 조건이 서비스, 컨트롤러, JSP에 흩어져 있었다. 특정 담당자에게 기능 하나만 열어주려 해도 코드를 고치고 배포해야…
게시판처럼 사용자가 HTML을 입력할 수 있는 기능은 저장형(Stored) XSS의 단골 대상이다. 공격 스크립트가 DB에 저장되면, 그 글을 여는 모든 사용자의 브라우저에서 실행된다. <img src=x onerr…
로그인에 5번 연속 실패하면 계정을 잠그는 기능이 있었다. 그런데 관리자가 잠금을 풀어준 계정이 비밀번호를 한 번만 틀려도 바로 다시 잠기는 문제가 들어왔다. 원인: 잠금 해제가 이력에 남지 않음 연속 실패 횟수를…
본인인증 모듈을 연동하면서 요청 데이터를 암호화한 뒤 Base64로 인코딩해 넘기는 부분이 있었다. 로컬에서는 잘 되는데 특정 서버에서만 "데이터 형식 오류"가 났다. 인코딩 결과를 로그로 찍어보니 문자열 중간중간에…
음성채팅 서비스를 만들면서 가장 오래 붙잡은 문제는 "통화 중 새로고침"이었다. 새로고침하면 RTCPeerConnection , 마이크 스트림, 소켓 연결이 전부 사라지기 때문에 통화가 그대로 끊긴다. 무엇을 서버에…
WebRTC 통화가 우리 집 와이파이에서는 되는데 특정 회사망이나 모바일 네트워크에서는 연결되지 않는 경우가 있었다. 원인은 NAT였다. STUN: 내 공인 주소 알아내기 공유기 뒤에 있는 기기는 자신의 공인 IP/…
핸드메이드 쇼핑몰 프로젝트에서 같은 옵션 상품을 여러 명이 동시에 결제하면 재고보다 많이 팔릴 수 있는 문제가 있었다. 당시에는 PG 결제 승인 요청 직전에 옵션별 재고를 다시 확인하는 방식으로 막았다. // 결제…
쇼핑몰 프로젝트에서 "장바구니로 여러 상품을 한 번에 결제한 뒤, 그중 하나만 환불"하는 요구사항이 있었다. 주문 테이블 하나에 결제 정보와 상품 정보를 같이 두면 이 요구를 표현할 수가 없다. 상품 구조부터 상품은…