Skip to content

feat: GEO audit fixes — SSR, structured data, crawl infra, about page - #29

Merged
holkexyz merged 2 commits into
mainfrom
staging
Apr 7, 2026
Merged

feat: GEO audit fixes — SSR, structured data, crawl infra, about page#29
holkexyz merged 2 commits into
mainfrom
staging

Conversation

@holkexyz

@holkexyz holkexyz commented Apr 7, 2026

Copy link
Copy Markdown
Member

Summary

  • Fix critical SSR bailout: split HomeClient into server-rendered LandingPage with client islands so AI crawlers see actual content instead of a blank loading spinner
  • Add JSON-LD structured data: Organization (Hypercerts Foundation + sameAs), WebSite, SoftwareApplication, and FAQPage schemas
  • Add crawl infrastructure: robots.ts, sitemap.ts, public/llms.txt
  • Add meta tags: OG/Twitter Card tags, canonical URLs, page-specific titles and descriptions for all public pages
  • Add security headers: X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy
  • Create /about page (~800 words) covering what Certified is, AT Protocol, Hypercerts Foundation, and contact info
  • Add About link to both landing and global footers

Addresses findings from the GEO audit (composite score: 20/100). No visible changes to existing pages except the About footer link.

Test plan

  • Landing page renders identically to before (no visual changes)
  • View page source on / — verify HTML contains landing content (not just a loading spinner)
  • Visit /about — verify content renders correctly
  • Visit /robots.txt — verify it returns valid robots.txt with sitemap reference
  • Visit /sitemap.xml — verify it lists all public pages
  • Visit /llms.txt — verify it returns the llms.txt file
  • Check footer on /terms — verify About link appears before Terms
  • Authenticated users still see the dashboard on / (not the landing page)

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added About page with company and product information
    • Introduced FAQ accordion section to landing page
    • Added new sign-in call-to-action component
  • Documentation & SEO

    • Enhanced metadata across all pages for improved search engine visibility and social sharing
    • Added structured data support for search engines
    • Created sitemap and crawler rules for better discoverability
  • Security

    • Applied security headers to all routes
  • Refactor

    • Reorganized landing page with modular section components

holkexyz and others added 2 commits April 7, 2026 09:14
… infra, about page

- Fix critical SSR bailout: split HomeClient into server-rendered LandingPage
  with client islands (FAQ accordion, CTA/hero sign-in buttons) so AI crawlers
  see actual content instead of a blank loading spinner
- Add JSON-LD structured data: Organization (Hypercerts Foundation with sameAs),
  WebSite, SoftwareApplication, and FAQPage schemas
- Add robots.ts, sitemap.ts, and public/llms.txt for crawler discovery
- Add OG/Twitter Card meta tags, canonical URLs, and page-specific metadata
  to all public pages (terms, privacy, dsa, about)
- Add security headers (X-Content-Type-Options, X-Frame-Options,
  Referrer-Policy, Permissions-Policy) via next.config.ts
- Create /about page (~800 words) with AT Protocol explainer, Hypercerts
  Foundation background, and social links
- Add About link to both landing and global footers
- Add hero description paragraph for AI citability

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
certified-app Ready Ready Preview, Comment Apr 7, 2026 7:30pm

Request Review

@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The pull request adds security headers to Next.js configuration, introduces multiple new pages with SEO metadata (about, privacy, terms, DSA), creates SEO routes (robots.ts, sitemap.ts), and restructures the landing page by server-rendering core content while refactoring client-side visibility logic. A new static llms.txt file and landing page components (hero sign-in button, FAQ accordion, CTA section) complete the changes.

Changes

