Skip to content

[Feat/#160] 행사 신청 자격을 서버 isFeeEligible로 판단 - #161

Merged
leegain1 merged 2 commits into
mainfrom
feat/#160-events-fee-eligibility
Nov 4, 2026
Merged

leegain1 merged 2 commits into
mainfrom
feat/#160-events-fee-eligibility

Conversation

@leegain1

@leegain1 leegain1 commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

#️⃣연관된 이슈

📚 스택 PR입니다 — base가 #159(feat/#158-events-api-integration) 브랜치예요. Files changed에는 이 PR 변경만 보입니다. 머지 순서: #159 → 이 PR. (#154·로그인 #172는 main에 머지됐고, 두 PR 모두 최신 main 위로 rebase했어요.)

✅ 서버 billilge/stream-server#241이 머지돼 dev 서버 상세 응답에 feePaidOnly·recruitType·capacity·isFeeEligible이 들어온 것을 확인했어요(11/5). 이 PR의 스키마(필수 필드)로 dev 응답 전체가 통과합니다. 운영 서버에 올릴 때도 서버 #241이 먼저 배포돼야 합니다 — 필드가 없으면 zod 검사에 걸려 모든 행사 상세가 에러 화면이 됩니다.

🎯 해결하려는 문제가 무엇인가요?

행사 상세는 납부자 전용 행사의 신청 자격을 /fee/me의 feeStatus === "PAID"로 판단하고 있다(#159 기준, #151에서 실 API). 문제는 두 가지다.

  • /fee/me는 앱 납부 요청 기록(student_transfer_statuses)만 본다. 그래서 납부자 명부(payers)에 있는 레거시 납부자를 미납으로 보고 신청 버튼을 막는다. 서버는 명부 기준이라 통과시킬 사람이다.
  • 상세가 행사와 학생회비를 같이 받아서, 납부자 전용이 아닌 행사도 학생회비 조회가 실패하면(dev 계좌 없음 404 등) 상세 전체가 에러 페이지가 된다.

목록·검색·홈의 "신청하기"는 신청서로 바로 가는데, 목록 응답에는 신청 자격이 없다. 그래서 미납자가 신청서를 다 쓰고 제출해야 거절된다.

❓ 왜 해결해야 하나요?

서버 billilge/stream-server#190(PR #241)이 상세 응답에 신청 조건(feePaidOnly·recruitType·capacity)과 isFeeEligible(납부자 명부 기준)을 넣었다. 미납자의 신청도 MEMBER_IS_NOT_PAYER(400)로 막는다. 화면이 서버와 같은 기준을 써야 신청 가능한 학생을 막지 않는다.

⭐ 어떻게 해결했나요?

1. 행사 상세 (44b03df)

  • 상세 응답 스키마(eventDetailSchema)의 신청 조건을 서버 계약대로 필수 필드로 바꾸고 isFeeEligible을 더했다. #159에서는 서버 반영 전이라 선택 필드였다. 타입(EventDetail)은 스키마에서 만든다.
  • 신청 버튼은 isFeeEligible로 막는다. 막힐 때 문구는 기존 "학생회비 납부자만 신청할 수 있어요"를 그대로 쓴다.
  • 상세에서 학생회비 조회(feeQueries)를 뺐다. 학생회비 조회가 실패해도 행사 상세는 그대로 뜬다.

2. 신청서 진입·제출 (7cdc148)

  • 신청서 화면이 양식과 행사 상세를 한 번에 받는다(useSuspenseQueries). 상세에서 들어왔으면 상세는 캐시에 있다.
  • 자격이 없으면 신청서 대신 행사 상세로 replace한다. 그러면 막힌 버튼 화면이 바로 나오고, 뒤로가기는 목록으로 간다. 새 화면은 만들지 않았다.
  • 제출이 MEMBER_IS_NOT_PAYER로 거절되면 "학생회비 납부자만 신청할 수 있어요." 토스트를 띄운다. 행사 상세도 무효화한다. 들어온 뒤에 명부에서 빠진 경우인데, 다시 받은 상세가 자격 없음이면 신청서가 상세로 넘어간다.

🧩 이 PR의 한계 & 트레이드오프

  • 목록 카드의 "신청하기"는 처음부터 막지 못한다 — 목록 API(GET /v1/app/events)에 신청 자격이 없다. 누르면 신청서 스켈레톤이 잠깐 보였다가 상세로 넘어간다. 카드에서 바로 막으려면 서버 목록 응답에 값을 더해야 한다(검색·홈도 같다).
  • 서버는 납부 확인을 마감 확인보다 먼저 한다. 그래서 마감된 납부자 전용 행사에 미납자가 제출하면 마감 화면이 아니라 납부자 토스트가 뜬다. 다만 마감된 양식은 진입할 때 먼저 마감 화면으로 가서, 이 경우는 거의 없다.
  • 레거시 납부자는 서버 #238(명부 계정 연결)이 머지되기 전까지 서버에서도 isFeeEligible=false다. 빌릴게·사물함과 같은 한계다.
  • coding-style.md 데이터 로딩 절의 select 예시("내 납부 상태 → 학생회비 화면·행사 상세")는 이제 행사 상세에 맞지 않는다. [Refactor/#153] API·도메인 조회 코드를 shared 폴더 구조로 정리 #154 문구라 여기서는 고치지 않았다.

⛓️ 기존 기능에 미치는 영향

  • 행사 상세가 학생회비를 조회하지 않는다. 학생회비 화면의 조회(feeQueries)는 그대로다.
  • #151과 합친 곳 — #151이 main에 먼저 머지돼 rebase 때 합쳤다. #151은 EventsDetailContent.tsx에서 학생회비를 feeQueries.me()로 조회하는데, 이 PR 쪽(학생회비 조회 없음)을 남겼다. FeeResponse import도 지웠다.

🔀 Edge Case & 실패 시나리오

서버 #241 계약대로 응답하는 목 서버로 375×812 브라우저에서 확인했다. JS 콘솔 에러는 없다(콘솔의 400은 일부러 돌려준 거절 응답 기록이다).

  • 납부자 전용인데 자격 없음(isFeeEligible: false) 상세 → 버튼 disabled "학생회비 납부자만 신청할 수 있어요", 대상 "소프트웨어융합대학 과학생회비 납부자 / 선착순 150명"
  • 목록에서 그 행사의 "신청하기" → 신청서가 아니라 /events/1 상세(막힌 버튼). 뒤로가기 → 목록
  • 납부자 전용이 아닌 행사 상세 → 대상 "소프트웨어융합대학 학생", 기존과 같음
  • 상세에선 자격 있음인데 제출이 MEMBER_IS_NOT_PAYER → "학생회비 납부자만 신청할 수 있어요." 토스트, 행사 상세 다시 받음
  • 실서버(dev) 확인 — 서버 #241 반영 뒤 dev 서버에 로그인해 GET 응답을 이 브랜치의 zod 스키마로 검사했다. 행사 목록, 행사 5건 상세(납부자 전용 1건 포함), 모집중 2건 양식, 신청내역 목록·상세가 모두 통과했다. 확인한 계정은 납부자 전용 행사(3번)도 isFeeEligible: true라서, 자격이 없어 막히는 경로는 실서버로 보지 못했다(위 목 서버 확인만 있음).
  • tsc -b --noEmit·biome check(기존 main.tsx 경고 1건)·vite build 통과 — rebase 뒤에도 다시 돌려 통과

📋 검토한 대안과 선택 이유

  • 제출 때 토스트만 — 신청서를 다 쓴 뒤에야 거절돼서, 진입할 때 상세로 보내는 쪽을 택했다.
  • 서버 목록 응답에 신청 자격 추가 — 카드에서 바로 막을 수 있지만 서버 목록·검색·홈 API를 모두 고쳐야 한다. 상세로 보내면 서버 수정 없이 같은 안내 화면을 보여 줄 수 있다.
  • isFeeEligible이 없을 때 신청 가능으로 보기(!== false) — 서버 #241 배포 전에 머지돼도 버튼이 막히지 않는다. 하지만 서버 계약이 확정됐으니 타입을 필수로 두고, 머지 순서로 맞추기로 했다.

💬 리뷰 포인트

  • [c] 신청서 진입 때 상세로 보내는 흐름 — 목록에서 누르면 스켈레톤이 잠깐 보였다가 상세로 넘어가는 게 괜찮은지
  • [c] 머지 순서(서버 #241 배포 뒤) — 지키지 않으면 상세 응답이 zod 검사에 걸려 모든 행사 상세가 에러 화면이 된다

@leegain1 leegain1 self-assigned this Nov 3, 2026
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 57172c81-7e72-4906-a18b-1392c773c028
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@leegain1
leegain1 marked this pull request as ready for review November 3, 2026 18:11
@leegain1
leegain1 force-pushed the feat/#158-events-api-integration branch from 770a7a4 to 7f489a5 Compare November 4, 2026 14:13
@leegain1
leegain1 force-pushed the feat/#160-events-fee-eligibility branch 2 times, most recently from 25f7e07 to 7cdc148 Compare November 4, 2026 14:46
Base automatically changed from feat/#158-events-api-integration to main November 4, 2026 15:03
@leegain1
leegain1 force-pushed the feat/#160-events-fee-eligibility branch from 7cdc148 to af7adf0 Compare November 4, 2026 15:04
@leegain1
leegain1 merged commit a9b1a97 into main Nov 4, 2026
1 check passed
@leegain1
leegain1 deleted the feat/#160-events-fee-eligibility branch November 4, 2026 15:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

행사 신청 자격을 서버 isFeeEligible로 판단

1 participant