Skip to content

Adding Updates Section, fixing documentation error.#705

Open
JMeng1 wants to merge 7 commits intomasterfrom
feature/updates
Open

Adding Updates Section, fixing documentation error.#705
JMeng1 wants to merge 7 commits intomasterfrom
feature/updates

Conversation

@JMeng1
Copy link
Collaborator

@JMeng1 JMeng1 commented Nov 16, 2025

Summary by CodeRabbit

  • New Features

    • Added a dedicated Updates section with an index and individual release pages, plus an Updates link in the site header.
    • Added a newsletter popup to the site to collect subscriptions.
  • Documentation

    • Expanded the Web Analytics Goals guide with goal types, page/path & event goal examples, conversion value types (LTV/advertising ROI), funnels, time-to-conversion ranges, performance metrics, and a "Goals Alerts (Coming Soon)" note.
    • Multiple new release-note pages (v1.0.0–v2.0.0) published.
  • Content

    • Blog post metadata updated (bounce-rate: date & tags); removed bounce-rate from one docs index.

@vercel
Copy link

vercel bot commented Nov 16, 2025

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

Project Deployment Preview Comments Updated (UTC)
rybbit Error Error Nov 18, 2025 10:15pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 16, 2025

Walkthrough

Adds an Updates section (metadata, release pages, list and dynamic post pages, layout, data source), extends docs with a reorganized Goals Tab article, adds newsletter UI and subscribe API, updates header nav with an Updates link, and adjusts blog/meta and package deps.

Changes