Cohort / File(s) Summary
Security & Configuration
next.config.ts
Added HTTP response headers for security (X-Content-Type-Options, Referrer-Policy, X-Frame-Options, Permissions-Policy) applied globally via async headers hook.
Public Assets
public/llms.txt
New static markdown file with platform information, navigation links, and partner app references.
Core Metadata & Layout
src/app/layout.tsx, src/app/page.tsx
Enhanced root and homepage metadata with title templating, metadataBase, Open Graph, Twitter card configs, and inline JSON-LD schemas (Organization, Website, SoftwareApplication, FAQPage).
New Page Routes
src/app/about/page.tsx, src/app/dsa/page.tsx, src/app/privacy/page.tsx, src/app/terms/page.tsx
Added four new pages with page-specific metadata exports (title, description, canonical URLs, Open Graph fields).
SEO Metadata Routes
src/app/robots.ts, src/app/sitemap.ts
New SEO configuration files: robots.ts defines crawler rules and sitemap URL; sitemap.ts generates XML sitemap entries for all major routes with change frequency and priority.
Landing Page Restructuring
src/components/landing/home-client.tsx, src/components/landing/landing-page.tsx, src/components/landing/hero-signin-button.tsx
Refactored landing page rendering: removed lazy-loaded client components, introduced server-rendered LandingPage component, added HeroSignInButton using auth context, and added DOM visibility toggling via useEffect based on auth state.
Landing Page Sections
src/components/landing/sections/faq-accordion.tsx, src/components/landing/sections/faq-content.tsx, src/components/landing/sections/ready-cta-button.tsx, src/components/landing/sections/ready-cta-content.tsx
New landing section components: FAQ accordion with accessibility attributes (aria-expanded, aria-controls, role="region"), FAQ content with FAQ_ITEMS array, and ready CTA sections with sign-in buttons.
Footer Navigation
src/components/layout/footer.tsx
Added "About" navigation link to footer alongside existing Terms and Privacy links.

Sequence Diagram

sequenceDiagram
    actor User
    participant Browser as Client Browser
    participant Server as Next.js Server
    participant LandingPage as LandingPage<br/>(Server Component)
    participant HomeClient as HomeClient<br/>(Client Component)
    participant AuthContext as Auth Context

    User->>Browser: Load Home Page
    Browser->>Server: Request /
    Server->>LandingPage: Render LandingPage
    LandingPage->>Server: Generate HTML (with hero & sections)
    Server->>HomeClient: Initialize HomeClient
    Server-->>Browser: Return HTML with SSR landing + client component
    
    Browser->>HomeClient: Mount component
    HomeClient->>AuthContext: Call useAuth()
    AuthContext-->>HomeClient: Return { isLoading, isAuthenticated, openSignIn }
    
    alt User Not Authenticated
        HomeClient->>Browser: useEffect finds .landing-ssr
        Browser->>Browser: Set display: block (show landing)
    else User Authenticated
        HomeClient->>Browser: useEffect finds .landing-ssr
        Browser->>Browser: Set display: none (hide landing)
    end
    
    User->>Browser: Click sign-in button
    Browser->>AuthContext: Trigger openSignIn()
    AuthContext-->>Browser: Open auth modal/redirect
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 With headers held high for security's sake,
And metadata woven through every page,
The landing takes flight, server-rendered and bright,
While FAQs accordion and CTAs engage!
Robots and sitemaps map out the way—
A certified platform for a secure day! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the primary changes: SSR restructuring, structured data (JSON-LD), crawl infrastructure (robots/sitemap), and the new about page, which are the main objectives described in the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch staging

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (6)
src/components/landing/sections/ready-cta-button.tsx (1)

5-13: Consider extracting a shared sign-in button component.

