Skip to content

Improvements to SEO#82

Merged
NexWasTaken merged 8 commits into
mainfrom
feat/seo-improvements
Feb 16, 2026
Merged

Improvements to SEO#82
NexWasTaken merged 8 commits into
mainfrom
feat/seo-improvements

Conversation

@NexWasTaken

@NexWasTaken NexWasTaken commented Feb 16, 2026

Copy link
Copy Markdown
Member

Closes #81
Closes #80
Closes #78

Summary by CodeRabbit

  • New Features

    • Added page descriptions site-wide for improved SEO and richer link previews.
  • Chores

    • Simplified page titles by removing redundant branding.
    • Centralized metadata generation with a new SEO helper for consistent titles, descriptions, and optional images.
    • Added SEO package, expanded spellcheck dictionary, and added .vercel to ignore rules.

@coderabbitai

coderabbitai Bot commented Feb 16, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new @workspace/seo package exposing createMetadata and replaces many plain metadata objects/generators with calls to createMetadata, standardizing titles and adding descriptions across auth, user, settings, blog, help, and legal pages.

Changes

Cohort / File(s) Summary
SEO Infrastructure
packages/seo/metadata.ts, packages/seo/package.json
Introduce new @workspace/seo package and export createMetadata(...) plus MetadataGenerator type.
App Root Layouts
apps/web/app/app/layout.tsx, apps/web/www/app/layout.tsx
Replace typed Metadata objects with createMetadata(...); remove explicit Metadata type imports.
Auth Pages
apps/web/app/app/(auth)/sign-in/[[...sign-in]]/page.tsx, apps/web/app/app/(auth)/sign-up/[[...sign-up]]/page.tsx
Swap static metadata objects for createMetadata(...), remove `
User Feature Pages
apps/web/app/app/(user)/folders/page.tsx, apps/web/app/app/(user)/folders/[id]/layout.tsx, apps/web/app/app/(user)/papers/[id]/layout.tsx, apps/web/app/app/(user)/search/page.tsx
Refactor metadata/generateMetadata to delegate to createMetadata(...); add dynamic descriptions/titles based on context.
Settings Pages
apps/web/app/app/(user)/settings/.../page.tsx
.../account/.../page.tsx, credits/page.tsx, customization/page.tsx, keys/page.tsx, webhooks/page.tsx
Replace static metadata with createMetadata(...), standardize titles and add descriptions.
Legal Pages
apps/web/www/app/(legal)/privacy/page.tsx, apps/web/www/app/(legal)/terms/page.tsx
Convert typed metadata exports to createMetadata(...), remove explicit type annotations, simplify titles while preserving descriptions.
Content Pages
apps/web/blog/app/(home)/blog/[slug]/page.tsx, apps/web/help/app/(docs)/[[...slug]]/page.tsx
Update generateMetadata to return createMetadata(...) with description fallbacks.
Workspace Linking & Packages
apps/web/app/package.json, apps/web/www/package.json
Add @workspace/seo as workspace dependency; also add motion to apps/web/www.
Spellcheck
cspell.json
Append words ("Sahil", "sahillll") to the cspell dictionary.
Misc/gitignore
apps/web/app/.gitignore
Add .vercel to .gitignore.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

enhancement

Poem

🐇 I hopped through code with nimble feet,

trimmed titles, added description sweet,
createMetadata stitched each page,
meta now shines on every stage,
A little rabbit cheers — SEO complete.

🚥 Pre-merge checks | ✅ 4 | ❌ 2

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive Two minor out-of-scope changes detected: cspell.json adds dictionary words ('Sahil', 'sahillll') unrelated to SEO, and .gitignore adds .vercel ignore rule not mentioned in issue requirements. Consider removing the cspell.json changes and .gitignore modification if they are unrelated to SEO improvements, or clarify their necessity in PR comments.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Improvements to SEO' accurately reflects the main objective of the PR, which comprehensively adds SEO metadata enhancements across multiple pages and introduces a createMetadata helper function.
Linked Issues check ✅ Passed The PR successfully addresses the core requirements: creates createMetadata helper for Open Graph and metadata management [#78], improves SEO metadata across www and app subapplications [#81], and refactors metadata declarations consistently across all pages.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/seo-improvements

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
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/app/app/(user)/search/page.tsx (1)

33-43: ⚠️ Potential issue | 🟠 Major

q is required in the schema, so the q ? ternary is unreachable in the falsy branch.

searchParamsSchema defines q: z.string() (required). If q is missing from search params, parse() on line 35 throws a ZodError before the ternary on line 38 is reached. The "Search" / "Search for research papers..." fallbacks are dead code.

If the intent is to handle pages without a query, make q optional:

Proposed fix
 const searchParamsSchema = z.object({
-  q: z.string(),
+  q: z.string().optional(),
   minimumCitations: z.coerce.number().optional(),
   openAccess: z.coerce.boolean().optional(),
   publicationTypes: csvToEnumArray(publicationTypes).optional(),
   fieldsOfStudy: csvToEnumArray(fieldsOfStudy).optional(),
 });

Note that this same issue applies to SearchPage on line 47 which also destructures q from the parse result.

🤖 Fix all issues with AI agents
In `@apps/web/app/app/`(user)/folders/[id]/layout.tsx:
- Around line 23-26: The title currently passes a pre-suffixed string to
createMetadata causing double suffixing; update the call in layout.tsx (the
createMetadata invocation) to pass only the folder name (e.g., folder.name) as
the title so createMetadata can append " | Qurious" itself, and remove the
explicit " | Folder" segment from the title/description construction to avoid
the extra segment.

In `@apps/web/app/app/`(user)/papers/[id]/layout.tsx:
- Around line 40-44: The title passed to createMetadata in layout.tsx currently
includes a hardcoded " | Paper" suffix which causes duplicate suffixing because
createMetadata already appends the application name; change the title argument
to just the page-specific name (e.g., use paper.title instead of `${paper.title}
| Paper`) and keep the description logic as-is so the final title becomes "Paper
Title | Qurious" via createMetadata; update the createMetadata call in the
layout.tsx function that uses paper.title accordingly.

In `@apps/web/app/app/layout.tsx`:
- Around line 16-19: The root layout export const metadata uses createMetadata
with title: APP_NAME which equals the application name, resulting in duplicate
"Qurious | Qurious"; fix by either passing a distinct root title (e.g., tagline)
from apps/web/app/layout.tsx and apps/web/www/app/layout.tsx, or change
createMetadata (in packages/seo/metadata.ts) to detect when the provided title
=== applicationName and avoid appending the applicationName suffix; reference
the metadata export in layout.tsx and the createMetadata function to locate and
implement the check or the alternate title.

In `@apps/web/www/app/`(legal)/terms/page.tsx:
- Around line 5-8: The metadata object created by createMetadata currently sets
a generic description for the Terms page using APP_NAME; update the description
value to be page-specific (e.g., "Terms of Service for ${APP_NAME} - Read the
rules and guidelines for using our platform.") so search engines/users see the
page intent; locate the export const metadata = createMetadata(...) in page.tsx
and replace the description template string accordingly.

In `@apps/web/www/app/layout.tsx`:
- Around line 14-17: The root layout is producing "Qurious | Qurious" because
createMetadata appends the application suffix to a title that is already
APP_NAME; update createMetadata to detect and avoid duplication by checking if
the passed title equals applicationName or already ends with ` |
${applicationName}` and only append the suffix when neither is true, or
alternatively stop passing APP_NAME from the root layouts (the export const
metadata in your layout files) so the suffix logic runs only for non-root pages;
reference createMetadata and the APP_NAME/title passed via export const
metadata.

In `@cspell.json`:
- Around line 85-87: The words list has three entries out of alphabetical order:
"samhoque", "Sahil", and "sahillll"; move these three entries into their correct
alphabetical location within the cspell words array (for example between
"retinoids" and "Segoe") so the list remains sorted and consistent; ensure
casing is preserved and avoid introducing duplicates when repositioning these
items.

In `@packages/seo/metadata.ts`:
- Around line 24-25: The metadata generator currently unconditionally appends "
| {applicationName}" (computed as parsedTitle) which causes double-appending
when callers already include the app suffix (e.g., callers that pass title =
`${folder.name} | Folder`); update the createMetadata logic in
packages/seo/metadata.ts (reference parsedTitle / createMetadata) to first
detect if the incoming title already endsWith ` | ${applicationName}` or already
contains the applicationName as a suffix and only append the app name when it's
not present (e.g., use a conditional check like title.endsWith(` |
${applicationName}`) or title.includes(applicationName) for the suffix) so
titles like "MyFolder | Folder" become "MyFolder | Folder" and titles without
the app name get " | Qurious" appended.
- Around line 57-66: When an image is provided the code only populates
metadata.openGraph.images but not the Twitter card; update the block that checks
`if (image && metadata.openGraph)` to also ensure `metadata.twitter` exists and
set its image(s) (e.g. `metadata.twitter.images` or the appropriate twitter
image field) to include `image` so the `card: "summary_large_image"` has an
explicit image; reference the existing `image`, `metadata.openGraph`,
`metadata.twitter`, and `title` symbols when making the change.
- Line 55: The current shallow merge creating const metadata: Metadata = {
...defaultMetadata, ...properties } overwrites nested objects like openGraph and
twitter; replace this with a deep merge of defaultMetadata and properties (e.g.,
call a deepMerge(defaultMetadata, properties) or use a typed utility such as
lodash.merge or a small recursive merge helper) and assign its result to
metadata so nested keys are merged rather than replaced while preserving the
Metadata type; update imports or add the helper in metadata.ts and ensure the
final value assigned to the metadata variable is the deep-merged object.
- Around line 10-13: The current type annotation const author:
Metadata["authors"] is too broad (null | Author | Author[] | undefined) and will
make author.name invalid; update the declaration of author to a narrow Author
type or let TypeScript infer a readonly literal by using no explicit
Metadata[...] annotation (or append as const) so author is an Author;
specifically change the author binding used by the code that accesses
author.name (the author constant in metadata.ts) to have type Author (or remove
the explicit type and use as const) so callers that access author.name compile
without errors.

In `@packages/seo/package.json`:
- Around line 1-16: Update the package.json to align with the monorepo and
provide a real entry point: change the dependencies.next version from "^16.1.6"
to the monorepo's "^15.5.x"; update the "main" field (or add an "exports" map)
to point to the actual entry (e.g., metadata.ts or a compiled index) instead of
"index.js"; populate "description", "author", and "keywords" with appropriate
values; and replace the placeholder "scripts.test" with either a real test
command or remove it. Ensure you update the "dependencies.next", "main" (or add
"exports"), "description", "author", "keywords", and "scripts.test" fields
accordingly.

Comment on lines +23 to +26
return createMetadata({
title: `${folder.name} | Folder`,
description: `View and manage papers and searches in the ${folder.name} folder`,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Title will render as "FolderName | Folder | Qurious" due to double suffixing.

As noted in packages/seo/metadata.ts, createMetadata appends " | Qurious" to the title. Passing \${folder.name} | Folder`here produces a three-segment title. If a two-segment title is intended, pass just the folder name and letcreateMetadata` handle the suffix:

Proposed fix
     return createMetadata({
-      title: `${folder.name} | Folder`,
+      title: folder.name,
       description: `View and manage papers and searches in the ${folder.name} folder`,
     });
📝 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
return createMetadata({
title: `${folder.name} | Folder`,
description: `View and manage papers and searches in the ${folder.name} folder`,
});
return createMetadata({
title: folder.name,
description: `View and manage papers and searches in the ${folder.name} folder`,
});
🤖 Prompt for AI Agents
In `@apps/web/app/app/`(user)/folders/[id]/layout.tsx around lines 23 - 26, The
title currently passes a pre-suffixed string to createMetadata causing double
suffixing; update the call in layout.tsx (the createMetadata invocation) to pass
only the folder name (e.g., folder.name) as the title so createMetadata can
append " | Qurious" itself, and remove the explicit " | Folder" segment from the
title/description construction to avoid the extra segment.

Comment on lines +40 to +44
return createMetadata({
title: `${paper.title} | Paper`,
description:
paper.tldr?.text || paper.abstract || "View paper details on Qurious",
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Double title suffix: paper.title | Paper | Qurious.

createMetadata already appends | ${applicationName} to the title (see packages/seo/metadata.ts Line 24). Passing "${paper.title} | Paper" here will produce a title like "My Paper Title | Paper | Qurious". Other pages in this PR pass only the page-specific name (e.g., "Folders", "Sign In").

Suggested fix
     return createMetadata({
-      title: `${paper.title} | Paper`,
+      title: paper.title,
       description:
         paper.tldr?.text || paper.abstract || "View paper details on Qurious",
     });
📝 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
return createMetadata({
title: `${paper.title} | Paper`,
description:
paper.tldr?.text || paper.abstract || "View paper details on Qurious",
});
return createMetadata({
title: paper.title,
description:
paper.tldr?.text || paper.abstract || "View paper details on Qurious",
});
🤖 Prompt for AI Agents
In `@apps/web/app/app/`(user)/papers/[id]/layout.tsx around lines 40 - 44, The
title passed to createMetadata in layout.tsx currently includes a hardcoded " |
Paper" suffix which causes duplicate suffixing because createMetadata already
appends the application name; change the title argument to just the
page-specific name (e.g., use paper.title instead of `${paper.title} | Paper`)
and keep the description logic as-is so the final title becomes "Paper Title |
Qurious" via createMetadata; update the createMetadata call in the layout.tsx
function that uses paper.title accordingly.

Comment thread apps/web/app/app/layout.tsx
Comment on lines +5 to +8
export const metadata = createMetadata({
title: "Terms of Service",
description: `Terms of Service for ${APP_NAME} - A research tool for the AI age.`,
};
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider making the Terms description more page-specific.

The Privacy page description explains what the user will learn ("how we collect, use, and protect your data"), but the Terms description falls back to a generic app tagline ("A research tool for the AI age"). A more specific description like Terms of Service for ${APP_NAME} - Read the rules and guidelines for using our platform. would better describe the page content for search engines.

✏️ Suggested description improvement
 export const metadata = createMetadata({
   title: "Terms of Service",
-  description: `Terms of Service for ${APP_NAME} - A research tool for the AI age.`,
+  description: `Terms of Service for ${APP_NAME} - Read the rules and guidelines for using our platform.`,
 });
📝 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
export const metadata = createMetadata({
title: "Terms of Service",
description: `Terms of Service for ${APP_NAME} - A research tool for the AI age.`,
};
});
export const metadata = createMetadata({
title: "Terms of Service",
description: `Terms of Service for ${APP_NAME} - Read the rules and guidelines for using our platform.`,
});
🤖 Prompt for AI Agents
In `@apps/web/www/app/`(legal)/terms/page.tsx around lines 5 - 8, The metadata
object created by createMetadata currently sets a generic description for the
Terms page using APP_NAME; update the description value to be page-specific
(e.g., "Terms of Service for ${APP_NAME} - Read the rules and guidelines for
using our platform.") so search engines/users see the page intent; locate the
export const metadata = createMetadata(...) in page.tsx and replace the
description template string accordingly.

Comment thread apps/web/www/app/layout.tsx
Comment thread packages/seo/metadata.ts
Comment on lines +10 to +13
const author: Metadata["authors"] = {
name: "Sahil Khan",
url: "https://sahilll.dev/",
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

git ls-files packages/seo/ | head -20

Repository: QuriousAI/qurious

Length of output: 111


🏁 Script executed:

cat -n packages/seo/metadata.ts

Repository: QuriousAI/qurious

Length of output: 2001


🏁 Script executed:

# Let me check the Next.js type definition for Metadata["authors"]
# First, let's see if there's any node_modules reference or type stubs
rg -t ts 'authors' packages/seo/metadata.ts -B 5 -A 5

Repository: QuriousAI/qurious

Length of output: 549


🏁 Script executed:

# Let's check what Next.js's Metadata["authors"] type actually resolves to
# First, check if there's a package.json to see the Next.js version
cat packages/seo/package.json

Repository: QuriousAI/qurious

Length of output: 360


🌐 Web query:

Next.js 16.1.6 Metadata type authors property TypeScript definition

💡 Result:

In Next.js next@16.1.6, the Metadata type defines authors as:

authors?: null | Author | Array<Author> | undefined;

[1]

And Author is defined as:

export type Author = {
  url?: string | URL | undefined;
  name?: string | undefined;
};

[2]

Example:

import type { Metadata } from "next";

export const metadata: Metadata = {
  authors: [{ name: "Seb", url: "https://example.com" }],
};

Sources: [1] [2]


🏁 Script executed:

# Let me check the TypeScript configuration and try to understand if there are any type errors
cat tsconfig.json

Repository: QuriousAI/qurious

Length of output: 106


🏁 Script executed:

# Find tsconfig.json file
fd tsconfig.json

Repository: QuriousAI/qurious

Length of output: 296


🏁 Script executed:

# Let me create a test to see if TypeScript would actually flag this as an error
# Check if there's any type checking configuration in the workspace
fd "tsconfig.json" -x head -30 {} \; | head -50

Repository: QuriousAI/qurious

Length of output: 1161


🏁 Script executed:

# Let me verify the exact type issue by simulating what TypeScript would see
# Create a test file to check if this would cause a type error
cat > /tmp/test_metadata.ts << 'EOF'
import type { Metadata } from "next";

type Author = {
  url?: string | URL | undefined;
  name?: string | undefined;
};

// Simulate Metadata["authors"] type
type MetadataAuthors = null | Author | Array<Author> | undefined;

// This is what the code does
const author: MetadataAuthors = {
  name: "Sahil Khan",
  url: "https://sahilll.dev/",
};

// This line would have a type error
const creatorName = author.name;  // Error: Property 'name' does not exist on type 'null | Author | Author[] | undefined'
EOF
cat /tmp/test_metadata.ts

Repository: QuriousAI/qurious

Length of output: 566


🏁 Script executed:

# Let me check if there are any type suppression comments or if the code has been fixed
rg "@ts-expect-error|@ts-ignore|as const" packages/seo/metadata.ts

Repository: QuriousAI/qurious

Length of output: 43


🏁 Script executed:

# Let me verify if the type system would actually catch this error
# by checking the actual repository structure and if there's any type checking happening
find . -name ".eslintrc*" -o -name "tsconfig.json" | grep -E "(root|packages/seo)" | head -5

Repository: QuriousAI/qurious

Length of output: 43


🏁 Script executed:

# Let me check if there's a root tsconfig or if packages are configured separately
cat package.json | head -30

Repository: QuriousAI/qurious

Length of output: 1132


Type annotation Metadata["authors"] is too wide for property access at line 32.

Metadata["authors"] resolves to null | Author | Array<Author> | undefined, but line 32 accesses author.name which will fail type checking against an array, null, or undefined. Narrow the type annotation to Author or use type inference with as const:

Proposed fix
-const author: Metadata["authors"] = {
+const author = {
   name: "Sahil Khan",
   url: "https://sahilll.dev/",
-};
+} as const;
📝 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
const author: Metadata["authors"] = {
name: "Sahil Khan",
url: "https://sahilll.dev/",
};
const author = {
name: "Sahil Khan",
url: "https://sahilll.dev/",
} as const;
🤖 Prompt for AI Agents
In `@packages/seo/metadata.ts` around lines 10 - 13, The current type annotation
const author: Metadata["authors"] is too broad (null | Author | Author[] |
undefined) and will make author.name invalid; update the declaration of author
to a narrow Author type or let TypeScript infer a readonly literal by using no
explicit Metadata[...] annotation (or append as const) so author is an Author;
specifically change the author binding used by the code that accesses
author.name (the author constant in metadata.ts) to have type Author (or remove
the explicit type and use as const) so callers that access author.name compile
without errors.

Comment thread packages/seo/metadata.ts
Comment on lines +24 to +25
}: MetadataGenerator): Metadata => {
const parsedTitle = `${title} | ${applicationName}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Double-appended suffix for folder pages.