Cohort / File(s) Summary
Goals Tab Documentation
docs/content/docs/web-analytics/goals-tab.mdx
Reworked content: removed image placeholders, added top banner, introduced Goal Type/Target fields, Page Path and Event Goals with examples, reorganized Viewing Goal Performance, Goals by Traffic Source/Device, Conversion value types, Multiple Goals (funnel stages), Time to Conversion, Goals vs Funnels, Using Goals Effectively, and Goals Alerts note.
Updates metadata & pages
docs/content/updates/meta.js, docs/content/updates/*.mdx
New metadata registry (meta.js) and eleven new release-note pages (v1.0.0.mdxv2.0.0.mdx) with frontmatter and release content.
Docs source config
docs/source.config.ts
Added updates export via defineDocs for dir content/updates with extended frontmatter schema (date, author, image, tags).
Updates UI pages
docs/src/app/updates/page.tsx, docs/src/app/updates/[...slug]/page.tsx, docs/src/app/updates/layout.tsx
New Updates list page (sorted cards), dynamic update post page (generateStaticParams, generateMetadata, UpdatePostPage with JSON‑LD and MDX rendering), and Updates layout wrapping header/footer.
Updates data source
docs/src/lib/updates-source.ts
New updatesSource export wired to loader with baseUrl: "/updates" and source: updates.toFumadocsSource?.() ?? updates.
Header navigation
docs/src/components/CustomHeader.tsx
Added "Updates" link to desktop and mobile nav (mobile closes menu on click); minor newline removal.
Blog metadata and post
docs/content/blog/_meta.js, docs/content/blog/bounce-rate.mdx, docs/content/docs/product-analytics/meta.json
Added bounce-rate entry to blog meta; added date/tags to bounce-rate post; removed bounce-rate from product-analytics meta pages array.
Newsletter UI & API
docs/src/components/NewsletterPopup.tsx, docs/src/app/api/subscribe/route.ts, docs/src/app/layout.tsx
New NewsletterPopup client component (cookie-based modal, posts to /api/subscribe), new API route handling POST subscriptions with Zod validation, rate-limiting, Resend integration, and newsletter popup mounted in root layout.
Docs package deps
docs/package.json
Added resend dependency (^6.4.2).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UpdatesList as UpdatesListPage (/updates)
    participant UpdatePage as UpdatePostPage (/updates/{slug})
    participant UpdatesSource
    participant MDXRenderer

    User->>UpdatesList: GET /updates
    UpdatesList->>UpdatesSource: getPages()
    UpdatesSource-->>UpdatesList: pages list
    UpdatesList->>UpdatesList: sort by date
    UpdatesList-->>User: render cards grid

    User->>UpdatePage: GET /updates/{slug}
    UpdatePage->>UpdatesSource: getPage(slug)
    UpdatesSource-->>UpdatePage: page data + MDX
    UpdatePage->>UpdatePage: generateMetadata() & structuredData
    UpdatePage->>MDXRenderer: render MDX with custom components
    MDXRenderer-->>UpdatePage: HTML content
    UpdatePage-->>User: full update post
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay extra attention to:
    • docs/src/app/updates/[...slug]/page.tsx — SEO/JSON‑LD correctness, notFound behavior, MDX renderers.
    • docs/src/app/api/subscribe/route.ts — rate-limiting logic and Resend error handling.
    • docs/source.config.ts and docs/src/lib/updates-source.ts — ensure new updates docs integration matches existing doc generation.

Possibly related PRs

Poem

🐰 I hopped through changelogs, nibbling notes anew,
Paths and events for goals, tidy updates in view,
A popup for mail, and a route for subscribe,
Pages that list and that render — the docs come alive! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title refers to multiple distinct changes: adding an Updates section (a substantial feature spanning many files) and fixing a documentation error (unclear what error). The title is overly broad and does not clarify the primary change. Clarify the title to focus on the primary change or use a more specific phrasing like 'Add Updates section with release notes pages' if the Updates section is primary.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/updates

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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.

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: 6

🧹 Nitpick comments (3)
docs/content/docs/web-analytics/goals-tab.mdx (1)

8-11: Rephrase to avoid successive sentences beginning with "Did".

The static analysis tool flagged a style concern: three successive sentences begin with "Did". Consider rephrasing one or more to improve readability.

 ![Rybbit Goals Dashboard](/blog/rybbit_goals_dashboard.png)
 
-Goals let you track specific outcomes you care about. Did users sign up? Did they complete checkout? Did they view key pages? The Goals tab helps you measure success.
+Goals let you track specific outcomes you care about—such as user signups, checkout completions, and key page views. The Goals tab helps you measure success.
docs/content/updates/v1.4.0.mdx (1)

9-9: Refine the note’s wording for a more neutral, clear tone

The note is understandable but a bit informal and first‑person. A small rephrase improves clarity:

-**Note**: You may have to run `git stash` before running the `./update` script since I made some changes to it.
+**Note**: You may need to run `git stash` before running the `./update` script because of recent changes to it.

This keeps the meaning while using a more neutral voice.

docs/source.config.ts (1)

31-42: Updates collection schema looks good; consider DRYing shared frontmatter

The updates collection definition mirrors the blog collection schema and looks correct for your frontmatter needs.

Since the date/author/image/tags extension is duplicated, consider extracting it into a shared constant (e.g., const datedFrontmatterSchema = frontmatterSchema.extend({ … })) and reusing it for both blog and updates to keep schemas in sync more easily.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db3d6ef and eedbaf6.

⛔ Files ignored due to path filters (2)
  • docs/package-lock.json is excluded by !**/package-lock.json
  • docs/public/blog/rybbit_goals_dashboard.png is excluded by !**/*.png
📒 Files selected for processing (19)
  • docs/content/docs/web-analytics/goals-tab.mdx (1 hunks)
  • docs/content/updates/meta.js (1 hunks)
  • docs/content/updates/v.1.4.1.mdx (1 hunks)
  • docs/content/updates/v1.0.0.mdx (1 hunks)
  • docs/content/updates/v1.1.0.mdx (1 hunks)
  • docs/content/updates/v1.2.0.mdx (1 hunks)
  • docs/content/updates/v1.3.0.mdx (1 hunks)
  • docs/content/updates/v1.4.0.mdx (1 hunks)
  • docs/content/updates/v1.5.0.mdx (1 hunks)
  • docs/content/updates/v1.5.1.mdx (1 hunks)
  • docs/content/updates/v1.6.0.mdx (1 hunks)
  • docs/content/updates/v1.6.1.mdx (1 hunks)
  • docs/content/updates/v2.0.0.mdx (1 hunks)
  • docs/source.config.ts (1 hunks)
  • docs/src/app/updates/[...slug]/page.tsx (1 hunks)
  • docs/src/app/updates/layout.tsx (1 hunks)
  • docs/src/app/updates/page.tsx (1 hunks)
  • docs/src/components/CustomHeader.tsx (1 hunks)
  • docs/src/lib/updates-source.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
docs/src/app/updates/page.tsx (1)
docs/src/lib/updates-source.ts (1)
  • updatesSource (4-7)
docs/src/app/updates/[...slug]/page.tsx (1)
docs/src/lib/updates-source.ts (1)
  • updatesSource (4-7)
docs/src/lib/updates-source.ts (1)
docs/source.config.ts (1)
  • updates (32-42)
docs/src/app/updates/layout.tsx (1)
docs/src/components/CustomHeader.tsx (1)
  • CustomHeader (10-174)
🪛 ast-grep (0.39.9)
docs/src/app/updates/[...slug]/page.tsx

[warning] 102-102: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)
docs/src/app/updates/[...slug]/page.tsx

[error] 103-103: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🪛 LanguageTool
docs/content/updates/v1.4.0.mdx

[style] ~9-~9: Consider rephrasing this to strengthen your wording.
Context: ...e running the ./update script since I made some changes to it. ## Key Features ### Session Re...

(MAKE_CHANGES)

docs/content/docs/web-analytics/goals-tab.mdx

[style] ~10-~10: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...rs sign up? Did they complete checkout? Did they view key pages? The Goals tab help...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

docs/content/updates/v2.0.0.mdx

[grammar] ~13-~13: Use a hyphen to join words.
Context: ...h the Globe page. There isn't a straight up 1-to-1 replacement of the Realtime pa...

(QB_NEW_EN_HYPHEN)


[style] ~15-~15: To strengthen your wording, consider replacing the phrasal verb “leave out”.
Context: ...dded a 3D mode using Mapbox, but I have left this feature out of the open source release because Mapbox ...

(OMIT_EXCLUDE)


[grammar] ~15-~15: Use a hyphen to join words.
Context: ...I have left this feature out of the open source release because Mapbox requires a...

(QB_NEW_EN_HYPHEN)

⏰ 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). (2)
  • GitHub Check: Build Client Images (ubuntu-latest, linux/amd64)
  • GitHub Check: Build Client Images (ubuntu-24.04-arm, linux/arm64)
🔇 Additional comments (13)
docs/content/docs/web-analytics/goals-tab.mdx (2)

28-40: LGTM!

The Page Path Goals section is well-structured with clear examples and practical wildcard patterns that will help users configure paths correctly.


54-78: LGTM!

The Viewing Goal Performance and Conversion Funnel Analysis sections provide clear value. The explanations of conversion paths, drop-offs, and time-to-conversion are practical and actionable.

docs/content/updates/v1.3.0.mdx (1)

1-15: LGTM!

Release notes are well-formatted, concise, and include a link to the full changelog for users wanting detailed information.

docs/content/updates/v1.5.1.mdx (1)

1-9: LGTM!

Release notes format is consistent. The minimal content is appropriate for a minor bug-fix release.

docs/content/updates/v1.6.1.mdx (1)

1-9: LGTM!

Release notes follow the established format and date progression.

docs/src/components/CustomHeader.tsx (1)

1-174: LGTM!

No functional changes; trailing newline formatting only.

docs/content/updates/v1.1.0.mdx (1)

1-32: LGTM!

Comprehensive release notes with clear feature descriptions, proper contributor attribution, and a full changelog link. The structure sets a good example for detailed release documentation.

docs/content/updates/v1.6.0.mdx (1)

1-46: LGTM!

Detailed release notes with comprehensive commit history, proper contributor attribution, and new contributor recognition. The format is consistent and thorough.

docs/src/lib/updates-source.ts (1)

1-7: Updates source wiring looks correct

Loader configuration and the toFumadocsSource?.() ?? updates fallback pattern look appropriate for fumadocs and align with the defined updates collection.

docs/src/app/updates/layout.tsx (1)

1-15: Updates layout composition looks consistent and type-safe

The layout cleanly composes CustomHeader, a <main> wrapper for children, and Footer, with correct ReactNode typing. Assuming the outer app layout provides a flex container, the flex-1 min-h-screen main styling should work as intended.

docs/content/updates/v1.2.0.mdx (1)

1-30: LGTM!

The release notes are well-structured with proper frontmatter, detailed changelog entries with contributor attribution, and links to relevant PRs. The date format follows the ISO standard.

docs/content/updates/v2.0.0.mdx (1)

1-58: LGTM!

The v2.0.0 release notes provide comprehensive coverage of major changes including Map/Globe rework, Journeys redesign, and script configuration updates. The breaking change is clearly documented with migration guidance.

docs/src/app/updates/[...slug]/page.tsx (1)

100-104: The dangerouslySetInnerHTML usage is safe here.

Static analysis flagged this line, but the structured data is constructed from known page data (title, description, author, tags) sourced from MDX frontmatter, not user input. This is a standard pattern for injecting JSON-LD structured data for SEO.

Comment on lines +8 to +59
"date": "2025-10-24"
},
"v1.6.1": {
"title": "v1.6.1",
"description": "Minor bug fixes and improvements",
"date": "2025-10"
},
"v1.6.0": {
"title": "v1.6.0",
"description": "Added tracking outbound links, IP exclusion, custom error tracking, and UI improvements",
"date": "2025-09"
},
"v1.5.1": {
"title": "v1.5.1",
"description": "Minor bug fixes and improvements",
"date": "2025-08"
},
"v1.5.0": {
"title": "v1.5.0",
"description": "Added organization members support, multiple organizations, session replay improvements, and bug fixes",
"date": "2025-07"
},
"v1.4.1": {
"title": "v1.4.1",
"description": "Minor bug fixes and improvements",
"date": "2025-07"
},
"v1.4.0": {
"title": "v1.4.0",
"description": "Major update introducing Session Replay and Error Tracking features",
"date": "2025-06-29"
},
"v1.3.0": {
"title": "v1.3.0",
"description": "Added API keys for tracking events and pageviews, with localhost tracking support",
"date": "2025-06"
},
"v1.2.0": {
"title": "v1.2.0",
"description": "Added more integrations, API improvements, and blog support",
"date": "2025-05"
},
"v1.1.0": {
"title": "v1.1.0",
"description": "Added data attribute event tracking, opt-out extension support, and subdomain tracking",
"date": "2025-04"
},
"v1.0.0": {
"title": "v1.0.0",
"description": "First major release with Browser/OS version filtering and breaking changes for reverse proxy configs",
"date": "2025-03"
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Standardize date formats across all version entries.

The date formats are inconsistent—some entries use full ISO dates (e.g., "2025-10-24", "2025-06-29") while others use partial year-month formats (e.g., "2025-10", "2025-09"). Additionally, v1.2.0 has "2025-05" here but "2025-05-01" in the corresponding MDX file.

Standardize all dates to full ISO format (YYYY-MM-DD) for consistency and reliable date parsing.

Apply this diff to standardize the date formats:

     "v1.6.1": {
       "title": "v1.6.1",
       "description": "Minor bug fixes and improvements",
-      "date": "2025-10"
+      "date": "2025-10-01"
     },
     "v1.6.0": {
       "title": "v1.6.0",
       "description": "Added tracking outbound links, IP exclusion, custom error tracking, and UI improvements",
-      "date": "2025-09"
+      "date": "2025-09-01"
     },
     "v1.5.1": {
       "title": "v1.5.1",
       "description": "Minor bug fixes and improvements",
-      "date": "2025-08"
+      "date": "2025-08-01"
     },
     "v1.5.0": {
       "title": "v1.5.0",
       "description": "Added organization members support, multiple organizations, session replay improvements, and bug fixes",
-      "date": "2025-07"
+      "date": "2025-07-01"
     },
     "v1.4.1": {
       "title": "v1.4.1",
       "description": "Minor bug fixes and improvements",
-      "date": "2025-07"
+      "date": "2025-07-01"
     },
     "v1.3.0": {
       "title": "v1.3.0",
       "description": "Added API keys for tracking events and pageviews, with localhost tracking support",
-      "date": "2025-06"
+      "date": "2025-06-01"
     },
     "v1.2.0": {
       "title": "v1.2.0",
       "description": "Added more integrations, API improvements, and blog support",
-      "date": "2025-05"
+      "date": "2025-05-01"
     },
     "v1.1.0": {
       "title": "v1.1.0",
       "description": "Added data attribute event tracking, opt-out extension support, and subdomain tracking",
-      "date": "2025-04"
+      "date": "2025-04-01"
     },
     "v1.0.0": {
       "title": "v1.0.0",
       "description": "First major release with Browser/OS version filtering and breaking changes for reverse proxy configs",
-      "date": "2025-03"
+      "date": "2025-03-01"
     }
📝 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
"date": "2025-10-24"
},
"v1.6.1": {
"title": "v1.6.1",
"description": "Minor bug fixes and improvements",
"date": "2025-10"
},
"v1.6.0": {
"title": "v1.6.0",
"description": "Added tracking outbound links, IP exclusion, custom error tracking, and UI improvements",
"date": "2025-09"
},
"v1.5.1": {
"title": "v1.5.1",
"description": "Minor bug fixes and improvements",
"date": "2025-08"
},
"v1.5.0": {
"title": "v1.5.0",
"description": "Added organization members support, multiple organizations, session replay improvements, and bug fixes",
"date": "2025-07"
},
"v1.4.1": {
"title": "v1.4.1",
"description": "Minor bug fixes and improvements",
"date": "2025-07"
},
"v1.4.0": {
"title": "v1.4.0",
"description": "Major update introducing Session Replay and Error Tracking features",
"date": "2025-06-29"
},
"v1.3.0": {
"title": "v1.3.0",
"description": "Added API keys for tracking events and pageviews, with localhost tracking support",
"date": "2025-06"
},
"v1.2.0": {
"title": "v1.2.0",
"description": "Added more integrations, API improvements, and blog support",
"date": "2025-05"
},
"v1.1.0": {
"title": "v1.1.0",
"description": "Added data attribute event tracking, opt-out extension support, and subdomain tracking",
"date": "2025-04"
},
"v1.0.0": {
"title": "v1.0.0",
"description": "First major release with Browser/OS version filtering and breaking changes for reverse proxy configs",
"date": "2025-03"
}
"date": "2025-10-24"
},
"v1.6.1": {
"title": "v1.6.1",
"description": "Minor bug fixes and improvements",
"date": "2025-10-01"
},
"v1.6.0": {
"title": "v1.6.0",
"description": "Added tracking outbound links, IP exclusion, custom error tracking, and UI improvements",
"date": "2025-09-01"
},
"v1.5.1": {
"title": "v1.5.1",
"description": "Minor bug fixes and improvements",
"date": "2025-08-01"
},
"v1.5.0": {
"title": "v1.5.0",
"description": "Added organization members support, multiple organizations, session replay improvements, and bug fixes",
"date": "2025-07-01"
},
"v1.4.1": {
"title": "v1.4.1",
"description": "Minor bug fixes and improvements",
"date": "2025-07-01"
},
"v1.4.0": {
"title": "v1.4.0",
"description": "Major update introducing Session Replay and Error Tracking features",
"date": "2025-06-29"
},
"v1.3.0": {
"title": "v1.3.0",
"description": "Added API keys for tracking events and pageviews, with localhost tracking support",
"date": "2025-06-01"
},
"v1.2.0": {
"title": "v1.2.0",
"description": "Added more integrations, API improvements, and blog support",
"date": "2025-05-01"
},
"v1.1.0": {
"title": "v1.1.0",
"description": "Added data attribute event tracking, opt-out extension support, and subdomain tracking",
"date": "2025-04-01"
},
"v1.0.0": {
"title": "v1.0.0",
"description": "First major release with Browser/OS version filtering and breaking changes for reverse proxy configs",
"date": "2025-03-01"
}
🤖 Prompt for AI Agents
In docs/content/updates/meta.js around lines 8 to 59, several version entries
use partial year-month dates; update every "date" value to full ISO YYYY-MM-DD
format for consistency (keep existing full dates as-is), setting the day to
"-01" for entries that only specify year-month (e.g., change "2025-10" →
"2025-10-01", "2025-09" → "2025-09-01", etc.), and ensure v1.2.0 matches its MDX
file by using "2025-05-01".

Comment on lines +1 to +9
---
title: "v1.4.1"
description: "Minor bug fixes and improvements"
date: "2025-07-01"
---

# v1.4.1

Minor release with bug fixes and improvements. No newline at end of file
Copy link
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

Rename file to follow naming convention.

The filename v.1.4.1.mdx deviates from the established pattern used by all other release notes (e.g., v1.3.0.mdx, v1.5.1.mdx, v1.6.1.mdx). This inconsistency may cause routing or discovery issues in the docs system.

Rename the file to v1.4.1.mdx to match the convention.


I'll verify the naming convention claim by checking the actual release note files in the repository.


---

🏁 Script executed:

```shell
#!/bin/bash
# List all markdown/mdx files in the docs/content/updates directory
fd -e mdx -e md . docs/content/updates 2>/dev/null | sort

Length of output: 352


Rename file to follow naming convention.

The filename v.1.4.1.mdx is indeed the only release note that deviates from the established pattern. All 10 other release notes (v1.0.0.mdx through v2.0.0.mdx) follow the vX.Y.Z.mdx format without a dot after "v".

Rename docs/content/updates/v.1.4.1.mdx to docs/content/updates/v1.4.1.mdx to match the convention.

🤖 Prompt for AI Agents
In docs/content/updates/v.1.4.1.mdx around lines 1 to 9, the filename includes
an extra dot after the "v" and breaks the established release-note naming
convention; rename the file from v.1.4.1.mdx to v1.4.1.mdx and update any
references (imports, links, navigation, or frontmatter indexes) in the repo to
use the new path docs/content/updates/v1.4.1.mdx so tooling and listings
continue to work.

Comment on lines +11 to +21
There are breaking changes if you used a custom reverse proxy to host Rybbit - We have removed the `/api` rewrite and you will need to modify your reverse proxy config

## Key Features

### Browser Versions

Filter analytics data by specific browser versions to understand user distribution across different browser releases.

### Operation System Versions

Filter analytics data by operating system versions to gain insights into your user's platform preferences.
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typos and lightly polish wording in this update

A few small language issues are worth correcting for clarity and polish:

  • Line 19: Operation System VersionsOperating System Versions.
  • Line 21: your user's platform preferencesyour users' platform preferences.
  • Line 11: Consider splitting into two sentences and avoiding the dash + capital “We”.

Example patch:

-There are breaking changes if you used a custom reverse proxy to host Rybbit - We have removed the `/api` rewrite and you will need to modify your reverse proxy config
+There are breaking changes if you use a custom reverse proxy to host Rybbit. We have removed the `/api` rewrite, so you will need to update your reverse proxy configuration.
-### Operation System Versions
+### Operating System Versions
-Filter analytics data by operating system versions to gain insights into your user's platform preferences.
+Filter analytics data by operating system versions to gain insights into your users' platform preferences.

Also consider expanding the truncated word in the line ending with subscri… to the full term for readability.

Also applies to: 19-21, 32-32

🤖 Prompt for AI Agents
In docs/content/updates/v1.0.0.mdx around lines 11 to 21 (also apply same fixes
to lines 19-21 and 32), split the long sentence that starts at line 11 into two
sentences and remove the dash + capital “We” (e.g., end the first sentence
before the clause about modifying reverse proxy config and start a new sentence
with a lowercase “we” or rephrase), correct the typo “Operation System Versions”
to “Operating System Versions” on line 19, change “your user's platform
preferences” to the plural possessive “your users' platform preferences” on line
21, and expand the truncated word ending with “subscri…” to the full term (e.g.,
“subscription”) wherever it appears.


## Commit Log

- Fix `update.sh` "Please commit your changes or stash them before you merge. by [@Mr-Technician](https://github.com/Mr-Technician) in [#438](https://github.com/rybbit-io/rybbit/pull/438)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Close the quoted message in the first commit log entry

The first commit log line has an opening quote with no closing quote:

- Fix `update.sh` "Please commit your changes or stash them before you merge. ...

Consider:

-- Fix `update.sh` "Please commit your changes or stash them before you merge. by [@Mr-Technician](https://github.com/Mr-Technician) in [#438](https://github.com/rybbit-io/rybbit/pull/438)
+- Fix `update.sh` "Please commit your changes or stash them before you merge." by [@Mr-Technician](https://github.com/Mr-Technician) in [#438](https://github.com/rybbit-io/rybbit/pull/438)
🤖 Prompt for AI Agents
In docs/content/updates/v1.5.0.mdx around line 18, the first commit log entry
contains an unmatched double-quote after `update.sh` which leaves the quoted
message open; fix it by adding the missing closing quote so the commit line
reads with balanced quotation marks and correct punctuation (ensure the
backticked filename and the quoted message are both properly closed and the
attribution remains unchanged).

Comment on lines +87 to +94
publisher: {
"@type": "Organization",
name: "Rybbit",
logo: {
"@type": "ImageObject",
url: "https://rybbit.com/public/rybbit.svg",
},
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix logo URL domain inconsistency.

The structured data uses https://rybbit.com/public/rybbit.svg while other URLs in this file (line 22) use rybbit.io. Ensure the logo URL uses the correct primary domain.

Apply this diff to fix the domain:

     publisher: {
       "@type": "Organization",
       name: "Rybbit",
       logo: {
         "@type": "ImageObject",
-        url: "https://rybbit.com/public/rybbit.svg",
+        url: "https://rybbit.io/rybbit.svg",
       },
     },
📝 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
publisher: {
"@type": "Organization",
name: "Rybbit",
logo: {
"@type": "ImageObject",
url: "https://rybbit.com/public/rybbit.svg",
},
},
publisher: {
"@type": "Organization",
name: "Rybbit",
logo: {
"@type": "ImageObject",
url: "https://rybbit.io/rybbit.svg",
},
},
🤖 Prompt for AI Agents
In docs/src/app/updates/[...slug]/page.tsx around lines 87 to 94, the
publisher.logo.url uses the wrong domain (rybbit.com) while other links use
rybbit.io; update the logo URL to the primary domain by changing it to
https://rybbit.io/public/rybbit.svg so it matches the rest of the file.

Comment on lines +34 to +40
{post.data.image && (
<img
src={post.data.image}
alt={post.data.title}
className="w-full h-48 object-cover rounded-lg mb-4"
/>
)}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use Next.js Image component for optimization.

The native img tag bypasses Next.js automatic image optimization. Use the Image component from next/image (already imported on line 4 of the slug page) for better performance, automatic format conversion, and responsive sizing.

Apply this diff:

+import Image from "next/image";

 // ... inside the map function
                 {post.data.image && (
-                  <img
+                  <Image
                     src={post.data.image}
                     alt={post.data.title}
+                    width={800}
+                    height={400}
                     className="w-full h-48 object-cover rounded-lg mb-4"
                   />
                 )}
📝 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
{post.data.image && (
<img
src={post.data.image}
alt={post.data.title}
className="w-full h-48 object-cover rounded-lg mb-4"
/>
)}
import Image from "next/image";
// ... other code ...
{post.data.image && (
<Image
src={post.data.image}
alt={post.data.title}
width={800}
height={400}
className="w-full h-48 object-cover rounded-lg mb-4"
/>
)}
🤖 Prompt for AI Agents
In docs/src/app/updates/page.tsx around lines 34-40, the native <img> is used
which bypasses Next.js image optimization; replace it with the next/image Image
component: add or ensure "import Image from 'next/image'" at the top of the
file, swap the <img> tag for <Image src={post.data.image} alt={post.data.title}
/> and provide sizing (either width/height props or use fill with a positioned
container) and keep the existing Tailwind classes (object-cover, rounded-lg,
mb-4) applied appropriately so automatic optimization and responsive behavior
are enabled.

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: 0

♻️ Duplicate comments (1)
docs/src/app/updates/page.tsx (1)

34-40: Use Next.js Image component for optimization.

This issue has already been flagged in a previous review. The native <img> tag bypasses Next.js automatic image optimization. Replace it with the Image component from next/image for better performance, automatic format conversion, and responsive sizing.

🧹 Nitpick comments (1)
docs/src/app/updates/page.tsx (1)

11-11: Consider simplifying the array handling.

The spread operator creates a copy before sorting, which is fine, but you could simplify by directly assigning the result of updatesSource.getPages().sort(...) to sortedPosts without the intermediate posts variable.

Apply this diff to streamline the logic:

-  const posts = [...updatesSource.getPages()];
-
-  // Sort posts by date (newest first)
-  const sortedPosts = posts.sort((a, b) => {
+  // Sort posts by date (newest first)
+  const sortedPosts = updatesSource.getPages().sort((a, b) => {
     const dateA = new Date(a.data.date || 0);
     const dateB = new Date(b.data.date || 0);
     return dateB.getTime() - dateA.getTime();
   });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eedbaf6 and a73ad7c.

📒 Files selected for processing (2)
  • docs/src/app/updates/page.tsx (1 hunks)
  • docs/src/components/CustomHeader.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/src/components/CustomHeader.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
docs/src/app/updates/page.tsx (1)
docs/src/lib/updates-source.ts (1)
  • updatesSource (4-7)
⏰ 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). (2)
  • GitHub Check: Build Client Images (ubuntu-latest, linux/amd64)
  • GitHub Check: Build Client Images (ubuntu-24.04-arm, linux/arm64)
🔇 Additional comments (4)
docs/src/app/updates/page.tsx (4)

1-8: LGTM! Clean imports and metadata setup.

The imports are appropriate for a Next.js page component, and the metadata export follows Next.js conventions correctly.


29-29: Good defensive date handling and semantic markup.

The date handling properly checks for null and uses the semantic <time> element with the dateTime attribute, which is excellent for accessibility and SEO. The date formatting is also clear and localized.

Also applies to: 50-58


20-85: Well-structured component with good UX considerations.

The component has a clean, responsive layout with proper dark mode support. The conditional rendering of optional fields (description, author, tags) is handled correctly, and the empty state provides helpful feedback to users. The use of semantic HTML elements (article, time) enhances accessibility.


14-18: No action required. The sorting behavior is correct and intentional.

The code includes an explicit inline comment ("Sort posts by date (newest first)") that documents the design choice. The fallback to 0 intentionally places undated posts at the end of the list (as the epoch date is the "oldest" possible). The UI then properly handles undated posts by checking post.data.date separately and only displaying a date label if one exists.

This pattern is consistently applied across both docs/src/app/updates/page.tsx and docs/src/app/blog/page.tsx, confirming it is a deliberate design decision rather than an oversight. The implementation gracefully handles both dated and undated posts.

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 (3)
docs/src/app/layout.tsx (1)

2-2: Newsletter popup integration is fine; consider small UX/config guards.

Mounting <NewsletterPopup /> inside RootProvider is a straightforward way to expose the newsletter UI globally and is compatible with it being a client component. Two optional tweaks you might consider:

  • Only render the popup when the subscription backend is configured (e.g., when RESEND_SEGMENT_ID / API key are set) so users never hit a guaranteed 500 from /api/subscribe.
  • If the popup feels noisy in practice, you could later gate it by route or experiment flag.

Also applies to: 117-117

docs/src/components/NewsletterPopup.tsx (1)

28-37: Optional: persist “Maybe later” choice to avoid re‑showing on every page load.

Right now you only set the rybbit_subscribed cookie on successful/409 subscription. If a user clicks “Maybe later” or closes the popup, they’ll see it again on the next page load since useEffect only checks for that cookie.

If “Maybe later” is intended to suppress the popup for some time (e.g., current session or a few days), consider setting a separate “dismissed” cookie or reusing rybbit_subscribed with a shorter expiry in the close handler.

Also applies to: 165-171

docs/src/app/api/subscribe/route.ts (1)

12-24: Email normalization should be added to prevent rate-limit bypass; in-memory approach is acceptable for docs.

Email is not normalized before rate limiting or Resend calls, so case variance (user@example.com vs USER@EXAMPLE.COM) bypasses the 5-request/minute throttle. Add normalization:

const normalizedEmail = email.trim().toLowerCase();
// Use normalizedEmail for checkRateLimit() and Resend API calls

In-memory per-email rate limiting via setInterval cleanup is appropriate for a docs site (the comment correctly notes "for production use Redis"); however, email normalization is a simple robustness improvement that prevents unintended bypass. Web search confirms serverless best practices recommend Redis + edge middleware for production, but docs-scoped in-memory with proper key normalization is acceptable.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a73ad7c and 8fd7ffb.

⛔ Files ignored due to path filters (1)
  • docs/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (7)
  • docs/content/blog/_meta.js (1 hunks)
  • docs/content/blog/bounce-rate.mdx (1 hunks)
  • docs/content/docs/product-analytics/meta.json (1 hunks)
  • docs/package.json (1 hunks)
  • docs/src/app/api/subscribe/route.ts (1 hunks)
  • docs/src/app/layout.tsx (2 hunks)
  • docs/src/components/NewsletterPopup.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/content/blog/bounce-rate.mdx
🧰 Additional context used
🧬 Code graph analysis (1)
docs/src/app/layout.tsx (1)
docs/src/components/NewsletterPopup.tsx (1)
  • NewsletterPopup (21-194)
⏰ 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). (2)
  • GitHub Check: Build Client Images (ubuntu-24.04-arm, linux/arm64)
  • GitHub Check: Build Client Images (ubuntu-latest, linux/amd64)
🔇 Additional comments (4)
docs/content/blog/_meta.js (1)

8-9: Bounce rate blog meta entry looks correct

Slug and title fit the existing pattern and the object syntax is valid. No issues from this change.

docs/content/docs/product-analytics/meta.json (1)

3-3: Change verified; no stale references remain

Meta.json correctly updated with bounce-rate removed and only "replay-session" in pages. Verification confirms no lingering references to the old product-analytics/bounce-rate path exist in the codebase. The only bounce-rate mentions found are an external link to rybbit.com and the expected blog metadata entry where the content now resides. The change is safe to merge.

docs/src/app/api/subscribe/route.ts (1)

159-176: FE/BE 409 mismatch remains unresolved; Resend doesn't expose duplicate-contact errors in documented API.

The verification confirms Resend's public API does not define dedicated error codes for duplicate contacts or segment membership. The Errors reference lists standard types (validation_error, invalid_idempotent_request, etc.) but nothing for duplicates. This means the caveat about the frontend expecting a 409 for "already registered" remains valid—handling that status will require either pre-checks before calling Resend or custom detection logic in your API layer to map any duplicate-indicating responses to 409. For now, duplicates will surface as generic errors client-side unless you layer in that logic.

docs/package.json (1)

30-30: Resend dependency version verified as compatible.

The Resend Node SDK v6.4.2 correctly exposes both contacts.create() and contacts.segments.add() methods matching the signatures used in your /api/subscribe route. The dependency is properly configured for your use case.

Comment on lines +43 to +91
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitting(true);
setErrorMessage(null);

try {
// Replace with your actual newsletter API endpoint
const response = await fetch("/api/subscribe", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
}),
});

const data = await response.json();

if (response.ok) {
// Set cookie to prevent showing popup again (1 year expiration)
const expirationDate = new Date();
expirationDate.setFullYear(expirationDate.getFullYear() + 1);
document.cookie = `rybbit_subscribed=true; expires=${expirationDate.toUTCString()}; path=/`;

setIsSubmitted(true);
setTimeout(() => {
handleClose();
}, 2000);
} else if (response.status === 409) {
// Email already registered - set cookie anyway
const expirationDate = new Date();
expirationDate.setFullYear(expirationDate.getFullYear() + 1);
document.cookie = `rybbit_subscribed=true; expires=${expirationDate.toUTCString()}; path=/`;

setErrorMessage("Email already registered");
setTimeout(() => {
handleClose();
}, 2000);
} else {
setErrorMessage(data.error || "Failed to subscribe. Please try again.");
}
} catch (error) {
console.error("Error subscribing to newsletter:", error);
setErrorMessage("An error occurred. Please try again.");
} finally {
setIsSubmitting(false);
}
};
Copy link
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

409 handling path is currently unreachable with the existing API route.

The client treats response.status === 409 as “Email already registered” (and sets the subscribed cookie), but the /api/subscribe handler never returns 409 today—validation errors are 400 and all Resend/contact issues are mapped to 500. That means this path is effectively dead, and repeat subscriptions will surface as generic errors instead of the nicer already‑registered flow.

To align behavior, either:

  • Update the API route to map “already subscribed/already in segment” conditions to a 409, or
  • Simplify the client logic and rely on the error message from the API instead of a hard‑coded 409 branch.

Also applies to: 148-154


🌐 Web query:

Check Resend’s error codes/messages for `contacts.create` and `contacts.segments.add` to see how an “already existing contact/segment membership” condition is represented so it can be mapped to HTTP 409 in `docs/src/app/api/subscribe/route.ts`.

💡 Result:

Findings:

  • Resend docs for Create Contact. (POST /contacts) — response examples show 201 on success; no documented "already exists" error for contacts.create. (resend.com)
  • Resend docs for Add Contact to Segment (contacts.segments.add) — response examples show a successful id (no documented error for "already a member"). (resend.com)
  • Resend API Errors page — Resend documents specific 409 cases for idempotency-related errors: invalid_idempotent_request and concurrent_idempotent_requests (both 409). There is no explicit documented error code named "already_exists" or a documented 409 specifically for duplicate contact/segment membership. (resend.com)

Recommendation for mapping in docs/src/app/api/subscribe/route.ts:

  • Map any Resend 409 responses to HTTP 409 (covers idempotency conflicts). Check the Resend error type/name in the response body (e.g., invalid_idempotent_request or concurrent_idempotent_requests) and map those to 409. (resend.com)
  • Because Resend’s docs do not explicitly document a distinct "already existing contact" or "already a member" error, also detect 409 with any duplicate-like message in the body (if observed in practice) — and treat it as 409. If you need a definitive mapping for a specific duplicate error string, run a quick API test (create a contact that already exists and add a contact already in a segment) and inspect the actual response body/status to add a precise case in your code.

Sources:

  1. Create Contact docs. (resend.com)
  2. Add Contact to Segment docs. (resend.com)
  3. Resend Errors reference (shows 409 idempotency errors; no explicit "already exists" code). (resend.com)

If you want, I can run a quick live test (POST same email to /contacts and POST add-to-segment twice) and return the exact response body/status to use in your mapping.

Citations:


Understood. The web search confirms that Resend's API doesn't explicitly document an "already exists" 409 response—only idempotency-related 409s are documented. This supports the original review's concern that the client's 409 handling is likely unreachable. Let me verify the backend implementation to confirm whether it actually maps any condition to 409 or if this path is indeed dead code.


---

🏁 Script executed:

```shell
#!/bin/bash
# Search for the backend subscribe route handler
find . -type f -name "route.ts" -o -name "route.js" | xargs grep -l "subscribe" 2>/dev/null | head -20

Length of output: 37


🏁 Script executed:

#!/bin/bash
# Also try direct path lookup for the file mentioned in the review
if [ -f "docs/src/app/api/subscribe/route.ts" ]; then
  cat "docs/src/app/api/subscribe/route.ts"
else
  echo "File not found at docs/src/app/api/subscribe/route.ts"
fi

Length of output: 5743


🏁 Script executed:

#!/bin/bash
# Search for /api/subscribe references in the codebase
rg -n "api/subscribe" --type=ts --type=tsx -A2 -B2

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Look for 409 status code usage anywhere in the backend
rg -n "409\|status.*409" --type=ts --type=js -B3 -A3

Length of output: 0


The 409 handling path in the client is confirmed to be unreachable dead code.

Backend verification confirms the mismatch: docs/src/app/api/subscribe/route.ts returns 500 for all Resend API errors (lines 110, 126)—there is no code path that returns 409. Additionally, Resend's API only documents 409 for idempotency-related errors, not for "already exists" conditions.

This means the client code at lines 67–76 that checks response.status === 409 will never execute, and repeat subscriptions will fail with a generic 500 error instead of the intended "Email already registered" message.

To fix, either:

  • Modify the backend to detect duplicate contact/segment membership (if Resend's SDK provides this info) and map to 409, or
  • Remove the 409 branch from the client and rely on the error message text from the backend instead.
🤖 Prompt for AI Agents
In docs/src/components/NewsletterPopup.tsx around lines 43 to 91, remove the
unreachable response.status === 409 branch (lines ~67–76) and its logic; instead
rely on the backend-provided error payload (data.error) to surface
duplicate-subscription messages to the user, only set the rybbit_subscribed
cookie on response.ok, and ensure setErrorMessage(data.error || "Failed to
subscribe. Please try again.") handles duplicate-case text returned as a 500
from the backend.

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