ReadyCtaButton and HeroSignInButton duplicate behavior/markup; a small shared component would reduce drift.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/sections/ready-cta-button.tsx` around lines 5 - 13,
ReadyCtaButton and HeroSignInButton duplicate the same sign-in markup and
behavior; extract a reusable SignInButton component that encapsulates the
button, image and onClick behavior, then replace ReadyCtaButton and
HeroSignInButton to render this new component. Create a SignInButton functional
component that accepts props for className (or wrapperClass and imgClass), image
src/alt if needed, and a click handler (defaulting to the useAuth().openSignIn
if not provided), and update ReadyCtaButton and HeroSignInButton to import and
render SignInButton to remove duplication.
src/components/landing/home-client.tsx (2)

38-39: Hiding SSR content during loading negates the perceived performance benefit.

While hiding the server-rendered landing page during isLoading ensures correct behavior, it means users still see the loading spinner first instead of the pre-rendered content. The SSR benefit is preserved for crawlers (no JS execution), but real users experience a flash: spinner → content.

Consider showing the SSR content immediately and only hiding it when isAuthenticated becomes true:

Proposed fix
   useEffect(() => {
     const landingSsr = document.querySelector(".landing-ssr") as HTMLElement | null;
     if (!landingSsr) return;

-    if (isLoading) {
-      landingSsr.style.display = "none";
-    } else if (isAuthenticated) {
+    if (isAuthenticated) {
       landingSsr.style.display = "none";
     } else {
       landingSsr.style.display = "";
     }
   }, [isLoading, isAuthenticated]);

This lets unauthenticated users see the landing page immediately. For authenticated users, there may be a brief flash of the landing page before the dashboard renders, but that's a smaller UX cost than showing a spinner to everyone.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/home-client.tsx` around lines 38 - 39, The current
code hides the server-rendered landing content whenever isLoading is true
(landingSsr.style.display = "none"), which causes users to see a spinner instead
of the SSR content; instead, change the logic to leave the SSR content visible
by default and only hide it when isAuthenticated becomes true (i.e., move the
landingSsr.style.display = "none" into the branch that runs when isAuthenticated
=== true), keeping the spinner logic only for explicit loading states that apply
to unauthenticated flows; update any related effect or conditional that
references isLoading to avoid hiding landingSsr and ensure landingSsr is
hidden/removed only when transitioning an authenticated user to the dashboard.

53-54: Use next/image instead of <img> for the loading screen logo.

Per coding guidelines, all images should use next/image for optimization benefits.

Proposed fix
+import Image from "next/image";
...
         <div className="loading-screen__inner">
-          <img
+          <Image
             src="/assets/certified_brandmark_black.svg"
             alt=""
             className="loading-screen__logo"
+            width={48}
+            height={48}
+            priority
           />
         </div>

As per coding guidelines: "Use next/image (not <img>) for all images".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/home-client.tsx` around lines 53 - 54, The loading
screen uses a raw <img> element (src="/assets/certified_brandmark_black.svg")
which violates the guideline — replace it with Next.js' Image component: import
Image from 'next/image', remove the <img> element inside the HomeClient (or the
component rendering the loading screen) and render <Image> pointing to the same
source, add an appropriate alt, and supply either explicit width/height or use
layout/fill props so Next/Image can optimize the asset.
src/app/sitemap.ts (1)

6-15: Consider using fixed dates for lastModified on static content.

Using new Date() for the homepage and about page means lastModified changes on every request/build, which may cause search engines to re-crawl unchanged content unnecessarily. For consistency with the other entries and better cache behavior, consider using fixed dates that you update when the content actually changes.

Proposed fix
     {
       url: "https://certified.app",
-      lastModified: new Date(),
+      lastModified: new Date("2026-04-15"),
       changeFrequency: "weekly",
       priority: 1,
     },
     {
       url: "https://certified.app/about",
-      lastModified: new Date(),
+      lastModified: new Date("2026-04-15"),
       changeFrequency: "monthly",
       priority: 0.8,
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/sitemap.ts` around lines 6 - 15, The sitemap entries for
"https://certified.app" and "https://certified.app/about" currently use new
Date(), causing lastModified to change on every build; replace those dynamic
lastModified values with explicit fixed dates (e.g., ISO date strings or Date
objects created from a fixed string) in the sitemap array entries for those URLs
and update them only when the page content actually changes so crawlers and
caches behave consistently.
src/components/landing/landing-page.tsx (1)

53-53: Use next/image instead of <img> for the footer logo.

Per coding guidelines, all images should use next/image for optimization.

