Skip to content

add: structured data for profile pages to improve visibility#1953

Merged
arkid15r merged 13 commits intoOWASP:mainfrom
bandhan-majumder:feature/profile-visibility
Aug 6, 2025
Merged

add: structured data for profile pages to improve visibility#1953
arkid15r merged 13 commits intoOWASP:mainfrom
bandhan-majumder:feature/profile-visibility

Conversation

@bandhan-majumder
Copy link
Contributor

@bandhan-majumder bandhan-majumder commented Aug 3, 2025

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
image

Checklist

  • I've read and followed the contributing guidelines.
  • I've run make check-test locally; all checks and tests passed.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 3, 2025

Summary by CodeRabbit

  • New Features
    • Added structured data (JSON-LD) to user profile pages, enhancing search engine visibility and rich results.
  • Bug Fixes
    • User profile data now includes the last updated timestamp.
  • Tests
    • Introduced unit tests to ensure accurate structured data generation for user profiles.
  • Documentation
    • Improved type definitions to reflect new structured data and updated user properties.

Walkthrough

This 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

Cohort / File(s) Change Summary
Profile Layout Enhancement
frontend/src/app/members/[memberKey]/layout.tsx
Refactored layout to async; fetches user data, generates structured data, and injects it via a new component.
Structured Data Script Component
frontend/src/components/StructuredDataScript.tsx
Added new React component to render JSON-LD structured data in a <script> tag.
Structured Data Type Definition
frontend/src/types/profilePageStructuredData.ts
Introduced TypeScript interface for the ProfilePage structured data schema.
Structured Data Utility Function
frontend/src/utils/structuredData.ts
Added utility to generate ProfilePage JSON-LD structured data from user details.
Unit Tests for Structured Data Utility
frontend/__tests__/unit/utils/structuredData.test.ts
Added comprehensive tests validating structured data generation for various user data scenarios.
User Query and Type Update
frontend/src/server/queries/userQueries.ts, frontend/src/types/user.ts
Extended GraphQL query and User type to include updatedAt field for last update timestamp.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
Add structured data (ProfilePage schema) to user profile pages using a <script type="application/ld+json"> block (#1767)

Assessment against linked issues: Out-of-scope changes

No 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 details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a05774f and 56da376.

📒 Files selected for processing (6)
  • frontend/__tests__/unit/utils/structuredData.test.ts (1 hunks)
  • frontend/src/app/members/[memberKey]/layout.tsx (2 hunks)
  • frontend/src/server/queries/userQueries.ts (1 hunks)
  • frontend/src/types/profilePageStructuredData.ts (1 hunks)
  • frontend/src/types/user.ts (1 hunks)
  • frontend/src/utils/structuredData.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • frontend/src/server/queries/userQueries.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • frontend/tests/unit/utils/structuredData.test.ts
  • frontend/src/types/profilePageStructuredData.ts
  • frontend/src/app/members/[memberKey]/layout.tsx
  • frontend/src/utils/structuredData.ts
⏰ 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 backend tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (1)
frontend/src/types/user.ts (1)

29-29: LGTM! Clean type extension for structured data support.

The addition of the optional updatedAt property follows the existing pattern and maintains consistency with the createdAt field by using the same generic type T. This change properly supports the ProfilePage structured data implementation.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • 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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Aug 3, 2025

@bandhan-majumder
Copy link
Contributor Author

I am working on the test

Copy link
Contributor

@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

🧹 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 sameAs property 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 knowsAbout array and hasOccupation might 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

📥 Commits

Reviewing files that changed from the base of the PR and between 3e97b15 and c6ad94b.

📒 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.

Copy link
Contributor

@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.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e6e67e and d61352f.

📒 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.

Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

Good naming and structure 👍

I like the modularization approach you used. Please look into these suggestions when you get a chance:

@bandhan-majumder
Copy link
Contributor Author

@arkid15r
added the changes & the test. ready to get merged after one more review. Please LMK if anything else is required

@sonarqubecloud
Copy link

sonarqubecloud bot commented Aug 6, 2025

Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

I changed the output structure to something that seems to be more closer to the recommended schema. Let's try this.

@arkid15r arkid15r enabled auto-merge August 6, 2025 01:54
@arkid15r arkid15r added this pull request to the merge queue Aug 6, 2025
Merged via the queue into OWASP:main with commit 4dcf9c8 Aug 6, 2025
24 checks passed
@bandhan-majumder bandhan-majumder deleted the feature/profile-visibility branch August 6, 2025 02:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add structured data to OWASP Nest profile pages

3 participants

Comments