add: structured data for profile pages to improve visibility#1953
add: structured data for profile pages to improve visibility#1953arkid15r merged 13 commits intoOWASP:mainfrom bandhan-majumder:feature/profile-visibility
Conversation
Summary by CodeRabbit
WalkthroughThis change introduces structured data to user profile pages using the ProfilePage schema. It adds a new utility for generating structured data, a React component for injecting JSON-LD into the page, and updates the profile layout to fetch user data and include the structured data script. Supporting TypeScript types are also defined. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changesNo out-of-scope changes detected. Possibly related PRs
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: .coderabbit.yaml 📒 Files selected for processing (6)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (4)
⏰ 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). (4)
🔇 Additional comments (1)
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
|
|
I am working on the test |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
frontend/src/components/StructuredDataScript.tsx (1)
8-17: LGTM! Appropriate use of dangerouslySetInnerHTML for JSON-LD injection.The static analysis warning about XSS is understandable, but this is the standard and safe way to inject JSON-LD structured data in React. The
JSON.stringify()method automatically escapes any potentially dangerous characters, making XSS attacks through this vector highly unlikely since we're serializing structured data, not raw HTML.For additional robustness, consider adding basic input validation:
const StructuredDataScript: React.FC<StructuredDataScriptProps> = ({ data }) => { + if (!data || typeof data !== 'object') { + return null + } + return ( <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(data, null, 2), }} /> ) }frontend/src/app/members/[memberKey]/layout.tsx (1)
43-69: Good implementation with room for error handling improvements.The async data fetching and structured data generation is well implemented. The graceful fallback ensures the page still renders even if structured data generation fails.
Consider more specific error handling to avoid masking important issues:
try { const { data } = await apolloClient.query({ query: GET_USER_DATA, variables: { key: memberKey, }, }) const user = data?.user - if (!user) { - return children - } - - if (user && user.login) { + if (user?.login) { const structuredData = generateProfilePageStructuredData(user) return ( <> <StructuredDataScript data={structuredData} /> {children} </> ) } - } catch { + } catch (error) { + console.warn('Failed to generate structured data for profile:', error) + } + + return children - return children - }frontend/src/utils/structuredData.ts (2)
28-28: Ensure sameAs is properly formatted as an array.The
sameAsproperty expects an array but receives a single string value. While this might work, it's better to be explicit about the array format.- sameAs: [user.url], // GitHub profile URL + sameAs: user.url ? [user.url] : undefined, // GitHub profile URL
55-65: Consider making hardcoded values more dynamic or user-specific.The hardcoded
knowsAboutarray andhasOccupationmight not accurately represent all users. Consider making these more dynamic based on user data or removing them if not applicable.For
knowsAbout, you could:
- Use user's repositories/topics if available
- Make it conditional based on user activity
- Or keep it as default OWASP-related topics
For
hasOccupation, consider:
- Using actual occupation from user profile if available
- Making it more generic like "Community Member"
- Or making it conditional
- structuredData.mainEntity.knowsAbout = [ - 'Application Security', - 'OWASP', - 'Cybersecurity', - 'Software Security', - ] + // Only add knowsAbout if we have meaningful data + structuredData.mainEntity.knowsAbout = [ + 'OWASP', + 'Application Security', + 'Cybersecurity', + ] - structuredData.mainEntity.hasOccupation = { - '@type': 'Occupation', - name: 'OWASP Community Member', - } + structuredData.mainEntity.hasOccupation = { + '@type': 'Occupation', + name: 'Community Member', + }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/src/app/members/[memberKey]/layout.tsx(2 hunks)frontend/src/components/StructuredDataScript.tsx(1 hunks)frontend/src/types/profilePageStructuredData.ts(1 hunks)frontend/src/utils/structuredData.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: in the next.js frontend mentorship application, there are two distinct types for authentication-rela...
Learnt from: Rajgupta36
PR: OWASP/Nest#1717
File: frontend/src/app/mentorship/programs/page.tsx:14-14
Timestamp: 2025-07-13T11:34:31.823Z
Learning: In the Next.js frontend mentorship application, there are two distinct types for authentication-related data: ExtendedSession for useSession hook (containing accessToken and user.login properties) and UserRolesData for useUserRoles hook (containing currentUserRoles.roles array). The correct access pattern for GitHub username is `(session as ExtendedSession)?.user?.login`.
Applied to files:
frontend/src/app/members/[memberKey]/layout.tsx
📚 Learning: in the detailscard component (frontend/src/components/carddetailspage.tsx), there's a safety check t...
Learnt from: ahmedxgouda
PR: OWASP/Nest#1633
File: frontend/src/components/HealthMetrics.tsx:30-30
Timestamp: 2025-06-20T16:12:59.256Z
Learning: In the DetailsCard component (frontend/src/components/CardDetailsPage.tsx), there's a safety check that ensures HealthMetrics component is only rendered when healthMetricsData exists and has at least one element: `healthMetricsData && healthMetricsData.length > 0`. This makes accessing data[0] safe within the HealthMetrics component.
Applied to files:
frontend/src/app/members/[memberKey]/layout.tsx
📚 Learning: in next.js 13+ app router, userouter from 'next/navigation' does not provide aspath or query propert...
Learnt from: Rajgupta36
PR: OWASP/Nest#1717
File: frontend/src/components/ModuleCard.tsx:53-55
Timestamp: 2025-07-13T07:31:06.511Z
Learning: In Next.js 13+ app router, useRouter from 'next/navigation' does not provide asPath or query properties. Use useParams to extract route parameters and usePathname to get the current pathname instead.
Applied to files:
frontend/src/app/members/[memberKey]/layout.tsx
📚 Learning: in next.js 13+ app router, components with the 'use client' directive run entirely on the client sid...
Learnt from: Rajgupta36
PR: OWASP/Nest#1717
File: frontend/src/app/mentorship/programs/page.tsx:59-61
Timestamp: 2025-07-13T11:29:25.245Z
Learning: In Next.js 13+ app router, components with the 'use client' directive run entirely on the client side and don't require window object existence checks or SSR hydration considerations. Direct access to window.location and other browser APIs is safe in client components.
Applied to files:
frontend/src/app/members/[memberKey]/layout.tsx
🪛 Biome (2.1.2)
frontend/src/components/StructuredDataScript.tsx
[error] 12-12: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
⏰ 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). (4)
- GitHub Check: Run frontend e2e tests
- GitHub Check: Run backend tests
- GitHub Check: Run frontend unit tests
- GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (2)
frontend/src/types/profilePageStructuredData.ts (1)
1-35: Excellent schema.org compliance and type safety.The interface perfectly aligns with Google's ProfilePage structured data specification. The use of optional properties, proper @context/@type fields, and comprehensive coverage of profile-related properties demonstrates good understanding of JSON-LD and schema.org standards.
frontend/src/utils/structuredData.ts (1)
13-78: Excellent schema.org compliance and comprehensive structured data generation.The function properly implements Google's ProfilePage structured data specification with appropriate handling of optional fields and good documentation. The use of schema.org vocabulary is consistent and the overall structure follows best practices for JSON-LD.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
frontend/src/components/StructuredDataScript.tsx(1 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
frontend/src/components/StructuredDataScript.tsx
[error] 13-13: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
⏰ 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). (5)
- GitHub Check: Run frontend unit tests
- GitHub Check: Run frontend e2e tests
- GitHub Check: Run backend tests
- GitHub Check: CodeQL (python)
- GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (2)
frontend/src/components/StructuredDataScript.tsx (2)
1-6: LGTM!Clean imports and well-defined interface. The component props are properly typed.
20-20: LGTM!Standard default export follows React component conventions.
arkid15r
left a comment
There was a problem hiding this comment.
Good naming and structure 👍
I like the modularization approach you used. Please look into these suggestions when you get a chance:
|
@arkid15r |
|
arkid15r
left a comment
There was a problem hiding this comment.
I changed the output structure to something that seems to be more closer to the recommended schema. Let's try this.



Proposed change
improving the visibility of user profile pages in search engine results by adding structured data using the JSON-LD format suggested for profile page by google in a script along with children
Resolves #1767

Checklist
make check-testlocally; all checks and tests passed.