Proposed fix
+import Image from "next/image";
...
-            <img src="/assets/certified_wordmark_black_green.png" alt="Certified" className="landing-footer__logo-img" />
+            <Image src="/assets/certified_wordmark_black_green.png" alt="Certified" className="landing-footer__logo-img" width={120} height={24} />

As per coding guidelines: "Use next/image (not <img>) for all images".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/landing-page.tsx` at line 53, Replace the raw <img> in
the LandingPage footer with Next.js' Image component: add "import Image from
'next/image'" to the top of the landing-page.tsx, then swap the <img
src="/assets/certified_wordmark_black_green.png" alt="Certified"
className="landing-footer__logo-img" /> for an <Image> using the same src, alt
and className (or appropriate wrapper), and provide explicit width and height
(or use fill with a positioned parent) so Next's optimizer can work; update the
LandingPage/footer JSX where the element with className
"landing-footer__logo-img" is rendered.
src/components/landing/sections/faq-accordion.tsx (1)

30-30: Add aria-hidden="true" to the decorative icon.

The Plus icon is decorative since the button text already provides the accessible label. Per coding guidelines, decorative elements should have aria-hidden="true" to prevent screen readers from announcing redundant or confusing content.

♿ Proposed fix
-              <Plus className={`landing-faq-icon${isOpen ? " landing-faq-icon--open" : ""}`} />
+              <Plus className={`landing-faq-icon${isOpen ? " landing-faq-icon--open" : ""}`} aria-hidden="true" />

As per coding guidelines: "aria-hidden='true' on decorative elements".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/sections/faq-accordion.tsx` at line 30, The Plus icon
is decorative and should be hidden from assistive tech; update the Plus
component usage in the FAQ accordion (the Plus JSX element with className
`landing-faq-icon${isOpen ? " landing-faq-icon--open" : ""}`) to include the
attribute aria-hidden="true" so screen readers ignore the icon while the button
text remains the accessible label.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@next.config.ts`:
- Line 20: The global header setting { key: "X-Frame-Options", value: "DENY" }
will block the OAuth iframe callback used by src/app/oauth/callback/page.tsx;
update next.config.ts to exclude the OAuth callback route (or change to
SAMEORIGIN or use frame-ancestors) so the callback can load in an iframe: modify
the place where security headers are defined (the headers array or function that
returns headers) to conditionally omit or alter the X-Frame-Options header for
the OAuth callback path (refer to the OAuth callback route in
src/app/oauth/callback/page.tsx and the X-Frame-Options header entry) and ensure
other routes keep the stricter header.

In `@public/llms.txt`:
- Line 16: Update the text in public/llms.txt so the description hyphenates
"Open-source" (change "Open source repositories for Certified and related
projects" to "Open-source repositories for Certified and related projects");
locate the GitHub link line containing the string
"[GitHub](https://github.com/hypercerts-org): Open source repositories for
Certified and related projects" and replace it with the hyphenated version to
keep copy consistent.

In `@src/components/landing/hero-signin-button.tsx`:
- Around line 10-11: Replace the raw <img> with Next's Image component: add
"import Image from 'next/image'" at the top of the component file and swap the
<img src="/assets/sign_in_with_certified_black.svg" alt="Sign in with Certified"
className="hero__btn-signin-img" /> with an <Image> element using the same src
and alt, preserving the surrounding <button onClick={openSignIn}
className="hero__btn-signin">; provide explicit width and height (or use fill
with a positioned container) and keep the className "hero__btn-signin-img" on
the Image so styles and the openSignIn handler remain intact.

In `@src/components/landing/sections/ready-cta-button.tsx`:
- Around line 10-11: The sign-in button currently uses a plain <img> which
violates the guideline; import Image from 'next/image' at the top of
ready-cta-button.tsx, replace the <img
src="/assets/sign_in_with_certified_black.svg" ... /> with <Image
src="/assets/sign_in_with_certified_black.svg" alt="Sign in with Certified"
className="hero__btn-signin-img" .../> and supply required size props (width and
height) or use layout/fill as appropriate so Next.js can optimize it; apply the
same change in the nearly identical hero-signin-button.tsx and keep the onClick
handler openSignIn and CSS class names unchanged.

---

Nitpick comments:
In `@src/app/sitemap.ts`:
- Around line 6-15: The sitemap entries for "https://certified.app" and
"https://certified.app/about" currently use new Date(), causing lastModified to
change on every build; replace those dynamic lastModified values with explicit
fixed dates (e.g., ISO date strings or Date objects created from a fixed string)
in the sitemap array entries for those URLs and update them only when the page
content actually changes so crawlers and caches behave consistently.

In `@src/components/landing/home-client.tsx`:
- Around line 38-39: The current code hides the server-rendered landing content
whenever isLoading is true (landingSsr.style.display = "none"), which causes
users to see a spinner instead of the SSR content; instead, change the logic to
leave the SSR content visible by default and only hide it when isAuthenticated
becomes true (i.e., move the landingSsr.style.display = "none" into the branch
that runs when isAuthenticated === true), keeping the spinner logic only for
explicit loading states that apply to unauthenticated flows; update any related
effect or conditional that references isLoading to avoid hiding landingSsr and
ensure landingSsr is hidden/removed only when transitioning an authenticated
user to the dashboard.
- Around line 53-54: The loading screen uses a raw <img> element
(src="/assets/certified_brandmark_black.svg") which violates the guideline —
replace it with Next.js' Image component: import Image from 'next/image', remove
the <img> element inside the HomeClient (or the component rendering the loading
screen) and render <Image> pointing to the same source, add an appropriate alt,
and supply either explicit width/height or use layout/fill props so Next/Image
can optimize the asset.

In `@src/components/landing/landing-page.tsx`:
- Line 53: Replace the raw <img> in the LandingPage footer with Next.js' Image
component: add "import Image from 'next/image'" to the top of the
landing-page.tsx, then swap the <img
src="/assets/certified_wordmark_black_green.png" alt="Certified"
className="landing-footer__logo-img" /> for an <Image> using the same src, alt
and className (or appropriate wrapper), and provide explicit width and height
(or use fill with a positioned parent) so Next's optimizer can work; update the
LandingPage/footer JSX where the element with className
"landing-footer__logo-img" is rendered.

In `@src/components/landing/sections/faq-accordion.tsx`:
- Line 30: The Plus icon is decorative and should be hidden from assistive tech;
update the Plus component usage in the FAQ accordion (the Plus JSX element with
className `landing-faq-icon${isOpen ? " landing-faq-icon--open" : ""}`) to
include the attribute aria-hidden="true" so screen readers ignore the icon while
the button text remains the accessible label.

In `@src/components/landing/sections/ready-cta-button.tsx`:
- Around line 5-13: ReadyCtaButton and HeroSignInButton duplicate the same
sign-in markup and behavior; extract a reusable SignInButton component that
encapsulates the button, image and onClick behavior, then replace ReadyCtaButton
and HeroSignInButton to render this new component. Create a SignInButton
functional component that accepts props for className (or wrapperClass and
imgClass), image src/alt if needed, and a click handler (defaulting to the
useAuth().openSignIn if not provided), and update ReadyCtaButton and
HeroSignInButton to import and render SignInButton to remove duplication.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 13cb0579-35c8-4470-ad88-e64b41adb8fe

📥 Commits

Reviewing files that changed from the base of the PR and between 07cdd1f and f10b9dc.

📒 Files selected for processing (18)
  • next.config.ts
  • public/llms.txt
  • src/app/about/page.tsx
  • src/app/dsa/page.tsx
  • src/app/layout.tsx
  • src/app/page.tsx
  • src/app/privacy/page.tsx
  • src/app/robots.ts
  • src/app/sitemap.ts
  • src/app/terms/page.tsx
  • src/components/landing/hero-signin-button.tsx
  • src/components/landing/home-client.tsx
  • src/components/landing/landing-page.tsx
  • src/components/landing/sections/faq-accordion.tsx
  • src/components/landing/sections/faq-content.tsx
  • src/components/landing/sections/ready-cta-button.tsx
  • src/components/landing/sections/ready-cta-content.tsx
  • src/components/layout/footer.tsx

Comment thread next.config.ts
headers: [
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "X-Frame-Options", value: "DENY" },

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

X-Frame-Options: DENY will break the OAuth callback flow.

The OAuth callback page at src/app/oauth/callback/page.tsx (lines 26-32) explicitly checks if it's running inside an iframe (window.parent !== window) and uses postMessage to communicate with the parent window. Setting X-Frame-Options: DENY globally prevents any page from loading in an iframe, which will break this embedded authentication flow.

Consider one of these approaches:

  1. Exclude the OAuth callback route from the DENY header
  2. Use SAMEORIGIN instead of DENY (allows same-origin iframes)
  3. Migrate to Content-Security-Policy: frame-ancestors for more granular control
Proposed fix: Exclude OAuth callback from X-Frame-Options
  async headers() {
    return [
      {
-       source: "/(.*)",
+       source: "/((?!oauth/callback).*)",
        headers: [
          { key: "X-Content-Type-Options", value: "nosniff" },
          { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
          { key: "X-Frame-Options", value: "DENY" },
          {
            key: "Permissions-Policy",
            value: "camera=(), microphone=(), geolocation=()",
          },
        ],
      },
+     {
+       source: "/oauth/callback",
+       headers: [
+         { key: "X-Content-Type-Options", value: "nosniff" },
+         { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
+         { key: "X-Frame-Options", value: "SAMEORIGIN" },
+         {
+           key: "Permissions-Policy",
+           value: "camera=(), microphone=(), geolocation=()",
+         },
+       ],
+     },
    ];
  },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@next.config.ts` at line 20, The global header setting { key:
"X-Frame-Options", value: "DENY" } will block the OAuth iframe callback used by
src/app/oauth/callback/page.tsx; update next.config.ts to exclude the OAuth
callback route (or change to SAMEORIGIN or use frame-ancestors) so the callback
can load in an iframe: modify the place where security headers are defined (the
headers array or function that returns headers) to conditionally omit or alter
the X-Frame-Options header for the OAuth callback path (refer to the OAuth
callback route in src/app/oauth/callback/page.tsx and the X-Frame-Options header
entry) and ensure other routes keep the stricter header.

