← gitpulse
New Feature·Pushed May 1, 2026·S

Story URLs now include keyword-rich slugs

Story URLs now include a readable slug derived from the headline, replacing opaque identifiers with paths like /stories/pr-123/adding-user-authentication/ that search engines can parse.

Search engines crawling the site previously encountered story URLs with no semantic meaning — [[code]]/stories/pr-2/[[/code]] and [[code]]/stories/commit-abc1234/[[/code]] convey nothing about content. Now story URLs include a human-readable slug drawn from the headline. A PR titled "Add user authentication" becomes [[code]]/stories/pr-2/add-user-authentication/[[/code]], making the URL itself a ranking signal. The site now generates slugs by lowercasing the headline, replacing spaces with hyphens, and truncating at 80 characters on a word boundary. URL generation is centralized in a new helper module rather than scattered across template strings. The sitemap, OpenGraph metadata, and all internal navigation links have been updated to use the new format. This change lives in the [[code]]@gitpulse/site[[/code]] Next.js application. Both the story page and its OpenGraph image route now accept the slug as a real route segment, with [[code ref=4]]storySlug()[[/code]] exposed for static generation.
Technical description
This PR transforms opaque story URLs into SEO-friendly paths by appending a keyword-rich slug derived from the story headline. The implementation introduces two new utility files. [[code ref=1]]slugify()[[/code]] in [[code]]site/src/lib/utils/slugify.ts[[/code]] converts text to URL-safe slugs: lowercase, non-alphanumeric replaced with hyphens, collapsed runs trimmed, and truncated at 80 characters on a word boundary. [[code]]site/src/lib/urls.ts[[/code]] provides centralized URL builders — [[code ref=2]]storyPath()[[/code]] returns the canonical [[code]]/stories/<id>/<slug>/[[/code]] shape, [[code ref=3]]storyOgImagePath()[[/code]] handles OG image URLs, and [[code ref=4]]storySlug()[[/code]] exposes just the slug for [[code ref=6]]generateStaticParams[[/code]]. Route structure changes: [[code]]site/src/app/stories/[id]/page.tsx[[/code]] and [[code]]site/src/app/stories/[id]/opengraph-image.tsx[[/code]] move into a [[code]][id]/[slug]/[[/code]] directory so the slug is a first-class route segment. Static params now return [[code]]{id, slug}[[/code]] pairs. The following locations are updated to use the new helpers: - [[code ref=7]]sitemap.ts[[/code]]: sitemap entries reference the slug path - [[code ref=8]]seo.ts[[/code]]: canonical URL and og:image use storyPath() and storyOgImagePath() - [[code ref=9]]FixesBrief.tsx[[/code]], [[code ref=10]]HousekeepingDrawer.tsx[[/code]], [[code ref=11]]PRFeedItem.tsx[[/code]]: internal story links use storyPath() ````mermaid graph LR A[Story headline] --> B[slugify] B --> C[storySlug] C --> D[storyPath] C --> E[storyOgImagePath] D --> F[sitemap] D --> G[canonical URL] D --> H[internal links] E --> I[og:image] ```` **Files at a Glance:** - [[code]]site/src/lib/utils/slugify.ts[[/code]] — new slug generation utility - [[code]]site/src/lib/urls.ts[[/code]] — centralized URL builder helpers - [[code]]site/src/app/sitemap.ts[[/code]] — updated to use storyPath() - [[code]]site/src/lib/seo.ts[[/code]] — canonical and OG URLs use new helpers - [[code]]site/src/app/stories/[id]/[slug]/page.tsx[[/code]] — moved from [id]/ (route change) - [[code]]site/src/app/stories/[id]/[slug]/opengraph-image.tsx[[/code]] — moved from [id]/ (route change) - [[code]]site/src/components/FixesBrief.tsx[[/code]] — links updated to storyPath() - [[code]]site/src/components/HousekeepingDrawer.tsx[[/code]] — links updated to storyPath() - [[code]]site/src/components/PRFeedItem.tsx[[/code]] — links updated to storyPath()

Categories

  • New Feature (85%)Primary purpose is adding SEO-friendly URLs with keyword-rich slugs that weren't possible before
  • Maintenance (15%)Centralizes URL generation logic into shared helpers, removing hardcoded path construction from multiple components