Skip to content
This repository was archived by the owner on Aug 11, 2026. It is now read-only.
This repository was archived by the owner on Aug 11, 2026. It is now read-only.

Issue 4: Implement Public Blog Routes, RSS, Sitemap, and SEO #540

Description

@ahliweb

Parent Epic: #536
Depends on: #537, #538, #539

Objective

Expose published blog content safely through public routes, RSS, sitemap, and SEO metadata rendering.

Context

This issue makes blog_content usable on the public website while enforcing strict public visibility rules. Public routes must never leak draft, review, scheduled-future, archived, private, unlisted, or soft-deleted content.

Scope

  • Public blog index
  • Public post detail page
  • Public category archive
  • Public tag archive
  • Public search
  • RSS feed
  • Blog sitemap
  • SEO metadata rendering
  • Canonical URL validation
  • Safe content rendering

Out of Scope

  • Admin UI
  • Revision restore UI
  • Template/widget/menu/ads advanced rendering unless implemented in a later issue
  • Comment system
  • Public user registration

Routes

GET /blog
GET /blog/[slug]
GET /blog/category/[slug]
GET /blog/tag/[slug]
GET /blog/search?q=
GET /feed.xml
GET /sitemap-blog.xml

Public Visibility Rule

All public queries must centralize and reuse this predicate:

status = 'published'
AND visibility = 'public'
AND deleted_at IS NULL
AND published_at IS NOT NULL
AND published_at <= now()

Additional listing/search/feed/sitemap rule:

visibility != 'unlisted'

SEO Requirements

  • Render seo_title when available.
  • Fall back to title when seo_title is empty.
  • Render meta_description when available.
  • Fall back to excerpt or safe generated summary when meta_description is empty.
  • Render canonical URL only when valid and safe.
  • Do not render unsafe URLs.

RSS Requirements

  • RSS must include only published public content.
  • RSS must exclude unlisted, private, archived, scheduled-future, draft, review, and deleted content.
  • RSS must respect tenant context and blog settings.

Sitemap Requirements

  • Sitemap must include only published public content.
  • Sitemap must exclude unlisted, private, archived, scheduled-future, draft, review, and deleted content.
  • Sitemap must respect tenant context and blog settings.

Content Safety Requirements

  • Use structured JSON content as the source of truth.
  • Rendering must sanitize or safely render content.
  • Script tags must be rejected or stripped.
  • Inline JavaScript must be rejected or stripped.
  • Dangerous iframe/embed content must be rejected or stripped.
  • Unsafe URLs must be rejected.
  • Error output must not expose stack traces.

Acceptance Criteria

  • Public blog index exists.
  • Public post detail route exists.
  • Public category archive exists.
  • Public tag archive exists.
  • Public search exists.
  • RSS feed exists.
  • Blog sitemap exists.
  • Public query helper centralizes the visibility predicate.
  • Draft content is never publicly visible.
  • Review content is never publicly visible.
  • Scheduled-future content is never publicly visible.
  • Archived content is never publicly visible.
  • Private content is never publicly visible.
  • Unlisted content is excluded from listing/search/feed/sitemap.
  • Soft-deleted content is never publicly visible.
  • Public post detail renders SEO title and meta description.
  • Canonical URL is rendered only when valid.
  • RSS includes only published public content.
  • Sitemap includes only published public content.
  • Content rendering is sanitized.
  • Tests cover public visibility leakage.
  • Tests cover SEO rendering.
  • Tests cover RSS and sitemap content filtering.
  • bun run build passes.

Validation Commands

bun run test
bun run typecheck
bun run build

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions