Skip to content

Conversation

@manNomi
Copy link
Contributor

@manNomi manNomi commented Dec 11, 2025

관련 이슈

  • resolves: #이슈 번호

작업 내용

  • 대학 정보 페이지 컴포넌트 구조 개선
  • 대학 정보 페이지 메타데이터 개선

특이 사항

리뷰 요구사항 (선택)

@manNomi manNomi requested a review from wibaek as a code owner December 11, 2025 08:41
@coderabbitai
Copy link

coderabbitai bot commented Dec 11, 2025

워크스루

  1. TitleSection의 타이포그래피 클래스 순서를 재정렬했습니다.
  2. UniversityDetail의 여러 UI 요소에서 클래스 순서와 일부 import 경로를 "../"로 변경했습니다.
  3. page.tsx에서 generateMetadata 시그니처를 단순화하고, openGraph·twitter·alternates를 포함한 SEO 메타데이터를 확장했습니다.
  4. 페이지에 JSON-LD 구조화된 데이터 스크립트를 주입하도록 렌더 흐름을 보강했습니다.

예상 코드 리뷰 노력

🎯 3 (보통) | ⏱️ ~25분

  • src/app/university/[id]/page.tsx의 SEO 필드(openGraph, twitter, alternates)와 URL(imageUrl, pageUrl, baseUrl) 조합 검증이 필요합니다.
  • 삽입된 JSON-LD의 스키마 유효성 및 조건부 필드(이미지 등) 확인이 필요합니다.
  • import 경로 변경이 다른 모듈에서 일관되게 동작하는지 점검하세요.
  • 클래스명 순서 변경은 주로 스타일 영향 검토만 필요합니다.

제안 리뷰어

  • wibaek

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive PR 설명이 필수 섹션 구조를 따르고 있으나, 구체적인 작업 내용과 변경 사항이 충분히 상세하지 않습니다. 작업 내용 섹션에서 구체적인 변경 사항(메타데이터 필드 추가, import 경로 변경, 클래스 순서 조정 등)을 자세히 설명하고, 특이 사항 섹션에 영향 범위를 명시해주세요.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 변경 사항의 주요 목표를 명확하게 반영합니다. 대학 정보 페이지 메타데이터 수정이라는 핵심 내용이 간결하게 표현되어 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a 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: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3d3f02 and 0f27f57.

📒 Files selected for processing (3)
  • src/app/university/[id]/_ui/UniversityDetail/_ui/TitleSection.tsx (1 hunks)
  • src/app/university/[id]/_ui/UniversityDetail/index.tsx (3 hunks)
  • src/app/university/[id]/page.tsx (4 hunks)
🧰 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.
🪛 ast-grep (0.40.0)
src/app/university/[id]/page.tsx

[warning] 128-128: 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)

🔇 Additional comments (8)
src/app/university/[id]/_ui/UniversityDetail/_ui/TitleSection.tsx (1)

16-16: 클래스명 순서 정리 완료!

타이포그래피 클래스를 앞으로 배치하여 일관성을 개선했습니다. 기능적 변경이 없으므로 안전한 변경입니다.

src/app/university/[id]/_ui/UniversityDetail/index.tsx (3)

7-11: 컴포넌트 구조 개선 - import 경로 정리

import 경로를 상위 디렉토리 참조(../)로 변경하여 컴포넌트 구조를 명확하게 개선했습니다. 이는 PR 설명에 언급된 "대학 정보 페이지 컴포넌트 구조 개선"의 일환으로 보입니다.


38-40: 스타일 클래스 순서 통일

타이포그래피 클래스를 앞으로 배치하여 코드 일관성을 개선했습니다. 렌더링에는 영향이 없습니다.


54-55: 타이포그래피 클래스 순서 정리

전공상세 및 영어강의 리스트 섹션에서도 동일하게 타이포그래피 클래스를 앞으로 배치하여 일관성을 유지했습니다.

Also applies to: 61-63

src/app/university/[id]/page.tsx (4)

1-1: import 구성 개선

  1. Metadata 타입 import 추가
  2. UniversityDetail 컴포넌트 경로를 ./_ui/UniversityDetail로 변경
  3. getUniversityDetail API import 추가

컴포넌트 구조 개선에 맞춰 import를 적절히 업데이트했습니다.

Also applies to: 6-6, 9-9


129-129: dangerouslySetInnerHTML 사용은 이 경우 안전합니다

정적 분석 도구가 dangerouslySetInnerHTML 사용에 대해 경고하고 있지만, 이 경우는 안전합니다:

안전한 이유:

  1. structuredData는 서버 측에서 생성된 내부 데이터입니다
  2. 사용자 입력이 전혀 포함되지 않습니다
  3. JSON.stringify()로 안전하게 직렬화됩니다
  4. JSON-LD 스크립트를 삽입하는 표준적인 방법입니다

이는 Next.js에서 structured data를 추가하는 일반적인 패턴이며, XSS 위험이 없습니다.


104-125: 구조화된 데이터(JSON-LD) 추가 - 검색 최적화!

schema.org의 EducationalOrganization 타입을 사용하여 구조화된 데이터를 추가했군요. 좋은 시작입니다!