createMetadata appends " | Qurious" to every title (line 25). But in apps/web/app/app/(user)/folders/[id]/layout.tsx (line 24), the caller already passes title: \${folder.name} | Folder`. The rendered title will be "MyFolder | Folder | Qurious". Similarly, the search page passes `${q} | Search`producing"query | Search | Qurious"`.

This isn't necessarily wrong, but verify this multi-segment title pattern is intentional across all call sites.

🤖 Prompt for AI Agents
In `@packages/seo/metadata.ts` around lines 24 - 25, The metadata generator
currently unconditionally appends " | {applicationName}" (computed as
parsedTitle) which causes double-appending when callers already include the app
suffix (e.g., callers that pass title = `${folder.name} | Folder`); update the
createMetadata logic in packages/seo/metadata.ts (reference parsedTitle /
createMetadata) to first detect if the incoming title already endsWith ` |
${applicationName}` or already contains the applicationName as a suffix and only
append the app name when it's not present (e.g., use a conditional check like
title.endsWith(` | ${applicationName}`) or title.includes(applicationName) for
the suffix) so titles like "MyFolder | Folder" become "MyFolder | Folder" and
titles without the app name get " | Qurious" appended.

Comment thread packages/seo/metadata.ts
},
};

const metadata: Metadata = { ...defaultMetadata, ...properties };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Shallow spread silently drops nested defaults when callers pass openGraph or twitter.

