Skip to content

[Feat/#151] 학생회비 납부 요청을 한 번에 받고 반려 시 재납부 허용 - #155

Open
xeoxxn wants to merge 5 commits into
refactor/#150-fee-rejected-statusfrom
feat/#151-fee-single-step-request
Open

xeoxxn wants to merge 5 commits into
refactor/#150-fee-rejected-statusfrom
feat/#151-fee-single-step-request

Conversation

@xeoxxn

@xeoxxn xeoxxn commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

#️⃣연관된 이슈

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

학생이 회비를 내려면 요청을 두 번 보내야 했습니다.

  1. POST /v1/app/fee — 남은 학기 수 + 학점이수현황 캡처 제출 (상태는 납부 전 그대로)
  2. POST /v1/app/fee/requests/confirm — 송금 후 확인 요청 → 납부확인중

그래서 "제출만 하고 이탈한" 학생을 나타내려고 UNPAID 행이 필요했고, 관리자 목록에 납부 전 회원을 띄우려고 V21이 전 회원에게 UNPAID 행을 만들고 로그인할 때마다 행을 만들었습니다. 또 확인필요로 돌려받은 학생은 직접 다시 낼 수 없어서 운영진이 납부 전으로 되돌려줘야 했습니다.

❓ 왜 해결해야 하나요?

  • 바뀐 납부 흐름(학기 인증 캡처 → 송금 링크 → 토스 송금 → "송금 완료했어요")에서 학생이 실제로 결정하는 순간은 "송금 완료했어요" 한 번입니다. 그 앞 단계는 링크를 계산해 보여줄 뿐이라 저장할 이유가 없습니다
  • 최신 관리자 콘솔에는 "납부 전" 상태가 없습니다 (납부확인중 · 납부완료 · 확인필요 셋뿐). 전 회원 백필이 필요 없습니다
  • 확인필요 학생이 문의만 할 수 있으면 운영진이 일일이 되돌려야 합니다. 학생이 안내 문구를 보고 다시 낼 수 있게 합니다
  • 운영진이 학기당 회비를 바꾸면 지금은 과거 요청의 금액까지 같이 바뀌어 보입니다 (매번 현재 설정으로 다시 계산)

⭐ 어떻게 해결했나요?

API

엔드포인트 전 후
GET /v1/app/fee/me 저장된 남은 학기로 금액 · 링크 remainingSemesters 쿼리(선택)로 금액 · 링크 계산. 저장하지 않음
POST /v1/app/fee 납부 정보 제출 (상태 그대로) 제출 + 확인 요청 → 바로 PENDING. 응답은 GET /me와 같은 FeeResponse
POST /v1/app/fee/requests/confirm 확인 요청 삭제

상태

  • TransferStatus에서 UNPAID 제거 → PENDING / PAID / REJECTED. 미납부 = 행 없음. 앱 응답 feeStatus는 클라이언트 호환을 위해 "UNPAID" 문자열을 유지합니다 (도메인에는 없고 FeeResponse 상수로만 존재)
  • POST 허용: 요청이 없거나 REJECTED. PENDING · PAID면 409 FEE_REQUEST_ALREADY_REQUESTED
  • REJECTED: adminNote를 보여주고, remainingSemesters가 오면 금액 · 링크를 계산해 줍니다 → 재납부. 이 PR에선 이전 요청 행을 덮어씁니다 (이력화는 [Refactor/#152] 학생회비 납부 요청을 이력으로 쌓기 #156)
  • PENDING · PAID: 요청할 때 남긴 남은 학기 · 금액만 보여주고 링크는 주지 않습니다 ("또 보내라"로 읽히지 않게)

저장

  • amount BIGINT 컬럼(V24) — 요청 시점 금액 스냅샷. 관리자 목록도 이 값을 보여줍니다
  • 남은 학기 1~8 검증을 FeeAmountCalculator.validateRemainingSemesters로 옮겨 링크 조회와 요청이 같이 씁니다
  • 로그인 시 createIfAbsent 호출 제거
  • V25 — UNPAID 정리: reviewed_at이 있으면 REJECTED (옛 흐름의 반려 · 운영진 되돌림 이력 보존), 없으면 삭제 (V21 백필 · 제출만 한 행)

커밋 — 각 커밋이 따로 컴파일되도록 나눴습니다

  1. 금액 컬럼 추가
  2. 로그인할 때 납부 상태 행을 만들지 않음
  3. 제출과 확인 요청을 한 번에 (핵심)
  4. 관리자 목록 금액을 요청 시점 값으로

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

  • 재납부는 같은 행을 덮어씁니다. 반려 이력은 #156에서 요청당 1행으로 바꾸며 남깁니다
  • 같은 회원의 첫 요청이 동시에 두 번 오면 두 번째가 500입니다. member_id 유니크에 걸리는 것으로 기존과 같은 동작이고, #156에서 409로 바꿉니다
  • 금액은 요청 시점에 서버가 다시 계산합니다. 학생이 링크를 받은 뒤 요청 전에 운영진이 학기당 회비를 바꾸면, 저장 금액이 실제 송금액과 다를 수 있습니다 (드문 경우라 운영진이 캡처와 대조)
  • V24 이전 행은 amount가 비어 있어 앱 · 관리자에서 금액이 안 보입니다
  • 로컬 검증 범위: compileJava(커밋마다), ModularityTests · DomainImplAccessTests. 회비 쪽 단위 테스트는 원래 없습니다. V24 · V25는 MySQL 8.4 컨테이너(ItemOptimisticLockTest — MySqlJpaTest 상속)에서 Flyway로 적용되고 ddl-auto=validate를 통과하는 것까지 확인했습니다

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

  • 앱 계약이 바뀝니다 — 배포 순서를 클라이언트와 맞춰야 합니다
    • POST /v1/app/fee/requests/confirm 삭제
    • POST /v1/app/fee 응답이 FeeSubmitResponse → FeeResponse
    • GET /v1/app/fee/me에 remainingSemesters 쿼리 추가
    • 화면 분기 "UNPAID인데 studentTransferStatusId가 있으면 송금 확인 화면"이 없어집니다 — 이제 그런 상태가 없습니다
  • 관리자: 상태 필터 · 변경에 UNPAID를 보내면 400. 목록에 요청하지 않은 회원이 더 이상 나오지 않습니다. 금액은 현재 설정이 아니라 요청 시점 값입니다
  • 로그인: 회비 행을 만들지 않으므로 로그인이 회비 테이블을 건드리지 않습니다

🔀 Edge Case & 실패 시나리오

상황 동작
PENDING인데 다시 POST 409 FEE_REQUEST_ALREADY_REQUESTED
PAID인데 POST 409 FEE_REQUEST_ALREADY_REQUESTED
REJECTED인데 GET에 remainingSemesters 없음 adminNote만, 금액 · 링크는 null
GET의 remainingSemesters가 0 · 9 400 INVALID_REMAINING_SEMESTERS
PENDING · PAID인데 GET에 remainingSemesters 무시하고 저장된 값을 보여줌
V25로 REJECTED가 된 옛 행 adminNote가 null — 앱이 안내 문구 없는 확인필요를 처리해야 합니다
409로 막힌 요청이 올린 새 캡처 고아 파일 → 파일 정리 배치가 걷어감

📋 검토한 대안과 선택 이유

  • 2단계 유지: "제출만 한" UNPAID를 없앨 수 없고, 저장 없이 끝나야 할 단계를 저장하게 됩니다
  • 링크 조회를 별도 엔드포인트로 (GET /transfer-link): 화면이 상태와 링크를 같이 쓰므로 GET /me 하나에 쿼리로 얹었습니다
  • V25에서 UNPAID 전부 삭제: 옛 흐름의 반려 이력이 사라집니다 (반려도 남기기로 함)
  • amount INT: 계산이 long이고 ddl-auto: validate라 타입 불일치로 기동이 실패합니다

💬 리뷰 포인트

  • [r] 앱 계약 변경 — 클라이언트 배포 순서
  • [c] V25 — 처리된 적 있는 UNPAID를 REJECTED로 바꾸는 판단 (reviewed_at 기준)
  • [c] 응답 전용 "UNPAID" 문자열 — enum에는 없고 FeeResponse 상수로만 있습니다
  • [a] 남은 학기 검증을 FeeAmountCalculator로 옮긴 것

@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

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

⚙️ Run configuration
  • Configuration used: Repository: billilge/stream-server/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a5d58ee9-1c3c-432c-b4c5-b11993265e77
  • 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

Comment @coderabbitai help to get the list of available commands.

…ingle-step-request

# Conflicts:
#	api/admin-api/src/main/java/kr/ac/kookmin/stream/api/admin/welfare/fee/usecase/AdminFeeSearchUseCase.java
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.

학생회비 납부 요청을 한 번에 받고 반려 시 재납부 허용

1 participant