다만 몇 가지 확인해볼 점이 있습니다:

  1. 현재 구현 — name, url, description, image 필드를 포함하고 있어 기본적인 마크업이 잘 되어 있습니다.

  2. schema.org 스펙 — EducationalOrganization은 "필수" 필드가 없습니다. 하지만 Google과 검색 엔진은 다음 속성을 권장합니다:

    • logo (이미지 객체 또는 URL)
    • address (PostalAddress 형식)
    • contactPoint (전화, 이메일 등)
    • sameAs (소셜 미디어, 공식 프로필 링크)
    • foundingDate, numberOfEmployees 등 추가 메타데이터
  3. 구현 제안 — 향후 이러한 권장 필드들을 단계적으로 추가하면 검색 결과의 풍부한 정보 표시(Rich Results)를 더욱 개선할 수 있습니다.

  4. 기술 확인 — 이 마크업이 <script type="application/ld+json"> 블록으로 감싸져 있는지, 그리고 Google Rich Results Test로 검증했는지 확인하세요.

현재 코드는 타입 안전성도 잘 확보하고 있으니, 추가 속성 확장은 향후 진행해도 좋겠습니다.


25-80: 메타데이터 대폭 개선 - SEO 최적화 완료!

PR 목표인 "대학 정보 페이지 메타데이터 개선"을 매우 잘 구현했습니다:

  1. Open Graph 메타데이터 추가

    • 소셜 미디어 공유 시 풍부한 프리뷰 제공
    • 이미지, 제목, 설명이 모두 포함됨
  2. Twitter 카드 메타데이터 추가

    • summary_large_image 타입으로 트위터 최적화
  3. Canonical URL 추가

    • SEO 중복 콘텐츠 문제 방지
  4. 상세한 description 생성

    • 대학명, 국가, 모집 인원 등 핵심 정보 포함
    • 코드의 주석에서 이미 150자 이내 권장을 명시하고 있으며, 실제로도 현실적인 대학명들로 생성되는 description은 110자 이내에서 잘 관리되고 있습니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/app/university/[id]/page.tsx (2)

25-87: 메타데이터 생성 로직 개선 확인

  1. SEO 최적화가 잘 구현되었습니다:

    • openGraph, twitter, canonical 메타데이터 추가
    • 국가별 키워드 (${country} 교환학생) 활용
    • 동적 이미지 URL 생성 및 폴백 처리
  2. 기본 이미지가 article-thumb.png로 변경되어 이전 리뷰의 파일 누락 문제가 해결되었습니다.

다만, Lines 41-47의 baseUrl, pageUrl, imageUrl 생성 로직이 Lines 107-133에서 중복됩니다. 헬퍼 함수로 추출하면 유지보수성이 향상됩니다.

선택적 리팩토링 제안:

// utils/seo.ts 또는 해당 파일 상단에 추가
function generateUniversityUrls(
  universityId: number,
  backgroundImageUrl: string | undefined
) {
  const baseUrl = process.env.NEXT_PUBLIC_WEB_URL || "https://solid-connection.com";
  const pageUrl = `${baseUrl}/university/${universityId}`;
  const imageUrl = backgroundImageUrl
    ? backgroundImageUrl.startsWith("http")
      ? backgroundImageUrl
      : `${baseUrl}${backgroundImageUrl}`
    : `${baseUrl}/images/article-thumb.png`;
  
  return { baseUrl, pageUrl, imageUrl };
}

이렇게 하면 generateMetadataCollegeDetailPage 양쪽에서 재사용할 수 있습니다.


107-134: JSON-LD 구조화된 데이터 추가 확인

EducationalOrganization 스키마를 사용한 구조화된 데이터는 검색 엔진 최적화에 효과적입니다.

Lines 114-122의 타입 명시는 명확하지만, 별도 타입으로 추출하면 재사용성이 높아집니다.

선택적 개선 사항:

// types/seo.ts
type UniversityStructuredData = {
  "@context": "https://schema.org";
  "@type": "EducationalOrganization";
  name: string;
  alternateName?: string;
  url: string;
  description: string;
  image: string;
};
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f27f57 and f8ab9f8.

📒 Files selected for processing (1)
  • src/app/university/[id]/page.tsx (4 hunks)
🧰 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.
🪛 ast-grep (0.40.0)
src/app/university/[id]/page.tsx

[warning] 137-137: 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)

🔇 Additional comments (2)
src/app/university/[id]/page.tsx (2)

1-6: Import 변경사항 확인 완료

  1. ResolvingMetadata 제거는 Next.js 15의 권장 패턴과 일치합니다.
  2. UniversityDetail 컴포넌트의 import 경로를 _ui 폴더로 이동한 것은 코드 구조 개선입니다.

138-138: JSON-LD 스크립트 주입 안전성 확인

정적 분석 도구가 dangerouslySetInnerHTML 사용을 경고했지만, 이 경우는 안전합니다:

  1. structuredData는 서버 측에서 신뢰할 수 있는 데이터베이스 소스로부터 생성됩니다.
  2. JSON.stringify()가 모든 특수 문자를 자동으로 이스케이프합니다.
  3. JSON-LD 스키마 마크업 주입은 표준적인 SEO 관행입니다.

사용자 입력이 직접 포함되지 않으므로 XSS 위험이 없습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant