The blog-analytics.tsx client component was importing from the @/lib/blog
barrel export, which transitively included content.ts that uses the Node.js
fs module. This caused the build to fail with "Module not found: Cannot
resolve fs" error.
Changed imports to use direct file paths:
- Import BlogPost type from @/lib/blog/types
- Import analytics functions from @/lib/blog/analytics
This avoids pulling content.ts into the client bundle.
- Create sitemap.ts with MetadataRoute.Sitemap for Next.js
- Include all static pages with priorities and change frequencies
- Include /blog index page (priority 0.8, daily updates)
- Dynamically include all published blog post URLs (/blog/[slug])
- Blog posts use publish_date as lastModified
The sitemap is referenced by robots.ts at /sitemap.xml
MKT-71
- Add SUBSTACK link to constants.ts
- Add Blog link to desktop nav Resources dropdown
- Add Blog link to mobile nav Resources section
- Add Blog link to footer Resources section
- Add Substack link to footer Connect section
MKT-72
- Add analytics.ts with blog-specific tracking events:
- trackBlogIndexView: Track blog index views with post count
- trackBlogPostView: Track individual post views with metadata
- trackBlogPostScrollDepth: Track reading progress (25%, 50%, 75%, 100%)
- trackBlogPostTimeSpent: Track time spent on posts
- trackBlogPostShare: Track social share clicks
- trackBlogPostCTAClick: Track CTA engagement
- Add BlogIndexAnalytics and BlogPostAnalytics client components
- Integrate analytics into /blog and /blog/[slug] pages
Attribution is handled by PostHog save_referrer and save_campaign_params.
MKT-74
- Add structured-data.ts with Article, CollectionPage, and BreadcrumbList schemas
- Integrate JSON-LD into /blog index page (Blog collection + breadcrumbs)
- Integrate JSON-LD into /blog/[slug] page (Article + post breadcrumbs)
- Export structured data utilities from blog module index
MKT-70
- Create dynamic route for individual blog posts
- Use force-dynamic for request-time publish gating
- Require Node.js runtime for filesystem reads
- Return 404 for drafts, future posts, or invalid slugs
- Render Markdown with react-markdown + remark-gfm
- No raw HTML rendering (safe by default)
- Include consistent typography and styling
Closes: MKT-69
- Create blog index page at /blog
- Use force-dynamic for request-time publish gating
- Require Node.js runtime for filesystem reads
- Display posts with title, description, and date
- Add empty state when no posts are published
- Include tags display (up to 3)
Closes: MKT-68
Adds the first canonical blog post to validate the content pipeline:
- Title: PRDs Are Becoming Artifacts of the Past
- Slug: prds-are-becoming-artifacts-of-the-past
- Status: published
- Publish date: 2026-01-12 at 9:00am PT
Content sourced from Office Hours S01E15 with Paige Bailey.
Closes: MKT-73
copy: update /slack page messaging
- Update trial CTA to 'Start a free 14 day Team trial'
- Replace 'humans' with 'your team' in value props subtitle
- Shorten value prop titles for consistent one-line display
- Improve Thread-aware and Open to all descriptions
* feat(web-evals): remember last Roo model selection
* fix(web-evals): reset model selections on provider switch and fix lint warning
- Add useEffect to reset model selections when switching between providers
This prevents OpenRouter model IDs from persisting when switching to Roo,
which was causing Roo's stored selection to be overwritten with wrong IDs
- Remove unused 'executionMethod' from onSubmit dependency array to fix
react-hooks/exhaustive-deps warning
* fix(web-evals): add missing executionMethod to test cases
* fix(web-evals): harden localStorage + keep provider selections