{ ...defaultMetadata, ...properties } is a shallow merge. If a consumer passes an openGraph property (e.g., to set type: "article" for a blog post), the entire default openGraph block (title, description, siteName, locale) is replaced rather than merged.

Consider a deep-merge strategy for nested objects:

Proposed fix
-  const metadata: Metadata = { ...defaultMetadata, ...properties };
+  const metadata: Metadata = {
+    ...defaultMetadata,
+    ...properties,
+    openGraph: {
+      ...defaultMetadata.openGraph,
+      ...properties.openGraph,
+    },
+    twitter: {
+      ...defaultMetadata.twitter,
+      ...properties.twitter,
+    },
+  };
📝 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
const metadata: Metadata = { ...defaultMetadata, ...properties };
const metadata: Metadata = {
...defaultMetadata,
...properties,
...(properties.openGraph && {
openGraph: {
...defaultMetadata.openGraph,
...properties.openGraph,
},
}),
...(properties.twitter && {
twitter: {
...defaultMetadata.twitter,
...properties.twitter,
},
}),
};
Suggested change
const metadata: Metadata = { ...defaultMetadata, ...properties };
const metadata: Metadata = {
...defaultMetadata,
...properties,
openGraph: {
...defaultMetadata.openGraph,
...properties.openGraph,
},
twitter: {
...defaultMetadata.twitter,
...properties.twitter,
},
};
🤖 Prompt for AI Agents
In `@packages/seo/metadata.ts` at line 55, The current shallow merge creating
const metadata: Metadata = { ...defaultMetadata, ...properties } overwrites
nested objects like openGraph and twitter; replace this with a deep merge of
defaultMetadata and properties (e.g., call a deepMerge(defaultMetadata,
properties) or use a typed utility such as lodash.merge or a small recursive
merge helper) and assign its result to metadata so nested keys are merged rather
than replaced while preserving the Metadata type; update imports or add the
helper in metadata.ts and ensure the final value assigned to the metadata
variable is the deep-merged object.

