Conversation
Walkthrough회원가입 폼에 수집 필드를 대폭 확장하고(학생 정보, 학번, 성별 등), 인증 상태 초기화/갱신 처리와 보호 라우트 로딩 표시를 조정했으며, Vite 설정을 환경변수 기반으로 전환하고 CSS 일부 레이아웃/스타일을 수정했습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User as "사용자 (브라우저)"
participant UI as "SignUpForm 컴포넌트"
participant API as "Auth API (/api/auth/signup)"
participant AuthU as "frontend/src/utils/auth.js"
rect rgba(135,206,235,0.5)
User->>UI: 회원정보 입력 및 제출
UI->>AuthU: signUp(payload with studentName, studentId, ...)
AuthU->>API: POST /api/auth/signup (확장된 페이로드)
API-->>AuthU: 201 Created / 에러
AuthU-->>UI: 성공 / 실패 응답 전달
end
sequenceDiagram
participant App as "클라이언트 앱"
participant Axios as "axios 인터셉터"
participant AuthCtx as "AuthContext"
participant API as "토큰 리프레시 엔드포인트"
rect rgba(144,238,144,0.5)
App->>Axios: API 호출 (토큰 만료)
Axios->>API: 토큰 리프레시 요청
API-->>Axios: 리프레시 성공 / 실패
alt 성공
Axios->>AuthCtx: 토큰 갱신 저장
Axios->>App: 원래 요청 재시도
else 실패
Axios-->>App: Promise.reject(refreshError) (더 이상 자동 리다이렉트 없음)
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/contexts/AuthContext.jsx (1)
34-45:⚠️ Potential issue | 🔴 Critical
logout성공 시isLoggedIn이false로 설정되지 않는 버그가 있습니다.
setIsLoggedIn(false)가catch블록(Line 40)에만 있어서, 로그아웃 API 호출이 성공했을 때isLoggedIn이true로 유지됩니다. 사용자가 로그아웃해도 인증 상태가 변경되지 않는 심각한 문제입니다.
setIsLoggedIn(false)를finally블록으로 이동하면 성공/실패 모두에서 올바르게 처리됩니다.제안하는 수정 사항
const logout = async () => { try { await api.post('/api/auth/logout'); } catch (error) { // 로그아웃 API 실패해도 무시 (토큰이 없을 수 있음) console.log('로그아웃 API 호출 실패:', error.message); - setIsLoggedIn(false); } finally { + setIsLoggedIn(false); // localStorage 유저 정보 삭제 localStorage.removeItem('user'); } };
🤖 Fix all issues with AI agents
In `@frontend/src/components/LoginAndSignUpForm.module.css`:
- Around line 184-195: The .radioGroup label block has duplicated properties
(color and font-weight) and missing a generic font family; clean this by
removing the duplicate declarations so each property appears once (keep the
intended values, e.g., color: `#000` and font-weight: 400), add a fallback generic
family to font-family (e.g., "Pretendard, sans-serif"), and merge the nearly
identical rules for .inputGroup label and .radioGroup label into a single
combined selector (.inputGroup label, .radioGroup label) to avoid repetition;
also inspect and fix the same duplicate property issues inside the existing
.inputGroup label rule so the merged selector is consistent.
In `@frontend/src/components/signup/SignUpForm.jsx`:
- Around line 105-119: The phone formatter in handlePhoneChange currently always
uses a 4-digit middle group which breaks 10-digit numbers; update
handlePhoneChange to branch on total digit count: when the cleaned digits length
=== 10 format as `${slice(0,3)}-${slice(3,6)}-${slice(6,10)}` (3-3-4), when
length >= 11 format as `${slice(0,3)}-${slice(3,7)}-${slice(7,11)}` (3-4-4), and
otherwise keep the existing short-number handling; adjust the conditional order
and slice indices accordingly and continue to call
setPhoneNumber(formattedValue).
- Around line 94-103: The isFormValid expression is incorrect: replace the
undefined isPasswordValid with a derived boolean from the passwordValid state
(e.g., ensure all entries in the passwordValid array are true) and change the
function references isStudentIdValid, isPhoneNumberValid, and isGenerationValid
to be invoked (isStudentIdValid(), isPhoneNumberValid(), isGenerationValid()) so
actual validation runs; update the isFormValid assignment (the constant that
currently uses areRequiredFieldsFilled, isStudentIdValid, isEmailValid(),
isVerificationSent, isVerificationChecked, isPhoneNumberValid,
isGenerationValid, isPasswordValid, password === confirmPassword) to use the
called functions and the derived password-valid boolean (for example using
passwordValid.every(Boolean) or equivalent).
In `@frontend/src/utils/auth.js`:
- Around line 21-33: The payload construction applies trim() inconsistently:
ensure all user-entered text fields are trimmed by updating the payload object
used to build the request (the payload constant) so that studentId, college,
department, and remark also call .trim() like studentName, email, phoneNumber,
generation, and teamName do; leave password and gender as-is. Locate the payload
declaration and wrap the values for studentId, college, department, and remark
with .trim() to normalize whitespace before sending.
In `@frontend/vite.config.js`:
- Around line 5-50: The VITE_API_URL loaded by loadEnv can be undefined which
breaks the proxy target; update the defineConfig callback to validate
env.VITE_API_URL and use a safe fallback or fail-fast: compute a local symbol
(e.g., apiUrl) from env.VITE_API_URL and if missing either set a sensible
default like 'http://localhost:3000' or throw a clear error, then assign that
apiUrl to the server.proxy['/api'].target; ensure references are to
defineConfig, loadEnv, env.VITE_API_URL and server.proxy['/api'].target so the
change is easy to locate.
🧹 Nitpick comments (4)
frontend/src/components/LoginAndSignUpForm.module.css (1)
212-229:.signUpButton스타일이.loginButton과 거의 동일합니다.81-98행의
.loginButton과 비교했을 때,margin값만 다르고 나머지 속성은 동일합니다. 공통 기본 버튼 클래스를 만들고 차이점만 오버라이드하면 유지보수가 쉬워집니다.frontend/src/utils/auth.js (1)
3-3:DEFAULT_ROLE이 더 이상 사용되지 않습니다.이전에
signUp페이로드에role: DEFAULT_ROLE로 사용되었지만, 현재 페이로드에서 제거되었습니다. 사용하지 않는 상수이므로 삭제하세요.제안하는 수정 사항
-const DEFAULT_ROLE = 'TEAM_MEMBER'; -frontend/src/components/signup/SignUpForm.jsx (2)
316-338: 성별 라디오 버튼의 접근성을 개선할 수 있습니다.현재
<label>성별</label>이 라디오 그룹과 프로그래밍적으로 연결되어 있지 않습니다.role="radiogroup"과aria-labelledby를 사용하면 스크린 리더 사용자 경험이 향상됩니다.제안하는 수정 사항
<div className={styles.radioGroup}> - <label>성별</label> - <div className={styles.radioOptions}> + <label id="gender-label">성별</label> + <div className={styles.radioOptions} role="radiogroup" aria-labelledby="gender-label">
162-192:handleSignUp에서 에러 처리가 일반적이어서 사용자에게 유용한 피드백을 줄 수 없습니다.API 응답의 에러 메시지(예: 중복 학번, 이미 가입된 이메일 등)를 파싱하여 구체적인 오류 내용을
toast.error에 표시하면 사용자 경험이 향상됩니다.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/components/signup/SignUpForm.jsx (1)
118-136:⚠️ Potential issue | 🟡 Minor
handleSendVerificationNumber와handleCheckVerificationNumber가 동일한abortRef를 공유합니다.재전송 버튼 클릭 중 인증번호 확인 버튼을 누르면, 진행 중인 전송 요청이 중단됩니다(그 반대도 마찬가지).
isSending상태가 전송 버튼만 비활성화하고 확인 버튼은 비활성화하지 않으므로, 재전송과 확인이 동시에 트리거될 수 있습니다.독립적인 AbortController를 사용하거나, 전송 중에는 확인 버튼도 비활성화하는 것을 고려해주세요.
🧹 Nitpick comments (4)
frontend/src/components/LoginAndSignUpForm.module.css (1)
207-224:.signUpButton이.loginButton(79-96행)과 거의 동일합니다.
margin속성만 다르고 나머지 속성은 동일합니다. 공통 스타일을 하나의 base 클래스로 추출하면 중복을 줄일 수 있습니다.frontend/src/components/signup/SignUpForm.jsx (3)
211-220: 학번 입력에maxLength제한 추가를 권장합니다.
isStudentIdValid는 정확히 8자리 숫자를 요구하지만, 입력 필드에는 길이 제한이 없습니다.inputMode="numeric"과 함께maxLength={8}을 추가하면 UX가 개선됩니다.제안하는 수정 사항
<input type="text" id="studentId" value={studentId} onChange={(e) => setStudentId(e.target.value)} placeholder="학번을 입력해주세요" + maxLength={8} + inputMode="numeric" />
308-331: 성별 라디오 버튼의 접근성(a11y)을 개선할 수 있습니다.현재 "성별" 레이블이
<label>태그이지만 라디오 그룹과 프로그래밍적으로 연결되어 있지 않습니다.<fieldset>과<legend>를 사용하면 스크린 리더 호환성이 향상됩니다.제안하는 수정 사항
- <div className={styles.radioGroup}> - <label>성별</label> - <div className={styles.radioOptions}> + <fieldset className={styles.radioGroup}> + <legend>성별</legend> + <div className={styles.radioOptions}> ... - </div> - </div> + </div> + </fieldset>
130-132: 에러 핸들링에서console.log대신console.error를 사용하세요.오류 객체를
console.log로 출력하고 있어, 브라우저 DevTools에서 오류 필터링 시 놓칠 수 있습니다.제안하는 수정 사항
} catch (error) { - console.log(error); + console.error(error); toast.error('오류가 발생했습니다.');Also applies to: 149-151, 180-182
Summary by CodeRabbit
새로운 기능
개선 사항
스타일