⏰🚨 선착순 강의 신청에서 “이미 신청했는데 다시 신청 가능?” 문제 해결

2026. 3. 6. 23:39·프로젝트/스프링 부트 3 백엔드 개발자 되기 Blog + 선착순 강의 프로젝트

1️⃣ 문제 상황

Spring Boot + Redis 기반 선착순 강의 신청 시스템을 구현하던 중,

다음과 같은 문제가 발생했다.

❗ 문제 증상

  1. 사용자가 이미 강의를 신청한 상태
  2. 다시 상세 페이지(/lectures/{id})에 진입
  3. "신청하기" 버튼 클릭

👉 결과:

  • ❌ "대기열 정보가 없습니다. 다시 신청하기 버튼을 눌러주세요."
  • ❌ 다시 대기열 진입 가능
  • ❌ 결제 페이지까지 다시 이동 가능

👉 정상이라면?

  • "이미 신청한 강의입니다."
  • 버튼은 "신청 완료" 상태여야 함

2️⃣ 원인 분석

1. 백엔드는 이미 정상

Postman으로 확인:

GET /api/lectures/1/enroll/me

응답:

{
  "status":"ENROLLED",
  "lectureId":1,
  "lectureTitle":"Redis 기반 대규모 선착순 수강신청 실전"
}

👉 즉, DB 기준으로는 이미 신청된 상태

2. 문제는 프론트(detail.html)

프론트에서는 /queue/me 응답을 이렇게 처리하고 있었다:

if (data.status==="QUEUED") {
  	...
}else if (data.status==="SUCCESS") {
  	...
}else {
	// ❌ 여기에 걸림
	"대기열 정보가 없습니다..."
}

👉 그런데 서버는 ENROLLED를 내려주고 있었음

👉 프론트는 ENROLLED를 모름 → 무조건 else로 떨어짐

💥 핵심 원인

👉 상태값(status)을 프론트에서 처리하지 않아서 발생한 문제

  • 백엔드: ENROLLED 정상 반환
  • 프론트: ENROLLED를 모름 ❌

3️⃣ 해결 방법

✅ 1. ENROLLED 상태를 프론트에서 처리

공통 처리 함수 추가

function renderEnrolled(message) {
  stopPolling();
  spinner.classList.add("hidden");
  resultArea.classList.remove("hidden");

  resultText.innerHTML = `
    <div class="mb-2">✅</div>
    <span class="text-gray-900 font-bold text-lg">신청 완료</span><br>
    <span class="text-xs text-gray-500">${message || "이미 신청한 강의입니다."}</span>
  `;

  applyBtn.textContent = "신청 완료";
  applyBtn.disabled = true;
}

✅ 2. 폴링 함수에 ENROLLED 처리 추가

if (data.status === "ENROLLED") {
  renderEnrolled(data.message);
  return;
}

✅ 3. 신청하기 버튼 클릭 시에도 처리

const data = await Token.apiFetch(`/api/lectures/${lectureId}/queue`, { method: "POST" });

if (data.status === "ENROLLED") {
  renderEnrolled(data.message);
  return;
}

✅ 4. 페이지 진입 시에도 체크

window.addEventListener("load", async () => {
  const data = await fetchMyQueueStatus();

  if (data.status === "ENROLLED") {
    renderEnrolled(data.message);
  }
});

4️⃣  결과

이제 동작 흐름은 다음과 같다:

상태 결과
NOT_ENROLLED 신청하기 버튼
QUEUED 대기열 표시
SUCCESS 결제 페이지 이동
✅ ENROLLED 신청 완료 표시 + 버튼 비활성화

5️⃣ 배운 점

1. 상태(status)는 반드시 프론트/백엔드 모두 정의해야 한다

  • 백엔드만 정의하면 의미 없음
  • 프론트도 반드시 처리해야 함

2.  “마지막 else”는 항상 의심해야 한다

else {
	"대기열 정보 없음"
}

👉 여기에 숨겨진 버그가 많다

3. API 테스트(Postman)는 필수

  • DB 상태 vs 화면 상태가 다를 때 👉 Postman으로 확인하면 바로 원인 분리 가능

4. UX는 “데이터”보다 “상태 표현”이 중요하다

  • 이미 신청했는데 다시 신청 가능하면 UX 망가짐
  • 상태 기반 UI 설계가 핵심

'프로젝트 > 스프링 부트 3 백엔드 개발자 되기 Blog + 선착순 강의 프로젝트' 카테고리의 다른 글

⏰💡 오픈 시간(openAt) 전에는 신청 버튼 막기 + 카운트다운 표시  (0) 2026.03.07
⏰🚨 “입장권이 있는데도 apply 페이지에서 입장권 없음 오류 발생”  (0) 2026.03.06
⏰💡 선착순 강의 Redis 대기열(ZSET) + 입장권 원자화 + 소비(consume) 적용하기 (Lua 1개로 끝)  (0) 2026.02.26
⏰🚨 선착순 강의 신청 페이지에서 버튼이 동작하지 않던 문제 해결  (0) 2026.02.23
⏰💡 소셜 로그인 + 선착순 강의 신청 시스템 통합 (JWT 기반 userId 전환)  (1) 2026.02.23
'프로젝트/스프링 부트 3 백엔드 개발자 되기 Blog + 선착순 강의 프로젝트' 카테고리의 다른 글
  • ⏰💡 오픈 시간(openAt) 전에는 신청 버튼 막기 + 카운트다운 표시
  • ⏰🚨 “입장권이 있는데도 apply 페이지에서 입장권 없음 오류 발생”
  • ⏰💡 선착순 강의 Redis 대기열(ZSET) + 입장권 원자화 + 소비(consume) 적용하기 (Lua 1개로 끝)
  • ⏰🚨 선착순 강의 신청 페이지에서 버튼이 동작하지 않던 문제 해결
hak0622
hak0622
개발하면서 “이게 뭐지?”라는 순간마다 궁금한 점을 바탕으로 정리한 개발 블로그입니다.
  • hak0622
    궁금한 개발 이야기 Why?
    hak0622
  • 전체
    오늘
    어제
    • 분류 전체보기 (68)
      • 공부 (36)
        • 1. 자바 ORM 표준 JPA 프로그래밍 - 기본.. (35)
        • 시험 (1)
      • 프로젝트 (32)
        • 스프링 부트 3 백엔드 개발자 되기 Blog + .. (32)
  • 인기 글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
hak0622
⏰🚨 선착순 강의 신청에서 “이미 신청했는데 다시 신청 가능?” 문제 해결
상단으로

티스토리툴바