배경
server #100에서 POST /api/v1/auth/password-reset-requests(재설정 링크 요청), POST /api/v1/auth/password-resets(토큰으로 새 비밀번호 저장)가 이미 구현됐는데, client의 ForgotPasswordPage.tsx/ResetPasswordPage.tsx는 완전히 정적 mock 상태임(서버 호출 없이 이메일 형식·비밀번호 길이만 검사하고 바로 다음 화면으로 navigate). SignupPage는 이미 /auth/signup에 연결돼 있어 이 페이지들만 남은 갭.
서버 계약
POST /auth/password-reset-requests body { email } → 202 (계정 존재 여부 노출 안 함, 항상 202)
POST /auth/password-resets body { token, new_password } → 204 성공 / 400 = 토큰 무효·만료
작업 범위
ForgotPasswordPage.tsx: 제출 시 password-reset-requests 호출 추가, 성공 시 기존처럼 /email-sent로 이동
ResetPasswordPage.tsx: useSearchParams()로 URL의 token 쿼리 파라미터를 읽어서 password-resets 호출, 성공 시 /reset-complete로 이동. 토큰 없음/400 응답 시 기존에 있던 "링크가 만료되었나요?" 안내를 실제로 트리거
- 관련 테스트 갱신
완료 조건
#278 에서 완료. 작업 중 apiFetch가 204만 무본문으로 특별 취급해서 202-무본문 응답(password-reset-requests)에서 .json() 파싱이 깨지는 버그를 발견해 같이 수정함 (status 코드 대신 실제 body 유무로 판단하도록 변경, 회귀 테스트 추가). 로컬 서버에 실제로 붙여서 요청 성공/토큰 없음/토큰 무효 세 경로 모두 브라우저로 확인함.
배경
server #100에서
POST /api/v1/auth/password-reset-requests(재설정 링크 요청),POST /api/v1/auth/password-resets(토큰으로 새 비밀번호 저장)가 이미 구현됐는데, client의ForgotPasswordPage.tsx/ResetPasswordPage.tsx는 완전히 정적 mock 상태임(서버 호출 없이 이메일 형식·비밀번호 길이만 검사하고 바로 다음 화면으로 navigate).SignupPage는 이미/auth/signup에 연결돼 있어 이 페이지들만 남은 갭.서버 계약
POST /auth/password-reset-requestsbody{ email }→ 202 (계정 존재 여부 노출 안 함, 항상 202)POST /auth/password-resetsbody{ token, new_password }→ 204 성공 / 400 = 토큰 무효·만료작업 범위
ForgotPasswordPage.tsx: 제출 시password-reset-requests호출 추가, 성공 시 기존처럼/email-sent로 이동ResetPasswordPage.tsx:useSearchParams()로 URL의token쿼리 파라미터를 읽어서password-resets호출, 성공 시/reset-complete로 이동. 토큰 없음/400 응답 시 기존에 있던 "링크가 만료되었나요?" 안내를 실제로 트리거완료 조건
#278 에서 완료. 작업 중
apiFetch가 204만 무본문으로 특별 취급해서 202-무본문 응답(password-reset-requests)에서.json()파싱이 깨지는 버그를 발견해 같이 수정함 (status 코드 대신 실제 body 유무로 판단하도록 변경, 회귀 테스트 추가). 로컬 서버에 실제로 붙여서 요청 성공/토큰 없음/토큰 무효 세 경로 모두 브라우저로 확인함.