Comment thread packages/seo/metadata.ts
Comment on lines +57 to +66
if (image && metadata.openGraph) {
metadata.openGraph.images = [
{
url: image,
width: 1200,
height: 630,
alt: title,
},
];
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Twitter card image is not populated.

When image is provided, only openGraph.images is set. The twitter object uses card: "summary_large_image" but never receives an image. While many platforms fall back to OG images, explicitly setting twitter.images ensures correct rendering on X/Twitter.

Proposed fix
   if (image && metadata.openGraph) {
     metadata.openGraph.images = [
       {
         url: image,
         width: 1200,
         height: 630,
         alt: title,
       },
     ];
+    if (metadata.twitter) {
+      metadata.twitter.images = [image];
+    }
   }
📝 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
if (image && metadata.openGraph) {
metadata.openGraph.images = [
{
url: image,
width: 1200,
height: 630,
alt: title,
},
];
}
if (image && metadata.openGraph) {
metadata.openGraph.images = [
{
url: image,
width: 1200,
height: 630,
alt: title,
},
];
if (metadata.twitter) {
metadata.twitter.images = [image];
}
}
🤖 Prompt for AI Agents
In `@packages/seo/metadata.ts` around lines 57 - 66, When an image is provided the
code only populates metadata.openGraph.images but not the Twitter card; update
the block that checks `if (image && metadata.openGraph)` to also ensure
`metadata.twitter` exists and set its image(s) (e.g. `metadata.twitter.images`
or the appropriate twitter image field) to include `image` so the `card:
"summary_large_image"` has an explicit image; reference the existing `image`,
`metadata.openGraph`, `metadata.twitter`, and `title` symbols when making the
change.

Comment thread packages/seo/package.json
Comment on lines +1 to +16
{
"name": "seo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.18.2",
"dependencies": {
"next": "^16.1.6"
}
}

Copy link
Copy Markdown
Contributor

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 what version of next is used in other package.json files in the repo
rg '"next"' --type=json -n -g '!node_modules' -g '!pnpm-lock.yaml'

Repository: QuriousAI/qurious

Length of output: 600


🏁 Script executed:

# Check the actual structure of packages/seo
ls -la packages/seo/

Repository: QuriousAI/qurious

Length of output: 294


🌐 Web query:

What is the latest stable version of Next.js as of February 2026?

💡 Result:

As of February 2026, the latest stable release of Next.js is v16.1.6 (released January 27, 2026). [1], [2]

Sources: [1] [2]


Fix package.json: version mismatch and missing entry point.

This package uses Next.js v16.1.6 while all other applications in the monorepo use v15.5.x. This major version mismatch will cause duplicate next installations and potential conflicts. Align with the monorepo versions.

Additionally:

  1. "main": "index.js" — No index.js exists; only metadata.ts is present. Update main to point to the actual entry point or add an exports field.
  2. Empty description, author, keywords — Fill these in for clarity.
  3. "test" script — Remove the placeholder or add real tests.
🤖 Prompt for AI Agents
In `@packages/seo/package.json` around lines 1 - 16, Update the package.json to
align with the monorepo and provide a real entry point: change the
dependencies.next version from "^16.1.6" to the monorepo's "^15.5.x"; update the
"main" field (or add an "exports" map) to point to the actual entry (e.g.,
metadata.ts or a compiled index) instead of "index.js"; populate "description",
"author", and "keywords" with appropriate values; and replace the placeholder
"scripts.test" with either a real test command or remove it. Ensure you update
the "dependencies.next", "main" (or add "exports"), "description", "author",
"keywords", and "scripts.test" fields accordingly.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/seo/metadata.ts`:
- Line 58: Remove the stray console.log(metadata) call in metadata.ts (the debug
artifact that prints the full metadata on every render); either delete the
console.log entirely or replace it with a proper logger/debug-level statement
guarded by an environment check (e.g., only log when NODE_ENV !== 'production'
or use an existing logger) so production logs and sensitive data are not
emitted.

Comment thread packages/seo/metadata.ts Outdated

const metadata: Metadata = { ...defaultMetadata, ...properties };

console.log(metadata);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove console.log — debug artifact left in production code.

This will log the full metadata object on every page render in production, polluting server logs and potentially leaking internal configuration details.

Proposed fix
-  console.log(metadata);
-
🤖 Prompt for AI Agents
In `@packages/seo/metadata.ts` at line 58, Remove the stray console.log(metadata)
call in metadata.ts (the debug artifact that prints the full metadata on every
render); either delete the console.log entirely or replace it with a proper
logger/debug-level statement guarded by an environment check (e.g., only log
when NODE_ENV !== 'production' or use an existing logger) so production logs and
sensitive data are not emitted.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/seo/metadata.ts`:
- Around line 17-30: The metadata currently hardcodes the site origin and asset
URLs (metadataBase, the default image in createMetadata, and icons), which
breaks portability; change these to derive from a configurable base URL (e.g.,
process.env.NEXT_PUBLIC_BASE_URL) with a sensible fallback (like
'https://quriousai.xyz'), build metadataBase from that base, and compose icons
and default image using that base so assets and links adapt across environments.

Comment thread packages/seo/metadata.ts
Comment on lines +17 to +30
const metadataBase = new URL(`https://quriousai.xyz`);

export const createMetadata = ({
title,
description,
image = "https://quriousai.xyz/image.png",
...properties
}: MetadataGenerator): Metadata => {
const parsedTitle = `${title} | ${applicationName}`;
const defaultMetadata: Metadata = {
title: parsedTitle,
description,
applicationName,
icons: "https://quriousai.xyz/logo.svg",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Hardcoded base URL and asset URLs reduce portability across environments.

metadataBase, icons, and the default image are all hardcoded to quriousai.xyz. If you ever need staging/preview deployments with a different domain, these won't adapt. Consider sourcing the base URL from an environment variable (e.g., process.env.NEXT_PUBLIC_BASE_URL).

🤖 Prompt for AI Agents
In `@packages/seo/metadata.ts` around lines 17 - 30, The metadata currently
hardcodes the site origin and asset URLs (metadataBase, the default image in
createMetadata, and icons), which breaks portability; change these to derive
from a configurable base URL (e.g., process.env.NEXT_PUBLIC_BASE_URL) with a
sensible fallback (like 'https://quriousai.xyz'), build metadataBase from that
base, and compose icons and default image using that base so assets and links
adapt across environments.

@sonarqubecloud

Copy link
Copy Markdown

@NexWasTaken NexWasTaken merged commit 17c3495 into main Feb 16, 2026
2 of 3 checks passed
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.

www - Improve SEO replace old logo with new one improve seo embeds

1 participant