-
Notifications
You must be signed in to change notification settings - Fork 2
feat : ci workflow #332
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat : ci workflow #332
Conversation
Walkthrough
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (3 warnings)
✨ Finishing touches
🧪 Generate unit tests (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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🧹 Nitpick comments (6)
src/app/sign-up/email/EmailSignUpForm.tsx (1)
76-79: 1. 타입 안전성 개선 👍
any에서unknown으로 변경하여 타입 안전성이 향상되었습니다.
- 에러 타입을 명시적으로 캐스팅하여 안전하게 접근
- 폴백 메시지로 사용자 경험 보장
선택적 개선 제안: 동일한 에러 추출 패턴이
SignupSurvey.tsx에서도 반복됩니다. 재사용 가능한 유틸리티 함수로 추출하면 일관성과 유지보수성이 높아질 수 있습니다.🔎 선택적 유틸리티 함수 제안
// src/utils/errorUtils.ts export const extractErrorMessage = ( error: unknown, fallback: string = "오류가 발생했습니다." ): string => { const axiosError = error as { response?: { data?: { message?: string } }; message?: string }; return axiosError.response?.data?.message || axiosError.message || fallback; };사용 예시:
onError: (error: unknown) => { - const axiosError = error as { response?: { data?: { message?: string } } }; - toast.error(axiosError.response?.data?.message || "회원가입에 실패했습니다."); + toast.error(extractErrorMessage(error, "회원가입에 실패했습니다.")); },.eslintrc.js (1)
100-100: 중복 규칙 설정을 확인해 주세요.Line 100에서
no-unused-vars: "warn"과 Line 107에서@typescript-eslint/no-unused-vars: "warn"이 동시에 활성화되어 있습니다.TypeScript 프로젝트에서는
no-unused-vars를"off"로 설정하고 TypeScript 버전만 사용하는 것이 권장됩니다.🔎 제안하는 수정
// 미사용 변수 경고 - "no-unused-vars": "warn", + "no-unused-vars": "off", // ========================================== // TypeScript 관련 규칙Also applies to: 107-107
src/utils/universityUtils.ts (1)
3-8: 타입 안정성이 개선되었습니다!
변경 사항:
- 반환 타입에
undefined를 추가하여 실제 동작을 정확히 반영합니다.- Line 7에서 명시적으로
undefined를 반환하여 코드가 더 명확해졌습니다.장점:
- 호출하는 쪽에서 undefined 케이스를 처리하도록 강제합니다.
- 타입 안정성이 향상되었습니다.
선택적 개선: 타입 캐스팅 대신 keyof 사용
Line 5의
as string대신 더 타입 안전한 방법을 사용할 수 있습니다:const shortenLanguageTestName = (name: string): string | undefined => { if (Object.prototype.hasOwnProperty.call(SHORT_LANGUAGE_TEST, name)) { - return SHORT_LANGUAGE_TEST[name] as string; + return SHORT_LANGUAGE_TEST[name as keyof typeof SHORT_LANGUAGE_TEST]; } return undefined; };하지만 현재 코드도
hasOwnProperty가드가 있어 안전하게 동작합니다.docs/eslint-prettier-migration-prd.md (2)
147-156: 코드 블록에 언어 지정자 추가를 권장합니다.파일 구조를 표현하는 이 코드 블록에 언어 지정자가 없어 markdownlint 경고가 발생합니다.
🔎 제안하는 수정
-``` +```text 프로젝트 루트/ ├── .eslintrc.js (신규, .eslintrc.json 대체) ... ```
203-211: 코드 블록에 언어 지정자 추가를 권장합니다.
.prettierignore파일 내용을 표현하는 이 코드 블록에 언어 지정자가 없어 markdownlint 경고가 발생합니다.🔎 제안하는 수정
-``` +```text node_modules .next ... ```src/utils/jwtUtils.ts (1)
11-11: 런타임 검증 추가를 고려해보세요.타입 캐스팅(
as JwtPayload)은 컴파일 타임에만 체크되며, 실제 JWT 페이로드가 예상된 구조와 다를 경우 런타임 오류가 발생할 수 있습니다.다음과 같은 개선을 고려해보세요:
- Zod 스키마를 사용한 런타임 검증 추가
- 필수 필드(sub, role, exp) 존재 여부 확인
🔎 Zod를 활용한 런타임 검증 예시
파일 상단에 Zod 스키마 추가:
+import { z } from 'zod'; + +const JwtPayloadSchema = z.object({ + sub: z.number(), + role: z.string(), + iat: z.number(), + exp: z.number(), +}); + -interface JwtPayload { - sub: number; - role: string; - iat: number; - exp: number; -} +type JwtPayload = z.infer<typeof JwtPayloadSchema>;
isTokenExpired함수에 검증 적용:export const isTokenExpired = (token: string | null): boolean => { if (!token) return true; try { - const payload = JSON.parse(atob(token.split(".")[1])) as JwtPayload; + const parsed = JSON.parse(atob(token.split(".")[1])); + const payload = JwtPayloadSchema.parse(parsed); const currentTime = Math.floor(Date.now() / 1000); return payload.exp < currentTime; } catch (error) { console.error("토큰 파싱 오류:", error); return true; } };
tokenParse함수에도 동일하게 적용:export const tokenParse = (token: string | null): JwtPayload | null => { if (typeof window === "undefined") return null; if (!token) return null; try { - const payload = JSON.parse(atob(token.split(".")[1])) as JwtPayload; + const parsed = JSON.parse(atob(token.split(".")[1])); + const payload = JwtPayloadSchema.parse(parsed); return payload; } catch (error) { console.error("토큰 파싱 오류:", error); return null; } };Also applies to: 26-26
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (21)
.eslintrc.js.eslintrc.json.github/workflows/ci.yml.prettierignoredocs/eslint-prettier-migration-prd.mdlint-fix.prd.mdpackage.jsonsrc/app/sign-up/email/EmailSignUpForm.tsxsrc/app/university/score/submit/language-test/_lib/schema.tssrc/components/button/BlockBtn.tsxsrc/components/button/RoundBtn.tsxsrc/components/login/signup/SignupPolicyScreen.tsxsrc/components/login/signup/SignupSurvey.tsxsrc/components/search/UniversityFilterSection.tsxsrc/components/search/UniversityRegionTabs.tsxsrc/components/ui/UniverSityCard/index.tsxsrc/utils/designUtils.tssrc/utils/jwtUtils.tssrc/utils/scoreUtils.tssrc/utils/universityUtils.tssrc/utils/useInfinityScroll.ts
💤 Files with no reviewable changes (1)
- .eslintrc.json
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 203
File: src/app/mentor/_ui/MentorClient/_ui/MentorFindSection/index.tsx:27-37
Timestamp: 2025-07-31T10:48:45.942Z
Learning: In the solid-connect-web project, manNomi handles merge conflicts and temporary code by leaving it in place during development with plans to remove it during proper feature implementation, rather than immediately fixing non-critical temporary code.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/components/ui/TabSelector.tsx:10-11
Timestamp: 2025-08-12T09:41:44.182Z
Learning: manNomi prefers to keep reusable UI components simple and focused on core functionality rather than adding many features. They don't want to over-engineer flexible/reusable UI components at the initial stage.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/components/mentor/MentorChatCard/index.tsx:17-21
Timestamp: 2025-08-24T11:14:34.297Z
Learning: manNomi prefers not to receive accessibility suggestions or recommendations during code reviews.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/usePostLogout.ts:17-33
Timestamp: 2025-08-24T11:13:08.477Z
Learning: manNomi prefers to prioritize user experience over perfect state consistency in auth flows. Specifically, in logout scenarios, they prefer to keep tokens intact on API failure to avoid forcing users to re-login, even if it means temporary UI state inconsistency.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/useDeleteUserAccount.ts:17-27
Timestamp: 2025-08-24T11:11:40.758Z
Learning: manNomi prefers optimistic navigation in auth-related flows (like account deletion) to prevent race conditions where token clearing before navigation could cause intermediate redirects to login page due to pending async requests failing.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/types/mentor.ts:70-73
Timestamp: 2025-08-12T04:07:04.134Z
Learning: manNomi prefers using Korean labels directly in enum values (e.g., MentorTab.MY_MENTEE = "나의 멘티") over separating enum keys from UI labels for efficiency and intuitiveness, considering scalability concerns as excessive for their current project needs.
📚 Learning: 2025-08-12T03:44:45.718Z
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/app/mentor/modify/_ui/ModifyContent/_hooks/usePutMyMentorProfileHandler.ts:24-29
Timestamp: 2025-08-12T03:44:45.718Z
Learning: 이 프로젝트에서는 React Query의 전역 에러 처리를 사용하므로, mutation 호출 시 try-catch를 추가하지 않는다. mutate() 호출만으로 충분하며, 필요한 경우에만 mutation 설정에서 onError 콜백을 사용한다.
Applied to files:
src/components/login/signup/SignupSurvey.tsx
📚 Learning: 2025-08-12T03:44:45.718Z
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/app/mentor/modify/_ui/ModifyContent/_hooks/usePutMyMentorProfileHandler.ts:24-29
Timestamp: 2025-08-12T03:44:45.718Z
Learning: React Query를 사용하는 프로젝트에서는 전역 에러 처리가 설정되어 있을 때 mutation 호출 시 try-catch를 추가할 필요가 없다. mutate() 함수 호출만으로 충분하며, 필요시 mutation 설정에서 onError 콜백을 사용한다.
Applied to files:
src/components/login/signup/SignupSurvey.tsx
📚 Learning: 2025-08-11T06:07:23.563Z
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 239
File: src/utils/jwtUtils.ts:32-37
Timestamp: 2025-08-11T06:07:23.563Z
Learning: 이 프로젝트에서는 JWT 토큰을 사용하는 인증 관련 페이지들에서 SSR을 사용하지 않음. 서버 비용과 렌더링 이득을 고려했을 때 SSR이 필요하지 않고, SEO도 중요하지 않은 부분이므로 JWT 유틸리티 함수들(jwtUtils.ts)에서 atob 사용이 문제되지 않음. Node.js 환경 호환성을 위한 base64UrlDecode 변경이 불필요함.
Applied to files:
src/utils/jwtUtils.ts
🧬 Code graph analysis (4)
src/app/sign-up/email/EmailSignUpForm.tsx (1)
src/lib/zustand/useToastStore.ts (1)
toast(39-44)
src/utils/designUtils.ts (1)
src/lib/utils.ts (1)
cn(4-6)
src/utils/universityUtils.ts (1)
src/constants/application.ts (1)
SHORT_LANGUAGE_TEST(28-35)
src/components/login/signup/SignupSurvey.tsx (1)
src/lib/zustand/useToastStore.ts (1)
toast(39-44)
🪛 markdownlint-cli2 (0.18.1)
lint-fix.prd.md
147-147: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
203-203: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/eslint-prettier-migration-prd.md
147-147: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
203-203: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: ci
🔇 Additional comments (17)
src/components/login/signup/SignupSurvey.tsx (3)
67-71: 1. 이미지 업로드 에러 처리 타입 개선 ✓
unknown타입으로 변경하여 타입 안전성이 향상되었습니다.
- 주석에 명시된 대로 hook의
onError에서 toast 처리가 이루어지므로 여기서는 로깅만 수행
93-105: 2. 회원가입 mutation 에러 처리 개선 ✓
any에서unknown으로 변경하고, axios 응답 에러와 일반 에러를 구분하여 처리합니다.
- axios 응답이 있는 경우:
response.data.message우선 사용- 그 외:
error.message사용- 두 경우 모두 폴백 메시지 제공
참고:
EmailSignUpForm.tsx의 에러 처리보다 더 상세합니다. 일관성을 위해 두 파일의 패턴을 통일하는 것도 고려해볼 수 있습니다.
107-111: 3. 외부 catch 블록 타입 개선 ✓
createRegisterRequest()에서 발생할 수 있는 에러(예: Line 58의throw new Error("준비 단계를 선택해주세요"))를 처리합니다.
- mutation 호출 전에 발생하는 에러를 포착하므로 필요한 처리입니다
- toast를 통해 사용자에게 에러 메시지 표시
src/utils/useInfinityScroll.ts (1)
28-30: LGTM!
IntersectionObserver콜백에서 entries 배열 구조분해가 명확하게 처리되었습니다..github/workflows/ci.yml (1)
1-36: CI 워크플로우가 잘 구성되었습니다!
구성 내용:
- Node.js 22.x 사용 (package.json의 engines와 일치)
- npm ci로 클린 설치
- 린트, 타입 체크, 빌드 순서로 검증
좋은 점:
- npm 캐시 활성화로 빌드 시간 단축
NODE_ENV=production으로 프로덕션 빌드 검증- main과 develop 브랜치에 대한 적절한 트리거 설정
.prettierignore (1)
1-37: LGTM!
.prettierignore파일이 적절하게 구성되었습니다.
- 제외 항목:
- 빌드 산출물 및 캐시
- 의존성 디렉토리
- 락 파일 및 자동 생성 파일
- 환경 변수 및 IDE 설정
모든 패턴이 표준 관행을 따르고 있습니다.
package.json (1)
12-17: 린트 및 포맷 스크립트가 잘 추가되었습니다!
추가된 스크립트:
lint:fix: ESLint 자동 수정format: Prettier로 코드 포맷팅format:check: 포맷 검증 (CI용)lint:all: 린트 + 포맷 체크 통합fix:all: 린트 수정 + 포맷팅 통합장점:
- CI와 로컬 개발 워크플로우를 모두 지원합니다.
- 파일 타입 패턴이 포괄적입니다(ts, tsx, js, jsx, json, md, yml, yaml).
- .prettierignore와 함께 적절하게 동작합니다.
.eslintrc.js (1)
1-46: ESLint 설정 파일이 잘 구성되었습니다!
주요 설정:
- TypeScript 파서와 프로젝트 레퍼런스 활성화
- Next.js 및 TypeScript 권장 규칙 적용
- Prettier 충돌 방지 (extends 배열 마지막에 위치 ✓)
중요한 수정:
- Lines 34-46: 설정 파일에 대한
project: null오버라이드가 추가되어 파싱 오류를 방지합니다.*.config.{js,mjs,ts}패턴이 다양한 설정 파일 형식을 커버합니다.src/components/button/RoundBtn.tsx (1)
5-5: LGTM!
designUtils의 default export로 변경된 것에 맞춰 import가 업데이트되었습니다. 다른 컴포넌트들(BlockBtn.tsx 등)과 일관된 패턴입니다.src/utils/universityUtils.ts (1)
10-10: LGTM!Default export로의 전환이 다른 유틸리티 파일들(designUtils, scoreUtils)과 일관되게 적용되었습니다.
src/app/university/score/submit/language-test/_lib/schema.ts (1)
3-3: Import 변경이 scoreUtils.ts의 export 스타일 변경과 일치합니다.Default import로의 변경은
src/utils/scoreUtils.ts의 export 방식 변경과 일관성 있게 적용되었습니다. Line 27의 함수 사용처도 정상적으로 동작하며, try-catch로 적절하게 에러 처리가 구현되어 있습니다.src/components/button/BlockBtn.tsx (1)
5-5: Import 변경이 designUtils.ts의 export 스타일 변경과 일치합니다.Default import로의 변경은
src/utils/designUtils.ts의 export 방식 변경과 일관성 있게 적용되었습니다. Line 33의cn함수 사용도 정상적으로 동작합니다.src/utils/scoreUtils.ts (1)
3-35: Export 스타일 변경이 일관성 있게 적용되었습니다.Named export에서 default export로의 변경이 정상적으로 이루어졌으며, 함수의 내부 로직은 그대로 유지되었습니다. Import를 사용하는
src/app/university/score/submit/language-test/_lib/schema.ts도 함께 업데이트된 것을 확인했습니다.docs/eslint-prettier-migration-prd.md (1)
1-285: 전체적으로 잘 작성된 마이그레이션 문서입니다.ESLint & Prettier 마이그레이션에 대한 상세한 계획과 배경이 명확하게 문서화되어 있습니다.
문서의 강점:
- 명확한 목적과 배경 설명
- 단계별 마이그레이션 계획 (Phase 1-4)
- 위험 요소 및 대응 방안 포함
- 구체적인 검증 방법 제시
- 실제 PR의 변경사항과 일치하는 내용
마크다운 lint 이슈는 사소한 스타일 문제이므로, 선택적으로 수정하시면 됩니다.
src/components/login/signup/SignupPolicyScreen.tsx (1)
61-61:mb-[29px]스타일은 회원가입 흐름 전반에서 일관된 패턴이므로 추가 확인은 불필요합니다.검토 결과, 다음 사항이 확인되었습니다.
일관된 디자인 패턴
- SignupPolicyScreen, SignupRegionScreen, SignupProfileScreen, SignupPrepareScreen 모두에서
BlockBtn의 className으로mb-[29px]를 동일하게 사용 중의도된 레이아웃 설계
- 하단 고정 버튼 영역 내에서 버튼의 하단 여백을 표준화한 것으로 보임
- SignupPolicyScreen에서는 여백 값 유지하면서 배경색만 조건부로 변경하는 구조
결론
- 버튼 위치와 여백은 의도된 설계에 따른 것이며, 다른 회원가입 화면과 일관성 있게 적용됨
- 추가 변경이나 검토는 필요 없음
src/utils/jwtUtils.ts (1)
1-6: JwtPayload 인터페이스 추가가 타입 안정성을 향상시킵니다.JWT 페이로드의 구조를 명확하게 정의하여 타입 안정성을 확보했습니다.
lint-fix.prd.md (1)
1-285: 마이그레이션 PRD 문서가 체계적이고 포괄적입니다.ESLint와 Prettier 마이그레이션을 위한 문서가 다음과 같이 잘 구성되어 있습니다:
- 명확한 목표와 배경: 현재 문제점과 개선 방향이 명확히 정의됨
- 단계별 계획: 4단계로 구분된 실행 가능한 마이그레이션 계획
- 위험 관리: 위험 요소 식별 및 대응 방안 포함
- 검증 계획: 기능 검증 및 회귀 테스트 체크리스트 제공
- 현실적인 일정: 총 2.5일의 합리적인 일정 수립
문서가 팀원들이 마이그레이션을 이해하고 실행하는 데 충분한 정보를 제공합니다.
|
|
||
| type UseInfinityScrollReturn = { | ||
| lastElementRef: (node: HTMLDivElement | null) => void; | ||
| lastElementRef: (node: Element | null) => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, locate and read the useInfinityScroll.ts file
cat -n src/utils/useInfinityScroll.tsRepository: solid-connection/solid-connect-web
Length of output: 212
🏁 Script executed:
# Search for usages of useInfinityScroll and lastElementRef in the codebase
rg -n 'useInfinityScroll|lastElementRef' --type=ts --type=tsx -B2 -A2Repository: solid-connection/solid-connect-web
Length of output: 105
🏁 Script executed:
# Check for any explicit HTMLDivElement type assignments related to this ref
rg -n 'HTMLDivElement' --type=ts --type=tsx -B2 -A2Repository: solid-connection/solid-connect-web
Length of output: 105
🏁 Script executed:
# List files in the utils directory
ls -la src/utils/ 2>/dev/null || find . -name "useInfinityScroll*" -type fRepository: solid-connection/solid-connect-web
Length of output: 1196
🏁 Script executed:
# Try to read the file directly
cat -n src/utils/useInfinityScroll.ts 2>/dev/null || cat -n src/utils/useInfinityScroll.js 2>/dev/nullRepository: solid-connection/solid-connect-web
Length of output: 1846
🏁 Script executed:
# Search for useInfinityScroll and lastElementRef without file type restrictions
rg -n 'useInfinityScroll|lastElementRef' -B2 -A2Repository: solid-connection/solid-connect-web
Length of output: 6821
🏁 Script executed:
# Check MentorCard component's ref prop type
rg -n 'observeRef' --type-listRepository: solid-connection/solid-connect-web
Length of output: 467
🏁 Script executed:
# Search for MentorCard definition and its prop types
rg -n 'interface MentorCardProps|type MentorCardProps|observeRef' -B2 -A2Repository: solid-connection/solid-connect-web
Length of output: 1979
훅 변경이 완료되지 않았습니다. 컴포넌트 타입 정의도 함께 업데이트해야 합니다.
현재 상태를 정리하면:
-
useInfinityScroll 훅의 변경 사항
lastElementRef의 타입이Element | null로 변경됨 (10번, 22번 줄 확인됨)
-
발견된 타입 불일치 문제
MentorExpandChatCard컴포넌트는 여전히HTMLDivElement | null타입을 기대함 (MentorExpandChatCard/index.tsx 24번 줄)MentorCard컴포넌트는 여전히React.RefCallback<HTMLDivElement>타입을 기대함 (MentorCard/index.tsx 19번 줄)- ApplicantListSection과 MentorFindSection에서 훅의 콜백을 이들 컴포넌트에 전달할 때 타입 충돌 발생
-
필요한 조치
- 두 컴포넌트(
MentorExpandChatCard,MentorCard)의 props 타입을Element | null또는React.RefCallback<Element>로 통일 - 이를 통해 IntersectionObserver.observe()의 Element 타입 요구사항과 일관성 있게 변경
- 두 컴포넌트(
🤖 Prompt for AI Agents
In src/utils/useInfinityScroll.ts around line 10 the hook changed lastElementRef
to use Element | null, but consuming components still expect HTMLDivElement
types; update MentorExpandChatCard props (MentorExpandChatCard/index.tsx line
~24) and MentorCard props (MentorCard/index.tsx line ~19) to accept Element |
null for the ref value (or React.RefCallback<Element> for callback refs) instead
of HTMLDivElement | null/React.RefCallback<HTMLDivElement>, adjust their prop
type definitions and any related imports so the hook callback can be passed
through without type conflicts, and update any local usages that assume
HTMLDivElement-specific APIs to either narrow the type where needed or cast
safely before use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/components/mentor/MentorExpandChatCard/index.tsx (1)
24-24: ref 타입 변경이 일관되게 적용되었습니다.lastElementRef의 타입이
(node: HTMLDivElement | null) => void에서(node: Element | null) => void로 변경되어, MentorCard 컴포넌트와 동일한 패턴을 따르고 있습니다.이 변경이 useInfinityScroll 훅의 타입 시그니처 업데이트와 일치하는지 확인이 필요합니다.
🧹 Nitpick comments (3)
.eslintrc.js (2)
84-84:prefer-default-export정책을 재검토해보시는 것을 권장합니다.현재 단일 export 시 default export를 권장하도록 설정되어 있습니다. 다만, 현대적인 코드베이스에서는 다음과 같은 이유로 named export를 선호하는 경향이 있습니다:
- 리팩토링 용이성: 이름 변경 시 IDE 지원이 더 우수함
- 명시적 import: import 문에서 어떤 기능을 가져오는지 명확함
- Tree-shaking: 번들러의 최적화가 더 효과적임
물론 프로젝트의 코딩 스타일에 따라 default export를 선호할 수도 있으므로, 팀의 규칙에 맞게 결정하시면 됩니다.
🔎 Named export 선호 시 수정 예시
- // 단일 export 시 default export 권장 (warning) - "import/prefer-default-export": 1, + // Named export 허용 + "import/prefer-default-export": "off",
110-114: Type-aware 린트 규칙 설정이 적절합니다.TypeScript의 타입 안전성 규칙들과 import resolver가 올바르게 구성되었습니다. 다만, type-aware 규칙들은 타입 체크를 수행하기 때문에 대규모 프로젝트에서 린트 속도가 느려질 수 있습니다.
현재 CI workflow 추가가 목적이므로 이 설정은 적합하며, 개발 중 린트 속도가 문제가 된다면 추후 다음을 고려해볼 수 있습니다:
- 개발 환경: 일부 type-aware 규칙을 비활성화
- CI 환경: 모든 규칙을 활성화하여 엄격한 체크
Also applies to: 129-140
src/utils/designUtils.ts (1)
1-4: 중복 제거를 위한 re-export 방식이 좋지만, 완전한 마이그레이션을 권장합니다.이전 리뷰에서 지적된 중복 cn 함수 문제를 re-export 방식으로 해결하여 단일 소스로 통합했습니다. named export와 default export를 모두 제공하여 하위 호환성을 유지하고 있습니다.
다만, 이 파일 자체가 불필요한 중간 레이어가 될 수 있습니다. 장기적으로는 모든 import를
@/lib/utils로 직접 마이그레이션하고 이 파일을 제거하는 것이 더 명확한 구조가 될 것입니다.다음 스크립트로 여전히 designUtils를 사용하는 곳이 있는지 확인해주세요:
#!/bin/bash # Description: Check remaining usages of designUtils imports # Check for any remaining imports from designUtils echo "=== designUtils import 사용처 확인 ===" rg -n "from ['\"]@/utils/designUtils['\"]" --type=tsx --type=ts -C2 # Check for default imports that might break echo -e "\n=== default import 패턴 확인 ===" rg -n "import cn from ['\"]@/utils/designUtils['\"]" --type=tsx --type=ts모든 컴포넌트가
@/lib/utils를 사용하도록 전환되었다면, 이 파일 제거를 고려해보세요.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
.eslintrc.jslint-fix.prd.mdsrc/components/button/BlockBtn.tsxsrc/components/button/RoundBtn.tsxsrc/components/mentor/MentorCard/index.tsxsrc/components/mentor/MentorExpandChatCard/index.tsxsrc/components/search/UniversityFilterSection.tsxsrc/components/search/UniversityRegionTabs.tsxsrc/types/university.tssrc/utils/designUtils.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- src/components/button/BlockBtn.tsx
- lint-fix.prd.md
- src/components/search/UniversityFilterSection.tsx
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 203
File: src/app/mentor/_ui/MentorClient/_ui/MentorFindSection/index.tsx:27-37
Timestamp: 2025-07-31T10:48:45.942Z
Learning: In the solid-connect-web project, manNomi handles merge conflicts and temporary code by leaving it in place during development with plans to remove it during proper feature implementation, rather than immediately fixing non-critical temporary code.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/components/ui/TabSelector.tsx:10-11
Timestamp: 2025-08-12T09:41:44.182Z
Learning: manNomi prefers to keep reusable UI components simple and focused on core functionality rather than adding many features. They don't want to over-engineer flexible/reusable UI components at the initial stage.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/components/mentor/MentorChatCard/index.tsx:17-21
Timestamp: 2025-08-24T11:14:34.297Z
Learning: manNomi prefers not to receive accessibility suggestions or recommendations during code reviews.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/usePostLogout.ts:17-33
Timestamp: 2025-08-24T11:13:08.477Z
Learning: manNomi prefers to prioritize user experience over perfect state consistency in auth flows. Specifically, in logout scenarios, they prefer to keep tokens intact on API failure to avoid forcing users to re-login, even if it means temporary UI state inconsistency.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/useDeleteUserAccount.ts:17-27
Timestamp: 2025-08-24T11:11:40.758Z
Learning: manNomi prefers optimistic navigation in auth-related flows (like account deletion) to prevent race conditions where token clearing before navigation could cause intermediate redirects to login page due to pending async requests failing.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/types/mentor.ts:70-73
Timestamp: 2025-08-12T04:07:04.134Z
Learning: manNomi prefers using Korean labels directly in enum values (e.g., MentorTab.MY_MENTEE = "나의 멘티") over separating enum keys from UI labels for efficiency and intuitiveness, considering scalability concerns as excessive for their current project needs.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: ci
🔇 Additional comments (5)
.eslintrc.js (1)
1-33: 전체 구조와 기본 설정이 잘 구성되어 있습니다! 👍ESLint 설정이 Next.js + TypeScript 프로젝트에 적합하게 구성되었습니다:
- 파서 설정: TypeScript 파서와 프로젝트 참조가 올바르게 구성됨
- 환경 설정: 브라우저, Node.js, ES2021 환경 적절히 활성화
- 확장 순서: Prettier가 마지막에 위치하여 충돌 방지
참고로, 과거 리뷰에서 지적된 Line 136의
project경로 문제가"./tsconfig.json"으로 올바르게 수정되었습니다.src/types/university.ts (1)
3-6: 새로운 RegionOption 인터페이스 추가가 적절합니다.지역 선택 UI를 위한 타입이 명확하게 정의되었습니다. value와 label 필드가 문자열로 선언되어 있어 사용처에서 타입 안정성을 제공합니다.
src/components/search/UniversityRegionTabs.tsx (1)
5-5: import 통합이 잘 이루어졌습니다.RegionKo와 RegionOption을 단일 모듈에서 가져오도록 변경하여 import 구문이 간결해지고 모듈 간 일관성이 향상되었습니다.
src/components/button/RoundBtn.tsx (1)
5-5: 유틸리티 함수 import 경로 중앙화가 적절합니다.cn 유틸리티를
@/lib/utils에서 가져오도록 변경하여 프로젝트의 유틸리티 중앙화 전략과 일치합니다.src/components/mentor/MentorCard/index.tsx (1)
19-19: 의도적인 타입 변경으로 실제 문제 없습니다.observeRef 타입이
(node: Element | null) => void인 것은 의도적이고 올바른 설계입니다.
useInfinityScroll 훅과의 일치
- useInfinityScroll이 반환하는 lastElementRef의 타입이 정확히
(node: Element | null) => void입니다- MentorCard의 observeRef 타입이 훅의 반환 타입과 완벽하게 일치합니다
IntersectionObserver API 호환성
- IntersectionObserver.observe()는 Element 타입을 받으므로, 더 일반적인 Element 타입이 정확합니다
- HTMLDivElement보다 Element로 추상화한 것이 API 요구사항에 더 부합합니다
실제 사용
- div는 Element이므로 타입 안전성이 유지되며, 타입 오류가 발생할 여지가 없습니다
- MentorFindSection에서 lastElementRef가 observeRef로 정확히 전달됩니다
타입이 "느슨해진" 것이 아니라 API 명세에 더 정확하게 맞춘 개선입니다. 추가 조치가 필요하지 않습니다.
Likely an incorrect or invalid review comment.
- Add lint:fix, format, format:check, typecheck scripts to package.json - Add lint:all and fix:all convenience scripts - Enhance CI workflow with Prettier check and PR title validation - Create .prettierignore for excluding build artifacts - Add development-workflow.md documentation - Apply Prettier formatting to all files
- designUtils, scoreUtils, universityUtils를 default export로 변경 - jwtUtils의 any 타입을 JwtPayload로 명시 - useInfinityScroll의 사용하지 않는 변수 제거 - 관련 import 문 수정
- EmailSignUpForm: any 타입을 unknown으로 변경 - SignupPolicyScreen: 중복된 className prop 제거 - SignupSurvey: any 타입들을 unknown으로 변경 - UniversityFilterSection, UniversityRegionTabs: import 경로에 확장자 추가 - useInfinityScroll: 타입 정의 수정
- .eslintrc.json → .eslintrc.js 변환 (주석 지원) - package.json에 lint:fix, format, format:check, lint:all, fix:all 스크립트 추가 - .prettierignore 파일 생성 - docs/eslint-prettier-migration-prd.md 마이그레이션 문서 추가
- .eslintrc.js overrides에 project: null 추가
- 설정 파일 패턴에 *.config.{js,mjs,ts} 추가
- Fix import/resolver typescript project path in .eslintrc.js - Add language identifiers to markdown code blocks in lint-fix.prd.md - Fix RegionOption import path and add type definition to university.ts - Remove .tsx extension from imports (ESLint import/extensions rule) - Consolidate cn utility to use @/lib/utils instead of duplicate in designUtils - Update MentorCard and MentorExpandChatCard ref types to Element | null
- Disable base no-unused-vars rule to prevent conflict with @typescript-eslint/no-unused-vars - Add fallback for shortenLanguageTestName undefined return in UniverSityCard
c5cfefd to
7f173ed
Compare
- UniversityDetail import 경로 수정 (../ → ./_ui/) - QueryKeys에 universityDetail 추가 - useGetRecommendedUniversity에서 useAuthStore 직접 사용 - MentorApplyCountModal 컴포넌트 복구 - ScoreCard에 toast import 추가
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/app/university/score/ScoreCard.tsx (1)
1-95: Prettier 포맷팅 이슈파이프라인에서 Prettier 포맷팅 문제가 감지되었습니다. 다음 명령어를 실행하여 수정할 수 있습니다:
npm run format
🧹 Nitpick comments (5)
src/app/university/score/example/gpa-cert/page.tsx (1)
59-94: 포매팅 변경이 일관되게 잘 적용되었습니다.CI 워크플로우 표준화의 일환으로 텍스트 콘텐츠를 멀티라인 형식으로 변경한 것이 코드 가독성과 git diff 추적에 도움이 됩니다. 변경사항들이 일관되게 적용되어 좋습니다.
다만, 95번 라인의 유사한 구조도 동일한 형식으로 변경하면 더 일관성 있을 것 같습니다:
- <span style={{ ...h1Style, marginTop: "48px" }}>성적 증명서 발급 방법</span> + <span style={{ ...h1Style, marginTop: "48px" }}> + 성적 증명서 발급 방법 + </span>src/components/mentor/MentorApplyCountModal/index.tsx (1)
9-11: 래퍼 컴포넌트의 제거를 검토해주세요.
MentorApplyCountContent에 이미"use client"지시어가 있어, 현재 래퍼 컴포넌트는 불필요한 중복입니다:
MentorApplyCountContent는 클라이언트 컴포넌트로 상태와 훅(useState, useAuthStore, useGetMentoringUncheckedCount)을 활용하고 있습니다.MentorApplyCountModal은 단순히 이를 감싸기만 하므로 추가 가치를 제공하지 않습니다.- 이 래퍼를 제거하고
MentorApplyCountContent를 직접 사용하면 컴포넌트 계층을 단순화할 수 있습니다.래퍼가 필요한 경우 에러 바운더리, 레이아웃 로직 등 실질적인 기능을 추가해주세요.
src/utils/useInfinityScroll.ts (1)
28-29: IntersectionObserver 콜백 패턴을 더 간결하게 작성할 수 있습니다.현재 코드는 정상 작동하지만, 매개변수 단계에서 직접 destructuring하는 패턴이 더 간결합니다.
🔎 더 간결한 destructuring 패턴 제안
observerRef.current = new IntersectionObserver( - (entries) => { - const [entry] = entries; + ([entry]) => { if (entry.isIntersecting) { fetchNextPage(); } },docs/development-workflow.md (1)
20-24: 코드 블록 언어 지정 추가 권장Line 20의 코드 블록에 언어 식별자가 없어 markdownlint 경고가 발생합니다. 가독성 향상을 위해 언어를 지정하는 것을 권장합니다.
🔎 제안하는 수정 방안
-``` +```text <type>: <subject> <body> (선택)</details> </blockquote></details> <details> <summary>docs/husky-ci-workflow-prd.md (1)</summary><blockquote> `315-322`: **코드 블록 언어 식별자 누락** 일부 코드 블록에 언어 식별자가 없습니다. 일관성을 위해 추가를 권장합니다: - Line 315: 파일 구조 → `text` 또는 `plaintext` - Line 378: 파일 구조 → `text` 또는 `plaintext` - Line 455: 커밋 메시지 형식 → `text` - Lines 475, 482, 491: 커밋 메시지 예시 → `text` <details> <summary>🔎 예시 수정</summary> ```diff -``` +```text .husky/ ├── _/ # Husky 내부 파일Also applies to: 378-391, 455-459, 475-495
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (150)
.eslintrc.js.eslintrc.json.github/ISSUE_TEMPLATE/bug_report.md.github/ISSUE_TEMPLATE/feature_request.md.github/workflows/ci.yml.prettierignorecommitlint.config.jscomponents.jsondocs/development-workflow.mddocs/eslint-prettier-migration-prd.mddocs/husky-ci-workflow-prd.mdlint-fix.prd.mdpackage.jsonsrc/api/auth/client/usePostAppleAuth.tssrc/api/auth/client/usePostEmailAuth.tssrc/api/auth/client/usePostKakaoAuth.tssrc/api/boards/clients/useGetPostList.tssrc/api/boards/server/getPostList.tssrc/api/community/client/useCreatePost.tssrc/api/community/client/useDeletePost.tssrc/api/my/client/usePatchMyInfo.tssrc/api/my/client/usePatchMyPassword.tssrc/api/news/client/useDeleteArticle.tssrc/api/news/client/usePostAddArticle.tssrc/api/reports/client/usePostReport.tssrc/api/score/client/usePostGpaScore.tssrc/api/score/client/usePostLanguageTestScore.tssrc/api/university/client/queryKey.tssrc/api/university/client/useGetRecommendedUniversity.tssrc/app/(home)/_ui/FindLastYearScoreBar/index.tsxsrc/app/(home)/_ui/NewsSection/index.tsxsrc/app/(home)/_ui/PopularUniversitySection/_ui/PopularUniversityCard.tsxsrc/app/(home)/_ui/UniversityList/index.tsxsrc/app/(home)/page.tsxsrc/app/community/[boardCode]/PostCards.tsxsrc/app/community/[boardCode]/PostWriteButton.tsxsrc/app/community/[boardCode]/[postId]/CommentInput.tsxsrc/app/community/[boardCode]/[postId]/CommentSection.tsxsrc/app/community/[boardCode]/[postId]/Content.tsxsrc/app/community/[boardCode]/[postId]/KebabMenu.tsxsrc/app/community/[boardCode]/[postId]/modify/PostModifyForm.tsxsrc/app/community/[boardCode]/create/PostForm.tsxsrc/app/login/LoginContent.tsxsrc/app/mentor/[id]/_ui/MentorDetialContent/_ui/MentorArticle/index.tsxsrc/app/mentor/[id]/_ui/MentorDetialContent/index.tsxsrc/app/mentor/_ui/MentorClient/_ui/MenteePageTabs/index.tsxsrc/app/mentor/_ui/MentorClient/_ui/MentorFindSection/index.tsxsrc/app/mentor/_ui/MentorClient/_ui/MentorPage/_ui/MyMentorSection/index.tsxsrc/app/mentor/_ui/MentorClient/_ui/MentorPage/index.tsxsrc/app/mentor/_ui/MentorClient/index.tsxsrc/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatInputBar/index.tsxsrc/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/index.tsxsrc/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsxsrc/app/mentor/chat/[chatId]/_ui/ChatNavBar/index.tsxsrc/app/mentor/chat/[chatId]/page.tsxsrc/app/mentor/chat/_ui/ChatPageClient/index.tsxsrc/app/mentor/modify/_ui/ModifyContent/_ui/AddArticleCard/index.tsxsrc/app/mentor/modify/_ui/ModifyContent/_ui/ArticlePanel/index.tsxsrc/app/mentor/modify/_ui/ModifyContent/_ui/ChannelBox/ChannelItem.tsxsrc/app/mentor/modify/_ui/ModifyContent/index.tsxsrc/app/mentor/waiting/_ui/WaitingContent/index.tsxsrc/app/my/_ui/MyProfileContent/index.tsxsrc/app/my/apply-mentor/_components/CompletionScreen/index.tsxsrc/app/my/apply-mentor/_components/InterestCountriesScreen/index.tsxsrc/app/my/apply-mentor/_components/StudyStatusScreen/index.tsxsrc/app/my/apply-mentor/_components/UniversityScreen/index.tsxsrc/app/my/favorite/_ui/FavoriteContent/index.tsxsrc/app/my/match/_ui/MatchContent/index.tsxsrc/app/my/modify/_ui/ModifyContent/_ui/ImageInputFiled/index.tsxsrc/app/my/modify/_ui/ModifyContent/_ui/InputFiled/index.tsxsrc/app/my/modify/_ui/ModifyContent/_ui/ReadOnlyField/index.tsxsrc/app/my/modify/_ui/ModifyContent/index.tsxsrc/app/my/password/_ui/PasswordContent/_ui/PasswordInput/index.tsxsrc/app/my/password/_ui/PasswordContent/index.tsxsrc/app/sign-up/email/EmailSignUpForm.tsxsrc/app/terms/page.tsxsrc/app/university/CustomDropdown.tsxsrc/app/university/SearchBar.tsxsrc/app/university/[id]/_ui/UniversityDetail/_ui/InfoSection.tsxsrc/app/university/[id]/_ui/UniversityDetail/_ui/LanguageSection.tsxsrc/app/university/[id]/_ui/UniversityDetail/_ui/MapSection.tsxsrc/app/university/[id]/_ui/UniversityDetail/_ui/TitleSection.tsxsrc/app/university/[id]/_ui/UniversityDetail/index.tsxsrc/app/university/application/ScorePageContent.tsxsrc/app/university/application/ScoreSearchBar.tsxsrc/app/university/application/ScoreSearchField.tsxsrc/app/university/application/ScoreSheet.tsxsrc/app/university/application/apply/ApplyPageContent.tsxsrc/app/university/application/apply/ConfirmStep.tsxsrc/app/university/application/apply/DoneStep.tsxsrc/app/university/application/apply/EmptyGPA.tsxsrc/app/university/application/apply/GpaStep.tsxsrc/app/university/application/apply/LanguageStep.tsxsrc/app/university/application/apply/UniversityStep.tsxsrc/app/university/score/ScoreCard.tsxsrc/app/university/score/ScoreScreen.tsxsrc/app/university/score/example/gpa-cert/page.tsxsrc/app/university/score/submit/gpa/GpaSubmitForm.tsxsrc/app/university/score/submit/language-test/LanguageTestSubmitForm.tsxsrc/app/university/score/submit/language-test/_lib/schema.tssrc/app/university/search/PageContent.tsxsrc/app/university/search/SearchBar.tsxsrc/components/button/BlockBtn.tsxsrc/components/button/RoundBtn.tsxsrc/components/home/NewsCards.tsxsrc/components/layout/GlobalLayout/index.tsxsrc/components/layout/GlobalLayout/ui/BottomNavigation/index.tsxsrc/components/layout/PathBasedNavigation/index.tsxsrc/components/layout/TopDetailNavigation.tsxsrc/components/login/signup/SignupPolicyScreen.tsxsrc/components/login/signup/SignupPrepareScreen.tsxsrc/components/login/signup/SignupProfileScreen.tsxsrc/components/login/signup/SignupRegionScreen.tsxsrc/components/login/signup/SignupSurvey.tsxsrc/components/mentor/ArticleBottomSheetModal/index.tsxsrc/components/mentor/ChannelSelct/index.tsxsrc/components/mentor/MentorApplyCountModal/index.tsxsrc/components/mentor/MentorCard/index.tsxsrc/components/mentor/MentorChatCard/index.tsxsrc/components/mentor/MentorExpandChatCard/index.tsxsrc/components/modal/ConfirmCancelModal.tsxsrc/components/modal/IconAlertModal.tsxsrc/components/modal/IconConfirmModal.tsxsrc/components/modal/SurveyModal.tsxsrc/components/modal/TextModal.tsxsrc/components/score/SubmitResult.tsxsrc/components/search/UniversityFilterSection.tsxsrc/components/search/UniversityRegionTabs.tsxsrc/components/search/UniversitySearchInput.tsxsrc/components/ui/BottomSheet/index.tsxsrc/components/ui/CloudSpinnerPage/index.tsxsrc/components/ui/EmptySdwBCards.tsxsrc/components/ui/LinkedTextWithIcon/index.tsxsrc/components/ui/Progress.tsxsrc/components/ui/ReportPanel/index.tsxsrc/components/ui/ReusableDropdown/index.tsxsrc/components/ui/ScrollTab.tsxsrc/components/ui/Select.tsxsrc/components/ui/TabSelector.tsxsrc/components/ui/Toast/index.tsxsrc/components/ui/TopLogoBar/index.tsxsrc/components/ui/UniverSityCard/index.tsxsrc/components/university/UniversityCards/index.tsxsrc/lib/utils.tssrc/types/university.tssrc/utils/designUtils.tssrc/utils/jwtUtils.tssrc/utils/scoreUtils.tssrc/utils/universityUtils.tssrc/utils/useInfinityScroll.ts
💤 Files with no reviewable changes (2)
- src/api/boards/server/getPostList.ts
- .eslintrc.json
✅ Files skipped from review due to trivial changes (44)
- src/app/university/score/ScoreScreen.tsx
- src/api/community/client/useCreatePost.ts
- src/components/modal/SurveyModal.tsx
- components.json
- src/components/modal/IconAlertModal.tsx
- src/api/auth/client/usePostEmailAuth.ts
- src/components/ui/ScrollTab.tsx
- src/components/layout/GlobalLayout/index.tsx
- src/app/mentor/modify/_ui/ModifyContent/_ui/ArticlePanel/index.tsx
- src/components/mentor/MentorChatCard/index.tsx
- src/app/mentor/modify/_ui/ModifyContent/_ui/ChannelBox/ChannelItem.tsx
- src/components/modal/IconConfirmModal.tsx
- src/app/university/application/apply/ApplyPageContent.tsx
- src/app/my/modify/_ui/ModifyContent/index.tsx
- src/app/my/apply-mentor/_components/CompletionScreen/index.tsx
- src/app/university/application/apply/GpaStep.tsx
- src/app/(home)/_ui/PopularUniversitySection/_ui/PopularUniversityCard.tsx
- src/app/(home)/_ui/UniversityList/index.tsx
- src/app/my/apply-mentor/_components/UniversityScreen/index.tsx
- src/app/mentor/_ui/MentorClient/_ui/MentorPage/_ui/MyMentorSection/index.tsx
- src/components/mentor/ChannelSelct/index.tsx
- src/components/home/NewsCards.tsx
- src/app/mentor/modify/_ui/ModifyContent/_ui/AddArticleCard/index.tsx
- src/app/university/application/ScoreSearchBar.tsx
- src/app/university/CustomDropdown.tsx
- src/components/ui/LinkedTextWithIcon/index.tsx
- src/app/university/application/apply/UniversityStep.tsx
- src/app/community/[boardCode]/[postId]/CommentSection.tsx
- src/app/university/search/SearchBar.tsx
- src/api/news/client/useDeleteArticle.ts
- src/app/my/_ui/MyProfileContent/index.tsx
- src/api/score/client/usePostLanguageTestScore.ts
- src/app/community/[boardCode]/[postId]/KebabMenu.tsx
- src/api/community/client/useDeletePost.ts
- src/components/score/SubmitResult.tsx
- src/components/ui/CloudSpinnerPage/index.tsx
- src/app/(home)/_ui/NewsSection/index.tsx
- src/api/score/client/usePostGpaScore.ts
- src/api/boards/clients/useGetPostList.ts
- src/components/modal/TextModal.tsx
- src/components/login/signup/SignupPrepareScreen.tsx
- src/components/university/UniversityCards/index.tsx
- src/app/university/score/submit/language-test/LanguageTestSubmitForm.tsx
- src/components/login/signup/SignupProfileScreen.tsx
🚧 Files skipped from review as they are similar to previous changes (13)
- src/components/button/RoundBtn.tsx
- src/types/university.ts
- src/utils/scoreUtils.ts
- src/app/sign-up/email/EmailSignUpForm.tsx
- src/utils/designUtils.ts
- src/components/login/signup/SignupSurvey.tsx
- .prettierignore
- .eslintrc.js
- src/components/mentor/MentorCard/index.tsx
- src/components/login/signup/SignupPolicyScreen.tsx
- src/components/button/BlockBtn.tsx
- package.json
- src/components/mentor/MentorExpandChatCard/index.tsx
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/components/ui/TabSelector.tsx:10-11
Timestamp: 2025-08-12T09:41:44.182Z
Learning: manNomi prefers to keep reusable UI components simple and focused on core functionality rather than adding many features. They don't want to over-engineer flexible/reusable UI components at the initial stage.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/components/mentor/MentorChatCard/index.tsx:17-21
Timestamp: 2025-08-24T11:14:34.297Z
Learning: manNomi prefers not to receive accessibility suggestions or recommendations during code reviews.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/usePostLogout.ts:17-33
Timestamp: 2025-08-24T11:13:08.477Z
Learning: manNomi prefers to prioritize user experience over perfect state consistency in auth flows. Specifically, in logout scenarios, they prefer to keep tokens intact on API failure to avoid forcing users to re-login, even if it means temporary UI state inconsistency.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/useDeleteUserAccount.ts:17-27
Timestamp: 2025-08-24T11:11:40.758Z
Learning: manNomi prefers optimistic navigation in auth-related flows (like account deletion) to prevent race conditions where token clearing before navigation could cause intermediate redirects to login page due to pending async requests failing.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/types/mentor.ts:70-73
Timestamp: 2025-08-12T04:07:04.134Z
Learning: manNomi prefers using Korean labels directly in enum values (e.g., MentorTab.MY_MENTEE = "나의 멘티") over separating enum keys from UI labels for efficiency and intuitiveness, considering scalability concerns as excessive for their current project needs.
📚 Learning: 2025-07-20T09:46:18.121Z
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 195
File: src/app/mento/modify/_components/MentoArticlePanel/index.tsx:7-7
Timestamp: 2025-07-20T09:46:18.121Z
Learning: In the solid-connect-web project, the team prefers using "mentor" terminology over "mento" for consistency. They are currently in the process of unifying all naming from "mento" to "mentor" including page routes, component names, and other references.
Applied to files:
src/app/mentor/_ui/MentorClient/_ui/MentorPage/index.tsxsrc/app/mentor/_ui/MentorClient/_ui/MenteePageTabs/index.tsxsrc/app/mentor/chat/[chatId]/_ui/ChatNavBar/index.tsxsrc/app/mentor/[id]/_ui/MentorDetialContent/index.tsxsrc/app/mentor/chat/_ui/ChatPageClient/index.tsx
📚 Learning: 2025-08-12T03:44:45.718Z
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/app/mentor/modify/_ui/ModifyContent/_hooks/usePutMyMentorProfileHandler.ts:24-29
Timestamp: 2025-08-12T03:44:45.718Z
Learning: 이 프로젝트에서는 React Query의 전역 에러 처리를 사용하므로, mutation 호출 시 try-catch를 추가하지 않는다. mutate() 호출만으로 충분하며, 필요한 경우에만 mutation 설정에서 onError 콜백을 사용한다.
Applied to files:
src/api/reports/client/usePostReport.ts
📚 Learning: 2025-08-12T03:44:45.718Z
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/app/mentor/modify/_ui/ModifyContent/_hooks/usePutMyMentorProfileHandler.ts:24-29
Timestamp: 2025-08-12T03:44:45.718Z
Learning: React Query를 사용하는 프로젝트에서는 전역 에러 처리가 설정되어 있을 때 mutation 호출 시 try-catch를 추가할 필요가 없다. mutate() 함수 호출만으로 충분하며, 필요시 mutation 설정에서 onError 콜백을 사용한다.
Applied to files:
src/api/reports/client/usePostReport.ts
📚 Learning: 2025-08-12T04:07:04.134Z
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/types/mentor.ts:70-73
Timestamp: 2025-08-12T04:07:04.134Z
Learning: manNomi prefers using Korean labels directly in enum values (e.g., MentorTab.MY_MENTEE = "나의 멘티") over separating enum keys from UI labels for efficiency and intuitiveness, considering scalability concerns as excessive for their current project needs.
Applied to files:
src/app/mentor/_ui/MentorClient/_ui/MenteePageTabs/index.tsx
📚 Learning: 2025-08-06T06:19:56.705Z
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 235
File: src/app/mentor/_ui/MentorClient/_hooks/useRouterHandler.ts:16-17
Timestamp: 2025-08-06T06:19:56.705Z
Learning: manNomi는 useRouterHandler 훅에서 로그인 체크 및 리다이렉트 로직을 useEffect를 통해 관리하여 사이드 이펙트를 적절히 처리하고 있다.
Applied to files:
src/app/university/application/ScorePageContent.tsx
📚 Learning: 2025-08-11T06:07:23.563Z
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 239
File: src/utils/jwtUtils.ts:32-37
Timestamp: 2025-08-11T06:07:23.563Z
Learning: 이 프로젝트에서는 JWT 토큰을 사용하는 인증 관련 페이지들에서 SSR을 사용하지 않음. 서버 비용과 렌더링 이득을 고려했을 때 SSR이 필요하지 않고, SEO도 중요하지 않은 부분이므로 JWT 유틸리티 함수들(jwtUtils.ts)에서 atob 사용이 문제되지 않음. Node.js 환경 호환성을 위한 base64UrlDecode 변경이 불필요함.
Applied to files:
src/utils/jwtUtils.ts
🧬 Code graph analysis (13)
src/components/ui/Progress.tsx (1)
src/lib/utils.ts (1)
cn(4-6)
src/components/ui/TopLogoBar/index.tsx (1)
public/svgs/home/index.ts (1)
IconCloud(11-11)
src/components/layout/TopDetailNavigation.tsx (1)
public/svgs/index.ts (1)
IconArrowBackFilled(29-29)
src/utils/universityUtils.ts (1)
src/constants/application.ts (1)
SHORT_LANGUAGE_TEST(28-35)
src/app/mentor/modify/_ui/ModifyContent/index.tsx (1)
public/svgs/mentor/index.ts (1)
IconUserPrimaryColor(39-39)
src/app/university/application/apply/ConfirmStep.tsx (1)
public/svgs/mentor/index.ts (1)
IconCheck(52-52)
src/app/mentor/chat/_ui/ChatPageClient/index.tsx (1)
src/utils/datetimeUtils.ts (1)
convertISODateToKoreanTime(47-62)
src/app/community/[boardCode]/[postId]/Content.tsx (1)
public/svgs/community/index.ts (1)
IconCommunication(4-4)
src/components/layout/PathBasedNavigation/index.tsx (1)
public/svgs/index.ts (1)
IconArrowBackFilled(29-29)
src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/index.tsx (3)
src/utils/fileUtils.ts (1)
getFileExtension(2-4)src/utils/datetimeUtils.ts (1)
formatTime(65-84)src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/_utils/messageUtils.ts (1)
shouldShowContent(25-27)
src/app/community/[boardCode]/[postId]/modify/PostModifyForm.tsx (1)
public/svgs/index.ts (1)
IconArrowBackFilled(29-29)
src/api/university/client/useGetRecommendedUniversity.ts (1)
src/utils/axiosInstance.ts (2)
axiosInstance(45-48)publicAxiosInstance(39-42)
src/app/(home)/page.tsx (1)
public/svgs/home/index.ts (2)
IconMagnifyingGlass(14-14)IconMuseum(15-15)
🪛 actionlint (1.7.9)
.github/workflows/ci.yml
75-75: "github.event.pull_request.title" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details
(expression)
🪛 ast-grep (0.40.3)
src/app/community/[boardCode]/[postId]/modify/PostModifyForm.tsx
[warning] 138-138: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
src/app/community/[boardCode]/create/PostForm.tsx
[warning] 132-132: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
src/app/(home)/page.tsx
[error] 91-91: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🪛 GitHub Actions: CI
src/components/mentor/MentorApplyCountModal/index.tsx
[warning] 1-1: Prettier formatting issues detected. Run 'prettier --write' to fix formatting.
src/app/university/score/ScoreCard.tsx
[warning] 1-1: Prettier formatting issues detected. Run 'prettier --write' to fix formatting.
🪛 markdownlint-cli2 (0.18.1)
docs/husky-ci-workflow-prd.md
104-104: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
110-110: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
116-116: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
123-123: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
129-129: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
134-134: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
139-139: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
146-146: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
151-151: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
156-156: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
163-163: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
169-169: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
315-315: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
378-378: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
455-455: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
475-475: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
482-482: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
491-491: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/development-workflow.md
20-20: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/eslint-prettier-migration-prd.md
104-104: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
110-110: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
116-116: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
123-123: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
129-129: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
134-134: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
139-139: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
146-146: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
151-151: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
156-156: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
163-163: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
169-169: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🔇 Additional comments (102)
src/app/mentor/chat/[chatId]/page.tsx (1)
22-22: 코드 스타일 통일 변경 승인Tailwind 클래스 순서를 표준화한 변경사항으로 확인됩니다:
- 변경 내용:
"w-full flex flex-col"→"flex w-full flex-col"- 기능적으로 동일한 렌더링 결과를 제공하며, Prettier/ESLint 설정에 따른 자동 포매팅으로 보입니다.
이번 PR의 CI 워크플로우 및 코드 스타일 표준화 목표와 일치합니다.
.github/ISSUE_TEMPLATE/feature_request.md (1)
4-4: ✅ 이슈 템플릿 통일성 개선템플릿 메타데이터를 정돈했네요. 변경 사항:
title필드 - 사용자가 직접 입력하도록 빈 상태 유지 ✓assignees필드 - 초기 검토자 미지정 상태 유지 ✓
bug_report.md와의 일관성도 좋습니다.Also applies to: 6-6
.github/ISSUE_TEMPLATE/bug_report.md (2)
4-4: ✅ 템플릿 메타데이터 표준화
feature_request.md와 동일한 방식으로 통일했습니다:
title: ""- 사용자 입력용 기본값 ✓assignees: ""- 초기 미지정 상태 ✓Also applies to: 6-6
14-20: ✅ 버그 재현 안내 개선"재현 방법" 섹션을 더 명확하게 정리했습니다:
- 한국어 안내 문구 추가 (라인 15) - 사용자가 어떻게 작성해야 하는지 가이드 ✓
- 단계별 구조 완성 (라인 20의 "4. See error" 추가) - 표준적인 재현 단계 완성 ✓
- 가독성 개선 - 빈 줄 추가로 섹션 구분을 명확하게 함 ✓
버그 리포트 품질이 개선될 것 같습니다.
src/app/mentor/_ui/MentorClient/_ui/MentorFindSection/index.tsx (1)
31-31: LGTM! Tailwind 클래스 순서 정리가 잘 적용되었습니다. 👍이 파일의 변경 사항을 정리해 드릴게요:
h2 요소 (Line 31)
typo-bold-5 text-gray-900→text-gray-900 typo-bold-5- Tailwind 클래스 순서만 변경되었고, 스타일에는 영향 없음
button 요소 (Line 39)
typo-sb-12 leading-[150%]→leading-[150%] typo-sb-12- 마찬가지로 순서만 변경됨
PR의 CI 워크플로우 추가 및 Prettier 설정 적용에 따른 자동 정렬 결과로 보이며, 기능적인 변경은 전혀 없습니다. 앞으로 일관된 클래스 순서 유지에 도움이 될 것 같아요! 🎉
Also applies to: 39-41
src/components/modal/ConfirmCancelModal.tsx (1)
28-29: 명시적인 텍스트 색상 추가로 스타일 일관성 확보변경사항을 간단히 정리하면:
제목 텍스트 (Line 28)
text-gray-900클래스 추가로 명시적 색상 지정내용 텍스트 (Line 29)
text-gray-300클래스 추가로 명시적 색상 지정취소 버튼 텍스트 (Line 37)
text-gray-700클래스 추가로 명시적 색상 지정확인 버튼 텍스트 (Line 44)
text-white클래스 추가로 명시적 색상 지정로직 변경 없이 스타일만 명확하게 정의한 변경입니다. CI 워크플로우의 일환으로 코드 일관성을 높이는 좋은 개선입니다.
Also applies to: 37-37, 44-44
src/api/auth/client/usePostKakaoAuth.ts (1)
5-6: LGTM! 1. Import 순서 정리 완료 ✨
validateSafeRedirect다음에publicAxiosInstanceimport가 위치하도록 순서가 변경되었습니다.- 이는 새로운 ESLint/Prettier 설정에 맞춘 포맷팅 변경으로, 기능적 변화는 없습니다.
src/api/my/client/usePatchMyPassword.ts (1)
9-11: LGTM! 1. Import 순서 재배치 완료 ✨
toastimport 다음에@tanstack/react-queryimport가 위치하도록 순서가 정리되었습니다.- CI 워크플로우에 추가된 린팅 규칙에 맞춘 포맷팅 변경이며, 실제 동작에는 영향이 없습니다.
src/api/auth/client/usePostAppleAuth.ts (1)
5-6: LGTM! 1. Import 순서 정리 완료 ✨
validateSafeRedirect다음에publicAxiosInstanceimport가 위치하도록 순서가 변경되었습니다.usePostKakaoAuth.ts,usePostEmailAuth.ts와 동일한 패턴으로 일관성 있게 정리되었습니다.- 새로운 CI 린팅 설정에 따른 포맷팅 변경이며, 기능적 변화는 없습니다.
src/components/ui/EmptySdwBCards.tsx (1)
7-7: LGTM! Prettier 포매팅이 잘 적용되었습니다.Tailwind CSS 클래스의 순서가 재정렬되었지만, 실제 스타일링에는 영향이 없는 변경사항입니다. CI 워크플로우와 함께 도입된 코드 포매팅 일관성 개선의 일환으로 보입니다.
src/components/ui/Select.tsx (1)
23-23: Tailwind 클래스 순서 정리가 잘 적용되었습니다.
SelectTrigger 컴포넌트 (Line 23)
- Tailwind 유틸리티 클래스 순서를 재정렬했습니다.
SelectItem 컴포넌트 (Line 111)
- Tailwind 유틸리티 클래스 순서를 재정렬했습니다.
이 변경사항들은 ESLint/Prettier 설정에 따른 순수 포매팅 정리이며, 컴포넌트의 기능이나 렌더링 결과에는 영향을 주지 않습니다. CI 워크플로우 추가와 함께 코드 스타일을 일관되게 유지하는 좋은 접근입니다.
Also applies to: 111-111
src/components/ui/TopLogoBar/index.tsx (1)
8-8: 포맷팅 변경이 깔끔하게 적용되었습니다!Tailwind 클래스 순서가 일관되게 정리되었네요. 기능적 영향 없이 코드 스타일만 개선되었습니다:
컨테이너 클래스 순서 정렬 (라인 8)
max-w-app이 뒤로 이동하여 positioning → layout → sizing 순서로 정렬텍스트 스타일 클래스 순서 정렬 (라인 14)
text-k-0와typo-sb-6순서 변경CI 워크플로우 및 린터 설정 추가의 일환으로 보이며, 코드베이스 전반의 일관성 향상에 기여하는 좋은 변경입니다.
Also applies to: 14-14
src/app/university/application/apply/EmptyGPA.tsx (1)
16-16: 코드 변경 승인: Tailwind 클래스 정렬
변경 내용
text-white와typo-sb-9클래스의 순서가 변경되었습니다.- 기능적 차이는 없으며, 순수하게 포매팅 개선입니다.
검토 결과
- CI 워크플로우 추가와 일관된 자동화된 코드 포매팅 결과로 보입니다.
- 클래스 정렬을 통해 코드 일관성이 향상되었습니다.
src/components/ui/Toast/index.tsx (1)
57-57: 포매팅 변경 사항 확인 완료Tailwind 클래스 순서가 재정렬되었습니다. 모든 유틸리티 클래스가 그대로 유지되어 기능상 변경 사항은 없으며, CI 워크플로우 추가 목적과 일치하는 포매팅 개선입니다.
src/app/community/[boardCode]/PostCards.tsx (1)
82-96: 포매팅 정리가 깔끔하게 적용되었습니다!변경사항을 확인한 결과:
클래스명 순서 재정렬
- Tailwind CSS 클래스 순서가 일관되게 정렬되었습니다
- 날짜 표시, 제목, 본문, 좋아요/댓글 수 영역 모두 포함
기능적 영향
- 로직 변경 없음
- UI 렌더링 결과 동일
- 순수 포매팅 개선
CI 워크플로우 도입에 따른 자동 포매팅 적용으로, 코드 일관성이 향상되었습니다.
src/components/ui/BottomSheet/index.tsx (1)
89-89: 포매팅 변경사항 확인 완료!Tailwind CSS 클래스 순서가 조정되었습니다. 이는 CI 워크플로우의 Prettier 설정에 따른 자동 포매팅으로 보이며, 기능적인 변경사항은 없습니다.
- 변경 내용:
typo-sb-5클래스의 위치가 재정렬됨- 런타임 동작이나 스타일 렌더링에는 영향 없음
- PR 전체에 걸쳐 일관된 포매팅 적용의 일부
src/app/mentor/_ui/MentorClient/_ui/MenteePageTabs/index.tsx (1)
37-37: CI 린팅 규칙에 맞춘 클래스 순서 정리가 잘 적용되었습니다!새로 추가된 Prettier/ESLint 설정에 따라 Tailwind 클래스 순서가 일관되게 정리되었습니다:
- Line 37: 색상 클래스(
text-k-900)를 타이포그래피 클래스(typo-sb-5) 앞으로 이동- Line 47: 동일한 패턴으로
text-k-500를typo-medium-3앞으로 배치기능적 변경 없이 코드 일관성만 개선된 좋은 변경입니다.
Also applies to: 47-47
src/app/community/[boardCode]/[postId]/CommentInput.tsx (1)
41-57: LGTM! 포매팅 표준화 및 레이아웃 개선이 적절하게 적용되었습니다.이 변경사항들은 ESLint/Prettier 마이그레이션의 일환으로 보이며, 다음과 같이 정리됩니다:
레이아웃 개선 (Line 41)
min-w-app클래스 추가로 최소 너비 보장클래스 순서 정리 (Lines 45, 57)
- Tailwind 클래스 순서 표준화
- 시각적/기능적 변화 없음
코드 로직과 동작에는 영향이 없으며, 일관된 코드 스타일을 유지하기 위한 변경으로 적절합니다.
src/app/community/[boardCode]/[postId]/Content.tsx (1)
84-84: 포맷팅 표준화 작업이 잘 적용되었습니다!이 파일의 모든 변경사항은 Tailwind 유틸리티 클래스의 순서를 정리한 순수 포맷팅 개선입니다. 기능적 변경은 전혀 없으며, CI 워크플로우 추가에 따른 프로젝트 전반의 코드 스타일 통일 작업의 일환으로 확인됩니다.
변경된 부분들을 정리하면:
카테고리 배지 (Line 84)
- 텍스트 색상 클래스 위치 조정
게시글 제목 및 내용 (Lines 87-88)
text-black,text-gray-850등 색상 관련 클래스를 타이포그래피 클래스와 함께 정렬좋아요/댓글 카운트 (Lines 106, 110)
text-gray-500클래스 위치 통일사용자 정보 영역 (Lines 131, 134)
- 닉네임과 날짜의 텍스트 색상 클래스 정렬
이미지 팝업 헤더 (Line 197)
- 제목 텍스트 색상 클래스 위치 조정
모든 변경사항이 시각적 결과에는 영향을 주지 않으며, 일관된 코드 스타일을 유지하는 데 기여합니다.
Also applies to: 87-88, 106-106, 110-110, 131-131, 134-134, 197-197
src/components/login/signup/SignupRegionScreen.tsx (1)
40-40: 코드 포맷팅이 일관되게 적용되었습니다.이 변경사항들은 Tailwind CSS 클래스 순서를 정리한 것으로, CI 워크플로우 및 ESLint/Prettier 설정 추가라는 PR 목표에 부합합니다.
변경 내용:
Line 40: 타이포그래피와 텍스트 색상 클래스 순서 조정
text-k-900을typo-bold-1앞으로 이동Line 53: 레이아웃 클래스 순서 조정
fixed,bottom-14,w-full,max-w-app,bg-white순서로 재정렬Line 83: 타이포그래피와 텍스트 색상 클래스 순서 조정
text-k-800을typo-sb-7앞으로 이동Line 88: 텍스트 정렬 및 색상 클래스 순서 조정
text-center,text-white,typo-regular-2순서로 재정렬모든 변경사항은 시각적·기능적 영향이 없으며, 코드베이스 전체의 일관성을 높이는 포맷팅 개선입니다.
Also applies to: 53-53, 83-83, 88-88
src/app/my/favorite/_ui/FavoriteContent/index.tsx (1)
34-34: Tailwind 클래스 순서 재정렬 - LGTM!CI 워크플로우 추가와 함께 코드 스타일을 표준화하는 작업의 일환으로 Tailwind 클래스 순서를 재정렬하셨네요. 변경사항을 정리하면 다음과 같습니다:
제목 영역 (라인 34)
text-k-700위치 조정으로 색상 관련 클래스 그룹화편집 버튼 (라인 44)
typo-medium-2클래스를 맨 뒤로 이동취소 버튼 (라인 53)
typo-medium-2클래스를 맨 뒤로 이동삭제 버튼 (라인 62)
typo-medium-2클래스를 맨 뒤로 이동빈 상태 메시지 (라인 75)
text-k-400위치를 색상 관련 클래스와 함께 배치이러한 변경사항들은 순수하게 포매팅만 조정한 것으로, 렌더링 결과나 기능에는 전혀 영향을 주지 않습니다. 프로젝트 전반의 일관된 코드 스타일을 위한 좋은 개선입니다!
Also applies to: 44-44, 53-53, 62-62, 75-75
src/api/reports/client/usePostReport.ts (1)
10-10: Import 순서 변경 확인 완료
변경 내용
useMutationimport가toastimport 이후로 이동되었습니다.검토 결과
- 이 변경사항은 PR에서 추가된 ESLint/Prettier 설정의 일부로 보입니다.
- 로직이나 동작에는 영향이 없으며, 코드 포맷팅 규칙을 따르기 위한 자동 정렬로 판단됩니다.
src/api/news/client/usePostAddArticle.ts (1)
11-11: Import 순서 변경 확인 완료
변경 내용
toastimport의 위치가 조정되었습니다.검토 결과
- 이 변경사항은 새로 적용된 린팅 규칙에 따른 자동 포맷팅으로 보입니다.
- 기능이나 동작에는 영향이 없으며, 코드 스타일 일관성을 위한 변경입니다.
src/app/mentor/waiting/_ui/WaitingContent/index.tsx (1)
24-24: 포매팅 변경이 올바르게 적용되었습니다!세 개의 제목 요소에서 Tailwind 클래스 순서가 일관되게 정리되었습니다:
라인 24:
<h2>요소의 className 재정렬
text-k-900과typo-sb-5클래스 순서 조정라인 33:
<h3>요소의 className 재정렬
- 동일한 클래스 순서 패턴 적용
라인 60:
<h3>요소의 className 재정렬
- 일관된 포매팅 유지
이 변경사항들은 CI 워크플로우(Prettier/ESLint) 설정의 일환으로, 렌더링 결과에는 영향을 주지 않으면서 코드 스타일의 일관성을 높여줍니다.
Also applies to: 33-33, 60-60
src/components/mentor/ArticleBottomSheetModal/index.tsx (1)
54-54: 포매팅 변경 사항 확인 완료새로 추가된 CI 워크플로우의 ESLint/Prettier 설정에 따라 className 속성들이 자동으로 정렬되었습니다. 변경 내역을 정리하면:
헤더 영역 스타일 정렬 (라인 54, 61)
- 모달 제목과 저장 버튼의 className 순서 조정
에러 메시지 스타일 통일 (라인 79, 91, 103)
- 폼 유효성 검증 에러 메시지의 className 일관성 확보
레이블 스타일 통일 (라인 96, 108)
- 아티클 링크와 썸네일 등록 레이블의 className 일관성 확보
입력 필드 스타일 정렬 (라인 101)
- URL 입력 필드의 className 순서 조정
안내 문구 스타일 정렬 (라인 133)
- 썸네일 등록 안내 문구의 className 순서 조정
기능적 변경 없이 코드 스타일만 개선되었습니다!
Also applies to: 61-61, 79-79, 91-91, 96-96, 101-101, 103-103, 108-108, 133-133
src/app/my/password/_ui/PasswordContent/index.tsx (1)
118-120: LGTM! 포맷팅 정리가 잘 되었습니다.두 버튼의 className 속성에서 Tailwind CSS 클래스 순서를 정렬한 변경사항입니다.
- 1단계 확인 버튼 (line 118): 클래스 순서 정리
- 2단계 변경하기 버튼 (line 131): 클래스 순서 정리
실제 렌더링이나 스타일링에는 영향이 없고, CI에 추가된 Prettier/ESLint 설정에 맞춘 코드 일관성 개선입니다.
Also applies to: 131-133
src/app/my/password/_ui/PasswordContent/_ui/PasswordInput/index.tsx (1)
39-41: LGTM! 일관된 포맷팅 적용 확인.세 곳의 className 속성에서 Tailwind CSS 클래스 순서를 정리한 변경사항입니다.
- label 요소 (line 39): 클래스 순서 정리
- 비밀번호 표시/숨김 버튼 (line 57): 클래스 순서 정리
- 에러 메시지 span (line 71): 클래스 순서 정리
기능적 변경 없이 코드 스타일 일관성만 개선되었습니다. CI 워크플로우 설정과 함께 적용된 포맷팅 규칙이 잘 반영되었네요.
Also applies to: 57-59, 71-72
src/api/my/client/usePatchMyInfo.ts (2)
10-27: AI 요약과 실제 코드 변경 사항 간 불일치 발견AI 요약에서는
UseMyMentorProfileRequest인터페이스에file?: File속성이 새로 추가되었고,patchMyMentorProfile함수가 파일 업로드를 지원하도록 변경되었다고 기술하고 있습니다.하지만 실제 코드에서는:
- 10-13번 줄의 인터페이스 정의
- 15-27번 줄의 FormData 처리 로직
위 부분들이 변경 마커(
~)로 표시되지 않았으며, 이는 해당 기능이 이미 존재했음을 의미합니다. 이번 PR의 실제 변경 사항은 import 문 재정렬(8번 줄)만 포함된 것으로 보입니다.
8-8: Import 문 재정렬 승인ESLint/Prettier 설정 개선에 따른 import 문 순서 정리가 적절히 적용되었습니다. 코드의 일관성과 가독성 향상에 기여합니다.
src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx (1)
78-151: 포매팅 표준화 작업 승인className 순서 재정렬 및 JSX 포매팅 개선 작업이 잘 적용되었습니다. 기능적 변경 없이 코드 스타일만 일관되게 정리되었습니다.
src/app/mentor/chat/_ui/ChatPageClient/index.tsx (1)
28-106: 스타일 정렬 확인 완료Tailwind 클래스 순서가 일관되게 정리되었으며, UI 렌더링 결과에는 영향이 없습니다. 변경 사항이 적절합니다.
src/app/mentor/chat/[chatId]/_ui/ChatNavBar/index.tsx (1)
100-159: 포매팅 변경 사항 양호채팅 네비게이션 바의 className 정렬 및 텍스트 스타일 순서가 표준화되었습니다. 기능에는 영향이 없으며 변경 사항이 적절합니다.
src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/index.tsx (1)
58-99: 메시지 박스 포매팅 개선 승인다음 개선 사항들이 적용되었습니다:
- className 속성 순서가 일관되게 정리됨
- JSX 블록에 괄호를 추가하여 가독성 향상
- 렌더링 로직은 변경되지 않음
변경 사항이 적절하며 코드 품질이 개선되었습니다.
src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatInputBar/index.tsx (1)
99-227: 입력 바 스타일 정리 완료채팅 입력 영역의 className 순서가 정리되었습니다:
- 닫기 버튼 스타일 정렬
- 파일 미리보기 레이블 클래스 순서 조정
- 입력창 및 첨부파일 옵션 스타일 정렬
모든 변경 사항이 표현 계층에만 해당하며, 전송 로직 및 이벤트 처리는 영향받지 않습니다.
src/api/university/client/queryKey.ts (1)
6-6: 검증 결과, 이미 사용 중인 코드입니다.
universityDetail쿼리 키는src/api/university/client/useGetUniversityDetail.ts에서 다음과 같이 활발히 사용되고 있습니다:
- QueryKeys.universityDetail을 queryKey 배열에 포함하여 React Query 훅 구성
따라서 추가된 쿼리 키는 적절하게 구현되었으며, 별도의 조치가 필요하지 않습니다.
Likely an incorrect or invalid review comment.
src/app/community/[boardCode]/create/PostForm.tsx (1)
77-77: CSS 클래스 순서 정렬 - 코드 스타일 일관성 개선다음 변경사항들이 적용되었습니다:
- 77번 줄 - 버튼 className 재정렬
- 91번 줄 - 제목 textarea placeholder 및 타이포그래피 클래스 정렬
- 104번 줄 - 체크박스 영역 컨테이너 클래스 재정렬
- 125번 줄 - 본문 textarea placeholder 및 유틸리티 클래스 정렬
이러한 변경들은 PR 전반에서 진행 중인 Tailwind 클래스 순서 표준화의 일부이며, 렌더링 결과나 기능에는 영향이 없습니다.
Also applies to: 91-91, 104-104, 125-125
src/app/university/score/submit/language-test/_lib/schema.ts (1)
3-3: Default import로의 변경이 올바르게 적용되어 있습니다.검증 결과를 정리하면 다음과 같습니다:
Export 정의 확인
scoreUtils.ts에서validateLanguageScore가 default export로 정의됨Import 문법 검증
schema.tsline 3의 import 문이 default import 형태로 정확함import validateLanguageScore from "@/utils/scoreUtils";✓일관성 확인
- 코드베이스 전체에서 이 함수를 import하는 파일은 현재 파일(schema.ts)이 유일함
- 다른 파일들의 업데이트가 필요 없음
모든 것이 일관되게 올바르게 적용되어 있습니다.
src/utils/useInfinityScroll.ts (1)
10-10: 타입 변경이 모든 소비 컴포넌트에 일관되게 반영되었습니다.이전 리뷰의 우려사항은 완전히 해결되었습니다. 검증 결과는 다음과 같습니다:
훅 정의 업데이트 완료
useInfinityScroll.ts10번 줄:lastElementRef: (node: Element | null) => void;- 콜백 매개변수도 동일하게
Element | null로 일관성 있게 적용됨모든 소비 컴포넌트 타입 일치
MentorCard:observeRef?: (node: Element | null) => void;✓MentorExpandChatCard:lastElementRef?: (node: Element | null) => void;✓useInfinityScroll 사용처 확인
useChatListHandler.ts에서 정상 사용MentorFindSection에서 정상 사용ApplicantListSection에서 정상 사용HTMLDivElement 타입 불일치 없음
- 코드베이스의 모든 HTMLDivElement 참조는 다른 목적의 ref들이며, useInfinityScroll 소비 컴포넌트와 무관
HTMLDivElement에서Element로의 타입 변경은 기술적으로 올바른 개선이며, 모든 소비 컴포넌트가 이를 올바르게 반영하고 있습니다.src/api/university/client/useGetRecommendedUniversity.ts (2)
7-7: 새로운 import가 적절하게 추가되었습니다.토큰 체크 로직에 필요한 Zustand store import가 올바르게 추가되었습니다.
18-19: 토큰 로직이 간소화되어 개선되었습니다.변경 내용을 정리하면 다음과 같습니다:
직접적인 토큰 상태 확인으로 단순화
- Zustand store에서 현재 access token 상태를 직접 조회하는 방식으로 변경
- React 컴포넌트 외부에서의
getState()사용은 올바른 패턴입니다방어적인 인스턴스 선택 로직
isLogin && accessToken조건으로 이중 체크하여 안전성 확보- 토큰이 없으면 public instance로 안전하게 fallback됩니다
요청 시점마다 최신 토큰 상태 반영
- 각 API 호출 시 현재 저장된 토큰을 확인하므로 상태 일관성이 유지됩니다
token reissue 로직은 axios interceptor에서 자동으로 처리됩니다 (
src/utils/axiosInstance.ts의 request interceptor가 토큰 누락 시 자동 갱신을 시도하며, reissuePromise 메커니즘으로 중복 요청을 방지합니다). 따라서 이 함수의 간소화된 로직과 토큰 갱신 체계가 잘 어울립니다.src/app/my/modify/_ui/ModifyContent/_ui/ReadOnlyField/index.tsx (1)
13-18: 포매팅 변경 확인 완료Tailwind 클래스 순서가 재정렬되었습니다:
- label 요소:
typo-medium-2와text-k-700순서 변경- span 요소: 조건부 스타일링 로직 유지하면서 클래스 순서 조정
동작에는 영향이 없으며, ESLint/Prettier 마이그레이션과 일치하는 변경사항입니다.
src/app/terms/page.tsx (1)
14-15: 포매팅 변경 확인 완료Tailwind 클래스 순서가 재정렬되었습니다:
- p 요소: 텍스트 색상 관련 클래스 순서 변경
- ol 요소: 폰트 및 레이아웃 클래스 순서 변경
동작에는 영향이 없습니다.
src/app/my/modify/_ui/ModifyContent/_ui/ImageInputFiled/index.tsx (1)
48-50: 포매팅 변경 확인 완료p 요소의 Tailwind 클래스 순서와 줄바꿈이 조정되었습니다. 조건부 텍스트 렌더링 로직은 그대로 유지되며, 동작에는 영향이 없습니다.
src/app/my/modify/_ui/ModifyContent/_ui/InputFiled/index.tsx (1)
23-38: 포매팅 변경 확인 완료여러 요소의 Tailwind 클래스 순서가 재정렬되었습니다:
- label:
text-k-700 typo-medium-2순서로 변경- 에러 메시지:
text-red-500 typo-regular-2순서로 변경- 성공 메시지 컨테이너:
text-primary typo-regular-2순서로 변경react-hook-form 연동 로직과 유효성 검사는 그대로 유지되며, 동작에는 영향이 없습니다.
src/app/mentor/modify/_ui/ModifyContent/index.tsx (1)
41-90: 포매팅 변경 확인 완료컴포넌트 전체에 걸쳐 Tailwind 클래스 순서가 재정렬되었습니다:
- 헤더 제목 및 텍스트 요소:
text-*와typo-*클래스 순서 변경- 섹션 제목들 (내 채널 관리, 멘토 한마디, 합격 레시피, 멘토 아티클): 일관된 클래스 순서로 정렬
- textarea 및 에러 메시지: 텍스트 스타일 관련 클래스 순서 조정
모든 변경사항은 시각적 표현에만 영향을 미치며, 폼 로직, 데이터 흐름, 유효성 검사는 그대로 유지됩니다. ESLint/Prettier 마이그레이션과 일치하는 변경사항입니다.
src/app/university/SearchBar.tsx (1)
71-73: LGTM! 👍 포맷팅 개선이 잘 적용되었습니다.
- 에러 메시지 렌더링 포맷팅
- 조건부 렌더링 블록이 괄호로 감싸져 가독성이 향상되었습니다.
- ESLint/Prettier 설정과 일관된 스타일입니다.
src/app/mentor/_ui/MentorClient/index.tsx (1)
39-49: LGTM! 👍 Tailwind 클래스 순서 정렬이 일관되게 적용되었습니다.
- 어드민 토글 버튼 className 정렬
transition-colors가typo-sb-9앞으로 이동- CI에서 Prettier/ESLint 플러그인이 자동 정렬한 결과로 보입니다.
src/app/university/[id]/_ui/UniversityDetail/_ui/MapSection.tsx (1)
12-12: LGTM! 👍 클래스 순서 정렬 완료.
- 파견학교 위치 제목 className
text-k-900과typo-sb-7순서가 정렬되었습니다.- 기능적 변화 없이 코드 일관성만 개선되었습니다.
src/components/ui/ReportPanel/index.tsx (1)
45-45: LGTM! 👍 Report 헤더 클래스 순서 정렬.
- h2 태그 className 정렬
text-k-800 typo-sb-5순서로 통일되었습니다.- 다른 컴포넌트들과 일관된 정렬 규칙이 적용되었네요.
src/app/community/[boardCode]/PostWriteButton.tsx (1)
32-32: LGTM! 👍 글쓰기 버튼 컨테이너 클래스 정렬.
- fixed 버튼 wrapper className
w-full max-w-app순서로 정렬되었습니다.- 조건부
translate-y로직은 그대로 유지되어 스크롤 시 버튼 숨김 기능에 영향 없습니다.src/app/mentor/[id]/_ui/MentorDetialContent/_ui/MentorArticle/index.tsx (1)
31-36: LGTM! 👍 아티클 제목과 설명 클래스 정렬.
h3 아티클 제목
text-k-800 typo-sb-7순서로 정렬p 아티클 설명
text-k-500 typo-regular-2순서로 정렬전체 프로젝트의 클래스 순서 컨벤션과 일치하도록 잘 정리되었습니다.
src/app/university/application/ScoreSearchField.tsx (1)
8-13: LGTM! 👍 인기 검색 섹션 클래스 정렬.
제목 div (Line 8)
text-black typo-sb-7순서로 정렬키워드 버튼 (Line 13)
text-black typo-medium-2순서로 정렬Tailwind 클래스 정렬 규칙이 일관되게 적용되었습니다.
src/app/university/application/apply/DoneStep.tsx (1)
11-11: LGTM! 👍 지원 완료 메시지 클래스 정렬.
- 완료 텍스트 div
text-center font-serif text-k-800 typo-sb-2순서로 정렬- 색상 클래스가 타이포그래피 클래스 앞에 오도록 통일되었습니다.
CI 워크플로우 추가와 함께 전체 코드베이스의 스타일 일관성이 잘 유지되고 있네요! 🎉
src/components/ui/TabSelector.tsx (1)
31-33: 1. Tailwind CSS 클래스 순서 정렬 ✓
- CI 도구 설정에 따른 클래스 순서 정규화가 적용되었습니다.
- 모든 클래스가 그대로 유지되며, 시각적/기능적 변경 없음을 확인했습니다.
src/app/my/match/_ui/MatchContent/index.tsx (2)
35-45: 1. 어드민 뷰 전환 버튼 클래스 정렬 ✓
typo-sb-9클래스가 다른 유틸리티 클래스 뒤로 이동되었습니다.- 버튼 스타일링과 동작에는 영향이 없습니다.
52-60: 2. 텍스트 요소 클래스 순서 정렬 ✓
- 헤더 문구와 빈 상태 메시지의 클래스 순서가 정규화되었습니다.
- Prettier/ESLint 플러그인에 의한 자동 정렬로 확인됩니다.
src/app/mentor/_ui/MentorClient/_ui/MentorPage/index.tsx (1)
36-44: 1. 제목 및 링크 요소 클래스 정렬 ✓
<h2>헤딩과 "전체보기"<Link>컴포넌트의 클래스 순서가 정규화되었습니다.- 렌더링 결과에는 차이가 없습니다.
src/app/university/application/ScorePageContent.tsx (2)
19-20: 1. Import 순서 정렬 ✓
toastimport가 다른 import들 뒤로 이동되었습니다.- ESLint import 순서 규칙에 맞게 정렬된 것으로 보입니다.
142-152: 2. 검색 UI 클래스 순서 정렬 ✓
- 검색 활성화 시 표시되는 UI 요소들의 Tailwind 클래스 순서가 정규화되었습니다.
font-sans,typo-sb-7,typo-medium-2등의 타이포그래피 클래스 위치만 변경되었습니다.src/components/search/UniversitySearchInput.tsx (1)
18-18: 1. 검색 입력 필드 클래스 정렬 ✓
typo-regular-1클래스가 다른 유틸리티 클래스 뒤로 이동되었습니다.- 입력 필드의 스타일링은 동일하게 유지됩니다.
src/components/ui/Progress.tsx (1)
19-19: 1. 퍼센티지 라벨 클래스 정렬 ✓
cn()헬퍼 내부의 클래스 순서가 정규화되었습니다.typo-medium-4가 다른 유틸리티 클래스 뒤로 이동되었으며, 시각적 결과는 동일합니다.src/components/ui/ReusableDropdown/index.tsx (1)
50-54: 1. 드롭다운 아이템 버튼 클래스 정렬 ✓
- 드롭다운 메뉴 아이템의 클래스 순서가 정규화되었습니다.
text-k-700과typo-medium-2의 순서만 변경되었으며, 동작에는 영향이 없습니다.src/lib/utils.ts (1)
1-5: 1. 유틸리티 모듈 포맷팅 정리 ✓
- Import 순서 정리:
type ClassValue가clsx앞으로 이동- 세미콜론 일관성 적용
cn()함수의 핵심 로직(twMerge(clsx(inputs)))은 변경 없음이 모듈은 프로젝트 전반에서 클래스명 조합에 사용되는 중요한 유틸리티입니다. 포맷팅만 정리되어 안전합니다.
src/app/university/search/PageContent.tsx (1)
184-184: 변경사항 확인 완료Tailwind 클래스 순서를 재정렬한 변경으로, 시각적 결과와 동작에는 영향이 없습니다. PR 전반에 걸친 스타일 정규화 작업의 일부로 보입니다.
src/app/(home)/_ui/FindLastYearScoreBar/index.tsx (1)
16-17: 변경사항 확인 완료두 개의 span 요소에서 className 순서가 재정렬되었습니다. 시각적 표현이나 기능에는 변화가 없으며, 코드 스타일 통일을 위한 작업입니다.
src/app/community/[boardCode]/[postId]/modify/PostModifyForm.tsx (1)
95-95: 변경사항 확인 완료여러 요소에서 className 속성의 Tailwind 클래스 순서가 재정렬되었습니다. 모든 변경사항은 순수하게 표현적인 것으로, 레이아웃이나 동작에 영향을 주지 않습니다.
Also applies to: 110-110, 131-131, 154-154, 158-158, 161-161
src/app/my/apply-mentor/_components/StudyStatusScreen/index.tsx (1)
38-38: 변경사항 확인 완료여러 요소에서 className 속성의 순서가 재정렬되었습니다:
- Line 38: 제목 텍스트 클래스 순서 변경
- Line 46: 에러 메시지 클래스 순서 변경
- Line 83: 컨테이너 클래스 순서 변경
- Lines 119-120: 상태 선택 버튼 설명 및 이름 클래스 순서 변경
모든 변경사항은 시각적 표현에 영향을 주지 않으며, 코드 스타일 정규화를 위한 작업입니다.
Also applies to: 46-46, 83-83, 119-120
src/utils/jwtUtils.ts (1)
1-6: 타입 안전성 개선
JwtPayload인터페이스를 명시적으로 정의하고isTokenExpired와tokenParse함수에서 타입 캐스팅을 적용했습니다. 이를 통해:
- JWT 페이로드 구조가 명확해졌습니다
- TypeScript 타입 체킹이 강화되었습니다
- 중복된 타입 정의가 제거되었습니다
동작 변경 없이 코드 품질이 향상되었습니다.
Also applies to: 11-11, 26-26
src/app/university/score/ScoreCard.tsx (1)
30-31: 변경사항 확인 완료여러 상태 라벨과 텍스트 요소에서 className 순서가 재정렬되었습니다. 시각적 표현이나 기능에는 영향이 없습니다.
Also applies to: 42-43, 51-51, 77-77
docs/development-workflow.md (1)
1-303: 유용한 개발 워크플로우 문서 추가프로젝트의 개발 워크플로우를 상세하게 문서화한 파일입니다. 다음 내용들이 잘 정리되어 있습니다:
- 커밋 메시지 규칙 및 예시
- Git Hooks (Husky, commitlint) 설정 및 문제 해결
- NPM 스크립트 사용법
- CI/CD 프로세스 설명
- 일반적인 개발 워크플로우
- 문제 해결 가이드
팀원들이 일관된 개발 프로세스를 따르는 데 큰 도움이 될 것입니다.
src/app/(home)/page.tsx (2)
84-134: 변경사항 확인 완료여러 Link 블록과 라벨 요소에서 className 순서가 재정렬되었습니다:
- 학교 검색하기, 성적 입력하기 Link 블록 (Lines 84-106)
- 학교 지원하기, 지원자 현황 확인 Link 블록 (Lines 110-133)
- "실시간 인기있는 파견학교" 헤더 (Line 137)
모든 변경사항은 시각적 표현이나 라우팅 로직에 영향을 주지 않으며, 코드 스타일 통일을 위한 작업입니다.
Also applies to: 137-137
78-78: JSON-LD 구조화 데이터에 대한 dangerouslySetInnerHTML 사용Line 78의
dangerouslySetInnerHTML은 SEO를 위한 JSON-LD 구조화 데이터를 삽입하는 표준적인 방법입니다. 정적 분석 도구에서 경고를 표시하지만, 다음 이유로 안전합니다:
- 콘텐츠가
structuredData상수에서 제공되는 정적 데이터입니다- 사용자 입력이 포함되지 않습니다
- schema.org 표준을 따르는 SEO 메타데이터입니다
이는 일반적인 XSS 위험이 아니라 false positive입니다.
src/app/university/score/submit/gpa/GpaSubmitForm.tsx (1)
94-173: LGTM! 코드 스타일 개선이 잘 적용되었습니다.
- HTML 구조 개선: 닫는
</p>태그 추가로 올바른 HTML 구조 확보- 클래스 순서 통일: Tailwind 유틸리티 클래스 순서를 일관되게 재정렬
- 기능 유지: 모든 폼 검증 로직과 제출 흐름이 그대로 유지됨
표현적 변경만 포함되어 있어 기능에 영향이 없습니다.
src/app/my/apply-mentor/_components/InterestCountriesScreen/index.tsx (1)
60-143: LGTM! 스타일 일관성이 개선되었습니다.
- 클래스 순서 정리: 텍스트 색상과 타이포그래피 클래스 순서를 통일
- 기능 보존: 국가 선택, 지역 탭, 유효성 검사 로직 모두 정상 작동
시각적 변경 없이 코드 일관성만 향상되었습니다.
docs/eslint-prettier-migration-prd.md (1)
1-285: LGTM! 마이그레이션 계획이 체계적으로 정리되었습니다.
- 명확한 목표 설정: 현재 문제점과 개선 방향이 구체적으로 명시됨
- 단계별 계획: Phase 1-4로 구분된 실행 가능한 마이그레이션 로드맵
- 위험 관리: 위험 요소와 대응 방안, 롤백 계획 포함
- 실용적인 가이드: 구체적인 명령어와 설정 예시 제공
문서가 팀의 워크플로우 개선에 큰 도움이 될 것입니다.
commitlint.config.js (1)
1-6: LGTM! Prettier 포맷팅이 적용되었습니다.
- 쿼트 스타일 통일: 싱글쿼트에서 더블쿼트로 변경
- 배열 포맷: 멀티라인 배열을 싱글라인으로 간소화
commitlint 설정의 기능은 그대로 유지되며 코드 스타일만 개선되었습니다.
src/app/mentor/[id]/_ui/MentorDetialContent/index.tsx (1)
59-123: LGTM! 스타일 일관성이 향상되었습니다.
- 클래스 순서 정리: 텍스트 색상과 타이포그래피 클래스 순서 통일
- 기능 보존: 멘토 정보 표시, 채널 링크, 지원 로직 모두 정상 작동
시각적 변경 없이 코드베이스의 일관성만 개선되었습니다.
src/app/login/LoginContent.tsx (1)
73-124: LGTM! 로그인 폼의 스타일이 정리되었습니다.
- 클래스 순서 통일: 헤더, 입력 필드, 버튼 전반에 걸쳐 일관된 className 순서 적용
- 기능 유지: Zod 스키마 검증, 에러 처리, 소셜 로그인 로직 모두 정상
사용자 경험에 영향 없이 코드 품질이 개선되었습니다.
src/app/university/application/apply/LanguageStep.tsx (1)
63-63: LGTM! 스타일 일관성이 개선되었습니다.
- 클래스 순서 정리: Tailwind 유틸리티 클래스 순서를 프로젝트 전체의 패턴에 맞게 조정
기능에 영향 없이 코드 일관성만 향상되었습니다.
src/app/university/application/ScoreSheet.tsx (1)
31-43: 지원자 정보 표시가 확장되었으며, 타입이 적절히 정의되어 있습니다.
데이터 확장:
- 닉네임만 표시하던 것에서 GPA, 어학시험 종류, 점수까지 추가로 표시
포맷팅 적용:
gpa.toFixed(2)로 소수점 둘째자리까지 정확하게 표현타입 매핑 사용:
languageTestMapping을 통해 시험 종류를 사용자 친화적으로 변환Applicant 인터페이스(
src/types/application.ts)에 모든 필드가 명확하게 정의되어 있습니다(gpa: number,testType: string,testScore: string). 코드와 타입 정의가 일치하며, 안정적으로 구현되었습니다.src/app/university/[id]/_ui/UniversityDetail/_ui/TitleSection.tsx (1)
15-16: Tailwind 클래스 순서 정리 - 좋습니다!클래스 순서를 일관되게 정리하여 코드 가독성을 개선했습니다. 색상 클래스(
text-*)를 타이포그래피 클래스(typo-*) 앞에 배치하는 패턴으로 통일하였으며, 기능적 변경 사항은 없습니다.src/components/layout/TopDetailNavigation.tsx (1)
21-21: 레이아웃 클래스 순서 정리 확인네비게이션 컴포넌트의 클래스 순서를 프로젝트 전반의 컨벤션에 맞춰 정리했습니다. 렌더링 결과와 동작에는 영향이 없습니다.
Also applies to: 25-25
src/components/search/UniversityRegionTabs.tsx (2)
5-5: Import 통합 - 깔끔합니다!
RegionKo와RegionOption을 단일 import 문으로 통합하여 코드를 간결하게 만들었습니다.src/types/university.ts에 새로 추가된RegionOption인터페이스를 중앙 집중식으로 관리하는 좋은 접근입니다.
27-27: 클래스 순서 조정 확인버튼의 Tailwind 클래스 순서를 프로젝트 컨벤션에 맞춰 정리했습니다. 시각적 결과는 동일합니다.
src/components/layout/GlobalLayout/ui/BottomNavigation/index.tsx (1)
30-30: 하단 네비게이션 스타일 정리네비게이션 바와 텍스트 스타일링 클래스 순서를 프로젝트 전반의 일관성에 맞춰 조정했습니다. 활성/비활성 상태의 시각적 표현은 그대로 유지됩니다.
Also applies to: 48-49
src/app/university/[id]/_ui/UniversityDetail/_ui/LanguageSection.tsx (1)
21-21: 어학 섹션 스타일 클래스 정리어학 성적 및 세부 요건 섹션의 모든 텍스트 스타일 클래스를 일관된 순서로 정리했습니다. 색상 클래스를 타이포그래피 클래스 앞에 배치하는 프로젝트 컨벤션을 따르고 있으며, 표시되는 내용과 레이아웃에는 변경이 없습니다.
Also applies to: 37-39, 52-52, 57-57
src/app/university/application/apply/ConfirmStep.tsx (1)
16-16: 지원 확인 페이지 스타일 정리지원하기 완료 페이지의 타이포그래피 및 색상 클래스 순서를 프로젝트 표준에 맞춰 정리했습니다. UI 표시와 사용자 경험은 동일하게 유지됩니다.
Also applies to: 20-23, 40-41
src/app/university/[id]/_ui/UniversityDetail/_ui/InfoSection.tsx (2)
31-31: 정보 섹션 스타일 클래스 정리최저 이수학기, 파견 가능학기, 자격요건, 기숙사 등 모든 정보 섹션의 텍스트 스타일 클래스를 일관된 순서로 정리했습니다. 프로젝트 전반의 컨벤션과 일치하며 기능적 변경은 없습니다.
Also applies to: 34-34, 41-41, 44-44, 61-61, 81-81, 88-88, 108-108, 128-128, 135-135
223-227: SVG 경로 포맷팅 정리기숙사 아이콘의 SVG path 속성을 여러 줄로 나누어 가독성을 개선했습니다. 렌더링에는 영향이 없습니다.
src/app/university/[id]/_ui/UniversityDetail/index.tsx (2)
7-11: 모듈 구조 개선 - 로컬 _ui 디렉토리 활용하위 UI 컴포넌트들(InfoSection, LanguageSection, MapSection, TitleSection, UniversityBtns)의 import 경로를 로컬
_ui디렉토리를 사용하도록 변경했습니다.개선 사항:
- 명확한 디렉토리 구조로 컴포넌트 계층 표현
- 상대 경로 간소화로 가독성 향상
- 모듈화된 구조로 유지보수성 개선
38-40: 대학 상세 페이지 스타일 정리파견 정보, 전공상세, 영어강의 리스트 섹션의 텍스트 스타일 클래스를 프로젝트 전반의 컨벤션에 맞춰 정리했습니다. 레이아웃과 표시 내용은 동일하게 유지됩니다.
Also applies to: 54-55, 61-61, 63-63
.github/workflows/ci.yml (2)
26-33: 2. Lint & Type Check 워크플로우 개선 승인
- ESLint, Prettier 포맷 체크, TypeScript 타입 체크가 순차적으로 실행됩니다.
- CI 파이프라인에서 코드 품질을 종합적으로 검증하는 좋은 구성입니다.
56-73: 3. PR 제목 검증 Job 추가 승인
if: github.event_name == 'pull_request'조건으로 PR일 때만 실행되도록 적절히 구성되었습니다.- commitlint를 활용한 PR 제목 검증으로 일관된 커밋 메시지 규칙을 강제합니다.
src/components/layout/PathBasedNavigation/index.tsx (1)
44-51: Tailwind 클래스 순서 정리 완료
- 기능 변경 없이 Prettier/ESLint 규칙에 따른 클래스 순서 정렬입니다.
- 프로젝트 전반의 일관된 포맷팅 적용의 일환으로 적절합니다.
src/components/search/UniversityFilterSection.tsx (2)
10-10: 1. Import 경로 수정 완료
RegionKo와RegionOption을@/types/university에서 올바르게 import하도록 수정되었습니다.- 이전 리뷰에서 지적된 존재하지 않는 경로 참조 문제가 해결되었습니다.
64-64: 2. Tailwind 클래스 순서 정리
typo-sb-9 text-k-700→text-k-700 typo-sb-9로 일관된 순서로 정리되었습니다.- Prettier/ESLint 규칙에 따른 자동 포맷팅 결과입니다.
Also applies to: 98-98
lint-fix.prd.md (1)
1-285: ESLint & Prettier 마이그레이션 PRD 문서 승인이전 리뷰에서 지적된 코드 블록 언어 식별자 문제가 해결되었습니다:
- Line 147:
text언어 식별자 추가됨- Line 203:
gitignore언어 식별자 추가됨문서 구성이 체계적입니다:
- 명확한 목표와 배경 설명
- 단계별 마이그레이션 계획
- 위험 요소 및 롤백 계획 포함
- 검증 체크리스트 제공
src/utils/universityUtils.ts (1)
3-10: 함수 시그니처 및 Export 변경 승인변경 사항 요약:
- 명시적 반환 타입:
string | undefined로 타입 안전성 향상- 명시적 undefined 반환: 키가 없을 때의 동작이 명확해짐
- Default export 전환: named export에서 default export로 변경
UniverSityCard컴포넌트에서testName ?? requirement.languageTestType으로 undefined 케이스를 적절히 처리하고 있어 연동에 문제가 없습니다.docs/husky-ci-workflow-prd.md (1)
1-630: Husky & CI 워크플로우 PRD 문서 승인문서 구성이 매우 체계적입니다:
- 현재 상황 분석: Husky, Commitlint, CI/CD 설정 상태 명확히 정리
- 구현 계획: Phase별로 상세한 작업 항목 제시
- 커밋 메시지 규칙: 타입별 설명과 올바른/잘못된 예시 제공
- 문제 해결 가이드: 실용적인 트러블슈팅 섹션 포함
팀 온보딩과 워크플로우 표준화에 유용한 문서입니다.
src/components/ui/UniverSityCard/index.tsx (3)
5-5: 1. Import 방식 변경 승인
shortenLanguageTestName을 default import로 변경하여universityUtils.ts의 export 방식과 일치합니다.
55-62: 2. undefined 반환값 처리 개선 완료이전 리뷰에서 지적된 문제가 해결되었습니다:
testName변수로 함수 결과를 저장testName ?? requirement.languageTestType으로 fallback 처리- undefined일 경우 원본
languageTestType값이 표시됩니다깔끔한 해결책입니다.
43-52: 3. Tailwind 클래스 순서 정리
typo-bold-4 text-k-700→text-k-700 typo-bold-4typo-medium-4 text-k-500→text-k-500 typo-medium-4- 조건부 capacity 표시 로직도 단순화되었습니다
프로젝트 전반의 일관된 포맷팅 적용입니다.
| className="px-5 pt-2.5 text-gray-100 typo-regular-4" | ||
| dangerouslySetInnerHTML={{ __html: notice.replace(/\n/g, "<br />") }} | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
정적 콘텐츠에 dangerouslySetInnerHTML 사용
Line 138에서 dangerouslySetInnerHTML을 사용하여 줄바꿈 문자를 <br /> 태그로 변환하고 있습니다. notice 변수는 컴포넌트 내부에서 정의된 정적 문자열이므로 실제 XSS 위험은 낮지만, React의 기본 XSS 보호 기능을 우회하고 있습니다.
더 안전한 대안으로 줄바꿈을 여러 개의 <p> 또는 <span> 요소로 분할하는 방법을 고려해보세요.
🔎 제안하는 수정 방안
- <div
- className="px-5 pt-2.5 text-gray-100 typo-regular-4"
- dangerouslySetInnerHTML={{ __html: notice.replace(/\n/g, "<br />") }}
- />
+ <div className="px-5 pt-2.5 text-gray-100 typo-regular-4">
+ {notice.split('\n').map((line, i) => (
+ <span key={i}>
+ {line}
+ {i < notice.split('\n').length - 1 && <br />}
+ </span>
+ ))}
+ </div>Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 ast-grep (0.40.3)
[warning] 138-138: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🤖 Prompt for AI Agents
In src/app/community/[boardCode]/[postId]/modify/PostModifyForm.tsx around lines
138-140, remove the use of dangerouslySetInnerHTML and instead render the static
notice by splitting the notice string on newline characters and mapping each
line to React elements (e.g., <p> or <span>) with a unique key so line breaks
are preserved; preserve the existing className on the container or each mapped
element, filter/trim empty lines as needed (or render empty lines as <br/>), and
return the mapped JSX fragment inside the render function to avoid bypassing
React's XSS protections.
| className="px-5 pt-2.5 text-gray-100 typo-regular-4" | ||
| dangerouslySetInnerHTML={{ __html: notice.replace(/\n/g, "<br />") }} | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's find and examine the PostForm.tsx file
find . -type f -name "PostForm.tsx" -path "*/community/*" 2>/dev/null | head -20Repository: solid-connection/solid-connect-web
Length of output: 129
🏁 Script executed:
# Let's also check if the file exists at the expected location
cat -n "src/app/community/[boardCode]/create/PostForm.tsx" 2>/dev/null | head -150 | tail -30Repository: solid-connection/solid-connect-web
Length of output: 1213
🏁 Script executed:
cat -n "src/app/community/[boardCode]/create/PostForm.tsx" | head -140Repository: solid-connection/solid-connect-web
Length of output: 5644
🏁 Script executed:
# Search for notice variable definition in the entire file
rg "notice" "src/app/community/[boardCode]/create/PostForm.tsx" -nRepository: solid-connection/solid-connect-web
Length of output: 181
dangerouslySetInnerHTML 사용 - 불필요한 보안 위험 제거
notice 변수가 현재 하드코딩된 정적 문자열이라 즉각적인 XSS 위험은 없습니다. 다만, 단순 텍스트의 개행 처리를 위해 dangerouslySetInnerHTML을 사용하는 것은 불필요한 보안 위험을 만드는 안티패턴입니다.
권장 개선안 (간단한 순서대로):
-
whitespace-pre-line사용 (가장 간단)<div className="px-5 pt-2.5 text-gray-100 typo-regular-4 whitespace-pre-line"> {notice} </div>
-
개행을 JSX
<br />요소로 변환 (더 명시적)<div className="px-5 pt-2.5 text-gray-100 typo-regular-4"> {notice.split('\n').map((line, index) => ( <div key={index}> {line} {index < notice.split('\n').length - 1 && <br />} </div> ))} </div>
dangerouslySetInnerHTML은 유지보수 과정에서 이 필드에 사용자 입력이나 외부 데이터가 들어갈 가능성을 열어두므로, 이러한 간단한 대안으로 변경해주세요.
🧰 Tools
🪛 ast-grep (0.40.3)
[warning] 132-132: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🤖 Prompt for AI Agents
In src/app/community/[boardCode]/create/PostForm.tsx around lines 132 to 134,
remove the dangerouslySetInnerHTML usage and render the static notice as plain,
escaped text; either apply the Tailwind class whitespace-pre-line to preserve
newlines (keep existing className) or split notice by '\n' and map to JSX with
explicit <br/> boundaries, ensuring no raw HTML injection is used and that the
component continues to display line breaks correctly.
| 탈퇴 시, 회원이 솔리드커넥션 내에서 보유한 모든 정보(프로필, 매칭 이력, 메시지 내역, 포인트 등)는 | ||
| 삭제되며, 삭제된 정보는 복구할 수 없습니다. 단, 회사가 관련 법령에 따라 보존해야 하는 정보는 예외로 | ||
| 합니다. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
한글 띄어쓰기 확인 필요
"모든 정보... 는 삭제되며"에서 조사 "는" 앞에 공백이 추가되었습니다. 표준 한글 문법에서는 "정보는"처럼 명사와 조사 사이에 공백을 넣지 않습니다.
"모든 정보...는 삭제되며"로 수정하는 것을 권장합니다.
🔎 제안하는 수정
- 탈퇴 시, 회원이 솔리드커넥션 내에서 보유한 모든 정보(프로필, 매칭 이력, 메시지 내역, 포인트 등)는
- 삭제되며, 삭제된 정보는 복구할 수 없습니다. 단, 회사가 관련 법령에 따라 보존해야 하는 정보는 예외로
- 합니다.
+ 탈퇴 시, 회원이 솔리드커넥션 내에서 보유한 모든 정보(프로필, 매칭 이력, 메시지 내역, 포인트 등)는
+ 삭제되며, 삭제된 정보는 복구할 수 없습니다. 단, 회사가 관련 법령에 따라 보존해야 하는 정보는 예외로
+ 합니다.Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/app/terms/page.tsx around lines 22 to 24, there is an extra space before
the Korean particle "는" in the phrase "모든 정보(프로필, 매칭 이력, 메시지 내역, 포인트 등) 는 삭제되며";
remove the stray space so the noun and particle are contiguous ("정보는 삭제되며").
Update the text accordingly and scan nearby sentences for any similar spacing
issues to keep Korean spacing consistent.
| /** | ||
| * 서버 컴포넌트에서 사용 가능한 MentorApplyCountModal 래퍼 | ||
| * MentorApplyCountContent를 그대로 렌더링합니다. | ||
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSDoc 주석을 명확하게 수정해주세요.
주석에 "서버 컴포넌트에서 사용 가능한"이라고 작성되어 있는데, 이 컴포넌트 자체는 "use client" 지시어로 인해 클라이언트 컴포넌트입니다. 정확한 설명은 "서버 컴포넌트에서 임포트 가능한 클라이언트 컴포넌트 래퍼"가 더 적절합니다.
🔎 제안하는 수정안
/**
- * 서버 컴포넌트에서 사용 가능한 MentorApplyCountModal 래퍼
+ * 서버 컴포넌트에서 임포트 가능한 클라이언트 컴포넌트 래퍼
* MentorApplyCountContent를 그대로 렌더링합니다.
*/📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /** | |
| * 서버 컴포넌트에서 사용 가능한 MentorApplyCountModal 래퍼 | |
| * MentorApplyCountContent를 그대로 렌더링합니다. | |
| */ | |
| /** | |
| * 서버 컴포넌트에서 임포트 가능한 클라이언트 컴포넌트 래퍼 | |
| * MentorApplyCountContent를 그대로 렌더링합니다. | |
| */ |
🤖 Prompt for AI Agents
In src/components/mentor/MentorApplyCountModal/index.tsx around lines 5 to 8,
update the JSDoc so it accurately describes the component as a client component
wrapper that can be imported from server components (e.g., replace "서버 컴포넌트에서 사용
가능한" with "서버 컴포넌트에서 임포트 가능한 클라이언트 컴포넌트 래퍼"), and note that the file uses the
"use client" directive to clarify why it's a client component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/components/mentor/MentorApplyCountModal/index.tsx (1)
5-8: JSDoc 주석이 여전히 수정되지 않았습니다.이전 리뷰에서 이미 지적되었지만, JSDoc 주석이 아직 수정되지 않았습니다. 현재 "서버 컴포넌트에서 사용 가능한"이라고 작성되어 있으나,
"use client"지시어가 있어 이 컴포넌트는 클라이언트 컴포넌트입니다. "서버 컴포넌트에서 임포트 가능한 클라이언트 컴포넌트 래퍼"로 수정해주세요.🔎 제안하는 수정안
/** - * 서버 컴포넌트에서 사용 가능한 MentorApplyCountModal 래퍼 + * 서버 컴포넌트에서 임포트 가능한 클라이언트 컴포넌트 래퍼 * MentorApplyCountContent를 그대로 렌더링합니다. */
🧹 Nitpick comments (4)
src/utils/authUtils.ts (1)
79-79: 타입 단언(type assertion)으로의 변경 확인 필요타입 어노테이션(
const res: Type)에서 타입 단언(as Type)으로 변경되었습니다.타입 단언은 컴파일 타임의 타입 검증을 우회하므로, Apple SDK의 실제 반환 타입이
appleOAuth2CodeResponse와 일치하지 않아도 컴파일러가 이를 감지하지 못합니다. PR 커밋 메시지에 "TypeScript 오류 해결"이 언급되어 있는데, Apple SDK의 타입 정의 문제로 인해 이 변경이 불가피했는지 확인 부탁드립니다.가능하다면 원래의 타입 어노테이션 형태(
const res: appleOAuth2CodeResponse = ...)로 유지하는 것이 타입 안정성 측면에서 더 바람직합니다.src/lib/ScriptLoader/KakaoScriptLoader.tsx (1)
7-9: 환경 변수 검증 로직 개선을 고려해보세요.변경사항을 정리하면:
- Kakao SDK 초기화 전
NEXT_PUBLIC_KAKAO_JS_KEY환경 변수 존재 여부를 확인하도록 개선
- 방어적 프로그래밍 관점에서 좋은 변경입니다
개선 제안:
- 스크립트 로딩 조건 추가: 현재는 환경 변수가 없어도 Kakao SDK 스크립트를 로드합니다. 키가 없으면 초기화할 수 없으므로 스크립트 로딩 자체를 조건부로 만들면 불필요한 네트워크 요청을 줄일 수 있습니다.
- 디버깅 로그 추가: 환경 변수가 없을 때 console.warn 등으로 로그를 남기면 개발/운영 환경에서 설정 누락을 쉽게 발견할 수 있습니다.
🔎 개선된 구현 예시
const KakaoScriptLoader = () => { + const kakaoKey = process.env.NEXT_PUBLIC_KAKAO_JS_KEY; + + if (!kakaoKey) { + console.warn("NEXT_PUBLIC_KAKAO_JS_KEY is not configured. Kakao SDK will not be loaded."); + return null; + } + const kakaoInit = () => { - if (typeof window !== "undefined" && window.Kakao && process.env.NEXT_PUBLIC_KAKAO_JS_KEY) { - window.Kakao.init(process.env.NEXT_PUBLIC_KAKAO_JS_KEY); + if (typeof window !== "undefined" && window.Kakao) { + window.Kakao.init(kakaoKey); } }; return <Script src="https://developers.kakao.com/sdk/js/kakao.js" strategy="afterInteractive" onLoad={kakaoInit} />; };src/app/layout.tsx (1)
41-52: 전역 타입 선언이 잘 추가되었습니다.변경사항을 정리하면:
window.Kakao타입 선언 추가
init(key: string): SDK 초기화 함수Auth.authorize(options: { redirectUri: string }): OAuth 인증 함수window.AppleID타입 선언 추가
auth.init(config: object): Apple 로그인 초기화auth.signIn(): Promise<unknown>: Apple 로그인 실행코드는 잘 작동하며, 서드파티 SDK의 타입 안정성을 제공합니다.
선택적 개선사항:
- AppleID 타입을 좀 더 구체화할 수 있습니다. 예를 들어
config: object대신 실제 사용하는 필드들을 명시하고,Promise<unknown>대신 응답 구조를 정의하면 더 나은 타입 안정성을 얻을 수 있습니다.- 다만 외부 SDK 문서가 불명확하거나 타입이 자주 변경되는 경우, 현재처럼 느슨한 타입이 더 실용적일 수 있습니다.
🔎 선택적 개선 예시 (AppleID 타입을 더 구체화하는 경우)
declare global { interface Window { Kakao: { init: (key: string) => void; Auth: { authorize: (options: { redirectUri: string }) => void; }; }; AppleID: { auth: { - init: (config: object) => void; - signIn: () => Promise<unknown>; + init: (config: { + clientId: string; + scope: string; + redirectURI: string; + state?: string; + usePopup?: boolean; + }) => void; + signIn: () => Promise<{ + authorization: { + code: string; + id_token: string; + state?: string; + }; + user?: { + email: string; + name: { firstName: string; lastName: string }; + }; + }>; }; }; } }참고: Apple JS SDK의 실제 타입 구조에 맞춰 조정이 필요합니다.
src/app/university/search/PageContent.tsx (1)
137-137: 선택적 제안: 타입 추론 활용명시적 타입 선언이 코드를 자기문서화하지만, TypeScript가 삼항 연산자에서 이 타입을 충분히 추론할 수 있습니다. 간결성을 선호한다면 타입 선언을 생략할 수 있습니다.
🔎 더 간결한 버전
- const name: "country1" | "country2" | "country3" = index === 1 ? "country1" : index === 2 ? "country2" : "country3"; + const name = index === 1 ? "country1" : index === 2 ? "country2" : ("country3" as const);
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
.eslintrc.js.github/workflows/ci.ymlsentry.client.config.tssolid-connect-web@2.2445src/api/boards/server/getPostList.tssrc/app/layout.tsxsrc/app/university/score/ScoreCard.tsxsrc/app/university/search/PageContent.tsxsrc/components/mentor/MentorApplyCountModal/index.tsxsrc/lib/ScriptLoader/KakaoScriptLoader.tsxsrc/utils/authUtils.tstsc
🚧 Files skipped from review as they are similar to previous changes (1)
- .eslintrc.js
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/components/ui/TabSelector.tsx:10-11
Timestamp: 2025-08-12T09:41:44.182Z
Learning: manNomi prefers to keep reusable UI components simple and focused on core functionality rather than adding many features. They don't want to over-engineer flexible/reusable UI components at the initial stage.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/components/mentor/MentorChatCard/index.tsx:17-21
Timestamp: 2025-08-24T11:14:34.297Z
Learning: manNomi prefers not to receive accessibility suggestions or recommendations during code reviews.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/usePostLogout.ts:17-33
Timestamp: 2025-08-24T11:13:08.477Z
Learning: manNomi prefers to prioritize user experience over perfect state consistency in auth flows. Specifically, in logout scenarios, they prefer to keep tokens intact on API failure to avoid forcing users to re-login, even if it means temporary UI state inconsistency.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/useDeleteUserAccount.ts:17-27
Timestamp: 2025-08-24T11:11:40.758Z
Learning: manNomi prefers optimistic navigation in auth-related flows (like account deletion) to prevent race conditions where token clearing before navigation could cause intermediate redirects to login page due to pending async requests failing.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/types/mentor.ts:70-73
Timestamp: 2025-08-12T04:07:04.134Z
Learning: manNomi prefers using Korean labels directly in enum values (e.g., MentorTab.MY_MENTEE = "나의 멘티") over separating enum keys from UI labels for efficiency and intuitiveness, considering scalability concerns as excessive for their current project needs.
🧬 Code graph analysis (3)
src/api/boards/server/getPostList.ts (1)
src/app/community/[boardCode]/page.tsx (1)
revalidate(25-25)
src/app/university/score/ScoreCard.tsx (1)
src/lib/zustand/useToastStore.ts (1)
toast(39-44)
src/utils/authUtils.ts (1)
src/types/auth.ts (1)
appleOAuth2CodeResponse(65-70)
🪛 GitHub Actions: CI
src/app/university/search/PageContent.tsx
[warning] 1-1: Code style issues found in the file. Run 'prettier --write' to fix.
🔇 Additional comments (10)
sentry.client.config.ts (1)
23-24:tracePropagationTargets위치 변경 — 완벽한 마이그레이션입니다! ✓프로젝트에서 사용 중인
@sentry/nextjsv10.22.0은 다음 변경 사항을 완벽하게 지원합니다:
최상위 옵션으로의 올바른 이동
Sentry.init()의 최상위 레벨에tracePropagationTargets를 설정하신 것이 맞습니다.- Sentry SDK v8 이상에서 권장되는 마이그레이션 패턴이며, v10에서는 필수 기준입니다.
설정값 적절성
- 문자열(
"solid-connection.com")과 정규식 패턴이 함께 사용되어 정확합니다.- 프로덕션 환경에만 적용되는 조건부 초기화도 바람직합니다.
변경 사항이 완벽하게 구현되었으니 염려 없이 진행하셔도 됩니다!
src/app/university/score/ScoreCard.tsx (3)
5-5: 이전 리뷰 이슈가 깔끔하게 해결되었습니다! 👍
- 타입 안전성 확보:
rejectedReason ?? "승인이 거절되었습니다."패턴을 사용하여toast.error()에 항상string타입이 전달되도록 보장했습니다.- 사용자 경험 개선: 거절 사유가 없는 경우에도 의미 있는 기본 메시지를 제공합니다.
- nullish coalescing 연산자 활용:
null또는undefined인 경우에만 기본값을 사용하므로 빈 문자열("")도 올바르게 처리됩니다.이전 리뷰에서 지적된 타입 계약 위반 문제가 완전히 해결되었습니다.
Also applies to: 40-40
57-57: 기본 매개변수 처리가 적절합니다.
- 타입 일관성:
rejectedReason?: string | null타입 정의와= null기본값이 완벽하게 일치합니다.- 명시적 기본값: 선택적 prop에 명시적 기본값을 제공하여 컴포넌트 사용자에게 명확한 의도를 전달합니다.
- nullish coalescing과의 조화: Line 40의
??연산자와 함께 null 케이스를 일관되게 처리합니다.
30-31: 스타일링 개선이 코드 일관성을 높였습니다.
- 명시적 색상 클래스 추가: 각 상태별 텍스트에 명시적인 색상 유틸리티(
text-sub-b,text-accent-custom-red,text-primary,text-k-300)를 추가했습니다.- Tailwind 클래스 정리: PR의 Prettier/ESLint 포맷팅 작업의 일환으로 클래스 순서와 일관성이 개선되었습니다.
- 유지보수성 향상: 암묵적 상속보다 명시적 스타일 선언이 코드 가독성과 예측 가능성을 높입니다.
이러한 변경사항은 기능적 영향 없이 시각적 일관성을 강화하는 좋은 리팩토링입니다.
Also applies to: 42-43, 51-51, 77-77
.github/workflows/ci.yml (3)
11-11: 작업 이름 명시로 가독성 개선 👍
Lint 작업명을 "Lint & Type Check"로 명확하게 변경
- 실제로 수행하는 작업(린트 + 타입 체크)을 정확히 표현했습니다.
Build 작업명을 명시적으로 "Build"로 설정
- CI 로그에서 각 작업의 목적을 한눈에 파악할 수 있게 되었습니다.
Also applies to: 36-36
26-33: 린트/포맷/타입 체크를 독립적인 단계로 분리 ✨다음 세 개의 검증 단계를 명확히 분리했습니다:
"Run ESLint" 단계
- 코드 린팅을
npm run lint로 실행합니다."Check Prettier formatting" 단계
- 코드 포맷팅을
npm run format:check로 검증합니다."TypeScript type check" 단계
- 타입 검사를
npm run typecheck로 별도로 수행합니다.각 검증 단계가 독립적으로 실행되어 CI 실패 시 문제를 빠르게 식별할 수 있습니다. package.json에 필요한 스크립트들이 모두 정의되어 있으므로 문제없습니다. ✅
20-21: Node.js 22.x 버전 지정 및 npm 캐싱 설정 확인 완료프로젝트의 현재 구성을 검증한 결과 다음과 같이 적절하게 설정되어 있습니다:
package.json에 Node.js 버전 명시
- engines 필드에
"node": "22.x"로 명확하게 지정되어 있습니다.CI 워크플로우의 일관된 설정
- lint 작업(20-21줄)과 build 작업(45-46줄) 모두에서 동일하게
node-version: "22.x"와cache: "npm"으로 구성되어 있습니다.의존성의 Node.js 22.x 호환성
- Next.js 14.2.35, React 18, TypeScript 5.3.3, @tanstack/react-query 5.84.1 등 모든 주요 의존성이 Node.js 22.x와 호환됩니다.
호환성 우려는 해결되었으며, 현재 설정이 적절합니다.
src/app/university/search/PageContent.tsx (3)
109-109: 변경 승인: 타입 안정성 개선
field.value ?? ""로 기본값을 명시적으로 처리한 것은 좋은 방어적 코딩입니다. CustomDropdown에 항상 문자열 값을 전달하여 잠재적인 undefined 관련 런타임 오류를 방지합니다.
155-155: 변경 승인: 일관된 타입 처리languageTestType과 동일한 패턴으로 기본값을 처리하여 코드의 일관성을 유지합니다.
184-184: 클래스 순서는 이미 올바르게 정렬되어 있습니다.현재 라인 184의 클래스 순서
text-white transition-colors typo-sb-9는 이미 Prettier의prettier-plugin-tailwindcss플러그인 규칙에 따라 올바르게 정렬되어 있습니다. 따라서 추가 조치는 필요하지 않습니다.Likely an incorrect or invalid review comment.
| method: "GET", | ||
| next: { | ||
| revalidate, | ||
| revalidate: revalidate === false ? undefined : revalidate, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat -n src/api/boards/server/getPostList.tsRepository: solid-connection/solid-connect-web
Length of output: 1521
🏁 Script executed:
rg -n "getPostList" --type ts --type tsx -A 3 -B 3Repository: solid-connection/solid-connect-web
Length of output: 105
🏁 Script executed:
rg -n "export const revalidate" --type ts --type tsx -A 2Repository: solid-connection/solid-connect-web
Length of output: 105
🏁 Script executed:
find . -type f \( -name "*.ts" -o -name "*.tsx" \) -exec grep -l "getPostList" {} \;Repository: solid-connection/solid-connect-web
Length of output: 200
🏁 Script executed:
find . -type f \( -name "*.ts" -o -name "*.tsx" \) -exec grep -l "export const revalidate" {} \;Repository: solid-connection/solid-connect-web
Length of output: 179
🏁 Script executed:
cat -n ./src/app/community/\[boardCode\]/page.tsxRepository: solid-connection/solid-connect-web
Length of output: 2134
🏁 Script executed:
cat -n ./src/api/boards/clients/useGetPostList.tsRepository: solid-connection/solid-connect-web
Length of output: 1563
주석 업데이트 필요: false 값 처리의 의도를 명확히 해주세요.
이 변경사항에서 revalidate === false ? undefined : revalidate 로직은 의도된 설계로 보입니다. 다만 현재 주석과 실제 동작이 불일치합니다:
-
의도된 동작:
false를undefined로 변환하여 라우트 레벨revalidate설정에 위임 -
주석의 문제점:
- Line 15: "또는 false (무한 캐시)" → 실제로는 무한 캐시를 강제하지 않고 라우트 설정에 위임
- Line 21: "자동 재생성 비활성화 (수동 revalidate만)" → 라우트 레벨에서 이미 제어되고 있음
-
현재 안전성:
community/[boardCode]/page.tsx에서export const revalidate = false로 설정되어 있어 동작에 영향 없음
주석을 다음과 같이 수정하면 명확할 것 같습니다:
@param revalidate - ISR revalidate 시간(초) 또는 false (라우트 레벨 설정에 위임, 지정하지 않으면 라우트 기본값 사용)
🤖 Prompt for AI Agents
In src/api/boards/server/getPostList.ts around line 35, the ternary that
converts revalidate === false to undefined is intentional but the existing
JSDoc/comments (around lines 15 and 21) incorrectly state that false means
"infinite cache" or "disable automatic regeneration"; update the comment to
state that passing false delegates to the route-level revalidate setting (i.e.,
false becomes undefined here so route defaults apply), and clarify that if no
route-level value exists the route default is used; adjust the @param line to:
"revalidate - ISR revalidate time (seconds) or false (delegates to route-level
setting; if not specified the route default is used)" so the comment matches the
code behavior.
| "use client"; | ||
|
|
||
| import MentorApplyCountContent from "../MentorApplyCountContent"; | ||
|
|
||
| /** | ||
| * 서버 컴포넌트에서 사용 가능한 MentorApplyCountModal 래퍼 | ||
| * MentorApplyCountContent를 그대로 렌더링합니다. | ||
| */ | ||
| const MentorApplyCountModal = () => { | ||
| return <MentorApplyCountContent />; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
fd -e tsx -e ts -type f | grep -i mentorapplycountcontent | head -20Repository: solid-connection/solid-connect-web
Length of output: 248
🏁 Script executed:
find . -name "*MentorApplyCountContent*" -type fRepository: solid-connection/solid-connect-web
Length of output: 60
🏁 Script executed:
rg "export.*MentorApplyCountContent" --type tsx --type tsRepository: solid-connection/solid-connect-web
Length of output: 105
🏁 Script executed:
find . -path "*MentorApplyCountContent*" -name "*.tsx" -o -path "*MentorApplyCountContent*" -name "*.ts"Repository: solid-connection/solid-connect-web
Length of output: 135
🏁 Script executed:
ls -la src/components/mentor/ | grep -i mentorRepository: solid-connection/solid-connect-web
Length of output: 415
🏁 Script executed:
head -15 ./src/components/mentor/MentorApplyCountContent/index.tsxRepository: solid-connection/solid-connect-web
Length of output: 524
MentorApplyCountContent가 이미 "use client" 지시어를 가지고 있으므로 이 래퍼는 불필요합니다.
MentorApplyCountContent 파일의 첫 줄에 "use client" 지시어가 있으므로, MentorApplyCountModal은 단순히 한 줄의 렌더링만 수행하는 중복된 래퍼입니다. 다음과 같이 정리하는 것을 권장합니다:
- 이 래퍼를 제거하고
MentorApplyCountContent를 직접 임포트하여 사용하거나 - 래퍼를 유지하려면 클라이언트 경계 마킹 이상의 추가 기능(props 변환, 로직 추가, 상태 관리 등)을 구현해야 합니다.
현재 상태에서는 래퍼를 유지할 명확한 이유가 없습니다.
🤖 Prompt for AI Agents
In src/components/mentor/MentorApplyCountModal/index.tsx lines 1-11, the file is
a client wrapper that only re-exports MentorApplyCountContent which already has
the "use client" directive, so this component is redundant; remove this wrapper
and update all imports to reference MentorApplyCountContent directly, or if you
want to keep the wrapper implement additional client-side logic (props mapping,
state, hooks) and keep the "use client" directive here — choose one: delete the
file and fix imports, or add meaningful client responsibilities before keeping
it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (3)
package.jsonsrc/app/university/search/PageContent.tsxsrc/lib/firebaseAdmin.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- package.json
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/components/ui/TabSelector.tsx:10-11
Timestamp: 2025-08-12T09:41:44.182Z
Learning: manNomi prefers to keep reusable UI components simple and focused on core functionality rather than adding many features. They don't want to over-engineer flexible/reusable UI components at the initial stage.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/components/mentor/MentorChatCard/index.tsx:17-21
Timestamp: 2025-08-24T11:14:34.297Z
Learning: manNomi prefers not to receive accessibility suggestions or recommendations during code reviews.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/usePostLogout.ts:17-33
Timestamp: 2025-08-24T11:13:08.477Z
Learning: manNomi prefers to prioritize user experience over perfect state consistency in auth flows. Specifically, in logout scenarios, they prefer to keep tokens intact on API failure to avoid forcing users to re-login, even if it means temporary UI state inconsistency.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/useDeleteUserAccount.ts:17-27
Timestamp: 2025-08-24T11:11:40.758Z
Learning: manNomi prefers optimistic navigation in auth-related flows (like account deletion) to prevent race conditions where token clearing before navigation could cause intermediate redirects to login page due to pending async requests failing.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/types/mentor.ts:70-73
Timestamp: 2025-08-12T04:07:04.134Z
Learning: manNomi prefers using Korean labels directly in enum values (e.g., MentorTab.MY_MENTEE = "나의 멘티") over separating enum keys from UI labels for efficiency and intuitiveness, considering scalability concerns as excessive for their current project needs.
🔇 Additional comments (4)
src/app/university/search/PageContent.tsx (4)
109-109: 방어적 null 처리가 적절합니다.
field.value ?? ""를 사용하여 undefined를 안전하게 빈 문자열로 변환했습니다. CustomDropdown이 항상 string 타입을 받을 수 있도록 보장합니다.
137-138: 명시적 타입 선언으로 가독성이 개선되었습니다.country 필드명을 명시적 union 타입(
"country1" | "country2" | "country3")으로 선언하여 코드의 의도가 더 명확해졌습니다.
156-163: 방어적 처리와 연쇄 초기화 로직이 우수합니다.변경사항:
field.value ?? ""로 안전한 값 처리- 상위 국가 필드가 비워질 때 하위 필드들도 자동으로 초기화
연쇄 초기화 로직 덕분에 사용자가 country1을 지우면 country2, country3도 함께 초기화되어 일관성 있는 상태를 유지합니다.
185-185: 클래스명 순서 정리가 완료되었습니다.Prettier/ESLint 규칙에 따라
typo-sb-9클래스의 위치가 조정되었습니다. 기능에는 영향이 없습니다.
| projectId: process.env.FIREBASE_PROJECT_ID, | ||
| private_key_id: process.env.FIREBASE_PRIVATE_KEY_ID, | ||
| privateKey: process.env.FIREBASE_PRIVATE_KEY!.replace(/\\n/g, "\n"), | ||
| privateKey, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat -n src/lib/firebaseAdmin.tsRepository: solid-connection/solid-connect-web
Length of output: 1444
🏁 Script executed:
# Check if there are Firebase type definitions or configuration files
find . -type f \( -name "*.ts" -o -name "*.json" \) -path "*/node_modules/firebase-admin/*" 2>/dev/null | head -5Repository: solid-connection/solid-connect-web
Length of output: 60
🌐 Web query:
Firebase Admin SDK service account credential field names private_key privateKey
💡 Result:
Short answer: the service-account JSON file uses "private_key" (snake_case); the Admin SDK's cert() ServiceAccount object (in code/TypeScript) accepts "privateKey" (camelCase). Use the JSON as-is (private_key) when loading the file, or pass an object with privateKey when constructing a ServiceAccount in code. [1][2][3]
Sources:
- Firebase setup / service account JSON format (private_key). [1]
- Firebase Admin Node.js reference — cert() example uses privateKey in the ServiceAccount object. [2]
- Stack Overflow example/error showing the JSON must contain "private_key". [3]
🌐 Web query:
Firebase Admin SDK cert ServiceAccount TypeScript interface projectId clientEmail field names
💡 Result:
Short answer — the TypeScript ServiceAccount used with admin.credential.cert() has these camelCase fields:
- projectId?: string
- clientEmail?: string
- privateKey?: string
(These are the names in the SDK's ServiceAccount interface; cert() accepts either that object or a path to the JSON key file.) [1][3]
Note: the downloaded Google service-account JSON file uses snake_case key names: project_id, client_email, private_key — when providing an object to cert() you must map those to the camelCase names (or load the JSON and pass it directly). [2][1]
References:
- Firebase Admin SDK ServiceAccount interface. [1]
- Google service account JSON key file field names (project_id, client_email, private_key). [2]
- GitHub discussion showing the camelCase vs snake_case usage with cert(). [3]
🌐 Web query:
Firebase Admin SDK ServiceAccount complete interface all field names privateKeyId clientId
💡 Result:
Short answer — two sets of fields:
- Firebase Admin SDK TypeScript interface ServiceAccount (what admin.cert() accepts as an object) — fields in the SDK typings:
- clientEmail
- privateKey
- projectId. [1]
- Typical Google service-account JSON key file (full field names you see in the downloaded JSON; includes private_key_id and client_id):
- type
- project_id
- private_key_id
- private_key
- client_email
- client_id
- auth_uri
- token_uri
- auth_provider_x509_cert_url
- client_x509_cert_url. [2]
References:
[1] Firebase Admin SDK — ServiceAccount interface.
[2] Example service account JSON format used by firebase-admin / Google Cloud.
privateKey는 Firebase Admin SDK가 요구하는 올바른 필드명입니다
Firebase Admin SDK의 cert() 함수는 서비스 계정 객체에 camelCase 필드명을 기대합니다 (privateKey, clientEmail, projectId). 따라서 현재 코드의 privateKey 필드명은 정확합니다.
(참고: 다운로드한 JSON 파일은 snake_case를 사용하지만, JavaScript 객체로 전달할 때는 camelCase를 사용해야 합니다.)
다만, 더 심각한 문제가 있습니다:
- line 7의 빈 문자열 폴백이 위험합니다
FIREBASE_PRIVATE_KEY환경변수가 없으면privateKey가 빈 문자열("")이 됩니다- Firebase 인증이 조용히 실패하여 런타임 에러로 이어집니다
- empty string 대신 명시적 에러를 발생시키는 것이 좋습니다
- const privateKey = process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, "\n") ?? "";
+ const privateKey = process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, "\n");
+ if (!privateKey) {
+ throw new Error("FIREBASE_PRIVATE_KEY environment variable is not set");
+ }Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/lib/firebaseAdmin.ts around line 12, the current use of
process.env.FIREBASE_PRIVATE_KEY with an empty-string fallback is unsafe because
it allows building a creds object with privateKey="" and causes silent runtime
auth failures; instead, validate the env var at startup and throw a clear,
descriptive error if FIREBASE_PRIVATE_KEY is missing or empty (e.g., check for
presence/trim length and throw new Error('FIREBASE_PRIVATE_KEY is required')
before constructing the cert object), ensuring the application fails fast and
loudly when the credential is not provided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/app/university/[id]/_ui/UniversityDetail/_ui/InfoSection.tsxsrc/lib/firebaseAdmin.tssrc/lib/firebaseKeywords.tssrc/lib/firebaseNews.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/app/university/[id]/_ui/UniversityDetail/_ui/InfoSection.tsx
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/components/ui/TabSelector.tsx:10-11
Timestamp: 2025-08-12T09:41:44.182Z
Learning: manNomi prefers to keep reusable UI components simple and focused on core functionality rather than adding many features. They don't want to over-engineer flexible/reusable UI components at the initial stage.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/components/mentor/MentorChatCard/index.tsx:17-21
Timestamp: 2025-08-24T11:14:34.297Z
Learning: manNomi prefers not to receive accessibility suggestions or recommendations during code reviews.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/usePostLogout.ts:17-33
Timestamp: 2025-08-24T11:13:08.477Z
Learning: manNomi prefers to prioritize user experience over perfect state consistency in auth flows. Specifically, in logout scenarios, they prefer to keep tokens intact on API failure to avoid forcing users to re-login, even if it means temporary UI state inconsistency.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/useDeleteUserAccount.ts:17-27
Timestamp: 2025-08-24T11:11:40.758Z
Learning: manNomi prefers optimistic navigation in auth-related flows (like account deletion) to prevent race conditions where token clearing before navigation could cause intermediate redirects to login page due to pending async requests failing.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/types/mentor.ts:70-73
Timestamp: 2025-08-12T04:07:04.134Z
Learning: manNomi prefers using Korean labels directly in enum values (e.g., MentorTab.MY_MENTEE = "나의 멘티") over separating enum keys from UI labels for efficiency and intuitiveness, considering scalability concerns as excessive for their current project needs.
🔇 Additional comments (4)
src/lib/firebaseAdmin.ts (2)
56-63: 프로덕션 환경에서 Firebase 초기화 실패 시 에러 처리 전략 확인 필요초기화 실패 시
null을 반환하는 것은 CI 환경에서는 적절하지만, 프로덕션 환경에서 Firebase가 잘못 설정된 경우(예: 유효하지 않은 private key 형식) 조용히 실패합니다.현재 동작:
- Firebase 초기화 실패 →
console.error로그 →null반환 → 앱 계속 실행- Firebase 의존 기능들은 빈 배열/조기 반환으로 처리
확인 필요:
- 프로덕션에서 Firebase 초기화 실패를 모니터링/알림 설정했는지
- 의도적으로 Firebase 없이 앱을 실행할 수 있도록 설계했는지
45-45: 검토 결과: 이 필드들은 Firebase Admin SDK에서 선택사항입니다좋은 지적이지만, Firebase Admin SDK 문서를 확인한 결과 다음과 같이 정리됩니다:
필수 필드 - 반드시 검증 필요
projectId✓ 이미 검증됨privateKey✓ 이미 검증됨clientEmail✓ 이미 검증됨선택 필드 - 검증 불필요
private_key_id(JWT 헤더에서 서명 키 식별용)client_id(서비스 계정 수치 ID)client_x509_cert_url(공개 인증서 URL)따라서 현재 코드는 올바르게 구현되었습니다. 선택적 필드는 환경변수에서 직접 할당되거나 undefined 상태로 남아도 Firebase 초기화에 영향을 주지 않습니다.
Likely an incorrect or invalid review comment.
src/lib/firebaseKeywords.ts (1)
5-42: Firebase 초기화 가드 패턴이 올바르게 적용됨두 함수 모두 Firebase 초기화 실패를 적절히 처리합니다:
fetchPopularKeywords: 빈 배열 반환으로 안전하게 처리saveSearchKeyword: 조기 반환으로 쓰기 작업 스킵CI 환경에서 Firebase 없이도 빌드가 가능하도록 하는 패턴이 일관되게 적용되었습니다.
src/lib/firebaseNews.ts (1)
7-13: Firebase 초기화 가드가 올바르게 적용됨CI 환경에서 Firebase가 설정되지 않은 경우를 적절히 처리합니다. 빈 배열 반환과 경고 로그로 안전하게 동작합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
.husky/pre-pushsrc/lib/firebaseAdmin.tssrc/lib/firebaseNews.ts
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/components/ui/TabSelector.tsx:10-11
Timestamp: 2025-08-12T09:41:44.182Z
Learning: manNomi prefers to keep reusable UI components simple and focused on core functionality rather than adding many features. They don't want to over-engineer flexible/reusable UI components at the initial stage.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/components/mentor/MentorChatCard/index.tsx:17-21
Timestamp: 2025-08-24T11:14:34.297Z
Learning: manNomi prefers not to receive accessibility suggestions or recommendations during code reviews.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/usePostLogout.ts:17-33
Timestamp: 2025-08-24T11:13:08.477Z
Learning: manNomi prefers to prioritize user experience over perfect state consistency in auth flows. Specifically, in logout scenarios, they prefer to keep tokens intact on API failure to avoid forcing users to re-login, even if it means temporary UI state inconsistency.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 245
File: src/api/auth/client/useDeleteUserAccount.ts:17-27
Timestamp: 2025-08-24T11:11:40.758Z
Learning: manNomi prefers optimistic navigation in auth-related flows (like account deletion) to prevent race conditions where token clearing before navigation could cause intermediate redirects to login page due to pending async requests failing.
Learnt from: manNomi
Repo: solid-connection/solid-connect-web PR: 242
File: src/types/mentor.ts:70-73
Timestamp: 2025-08-12T04:07:04.134Z
Learning: manNomi prefers using Korean labels directly in enum values (e.g., MentorTab.MY_MENTEE = "나의 멘티") over separating enum keys from UI labels for efficiency and intuitiveness, considering scalability concerns as excessive for their current project needs.
🔇 Additional comments (5)
src/lib/firebaseNews.ts (2)
6-12: 이전 리뷰 이슈가 잘 해결되었습니다! 초기화 가드 로직이 적절합니다.변경사항 정리:
- 동기적 초기화: Firebase Admin을 동기적으로 호출하여 초기화 여부를 즉시 확인합니다.
- 조기 반환 가드: Firebase가 초기화되지 않은 경우(CI 환경 등) 명확한 경고 메시지와 함께 빈 배열을 반환합니다.
- 명확한 실패 처리: 초기화 실패는 null 반환으로 감지되며, 실제 데이터 처리 오류는 이제 상위로 전파됩니다.
이 접근 방식은 CI 환경에서의 빌드 성공과 프로덕션 환경에서의 명확한 에러 전파를 모두 만족합니다.
14-26: 에러 전파 개선 - 이전 리뷰의 핵심 문제가 해결되었습니다.변경사항:
- 과도한 catch 블록 제거: 이전에 모든 에러를 잡아 빈 배열로 반환하던 로직이 제거되었습니다.
- 실제 버그 노출: 네트워크 장애, 데이터 파싱 에러, 런타임 예외가 이제 적절히 상위로 전파됩니다.
- 디버깅 용이성: 프로덕션 환경에서 실제 문제가 발생하면 명확한 에러 메시지를 확인할 수 있습니다.
이전 리뷰에서 지적된 "실제 버그를 마스킹할 수 있는" 문제가 완전히 해결되었습니다.
src/lib/firebaseAdmin.ts (3)
4-20: 환경변수 검증 로직이 매우 잘 구현되었습니다!변경사항 정리:
- 명시적 검증: 각 필수 환경변수(projectId, privateKey, clientEmail)를 개별적으로 검증합니다.
- 명확한 에러 메시지: 어떤 환경변수가 누락되었는지 구체적으로 알려주는 에러를 발생시킵니다.
- 값 정제: trim()으로 공백을 제거하고, privateKey의 개행 문자를 정규화합니다.
- 조기 실패 전략: 빈 문자열 폴백 대신 즉시 에러를 발생시켜 설정 오류를 조기에 발견합니다.
이전 리뷰에서 지적된 "빈 문자열 폴백으로 인한 조용한 실패" 문제가 완벽하게 해결되었습니다.
24-31: CI 환경 감지 로직이 정확합니다.변경사항:
- 전체 누락 감지: 세 개의 환경변수가 모두 없는 경우만 true를 반환합니다.
- 부분 설정 구분: 하나라도 설정된 경우 false를 반환하여 validateFirebaseEnv()에서 검증하도록 합니다.
- 명확한 의도: 함수명과 주석이 용도를 명확하게 설명합니다.
CI 빌드 환경(모든 변수 없음)과 잘못된 설정(일부만 있음)을 정확히 구분합니다.
33-68: 초기화 흐름이 모든 케이스를 올바르게 처리합니다!변경사항 정리:
CI 환경 처리 (lines 34-38):
- 모든 환경변수가 없으면 경고 로그와 함께 null 반환
- 에러를 발생시키지 않아 CI 빌드가 정상적으로 완료됩니다
부분 설정 검증 (line 42):
- 하나라도 환경변수가 있으면 validateFirebaseEnv()를 호출
- 누락된 변수에 대해 명확한 에러가 발생합니다
정제된 값 사용 (lines 46, 48-49):
- 검증된 projectId, privateKey, clientEmail을 사용
- 더 이상 직접 env 변수를 참조하지 않습니다
초기화 에러 처리 (lines 62-64):
- 초기화 실패 시 에러를 로깅하고 null 반환
- 상위 호출자가 null을 통해 실패를 감지할 수 있습니다
이전 리뷰에서 지적된 "부분 설정 시 검증이 우회되는 로직 문제"가 완벽하게 해결되었습니다. 세 가지 케이스(전체 누락 / 부분 설정 / 완전 설정)를 모두 적절히 처리합니다.
| #!/usr/bin/env sh | ||
| . "$(dirname -- "$0")/_/husky.sh" | ||
|
|
||
| echo "🔍 Running lint check before push..." | ||
| npm run lint | ||
|
|
||
| echo "🔍 Running type check before push..." | ||
| npm run typecheck | ||
|
|
||
| echo "✅ All checks passed!" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오류 발생 시 push가 차단되지 않는 치명적인 문제가 있습니다.
현재 스크립트는 lint나 typecheck가 실패해도 계속 진행되며, 심지어 "All checks passed!" 메시지까지 출력합니다. 이는 pre-push 훅의 핵심 목적을 무력화시킵니다.
🔎 오류 발생 시 즉시 종료하도록 수정
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
+
+set -e
echo "🔍 Running lint check before push..."
npm run lint
echo "🔍 Running type check before push..."
npm run typecheck
echo "✅ All checks passed!"set -e를 추가하면 어떤 명령이든 실패할 경우(non-zero exit code) 즉시 스크립트가 종료되어 push가 차단됩니다.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #!/usr/bin/env sh | |
| . "$(dirname -- "$0")/_/husky.sh" | |
| echo "🔍 Running lint check before push..." | |
| npm run lint | |
| echo "🔍 Running type check before push..." | |
| npm run typecheck | |
| echo "✅ All checks passed!" | |
| #!/usr/bin/env sh | |
| . "$(dirname -- "$0")/_/husky.sh" | |
| set -e | |
| echo "🔍 Running lint check before push..." | |
| npm run lint | |
| echo "🔍 Running type check before push..." | |
| npm run typecheck | |
| echo "✅ All checks passed!" |
🤖 Prompt for AI Agents
In .husky/pre-push around lines 1-10, the script continues even if npm run lint
or npm run typecheck fail and still prints "All checks passed!"; add an
immediate-exit setting (e.g., enable set -e and optionally set -o pipefail) at
the top so the hook aborts on any non-zero exit status, keep the existing
commands as-is (they will cause the script to exit on failure) and leave the
final success echo only reachable when both commands succeed.
관련 이슈
작업 내용