-
Notifications
You must be signed in to change notification settings - Fork 2
feat : 홈페이지 스트럭처 데이터 추가 #312
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?
Conversation
개요홈페이지 컴포넌트에서 SEO 최적화 및 레이아웃 재구성이 진행되었습니다. 다음 내용이 추가되었습니다:
기존 데이터 페치(newsList, recommendedUniversities, allRegionsUniversityList)는 유지되지만, 렌더링 흐름이 새로운 섹션에 맞게 변경되었습니다. 코드 리뷰 예상 소요 시간🎯 3 (Moderate) | ⏱️ ~20-25분
검토 제안자
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ 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: 2
🧹 Nitpick comments (1)
src/app/(home)/page.tsx (1)
23-53: 2) 메타데이터 구성은 깔끔해졌고, “중복”은 문제될 수준은 아니에요.
title/description을 OG/Twitter에 반복 세팅하는 건 일반적인 패턴이라 “과한 SEO 관리”로 보이진 않아요.- 다만 문자열이 길어지기 쉬우니(특히 title) 실제 SERP/공유 카드에서 잘리는지 정도만 한번 확인하면 충분해요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/app/(home)/page.tsx(2 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.
🧬 Code graph analysis (1)
src/app/(home)/page.tsx (1)
public/svgs/home/index.ts (4)
IconMagnifyingGlass(14-14)IconPaper(16-16)IconMuseum(15-15)IconIdCard(13-13)
🪛 ast-grep (0.40.0)
src/app/(home)/page.tsx
[warning] 77-77: 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)
🔇 Additional comments (2)
src/app/(home)/page.tsx (2)
55-67: 구조화 데이터의 쿼리 키(searchText)가 실제 라우트와 일치합니다.검색 구현을 확인한 결과, SearchBar 컴포넌트와 SearchResultsContent 모두에서
searchText매개변수를 일관되게 사용하고 있습니다.
- 쿼리 생성: SearchBar.tsx에서
queryParams.append("searchText", data.searchText.trim())로 검색 쿼리를 생성합니다.- 쿼리 읽기: SearchResultsContent.tsx에서
searchParams.get("searchText")로 검색 매개변수를 읽습니다.따라서 구조화 데이터의
target: /university?searchText={search_term_string}은 실제 구현과 완벽하게 일치하므로 추가 수정이 불필요합니다.
69-75: 이 검토 의견은 대상 지정이 부정확합니다.
- "실시간" 레이블은 **145번 줄의 뉴스 섹션이 아니라 137번 줄의 PopularUniversitySection("실시간 인기있는 파견학교")**에 있습니다.
- 직렬화 문제는 발견되지 않습니다:
fetchAllNews()는 오직 기본 타입만 반환합니다 (id: number, title/description/imageUrl/url: string). News 인터페이스에는 Date/Timestamp 필드가 없고, NewsSectionDynamic으로 전달되는 newsList는 모두 직렬화 가능한 데이터입니다.revalidate = 60 * 60 * 24(24시간)는 전체 페이지에 적용되며, 현재 뉴스 섹션 구현에서는 직렬화 관련 런타임 에러가 발생하지 않습니다.Likely an incorrect or invalid review comment.
| const baseUrl = process.env.NEXT_PUBLIC_WEB_URL || "https://solid-connection.com"; | ||
| const ogImageUrl = `${baseUrl}/opengraph-image.png`; | ||
|
|
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:
# Read the relevant file to see current state
head -n 75 src/app/(home)/page.tsx | tail -n +15Repository: solid-connection/solid-connect-web
Length of output: 213
🏁 Script executed:
# Search for NEXT_PUBLIC_WEB_URL usage across the codebase
rg "NEXT_PUBLIC_WEB_URL" --type ts --type tsxRepository: solid-connection/solid-connect-web
Length of output: 105
🏁 Script executed:
# Search for environment files or configuration
fd -e env -e "env.*" | head -20Repository: solid-connection/solid-connect-web
Length of output: 60
🏁 Script executed:
# Check for URL construction patterns (canonical, OG) in the file
rg "canonical|og|openGraph" src/app/\(home\)/page.tsx -A 2 -B 2Repository: solid-connection/solid-connect-web
Length of output: 724
🏁 Script executed:
# Search for baseUrl usage throughout the file
rg "baseUrl" 'src/app/(home)/page.tsx' -nRepository: solid-connection/solid-connect-web
Length of output: 376
🏁 Script executed:
# Check environment configuration files
find . -type f \( -name ".env*" -o -name "*.config.*" \) | grep -v node_modules | head -20Repository: solid-connection/solid-connect-web
Length of output: 256
🏁 Script executed:
# Search for where NEXT_PUBLIC_WEB_URL might be set
rg "NEXT_PUBLIC_WEB_URL" . --type ts --type js -B 2 -A 2Repository: solid-connection/solid-connect-web
Length of output: 984
🏁 Script executed:
# Check if there's any URL normalization utility already in use
rg "replace.*/$|removeTrailing|normaliz.*url" . --type ts --type jsRepository: solid-connection/solid-connect-web
Length of output: 60
🏁 Script executed:
# Read environment files to check for trailing slashes in NEXT_PUBLIC_WEB_URL
cat .env .env.development .env.production 2>/dev/null | grep NEXT_PUBLIC_WEB_URLRepository: solid-connection/solid-connect-web
Length of output: 233
🏁 Script executed:
# Check for any other direct process.env.NEXT_PUBLIC_WEB_URL usage that might have same issue
rg "process\.env\.NEXT_PUBLIC_WEB_URL" . --type ts --type js -B 1 -A 1Repository: solid-connection/solid-connect-web
Length of output: 712
🏁 Script executed:
# Verify the exact canonical construction to see if double slash would actually occur
head -n 35 'src/app/(home)/page.tsx' | tail -n +20Repository: solid-connection/solid-connect-web
Length of output: 672
baseUrl 설정 시 후행 슬래시로 인한 canonical/OG URL 중복 방지
환경 변수로 전달되는 NEXT_PUBLIC_WEB_URL이 후행 슬래시로 끝나는 경우를 대비해야 합니다:
-
후행 슬래시 제거
${baseUrl}/패턴에서NEXT_PUBLIC_WEB_URL="https://example.com/"이면https://example.com//이 되어 URL 정규화를 깨뜨립니다. -
영향 범위
- Line 28: canonical URL
- Line 34: openGraph.url
- Line 60: JSON-LD url
- Line 21: ogImageUrl
모두 동일한 위험을 가집니다.
-const baseUrl = process.env.NEXT_PUBLIC_WEB_URL || "https://solid-connection.com";
+const baseUrl = (process.env.NEXT_PUBLIC_WEB_URL ?? "https://solid-connection.com").replace(/\/+$/, "");
const ogImageUrl = `${baseUrl}/opengraph-image.png`;참고: authUtils.ts에서도 직접 process.env.NEXT_PUBLIC_WEB_URL을 사용하므로 동일한 처리가 필요합니다.
📝 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.
| const baseUrl = process.env.NEXT_PUBLIC_WEB_URL || "https://solid-connection.com"; | |
| const ogImageUrl = `${baseUrl}/opengraph-image.png`; | |
| const baseUrl = (process.env.NEXT_PUBLIC_WEB_URL ?? "https://solid-connection.com").replace(/\/+$/, ""); | |
| const ogImageUrl = `${baseUrl}/opengraph-image.png`; | |
🤖 Prompt for AI Agents
In src/app/(home)/page.tsx around lines 20 to 22, baseUrl is taken directly from
NEXT_PUBLIC_WEB_URL which can end with a trailing slash and cause double-slashes
in constructed URLs (canonical, openGraph.url, JSON-LD url, ogImageUrl); trim
any trailing slash from the environment value before using it (e.g., normalize
process.env.NEXT_PUBLIC_WEB_URL by removing a trailing '/' unless the value is
just '/' or empty) and use that normalized baseUrl to build
canonical/OG/JSON-LD/ogImageUrl; apply the same normalization in authUtils.ts
where NEXT_PUBLIC_WEB_URL is used.
| <> | ||
| <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }} /> | ||
| <div className="w-full"> |
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.
4) dangerouslySetInnerHTML는 린트 에러 + 잠재 XSS 포인트라 교체가 필요해요.
- 현재는 상수 기반이라 “즉시 취약”까지는 아닐 수 있지만, 린트가 에러로 잡고 있어 머지 블로커에 가까워요.
next/script로 바꾸면 의도도 명확해지고 규칙도 피할 수 있어요(그리고<escaping도 같이 해두면 더 단단해요).
import { Metadata } from "next";
import dynamic from "next/dynamic";
import Link from "next/link";
+import Script from "next/script";
@@
const structuredData = {
"@context": "https://schema.org",
"@type": "WebSite",
@@
};
+
+const structuredDataJson = JSON.stringify(structuredData).replace(/</g, "\\u003c");
@@
return (
<>
- <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }} />
+ <Script id="home-structured-data" type="application/ld+json" strategy="beforeInteractive">
+ {structuredDataJson}
+ </Script>
<div className="w-full">Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 ast-grep (0.40.0)
[warning] 77-77: 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/(home)/page.tsx around lines 77 to 79, replace the raw <script
dangerouslySetInnerHTML> with Next's Script component and ensure the JSON-LD
string has '<' escaped to avoid XSS lint errors; import Script from
'next/script', then render <Script id="structured-data"
type="application/ld+json" dangerouslySetInnerHTML={{ __html:
JSON.stringify(structuredData).replace(/</g, '\\u003c') }} /> so the linter no
longer flags the pattern and the payload is safer.
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.
rsc라서 서버 작업이고 상수인데 xss 공격 위험이 있습니까?
서버데이터는 안전하게 보관되고 있다는 가정하입니다
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
🌐 Web query:
Next.js 15 JSON-LD structured data best practices Script component
💡 Result:
Here are concise Next.js 15 best practices for adding JSON‑LD (structured data) using script tags:
-
Render JSON‑LD as a <script type="application/ld+json"> inside your page or layout (server component) — Next.js recommends this. [1][2]
-
Sanitize/escape before inlining to avoid XSS — e.g. JSON.stringify(jsonLd).replace(/</g, '\u003c') or use a safe serializer (serialize-javascript) per your security policy. Example:
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/. [1] -
Placement:
- Put JSON‑LD in the layout/page that matches the content (head or top of page) so server-rendered HTML includes it for crawlers. Avoid duplicating the same schema across layouts/pages. [1][2]
-
When to use next/script:
- Prefer plain <script type="application/ld+json"> for static/server-known JSON‑LD.
- If you must inject dynamic JSON‑LD client-side, use next/script with strategy="beforeInteractive" (or push to dataLayer) to ensure it appears correctly and avoid hydration issues — but use this only when JSON‑LD cannot be produced server-side. [3]
-
Content correctness & scope:
- Use the most specific Schema.org type, keep values accurate and visible on the page, include required/recommended properties, and don’t mark up content that isn’t present (avoids search penalties). [4]
-
Types & tooling:
- Use TypeScript typing libs (e.g., schema-dts) to model JSON‑LD objects and validate during dev. Validate final output with Google Rich Results Test / Schema Markup Validator and monitor Search Console. [1][4]
-
Avoid common pitfalls:
- Duplicate scripts (check layouts and components), invalid JSON syntax, mismatched server/client JSON (causes hydration diffs), and leaking unsanitized user content into JSON‑LD. [1][4]
Sources:
- Next.js JSON‑LD guide and metadata docs. [1][2]
- Community guidance on using next/script for JSON‑LD (strategy beforeInteractive). [3]
- JSON‑LD best practices / validation guidance. [4]
@manNomi 맞습니다. 귀하의 평가가 정확해요.
1. RSC + 상수 데이터 → XSS 위험 거의 없음
- 서버 컴포넌트에서 하드코딩된 상수만 사용하고 있고, 사용자 입력이 전혀 들어가지 않기 때문에 실질적인 XSS 공격 벡터가 없습니다.
baseUrl도 환경 변수(빌드 타임)라서 안전합니다.
2. 린트 경고의 성격
- 린트 도구는 패턴 기반으로
dangerouslySetInnerHTML을 발견하면 맥락을 파악하지 못하고 무조건 경고를 띄웁니다. - 실제 위험이 아니라 "잠재적으로 위험할 수 있는 패턴"을 감지한 것입니다.
3. Next.js 권장사항
- 웹 검색 결과에 따르면, Next.js는 정적 JSON-LD의 경우 RSC에서 일반
<script type="application/ld+json">을 사용하는 것을 권장합니다. - 다만 방어적 차원에서
JSON.stringify(structuredData).replace(/</g, '\\u003c')같은 이스케이핑을 "best practice"로 제안하고 있지만, 현재 코드처럼 상수만 사용하는 경우엔 필수는 아닙니다.
현재 코드가 안전하다고 판단하신다면 그대로 유지하셔도 괜찮습니다. 린트 경고를 해소하고 싶으시면 간단한 < 이스케이핑만 추가하시면 됩니다. 선택은 귀하께 맡기겠습니다! 😊
🧠 Learnings used
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.
관련 이슈
작업 내용
리뷰요구사항