Comment thread public/llms.txt
## About

- [Hypercerts Foundation](https://hypercerts.org): Parent organization building open-source protocols for impact funding
- [GitHub](https://github.com/hypercerts-org): Open source repositories for Certified and related projects

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Hyphenate “Open-source” in this description.

Minor copy edit for consistency/readability.

Proposed fix
-- [GitHub](https://github.com/hypercerts-org): Open source repositories for Certified and related projects
+- [GitHub](https://github.com/hypercerts-org): Open-source repositories for Certified and related projects
📝 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.

Suggested change
- [GitHub](https://github.com/hypercerts-org): Open source repositories for Certified and related projects
- [GitHub](https://github.com/hypercerts-org): Open-source repositories for Certified and related projects
🧰 Tools
🪛 LanguageTool

[grammar] ~16-~16: Use a hyphen to join words.
Context: ...https://github.com/hypercerts-org): Open source repositories for Certified and re...

(QB_NEW_EN_HYPHEN)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@public/llms.txt` at line 16, Update the text in public/llms.txt so the
description hyphenates "Open-source" (change "Open source repositories for
Certified and related projects" to "Open-source repositories for Certified and
related projects"); locate the GitHub link line containing the string
"[GitHub](https://github.com/hypercerts-org): Open source repositories for
Certified and related projects" and replace it with the hyphenated version to
keep copy consistent.

Comment on lines +10 to +11
<button className="hero__btn-signin" onClick={openSignIn}>
<img src="/assets/sign_in_with_certified_black.svg" alt="Sign in with Certified" className="hero__btn-signin-img" />

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

fd -type f hero-signin-button.tsx

Repository: hypercerts-org/certified-app

Length of output: 242


🏁 Script executed:

fd hero-signin-button.tsx

Repository: hypercerts-org/certified-app

Length of output: 117


🏁 Script executed:

cat -n src/components/landing/hero-signin-button.tsx

Repository: hypercerts-org/certified-app

Length of output: 596


Replace <img> with next/image in this CTA button.

This violates the image handling requirement for TSX components. The next/image component must be used instead of the HTML <img> tag.

Proposed fix
+import Image from "next/image";
+
import { useAuth } from "@/lib/auth/auth-context";

export default function HeroSignInButton() {
  const { openSignIn } = useAuth();

  return (
    <div className="hero__actions">
-      <button className="hero__btn-signin" onClick={openSignIn}>
-        <img src="/assets/sign_in_with_certified_black.svg" alt="Sign in with Certified" className="hero__btn-signin-img" />
+      <button type="button" className="hero__btn-signin" onClick={openSignIn}>
+        <Image
+          src="/assets/sign_in_with_certified_black.svg"
+          alt="Sign in with Certified"
+          className="hero__btn-signin-img"
+          width={240}
+          height={56}
+        />
       </button>
    </div>
  );
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/hero-signin-button.tsx` around lines 10 - 11, Replace
the raw <img> with Next's Image component: add "import Image from 'next/image'"
at the top of the component file and swap the <img
src="/assets/sign_in_with_certified_black.svg" alt="Sign in with Certified"
className="hero__btn-signin-img" /> with an <Image> element using the same src
and alt, preserving the surrounding <button onClick={openSignIn}
className="hero__btn-signin">; provide explicit width and height (or use fill
with a positioned container) and keep the className "hero__btn-signin-img" on
the Image so styles and the openSignIn handler remain intact.

Comment on lines +10 to +11
<button className="hero__btn-signin" onClick={openSignIn}>
<img src="/assets/sign_in_with_certified_black.svg" alt="Sign in with Certified" className="hero__btn-signin-img" />

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check the actual file content
cat -n src/components/landing/sections/ready-cta-button.tsx | head -20

Repository: hypercerts-org/certified-app

Length of output: 601


🏁 Script executed:

# Also check the hero-signin-button.tsx for comparison
cat -n src/components/landing/hero-signin-button.tsx | head -20

Repository: hypercerts-org/certified-app

Length of output: 596


🏁 Script executed:

# Search for other uses of <img> vs next/image in the codebase to understand the pattern
rg "<img" --type tsx --type jsx -c | head -20

Repository: hypercerts-org/certified-app

Length of output: 99


🏁 Script executed:

# Check if next/image is being used anywhere in the landing components
rg "from 'next/image'" src/components/landing/ --type tsx --type jsx

Repository: hypercerts-org/certified-app

Length of output: 99


🏁 Script executed:

# Search for next/image usage in the codebase
rg "from 'next/image'|from \"next/image\"" --max-count 10

Repository: hypercerts-org/certified-app

Length of output: 375


🏁 Script executed:

# Search for <img tags to see how widespread the issue is
rg "<img" --max-count 20 -A 1

Repository: hypercerts-org/certified-app

Length of output: 4118


Use next/image instead of <img> for the sign-in button image.

Per coding guidelines: "Use next/image (not <img>) for all images". This also affects the nearly identical hero-signin-button.tsx component.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/landing/sections/ready-cta-button.tsx` around lines 10 - 11,
The sign-in button currently uses a plain <img> which violates the guideline;
import Image from 'next/image' at the top of ready-cta-button.tsx, replace the
<img src="/assets/sign_in_with_certified_black.svg" ... /> with <Image
src="/assets/sign_in_with_certified_black.svg" alt="Sign in with Certified"
className="hero__btn-signin-img" .../> and supply required size props (width and
height) or use layout/fill as appropriate so Next.js can optimize it; apply the
same change in the nearly identical hero-signin-button.tsx and keep the onClick
handler openSignIn and CSS class names unchanged.

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