Repository navigation
[Feat/#149] 학생회비 납부 API 연결 - #151
Merged
Merged
Conversation
Chromium은 File이 든 history.state를 뒤로가기로 되살리지 못하고 null로 돌려준다. 캡처 파일은 퍼널 화면이 메모리에 들고, context에는 파일 키와 송금 링크만 싣는다.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
충돌은 회비 쪽 내용을 새 경로로 옮겨 풀었다(feeKeys·feeQueries 분리, feeMock 삭제, import 경로, coding-style 데이터 로딩 절).
xeoxxn
changed the base branch from
main
to
refactor/#153-shared-folder-structure
November 3, 2026 15:37
This was referenced Nov 4, 2026
xeoxxn
changed the base branch from
refactor/#153-shared-folder-structure
to
main
November 4, 2026 12:14
xeoxxn
marked this pull request as ready for review
November 4, 2026 12:28
github-actions
Bot
requested review from
jjunh33,
leegain1,
sangrae2325 and
tnals0924
November 4, 2026 12:28
jjunh33
approved these changes
Nov 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#️⃣연관된 이슈
🎯 해결하려는 문제가 무엇인가요?
학생회비 화면(납부내역
/my/fee, 계좌 송금 퍼널/fee/transfer)과 행사 상세의 "학생회비 납부자 전용" 판단이 목데이터(feeMock.ts)로 돈다. 서버(billilge/stream-server#167)가 납부 흐름을 "토스로 송금한 뒤 남은 학기 수 + 학점이수현황 캡처를 한 번에 요청"으로 개편해서 앱 API가 확정됐다. 이걸 실제로 연결한다. 파일 업로드(presigned URL) 방식도 이번에 정했다.❓ 왜 해결해야 하나요?
목데이터로는 납부 요청이 운영진에게 가지 않고, 송금 링크도 비어 있어 토스로 넘어갈 수 없다(지금은 항상 "토스를 열지 못했어요"). 납부 흐름 전체가 서버 연결을 기다리고 있다.
⭐ 어떻게 해결했나요?
쓰는 API — 사용자 앱 API만 (관리자 API는 건드리지 않음)
GET /v1/app/fee/meGET /v1/app/fee/me?remainingSemesters=POST /v1/files/presigned-url→ 스토리지PUTPOST /v1/app/fee{ remainingSemesters, proofImageKey }1. 공용 — 서버 일시 표시 (
fec1a3d) — 서버LocalDateTime은"11:49:00.123456"까지 내려와서formatDateTime이 시:분까지만 남긴다2. 상태 이름을 서버 문자열로 (
5e6a8cd) —checking·needs-check·paid→PENDING·REJECTED·PAID(+ 미납UNPAID). 매핑 계층 없이 서버와 1:1이다. 배지 key와 홈 목데이터도 같이 바뀐다3. 납부 상태 조회 (
4c8cfd2) —feeQueries.me()를 실 API로,feeMock.ts삭제FeeResponse) 그대로 두고 화면이select로 바꾼다 — 납부내역은 미납이면null(빈 화면), 행사 상세는PAID만 납부로 본다FEE_TITLE상수4. 송금 링크 (
9ebba1b) —feeQueries.transferGuide(semester). 캡처 단계 "다음"에서 받아 토스 단계 context에 싣는다 — 토스 단계가 데이터를 기다리지 않는다. 링크가 null이면 기존 "토스를 열지 못했어요" 화면5. 캡처 업로드 (
267a47f) —shared/entities/files(useUploadFileMutation) 신설PUT은apiClient를 거치지 않는다(baseURL·인증 헤더·봉투 해제가 붙으면 안 됨)isAcceptableTranscript)6. 납부 요청 (
6277c1b) —useSubmitFeeMutation. 성공하면["fee"]무효화 후 완료 단계로replace7. 진입 차단 (
665fb62) — 이미 요청한 학생(PENDING·PAID)이 퍼널로 들어오면 납부내역으로 보낸다(안 막으면 송금까지 다 하고 409를 받는다). 들어올 때의 상태만 본다 — 요청을 보내면PENDING이 되는데 그때 완료 단계에서 쫓겨나면 안 되기 때문이다. 퍼널은Suspense+FeeTransferSkeleton8. 다시 납부하기 (
0585f8d) — 확인필요(REJECTED) 카드 아래쪽에 "문의하기"와 같은 모양으로. 서버는 확인필요면 학기 수부터 다시 내게 한다9. 뒤로가기 버그 수정 (
af2504e) — 확인 중 발견. 캡처File을 퍼널 context(history.state)에 담고 있었는데, Chromium은File이 든 history.state를 뒤로가기로 되살리지 못하고null로 돌려준다(문자열만 든 state는 그대로 돌아오는 것으로 따로 확인). 그래서 토스·송금 확인에서 뒤로 가면 퍼널이 첫 단계로 초기화됐다(#107부터 있던 구조). 파일은 퍼널 화면 state로 옮기고 context에는proofImageKey·transferLinkUrl만 싣는다10. 문서 (
b403683,b31f162) —coding-style.md데이터 로딩(파일 업로드),wds-component-usage.md송금 퍼널·버튼 표11. #154 구조에 맞춤 (
9922fe0,b1ad775) — #154 브랜치를 합치고 회비·파일 코드를 새 구조로 옮겼다entities/fee/feeApi.ts→shared/entities/fee/feeKeys.ts(root·me·transferGuide) +feeQueries.ts(feeQueries·FEE_ERROR_CODES·useSubmitFeeMutation),types.ts→feeTypes.ts, #154가 옮긴feeMock.ts는 삭제entities/files/filesApi.ts·types.ts→shared/entities/files/filesQueries.ts·filesTypes.ts(key 없음 — auth·search와 같은 예외)@/shared/api(index)로만12. main 병합 (
923695c,e443885) — #154가 squash merge되고 빌릴게 용어 통일(#163)·로그인 연동(#172)·이메일 인증(#152)이 main에 들어와서 base를 main으로 바꾸고 합쳤다. 회비 변경분과 겹친 곳은homeMock.ts의 아이콘 경로(billilge-items) 하나다. 로그인이 먼저 붙어서coding-style.md의 "회비가 처음 붙인 도메인" 문구는 지웠다13. zod 응답 검사 (
d504e08,5badfb2,d79306e) — #156(사물함)과 같은 방식이다.zod도 같은 버전(^4.6.7)이라 lockfile 추가분이 #156과 똑같다feeQueries.ts에FEE_STATUSES·feeResponseSchema,filesQueries.ts에fileUploadUrlResponseSchema(z.looseObject— 서버가 필드를 더해도 통과). 요청은api.get<unknown>(…)을 스키마의parse로 감싼다feeTypes.ts·filesTypes.ts에서z.infer로 만든다(FeeResponse·FeeStatus는 이름 그대로라 화면 코드는 그대로,FileUploadUrl→FileUploadUrlResponse)POST /v1/app/fee) 응답은 검사하지 않는다 — 응답을 쓰지 않고 무효화로me를 다시 받아서(그쪽이 검사한다), 여기서 검사하면 이미 접수된 요청을 응답 모양 때문에 실패로 안내하게 된다coding-style.md에 넣어서 여기선 건드리지 않았다(같은 줄을 고치면 충돌)🧩 이 PR의 한계 & 트레이드오프
GET /me·POST /fee가 404(FEE_ACCOUNT_NOT_FOUND)다. 관리자 페이지가 생기기 전까지는 dev DB(admin_config_values)나 관리자 API로 넣어야 한다ZodError)는ApiError가 아니라서queryClient재시도 규칙에 따라 한 번 더 요청한 뒤 실패한다window.open그대로 — 모바일 브라우저·앱 WebView 동작은 앱에서 따로 작업한다. 토스 앱이 실제로 송금 화면을 여는지는 기기에서 확인해야 한다ScreenToast위치, 버튼이 두 줄인 화면) — 이번엔 손대지 않았다⛓️ 기존 기능에 미치는 영향
AuthEntryGate가 로그인으로 보낸다UNPAID로 맞추기로 했다formatDateTime— 모든 도메인이 쓴다. 기존 목데이터("13:59")는 결과가 같다?fee.step=)는 그대로다🔀 Edge Case & 실패 시나리오
FEE_REQUEST_ALREADY_REQUESTEDINVALID_PROOF_IMAGEPENDING·PAID인데 퍼널 진입브라우저 확인 (dev 서버, 375×812)
2026.11.01 10:20{ category: "FEE_TRANSCRIPT_IMAGE", contentType, fileSize, originalName }→ 스토리지PUT(Content-Type: image/png, 인증 헤더 없음) →GET /me?remainingSemesters=3supertoss://send?bank=…&accountNo=…&amount=30000으로 열고 송금 확인으로{ proofImageKey, remainingSemesters: 3 }— 성공·500·409·INVALID_PROOF_IMAGE각각 위 표대로/fee/transfer→ 납부내역GET /me?remainingSemesters=3· presigned-url · 스토리지PUT) → 토스 링크 → 납부 요청 → 완료까지 그대로 동작feeStatus·숫자 자리에 문자열·필드 누락은 거절fileKey가 없으면 스토리지PUT을 보내지 않고 캡처 단계에 머물러 토스트📋 검토한 대안과 선택 이유
GET /me·POST /fee의 404는 그대로라 화면이 깨진다. dev 쪽에 계좌를 넣는 게 맞다💬 리뷰 포인트
[r]진입 차단을 "들어올 때 상태"(useState초기값)로만 판단하는 부분 —FeeTransferScreen.tsx[c]캐시엔FeeResponse그대로 두고 화면에서select로 바꾸는 방식 —FeePaymentList(FeeResponse & { feeStatus: FeePaymentStatus }),EventsDetailContent[c]스토리지PUT을apiClient밖에서 보내는 부분 —shared/entities/files/filesQueries.ts. #154의 "요청은@/shared/api로" 규칙에 맞춰shared/api도우미로 옮길지[c]납부 요청 응답을 스키마로 검사하지 않는 부분 —feeQueries.ts의useSubmitFeeMutation(13번)[a]토스트 문구 —FeeTransferScreen.tsx의TOAST_MESSAGES